summaryrefslogtreecommitdiff
path: root/contrib
diff options
context:
space:
mode:
Diffstat (limited to 'contrib')
-rw-r--r--contrib/compiler-rt/include/sanitizer/asan_interface.h4
-rw-r--r--contrib/compiler-rt/include/sanitizer/common_interface_defs.h19
-rw-r--r--contrib/compiler-rt/include/sanitizer/coverage_interface.h11
-rw-r--r--contrib/compiler-rt/include/sanitizer/dfsan_interface.h6
-rw-r--r--contrib/compiler-rt/include/sanitizer/lsan_interface.h2
-rw-r--r--contrib/compiler-rt/include/sanitizer/msan_interface.h16
-rw-r--r--contrib/compiler-rt/lib/asan/README.txt2
-rw-r--r--contrib/compiler-rt/lib/asan/asan_activation.cc9
-rw-r--r--contrib/compiler-rt/lib/asan/asan_allocator.cc22
-rw-r--r--contrib/compiler-rt/lib/asan/asan_allocator.h5
-rw-r--r--contrib/compiler-rt/lib/asan/asan_debugging.cc4
-rw-r--r--contrib/compiler-rt/lib/asan/asan_fake_stack.cc22
-rw-r--r--contrib/compiler-rt/lib/asan/asan_flags.cc9
-rw-r--r--contrib/compiler-rt/lib/asan/asan_flags.inc24
-rw-r--r--contrib/compiler-rt/lib/asan/asan_globals.cc5
-rw-r--r--contrib/compiler-rt/lib/asan/asan_init_version.h4
-rw-r--r--contrib/compiler-rt/lib/asan/asan_interceptors.cc74
-rw-r--r--contrib/compiler-rt/lib/asan/asan_interceptors.h6
-rw-r--r--contrib/compiler-rt/lib/asan/asan_interface_internal.h23
-rw-r--r--contrib/compiler-rt/lib/asan/asan_internal.h7
-rw-r--r--contrib/compiler-rt/lib/asan/asan_linux.cc23
-rw-r--r--contrib/compiler-rt/lib/asan/asan_mac.cc197
-rw-r--r--contrib/compiler-rt/lib/asan/asan_malloc_linux.cc21
-rw-r--r--contrib/compiler-rt/lib/asan/asan_malloc_mac.cc371
-rw-r--r--contrib/compiler-rt/lib/asan/asan_mapping.h33
-rw-r--r--contrib/compiler-rt/lib/asan/asan_new_delete.cc10
-rw-r--r--contrib/compiler-rt/lib/asan/asan_poisoning.cc29
-rw-r--r--contrib/compiler-rt/lib/asan/asan_posix.cc10
-rw-r--r--contrib/compiler-rt/lib/asan/asan_report.cc226
-rw-r--r--contrib/compiler-rt/lib/asan/asan_report.h67
-rw-r--r--contrib/compiler-rt/lib/asan/asan_rtl.cc152
-rw-r--r--contrib/compiler-rt/lib/asan/asan_stack.h9
-rw-r--r--contrib/compiler-rt/lib/asan/asan_thread.cc21
-rw-r--r--contrib/compiler-rt/lib/asan/asan_thread.h13
-rw-r--r--contrib/compiler-rt/lib/asan/asan_win.cc20
-rw-r--r--contrib/compiler-rt/lib/asan/asan_win_dll_thunk.cc30
-rw-r--r--contrib/compiler-rt/lib/asan/asan_win_dynamic_runtime_thunk.cc2
-rwxr-xr-xcontrib/compiler-rt/lib/asan/scripts/asan_device_setup344
-rwxr-xr-xcontrib/compiler-rt/lib/asan/scripts/asan_symbolize.py482
-rw-r--r--contrib/compiler-rt/lib/asan/tests/asan_asm_test.cc267
-rw-r--r--contrib/compiler-rt/lib/asan/tests/asan_benchmarks_test.cc85
-rw-r--r--contrib/compiler-rt/lib/asan/tests/asan_exceptions_test.cc27
-rw-r--r--contrib/compiler-rt/lib/asan/tests/asan_fake_stack_test.cc152
-rw-r--r--contrib/compiler-rt/lib/asan/tests/asan_globals_test.cc45
-rw-r--r--contrib/compiler-rt/lib/asan/tests/asan_interface_test.cc433
-rw-r--r--contrib/compiler-rt/lib/asan/tests/asan_mac_test.cc236
-rw-r--r--contrib/compiler-rt/lib/asan/tests/asan_mac_test.h19
-rw-r--r--contrib/compiler-rt/lib/asan/tests/asan_mac_test_helpers.mm240
-rw-r--r--contrib/compiler-rt/lib/asan/tests/asan_mem_test.cc241
-rw-r--r--contrib/compiler-rt/lib/asan/tests/asan_noinst_test.cc263
-rw-r--r--contrib/compiler-rt/lib/asan/tests/asan_oob_test.cc128
-rw-r--r--contrib/compiler-rt/lib/asan/tests/asan_racy_double_free_test.cc32
-rw-r--r--contrib/compiler-rt/lib/asan/tests/asan_str_test.cc573
-rw-r--r--contrib/compiler-rt/lib/asan/tests/asan_test.cc1319
-rw-r--r--contrib/compiler-rt/lib/asan/tests/asan_test.ignore3
-rw-r--r--contrib/compiler-rt/lib/asan/tests/asan_test_config.h54
-rw-r--r--contrib/compiler-rt/lib/asan/tests/asan_test_main.cc19
-rw-r--r--contrib/compiler-rt/lib/asan/tests/asan_test_utils.h107
-rw-r--r--contrib/compiler-rt/lib/builtins/README.txt4
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/aeabi_cdcmp.S96
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/aeabi_cdcmpeq_check_nan.c16
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/aeabi_cfcmp.S91
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/aeabi_cfcmpeq_check_nan.c16
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/aeabi_drsub.c19
-rw-r--r--contrib/compiler-rt/lib/builtins/arm/aeabi_frsub.c19
-rw-r--r--contrib/compiler-rt/lib/builtins/assembly.h9
-rw-r--r--contrib/compiler-rt/lib/builtins/atomic.c14
-rw-r--r--contrib/compiler-rt/lib/builtins/atomic_flag_clear.c10
-rw-r--r--contrib/compiler-rt/lib/builtins/atomic_flag_clear_explicit.c10
-rw-r--r--contrib/compiler-rt/lib/builtins/atomic_flag_test_and_set.c8
-rw-r--r--contrib/compiler-rt/lib/builtins/atomic_flag_test_and_set_explicit.c8
-rw-r--r--contrib/compiler-rt/lib/builtins/atomic_signal_fence.c8
-rw-r--r--contrib/compiler-rt/lib/builtins/atomic_thread_fence.c8
-rw-r--r--contrib/compiler-rt/lib/builtins/comparedf2.c5
-rw-r--r--contrib/compiler-rt/lib/builtins/comparesf2.c5
-rw-r--r--contrib/compiler-rt/lib/builtins/comparetf2.c5
-rw-r--r--contrib/compiler-rt/lib/builtins/divdc3.c22
-rw-r--r--contrib/compiler-rt/lib/builtins/divsc3.c22
-rw-r--r--contrib/compiler-rt/lib/builtins/divtc3.c60
-rw-r--r--contrib/compiler-rt/lib/builtins/divxc3.c22
-rw-r--r--contrib/compiler-rt/lib/builtins/emutls.c183
-rw-r--r--contrib/compiler-rt/lib/builtins/enable_execute_stack.c4
-rw-r--r--contrib/compiler-rt/lib/builtins/extendhfsf2.c4
-rw-r--r--contrib/compiler-rt/lib/builtins/fixunsdfdi.c4
-rw-r--r--contrib/compiler-rt/lib/builtins/fixunssfdi.c4
-rw-r--r--contrib/compiler-rt/lib/builtins/floatdidf.c4
-rw-r--r--contrib/compiler-rt/lib/builtins/floatditf.c10
-rw-r--r--contrib/compiler-rt/lib/builtins/floatsitf.c8
-rw-r--r--contrib/compiler-rt/lib/builtins/floatundidf.c6
-rw-r--r--contrib/compiler-rt/lib/builtins/fp_add_impl.inc2
-rw-r--r--contrib/compiler-rt/lib/builtins/fp_extend.h6
-rw-r--r--contrib/compiler-rt/lib/builtins/fp_extend_impl.inc2
-rw-r--r--contrib/compiler-rt/lib/builtins/fp_fixint_impl.inc2
-rw-r--r--contrib/compiler-rt/lib/builtins/fp_fixuint_impl.inc4
-rw-r--r--contrib/compiler-rt/lib/builtins/fp_lib.h22
-rw-r--r--contrib/compiler-rt/lib/builtins/fp_mul_impl.inc2
-rw-r--r--contrib/compiler-rt/lib/builtins/fp_trunc.h4
-rw-r--r--contrib/compiler-rt/lib/builtins/fp_trunc_impl.inc2
-rw-r--r--contrib/compiler-rt/lib/builtins/gcc_personality_v0.c13
-rw-r--r--contrib/compiler-rt/lib/builtins/i386/chkstk.S4
-rw-r--r--contrib/compiler-rt/lib/builtins/i386/chkstk2.S40
-rw-r--r--contrib/compiler-rt/lib/builtins/int_lib.h61
-rw-r--r--contrib/compiler-rt/lib/builtins/int_math.h57
-rw-r--r--contrib/compiler-rt/lib/builtins/int_types.h28
-rw-r--r--contrib/compiler-rt/lib/builtins/int_util.c8
-rw-r--r--contrib/compiler-rt/lib/builtins/int_util.h12
-rw-r--r--contrib/compiler-rt/lib/builtins/muldc3.c14
-rw-r--r--contrib/compiler-rt/lib/builtins/mulsc3.c14
-rw-r--r--contrib/compiler-rt/lib/builtins/mulxc3.c14
-rw-r--r--contrib/compiler-rt/lib/builtins/ppc/DD.h43
-rw-r--r--contrib/compiler-rt/lib/builtins/ppc/divtc3.c5
-rw-r--r--contrib/compiler-rt/lib/builtins/ppc/multc3.c4
-rw-r--r--contrib/compiler-rt/lib/builtins/subdf3.c1
-rw-r--r--contrib/compiler-rt/lib/builtins/subsf3.c1
-rw-r--r--contrib/compiler-rt/lib/builtins/truncdfhf2.c2
-rw-r--r--contrib/compiler-rt/lib/builtins/truncsfhf2.c4
-rw-r--r--contrib/compiler-rt/lib/builtins/x86_64/chkstk.S4
-rw-r--r--contrib/compiler-rt/lib/builtins/x86_64/chkstk2.S42
-rw-r--r--contrib/compiler-rt/lib/cfi/cfi.cc271
-rw-r--r--contrib/compiler-rt/lib/cfi/cfi_blacklist.txt26
-rw-r--r--contrib/compiler-rt/lib/dfsan/dfsan.cc97
-rw-r--r--contrib/compiler-rt/lib/dfsan/dfsan.h7
-rw-r--r--contrib/compiler-rt/lib/dfsan/dfsan_custom.cc48
-rw-r--r--contrib/compiler-rt/lib/dfsan/dfsan_platform.h107
-rw-r--r--contrib/compiler-rt/lib/dfsan/done_abilist.txt35
-rwxr-xr-xcontrib/compiler-rt/lib/dfsan/scripts/build-libc-list.py96
-rwxr-xr-xcontrib/compiler-rt/lib/dfsan/scripts/check_custom_wrappers.sh52
-rw-r--r--contrib/compiler-rt/lib/interception/interception_linux.h10
-rw-r--r--contrib/compiler-rt/lib/interception/interception_win.cc60
-rw-r--r--contrib/compiler-rt/lib/interception/interception_win.h4
-rw-r--r--contrib/compiler-rt/lib/lsan/lsan.cc2
-rw-r--r--contrib/compiler-rt/lib/lsan/lsan_allocator.cc14
-rw-r--r--contrib/compiler-rt/lib/lsan/lsan_common.cc39
-rw-r--r--contrib/compiler-rt/lib/lsan/lsan_common.h4
-rw-r--r--contrib/compiler-rt/lib/lsan/lsan_common_linux.cc9
-rw-r--r--contrib/compiler-rt/lib/lsan/lsan_flags.inc2
-rw-r--r--contrib/compiler-rt/lib/lsan/lsan_interceptors.cc10
-rw-r--r--contrib/compiler-rt/lib/lsan/lsan_thread.cc10
-rw-r--r--contrib/compiler-rt/lib/msan/msan.cc44
-rw-r--r--contrib/compiler-rt/lib/msan/msan.h82
-rw-r--r--contrib/compiler-rt/lib/msan/msan_allocator.cc36
-rw-r--r--contrib/compiler-rt/lib/msan/msan_chained_origin_depot.cc10
-rw-r--r--contrib/compiler-rt/lib/msan/msan_flags.inc4
-rw-r--r--contrib/compiler-rt/lib/msan/msan_interceptors.cc90
-rw-r--r--contrib/compiler-rt/lib/msan/msan_interface_internal.h14
-rw-r--r--contrib/compiler-rt/lib/msan/msan_linux.cc23
-rw-r--r--contrib/compiler-rt/lib/msan/msan_new_delete.cc4
-rw-r--r--contrib/compiler-rt/lib/msan/msan_thread.h2
-rw-r--r--contrib/compiler-rt/lib/msan/tests/msan_loadable.cc27
-rw-r--r--contrib/compiler-rt/lib/msan/tests/msan_test.cc4287
-rw-r--r--contrib/compiler-rt/lib/msan/tests/msan_test_config.h20
-rw-r--r--contrib/compiler-rt/lib/msan/tests/msan_test_main.cc21
-rw-r--r--contrib/compiler-rt/lib/profile/GCDAProfiling.c6
-rw-r--r--contrib/compiler-rt/lib/profile/InstrProfData.inc767
-rw-r--r--contrib/compiler-rt/lib/profile/InstrProfiling.c77
-rw-r--r--contrib/compiler-rt/lib/profile/InstrProfiling.h77
-rw-r--r--contrib/compiler-rt/lib/profile/InstrProfilingBuffer.c82
-rw-r--r--contrib/compiler-rt/lib/profile/InstrProfilingFile.c111
-rw-r--r--contrib/compiler-rt/lib/profile/InstrProfilingInternal.h78
-rw-r--r--contrib/compiler-rt/lib/profile/InstrProfilingPlatformDarwin.c45
-rw-r--r--contrib/compiler-rt/lib/profile/InstrProfilingPlatformLinux.c59
-rw-r--r--contrib/compiler-rt/lib/profile/InstrProfilingPlatformOther.c48
-rw-r--r--contrib/compiler-rt/lib/profile/InstrProfilingPort.h62
-rw-r--r--contrib/compiler-rt/lib/profile/InstrProfilingRuntime.cc3
-rw-r--r--contrib/compiler-rt/lib/profile/InstrProfilingUtil.c3
-rw-r--r--contrib/compiler-rt/lib/profile/InstrProfilingValue.c180
-rw-r--r--contrib/compiler-rt/lib/profile/InstrProfilingWriter.c175
-rw-r--r--contrib/compiler-rt/lib/profile/WindowsMMap.c128
-rw-r--r--contrib/compiler-rt/lib/profile/WindowsMMap.h65
-rw-r--r--contrib/compiler-rt/lib/safestack/CMakeLists.txt28
-rw-r--r--contrib/compiler-rt/lib/safestack/safestack.cc9
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_addrhashmap.h8
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_allocator.cc17
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_allocator.h42
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_internal.h10
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_asm.h20
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_atomic.h16
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_common.cc190
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_common.h79
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc696
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_format.inc19
-rwxr-xr-xcontrib/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc4
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_common_libcdep.cc24
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_common_nolibc.cc27
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_common_syscalls.inc4
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_coverage_libcdep.cc64
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc4
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector1.cc8
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector_interface.h6
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_flag_parser.cc18
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_flag_parser.h1
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_flags.cc51
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_flags.h2
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_flags.inc29
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_interface_internal.h5
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h13
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_lfstack.h8
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_libc.cc46
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_libc.h9
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_libignore.cc15
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_linux.cc237
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_linux.h3
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cc154
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_list.h19
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_mac.cc283
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_mac.h14
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_malloc_mac.inc329
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_persistent_allocator.h5
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_platform.h24
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h15
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cc115
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h19
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_posix.cc98
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_posix.h3
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cc61
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_printf.cc13
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_common.cc13
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_linux.cc6
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_mac.cc2
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_quarantine.h6
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_stackdepot.cc4
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_stackdepot.h7
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_stackdepotbase.h10
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.cc13
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.h6
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_printer.cc7
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc102
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_suppressions.cc19
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_suppressions.h6
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_internal.h62
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.h1
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc241
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.cc96
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc319
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_process_libcdep.cc229
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_win.cc141
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_win.h31
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_syscall_linux_aarch64.inc138
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_thread_registry.h8
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_tls_get_addr.cc11
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_win.cc177
-rwxr-xr-xcontrib/compiler-rt/lib/sanitizer_common/scripts/check_lint.sh136
-rwxr-xr-xcontrib/compiler-rt/lib/sanitizer_common/scripts/cpplint.py4024
-rwxr-xr-xcontrib/compiler-rt/lib/sanitizer_common/scripts/gen_dynamic_list.py110
-rwxr-xr-xcontrib/compiler-rt/lib/sanitizer_common/scripts/litlint.py72
-rwxr-xr-xcontrib/compiler-rt/lib/sanitizer_common/scripts/litlint_test.py23
-rwxr-xr-xcontrib/compiler-rt/lib/sanitizer_common/scripts/sancov.py241
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_allocator_test.cc860
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_allocator_testlib.cc162
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_atomic_test.cc128
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_bitvector_test.cc176
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_bvgraph_test.cc339
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_common_test.cc229
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_deadlock_detector_test.cc496
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_flags_test.cc142
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_format_interceptor_test.cc259
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_ioctl_test.cc103
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_libc_test.cc159
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_linux_test.cc268
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_list_test.cc173
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_mutex_test.cc137
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_nolibc_test.cc31
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_nolibc_test_main.cc19
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_posix_test.cc80
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_printf_test.cc153
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_procmaps_test.cc56
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_pthread_wrappers.h66
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_stackdepot_test.cc93
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_stacktrace_printer_test.cc152
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc154
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_stoptheworld_test.cc204
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_stoptheworld_testlib.cc53
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_suppressions_test.cc134
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_symbolizer_test.cc58
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_test_config.h30
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_test_main.cc22
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_test_utils.h127
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_thread_registry_test.cc232
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/tests/standalone_malloc_test.cc87
-rwxr-xr-xcontrib/compiler-rt/lib/tsan/analyze_libtsan.sh43
-rwxr-xr-xcontrib/compiler-rt/lib/tsan/check_analyze.sh44
-rwxr-xr-xcontrib/compiler-rt/lib/tsan/check_cmake.sh18
-rwxr-xr-xcontrib/compiler-rt/lib/tsan/check_memcpy.sh31
-rw-r--r--contrib/compiler-rt/lib/tsan/go/build.bat4
-rwxr-xr-xcontrib/compiler-rt/lib/tsan/go/buildgo.sh130
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_clock.cc2
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_defs.h5
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_dense_alloc.h2
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_flags.cc15
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_flags.inc1
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc462
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_interceptors.h20
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_interceptors_mac.cc91
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_interface_ann.cc34
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_libdispatch_mac.cc284
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_malloc_mac.cc65
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_mman.cc16
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_mman.h1
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_mutex.cc2
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_mutex.h2
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_new_delete.cc16
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_platform.h753
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_platform_linux.cc132
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_platform_mac.cc128
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_platform_posix.cc151
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_platform_windows.cc3
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_ppc_regs.h96
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_report.cc32
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_rtl.cc30
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_rtl.h28
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_rtl_aarch64.S206
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_rtl_amd64.S99
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_rtl_mutex.cc2
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_rtl_ppc64.S288
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cc189
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_rtl_thread.cc8
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_stat.cc3
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_stat.h3
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_suppressions.cc13
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_symbolize.cc10
-rw-r--r--contrib/compiler-rt/lib/tsan/rtl/tsan_sync.h6
-rw-r--r--contrib/compiler-rt/lib/tsan/tests/rtl/tsan_bench.cc105
-rw-r--r--contrib/compiler-rt/lib/tsan/tests/rtl/tsan_mop.cc233
-rw-r--r--contrib/compiler-rt/lib/tsan/tests/rtl/tsan_mutex.cc221
-rw-r--r--contrib/compiler-rt/lib/tsan/tests/rtl/tsan_posix.cc146
-rw-r--r--contrib/compiler-rt/lib/tsan/tests/rtl/tsan_string.cc82
-rw-r--r--contrib/compiler-rt/lib/tsan/tests/rtl/tsan_test.cc53
-rw-r--r--contrib/compiler-rt/lib/tsan/tests/rtl/tsan_test_util.h122
-rw-r--r--contrib/compiler-rt/lib/tsan/tests/rtl/tsan_test_util_linux.cc470
-rw-r--r--contrib/compiler-rt/lib/tsan/tests/rtl/tsan_thread.cc59
-rw-r--r--contrib/compiler-rt/lib/tsan/tests/unit/tsan_clock_test.cc432
-rw-r--r--contrib/compiler-rt/lib/tsan/tests/unit/tsan_dense_alloc_test.cc55
-rw-r--r--contrib/compiler-rt/lib/tsan/tests/unit/tsan_flags_test.cc180
-rw-r--r--contrib/compiler-rt/lib/tsan/tests/unit/tsan_mman_test.cc153
-rw-r--r--contrib/compiler-rt/lib/tsan/tests/unit/tsan_mutex_test.cc126
-rw-r--r--contrib/compiler-rt/lib/tsan/tests/unit/tsan_mutexset_test.cc127
-rw-r--r--contrib/compiler-rt/lib/tsan/tests/unit/tsan_shadow_test.cc78
-rw-r--r--contrib/compiler-rt/lib/tsan/tests/unit/tsan_stack_test.cc95
-rw-r--r--contrib/compiler-rt/lib/tsan/tests/unit/tsan_sync_test.cc123
-rw-r--r--contrib/compiler-rt/lib/tsan/tests/unit/tsan_unit_test_main.cc19
-rw-r--r--contrib/compiler-rt/lib/tsan/tests/unit/tsan_vector_test.cc43
-rw-r--r--contrib/compiler-rt/lib/ubsan/ubsan_checks.inc45
-rw-r--r--contrib/compiler-rt/lib/ubsan/ubsan_diag.cc74
-rw-r--r--contrib/compiler-rt/lib/ubsan/ubsan_diag.h24
-rw-r--r--contrib/compiler-rt/lib/ubsan/ubsan_flags.cc3
-rw-r--r--contrib/compiler-rt/lib/ubsan/ubsan_flags.inc3
-rw-r--r--contrib/compiler-rt/lib/ubsan/ubsan_handlers.cc299
-rw-r--r--contrib/compiler-rt/lib/ubsan/ubsan_handlers.h22
-rw-r--r--contrib/compiler-rt/lib/ubsan/ubsan_handlers_cxx.cc29
349 files changed, 10418 insertions, 26209 deletions
diff --git a/contrib/compiler-rt/include/sanitizer/asan_interface.h b/contrib/compiler-rt/include/sanitizer/asan_interface.h
index 7763389ab257..97ba0ceb0b23 100644
--- a/contrib/compiler-rt/include/sanitizer/asan_interface.h
+++ b/contrib/compiler-rt/include/sanitizer/asan_interface.h
@@ -110,10 +110,6 @@ extern "C" {
void __asan_report_error(void *pc, void *bp, void *sp,
void *addr, int is_write, size_t access_size);
- // Sets the exit code to use when reporting an error.
- // Returns the old value.
- int __asan_set_error_exit_code(int exit_code);
-
// Deprecated. Call __sanitizer_set_death_callback instead.
void __asan_set_death_callback(void (*callback)(void));
diff --git a/contrib/compiler-rt/include/sanitizer/common_interface_defs.h b/contrib/compiler-rt/include/sanitizer/common_interface_defs.h
index ef645e527119..b2a4bb7b89ee 100644
--- a/contrib/compiler-rt/include/sanitizer/common_interface_defs.h
+++ b/contrib/compiler-rt/include/sanitizer/common_interface_defs.h
@@ -105,12 +105,31 @@ extern "C" {
int __sanitizer_verify_contiguous_container(const void *beg, const void *mid,
const void *end);
+ // Similar to __sanitizer_verify_contiguous_container but returns the address
+ // of the first improperly poisoned byte otherwise. Returns null if the area
+ // is poisoned properly.
+ const void *__sanitizer_contiguous_container_find_bad_address(
+ const void *beg, const void *mid, const void *end);
+
// Print the stack trace leading to this call. Useful for debugging user code.
void __sanitizer_print_stack_trace();
// Sets the callback to be called right before death on error.
// Passing 0 will unset the callback.
void __sanitizer_set_death_callback(void (*callback)(void));
+
+ // Interceptor hooks.
+ // Whenever a libc function interceptor is called it checks if the
+ // corresponding weak hook is defined, and it so -- calls it.
+ // The primary use case is data-flow-guided fuzzing, where the fuzzer needs
+ // to know what is being passed to libc functions, e.g. memcmp.
+ // FIXME: implement more hooks.
+ void __sanitizer_weak_hook_memcmp(void *called_pc, const void *s1,
+ const void *s2, size_t n, int result);
+ void __sanitizer_weak_hook_strncmp(void *called_pc, const char *s1,
+ const char *s2, size_t n, int result);
+ void __sanitizer_weak_hook_strcmp(void *called_pc, const char *s1,
+ const char *s2, int result);
#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/contrib/compiler-rt/include/sanitizer/coverage_interface.h b/contrib/compiler-rt/include/sanitizer/coverage_interface.h
index 404b71e3086f..2dcc09fc8499 100644
--- a/contrib/compiler-rt/include/sanitizer/coverage_interface.h
+++ b/contrib/compiler-rt/include/sanitizer/coverage_interface.h
@@ -27,9 +27,11 @@ extern "C" {
// descriptor. Returns -1 on failure, or if coverage dumping is disabled.
// This is intended for use by sandboxing code.
intptr_t __sanitizer_maybe_open_cov_file(const char *name);
- // Get the number of total unique covered entities (blocks, edges, calls).
+ // Get the number of unique covered blocks (or edges).
// This can be useful for coverage-directed in-process fuzzers.
uintptr_t __sanitizer_get_total_unique_coverage();
+ // Get the number of unique indirect caller-callee pairs.
+ uintptr_t __sanitizer_get_total_unique_caller_callee_pairs();
// Reset the basic-block (edge) coverage to the initial state.
// Useful for in-process fuzzing to start collecting coverage from scratch.
@@ -39,6 +41,13 @@ extern "C" {
// Some of the entries in *data will be zero.
uintptr_t __sanitizer_get_coverage_guards(uintptr_t **data);
+ // Set *data to the growing buffer with covered PCs and return the size
+ // of the buffer. The entries are never zero.
+ // When only unique pcs are collected, the size is equal to
+ // __sanitizer_get_total_unique_coverage.
+ // WARNING: EXPERIMENTAL API.
+ uintptr_t __sanitizer_get_coverage_pc_buffer(uintptr_t **data);
+
// The coverage instrumentation may optionally provide imprecise counters.
// Rather than exposing the counter values to the user we instead map
// the counters to a bitset.
diff --git a/contrib/compiler-rt/include/sanitizer/dfsan_interface.h b/contrib/compiler-rt/include/sanitizer/dfsan_interface.h
index 84ffd49f8afe..05666f736718 100644
--- a/contrib/compiler-rt/include/sanitizer/dfsan_interface.h
+++ b/contrib/compiler-rt/include/sanitizer/dfsan_interface.h
@@ -91,16 +91,18 @@ void dfsan_set_write_callback(dfsan_write_callback_t labeled_write_callback);
/// <label> <parent label 1> <parent label 2> <label description if any>
void dfsan_dump_labels(int fd);
+/// Interceptor hooks.
/// Whenever a dfsan's custom function is called the corresponding
/// hook is called it non-zero. The hooks should be defined by the user.
/// The primary use case is taint-guided fuzzing, where the fuzzer
/// needs to see the parameters of the function and the labels.
/// FIXME: implement more hooks.
-
-/// memcmp hook.
void dfsan_weak_hook_memcmp(void *caller_pc, const void *s1, const void *s2,
size_t n, dfsan_label s1_label,
dfsan_label s2_label, dfsan_label n_label);
+void dfsan_weak_hook_strncmp(void *caller_pc, const char *s1, const char *s2,
+ size_t n, dfsan_label s1_label,
+ dfsan_label s2_label, dfsan_label n_label);
#ifdef __cplusplus
} // extern "C"
diff --git a/contrib/compiler-rt/include/sanitizer/lsan_interface.h b/contrib/compiler-rt/include/sanitizer/lsan_interface.h
index db017c4de1a3..8fb8e756da26 100644
--- a/contrib/compiler-rt/include/sanitizer/lsan_interface.h
+++ b/contrib/compiler-rt/include/sanitizer/lsan_interface.h
@@ -43,7 +43,7 @@ extern "C" {
// Check for leaks now. This function behaves identically to the default
// end-of-process leak check. In particular, it will terminate the process if
- // leaks are found and the exit_code flag is non-zero.
+ // leaks are found and the exitcode runtime flag is non-zero.
// Subsequent calls to this function will have no effect and end-of-process
// leak check will not run. Effectively, end-of-process leak check is moved to
// the time of first invocation of this function.
diff --git a/contrib/compiler-rt/include/sanitizer/msan_interface.h b/contrib/compiler-rt/include/sanitizer/msan_interface.h
index f54bcaa3e157..6d6a3765241b 100644
--- a/contrib/compiler-rt/include/sanitizer/msan_interface.h
+++ b/contrib/compiler-rt/include/sanitizer/msan_interface.h
@@ -61,10 +61,6 @@ extern "C" {
* is not. */
void __msan_check_mem_is_initialized(const volatile void *x, size_t size);
- /* Set exit code when error(s) were detected.
- Value of 0 means don't change the program exit code. */
- void __msan_set_exit_code(int exit_code);
-
/* For testing:
__msan_set_expect_umr(1);
... some buggy code ...
@@ -92,14 +88,22 @@ extern "C" {
Memory will be marked uninitialized, with origin at the call site. */
void __msan_allocated_memory(const volatile void* data, size_t size);
+ /* Tell MSan about newly destroyed memory. Mark memory as uninitialized. */
+ void __sanitizer_dtor_callback(const volatile void* data, size_t size);
+
/* This function may be optionally provided by user and should return
a string containing Msan runtime options. See msan_flags.h for details. */
const char* __msan_default_options();
- /* Sets the callback to be called right before death on error.
- Passing 0 will unset the callback. */
+ /* Deprecated. Call __sanitizer_set_death_callback instead. */
void __msan_set_death_callback(void (*callback)(void));
+ /* Update shadow for the application copy of size bytes from src to dst.
+ Src and dst are application addresses. This function does not copy the
+ actual application memory, it only updates shadow and origin for such
+ copy. Source and destination regions can overlap. */
+ void __msan_copy_shadow(const volatile void *dst, const volatile void *src,
+ size_t size);
#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/contrib/compiler-rt/lib/asan/README.txt b/contrib/compiler-rt/lib/asan/README.txt
index 8cc9bb17b59d..bb6ff42c5cde 100644
--- a/contrib/compiler-rt/lib/asan/README.txt
+++ b/contrib/compiler-rt/lib/asan/README.txt
@@ -23,4 +23,4 @@ from the root of your CMake build tree:
make check-asan
For more instructions see:
-http://code.google.com/p/address-sanitizer/wiki/HowToBuild
+https://github.com/google/sanitizers/wiki/AddressSanitizerHowToBuild
diff --git a/contrib/compiler-rt/lib/asan/asan_activation.cc b/contrib/compiler-rt/lib/asan/asan_activation.cc
index 3bc01984898d..9df3b977ea1b 100644
--- a/contrib/compiler-rt/lib/asan/asan_activation.cc
+++ b/contrib/compiler-rt/lib/asan/asan_activation.cc
@@ -38,7 +38,7 @@ static struct AsanDeactivatedFlags {
#undef ASAN_ACTIVATION_FLAG
#undef COMMON_ACTIVATION_FLAG
- RegisterIncludeFlag(parser, cf);
+ RegisterIncludeFlags(parser, cf);
}
void OverrideFromActivationFlags() {
@@ -61,11 +61,6 @@ static struct AsanDeactivatedFlags {
parser.ParseString(env);
}
- // Override from getprop asan.options.
- char buf[100];
- GetExtraActivationFlags(buf, sizeof(buf));
- parser.ParseString(buf);
-
SetVerbosity(cf.verbosity);
if (Verbosity()) ReportUnrecognizedFlags();
@@ -124,6 +119,8 @@ void AsanActivate() {
if (!asan_is_deactivated) return;
VReport(1, "Activating ASan\n");
+ UpdateProcessName();
+
asan_deactivated_flags.OverrideFromActivationFlags();
SetCanPoisonMemory(asan_deactivated_flags.poison_heap);
diff --git a/contrib/compiler-rt/lib/asan/asan_allocator.cc b/contrib/compiler-rt/lib/asan/asan_allocator.cc
index 2df9a510bd9a..56f184a36651 100644
--- a/contrib/compiler-rt/lib/asan/asan_allocator.cc
+++ b/contrib/compiler-rt/lib/asan/asan_allocator.cc
@@ -14,8 +14,8 @@
// with ThreadSanitizer and MemorySanitizer.
//
//===----------------------------------------------------------------------===//
-#include "asan_allocator.h"
+#include "asan_allocator.h"
#include "asan_mapping.h"
#include "asan_poisoning.h"
#include "asan_report.h"
@@ -541,7 +541,7 @@ struct Allocator {
u8 chunk_state = m->chunk_state;
if (chunk_state != CHUNK_ALLOCATED)
ReportInvalidFree(old_ptr, chunk_state, stack);
- CHECK_NE(REAL(memcpy), (void*)0);
+ CHECK_NE(REAL(memcpy), nullptr);
uptr memcpy_size = Min(new_size, m->UsedSize());
// If realloc() races with free(), we may start copying freed memory.
// However, we will report racy double-free later anyway.
@@ -579,7 +579,7 @@ struct Allocator {
// Assumes alloc_beg == allocator.GetBlockBegin(alloc_beg).
AsanChunk *GetAsanChunk(void *alloc_beg) {
- if (!alloc_beg) return 0;
+ if (!alloc_beg) return nullptr;
if (!allocator.FromPrimary(alloc_beg)) {
uptr *meta = reinterpret_cast<uptr *>(allocator.GetMetaData(alloc_beg));
AsanChunk *m = reinterpret_cast<AsanChunk *>(meta[1]);
@@ -619,7 +619,7 @@ struct Allocator {
// The address is in the chunk's left redzone, so maybe it is actually
// a right buffer overflow from the other chunk to the left.
// Search a bit to the left to see if there is another chunk.
- AsanChunk *m2 = 0;
+ AsanChunk *m2 = nullptr;
for (uptr l = 1; l < GetPageSizeCached(); l++) {
m2 = GetAsanChunkByAddr(addr - l);
if (m2 == m1) continue; // Still the same chunk.
@@ -653,7 +653,7 @@ static AsanAllocator &get_allocator() {
}
bool AsanChunkView::IsValid() {
- return chunk_ != 0 && chunk_->chunk_state != CHUNK_AVAILABLE;
+ return chunk_ && chunk_->chunk_state != CHUNK_AVAILABLE;
}
uptr AsanChunkView::Beg() { return chunk_->Beg(); }
uptr AsanChunkView::End() { return Beg() + UsedSize(); }
@@ -723,11 +723,11 @@ void *asan_calloc(uptr nmemb, uptr size, BufferedStackTrace *stack) {
}
void *asan_realloc(void *p, uptr size, BufferedStackTrace *stack) {
- if (p == 0)
+ if (!p)
return instance.Allocate(size, 8, stack, FROM_MALLOC, true);
if (size == 0) {
instance.Deallocate(p, 0, stack, FROM_MALLOC);
- return 0;
+ return nullptr;
}
return instance.Reallocate(p, size, stack);
}
@@ -755,7 +755,7 @@ int asan_posix_memalign(void **memptr, uptr alignment, uptr size,
}
uptr asan_malloc_usable_size(void *ptr, uptr pc, uptr bp) {
- if (ptr == 0) return 0;
+ if (!ptr) return 0;
uptr usable_size = instance.AllocationSize(reinterpret_cast<uptr>(ptr));
if (flags()->check_malloc_usable_size && (usable_size == 0)) {
GET_STACK_TRACE_FATAL(pc, bp);
@@ -780,7 +780,7 @@ void AsanSoftRssLimitExceededCallback(bool exceeded) {
instance.allocator.SetRssLimitIsExceeded(exceeded);
}
-} // namespace __asan
+} // namespace __asan
// --- Implementation of LSan-specific functions --- {{{1
namespace __lsan {
@@ -881,7 +881,7 @@ int __sanitizer_get_ownership(const void *p) {
}
uptr __sanitizer_get_allocated_size(const void *p) {
- if (p == 0) return 0;
+ if (!p) return 0;
uptr ptr = reinterpret_cast<uptr>(p);
uptr allocated_size = instance.AllocationSize(ptr);
// Die if p is not malloced or if it is already freed.
@@ -904,5 +904,5 @@ SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
void __sanitizer_free_hook(void *ptr) {
(void)ptr;
}
-} // extern "C"
+} // extern "C"
#endif
diff --git a/contrib/compiler-rt/lib/asan/asan_allocator.h b/contrib/compiler-rt/lib/asan/asan_allocator.h
index 5ccd00c97bab..e3d53330cd2f 100644
--- a/contrib/compiler-rt/lib/asan/asan_allocator.h
+++ b/contrib/compiler-rt/lib/asan/asan_allocator.h
@@ -114,6 +114,11 @@ struct AsanMapUnmapCallback {
# if defined(__powerpc64__)
const uptr kAllocatorSpace = 0xa0000000000ULL;
const uptr kAllocatorSize = 0x20000000000ULL; // 2T.
+# elif defined(__aarch64__)
+// AArch64/SANITIZIER_CAN_USER_ALLOCATOR64 is only for 42-bit VMA
+// so no need to different values for different VMA.
+const uptr kAllocatorSpace = 0x10000000000ULL;
+const uptr kAllocatorSize = 0x10000000000ULL; // 3T.
# else
const uptr kAllocatorSpace = 0x600000000000ULL;
const uptr kAllocatorSize = 0x40000000000ULL; // 4T.
diff --git a/contrib/compiler-rt/lib/asan/asan_debugging.cc b/contrib/compiler-rt/lib/asan/asan_debugging.cc
index 6fc5b690de99..7c3a8a73bd4e 100644
--- a/contrib/compiler-rt/lib/asan/asan_debugging.cc
+++ b/contrib/compiler-rt/lib/asan/asan_debugging.cc
@@ -108,14 +108,14 @@ static uptr AsanGetStack(uptr addr, uptr *trace, u32 size, u32 *thread_id,
return 0;
}
-} // namespace __asan
+} // namespace __asan
using namespace __asan;
SANITIZER_INTERFACE_ATTRIBUTE
const char *__asan_locate_address(uptr addr, char *name, uptr name_size,
uptr *region_address, uptr *region_size) {
- AddressDescription descr = { name, name_size, 0, 0, 0 };
+ AddressDescription descr = { name, name_size, 0, 0, nullptr };
AsanLocateAddress(addr, &descr);
if (region_address) *region_address = descr.region_address;
if (region_size) *region_size = descr.region_size;
diff --git a/contrib/compiler-rt/lib/asan/asan_fake_stack.cc b/contrib/compiler-rt/lib/asan/asan_fake_stack.cc
index d20641155b88..91fdf0aa1dca 100644
--- a/contrib/compiler-rt/lib/asan/asan_fake_stack.cc
+++ b/contrib/compiler-rt/lib/asan/asan_fake_stack.cc
@@ -11,6 +11,7 @@
//
// FakeStack is used to detect use-after-return bugs.
//===----------------------------------------------------------------------===//
+
#include "asan_allocator.h"
#include "asan_poisoning.h"
#include "asan_thread.h"
@@ -32,7 +33,8 @@ ALWAYS_INLINE void SetShadow(uptr ptr, uptr size, uptr class_id, u64 magic) {
if (class_id <= 6) {
for (uptr i = 0; i < (1U << class_id); i++) {
shadow[i] = magic;
- SanitizerBreakOptimization(0); // Make sure this does not become memset.
+ // Make sure this does not become memset.
+ SanitizerBreakOptimization(nullptr);
}
} else {
// The size class is too big, it's cheaper to poison only size bytes.
@@ -80,7 +82,9 @@ void FakeStack::PoisonAll(u8 magic) {
magic);
}
+#if !defined(_MSC_VER) || defined(__clang__)
ALWAYS_INLINE USED
+#endif
FakeFrame *FakeStack::Allocate(uptr stack_size_log, uptr class_id,
uptr real_stack) {
CHECK_LT(class_id, kNumberOfSizeClasses);
@@ -106,7 +110,7 @@ FakeFrame *FakeStack::Allocate(uptr stack_size_log, uptr class_id,
*SavedFlagPtr(reinterpret_cast<uptr>(res), class_id) = &flags[pos];
return res;
}
- return 0; // We are out of fake stack.
+ return nullptr; // We are out of fake stack.
}
uptr FakeStack::AddrIsInFakeStack(uptr ptr, uptr *frame_beg, uptr *frame_end) {
@@ -183,7 +187,7 @@ void SetTLSFakeStack(FakeStack *fs) { }
static FakeStack *GetFakeStack() {
AsanThread *t = GetCurrentThread();
- if (!t) return 0;
+ if (!t) return nullptr;
return t->fake_stack();
}
@@ -191,7 +195,7 @@ static FakeStack *GetFakeStackFast() {
if (FakeStack *fs = GetTLSFakeStack())
return fs;
if (!__asan_option_detect_stack_use_after_return)
- return 0;
+ return nullptr;
return GetFakeStack();
}
@@ -212,7 +216,7 @@ ALWAYS_INLINE void OnFree(uptr ptr, uptr class_id, uptr size) {
SetShadow(ptr, size, class_id, kMagic8);
}
-} // namespace __asan
+} // namespace __asan
// ---------------------- Interface ---------------- {{{1
using namespace __asan;
@@ -245,13 +249,13 @@ SANITIZER_INTERFACE_ATTRIBUTE
void *__asan_addr_is_in_fake_stack(void *fake_stack, void *addr, void **beg,
void **end) {
FakeStack *fs = reinterpret_cast<FakeStack*>(fake_stack);
- if (!fs) return 0;
+ if (!fs) return nullptr;
uptr frame_beg, frame_end;
FakeFrame *frame = reinterpret_cast<FakeFrame *>(fs->AddrIsInFakeStack(
reinterpret_cast<uptr>(addr), &frame_beg, &frame_end));
- if (!frame) return 0;
+ if (!frame) return nullptr;
if (frame->magic != kCurrentStackFrameMagic)
- return 0;
+ return nullptr;
if (beg) *beg = reinterpret_cast<void*>(frame_beg);
if (end) *end = reinterpret_cast<void*>(frame_end);
return reinterpret_cast<void*>(frame->real_stack);
@@ -276,4 +280,4 @@ void __asan_allocas_unpoison(uptr top, uptr bottom) {
REAL(memset)(reinterpret_cast<void*>(MemToShadow(top)), 0,
(bottom - top) / SHADOW_GRANULARITY);
}
-} // extern "C"
+} // extern "C"
diff --git a/contrib/compiler-rt/lib/asan/asan_flags.cc b/contrib/compiler-rt/lib/asan/asan_flags.cc
index e8ea549b62e3..363ee67e77c6 100644
--- a/contrib/compiler-rt/lib/asan/asan_flags.cc
+++ b/contrib/compiler-rt/lib/asan/asan_flags.cc
@@ -65,6 +65,7 @@ void InitializeFlags() {
cf.external_symbolizer_path = GetEnv("ASAN_SYMBOLIZER_PATH");
cf.malloc_context_size = kDefaultMallocContextSize;
cf.intercept_tls_get_addr = true;
+ cf.exitcode = 1;
OverrideCommonFlags(cf);
}
Flags *f = flags();
@@ -115,14 +116,6 @@ void InitializeFlags() {
ubsan_parser.ParseString(GetEnv("UBSAN_OPTIONS"));
#endif
- // Let activation flags override current settings. On Android they come
- // from a system property. On other platforms this is no-op.
- if (!flags()->start_deactivated) {
- char buf[100];
- GetExtraActivationFlags(buf, sizeof(buf));
- asan_parser.ParseString(buf);
- }
-
SetVerbosity(common_flags()->verbosity);
// TODO(eugenis): dump all flags at verbosity>=2?
diff --git a/contrib/compiler-rt/lib/asan/asan_flags.inc b/contrib/compiler-rt/lib/asan/asan_flags.inc
index 53a8a4039e7e..5e69242fb8e9 100644
--- a/contrib/compiler-rt/lib/asan/asan_flags.inc
+++ b/contrib/compiler-rt/lib/asan/asan_flags.inc
@@ -44,9 +44,6 @@ ASAN_FLAG(
"to find more errors.")
ASAN_FLAG(bool, replace_intrin, true,
"If set, uses custom wrappers for memset/memcpy/memmove intinsics.")
-ASAN_FLAG(bool, mac_ignore_invalid_free, false,
- "Ignore invalid free() calls to work around some bugs. Used on OS X "
- "only.")
ASAN_FLAG(bool, detect_stack_use_after_return, false,
"Enables stack-use-after-return checking at run-time.")
ASAN_FLAG(int, min_uar_stack_size_log, 16, // We can't do smaller anyway.
@@ -62,8 +59,6 @@ ASAN_FLAG(
"bytes that will be filled with malloc_fill_byte on malloc.")
ASAN_FLAG(int, malloc_fill_byte, 0xbe,
"Value used to fill the newly allocated memory.")
-ASAN_FLAG(int, exitcode, ASAN_DEFAULT_FAILURE_EXITCODE,
- "Override the program exit status if the tool found an error.")
ASAN_FLAG(bool, allow_user_poisoning, true,
"If set, user may manually mark memory regions as poisoned or "
"unpoisoned.")
@@ -77,10 +72,7 @@ ASAN_FLAG(bool, check_malloc_usable_size, true,
"295.*.")
ASAN_FLAG(bool, unmap_shadow_on_exit, false,
"If set, explicitly unmaps the (huge) shadow at exit.")
-ASAN_FLAG(
- bool, abort_on_error, false,
- "If set, the tool calls abort() instead of _exit() after printing the "
- "error report.")
+ASAN_FLAG(bool, protect_shadow_gap, true, "If set, mprotect the shadow gap")
ASAN_FLAG(bool, print_stats, false,
"Print various statistics after printing an error message or if "
"atexit=1.")
@@ -104,8 +96,8 @@ ASAN_FLAG(bool, poison_array_cookie, true,
"Poison (or not) the array cookie after operator new[].")
// Turn off alloc/dealloc mismatch checker on Mac and Windows for now.
-// https://code.google.com/p/address-sanitizer/issues/detail?id=131
-// https://code.google.com/p/address-sanitizer/issues/detail?id=309
+// https://github.com/google/sanitizers/issues/131
+// https://github.com/google/sanitizers/issues/309
// TODO(glider,timurrrr): Fix known issues and enable this back.
ASAN_FLAG(bool, alloc_dealloc_mismatch,
(SANITIZER_MAC == 0) && (SANITIZER_WINDOWS == 0),
@@ -113,9 +105,6 @@ ASAN_FLAG(bool, alloc_dealloc_mismatch,
ASAN_FLAG(bool, new_delete_type_mismatch, true,
"Report errors on mismatch betwen size of new and delete.")
-ASAN_FLAG(bool, strict_memcmp, true,
- "If true, assume that memcmp(p1, p2, n) always reads n bytes before "
- "comparing p1 and p2.")
ASAN_FLAG(
bool, strict_init_order, false,
"If true, assume that dynamic initializers can never access globals from "
@@ -134,8 +123,8 @@ ASAN_FLAG(
"The bigger the value the harder we try.")
ASAN_FLAG(
bool, detect_container_overflow, true,
- "If true, honor the container overflow annotations. "
- "See https://code.google.com/p/address-sanitizer/wiki/ContainerOverflow")
+ "If true, honor the container overflow annotations. See "
+ "https://github.com/google/sanitizers/wiki/AddressSanitizerContainerOverflow")
ASAN_FLAG(int, detect_odr_violation, 2,
"If >=2, detect violation of One-Definition-Rule (ODR); "
"If ==1, detect ODR-violation only if the two variables "
@@ -143,3 +132,6 @@ ASAN_FLAG(int, detect_odr_violation, 2,
ASAN_FLAG(bool, dump_instruction_bytes, false,
"If true, dump 16 bytes starting at the instruction that caused SEGV")
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!)")
diff --git a/contrib/compiler-rt/lib/asan/asan_globals.cc b/contrib/compiler-rt/lib/asan/asan_globals.cc
index c34b1d3cedf2..eb9f1bfefec2 100644
--- a/contrib/compiler-rt/lib/asan/asan_globals.cc
+++ b/contrib/compiler-rt/lib/asan/asan_globals.cc
@@ -11,6 +11,7 @@
//
// Handle globals.
//===----------------------------------------------------------------------===//
+
#include "asan_interceptors.h"
#include "asan_internal.h"
#include "asan_mapping.h"
@@ -167,7 +168,7 @@ static void RegisterGlobal(const Global *g) {
l->next = list_of_all_globals;
list_of_all_globals = l;
if (g->has_dynamic_init) {
- if (dynamic_init_globals == 0) {
+ if (!dynamic_init_globals) {
dynamic_init_globals = new(allocator_for_globals)
VectorOfGlobals(kDynamicInitGlobalsInitialCapacity);
}
@@ -206,7 +207,7 @@ void StopInitOrderChecking() {
}
}
-} // namespace __asan
+} // namespace __asan
// ---------------------- Interface ---------------- {{{1
using namespace __asan; // NOLINT
diff --git a/contrib/compiler-rt/lib/asan/asan_init_version.h b/contrib/compiler-rt/lib/asan/asan_init_version.h
index 6cf57c4aa2a8..bc8a622f5bb1 100644
--- a/contrib/compiler-rt/lib/asan/asan_init_version.h
+++ b/contrib/compiler-rt/lib/asan/asan_init_version.h
@@ -27,8 +27,8 @@ extern "C" {
// v3=>v4: added '__asan_global_source_location' to __asan_global.
// v4=>v5: changed the semantics and format of __asan_stack_malloc_ and
// __asan_stack_free_ functions.
- #define __asan_init __asan_init_v5
- #define __asan_init_name "__asan_init_v5"
+ // v5=>v6: changed the name of the version check symbol
+ #define __asan_version_mismatch_check __asan_version_mismatch_check_v6
}
#endif // ASAN_INIT_VERSION_H
diff --git a/contrib/compiler-rt/lib/asan/asan_interceptors.cc b/contrib/compiler-rt/lib/asan/asan_interceptors.cc
index d8b48d391ab8..d9a0c71a002d 100644
--- a/contrib/compiler-rt/lib/asan/asan_interceptors.cc
+++ b/contrib/compiler-rt/lib/asan/asan_interceptors.cc
@@ -11,8 +11,8 @@
//
// Intercept various libc functions.
//===----------------------------------------------------------------------===//
-#include "asan_interceptors.h"
+#include "asan_interceptors.h"
#include "asan_allocator.h"
#include "asan_internal.h"
#include "asan_mapping.h"
@@ -27,6 +27,12 @@
#include "sanitizer_common/sanitizer_posix.h"
#endif
+#if defined(__i386) && SANITIZER_LINUX
+#define ASAN_PTHREAD_CREATE_VERSION "GLIBC_2.1"
+#elif defined(__mips__) && SANITIZER_LINUX
+#define ASAN_PTHREAD_CREATE_VERSION "GLIBC_2.2"
+#endif
+
namespace __asan {
// Return true if we can quickly decide that the region is unpoisoned.
@@ -69,7 +75,7 @@ struct AsanInterceptorContext {
} \
if (!suppressed) { \
GET_CURRENT_PC_BP_SP; \
- __asan_report_error(pc, bp, sp, __bad, isWrite, __size, 0); \
+ ReportGenericError(pc, bp, sp, __bad, isWrite, __size, 0, false);\
} \
} \
} while (0)
@@ -105,7 +111,7 @@ static inline bool RangesOverlap(const char *offset1, uptr length1,
static inline uptr MaybeRealStrnlen(const char *s, uptr maxlen) {
#if ASAN_INTERCEPT_STRNLEN
- if (REAL(strnlen) != 0) {
+ if (REAL(strnlen)) {
return REAL(strnlen)(s, maxlen);
}
#endif
@@ -123,7 +129,7 @@ int OnExit() {
return 0;
}
-} // namespace __asan
+} // namespace __asan
// ---------------------- Wrappers ---------------- {{{1
using namespace __asan; // NOLINT
@@ -172,7 +178,7 @@ DECLARE_REAL_AND_INTERCEPTOR(void, free, void *)
} while (false)
#define COMMON_INTERCEPTOR_BLOCK_REAL(name) REAL(name)
// Strict init-order checking is dlopen-hostile:
-// https://code.google.com/p/address-sanitizer/issues/detail?id=178
+// https://github.com/google/sanitizers/issues/178
#define COMMON_INTERCEPTOR_ON_DLOPEN(filename, flag) \
if (flags()->strict_init_order) { \
StopInitOrderChecking(); \
@@ -216,7 +222,7 @@ static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) {
ThreadStartParam *param = reinterpret_cast<ThreadStartParam *>(arg);
AsanThread *t = nullptr;
while ((t = reinterpret_cast<AsanThread *>(
- atomic_load(&param->t, memory_order_acquire))) == 0)
+ atomic_load(&param->t, memory_order_acquire))) == nullptr)
internal_sched_yield();
SetCurrentThread(t);
return t->ThreadStart(GetTid(), &param->is_registered);
@@ -231,7 +237,7 @@ INTERCEPTOR(int, pthread_create, void *thread,
StopInitOrderChecking();
GET_STACK_TRACE_THREAD;
int detached = 0;
- if (attr != 0)
+ if (attr)
REAL(pthread_attr_getdetachstate)(attr, &detached);
ThreadStartParam param;
atomic_store(&param.t, 0, memory_order_relaxed);
@@ -270,14 +276,14 @@ INTERCEPTOR(void*, bsd_signal, int signum, void *handler) {
}
return 0;
}
-#else
+#endif
+
INTERCEPTOR(void*, signal, int signum, void *handler) {
if (!IsDeadlySignal(signum) || common_flags()->allow_user_segv_handler) {
return REAL(signal)(signum, handler);
}
- return 0;
+ return nullptr;
}
-#endif
INTERCEPTOR(int, sigaction, int signum, const struct sigaction *act,
struct sigaction *oldact) {
@@ -292,7 +298,7 @@ int real_sigaction(int signum, const void *act, void *oldact) {
return REAL(sigaction)(signum, (const struct sigaction *)act,
(struct sigaction *)oldact);
}
-} // namespace __sanitizer
+} // namespace __sanitizer
#elif SANITIZER_POSIX
// We need to have defined REAL(sigaction) on posix systems.
@@ -363,40 +369,6 @@ INTERCEPTOR(void, __cxa_throw, void *a, void *b, void *c) {
}
#endif
-static inline int CharCmp(unsigned char c1, unsigned char c2) {
- return (c1 == c2) ? 0 : (c1 < c2) ? -1 : 1;
-}
-
-INTERCEPTOR(int, memcmp, const void *a1, const void *a2, uptr size) {
- void *ctx;
- ASAN_INTERCEPTOR_ENTER(ctx, memcmp);
- if (UNLIKELY(!asan_inited)) return internal_memcmp(a1, a2, size);
- ENSURE_ASAN_INITED();
- if (flags()->replace_intrin) {
- if (flags()->strict_memcmp) {
- // Check the entire regions even if the first bytes of the buffers are
- // different.
- ASAN_READ_RANGE(ctx, a1, size);
- ASAN_READ_RANGE(ctx, a2, size);
- // Fallthrough to REAL(memcmp) below.
- } else {
- unsigned char c1 = 0, c2 = 0;
- const unsigned char *s1 = (const unsigned char*)a1;
- const unsigned char *s2 = (const unsigned char*)a2;
- uptr i;
- for (i = 0; i < size; i++) {
- c1 = s1[i];
- c2 = s2[i];
- if (c1 != c2) break;
- }
- ASAN_READ_RANGE(ctx, s1, Min(i + 1, size));
- ASAN_READ_RANGE(ctx, s2, Min(i + 1, size));
- return CharCmp(c1, c2);
- }
- }
- return REAL(memcmp(a1, a2, size));
-}
-
// memcpy is called during __asan_init() from the internals of printf(...).
// We do not treat memcpy with to==from as a bug.
// See http://llvm.org/bugs/show_bug.cgi?id=11763.
@@ -743,7 +715,7 @@ INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg,
#endif
ENSURE_ASAN_INITED();
int res = REAL(__cxa_atexit)(func, arg, dso_handle);
- REAL(__cxa_atexit)(AtCxaAtexit, 0, 0);
+ REAL(__cxa_atexit)(AtCxaAtexit, nullptr, nullptr);
return res;
}
#endif // ASAN_INTERCEPT___CXA_ATEXIT
@@ -767,7 +739,6 @@ void InitializeAsanInterceptors() {
InitializeCommonInterceptors();
// Intercept mem* functions.
- ASAN_INTERCEPT_FUNC(memcmp);
ASAN_INTERCEPT_FUNC(memmove);
ASAN_INTERCEPT_FUNC(memset);
if (PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE) {
@@ -806,9 +777,8 @@ void InitializeAsanInterceptors() {
ASAN_INTERCEPT_FUNC(sigaction);
#if SANITIZER_ANDROID
ASAN_INTERCEPT_FUNC(bsd_signal);
-#else
- ASAN_INTERCEPT_FUNC(signal);
#endif
+ ASAN_INTERCEPT_FUNC(signal);
#endif
#if ASAN_INTERCEPT_SWAPCONTEXT
ASAN_INTERCEPT_FUNC(swapcontext);
@@ -827,7 +797,11 @@ void InitializeAsanInterceptors() {
// Intercept threading-related functions
#if ASAN_INTERCEPT_PTHREAD_CREATE
+#if defined(ASAN_PTHREAD_CREATE_VERSION)
+ ASAN_INTERCEPT_FUNC_VER(pthread_create, ASAN_PTHREAD_CREATE_VERSION);
+#else
ASAN_INTERCEPT_FUNC(pthread_create);
+#endif
ASAN_INTERCEPT_FUNC(pthread_join);
#endif
@@ -845,4 +819,4 @@ void InitializeAsanInterceptors() {
VReport(1, "AddressSanitizer: libc interceptors initialized\n");
}
-} // namespace __asan
+} // namespace __asan
diff --git a/contrib/compiler-rt/lib/asan/asan_interceptors.h b/contrib/compiler-rt/lib/asan/asan_interceptors.h
index 488ada78ab8b..279c5f38451f 100644
--- a/contrib/compiler-rt/lib/asan/asan_interceptors.h
+++ b/contrib/compiler-rt/lib/asan/asan_interceptors.h
@@ -98,6 +98,12 @@ DECLARE_REAL(int, sigaction, int signum, const struct sigaction *act,
if ((!INTERCEPT_FUNCTION(name) || !REAL(name))) \
VReport(1, "AddressSanitizer: failed to intercept '" #name "'\n"); \
} while (0)
+#define ASAN_INTERCEPT_FUNC_VER(name, ver) \
+ do { \
+ if ((!INTERCEPT_FUNCTION_VER(name, ver) || !REAL(name))) \
+ VReport( \
+ 1, "AddressSanitizer: failed to intercept '" #name "@@" #ver "'\n"); \
+ } while (0)
#else
// OS X interceptors don't need to be initialized with INTERCEPT_FUNCTION.
#define ASAN_INTERCEPT_FUNC(name)
diff --git a/contrib/compiler-rt/lib/asan/asan_interface_internal.h b/contrib/compiler-rt/lib/asan/asan_interface_internal.h
index ad8ebcd91ad9..9efddcbd42b2 100644
--- a/contrib/compiler-rt/lib/asan/asan_interface_internal.h
+++ b/contrib/compiler-rt/lib/asan/asan_interface_internal.h
@@ -27,10 +27,14 @@ using __sanitizer::uptr;
extern "C" {
// This function should be called at the very beginning of the process,
// before any instrumented code is executed and before any call to malloc.
- // Please note that __asan_init is a macro that is replaced with
- // __asan_init_vXXX at compile-time.
SANITIZER_INTERFACE_ATTRIBUTE void __asan_init();
+ // This function exists purely to get a linker/loader error when using
+ // incompatible versions of instrumentation and runtime library. Please note
+ // that __asan_version_mismatch_check is a macro that is replaced with
+ // __asan_version_mismatch_check_vXXX at compile-time.
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_version_mismatch_check();
+
// This structure is used to describe the source location of a place where
// global was defined.
struct __asan_global_source_location {
@@ -131,8 +135,6 @@ extern "C" {
uptr addr, int is_write, uptr access_size, u32 exp);
SANITIZER_INTERFACE_ATTRIBUTE
- int __asan_set_error_exit_code(int exit_code);
- SANITIZER_INTERFACE_ATTRIBUTE
void __asan_set_death_callback(void (*callback)(void));
SANITIZER_INTERFACE_ATTRIBUTE
void __asan_set_error_report_callback(void (*callback)(const char*));
@@ -165,6 +167,19 @@ extern "C" {
SANITIZER_INTERFACE_ATTRIBUTE void __asan_loadN(uptr p, uptr size);
SANITIZER_INTERFACE_ATTRIBUTE void __asan_storeN(uptr p, uptr size);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_load1_noabort(uptr p);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_load2_noabort(uptr p);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_load4_noabort(uptr p);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_load8_noabort(uptr p);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_load16_noabort(uptr p);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_store1_noabort(uptr p);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_store2_noabort(uptr p);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_store4_noabort(uptr p);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_store8_noabort(uptr p);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_store16_noabort(uptr p);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_loadN_noabort(uptr p, uptr size);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_storeN_noabort(uptr p, uptr size);
+
SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_load1(uptr p, u32 exp);
SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_load2(uptr p, u32 exp);
SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_load4(uptr p, u32 exp);
diff --git a/contrib/compiler-rt/lib/asan/asan_internal.h b/contrib/compiler-rt/lib/asan/asan_internal.h
index 107e16ee31b9..0ef0d0eb5263 100644
--- a/contrib/compiler-rt/lib/asan/asan_internal.h
+++ b/contrib/compiler-rt/lib/asan/asan_internal.h
@@ -21,8 +21,6 @@
#include "sanitizer_common/sanitizer_stacktrace.h"
#include "sanitizer_common/sanitizer_libc.h"
-#define ASAN_DEFAULT_FAILURE_EXITCODE 1
-
#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
# error "The AddressSanitizer run-time should not be"
" instrumented by AddressSanitizer"
@@ -75,12 +73,9 @@ void *AsanDoesNotSupportStaticLinkage();
void AsanCheckDynamicRTPrereqs();
void AsanCheckIncompatibleRT();
-void AsanOnSIGSEGV(int, void *siginfo, void *context);
+void AsanOnDeadlySignal(int, void *siginfo, void *context);
-void DisableReexec();
-void MaybeReexec();
void ReadContextStack(void *context, uptr *stack, uptr *ssize);
-void AsanPlatformThreadInit();
void StopInitOrderChecking();
// Wrapper for TLS/TSD.
diff --git a/contrib/compiler-rt/lib/asan/asan_linux.cc b/contrib/compiler-rt/lib/asan/asan_linux.cc
index 9580fc7c06d4..e26b400562df 100644
--- a/contrib/compiler-rt/lib/asan/asan_linux.cc
+++ b/contrib/compiler-rt/lib/asan/asan_linux.cc
@@ -70,14 +70,6 @@ namespace __asan {
void InitializePlatformInterceptors() {}
-void DisableReexec() {
- // No need to re-exec on Linux.
-}
-
-void MaybeReexec() {
- // No need to re-exec on Linux.
-}
-
void *AsanDoesNotSupportStaticLinkage() {
// This will fail to link with -static.
return &_DYNAMIC; // defined in link.h
@@ -117,7 +109,7 @@ void AsanCheckDynamicRTPrereqs() {
return;
// Ensure that dynamic RT is the first DSO in the list
- const char *first_dso_name = 0;
+ const char *first_dso_name = nullptr;
dl_iterate_phdr(FindFirstDSOCallback, &first_dso_name);
if (first_dso_name && !IsDynamicRTName(first_dso_name)) {
Report("ASan runtime does not come first in initial library list; "
@@ -142,7 +134,8 @@ void AsanCheckIncompatibleRT() {
// system libraries, causing crashes later in ASan initialization.
MemoryMappingLayout proc_maps(/*cache_enabled*/true);
char filename[128];
- while (proc_maps.Next(0, 0, 0, filename, sizeof(filename), 0)) {
+ while (proc_maps.Next(nullptr, nullptr, nullptr, filename,
+ sizeof(filename), nullptr)) {
if (IsDynamicRTName(filename)) {
Report("Your application is linked against "
"incompatible ASan runtimes.\n");
@@ -155,11 +148,7 @@ void AsanCheckIncompatibleRT() {
}
}
}
-#endif // SANITIZER_ANDROID
-
-void AsanPlatformThreadInit() {
- // Nothing here for now.
-}
+#endif // SANITIZER_ANDROID
#if !SANITIZER_ANDROID
void ReadContextStack(void *context, uptr *stack, uptr *ssize) {
@@ -177,6 +166,6 @@ void *AsanDlSymNext(const char *sym) {
return dlsym(RTLD_NEXT, sym);
}
-} // namespace __asan
+} // namespace __asan
-#endif // SANITIZER_FREEBSD || SANITIZER_LINUX
+#endif // SANITIZER_FREEBSD || SANITIZER_LINUX
diff --git a/contrib/compiler-rt/lib/asan/asan_mac.cc b/contrib/compiler-rt/lib/asan/asan_mac.cc
index 3e028378df28..f00d98f8e5e6 100644
--- a/contrib/compiler-rt/lib/asan/asan_mac.cc
+++ b/contrib/compiler-rt/lib/asan/asan_mac.cc
@@ -24,26 +24,17 @@
#include "sanitizer_common/sanitizer_libc.h"
#include "sanitizer_common/sanitizer_mac.h"
-#if !SANITIZER_IOS
-#include <crt_externs.h> // for _NSGetArgv and _NSGetEnviron
-#else
-extern "C" {
- extern char ***_NSGetArgv(void);
-}
-#endif
-
-#include <dlfcn.h> // for dladdr()
+#include <fcntl.h>
+#include <libkern/OSAtomic.h>
#include <mach-o/dyld.h>
#include <mach-o/loader.h>
+#include <pthread.h>
+#include <stdlib.h> // for free()
#include <sys/mman.h>
#include <sys/resource.h>
#include <sys/sysctl.h>
#include <sys/ucontext.h>
-#include <fcntl.h>
-#include <pthread.h>
-#include <stdlib.h> // for free()
#include <unistd.h>
-#include <libkern/OSAtomic.h>
namespace __asan {
@@ -52,187 +43,12 @@ void InitializePlatformInterceptors() {}
bool PlatformHasDifferentMemcpyAndMemmove() {
// On OS X 10.7 memcpy() and memmove() are both resolved
// into memmove$VARIANT$sse42.
- // See also http://code.google.com/p/address-sanitizer/issues/detail?id=34.
+ // See also https://github.com/google/sanitizers/issues/34.
// TODO(glider): need to check dynamically that memcpy() and memmove() are
// actually the same function.
return GetMacosVersion() == MACOS_VERSION_SNOW_LEOPARD;
}
-extern "C"
-void __asan_init();
-
-static const char kDyldInsertLibraries[] = "DYLD_INSERT_LIBRARIES";
-LowLevelAllocator allocator_for_env;
-
-// Change the value of the env var |name|, leaking the original value.
-// If |name_value| is NULL, the variable is deleted from the environment,
-// otherwise the corresponding "NAME=value" string is replaced with
-// |name_value|.
-void LeakyResetEnv(const char *name, const char *name_value) {
- char **env = GetEnviron();
- uptr name_len = internal_strlen(name);
- while (*env != 0) {
- uptr len = internal_strlen(*env);
- if (len > name_len) {
- const char *p = *env;
- if (!internal_memcmp(p, name, name_len) && p[name_len] == '=') {
- // Match.
- if (name_value) {
- // Replace the old value with the new one.
- *env = const_cast<char*>(name_value);
- } else {
- // Shift the subsequent pointers back.
- char **del = env;
- do {
- del[0] = del[1];
- } while (*del++);
- }
- }
- }
- env++;
- }
-}
-
-static bool reexec_disabled = false;
-
-void DisableReexec() {
- reexec_disabled = true;
-}
-
-bool DyldNeedsEnvVariable() {
-// If running on OS X 10.11+ or iOS 9.0+, dyld will interpose even if
-// DYLD_INSERT_LIBRARIES is not set.
-
-#if SANITIZER_IOSSIM
- // GetMacosVersion will not work for the simulator, whose kernel version
- // is tied to the host. Use a weak linking hack for the simulator.
- // This API was introduced in the same version of the OS as the dyld
- // optimization.
-
- // Check for presence of a symbol that is available on OS X 10.11+, iOS 9.0+.
- return (dlsym(RTLD_NEXT, "mach_memory_info") == nullptr);
-#else
- return (GetMacosVersion() <= MACOS_VERSION_YOSEMITE);
-#endif
-}
-
-void MaybeReexec() {
- if (reexec_disabled) return;
-
- // Make sure the dynamic ASan runtime library is preloaded so that the
- // wrappers work. If it is not, set DYLD_INSERT_LIBRARIES and re-exec
- // ourselves.
- Dl_info info;
- CHECK(dladdr((void*)((uptr)__asan_init), &info));
- char *dyld_insert_libraries =
- const_cast<char*>(GetEnv(kDyldInsertLibraries));
- uptr old_env_len = dyld_insert_libraries ?
- internal_strlen(dyld_insert_libraries) : 0;
- uptr fname_len = internal_strlen(info.dli_fname);
- const char *dylib_name = StripModuleName(info.dli_fname);
- uptr dylib_name_len = internal_strlen(dylib_name);
-
- bool lib_is_in_env =
- dyld_insert_libraries && REAL(strstr)(dyld_insert_libraries, dylib_name);
- if (DyldNeedsEnvVariable() && !lib_is_in_env) {
- // DYLD_INSERT_LIBRARIES is not set or does not contain the runtime
- // library.
- char program_name[1024];
- uint32_t buf_size = sizeof(program_name);
- _NSGetExecutablePath(program_name, &buf_size);
- char *new_env = const_cast<char*>(info.dli_fname);
- if (dyld_insert_libraries) {
- // Append the runtime dylib name to the existing value of
- // DYLD_INSERT_LIBRARIES.
- new_env = (char*)allocator_for_env.Allocate(old_env_len + fname_len + 2);
- internal_strncpy(new_env, dyld_insert_libraries, old_env_len);
- new_env[old_env_len] = ':';
- // Copy fname_len and add a trailing zero.
- internal_strncpy(new_env + old_env_len + 1, info.dli_fname,
- fname_len + 1);
- // Ok to use setenv() since the wrappers don't depend on the value of
- // asan_inited.
- setenv(kDyldInsertLibraries, new_env, /*overwrite*/1);
- } else {
- // Set DYLD_INSERT_LIBRARIES equal to the runtime dylib name.
- setenv(kDyldInsertLibraries, info.dli_fname, /*overwrite*/0);
- }
- VReport(1, "exec()-ing the program with\n");
- VReport(1, "%s=%s\n", kDyldInsertLibraries, new_env);
- VReport(1, "to enable ASan wrappers.\n");
- execv(program_name, *_NSGetArgv());
-
- // We get here only if execv() failed.
- Report("ERROR: The process is launched without DYLD_INSERT_LIBRARIES, "
- "which is required for ASan to work. ASan tried to set the "
- "environment variable and re-execute itself, but execv() failed, "
- "possibly because of sandbox restrictions. Make sure to launch the "
- "executable with:\n%s=%s\n", kDyldInsertLibraries, new_env);
- CHECK("execv failed" && 0);
- }
-
- if (!lib_is_in_env)
- return;
-
- // DYLD_INSERT_LIBRARIES is set and contains the runtime library. Let's remove
- // the dylib from the environment variable, because interceptors are installed
- // and we don't want our children to inherit the variable.
-
- uptr env_name_len = internal_strlen(kDyldInsertLibraries);
- // Allocate memory to hold the previous env var name, its value, the '='
- // sign and the '\0' char.
- char *new_env = (char*)allocator_for_env.Allocate(
- old_env_len + 2 + env_name_len);
- CHECK(new_env);
- internal_memset(new_env, '\0', old_env_len + 2 + env_name_len);
- internal_strncpy(new_env, kDyldInsertLibraries, env_name_len);
- new_env[env_name_len] = '=';
- char *new_env_pos = new_env + env_name_len + 1;
-
- // Iterate over colon-separated pieces of |dyld_insert_libraries|.
- char *piece_start = dyld_insert_libraries;
- char *piece_end = NULL;
- char *old_env_end = dyld_insert_libraries + old_env_len;
- do {
- if (piece_start[0] == ':') piece_start++;
- piece_end = REAL(strchr)(piece_start, ':');
- if (!piece_end) piece_end = dyld_insert_libraries + old_env_len;
- if ((uptr)(piece_start - dyld_insert_libraries) > old_env_len) break;
- uptr piece_len = piece_end - piece_start;
-
- char *filename_start =
- (char *)internal_memrchr(piece_start, '/', piece_len);
- uptr filename_len = piece_len;
- if (filename_start) {
- filename_start += 1;
- filename_len = piece_len - (filename_start - piece_start);
- } else {
- filename_start = piece_start;
- }
-
- // If the current piece isn't the runtime library name,
- // append it to new_env.
- if ((dylib_name_len != filename_len) ||
- (internal_memcmp(filename_start, dylib_name, dylib_name_len) != 0)) {
- if (new_env_pos != new_env + env_name_len + 1) {
- new_env_pos[0] = ':';
- new_env_pos++;
- }
- internal_strncpy(new_env_pos, piece_start, piece_len);
- new_env_pos += piece_len;
- }
- // Move on to the next piece.
- piece_start = piece_end;
- } while (piece_start < old_env_end);
-
- // Can't use setenv() here, because it requires the allocator to be
- // initialized.
- // FIXME: instead of filtering DYLD_INSERT_LIBRARIES here, do it in
- // a separate function called after InitializeAllocator().
- if (new_env_pos == new_env + env_name_len + 1) new_env = NULL;
- LeakyResetEnv(kDyldInsertLibraries, new_env);
-}
-
// No-op. Mac does not support static linkage anyway.
void *AsanDoesNotSupportStaticLinkage() {
return 0;
@@ -244,9 +60,6 @@ void AsanCheckDynamicRTPrereqs() {}
// No-op. Mac does not support static linkage anyway.
void AsanCheckIncompatibleRT() {}
-void AsanPlatformThreadInit() {
-}
-
void ReadContextStack(void *context, uptr *stack, uptr *ssize) {
UNIMPLEMENTED();
}
diff --git a/contrib/compiler-rt/lib/asan/asan_malloc_linux.cc b/contrib/compiler-rt/lib/asan/asan_malloc_linux.cc
index 46a6a9db4a81..d5089f9f7b36 100644
--- a/contrib/compiler-rt/lib/asan/asan_malloc_linux.cc
+++ b/contrib/compiler-rt/lib/asan/asan_malloc_linux.cc
@@ -26,13 +26,25 @@
// ---------------------- Replacement functions ---------------- {{{1
using namespace __asan; // NOLINT
+static const uptr kCallocPoolSize = 1024;
+static uptr calloc_memory_for_dlsym[kCallocPoolSize];
+
+static bool IsInCallocPool(const void *ptr) {
+ sptr off = (sptr)ptr - (sptr)calloc_memory_for_dlsym;
+ return 0 <= off && off < (sptr)kCallocPoolSize;
+}
+
INTERCEPTOR(void, free, void *ptr) {
GET_STACK_TRACE_FREE;
+ if (UNLIKELY(IsInCallocPool(ptr)))
+ return;
asan_free(ptr, &stack, FROM_MALLOC);
}
INTERCEPTOR(void, cfree, void *ptr) {
GET_STACK_TRACE_FREE;
+ if (UNLIKELY(IsInCallocPool(ptr)))
+ return;
asan_free(ptr, &stack, FROM_MALLOC);
}
@@ -44,8 +56,6 @@ INTERCEPTOR(void*, malloc, uptr size) {
INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) {
if (UNLIKELY(!asan_inited)) {
// Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym.
- const uptr kCallocPoolSize = 1024;
- static uptr calloc_memory_for_dlsym[kCallocPoolSize];
static uptr allocated;
uptr size_in_words = ((nmemb * size) + kWordSize - 1) / kWordSize;
void *mem = (void*)&calloc_memory_for_dlsym[allocated];
@@ -59,6 +69,13 @@ INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) {
INTERCEPTOR(void*, realloc, void *ptr, uptr size) {
GET_STACK_TRACE_MALLOC;
+ if (UNLIKELY(IsInCallocPool(ptr))) {
+ uptr offset = (uptr)ptr - (uptr)calloc_memory_for_dlsym;
+ uptr copy_size = Min(size, kCallocPoolSize - offset);
+ void *new_ptr = asan_malloc(size, &stack);
+ internal_memcpy(new_ptr, ptr, copy_size);
+ return new_ptr;
+ }
return asan_realloc(ptr, size, &stack);
}
diff --git a/contrib/compiler-rt/lib/asan/asan_malloc_mac.cc b/contrib/compiler-rt/lib/asan/asan_malloc_mac.cc
index d7a6307c9bdc..744728d40df5 100644
--- a/contrib/compiler-rt/lib/asan/asan_malloc_mac.cc
+++ b/contrib/compiler-rt/lib/asan/asan_malloc_mac.cc
@@ -15,348 +15,47 @@
#include "sanitizer_common/sanitizer_platform.h"
#if SANITIZER_MAC
-#include <AvailabilityMacros.h>
-#include <CoreFoundation/CFBase.h>
-#include <dlfcn.h>
-#include <malloc/malloc.h>
-#include <sys/mman.h>
-
-#include "asan_allocator.h"
#include "asan_interceptors.h"
-#include "asan_internal.h"
#include "asan_report.h"
#include "asan_stack.h"
#include "asan_stats.h"
-#include "sanitizer_common/sanitizer_mac.h"
-
-// Similar code is used in Google Perftools,
-// http://code.google.com/p/google-perftools.
-
-// ---------------------- Replacement functions ---------------- {{{1
-using namespace __asan; // NOLINT
-
-// TODO(glider): do we need both zones?
-static malloc_zone_t *system_malloc_zone = 0;
-static malloc_zone_t asan_zone;
-
-INTERCEPTOR(malloc_zone_t *, malloc_create_zone,
- vm_size_t start_size, unsigned zone_flags) {
- ENSURE_ASAN_INITED();
- GET_STACK_TRACE_MALLOC;
- uptr page_size = GetPageSizeCached();
- uptr allocated_size = RoundUpTo(sizeof(asan_zone), page_size);
- malloc_zone_t *new_zone =
- (malloc_zone_t*)asan_memalign(page_size, allocated_size,
- &stack, FROM_MALLOC);
- internal_memcpy(new_zone, &asan_zone, sizeof(asan_zone));
- new_zone->zone_name = NULL; // The name will be changed anyway.
- if (GetMacosVersion() >= MACOS_VERSION_LION) {
- // Prevent the client app from overwriting the zone contents.
- // Library functions that need to modify the zone will set PROT_WRITE on it.
- // This matches the behavior of malloc_create_zone() on OSX 10.7 and higher.
- mprotect(new_zone, allocated_size, PROT_READ);
- }
- return new_zone;
-}
-
-INTERCEPTOR(malloc_zone_t *, malloc_default_zone, void) {
- ENSURE_ASAN_INITED();
- return &asan_zone;
-}
-
-INTERCEPTOR(malloc_zone_t *, malloc_default_purgeable_zone, void) {
- // FIXME: ASan should support purgeable allocations.
- // https://code.google.com/p/address-sanitizer/issues/detail?id=139
- ENSURE_ASAN_INITED();
- return &asan_zone;
-}
-
-INTERCEPTOR(void, malloc_make_purgeable, void *ptr) {
- // FIXME: ASan should support purgeable allocations. Ignoring them is fine
- // for now.
- ENSURE_ASAN_INITED();
-}
-
-INTERCEPTOR(int, malloc_make_nonpurgeable, void *ptr) {
- // FIXME: ASan should support purgeable allocations. Ignoring them is fine
- // for now.
- ENSURE_ASAN_INITED();
- // Must return 0 if the contents were not purged since the last call to
- // malloc_make_purgeable().
- return 0;
-}
-
-INTERCEPTOR(void, malloc_set_zone_name, malloc_zone_t *zone, const char *name) {
- ENSURE_ASAN_INITED();
- // Allocate |strlen("asan-") + 1 + internal_strlen(name)| bytes.
- size_t buflen = 6 + (name ? internal_strlen(name) : 0);
- InternalScopedString new_name(buflen);
- if (name && zone->introspect == asan_zone.introspect) {
- new_name.append("asan-%s", name);
- name = new_name.data();
- }
-
- // Call the system malloc's implementation for both external and our zones,
- // since that appropriately changes VM region protections on the zone.
- REAL(malloc_set_zone_name)(zone, name);
-}
-
-INTERCEPTOR(void *, malloc, size_t size) {
- ENSURE_ASAN_INITED();
- GET_STACK_TRACE_MALLOC;
- void *res = asan_malloc(size, &stack);
- return res;
-}
-INTERCEPTOR(void, free, void *ptr) {
- ENSURE_ASAN_INITED();
- if (!ptr) return;
- GET_STACK_TRACE_FREE;
+using namespace __asan;
+#define COMMON_MALLOC_ZONE_NAME "asan"
+#define COMMON_MALLOC_ENTER() ENSURE_ASAN_INITED()
+#define COMMON_MALLOC_SANITIZER_INITIALIZED asan_inited
+#define COMMON_MALLOC_FORCE_LOCK() asan_mz_force_lock()
+#define COMMON_MALLOC_FORCE_UNLOCK() asan_mz_force_unlock()
+#define COMMON_MALLOC_MEMALIGN(alignment, size) \
+ GET_STACK_TRACE_MALLOC; \
+ void *p = asan_memalign(alignment, size, &stack, FROM_MALLOC)
+#define COMMON_MALLOC_MALLOC(size) \
+ GET_STACK_TRACE_MALLOC; \
+ void *p = asan_malloc(size, &stack)
+#define COMMON_MALLOC_REALLOC(ptr, size) \
+ GET_STACK_TRACE_MALLOC; \
+ void *p = asan_realloc(ptr, size, &stack);
+#define COMMON_MALLOC_CALLOC(count, size) \
+ GET_STACK_TRACE_MALLOC; \
+ void *p = asan_calloc(count, size, &stack);
+#define COMMON_MALLOC_VALLOC(size) \
+ GET_STACK_TRACE_MALLOC; \
+ void *p = asan_memalign(GetPageSizeCached(), size, &stack, FROM_MALLOC);
+#define COMMON_MALLOC_FREE(ptr) \
+ GET_STACK_TRACE_FREE; \
asan_free(ptr, &stack, FROM_MALLOC);
-}
-
-INTERCEPTOR(void *, realloc, void *ptr, size_t size) {
- ENSURE_ASAN_INITED();
- GET_STACK_TRACE_MALLOC;
- return asan_realloc(ptr, size, &stack);
-}
-
-INTERCEPTOR(void *, calloc, size_t nmemb, size_t size) {
- ENSURE_ASAN_INITED();
- GET_STACK_TRACE_MALLOC;
- return asan_calloc(nmemb, size, &stack);
-}
-
-INTERCEPTOR(void *, valloc, size_t size) {
- ENSURE_ASAN_INITED();
- GET_STACK_TRACE_MALLOC;
- return asan_memalign(GetPageSizeCached(), size, &stack, FROM_MALLOC);
-}
-
-INTERCEPTOR(size_t, malloc_good_size, size_t size) {
- ENSURE_ASAN_INITED();
- return asan_zone.introspect->good_size(&asan_zone, size);
-}
-
-INTERCEPTOR(int, posix_memalign, void **memptr, size_t alignment, size_t size) {
- ENSURE_ASAN_INITED();
- CHECK(memptr);
- GET_STACK_TRACE_MALLOC;
- void *result = asan_memalign(alignment, size, &stack, FROM_MALLOC);
- if (result) {
- *memptr = result;
- return 0;
- }
- return -1;
-}
-
-namespace {
-
-// TODO(glider): the __asan_mz_* functions should be united with the Linux
-// wrappers, as they are basically copied from there.
-extern "C"
-SANITIZER_INTERFACE_ATTRIBUTE
-size_t __asan_mz_size(malloc_zone_t* zone, const void* ptr) {
- return asan_mz_size(ptr);
-}
-
-extern "C"
-SANITIZER_INTERFACE_ATTRIBUTE
-void *__asan_mz_malloc(malloc_zone_t *zone, uptr size) {
- if (UNLIKELY(!asan_inited)) {
- CHECK(system_malloc_zone);
- return malloc_zone_malloc(system_malloc_zone, size);
- }
- GET_STACK_TRACE_MALLOC;
- return asan_malloc(size, &stack);
-}
-
-extern "C"
-SANITIZER_INTERFACE_ATTRIBUTE
-void *__asan_mz_calloc(malloc_zone_t *zone, size_t nmemb, size_t size) {
- if (UNLIKELY(!asan_inited)) {
- // Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym.
- const size_t kCallocPoolSize = 1024;
- static uptr calloc_memory_for_dlsym[kCallocPoolSize];
- static size_t allocated;
- size_t size_in_words = ((nmemb * size) + kWordSize - 1) / kWordSize;
- void *mem = (void*)&calloc_memory_for_dlsym[allocated];
- allocated += size_in_words;
- CHECK(allocated < kCallocPoolSize);
- return mem;
- }
- GET_STACK_TRACE_MALLOC;
- return asan_calloc(nmemb, size, &stack);
-}
-
-extern "C"
-SANITIZER_INTERFACE_ATTRIBUTE
-void *__asan_mz_valloc(malloc_zone_t *zone, size_t size) {
- if (UNLIKELY(!asan_inited)) {
- CHECK(system_malloc_zone);
- return malloc_zone_valloc(system_malloc_zone, size);
- }
- GET_STACK_TRACE_MALLOC;
- return asan_memalign(GetPageSizeCached(), size, &stack, FROM_MALLOC);
-}
-
-#define GET_ZONE_FOR_PTR(ptr) \
- malloc_zone_t *zone_ptr = malloc_zone_from_ptr(ptr); \
- const char *zone_name = (zone_ptr == 0) ? 0 : zone_ptr->zone_name
-
-void ALWAYS_INLINE free_common(void *context, void *ptr) {
- if (!ptr) return;
- GET_STACK_TRACE_FREE;
- // FIXME: need to retire this flag.
- if (!flags()->mac_ignore_invalid_free) {
- asan_free(ptr, &stack, FROM_MALLOC);
- } else {
- GET_ZONE_FOR_PTR(ptr);
- WarnMacFreeUnallocated((uptr)ptr, (uptr)zone_ptr, zone_name, &stack);
- return;
- }
-}
-
-// TODO(glider): the allocation callbacks need to be refactored.
-extern "C"
-SANITIZER_INTERFACE_ATTRIBUTE
-void __asan_mz_free(malloc_zone_t *zone, void *ptr) {
- free_common(zone, ptr);
-}
-
-extern "C"
-SANITIZER_INTERFACE_ATTRIBUTE
-void *__asan_mz_realloc(malloc_zone_t *zone, void *ptr, size_t size) {
- if (!ptr) {
- GET_STACK_TRACE_MALLOC;
- return asan_malloc(size, &stack);
- } else {
- if (asan_mz_size(ptr)) {
- GET_STACK_TRACE_MALLOC;
- return asan_realloc(ptr, size, &stack);
- } else {
- // We can't recover from reallocating an unknown address, because
- // this would require reading at most |size| bytes from
- // potentially unaccessible memory.
- GET_STACK_TRACE_FREE;
- GET_ZONE_FOR_PTR(ptr);
- ReportMacMzReallocUnknown((uptr)ptr, (uptr)zone_ptr, zone_name, &stack);
- }
- }
-}
-
-extern "C"
-SANITIZER_INTERFACE_ATTRIBUTE
-void __asan_mz_destroy(malloc_zone_t* zone) {
- // A no-op -- we will not be destroyed!
- Report("__asan_mz_destroy() called -- ignoring\n");
-}
-
-extern "C"
-SANITIZER_INTERFACE_ATTRIBUTE
-void *__asan_mz_memalign(malloc_zone_t *zone, size_t align, size_t size) {
- if (UNLIKELY(!asan_inited)) {
- CHECK(system_malloc_zone);
- return malloc_zone_memalign(system_malloc_zone, align, size);
- }
- GET_STACK_TRACE_MALLOC;
- return asan_memalign(align, size, &stack, FROM_MALLOC);
-}
-
-// This function is currently unused, and we build with -Werror.
-#if 0
-void __asan_mz_free_definite_size(
- malloc_zone_t* zone, void *ptr, size_t size) {
- // TODO(glider): check that |size| is valid.
- UNIMPLEMENTED();
-}
-#endif
-
-kern_return_t mi_enumerator(task_t task, void *,
- unsigned type_mask, vm_address_t zone_address,
- memory_reader_t reader,
- vm_range_recorder_t recorder) {
- // Should enumerate all the pointers we have. Seems like a lot of work.
- return KERN_FAILURE;
-}
-
-size_t mi_good_size(malloc_zone_t *zone, size_t size) {
- // I think it's always safe to return size, but we maybe could do better.
- return size;
-}
-
-boolean_t mi_check(malloc_zone_t *zone) {
- UNIMPLEMENTED();
-}
-
-void mi_print(malloc_zone_t *zone, boolean_t verbose) {
- UNIMPLEMENTED();
-}
-
-void mi_log(malloc_zone_t *zone, void *address) {
- // I don't think we support anything like this
-}
-
-void mi_force_lock(malloc_zone_t *zone) {
- asan_mz_force_lock();
-}
-
-void mi_force_unlock(malloc_zone_t *zone) {
- asan_mz_force_unlock();
-}
-
-void mi_statistics(malloc_zone_t *zone, malloc_statistics_t *stats) {
- AsanMallocStats malloc_stats;
- FillMallocStatistics(&malloc_stats);
- CHECK(sizeof(malloc_statistics_t) == sizeof(AsanMallocStats));
+#define COMMON_MALLOC_SIZE(ptr) \
+ uptr size = asan_mz_size(ptr);
+#define COMMON_MALLOC_FILL_STATS(zone, stats) \
+ AsanMallocStats malloc_stats; \
+ FillMallocStatistics(&malloc_stats); \
+ CHECK(sizeof(malloc_statistics_t) == sizeof(AsanMallocStats)); \
internal_memcpy(stats, &malloc_stats, sizeof(malloc_statistics_t));
-}
-
-boolean_t mi_zone_locked(malloc_zone_t *zone) {
- // UNIMPLEMENTED();
- return false;
-}
-
-} // unnamed namespace
-
-namespace __asan {
+#define COMMON_MALLOC_REPORT_UNKNOWN_REALLOC(ptr, zone_ptr, zone_name) \
+ GET_STACK_TRACE_FREE; \
+ ReportMacMzReallocUnknown((uptr)ptr, (uptr)zone_ptr, zone_name, &stack);
+#define COMMON_MALLOC_NAMESPACE __asan
-void ReplaceSystemMalloc() {
- static malloc_introspection_t asan_introspection;
- // Ok to use internal_memset, these places are not performance-critical.
- internal_memset(&asan_introspection, 0, sizeof(asan_introspection));
+#include "sanitizer_common/sanitizer_malloc_mac.inc"
- asan_introspection.enumerator = &mi_enumerator;
- asan_introspection.good_size = &mi_good_size;
- asan_introspection.check = &mi_check;
- asan_introspection.print = &mi_print;
- asan_introspection.log = &mi_log;
- asan_introspection.force_lock = &mi_force_lock;
- asan_introspection.force_unlock = &mi_force_unlock;
- asan_introspection.statistics = &mi_statistics;
- asan_introspection.zone_locked = &mi_zone_locked;
-
- internal_memset(&asan_zone, 0, sizeof(malloc_zone_t));
-
- // Use version 6 for OSX >= 10.6.
- asan_zone.version = 6;
- asan_zone.zone_name = "asan";
- asan_zone.size = &__asan_mz_size;
- asan_zone.malloc = &__asan_mz_malloc;
- asan_zone.calloc = &__asan_mz_calloc;
- asan_zone.valloc = &__asan_mz_valloc;
- asan_zone.free = &__asan_mz_free;
- asan_zone.realloc = &__asan_mz_realloc;
- asan_zone.destroy = &__asan_mz_destroy;
- asan_zone.batch_malloc = 0;
- asan_zone.batch_free = 0;
- asan_zone.free_definite_size = 0;
- asan_zone.memalign = &__asan_mz_memalign;
- asan_zone.introspect = &asan_introspection;
-
- // Register the ASan zone.
- malloc_zone_register(&asan_zone);
-}
-} // namespace __asan
-
-#endif // SANITIZER_MAC
+#endif
diff --git a/contrib/compiler-rt/lib/asan/asan_mapping.h b/contrib/compiler-rt/lib/asan/asan_mapping.h
index f9e1a527de18..8fe347c8bad0 100644
--- a/contrib/compiler-rt/lib/asan/asan_mapping.h
+++ b/contrib/compiler-rt/lib/asan/asan_mapping.h
@@ -17,7 +17,7 @@
#include "asan_internal.h"
// The full explanation of the memory mapping could be found here:
-// http://code.google.com/p/address-sanitizer/wiki/AddressSanitizerAlgorithm
+// https://github.com/google/sanitizers/wiki/AddressSanitizerAlgorithm
//
// Typical shadow mapping on Linux/x86_64 with SHADOW_OFFSET == 0x00007fff8000:
// || `[0x10007fff8000, 0x7fffffffffff]` || HighMem ||
@@ -73,6 +73,20 @@
// || `[0x2000000000, 0x23ffffffff]` || LowShadow ||
// || `[0x0000000000, 0x1fffffffff]` || LowMem ||
//
+// Default Linux/AArch64 (39-bit VMA) mapping:
+// || `[0x2000000000, 0x7fffffffff]` || highmem ||
+// || `[0x1400000000, 0x1fffffffff]` || highshadow ||
+// || `[0x1200000000, 0x13ffffffff]` || shadowgap ||
+// || `[0x1000000000, 0x11ffffffff]` || lowshadow ||
+// || `[0x0000000000, 0x0fffffffff]` || lowmem ||
+//
+// Default Linux/AArch64 (42-bit VMA) mapping:
+// || `[0x10000000000, 0x3ffffffffff]` || highmem ||
+// || `[0x0a000000000, 0x0ffffffffff]` || highshadow ||
+// || `[0x09000000000, 0x09fffffffff]` || shadowgap ||
+// || `[0x08000000000, 0x08fffffffff]` || lowshadow ||
+// || `[0x00000000000, 0x07fffffffff]` || lowmem ||
+//
// Shadow mapping on FreeBSD/x86-64 with SHADOW_OFFSET == 0x400000000000:
// || `[0x500000000000, 0x7fffffffffff]` || HighMem ||
// || `[0x4a0000000000, 0x4fffffffffff]` || HighShadow ||
@@ -113,11 +127,12 @@ static const u64 kFreeBSD_ShadowOffset64 = 1ULL << 46; // 0x400000000000
static const u64 kWindowsShadowOffset32 = 3ULL << 28; // 0x30000000
#define SHADOW_SCALE kDefaultShadowScale
-#if SANITIZER_ANDROID
-# define SHADOW_OFFSET (0)
-#else
-# if SANITIZER_WORDSIZE == 32
-# if defined(__mips__)
+
+
+#if SANITIZER_WORDSIZE == 32
+# if SANITIZER_ANDROID
+# define SHADOW_OFFSET (0)
+# elif defined(__mips__)
# define SHADOW_OFFSET kMIPS32_ShadowOffset32
# elif SANITIZER_FREEBSD
# define SHADOW_OFFSET kFreeBSD_ShadowOffset32
@@ -130,7 +145,7 @@ static const u64 kWindowsShadowOffset32 = 3ULL << 28; // 0x30000000
# else
# define SHADOW_OFFSET kDefaultShadowOffset32
# endif
-# else
+#else
# if defined(__aarch64__)
# define SHADOW_OFFSET kAArch64_ShadowOffset64
# elif defined(__powerpc64__)
@@ -148,7 +163,6 @@ static const u64 kWindowsShadowOffset32 = 3ULL << 28; // 0x30000000
# else
# define SHADOW_OFFSET kDefaultShort64bitShadowOffset
# endif
-# endif
#endif
#define SHADOW_GRANULARITY (1ULL << SHADOW_SCALE)
@@ -171,7 +185,8 @@ static const u64 kWindowsShadowOffset32 = 3ULL << 28; // 0x30000000
// With the zero shadow base we can not actually map pages starting from 0.
// This constant is somewhat arbitrary.
-#define kZeroBaseShadowStart (1 << 18)
+#define kZeroBaseShadowStart 0
+#define kZeroBaseMaxShadowStart (1 << 18)
#define kShadowGapBeg (kLowShadowEnd ? kLowShadowEnd + 1 \
: kZeroBaseShadowStart)
diff --git a/contrib/compiler-rt/lib/asan/asan_new_delete.cc b/contrib/compiler-rt/lib/asan/asan_new_delete.cc
index e48bdaf03dd3..b5ba13ef4055 100644
--- a/contrib/compiler-rt/lib/asan/asan_new_delete.cc
+++ b/contrib/compiler-rt/lib/asan/asan_new_delete.cc
@@ -30,7 +30,7 @@
using namespace __asan; // NOLINT
// This code has issues on OSX.
-// See https://code.google.com/p/address-sanitizer/issues/detail?id=131.
+// See https://github.com/google/sanitizers/issues/131.
// Fake std::nothrow_t to avoid including <new>.
namespace std {
@@ -90,11 +90,11 @@ INTERCEPTOR(void *, _ZnamRKSt9nothrow_t, size_t size, std::nothrow_t const&) {
#if !SANITIZER_MAC
CXX_OPERATOR_ATTRIBUTE
-void operator delete(void *ptr) throw() {
+void operator delete(void *ptr) NOEXCEPT {
OPERATOR_DELETE_BODY(FROM_NEW);
}
CXX_OPERATOR_ATTRIBUTE
-void operator delete[](void *ptr) throw() {
+void operator delete[](void *ptr) NOEXCEPT {
OPERATOR_DELETE_BODY(FROM_NEW_BR);
}
CXX_OPERATOR_ATTRIBUTE
@@ -106,12 +106,12 @@ void operator delete[](void *ptr, std::nothrow_t const&) {
OPERATOR_DELETE_BODY(FROM_NEW_BR);
}
CXX_OPERATOR_ATTRIBUTE
-void operator delete(void *ptr, size_t size) throw() {
+void operator delete(void *ptr, size_t size) NOEXCEPT {
GET_STACK_TRACE_FREE;
asan_sized_free(ptr, size, &stack, FROM_NEW);
}
CXX_OPERATOR_ATTRIBUTE
-void operator delete[](void *ptr, size_t size) throw() {
+void operator delete[](void *ptr, size_t size) NOEXCEPT {
GET_STACK_TRACE_FREE;
asan_sized_free(ptr, size, &stack, FROM_NEW_BR);
}
diff --git a/contrib/compiler-rt/lib/asan/asan_poisoning.cc b/contrib/compiler-rt/lib/asan/asan_poisoning.cc
index 569d359aa425..f77ab8780bb7 100644
--- a/contrib/compiler-rt/lib/asan/asan_poisoning.cc
+++ b/contrib/compiler-rt/lib/asan/asan_poisoning.cc
@@ -102,7 +102,7 @@ using namespace __asan; // NOLINT
// that user program (un)poisons the memory it owns. It poisons memory
// conservatively, and unpoisons progressively to make sure asan shadow
// mapping invariant is preserved (see detailed mapping description here:
-// http://code.google.com/p/address-sanitizer/wiki/AddressSanitizerAlgorithm).
+// https://github.com/google/sanitizers/wiki/AddressSanitizerAlgorithm).
//
// * if user asks to poison region [left, right), the program poisons
// at least [left, AlignDown(right)).
@@ -354,7 +354,7 @@ void __sanitizer_annotate_contiguous_container(const void *beg_p,
// Make a quick sanity check that we are indeed in this state.
//
// FIXME: Two of these three checks are disabled until we fix
- // https://code.google.com/p/address-sanitizer/issues/detail?id=258.
+ // https://github.com/google/sanitizers/issues/258.
// if (d1 != d2)
// CHECK_EQ(*(u8*)MemToShadow(d1), old_mid - d1);
if (a + granularity <= d1)
@@ -375,10 +375,10 @@ void __sanitizer_annotate_contiguous_container(const void *beg_p,
}
}
-int __sanitizer_verify_contiguous_container(const void *beg_p,
- const void *mid_p,
- const void *end_p) {
- if (!flags()->detect_container_overflow) return 1;
+const void *__sanitizer_contiguous_container_find_bad_address(
+ const void *beg_p, const void *mid_p, const void *end_p) {
+ if (!flags()->detect_container_overflow)
+ return nullptr;
uptr beg = reinterpret_cast<uptr>(beg_p);
uptr end = reinterpret_cast<uptr>(end_p);
uptr mid = reinterpret_cast<uptr>(mid_p);
@@ -395,17 +395,24 @@ int __sanitizer_verify_contiguous_container(const void *beg_p,
uptr r3_end = end;
for (uptr i = r1_beg; i < r1_end; i++)
if (AddressIsPoisoned(i))
- return 0;
+ return reinterpret_cast<const void *>(i);
for (uptr i = r2_beg; i < mid; i++)
if (AddressIsPoisoned(i))
- return 0;
+ return reinterpret_cast<const void *>(i);
for (uptr i = mid; i < r2_end; i++)
if (!AddressIsPoisoned(i))
- return 0;
+ return reinterpret_cast<const void *>(i);
for (uptr i = r3_beg; i < r3_end; i++)
if (!AddressIsPoisoned(i))
- return 0;
- return 1;
+ return reinterpret_cast<const void *>(i);
+ return nullptr;
+}
+
+int __sanitizer_verify_contiguous_container(const void *beg_p,
+ const void *mid_p,
+ const void *end_p) {
+ return __sanitizer_contiguous_container_find_bad_address(beg_p, mid_p,
+ end_p) == nullptr;
}
extern "C" SANITIZER_INTERFACE_ATTRIBUTE
diff --git a/contrib/compiler-rt/lib/asan/asan_posix.cc b/contrib/compiler-rt/lib/asan/asan_posix.cc
index 2e857f6f624c..9e01bcd091bf 100644
--- a/contrib/compiler-rt/lib/asan/asan_posix.cc
+++ b/contrib/compiler-rt/lib/asan/asan_posix.cc
@@ -33,11 +33,11 @@
namespace __asan {
-void AsanOnSIGSEGV(int, void *siginfo, void *context) {
+void AsanOnDeadlySignal(int signo, void *siginfo, void *context) {
ScopedDeadlySignal signal_scope(GetCurrentThread());
int code = (int)((siginfo_t*)siginfo)->si_code;
// Write the first message using the bullet-proof write.
- if (13 != internal_write(2, "ASAN:SIGSEGV\n", 13)) Die();
+ if (18 != internal_write(2, "ASAN:DEADLYSIGNAL\n", 18)) Die();
SignalContext sig = SignalContext::Create(siginfo, context);
// Access at a reasonable offset above SP, or slightly below it (to account
@@ -75,8 +75,12 @@ void AsanOnSIGSEGV(int, void *siginfo, void *context) {
// unaligned memory access.
if (IsStackAccess && (code == si_SEGV_MAPERR || code == si_SEGV_ACCERR))
ReportStackOverflow(sig);
+ else if (signo == SIGFPE)
+ ReportDeadlySignal("FPE", sig);
+ else if (signo == SIGILL)
+ ReportDeadlySignal("ILL", sig);
else
- ReportSIGSEGV("SEGV", sig);
+ ReportDeadlySignal("SEGV", sig);
}
// ---------------------- TSD ---------------- {{{1
diff --git a/contrib/compiler-rt/lib/asan/asan_report.cc b/contrib/compiler-rt/lib/asan/asan_report.cc
index c1681e644464..bb7e36e84652 100644
--- a/contrib/compiler-rt/lib/asan/asan_report.cc
+++ b/contrib/compiler-rt/lib/asan/asan_report.cc
@@ -11,6 +11,7 @@
//
// This file contains error reporting code.
//===----------------------------------------------------------------------===//
+
#include "asan_flags.h"
#include "asan_internal.h"
#include "asan_mapping.h"
@@ -27,9 +28,11 @@ namespace __asan {
// -------------------- User-specified callbacks ----------------- {{{1
static void (*error_report_callback)(const char*);
-static char *error_message_buffer = 0;
+static char *error_message_buffer = nullptr;
static uptr error_message_buffer_pos = 0;
-static uptr error_message_buffer_size = 0;
+static BlockingMutex error_message_buf_mutex(LINKER_INITIALIZED);
+static const unsigned kAsanBuggyPcPoolSize = 25;
+static __sanitizer::atomic_uintptr_t AsanBuggyPcPool[kAsanBuggyPcPoolSize];
struct ReportData {
uptr pc;
@@ -45,16 +48,20 @@ static bool report_happened = false;
static ReportData report_data = {};
void AppendToErrorMessageBuffer(const char *buffer) {
- if (error_message_buffer) {
- uptr length = internal_strlen(buffer);
- CHECK_GE(error_message_buffer_size, error_message_buffer_pos);
- uptr remaining = error_message_buffer_size - error_message_buffer_pos;
- internal_strncpy(error_message_buffer + error_message_buffer_pos,
- buffer, remaining);
- error_message_buffer[error_message_buffer_size - 1] = '\0';
- // FIXME: reallocate the buffer instead of truncating the message.
- error_message_buffer_pos += Min(remaining, length);
+ BlockingMutexLock l(&error_message_buf_mutex);
+ if (!error_message_buffer) {
+ error_message_buffer =
+ (char*)MmapOrDieQuietly(kErrorMessageBufferSize, __func__);
+ error_message_buffer_pos = 0;
}
+ uptr length = internal_strlen(buffer);
+ RAW_CHECK(kErrorMessageBufferSize >= error_message_buffer_pos);
+ uptr remaining = kErrorMessageBufferSize - error_message_buffer_pos;
+ internal_strncpy(error_message_buffer + error_message_buffer_pos,
+ buffer, remaining);
+ error_message_buffer[kErrorMessageBufferSize - 1] = '\0';
+ // FIXME: reallocate the buffer instead of truncating the message.
+ error_message_buffer_pos += Min(remaining, length);
}
// ---------------------- Decorator ------------------------------ {{{1
@@ -373,7 +380,7 @@ static void PrintAccessAndVarIntersection(const StackVarDescr &var, uptr addr,
uptr next_var_beg) {
uptr var_end = var.beg + var.size;
uptr addr_end = addr + access_size;
- const char *pos_descr = 0;
+ const char *pos_descr = nullptr;
// If the variable [var.beg, var_end) is the nearest variable to the
// current memory access, indicate it in the log.
if (addr >= var.beg) {
@@ -544,7 +551,7 @@ void DescribeHeapAddress(uptr addr, uptr access_size) {
StackTrace alloc_stack = chunk.GetAllocStack();
char tname[128];
Decorator d;
- AsanThreadContext *free_thread = 0;
+ AsanThreadContext *free_thread = nullptr;
if (chunk.FreeTid() != kInvalidTid) {
free_thread = GetThreadContextByTidLocked(chunk.FreeTid());
Printf("%sfreed by thread T%d%s here:%s\n", d.Allocation(),
@@ -621,26 +628,90 @@ void DescribeThread(AsanThreadContext *context) {
// immediately after printing error report.
class ScopedInErrorReport {
public:
- explicit ScopedInErrorReport(ReportData *report = nullptr) {
- static atomic_uint32_t num_calls;
- static u32 reporting_thread_tid;
- if (atomic_fetch_add(&num_calls, 1, memory_order_relaxed) != 0) {
+ explicit ScopedInErrorReport(ReportData *report = nullptr,
+ bool fatal = false) {
+ halt_on_error_ = fatal || flags()->halt_on_error;
+
+ if (lock_.TryLock()) {
+ StartReporting(report);
+ return;
+ }
+
+ // ASan found two bugs in different threads simultaneously.
+
+ u32 current_tid = GetCurrentTidOrInvalid();
+ if (reporting_thread_tid_ == current_tid ||
+ reporting_thread_tid_ == kInvalidTid) {
+ // This is either asynch signal or nested error during error reporting.
+ // Fail simple to avoid deadlocks in Report().
+
+ // Can't use Report() here because of potential deadlocks
+ // in nested signal handlers.
+ const char msg[] = "AddressSanitizer: nested bug in the same thread, "
+ "aborting.\n";
+ WriteToFile(kStderrFd, msg, sizeof(msg));
+
+ internal__exit(common_flags()->exitcode);
+ }
+
+ if (halt_on_error_) {
// Do not print more than one report, otherwise they will mix up.
// Error reporting functions shouldn't return at this situation, as
- // they are defined as no-return.
+ // they are effectively no-returns.
+
Report("AddressSanitizer: while reporting a bug found another one. "
- "Ignoring.\n");
- u32 current_tid = GetCurrentTidOrInvalid();
- if (current_tid != reporting_thread_tid) {
- // ASan found two bugs in different threads simultaneously. Sleep
- // long enough to make sure that the thread which started to print
- // an error report will finish doing it.
- SleepForSeconds(Max(100, flags()->sleep_before_dying + 1));
- }
+ "Ignoring.\n");
+
+ // Sleep long enough to make sure that the thread which started
+ // to print an error report will finish doing it.
+ SleepForSeconds(Max(100, flags()->sleep_before_dying + 1));
+
// If we're still not dead for some reason, use raw _exit() instead of
// Die() to bypass any additional checks.
- internal__exit(flags()->exitcode);
+ internal__exit(common_flags()->exitcode);
+ } else {
+ // The other thread will eventually finish reporting
+ // so it's safe to wait
+ lock_.Lock();
}
+
+ StartReporting(report);
+ }
+
+ ~ScopedInErrorReport() {
+ // Make sure the current thread is announced.
+ DescribeThread(GetCurrentThread());
+ // We may want to grab this lock again when printing stats.
+ asanThreadRegistry().Unlock();
+ // Print memory stats.
+ if (flags()->print_stats)
+ __asan_print_accumulated_stats();
+
+ // Copy the message buffer so that we could start logging without holding a
+ // lock that gets aquired during printing.
+ InternalScopedBuffer<char> buffer_copy(kErrorMessageBufferSize);
+ {
+ BlockingMutexLock l(&error_message_buf_mutex);
+ internal_memcpy(buffer_copy.data(),
+ error_message_buffer, kErrorMessageBufferSize);
+ }
+
+ LogFullErrorReport(buffer_copy.data());
+
+ if (error_report_callback) {
+ error_report_callback(buffer_copy.data());
+ }
+ CommonSanitizerReportMutex.Unlock();
+ reporting_thread_tid_ = kInvalidTid;
+ lock_.Unlock();
+ if (halt_on_error_) {
+ Report("ABORTING\n");
+ Die();
+ }
+ }
+
+ private:
+ void StartReporting(ReportData *report) {
if (report) report_data = *report;
report_happened = true;
ASAN_ON_ERROR();
@@ -650,27 +721,19 @@ class ScopedInErrorReport {
// recursive reports.
asanThreadRegistry().Lock();
CommonSanitizerReportMutex.Lock();
- reporting_thread_tid = GetCurrentTidOrInvalid();
+ reporting_thread_tid_ = GetCurrentTidOrInvalid();
Printf("===================================================="
"=============\n");
}
- // Destructor is NORETURN, as functions that report errors are.
- NORETURN ~ScopedInErrorReport() {
- // Make sure the current thread is announced.
- DescribeThread(GetCurrentThread());
- // We may want to grab this lock again when printing stats.
- asanThreadRegistry().Unlock();
- // Print memory stats.
- if (flags()->print_stats)
- __asan_print_accumulated_stats();
- if (error_report_callback) {
- error_report_callback(error_message_buffer);
- }
- Report("ABORTING\n");
- Die();
- }
+
+ static StaticSpinMutex lock_;
+ static u32 reporting_thread_tid_;
+ bool halt_on_error_;
};
+StaticSpinMutex ScopedInErrorReport::lock_;
+u32 ScopedInErrorReport::reporting_thread_tid_;
+
void ReportStackOverflow(const SignalContext &sig) {
ScopedInErrorReport in_report;
Decorator d;
@@ -686,8 +749,8 @@ void ReportStackOverflow(const SignalContext &sig) {
ReportErrorSummary("stack-overflow", &stack);
}
-void ReportSIGSEGV(const char *description, const SignalContext &sig) {
- ScopedInErrorReport in_report;
+void ReportDeadlySignal(const char *description, const SignalContext &sig) {
+ ScopedInErrorReport in_report(/*report*/nullptr, /*fatal*/true);
Decorator d;
Printf("%s", d.Warning());
Report(
@@ -703,7 +766,7 @@ void ReportSIGSEGV(const char *description, const SignalContext &sig) {
stack.Print();
MaybeDumpInstructionBytes(sig.pc);
Printf("AddressSanitizer can not provide additional info.\n");
- ReportErrorSummary("SEGV", &stack);
+ ReportErrorSummary(description, &stack);
}
void ReportDoubleFree(uptr addr, BufferedStackTrace *free_stack) {
@@ -744,7 +807,7 @@ void ReportNewDeleteSizeMismatch(uptr addr, uptr delete_size,
stack.Print();
DescribeHeapAddress(addr, 1);
ReportErrorSummary("new-delete-type-mismatch", &stack);
- Report("HINT: if you don't care about these warnings you may set "
+ Report("HINT: if you don't care about these errors you may set "
"ASAN_OPTIONS=new_delete_type_mismatch=0\n");
}
@@ -784,7 +847,7 @@ void ReportAllocTypeMismatch(uptr addr, BufferedStackTrace *free_stack,
stack.Print();
DescribeHeapAddress(addr, 1);
ReportErrorSummary("alloc-dealloc-mismatch", &stack);
- Report("HINT: if you don't care about these warnings you may set "
+ Report("HINT: if you don't care about these errors you may set "
"ASAN_OPTIONS=alloc_dealloc_mismatch=0\n");
}
@@ -886,7 +949,7 @@ void ReportODRViolation(const __asan_global *g1, u32 stack_id1,
Printf(" [2]:\n");
StackDepotGet(stack_id2).Print();
}
- Report("HINT: if you don't care about these warnings you may set "
+ Report("HINT: if you don't care about these errors you may set "
"ASAN_OPTIONS=detect_odr_violation=0\n");
InternalScopedString error_msg(256);
error_msg.append("odr-violation: global '%s' at %s",
@@ -925,17 +988,6 @@ static INLINE void CheckForInvalidPointerPair(void *p1, void *p2) {
}
// ----------------------- Mac-specific reports ----------------- {{{1
-void WarnMacFreeUnallocated(uptr addr, uptr zone_ptr, const char *zone_name,
- BufferedStackTrace *stack) {
- // Just print a warning here.
- Printf("free_common(%p) -- attempting to free unallocated memory.\n"
- "AddressSanitizer is ignoring this error on Mac OS now.\n",
- addr);
- PrintZoneForPointer(addr, zone_ptr, zone_name);
- stack->Print();
- DescribeHeapAddress(addr, 1);
-}
-
void ReportMacMzReallocUnknown(uptr addr, uptr zone_ptr, const char *zone_name,
BufferedStackTrace *stack) {
ScopedInErrorReport in_report;
@@ -947,24 +999,23 @@ void ReportMacMzReallocUnknown(uptr addr, uptr zone_ptr, const char *zone_name,
DescribeHeapAddress(addr, 1);
}
-void ReportMacCfReallocUnknown(uptr addr, uptr zone_ptr, const char *zone_name,
- BufferedStackTrace *stack) {
- ScopedInErrorReport in_report;
- Printf("cf_realloc(%p) -- attempting to realloc unallocated memory.\n"
- "This is an unrecoverable problem, exiting now.\n",
- addr);
- PrintZoneForPointer(addr, zone_ptr, zone_name);
- stack->Print();
- DescribeHeapAddress(addr, 1);
+// -------------- SuppressErrorReport -------------- {{{1
+// Avoid error reports duplicating for ASan recover mode.
+static bool SuppressErrorReport(uptr pc) {
+ if (!common_flags()->suppress_equal_pcs) return false;
+ for (unsigned i = 0; i < kAsanBuggyPcPoolSize; i++) {
+ uptr cmp = atomic_load_relaxed(&AsanBuggyPcPool[i]);
+ if (cmp == 0 && atomic_compare_exchange_strong(&AsanBuggyPcPool[i], &cmp,
+ pc, memory_order_relaxed))
+ return false;
+ if (cmp == pc) return true;
+ }
+ Die();
}
-} // namespace __asan
-
-// --------------------------- Interface --------------------- {{{1
-using namespace __asan; // NOLINT
-
-void __asan_report_error(uptr pc, uptr bp, uptr sp, uptr addr, int is_write,
- uptr access_size, u32 exp) {
+void ReportGenericError(uptr pc, uptr bp, uptr sp, uptr addr, bool is_write,
+ uptr access_size, u32 exp, bool fatal) {
+ if (!fatal && SuppressErrorReport(pc)) return;
ENABLE_FRAME_POINTER;
// Optimization experiments.
@@ -1033,7 +1084,7 @@ void __asan_report_error(uptr pc, uptr bp, uptr sp, uptr addr, int is_write,
ReportData report = { pc, sp, bp, addr, (bool)is_write, access_size,
bug_descr };
- ScopedInErrorReport in_report(&report);
+ ScopedInErrorReport in_report(&report, fatal);
Decorator d;
Printf("%s", d.Warning());
@@ -1059,14 +1110,21 @@ void __asan_report_error(uptr pc, uptr bp, uptr sp, uptr addr, int is_write,
PrintShadowMemoryForAddress(addr);
}
+} // namespace __asan
+
+// --------------------------- Interface --------------------- {{{1
+using namespace __asan; // NOLINT
+
+void __asan_report_error(uptr pc, uptr bp, uptr sp, uptr addr, int is_write,
+ uptr access_size, u32 exp) {
+ ENABLE_FRAME_POINTER;
+ bool fatal = flags()->halt_on_error;
+ ReportGenericError(pc, bp, sp, addr, is_write, access_size, exp, fatal);
+}
+
void NOINLINE __asan_set_error_report_callback(void (*callback)(const char*)) {
+ BlockingMutexLock l(&error_message_buf_mutex);
error_report_callback = callback;
- if (callback) {
- error_message_buffer_size = 1 << 16;
- error_message_buffer =
- (char*)MmapOrDie(error_message_buffer_size, __func__);
- error_message_buffer_pos = 0;
- }
}
void __asan_describe_address(uptr addr) {
@@ -1117,7 +1175,7 @@ SANITIZER_INTERFACE_ATTRIBUTE
void __sanitizer_ptr_cmp(void *a, void *b) {
CheckForInvalidPointerPair(a, b);
}
-} // extern "C"
+} // extern "C"
#if !SANITIZER_SUPPORTS_WEAK_HOOKS
// Provide default implementation of __asan_on_error that does nothing
diff --git a/contrib/compiler-rt/lib/asan/asan_report.h b/contrib/compiler-rt/lib/asan/asan_report.h
index e2786b0f260c..559b8adfd51d 100644
--- a/contrib/compiler-rt/lib/asan/asan_report.h
+++ b/contrib/compiler-rt/lib/asan/asan_report.h
@@ -49,44 +49,39 @@ bool DescribeAddressIfStack(uptr addr, uptr access_size);
void DescribeThread(AsanThreadContext *context);
// Different kinds of error reports.
-void NORETURN ReportStackOverflow(const SignalContext &sig);
-void NORETURN ReportSIGSEGV(const char *description, const SignalContext &sig);
-void NORETURN ReportNewDeleteSizeMismatch(uptr addr, uptr delete_size,
- BufferedStackTrace *free_stack);
-void NORETURN ReportDoubleFree(uptr addr, BufferedStackTrace *free_stack);
-void NORETURN ReportFreeNotMalloced(uptr addr, BufferedStackTrace *free_stack);
-void NORETURN ReportAllocTypeMismatch(uptr addr, BufferedStackTrace *free_stack,
- AllocType alloc_type,
- AllocType dealloc_type);
-void NORETURN
- ReportMallocUsableSizeNotOwned(uptr addr, BufferedStackTrace *stack);
-void NORETURN
- ReportSanitizerGetAllocatedSizeNotOwned(uptr addr,
- BufferedStackTrace *stack);
-void NORETURN
- ReportStringFunctionMemoryRangesOverlap(const char *function,
- const char *offset1, uptr length1,
- const char *offset2, uptr length2,
- BufferedStackTrace *stack);
-void NORETURN ReportStringFunctionSizeOverflow(uptr offset, uptr size,
- BufferedStackTrace *stack);
-void NORETURN
- ReportBadParamsToAnnotateContiguousContainer(uptr beg, uptr end,
- uptr old_mid, uptr new_mid,
- BufferedStackTrace *stack);
+void ReportGenericError(uptr pc, uptr bp, uptr sp, uptr addr, bool is_write,
+ uptr access_size, u32 exp, bool fatal);
+void ReportStackOverflow(const SignalContext &sig);
+void ReportDeadlySignal(const char *description, const SignalContext &sig);
+void ReportNewDeleteSizeMismatch(uptr addr, uptr delete_size,
+ BufferedStackTrace *free_stack);
+void ReportDoubleFree(uptr addr, BufferedStackTrace *free_stack);
+void ReportFreeNotMalloced(uptr addr, BufferedStackTrace *free_stack);
+void ReportAllocTypeMismatch(uptr addr, BufferedStackTrace *free_stack,
+ AllocType alloc_type,
+ AllocType dealloc_type);
+void ReportMallocUsableSizeNotOwned(uptr addr, BufferedStackTrace *stack);
+void ReportSanitizerGetAllocatedSizeNotOwned(uptr addr,
+ BufferedStackTrace *stack);
+void ReportStringFunctionMemoryRangesOverlap(const char *function,
+ const char *offset1, uptr length1,
+ const char *offset2, uptr length2,
+ BufferedStackTrace *stack);
+void ReportStringFunctionSizeOverflow(uptr offset, uptr size,
+ BufferedStackTrace *stack);
+void ReportBadParamsToAnnotateContiguousContainer(uptr beg, uptr end,
+ uptr old_mid, uptr new_mid,
+ BufferedStackTrace *stack);
-void NORETURN
-ReportODRViolation(const __asan_global *g1, u32 stack_id1,
- const __asan_global *g2, u32 stack_id2);
+void ReportODRViolation(const __asan_global *g1, u32 stack_id1,
+ const __asan_global *g2, u32 stack_id2);
// Mac-specific errors and warnings.
-void WarnMacFreeUnallocated(uptr addr, uptr zone_ptr, const char *zone_name,
- BufferedStackTrace *stack);
-void NORETURN ReportMacMzReallocUnknown(uptr addr, uptr zone_ptr,
- const char *zone_name,
- BufferedStackTrace *stack);
-void NORETURN ReportMacCfReallocUnknown(uptr addr, uptr zone_ptr,
- const char *zone_name,
- BufferedStackTrace *stack);
+void ReportMacMzReallocUnknown(uptr addr, uptr zone_ptr,
+ const char *zone_name,
+ BufferedStackTrace *stack);
+void ReportMacCfReallocUnknown(uptr addr, uptr zone_ptr,
+ const char *zone_name,
+ BufferedStackTrace *stack);
} // namespace __asan
diff --git a/contrib/compiler-rt/lib/asan/asan_rtl.cc b/contrib/compiler-rt/lib/asan/asan_rtl.cc
index a8d92b915a9a..7b8b5dd9be1b 100644
--- a/contrib/compiler-rt/lib/asan/asan_rtl.cc
+++ b/contrib/compiler-rt/lib/asan/asan_rtl.cc
@@ -11,6 +11,7 @@
//
// Main file of the ASan run-time library.
//===----------------------------------------------------------------------===//
+
#include "asan_activation.h"
#include "asan_allocator.h"
#include "asan_interceptors.h"
@@ -56,11 +57,6 @@ static void AsanDie() {
UnmapOrDie((void*)kLowShadowBeg, kHighShadowEnd - kLowShadowBeg);
}
}
- if (common_flags()->coverage)
- __sanitizer_cov_dump();
- if (flags()->abort_on_error)
- Abort();
- internal__exit(flags()->exitcode);
}
static void AsanCheckFailed(const char *file, int line, const char *cond,
@@ -117,13 +113,18 @@ static void OnLowLevelAllocate(uptr ptr, uptr size) {
extern "C" NOINLINE INTERFACE_ATTRIBUTE \
void __asan_report_ ## type ## size(uptr addr) { \
GET_CALLER_PC_BP_SP; \
- __asan_report_error(pc, bp, sp, addr, is_write, size, 0); \
+ ReportGenericError(pc, bp, sp, addr, is_write, size, 0, true); \
} \
extern "C" NOINLINE INTERFACE_ATTRIBUTE \
void __asan_report_exp_ ## type ## size(uptr addr, u32 exp) { \
GET_CALLER_PC_BP_SP; \
- __asan_report_error(pc, bp, sp, addr, is_write, size, exp); \
-}
+ ReportGenericError(pc, bp, sp, addr, is_write, size, exp, true); \
+} \
+extern "C" NOINLINE INTERFACE_ATTRIBUTE \
+void __asan_report_ ## type ## size ## _noabort(uptr addr) { \
+ GET_CALLER_PC_BP_SP; \
+ ReportGenericError(pc, bp, sp, addr, is_write, size, 0, false); \
+} \
ASAN_REPORT_ERROR(load, false, 1)
ASAN_REPORT_ERROR(load, false, 2)
@@ -136,22 +137,27 @@ ASAN_REPORT_ERROR(store, true, 4)
ASAN_REPORT_ERROR(store, true, 8)
ASAN_REPORT_ERROR(store, true, 16)
-#define ASAN_REPORT_ERROR_N(type, is_write) \
-extern "C" NOINLINE INTERFACE_ATTRIBUTE \
-void __asan_report_ ## type ## _n(uptr addr, uptr size) { \
- GET_CALLER_PC_BP_SP; \
- __asan_report_error(pc, bp, sp, addr, is_write, size, 0); \
-} \
-extern "C" NOINLINE INTERFACE_ATTRIBUTE \
+#define ASAN_REPORT_ERROR_N(type, is_write) \
+extern "C" NOINLINE INTERFACE_ATTRIBUTE \
+void __asan_report_ ## type ## _n(uptr addr, uptr size) { \
+ GET_CALLER_PC_BP_SP; \
+ ReportGenericError(pc, bp, sp, addr, is_write, size, 0, true); \
+} \
+extern "C" NOINLINE INTERFACE_ATTRIBUTE \
void __asan_report_exp_ ## type ## _n(uptr addr, uptr size, u32 exp) { \
GET_CALLER_PC_BP_SP; \
- __asan_report_error(pc, bp, sp, addr, is_write, size, exp); \
-}
+ ReportGenericError(pc, bp, sp, addr, is_write, size, exp, true); \
+} \
+extern "C" NOINLINE INTERFACE_ATTRIBUTE \
+void __asan_report_ ## type ## _n_noabort(uptr addr, uptr size) { \
+ GET_CALLER_PC_BP_SP; \
+ ReportGenericError(pc, bp, sp, addr, is_write, size, 0, false); \
+} \
ASAN_REPORT_ERROR_N(load, false)
ASAN_REPORT_ERROR_N(store, true)
-#define ASAN_MEMORY_ACCESS_CALLBACK_BODY(type, is_write, size, exp_arg) \
+#define ASAN_MEMORY_ACCESS_CALLBACK_BODY(type, is_write, size, exp_arg, fatal) \
uptr sp = MEM_TO_SHADOW(addr); \
uptr s = size <= SHADOW_GRANULARITY ? *reinterpret_cast<u8 *>(sp) \
: *reinterpret_cast<u16 *>(sp); \
@@ -163,7 +169,8 @@ ASAN_REPORT_ERROR_N(store, true)
*__asan_test_only_reported_buggy_pointer = addr; \
} else { \
GET_CALLER_PC_BP_SP; \
- __asan_report_error(pc, bp, sp, addr, is_write, size, exp_arg); \
+ ReportGenericError(pc, bp, sp, addr, is_write, size, exp_arg, \
+ fatal); \
} \
} \
}
@@ -171,12 +178,16 @@ ASAN_REPORT_ERROR_N(store, true)
#define ASAN_MEMORY_ACCESS_CALLBACK(type, is_write, size) \
extern "C" NOINLINE INTERFACE_ATTRIBUTE \
void __asan_##type##size(uptr addr) { \
- ASAN_MEMORY_ACCESS_CALLBACK_BODY(type, is_write, size, 0) \
+ ASAN_MEMORY_ACCESS_CALLBACK_BODY(type, is_write, size, 0, true) \
} \
extern "C" NOINLINE INTERFACE_ATTRIBUTE \
void __asan_exp_##type##size(uptr addr, u32 exp) { \
- ASAN_MEMORY_ACCESS_CALLBACK_BODY(type, is_write, size, exp) \
- }
+ ASAN_MEMORY_ACCESS_CALLBACK_BODY(type, is_write, size, exp, true) \
+ } \
+ extern "C" NOINLINE INTERFACE_ATTRIBUTE \
+ void __asan_##type##size ## _noabort(uptr addr) { \
+ ASAN_MEMORY_ACCESS_CALLBACK_BODY(type, is_write, size, 0, false) \
+ } \
ASAN_MEMORY_ACCESS_CALLBACK(load, false, 1)
ASAN_MEMORY_ACCESS_CALLBACK(load, false, 2)
@@ -194,7 +205,7 @@ NOINLINE INTERFACE_ATTRIBUTE
void __asan_loadN(uptr addr, uptr size) {
if (__asan_region_is_poisoned(addr, size)) {
GET_CALLER_PC_BP_SP;
- __asan_report_error(pc, bp, sp, addr, false, size, 0);
+ ReportGenericError(pc, bp, sp, addr, false, size, 0, true);
}
}
@@ -203,7 +214,16 @@ NOINLINE INTERFACE_ATTRIBUTE
void __asan_exp_loadN(uptr addr, uptr size, u32 exp) {
if (__asan_region_is_poisoned(addr, size)) {
GET_CALLER_PC_BP_SP;
- __asan_report_error(pc, bp, sp, addr, false, size, exp);
+ ReportGenericError(pc, bp, sp, addr, false, size, exp, true);
+ }
+}
+
+extern "C"
+NOINLINE INTERFACE_ATTRIBUTE
+void __asan_loadN_noabort(uptr addr, uptr size) {
+ if (__asan_region_is_poisoned(addr, size)) {
+ GET_CALLER_PC_BP_SP;
+ ReportGenericError(pc, bp, sp, addr, false, size, 0, false);
}
}
@@ -212,7 +232,7 @@ NOINLINE INTERFACE_ATTRIBUTE
void __asan_storeN(uptr addr, uptr size) {
if (__asan_region_is_poisoned(addr, size)) {
GET_CALLER_PC_BP_SP;
- __asan_report_error(pc, bp, sp, addr, true, size, 0);
+ ReportGenericError(pc, bp, sp, addr, true, size, 0, true);
}
}
@@ -221,7 +241,16 @@ NOINLINE INTERFACE_ATTRIBUTE
void __asan_exp_storeN(uptr addr, uptr size, u32 exp) {
if (__asan_region_is_poisoned(addr, size)) {
GET_CALLER_PC_BP_SP;
- __asan_report_error(pc, bp, sp, addr, true, size, exp);
+ ReportGenericError(pc, bp, sp, addr, true, size, exp, true);
+ }
+}
+
+extern "C"
+NOINLINE INTERFACE_ATTRIBUTE
+void __asan_storeN_noabort(uptr addr, uptr size) {
+ if (__asan_region_is_poisoned(addr, size)) {
+ GET_CALLER_PC_BP_SP;
+ ReportGenericError(pc, bp, sp, addr, true, size, 0, false);
}
}
@@ -259,16 +288,15 @@ static NOINLINE void force_interface_symbols() {
case 22: __asan_report_exp_store8(0, 0); break;
case 23: __asan_report_exp_store16(0, 0); break;
case 24: __asan_report_exp_store_n(0, 0, 0); break;
- case 25: __asan_register_globals(0, 0); break;
- case 26: __asan_unregister_globals(0, 0); break;
- case 27: __asan_set_death_callback(0); break;
- case 28: __asan_set_error_report_callback(0); break;
+ case 25: __asan_register_globals(nullptr, 0); break;
+ case 26: __asan_unregister_globals(nullptr, 0); break;
+ case 27: __asan_set_death_callback(nullptr); break;
+ case 28: __asan_set_error_report_callback(nullptr); break;
case 29: __asan_handle_no_return(); break;
- case 30: __asan_address_is_poisoned(0); break;
- case 31: __asan_poison_memory_region(0, 0); break;
- case 32: __asan_unpoison_memory_region(0, 0); break;
- case 33: __asan_set_error_exit_code(0); break;
- case 34: __asan_before_dynamic_init(0); break;
+ case 30: __asan_address_is_poisoned(nullptr); break;
+ case 31: __asan_poison_memory_region(nullptr, 0); break;
+ case 32: __asan_unpoison_memory_region(nullptr, 0); break;
+ case 34: __asan_before_dynamic_init(nullptr); break;
case 35: __asan_after_dynamic_init(); break;
case 36: __asan_poison_stack_memory(0, 0); break;
case 37: __asan_unpoison_stack_memory(0, 0); break;
@@ -298,9 +326,25 @@ static void InitializeHighMemEnd() {
}
static void ProtectGap(uptr addr, uptr size) {
+ if (!flags()->protect_shadow_gap)
+ return;
void *res = MmapNoAccess(addr, size, "shadow gap");
if (addr == (uptr)res)
return;
+ // A few pages at the start of the address space can not be protected.
+ // But we really want to protect as much as possible, to prevent this memory
+ // being returned as a result of a non-FIXED mmap().
+ if (addr == kZeroBaseShadowStart) {
+ uptr step = GetPageSizeCached();
+ while (size > step && addr < kZeroBaseMaxShadowStart) {
+ addr += step;
+ size -= step;
+ void *res = MmapNoAccess(addr, size, "shadow gap");
+ if (addr == (uptr)res)
+ return;
+ }
+ }
+
Report("ERROR: Failed to protect the shadow gap. "
"ASan cannot proceed correctly. ABORTING.\n");
DumpProcessMap();
@@ -363,12 +407,12 @@ static void AsanInitInternal() {
CHECK(!asan_init_is_running && "ASan init calls itself!");
asan_init_is_running = true;
+ CacheBinaryName();
+
// Initialize flags. This must be done early, because most of the
// initialization steps look at flags().
InitializeFlags();
- CacheBinaryName();
-
AsanCheckIncompatibleRT();
AsanCheckDynamicRTPrereqs();
@@ -381,7 +425,7 @@ static void AsanInitInternal() {
AsanDoesNotSupportStaticLinkage();
// Install tool-specific callbacks in sanitizer_common.
- SetDieCallback(AsanDie);
+ AddDieCallback(AsanDie);
SetCheckFailedCallback(AsanCheckFailed);
SetPrintfAndReportCallback(AppendToErrorMessageBuffer);
@@ -457,7 +501,7 @@ static void AsanInitInternal() {
}
AsanTSDInit(PlatformTSDDtor);
- InstallDeadlySignalHandlers(AsanOnSIGSEGV);
+ InstallDeadlySignalHandlers(AsanOnDeadlySignal);
AllocatorOptions allocator_options;
allocator_options.SetFrom(flags(), common_flags());
@@ -531,24 +575,26 @@ public: // NOLINT
static AsanInitializer asan_initializer;
#endif // ASAN_DYNAMIC
-} // namespace __asan
+} // namespace __asan
// ---------------------- Interface ---------------- {{{1
using namespace __asan; // NOLINT
-int NOINLINE __asan_set_error_exit_code(int exit_code) {
- int old = flags()->exitcode;
- flags()->exitcode = exit_code;
- return old;
-}
-
void NOINLINE __asan_handle_no_return() {
int local_stack;
AsanThread *curr_thread = GetCurrentThread();
- CHECK(curr_thread);
uptr PageSize = GetPageSizeCached();
- uptr top = curr_thread->stack_top();
- uptr bottom = ((uptr)&local_stack - PageSize) & ~(PageSize-1);
+ uptr top, bottom;
+ if (curr_thread) {
+ top = curr_thread->stack_top();
+ bottom = ((uptr)&local_stack - PageSize) & ~(PageSize - 1);
+ } else {
+ // If we haven't seen this thread, try asking the OS for stack bounds.
+ uptr tls_addr, tls_size, stack_size;
+ GetThreadStackAndTls(/*main=*/false, &bottom, &stack_size, &tls_addr,
+ &tls_size);
+ top = bottom + stack_size;
+ }
static const uptr kMaxExpectedCleanupSize = 64 << 20; // 64M
if (top - bottom > kMaxExpectedCleanupSize) {
static bool reported_warning = false;
@@ -559,12 +605,12 @@ void NOINLINE __asan_handle_no_return() {
"stack top: %p; bottom %p; size: %p (%zd)\n"
"False positive error reports may follow\n"
"For details see "
- "http://code.google.com/p/address-sanitizer/issues/detail?id=189\n",
+ "https://github.com/google/sanitizers/issues/189\n",
top, bottom, top - bottom, top - bottom);
return;
}
PoisonShadow(bottom, top - bottom, 0);
- if (curr_thread->has_fake_stack())
+ if (curr_thread && curr_thread->has_fake_stack())
curr_thread->fake_stack()->HandleNoReturn();
}
@@ -578,3 +624,7 @@ void __asan_init() {
AsanActivate();
AsanInitInternal();
}
+
+void __asan_version_mismatch_check() {
+ // Do nothing.
+}
diff --git a/contrib/compiler-rt/lib/asan/asan_stack.h b/contrib/compiler-rt/lib/asan/asan_stack.h
index 122967a152f8..5c5181509801 100644
--- a/contrib/compiler-rt/lib/asan/asan_stack.h
+++ b/contrib/compiler-rt/lib/asan/asan_stack.h
@@ -11,6 +11,7 @@
//
// ASan-private header for asan_stack.cc.
//===----------------------------------------------------------------------===//
+
#ifndef ASAN_STACK_H
#define ASAN_STACK_H
@@ -48,15 +49,15 @@ void GetStackTraceWithPcBpAndContext(BufferedStackTrace *stack, uptr max_depth,
uptr stack_bottom = t->stack_bottom();
ScopedUnwinding unwind_scope(t);
stack->Unwind(max_depth, pc, bp, context, stack_top, stack_bottom, fast);
- } else if (t == 0 && !fast) {
+ } else if (!t && !fast) {
/* If GetCurrentThread() has failed, try to do slow unwind anyways. */
stack->Unwind(max_depth, pc, bp, context, 0, 0, false);
}
}
-#endif // SANITIZER_WINDOWS
+#endif // SANITIZER_WINDOWS
}
-} // namespace __asan
+} // namespace __asan
// NOTE: A Rule of thumb is to retrieve stack trace in the interceptors
// as early as possible (in functions exposed to the user), as we generally
@@ -115,4 +116,4 @@ void GetStackTraceWithPcBpAndContext(BufferedStackTrace *stack, uptr max_depth,
stack.Print(); \
}
-#endif // ASAN_STACK_H
+#endif // ASAN_STACK_H
diff --git a/contrib/compiler-rt/lib/asan/asan_thread.cc b/contrib/compiler-rt/lib/asan/asan_thread.cc
index 9af5706d86d0..69813546f551 100644
--- a/contrib/compiler-rt/lib/asan/asan_thread.cc
+++ b/contrib/compiler-rt/lib/asan/asan_thread.cc
@@ -42,7 +42,7 @@ void AsanThreadContext::OnCreated(void *arg) {
void AsanThreadContext::OnFinished() {
// Drop the link to the AsanThread object.
- thread = 0;
+ thread = nullptr;
}
// MIPS requires aligned address
@@ -125,7 +125,7 @@ void AsanThread::Destroy() {
FakeStack *AsanThread::AsyncSignalSafeLazyInitFakeStack() {
uptr stack_size = this->stack_size();
if (stack_size == 0) // stack_size is not yet available, don't use FakeStack.
- return 0;
+ return nullptr;
uptr old_val = 0;
// fake_stack_ has 3 states:
// 0 -- not initialized
@@ -146,11 +146,11 @@ FakeStack *AsanThread::AsyncSignalSafeLazyInitFakeStack() {
SetTLSFakeStack(fake_stack_);
return fake_stack_;
}
- return 0;
+ return nullptr;
}
void AsanThread::Init() {
- fake_stack_ = 0; // Will be initialized lazily if needed.
+ fake_stack_ = nullptr; // Will be initialized lazily if needed.
CHECK_EQ(this->stack_size(), 0U);
SetThreadStackAndTls();
CHECK_GT(this->stack_size(), 0U);
@@ -161,13 +161,12 @@ void AsanThread::Init() {
VReport(1, "T%d: stack [%p,%p) size 0x%zx; local=%p\n", tid(),
(void *)stack_bottom_, (void *)stack_top_, stack_top_ - stack_bottom_,
&local);
- AsanPlatformThreadInit();
}
thread_return_t AsanThread::ThreadStart(
uptr os_id, atomic_uintptr_t *signal_thread_is_registered) {
Init();
- asanThreadRegistry().StartThread(tid(), os_id, 0);
+ asanThreadRegistry().StartThread(tid(), os_id, nullptr);
if (signal_thread_is_registered)
atomic_store(signal_thread_is_registered, 1, memory_order_release);
@@ -277,7 +276,7 @@ AsanThread *GetCurrentThread() {
return tctx->thread;
}
}
- return 0;
+ return nullptr;
}
return context->thread;
}
@@ -302,7 +301,7 @@ AsanThread *FindThreadByStackAddress(uptr addr) {
AsanThreadContext *tctx = static_cast<AsanThreadContext *>(
asanThreadRegistry().FindThreadContextLocked(ThreadStackContainsAddress,
(void *)addr));
- return tctx ? tctx->thread : 0;
+ return tctx ? tctx->thread : nullptr;
}
void EnsureMainThreadIDIsCorrect() {
@@ -315,10 +314,10 @@ void EnsureMainThreadIDIsCorrect() {
__asan::AsanThread *GetAsanThreadByOsIDLocked(uptr os_id) {
__asan::AsanThreadContext *context = static_cast<__asan::AsanThreadContext *>(
__asan::asanThreadRegistry().FindThreadContextByOsIDLocked(os_id));
- if (!context) return 0;
+ if (!context) return nullptr;
return context->thread;
}
-} // namespace __asan
+} // namespace __asan
// --- Implementation of LSan-specific functions --- {{{1
namespace __lsan {
@@ -355,4 +354,4 @@ void UnlockThreadRegistry() {
void EnsureMainThreadIDIsCorrect() {
__asan::EnsureMainThreadIDIsCorrect();
}
-} // namespace __lsan
+} // namespace __lsan
diff --git a/contrib/compiler-rt/lib/asan/asan_thread.h b/contrib/compiler-rt/lib/asan/asan_thread.h
index 50acfc42d6a2..ac35711f5794 100644
--- a/contrib/compiler-rt/lib/asan/asan_thread.h
+++ b/contrib/compiler-rt/lib/asan/asan_thread.h
@@ -11,6 +11,7 @@
//
// ASan-private header for asan_thread.cc.
//===----------------------------------------------------------------------===//
+
#ifndef ASAN_THREAD_H
#define ASAN_THREAD_H
@@ -36,7 +37,7 @@ class AsanThreadContext : public ThreadContextBase {
explicit AsanThreadContext(int tid)
: ThreadContextBase(tid), announced(false),
destructor_iterations(GetPthreadDestructorIterations()), stack_id(0),
- thread(0) {}
+ thread(nullptr) {}
bool announced;
u8 destructor_iterations;
u32 stack_id;
@@ -84,8 +85,8 @@ class AsanThread {
void DeleteFakeStack(int tid) {
if (!fake_stack_) return;
FakeStack *t = fake_stack_;
- fake_stack_ = 0;
- SetTLSFakeStack(0);
+ fake_stack_ = nullptr;
+ SetTLSFakeStack(nullptr);
t->Destroy(tid);
}
@@ -95,7 +96,7 @@ class AsanThread {
FakeStack *fake_stack() {
if (!__asan_option_detect_stack_use_after_return)
- return 0;
+ return nullptr;
if (!has_fake_stack())
return AsyncSignalSafeLazyInitFakeStack();
return fake_stack_;
@@ -179,6 +180,6 @@ AsanThread *FindThreadByStackAddress(uptr addr);
// Used to handle fork().
void EnsureMainThreadIDIsCorrect();
-} // namespace __asan
+} // namespace __asan
-#endif // ASAN_THREAD_H
+#endif // ASAN_THREAD_H
diff --git a/contrib/compiler-rt/lib/asan/asan_win.cc b/contrib/compiler-rt/lib/asan/asan_win.cc
index addb3d40a696..92bd893d10ef 100644
--- a/contrib/compiler-rt/lib/asan/asan_win.cc
+++ b/contrib/compiler-rt/lib/asan/asan_win.cc
@@ -14,9 +14,9 @@
#include "sanitizer_common/sanitizer_platform.h"
#if SANITIZER_WINDOWS
+#define WIN32_LEAN_AND_MEAN
#include <windows.h>
-#include <dbghelp.h>
#include <stdlib.h>
#include "asan_interceptors.h"
@@ -175,14 +175,6 @@ void PlatformTSDDtor(void *tsd) {
// }}}
// ---------------------- Various stuff ---------------- {{{
-void DisableReexec() {
- // No need to re-exec on Windows.
-}
-
-void MaybeReexec() {
- // No need to re-exec on Windows.
-}
-
void *AsanDoesNotSupportStaticLinkage() {
#if defined(_DEBUG)
#error Please build the runtime with a non-debug CRT: /MD or /MT
@@ -194,15 +186,11 @@ void AsanCheckDynamicRTPrereqs() {}
void AsanCheckIncompatibleRT() {}
-void AsanPlatformThreadInit() {
- // Nothing here for now.
-}
-
void ReadContextStack(void *context, uptr *stack, uptr *ssize) {
UNIMPLEMENTED();
}
-void AsanOnSIGSEGV(int, void *siginfo, void *context) {
+void AsanOnDeadlySignal(int, void *siginfo, void *context) {
UNIMPLEMENTED();
}
@@ -219,7 +207,7 @@ static long WINAPI SEHHandler(EXCEPTION_POINTERS *info) {
? "access-violation"
: "in-page-error";
SignalContext sig = SignalContext::Create(exception_record, context);
- ReportSIGSEGV(description, sig);
+ ReportDeadlySignal(description, sig);
}
// FIXME: Handle EXCEPTION_STACK_OVERFLOW here.
@@ -257,7 +245,7 @@ int __asan_set_seh_filter() {
// Put a pointer to __asan_set_seh_filter at the end of the global list
// of C initializers, after the default EH is set by the CRT.
#pragma section(".CRT$XIZ", long, read) // NOLINT
-static __declspec(allocate(".CRT$XIZ"))
+__declspec(allocate(".CRT$XIZ"))
int (*__intercept_seh)() = __asan_set_seh_filter;
#endif
// }}}
diff --git a/contrib/compiler-rt/lib/asan/asan_win_dll_thunk.cc b/contrib/compiler-rt/lib/asan/asan_win_dll_thunk.cc
index b77f18168ae5..672cabf43ec1 100644
--- a/contrib/compiler-rt/lib/asan/asan_win_dll_thunk.cc
+++ b/contrib/compiler-rt/lib/asan/asan_win_dll_thunk.cc
@@ -12,8 +12,7 @@
// This file defines a family of thunks that should be statically linked into
// the DLLs that have ASan instrumentation in order to delegate the calls to the
// shared runtime that lives in the main binary.
-// See https://code.google.com/p/address-sanitizer/issues/detail?id=209 for the
-// details.
+// See https://github.com/google/sanitizers/issues/209 for the details.
//===----------------------------------------------------------------------===//
// Only compile this code when buidling asan_dll_thunk.lib
@@ -30,8 +29,9 @@ void *__stdcall GetProcAddress(void *module, const char *proc_name);
void abort();
}
-static void *getRealProcAddressOrDie(const char *name) {
- void *ret = GetProcAddress(GetModuleHandleA(0), name);
+static uptr getRealProcAddressOrDie(const char *name) {
+ uptr ret =
+ __interception::InternalGetProcAddress((void *)GetModuleHandleA(0), name);
if (!ret)
abort();
return ret;
@@ -62,13 +62,12 @@ struct FunctionInterceptor<0> {
};
#define INTERCEPT_WHEN_POSSIBLE(main_function, dll_function) \
- template<> struct FunctionInterceptor<__LINE__> { \
+ template <> struct FunctionInterceptor<__LINE__> { \
static void Execute() { \
- void *wrapper = getRealProcAddressOrDie(main_function); \
- if (!__interception::OverrideFunction((uptr)dll_function, \
- (uptr)wrapper, 0)) \
+ uptr wrapper = getRealProcAddressOrDie(main_function); \
+ if (!__interception::OverrideFunction((uptr)dll_function, wrapper, 0)) \
abort(); \
- FunctionInterceptor<__LINE__-1>::Execute(); \
+ FunctionInterceptor<__LINE__ - 1>::Execute(); \
} \
};
@@ -210,7 +209,7 @@ extern "C" {
// __asan_init is expected to be called by only one thread.
if (fn) return;
- fn = (fntype)getRealProcAddressOrDie(__asan_init_name);
+ fn = (fntype)getRealProcAddressOrDie("__asan_init");
fn();
__asan_option_detect_stack_use_after_return =
(__asan_should_detect_stack_use_after_return() != 0);
@@ -219,6 +218,10 @@ extern "C" {
}
}
+extern "C" void __asan_version_mismatch_check() {
+ // Do nothing.
+}
+
INTERFACE_FUNCTION(__asan_handle_no_return)
INTERFACE_FUNCTION(__asan_report_store1)
@@ -253,6 +256,9 @@ INTERFACE_FUNCTION(__asan_memcpy);
INTERFACE_FUNCTION(__asan_memset);
INTERFACE_FUNCTION(__asan_memmove);
+INTERFACE_FUNCTION(__asan_alloca_poison);
+INTERFACE_FUNCTION(__asan_allocas_unpoison);
+
INTERFACE_FUNCTION(__asan_register_globals)
INTERFACE_FUNCTION(__asan_unregister_globals)
@@ -296,6 +302,7 @@ INTERFACE_FUNCTION(__asan_stack_free_10)
// FIXME: we might want to have a sanitizer_win_dll_thunk?
INTERFACE_FUNCTION(__sanitizer_annotate_contiguous_container)
+INTERFACE_FUNCTION(__sanitizer_contiguous_container_find_bad_address)
INTERFACE_FUNCTION(__sanitizer_cov)
INTERFACE_FUNCTION(__sanitizer_cov_dump)
INTERFACE_FUNCTION(__sanitizer_cov_indir_call16)
@@ -304,14 +311,17 @@ INTERFACE_FUNCTION(__sanitizer_cov_module_init)
INTERFACE_FUNCTION(__sanitizer_cov_trace_basic_block)
INTERFACE_FUNCTION(__sanitizer_cov_trace_func_enter)
INTERFACE_FUNCTION(__sanitizer_cov_trace_cmp)
+INTERFACE_FUNCTION(__sanitizer_cov_trace_switch)
INTERFACE_FUNCTION(__sanitizer_cov_with_check)
INTERFACE_FUNCTION(__sanitizer_get_allocated_size)
INTERFACE_FUNCTION(__sanitizer_get_coverage_guards)
+INTERFACE_FUNCTION(__sanitizer_get_coverage_pc_buffer)
INTERFACE_FUNCTION(__sanitizer_get_current_allocated_bytes)
INTERFACE_FUNCTION(__sanitizer_get_estimated_allocated_size)
INTERFACE_FUNCTION(__sanitizer_get_free_bytes)
INTERFACE_FUNCTION(__sanitizer_get_heap_size)
INTERFACE_FUNCTION(__sanitizer_get_ownership)
+INTERFACE_FUNCTION(__sanitizer_get_total_unique_caller_callee_pairs)
INTERFACE_FUNCTION(__sanitizer_get_total_unique_coverage)
INTERFACE_FUNCTION(__sanitizer_get_unmapped_bytes)
INTERFACE_FUNCTION(__sanitizer_maybe_open_cov_file)
diff --git a/contrib/compiler-rt/lib/asan/asan_win_dynamic_runtime_thunk.cc b/contrib/compiler-rt/lib/asan/asan_win_dynamic_runtime_thunk.cc
index d59f9f5768a0..73e5207bb334 100644
--- a/contrib/compiler-rt/lib/asan/asan_win_dynamic_runtime_thunk.cc
+++ b/contrib/compiler-rt/lib/asan/asan_win_dynamic_runtime_thunk.cc
@@ -24,6 +24,7 @@
// Using #ifdef rather than relying on Makefiles etc.
// simplifies the build procedure.
#ifdef ASAN_DYNAMIC_RUNTIME_THUNK
+#define WIN32_LEAN_AND_MEAN
#include <windows.h>
// First, declare CRT sections we'll be using in this file
@@ -58,6 +59,7 @@ int __asan_option_detect_stack_use_after_return =
// using atexit() that calls a small subset of C terminators
// where LLVM global_dtors is placed. Fingers crossed, no other C terminators
// are there.
+extern "C" int __cdecl atexit(void (__cdecl *f)(void));
extern "C" void __cdecl _initterm(void *a, void *b);
namespace {
diff --git a/contrib/compiler-rt/lib/asan/scripts/asan_device_setup b/contrib/compiler-rt/lib/asan/scripts/asan_device_setup
deleted file mode 100755
index 104e07b722ca..000000000000
--- a/contrib/compiler-rt/lib/asan/scripts/asan_device_setup
+++ /dev/null
@@ -1,344 +0,0 @@
-#!/bin/bash
-#===- lib/asan/scripts/asan_device_setup -----------------------------------===#
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-# Prepare Android device to run ASan applications.
-#
-#===------------------------------------------------------------------------===#
-
-set -e
-
-HERE="$(cd "$(dirname "$0")" && pwd)"
-
-revert=no
-extra_options=
-device=
-lib=
-use_su=0
-
-function usage {
- echo "usage: $0 [--revert] [--device device-id] [--lib path] [--extra-options options]"
- echo " --revert: Uninstall ASan from the device."
- echo " --lib: Path to ASan runtime library."
- echo " --extra-options: Extra ASAN_OPTIONS."
- echo " --device: Install to the given device. Use 'adb devices' to find"
- echo " device-id."
- echo " --use-su: Use 'su -c' prefix for every adb command instead of using"
- echo " 'adb root' once."
- echo
- exit 1
-}
-
-function adb_push {
- if [ $use_su -eq 0 ]; then
- $ADB push "$1" "$2"
- else
- local FILENAME=$(basename $1)
- $ADB push "$1" "/data/local/tmp/$FILENAME"
- $ADB shell su -c "rm \\\"$2/$FILENAME\\\"" >&/dev/null
- $ADB shell su -c "cat \\\"/data/local/tmp/$FILENAME\\\" > \\\"$2/$FILENAME\\\""
- $ADB shell su -c "rm \\\"/data/local/tmp/$FILENAME\\\""
- fi
-}
-
-function adb_remount {
- if [ $use_su -eq 0 ]; then
- $ADB remount
- else
- local STORAGE=`$ADB shell mount | grep /system | cut -d ' ' -f1`
- if [ "$STORAGE" != "" ]; then
- echo Remounting $STORAGE at /system
- $ADB shell su -c "mount -o remount,rw $STORAGE /system"
- else
- echo Failed to get storage device name for "/system" mount point
- fi
- fi
-}
-
-function adb_shell {
- if [ $use_su -eq 0 ]; then
- $ADB shell $@
- else
- $ADB shell su -c "$*"
- fi
-}
-
-function adb_root {
- if [ $use_su -eq 0 ]; then
- $ADB root
- fi
-}
-
-function adb_wait_for_device {
- $ADB wait-for-device
-}
-
-function adb_pull {
- if [ $use_su -eq 0 ]; then
- $ADB pull "$1" "$2"
- else
- local FILENAME=$(basename $1)
- $ADB shell rm "/data/local/tmp/$FILENAME" >&/dev/null
- $ADB shell su -c "[ -f \\\"$1\\\" ] && cat \\\"$1\\\" > \\\"/data/local/tmp/$FILENAME\\\" && chown root.shell \\\"/data/local/tmp/$FILENAME\\\" && chmod 755 \\\"/data/local/tmp/$FILENAME\\\"" &&
- $ADB pull "/data/local/tmp/$FILENAME" "$2" >&/dev/null && $ADB shell "rm \"/data/local/tmp/$FILENAME\""
- fi
-}
-
-function get_device_arch { # OUTVAR
- local _outvar=$1
- local _ABI=$(adb_shell getprop ro.product.cpu.abi)
- local _ARCH=
- if [[ $_ABI == x86* ]]; then
- _ARCH=i686
- elif [[ $_ABI == armeabi* ]]; then
- _ARCH=arm
- else
- echo "Unrecognized device ABI: $_ABI"
- exit 1
- fi
- eval $_outvar=\$_ARCH
-}
-
-while [[ $# > 0 ]]; do
- case $1 in
- --revert)
- revert=yes
- ;;
- --extra-options)
- shift
- if [[ $# == 0 ]]; then
- echo "--extra-options requires an argument."
- exit 1
- fi
- extra_options="$1"
- ;;
- --lib)
- shift
- if [[ $# == 0 ]]; then
- echo "--lib requires an argument."
- exit 1
- fi
- lib="$1"
- ;;
- --device)
- shift
- if [[ $# == 0 ]]; then
- echo "--device requires an argument."
- exit 1
- fi
- device="$1"
- ;;
- --use-su)
- use_su=1
- ;;
- *)
- usage
- ;;
- esac
- shift
-done
-
-ADB=${ADB:-adb}
-if [[ x$device != x ]]; then
- ADB="$ADB -s $device"
-fi
-
-if [ $use_su -eq 1 ]; then
- # Test if 'su' is present on the device
- SU_TEST_OUT=`$ADB shell su -c "echo foo" 2>&1 | sed 's/\r$//'`
- if [ $? != 0 -o "$SU_TEST_OUT" != "foo" ]; then
- echo "ERROR: Cannot use 'su -c':"
- echo "$ adb shell su -c \"echo foo\""
- echo $SU_TEST_OUT
- echo "Check that 'su' binary is correctly installed on the device or omit"
- echo " --use-su flag"
- exit 1
- fi
-fi
-
-echo '>> Remounting /system rw'
-adb_wait_for_device
-adb_root
-adb_wait_for_device
-adb_remount
-adb_wait_for_device
-
-get_device_arch ARCH
-echo "Target architecture: $ARCH"
-ASAN_RT="libclang_rt.asan-$ARCH-android.so"
-
-if [[ x$revert == xyes ]]; then
- echo '>> Uninstalling ASan'
-
- if ! adb_shell ls -l /system/bin/app_process | grep -o '\->.*app_process' >&/dev/null; then
- echo '>> Pre-L device detected.'
- adb_shell mv /system/bin/app_process.real /system/bin/app_process
- adb_shell rm /system/bin/asanwrapper
- else
- adb_shell rm /system/bin/app_process.wrap
- adb_shell rm /system/bin/asanwrapper
- adb_shell rm /system/bin/app_process
- adb_shell ln -s /system/bin/app_process32 /system/bin/app_process
- fi
-
- echo '>> Restarting shell'
- adb_shell stop
- adb_shell start
-
- # Remove the library on the last step to give a chance to the 'su' binary to
- # be executed without problem.
- adb_shell rm /system/lib/$ASAN_RT
-
- echo '>> Done'
- exit 0
-fi
-
-if [[ -d "$lib" ]]; then
- ASAN_RT_PATH="$lib"
-elif [[ -f "$lib" && "$lib" == *"$ASAN_RT" ]]; then
- ASAN_RT_PATH=$(dirname "$lib")
-elif [[ -f "$HERE/$ASAN_RT" ]]; then
- ASAN_RT_PATH="$HERE"
-elif [[ $(basename "$HERE") == "bin" ]]; then
- # We could be in the toolchain's base directory.
- # Consider ../lib, ../lib/asan, ../lib/linux and ../lib/clang/$VERSION/lib/linux.
- P=$(ls "$HERE"/../lib/"$ASAN_RT" "$HERE"/../lib/asan/"$ASAN_RT" "$HERE"/../lib/linux/"$ASAN_RT" "$HERE"/../lib/clang/*/lib/linux/"$ASAN_RT" 2>/dev/null | sort | tail -1)
- if [[ -n "$P" ]]; then
- ASAN_RT_PATH="$(dirname "$P")"
- fi
-fi
-
-if [[ -z "$ASAN_RT_PATH" || ! -f "$ASAN_RT_PATH/$ASAN_RT" ]]; then
- echo ">> ASan runtime library not found"
- exit 1
-fi
-
-TMPDIRBASE=$(mktemp -d)
-TMPDIROLD="$TMPDIRBASE/old"
-TMPDIR="$TMPDIRBASE/new"
-mkdir "$TMPDIROLD"
-
-RELEASE=$(adb_shell getprop ro.build.version.release)
-PRE_L=0
-if echo "$RELEASE" | grep '^4\.' >&/dev/null; then
- PRE_L=1
-fi
-
-if ! adb_shell ls -l /system/bin/app_process | grep -o '\->.*app_process' >&/dev/null; then
-
- if adb_pull /system/bin/app_process.real /dev/null >&/dev/null; then
- echo '>> Old-style ASan installation detected. Reverting.'
- adb_shell mv /system/bin/app_process.real /system/bin/app_process
- fi
-
- echo '>> Pre-L device detected. Setting up app_process symlink.'
- adb_shell mv /system/bin/app_process /system/bin/app_process32
- adb_shell ln -s /system/bin/app_process32 /system/bin/app_process
-fi
-
-echo '>> Copying files from the device'
-adb_pull /system/bin/app_process.wrap "$TMPDIROLD" || true
-adb_pull /system/bin/asanwrapper "$TMPDIROLD" || true
-adb_pull /system/lib/"$ASAN_RT" "$TMPDIROLD" || true
-cp -r "$TMPDIROLD" "$TMPDIR"
-
-if [[ -f "$TMPDIR/app_process.wrap" ]]; then
- echo ">> Previous installation detected"
-else
- echo ">> New installation"
-fi
-
-echo '>> Generating wrappers'
-
-cp "$ASAN_RT_PATH/$ASAN_RT" "$TMPDIR/"
-
-# FIXME: alloc_dealloc_mismatch=0 prevents a failure in libdvm startup,
-# which may or may not be a real bug (probably not).
-ASAN_OPTIONS=start_deactivated=1,alloc_dealloc_mismatch=0
-
-# On Android-L not allowing user segv handler breaks some applications.
-if [[ PRE_L -eq 0 ]]; then
- ASAN_OPTIONS="$ASAN_OPTIONS,allow_user_segv_handler=1"
-fi
-
-if [[ x$extra_options != x ]] ; then
- ASAN_OPTIONS="$ASAN_OPTIONS,$extra_options"
-fi
-
-# Zygote wrapper.
-cat <<EOF >"$TMPDIR/app_process.wrap"
-#!/system/bin/sh-from-zygote
-ASAN_OPTIONS=$ASAN_OPTIONS \\
-LD_PRELOAD=\$LD_PRELOAD:$ASAN_RT \\
-exec /system/bin/app_process32 \$@
-
-EOF
-
-# General command-line tool wrapper (use for anything that's not started as
-# zygote).
-cat <<EOF >"$TMPDIR/asanwrapper"
-#!/system/bin/sh
-LD_PRELOAD=$ASAN_RT \\
-exec \$@
-
-EOF
-
-if ! ( cd "$TMPDIRBASE" && diff -qr old/ new/ ) ; then
- echo '>> Pushing files to the device'
- adb_push "$TMPDIR/$ASAN_RT" /system/lib/
- adb_push "$TMPDIR/app_process.wrap" /system/bin
- adb_push "$TMPDIR/asanwrapper" /system/bin
-
- adb_shell rm /system/bin/app_process
- adb_shell ln -s /system/bin/app_process.wrap /system/bin/app_process
-
- adb_shell chown root.shell \
- /system/lib/"$ASAN_RT" \
- /system/bin/app_process.wrap \
- /system/bin/asanwrapper
- adb_shell chmod 644 \
- /system/lib/"$ASAN_RT"
- adb_shell chmod 755 \
- /system/bin/app_process.wrap \
- /system/bin/asanwrapper
-
- # Make SELinux happy by keeping app_process wrapper and the shell
- # it runs on in zygote domain.
- ENFORCING=0
- if adb_shell getenforce | grep Enforcing >/dev/null; then
- # Sometimes shell is not allowed to change file contexts.
- # Temporarily switch to permissive.
- ENFORCING=1
- adb_shell setenforce 0
- fi
-
- adb_shell cp /system/bin/sh /system/bin/sh-from-zygote
-
- if [[ PRE_L -eq 1 ]]; then
- CTX=u:object_r:system_file:s0
- else
- CTX=u:object_r:zygote_exec:s0
- fi
- adb_shell chcon $CTX \
- /system/bin/sh-from-zygote \
- /system/bin/app_process.wrap \
- /system/bin/app_process32
-
- if [ $ENFORCING == 1 ]; then
- adb_shell setenforce 1
- fi
-
- echo '>> Restarting shell (asynchronous)'
- adb_shell stop
- adb_shell start
-
- echo '>> Please wait until the device restarts'
-else
- echo '>> Device is up to date'
-fi
-
-rm -r "$TMPDIRBASE"
diff --git a/contrib/compiler-rt/lib/asan/scripts/asan_symbolize.py b/contrib/compiler-rt/lib/asan/scripts/asan_symbolize.py
deleted file mode 100755
index b9d3ad3ad2fe..000000000000
--- a/contrib/compiler-rt/lib/asan/scripts/asan_symbolize.py
+++ /dev/null
@@ -1,482 +0,0 @@
-#!/usr/bin/env python
-#===- lib/asan/scripts/asan_symbolize.py -----------------------------------===#
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-#===------------------------------------------------------------------------===#
-import argparse
-import bisect
-import getopt
-import os
-import re
-import subprocess
-import sys
-
-symbolizers = {}
-DEBUG = False
-demangle = False
-binutils_prefix = None
-sysroot_path = None
-binary_name_filter = None
-fix_filename_patterns = None
-logfile = sys.stdin
-allow_system_symbolizer = True
-
-# FIXME: merge the code that calls fix_filename().
-def fix_filename(file_name):
- if fix_filename_patterns:
- for path_to_cut in fix_filename_patterns:
- file_name = re.sub('.*' + path_to_cut, '', file_name)
- file_name = re.sub('.*asan_[a-z_]*.cc:[0-9]*', '_asan_rtl_', file_name)
- file_name = re.sub('.*crtstuff.c:0', '???:0', file_name)
- return file_name
-
-def sysroot_path_filter(binary_name):
- return sysroot_path + binary_name
-
-def guess_arch(addr):
- # Guess which arch we're running. 10 = len('0x') + 8 hex digits.
- if len(addr) > 10:
- return 'x86_64'
- else:
- return 'i386'
-
-class Symbolizer(object):
- def __init__(self):
- pass
-
- def symbolize(self, addr, binary, offset):
- """Symbolize the given address (pair of binary and offset).
-
- Overriden in subclasses.
- Args:
- addr: virtual address of an instruction.
- binary: path to executable/shared object containing this instruction.
- offset: instruction offset in the @binary.
- Returns:
- list of strings (one string for each inlined frame) describing
- the code locations for this instruction (that is, function name, file
- name, line and column numbers).
- """
- return None
-
-
-class LLVMSymbolizer(Symbolizer):
- def __init__(self, symbolizer_path, default_arch, system, dsym_hints=[]):
- super(LLVMSymbolizer, self).__init__()
- self.symbolizer_path = symbolizer_path
- self.default_arch = default_arch
- self.system = system
- self.dsym_hints = dsym_hints
- self.pipe = self.open_llvm_symbolizer()
-
- def open_llvm_symbolizer(self):
- cmd = [self.symbolizer_path,
- '--use-symbol-table=true',
- '--demangle=%s' % demangle,
- '--functions=short',
- '--inlining=true',
- '--default-arch=%s' % self.default_arch]
- if self.system == 'Darwin':
- for hint in self.dsym_hints:
- cmd.append('--dsym-hint=%s' % hint)
- if DEBUG:
- print ' '.join(cmd)
- try:
- result = subprocess.Popen(cmd, stdin=subprocess.PIPE,
- stdout=subprocess.PIPE)
- except OSError:
- result = None
- return result
-
- def symbolize(self, addr, binary, offset):
- """Overrides Symbolizer.symbolize."""
- if not self.pipe:
- return None
- result = []
- try:
- symbolizer_input = '"%s" %s' % (binary, offset)
- if DEBUG:
- print symbolizer_input
- print >> self.pipe.stdin, symbolizer_input
- while True:
- function_name = self.pipe.stdout.readline().rstrip()
- if not function_name:
- break
- file_name = self.pipe.stdout.readline().rstrip()
- file_name = fix_filename(file_name)
- if (not function_name.startswith('??') or
- not file_name.startswith('??')):
- # Append only non-trivial frames.
- result.append('%s in %s %s' % (addr, function_name,
- file_name))
- except Exception:
- result = []
- if not result:
- result = None
- return result
-
-
-def LLVMSymbolizerFactory(system, default_arch, dsym_hints=[]):
- symbolizer_path = os.getenv('LLVM_SYMBOLIZER_PATH')
- if not symbolizer_path:
- symbolizer_path = os.getenv('ASAN_SYMBOLIZER_PATH')
- if not symbolizer_path:
- # Assume llvm-symbolizer is in PATH.
- symbolizer_path = 'llvm-symbolizer'
- return LLVMSymbolizer(symbolizer_path, default_arch, system, dsym_hints)
-
-
-class Addr2LineSymbolizer(Symbolizer):
- def __init__(self, binary):
- super(Addr2LineSymbolizer, self).__init__()
- self.binary = binary
- self.pipe = self.open_addr2line()
-
- def open_addr2line(self):
- addr2line_tool = 'addr2line'
- if binutils_prefix:
- addr2line_tool = binutils_prefix + addr2line_tool
- cmd = [addr2line_tool, '-f']
- if demangle:
- cmd += ['--demangle']
- cmd += ['-e', self.binary]
- if DEBUG:
- print ' '.join(cmd)
- return subprocess.Popen(cmd,
- stdin=subprocess.PIPE, stdout=subprocess.PIPE)
-
- def symbolize(self, addr, binary, offset):
- """Overrides Symbolizer.symbolize."""
- if self.binary != binary:
- return None
- try:
- print >> self.pipe.stdin, offset
- function_name = self.pipe.stdout.readline().rstrip()
- file_name = self.pipe.stdout.readline().rstrip()
- except Exception:
- function_name = ''
- file_name = ''
- file_name = fix_filename(file_name)
- return ['%s in %s %s' % (addr, function_name, file_name)]
-
-
-class UnbufferedLineConverter(object):
- """
- Wrap a child process that responds to each line of input with one line of
- output. Uses pty to trick the child into providing unbuffered output.
- """
- def __init__(self, args, close_stderr=False):
- # Local imports so that the script can start on Windows.
- import pty
- import termios
- pid, fd = pty.fork()
- if pid == 0:
- # We're the child. Transfer control to command.
- if close_stderr:
- dev_null = os.open('/dev/null', 0)
- os.dup2(dev_null, 2)
- os.execvp(args[0], args)
- else:
- # Disable echoing.
- attr = termios.tcgetattr(fd)
- attr[3] = attr[3] & ~termios.ECHO
- termios.tcsetattr(fd, termios.TCSANOW, attr)
- # Set up a file()-like interface to the child process
- self.r = os.fdopen(fd, "r", 1)
- self.w = os.fdopen(os.dup(fd), "w", 1)
-
- def convert(self, line):
- self.w.write(line + "\n")
- return self.readline()
-
- def readline(self):
- return self.r.readline().rstrip()
-
-
-class DarwinSymbolizer(Symbolizer):
- def __init__(self, addr, binary):
- super(DarwinSymbolizer, self).__init__()
- self.binary = binary
- self.arch = guess_arch(addr)
- self.open_atos()
-
- def open_atos(self):
- if DEBUG:
- print 'atos -o %s -arch %s' % (self.binary, self.arch)
- cmdline = ['atos', '-o', self.binary, '-arch', self.arch]
- self.atos = UnbufferedLineConverter(cmdline, close_stderr=True)
-
- def symbolize(self, addr, binary, offset):
- """Overrides Symbolizer.symbolize."""
- if self.binary != binary:
- return None
- atos_line = self.atos.convert('0x%x' % int(offset, 16))
- while "got symbolicator for" in atos_line:
- atos_line = self.atos.readline()
- # A well-formed atos response looks like this:
- # foo(type1, type2) (in object.name) (filename.cc:80)
- match = re.match('^(.*) \(in (.*)\) \((.*:\d*)\)$', atos_line)
- if DEBUG:
- print 'atos_line: ', atos_line
- if match:
- function_name = match.group(1)
- function_name = re.sub('\(.*?\)', '', function_name)
- file_name = fix_filename(match.group(3))
- return ['%s in %s %s' % (addr, function_name, file_name)]
- else:
- return ['%s in %s' % (addr, atos_line)]
-
-
-# Chain several symbolizers so that if one symbolizer fails, we fall back
-# to the next symbolizer in chain.
-class ChainSymbolizer(Symbolizer):
- def __init__(self, symbolizer_list):
- super(ChainSymbolizer, self).__init__()
- self.symbolizer_list = symbolizer_list
-
- def symbolize(self, addr, binary, offset):
- """Overrides Symbolizer.symbolize."""
- for symbolizer in self.symbolizer_list:
- if symbolizer:
- result = symbolizer.symbolize(addr, binary, offset)
- if result:
- return result
- return None
-
- def append_symbolizer(self, symbolizer):
- self.symbolizer_list.append(symbolizer)
-
-
-def BreakpadSymbolizerFactory(binary):
- suffix = os.getenv('BREAKPAD_SUFFIX')
- if suffix:
- filename = binary + suffix
- if os.access(filename, os.F_OK):
- return BreakpadSymbolizer(filename)
- return None
-
-
-def SystemSymbolizerFactory(system, addr, binary):
- if system == 'Darwin':
- return DarwinSymbolizer(addr, binary)
- elif system == 'Linux':
- return Addr2LineSymbolizer(binary)
-
-
-class BreakpadSymbolizer(Symbolizer):
- def __init__(self, filename):
- super(BreakpadSymbolizer, self).__init__()
- self.filename = filename
- lines = file(filename).readlines()
- self.files = []
- self.symbols = {}
- self.address_list = []
- self.addresses = {}
- # MODULE mac x86_64 A7001116478B33F18FF9BEDE9F615F190 t
- fragments = lines[0].rstrip().split()
- self.arch = fragments[2]
- self.debug_id = fragments[3]
- self.binary = ' '.join(fragments[4:])
- self.parse_lines(lines[1:])
-
- def parse_lines(self, lines):
- cur_function_addr = ''
- for line in lines:
- fragments = line.split()
- if fragments[0] == 'FILE':
- assert int(fragments[1]) == len(self.files)
- self.files.append(' '.join(fragments[2:]))
- elif fragments[0] == 'PUBLIC':
- self.symbols[int(fragments[1], 16)] = ' '.join(fragments[3:])
- elif fragments[0] in ['CFI', 'STACK']:
- pass
- elif fragments[0] == 'FUNC':
- cur_function_addr = int(fragments[1], 16)
- if not cur_function_addr in self.symbols.keys():
- self.symbols[cur_function_addr] = ' '.join(fragments[4:])
- else:
- # Line starting with an address.
- addr = int(fragments[0], 16)
- self.address_list.append(addr)
- # Tuple of symbol address, size, line, file number.
- self.addresses[addr] = (cur_function_addr,
- int(fragments[1], 16),
- int(fragments[2]),
- int(fragments[3]))
- self.address_list.sort()
-
- def get_sym_file_line(self, addr):
- key = None
- if addr in self.addresses.keys():
- key = addr
- else:
- index = bisect.bisect_left(self.address_list, addr)
- if index == 0:
- return None
- else:
- key = self.address_list[index - 1]
- sym_id, size, line_no, file_no = self.addresses[key]
- symbol = self.symbols[sym_id]
- filename = self.files[file_no]
- if addr < key + size:
- return symbol, filename, line_no
- else:
- return None
-
- def symbolize(self, addr, binary, offset):
- if self.binary != binary:
- return None
- res = self.get_sym_file_line(int(offset, 16))
- if res:
- function_name, file_name, line_no = res
- result = ['%s in %s %s:%d' % (
- addr, function_name, file_name, line_no)]
- print result
- return result
- else:
- return None
-
-
-class SymbolizationLoop(object):
- def __init__(self, binary_name_filter=None, dsym_hint_producer=None):
- if sys.platform == 'win32':
- # ASan on Windows uses dbghelp.dll to symbolize in-process, which works
- # even in sandboxed processes. Nothing needs to be done here.
- self.process_line = self.process_line_echo
- else:
- # Used by clients who may want to supply a different binary name.
- # E.g. in Chrome several binaries may share a single .dSYM.
- self.binary_name_filter = binary_name_filter
- self.dsym_hint_producer = dsym_hint_producer
- self.system = os.uname()[0]
- if self.system not in ['Linux', 'Darwin', 'FreeBSD']:
- raise Exception('Unknown system')
- self.llvm_symbolizers = {}
- self.last_llvm_symbolizer = None
- self.dsym_hints = set([])
- self.frame_no = 0
- self.process_line = self.process_line_posix
-
- def symbolize_address(self, addr, binary, offset):
- # On non-Darwin (i.e. on platforms without .dSYM debug info) always use
- # a single symbolizer binary.
- # On Darwin, if the dsym hint producer is present:
- # 1. check whether we've seen this binary already; if so,
- # use |llvm_symbolizers[binary]|, which has already loaded the debug
- # info for this binary (might not be the case for
- # |last_llvm_symbolizer|);
- # 2. otherwise check if we've seen all the hints for this binary already;
- # if so, reuse |last_llvm_symbolizer| which has the full set of hints;
- # 3. otherwise create a new symbolizer and pass all currently known
- # .dSYM hints to it.
- if not binary in self.llvm_symbolizers:
- use_new_symbolizer = True
- if self.system == 'Darwin' and self.dsym_hint_producer:
- dsym_hints_for_binary = set(self.dsym_hint_producer(binary))
- use_new_symbolizer = bool(dsym_hints_for_binary - self.dsym_hints)
- self.dsym_hints |= dsym_hints_for_binary
- if self.last_llvm_symbolizer and not use_new_symbolizer:
- self.llvm_symbolizers[binary] = self.last_llvm_symbolizer
- else:
- self.last_llvm_symbolizer = LLVMSymbolizerFactory(
- self.system, guess_arch(addr), self.dsym_hints)
- self.llvm_symbolizers[binary] = self.last_llvm_symbolizer
- # Use the chain of symbolizers:
- # Breakpad symbolizer -> LLVM symbolizer -> addr2line/atos
- # (fall back to next symbolizer if the previous one fails).
- if not binary in symbolizers:
- symbolizers[binary] = ChainSymbolizer(
- [BreakpadSymbolizerFactory(binary), self.llvm_symbolizers[binary]])
- result = symbolizers[binary].symbolize(addr, binary, offset)
- if result is None:
- if not allow_system_symbolizer:
- raise Exception('Failed to launch or use llvm-symbolizer.')
- # Initialize system symbolizer only if other symbolizers failed.
- symbolizers[binary].append_symbolizer(
- SystemSymbolizerFactory(self.system, addr, binary))
- result = symbolizers[binary].symbolize(addr, binary, offset)
- # The system symbolizer must produce some result.
- assert result
- return result
-
- def get_symbolized_lines(self, symbolized_lines):
- if not symbolized_lines:
- return [self.current_line]
- else:
- result = []
- for symbolized_frame in symbolized_lines:
- result.append(' #%s %s' % (str(self.frame_no), symbolized_frame.rstrip()))
- self.frame_no += 1
- return result
-
- def process_logfile(self):
- self.frame_no = 0
- for line in logfile:
- processed = self.process_line(line)
- print '\n'.join(processed)
-
- def process_line_echo(self, line):
- return [line.rstrip()]
-
- def process_line_posix(self, line):
- self.current_line = line.rstrip()
- #0 0x7f6e35cf2e45 (/blah/foo.so+0x11fe45)
- stack_trace_line_format = (
- '^( *#([0-9]+) *)(0x[0-9a-f]+) *\((.*)\+(0x[0-9a-f]+)\)')
- match = re.match(stack_trace_line_format, line)
- if not match:
- return [self.current_line]
- if DEBUG:
- print line
- _, frameno_str, addr, binary, offset = match.groups()
- if frameno_str == '0':
- # Assume that frame #0 is the first frame of new stack trace.
- self.frame_no = 0
- original_binary = binary
- if self.binary_name_filter:
- binary = self.binary_name_filter(binary)
- symbolized_line = self.symbolize_address(addr, binary, offset)
- if not symbolized_line:
- if original_binary != binary:
- symbolized_line = self.symbolize_address(addr, binary, offset)
- return self.get_symbolized_lines(symbolized_line)
-
-
-if __name__ == '__main__':
- parser = argparse.ArgumentParser(
- formatter_class=argparse.RawDescriptionHelpFormatter,
- description='ASan symbolization script',
- epilog='Example of use:\n'
- 'asan_symbolize.py -c "$HOME/opt/cross/bin/arm-linux-gnueabi-" '
- '-s "$HOME/SymbolFiles" < asan.log')
- parser.add_argument('path_to_cut', nargs='*',
- help='pattern to be cut from the result file path ')
- parser.add_argument('-d','--demangle', action='store_true',
- help='demangle function names')
- parser.add_argument('-s', metavar='SYSROOT',
- help='set path to sysroot for sanitized binaries')
- parser.add_argument('-c', metavar='CROSS_COMPILE',
- help='set prefix for binutils')
- parser.add_argument('-l','--logfile', default=sys.stdin,
- type=argparse.FileType('r'),
- help='set log file name to parse, default is stdin')
- args = parser.parse_args()
- if args.path_to_cut:
- fix_filename_patterns = args.path_to_cut
- if args.demangle:
- demangle = True
- if args.s:
- binary_name_filter = sysroot_path_filter
- sysroot_path = args.s
- if args.c:
- binutils_prefix = args.c
- if args.logfile:
- logfile = args.logfile
- else:
- logfile = sys.stdin
- loop = SymbolizationLoop(binary_name_filter)
- loop.process_logfile()
diff --git a/contrib/compiler-rt/lib/asan/tests/asan_asm_test.cc b/contrib/compiler-rt/lib/asan/tests/asan_asm_test.cc
deleted file mode 100644
index 200de2c137a5..000000000000
--- a/contrib/compiler-rt/lib/asan/tests/asan_asm_test.cc
+++ /dev/null
@@ -1,267 +0,0 @@
-//===-- asan_asm_test.cc --------------------------------------------------===//
-//
-// 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 AddressSanitizer, an address sanity checker.
-//
-//===----------------------------------------------------------------------===//
-#include "asan_test_utils.h"
-
-#if defined(__linux__)
-
-#if defined(__x86_64__) || (defined(__i386__) && defined(__SSE2__))
-
-#include <emmintrin.h>
-
-namespace {
-
-template<typename T> void asm_write(T *ptr, T val);
-template<typename T> T asm_read(T *ptr);
-template<typename T> void asm_rep_movs(T *dst, T *src, size_t n);
-
-} // End of anonymous namespace
-
-#endif // defined(__x86_64__) || (defined(__i386__) && defined(__SSE2__))
-
-#if defined(__x86_64__)
-
-namespace {
-
-#define DECLARE_ASM_WRITE(Type, Size, Mov, Reg) \
-template<> void asm_write<Type>(Type *ptr, Type val) { \
- __asm__( \
- Mov " %[val], (%[ptr]) \n\t" \
- : \
- : [ptr] "r" (ptr), [val] Reg (val) \
- : "memory" \
- ); \
-}
-
-#define DECLARE_ASM_READ(Type, Size, Mov, Reg) \
-template<> Type asm_read<Type>(Type *ptr) { \
- Type res; \
- __asm__( \
- Mov " (%[ptr]), %[res] \n\t" \
- : [res] Reg (res) \
- : [ptr] "r" (ptr) \
- : "memory" \
- ); \
- return res; \
-}
-
-#define DECLARE_ASM_REP_MOVS(Type, Movs) \
- template <> void asm_rep_movs<Type>(Type * dst, Type * src, size_t size) { \
- __asm__("rep " Movs " \n\t" \
- : \
- : "D"(dst), "S"(src), "c"(size) \
- : "rsi", "rdi", "rcx", "memory"); \
- }
-
-DECLARE_ASM_WRITE(U8, "8", "movq", "r");
-DECLARE_ASM_READ(U8, "8", "movq", "=r");
-DECLARE_ASM_REP_MOVS(U8, "movsq");
-
-} // End of anonymous namespace
-
-#endif // defined(__x86_64__)
-
-#if defined(__i386__) && defined(__SSE2__)
-
-namespace {
-
-#define DECLARE_ASM_WRITE(Type, Size, Mov, Reg) \
-template<> void asm_write<Type>(Type *ptr, Type val) { \
- __asm__( \
- Mov " %[val], (%[ptr]) \n\t" \
- : \
- : [ptr] "r" (ptr), [val] Reg (val) \
- : "memory" \
- ); \
-}
-
-#define DECLARE_ASM_READ(Type, Size, Mov, Reg) \
-template<> Type asm_read<Type>(Type *ptr) { \
- Type res; \
- __asm__( \
- Mov " (%[ptr]), %[res] \n\t" \
- : [res] Reg (res) \
- : [ptr] "r" (ptr) \
- : "memory" \
- ); \
- return res; \
-}
-
-#define DECLARE_ASM_REP_MOVS(Type, Movs) \
- template <> void asm_rep_movs<Type>(Type * dst, Type * src, size_t size) { \
- __asm__("rep " Movs " \n\t" \
- : \
- : "D"(dst), "S"(src), "c"(size) \
- : "esi", "edi", "ecx", "memory"); \
- }
-
-} // End of anonymous namespace
-
-#endif // defined(__i386__) && defined(__SSE2__)
-
-#if defined(__x86_64__) || (defined(__i386__) && defined(__SSE2__))
-
-namespace {
-
-DECLARE_ASM_WRITE(U1, "1", "movb", "r");
-DECLARE_ASM_WRITE(U2, "2", "movw", "r");
-DECLARE_ASM_WRITE(U4, "4", "movl", "r");
-DECLARE_ASM_WRITE(__m128i, "16", "movaps", "x");
-
-DECLARE_ASM_READ(U1, "1", "movb", "=r");
-DECLARE_ASM_READ(U2, "2", "movw", "=r");
-DECLARE_ASM_READ(U4, "4", "movl", "=r");
-DECLARE_ASM_READ(__m128i, "16", "movaps", "=x");
-
-DECLARE_ASM_REP_MOVS(U1, "movsb");
-DECLARE_ASM_REP_MOVS(U2, "movsw");
-DECLARE_ASM_REP_MOVS(U4, "movsl");
-
-template<typename T> void TestAsmWrite(const char *DeathPattern) {
- T *buf = new T;
- EXPECT_DEATH(asm_write(&buf[1], static_cast<T>(0)), DeathPattern);
- T var = 0x12;
- asm_write(&var, static_cast<T>(0x21));
- ASSERT_EQ(static_cast<T>(0x21), var);
- delete buf;
-}
-
-template<> void TestAsmWrite<__m128i>(const char *DeathPattern) {
- char *buf = new char[16];
- char *p = buf + 16;
- if (((uintptr_t) p % 16) != 0)
- p = buf + 8;
- assert(((uintptr_t) p % 16) == 0);
- __m128i val = _mm_set1_epi16(0x1234);
- EXPECT_DEATH(asm_write<__m128i>((__m128i*) p, val), DeathPattern);
- __m128i var = _mm_set1_epi16(0x4321);
- asm_write(&var, val);
- ASSERT_EQ(0x1234, _mm_extract_epi16(var, 0));
- delete [] buf;
-}
-
-template<typename T> void TestAsmRead(const char *DeathPattern) {
- T *buf = new T;
- EXPECT_DEATH(asm_read(&buf[1]), DeathPattern);
- T var = 0x12;
- ASSERT_EQ(static_cast<T>(0x12), asm_read(&var));
- delete buf;
-}
-
-template<> void TestAsmRead<__m128i>(const char *DeathPattern) {
- char *buf = new char[16];
- char *p = buf + 16;
- if (((uintptr_t) p % 16) != 0)
- p = buf + 8;
- assert(((uintptr_t) p % 16) == 0);
- EXPECT_DEATH(asm_read<__m128i>((__m128i*) p), DeathPattern);
- __m128i val = _mm_set1_epi16(0x1234);
- ASSERT_EQ(0x1234, _mm_extract_epi16(asm_read(&val), 0));
- delete [] buf;
-}
-
-U4 AsmLoad(U4 *a) {
- U4 r;
- __asm__("movl (%[a]), %[r] \n\t" : [r] "=r" (r) : [a] "r" (a) : "memory");
- return r;
-}
-
-void AsmStore(U4 r, U4 *a) {
- __asm__("movl %[r], (%[a]) \n\t" : : [a] "r" (a), [r] "r" (r) : "memory");
-}
-
-template <typename T>
-void TestAsmRepMovs(const char *DeathPatternRead,
- const char *DeathPatternWrite) {
- T src_good[4] = { 0x0, 0x1, 0x2, 0x3 };
- T dst_good[4] = {};
- asm_rep_movs(dst_good, src_good, 4);
- ASSERT_EQ(static_cast<T>(0x0), dst_good[0]);
- ASSERT_EQ(static_cast<T>(0x1), dst_good[1]);
- ASSERT_EQ(static_cast<T>(0x2), dst_good[2]);
- ASSERT_EQ(static_cast<T>(0x3), dst_good[3]);
-
- T dst_bad[3];
- EXPECT_DEATH(asm_rep_movs(dst_bad, src_good, 4), DeathPatternWrite);
-
- T src_bad[3] = { 0x0, 0x1, 0x2 };
- EXPECT_DEATH(asm_rep_movs(dst_good, src_bad, 4), DeathPatternRead);
-
- T* dp = dst_bad + 4;
- T* sp = src_bad + 4;
- asm_rep_movs(dp, sp, 0);
-}
-
-} // End of anonymous namespace
-
-TEST(AddressSanitizer, asm_load_store) {
- U4* buf = new U4[2];
- EXPECT_DEATH(AsmLoad(&buf[3]), "READ of size 4");
- EXPECT_DEATH(AsmStore(0x1234, &buf[3]), "WRITE of size 4");
- delete [] buf;
-}
-
-TEST(AddressSanitizer, asm_rw) {
- TestAsmWrite<U1>("WRITE of size 1");
- TestAsmWrite<U2>("WRITE of size 2");
- TestAsmWrite<U4>("WRITE of size 4");
-#if defined(__x86_64__)
- TestAsmWrite<U8>("WRITE of size 8");
-#endif // defined(__x86_64__)
- TestAsmWrite<__m128i>("WRITE of size 16");
-
- TestAsmRead<U1>("READ of size 1");
- TestAsmRead<U2>("READ of size 2");
- TestAsmRead<U4>("READ of size 4");
-#if defined(__x86_64__)
- TestAsmRead<U8>("READ of size 8");
-#endif // defined(__x86_64__)
- TestAsmRead<__m128i>("READ of size 16");
-}
-
-TEST(AddressSanitizer, asm_flags) {
- long magic = 0x1234;
- long r = 0x0;
-
-#if defined(__x86_64__) && !defined(__ILP32__)
- __asm__("xorq %%rax, %%rax \n\t"
- "movq (%[p]), %%rax \n\t"
- "sete %%al \n\t"
- "movzbq %%al, %[r] \n\t"
- : [r] "=r"(r)
- : [p] "r"(&magic)
- : "rax", "memory");
-#else
- __asm__("xorl %%eax, %%eax \n\t"
- "movl (%[p]), %%eax \n\t"
- "sete %%al \n\t"
- "movzbl %%al, %[r] \n\t"
- : [r] "=r"(r)
- : [p] "r"(&magic)
- : "eax", "memory");
-#endif // defined(__x86_64__) && !defined(__ILP32__)
-
- ASSERT_EQ(0x1, r);
-}
-
-TEST(AddressSanitizer, asm_rep_movs) {
- TestAsmRepMovs<U1>("READ of size 1", "WRITE of size 1");
- TestAsmRepMovs<U2>("READ of size 2", "WRITE of size 2");
- TestAsmRepMovs<U4>("READ of size 4", "WRITE of size 4");
-#if defined(__x86_64__)
- TestAsmRepMovs<U8>("READ of size 8", "WRITE of size 8");
-#endif // defined(__x86_64__)
-}
-
-#endif // defined(__x86_64__) || (defined(__i386__) && defined(__SSE2__))
-
-#endif // defined(__linux__)
diff --git a/contrib/compiler-rt/lib/asan/tests/asan_benchmarks_test.cc b/contrib/compiler-rt/lib/asan/tests/asan_benchmarks_test.cc
deleted file mode 100644
index fc522de475fa..000000000000
--- a/contrib/compiler-rt/lib/asan/tests/asan_benchmarks_test.cc
+++ /dev/null
@@ -1,85 +0,0 @@
-//===-- asan_benchmarks_test.cc ----------------------===//
-//
-// 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 AddressSanitizer, an address sanity checker.
-//
-// Some benchmarks for the instrumented code.
-//===----------------------------------------------------------------------===//
-
-#include "asan_test_utils.h"
-
-template<class T>
-__attribute__((noinline))
-static void ManyAccessFunc(T *x, size_t n_elements, size_t n_iter) {
- for (size_t iter = 0; iter < n_iter; iter++) {
- break_optimization(0);
- // hand unroll the loop to stress the reg alloc.
- for (size_t i = 0; i <= n_elements - 16; i += 16) {
- x[i + 0] = i;
- x[i + 1] = i;
- x[i + 2] = i;
- x[i + 3] = i;
- x[i + 4] = i;
- x[i + 5] = i;
- x[i + 6] = i;
- x[i + 7] = i;
- x[i + 8] = i;
- x[i + 9] = i;
- x[i + 10] = i;
- x[i + 11] = i;
- x[i + 12] = i;
- x[i + 13] = i;
- x[i + 14] = i;
- x[i + 15] = i;
- }
- }
-}
-
-TEST(AddressSanitizer, ManyAccessBenchmark) {
- size_t kLen = 1024;
- int *int_array = new int[kLen];
- ManyAccessFunc(int_array, kLen, 1 << 24);
- delete [] int_array;
-}
-
-// access 7 char elements in a 7 byte array (i.e. on the border).
-__attribute__((noinline))
-static void BorderAccessFunc(char *x, size_t n_iter) {
- for (size_t iter = 0; iter < n_iter; iter++) {
- break_optimization(x);
- x[0] = 0;
- x[1] = 0;
- x[2] = 0;
- x[3] = 0;
- x[4] = 0;
- x[5] = 0;
- x[6] = 0;
- }
-}
-
-TEST(AddressSanitizer, BorderAccessBenchmark) {
- char *char_7_array = new char[7];
- BorderAccessFunc(char_7_array, 1 << 30);
- delete [] char_7_array;
-}
-
-static void FunctionWithLargeStack() {
- int stack[1000];
- Ident(stack);
-}
-
-TEST(AddressSanitizer, FakeStackBenchmark) {
- for (int i = 0; i < 10000000; i++)
- Ident(&FunctionWithLargeStack)();
-}
-
-int main(int argc, char **argv) {
- testing::InitGoogleTest(&argc, argv);
- return RUN_ALL_TESTS();
-}
diff --git a/contrib/compiler-rt/lib/asan/tests/asan_exceptions_test.cc b/contrib/compiler-rt/lib/asan/tests/asan_exceptions_test.cc
deleted file mode 100644
index ecd406de7561..000000000000
--- a/contrib/compiler-rt/lib/asan/tests/asan_exceptions_test.cc
+++ /dev/null
@@ -1,27 +0,0 @@
-// See http://llvm.org/bugs/show_bug.cgi?id=11468
-#include <stdio.h>
-#include <string>
-
-class Action {
- public:
- Action() {}
- void PrintString(const std::string& msg) const {
- fprintf(stderr, "%s\n", msg.c_str());
- }
- void Throw(const char& arg) const {
- PrintString("PrintString called!"); // this line is important
- throw arg;
- }
-};
-
-int main() {
- const Action a;
- fprintf(stderr, "&a before = %p\n", &a);
- try {
- a.Throw('c');
- } catch(const char&) {
- fprintf(stderr, "&a in catch = %p\n", &a);
- }
- fprintf(stderr, "&a final = %p\n", &a);
- return 0;
-}
diff --git a/contrib/compiler-rt/lib/asan/tests/asan_fake_stack_test.cc b/contrib/compiler-rt/lib/asan/tests/asan_fake_stack_test.cc
deleted file mode 100644
index 516142f0c3b7..000000000000
--- a/contrib/compiler-rt/lib/asan/tests/asan_fake_stack_test.cc
+++ /dev/null
@@ -1,152 +0,0 @@
-//===-- asan_fake_stack_test.cc -------------------------------------------===//
-//
-// 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 AddressSanitizer, an address sanity checker.
-//
-// Tests for FakeStack.
-// This test file should be compiled w/o asan instrumentation.
-//===----------------------------------------------------------------------===//
-
-#include "asan_fake_stack.h"
-#include "asan_test_utils.h"
-#include "sanitizer_common/sanitizer_common.h"
-
-#include <assert.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-#include <map>
-
-namespace __asan {
-
-TEST(FakeStack, FlagsSize) {
- EXPECT_EQ(FakeStack::SizeRequiredForFlags(10), 1U << 5);
- EXPECT_EQ(FakeStack::SizeRequiredForFlags(11), 1U << 6);
- EXPECT_EQ(FakeStack::SizeRequiredForFlags(20), 1U << 15);
-}
-
-TEST(FakeStack, RequiredSize) {
- // for (int i = 15; i < 20; i++) {
- // uptr alloc_size = FakeStack::RequiredSize(i);
- // printf("%zdK ==> %zd\n", 1 << (i - 10), alloc_size);
- // }
- EXPECT_EQ(FakeStack::RequiredSize(15), 365568U);
- EXPECT_EQ(FakeStack::RequiredSize(16), 727040U);
- EXPECT_EQ(FakeStack::RequiredSize(17), 1449984U);
- EXPECT_EQ(FakeStack::RequiredSize(18), 2895872U);
- EXPECT_EQ(FakeStack::RequiredSize(19), 5787648U);
-}
-
-TEST(FakeStack, FlagsOffset) {
- for (uptr stack_size_log = 15; stack_size_log <= 20; stack_size_log++) {
- uptr stack_size = 1UL << stack_size_log;
- uptr offset = 0;
- for (uptr class_id = 0; class_id < FakeStack::kNumberOfSizeClasses;
- class_id++) {
- uptr frame_size = FakeStack::BytesInSizeClass(class_id);
- uptr num_flags = stack_size / frame_size;
- EXPECT_EQ(offset, FakeStack::FlagsOffset(stack_size_log, class_id));
- // printf("%zd: %zd => %zd %zd\n", stack_size_log, class_id, offset,
- // FakeStack::FlagsOffset(stack_size_log, class_id));
- offset += num_flags;
- }
- }
-}
-
-#if !defined(_WIN32) // FIXME: Fails due to OOM on Windows.
-TEST(FakeStack, CreateDestroy) {
- for (int i = 0; i < 1000; i++) {
- for (uptr stack_size_log = 20; stack_size_log <= 22; stack_size_log++) {
- FakeStack *fake_stack = FakeStack::Create(stack_size_log);
- fake_stack->Destroy(0);
- }
- }
-}
-#endif
-
-TEST(FakeStack, ModuloNumberOfFrames) {
- EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 0, 0), 0U);
- EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 0, (1<<15)), 0U);
- EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 0, (1<<10)), 0U);
- EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 0, (1<<9)), 0U);
- EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 0, (1<<8)), 1U<<8);
- EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 0, (1<<15) + 1), 1U);
-
- EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 1, 0), 0U);
- EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 1, 1<<9), 0U);
- EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 1, 1<<8), 0U);
- EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 1, 1<<7), 1U<<7);
-
- EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 5, 0), 0U);
- EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 5, 1), 1U);
- EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 5, 15), 15U);
- EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 5, 16), 0U);
- EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 5, 17), 1U);
-}
-
-TEST(FakeStack, GetFrame) {
- const uptr stack_size_log = 20;
- const uptr stack_size = 1 << stack_size_log;
- FakeStack *fs = FakeStack::Create(stack_size_log);
- u8 *base = fs->GetFrame(stack_size_log, 0, 0);
- EXPECT_EQ(base, reinterpret_cast<u8 *>(fs) +
- fs->SizeRequiredForFlags(stack_size_log) + 4096);
- EXPECT_EQ(base + 0*stack_size + 64 * 7, fs->GetFrame(stack_size_log, 0, 7U));
- EXPECT_EQ(base + 1*stack_size + 128 * 3, fs->GetFrame(stack_size_log, 1, 3U));
- EXPECT_EQ(base + 2*stack_size + 256 * 5, fs->GetFrame(stack_size_log, 2, 5U));
- fs->Destroy(0);
-}
-
-TEST(FakeStack, Allocate) {
- const uptr stack_size_log = 19;
- FakeStack *fs = FakeStack::Create(stack_size_log);
- std::map<FakeFrame *, uptr> s;
- for (int iter = 0; iter < 2; iter++) {
- s.clear();
- for (uptr cid = 0; cid < FakeStack::kNumberOfSizeClasses; cid++) {
- uptr n = FakeStack::NumberOfFrames(stack_size_log, cid);
- uptr bytes_in_class = FakeStack::BytesInSizeClass(cid);
- for (uptr j = 0; j < n; j++) {
- FakeFrame *ff = fs->Allocate(stack_size_log, cid, 0);
- uptr x = reinterpret_cast<uptr>(ff);
- EXPECT_TRUE(s.insert(std::make_pair(ff, cid)).second);
- EXPECT_EQ(x, fs->AddrIsInFakeStack(x));
- EXPECT_EQ(x, fs->AddrIsInFakeStack(x + 1));
- EXPECT_EQ(x, fs->AddrIsInFakeStack(x + bytes_in_class - 1));
- EXPECT_NE(x, fs->AddrIsInFakeStack(x + bytes_in_class));
- }
- // We are out of fake stack, so Allocate should return 0.
- EXPECT_EQ(0UL, fs->Allocate(stack_size_log, cid, 0));
- }
- for (std::map<FakeFrame *, uptr>::iterator it = s.begin(); it != s.end();
- ++it) {
- fs->Deallocate(reinterpret_cast<uptr>(it->first), it->second);
- }
- }
- fs->Destroy(0);
-}
-
-static void RecursiveFunction(FakeStack *fs, int depth) {
- uptr class_id = depth / 3;
- FakeFrame *ff = fs->Allocate(fs->stack_size_log(), class_id, 0);
- if (depth) {
- RecursiveFunction(fs, depth - 1);
- RecursiveFunction(fs, depth - 1);
- }
- fs->Deallocate(reinterpret_cast<uptr>(ff), class_id);
-}
-
-TEST(FakeStack, RecursiveStressTest) {
- const uptr stack_size_log = 16;
- FakeStack *fs = FakeStack::Create(stack_size_log);
- RecursiveFunction(fs, 22); // with 26 runs for 2-3 seconds.
- fs->Destroy(0);
-}
-
-} // namespace __asan
diff --git a/contrib/compiler-rt/lib/asan/tests/asan_globals_test.cc b/contrib/compiler-rt/lib/asan/tests/asan_globals_test.cc
deleted file mode 100644
index 5042ef07378d..000000000000
--- a/contrib/compiler-rt/lib/asan/tests/asan_globals_test.cc
+++ /dev/null
@@ -1,45 +0,0 @@
-//===-- asan_globals_test.cc ----------------------------------------------===//
-//
-// 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 AddressSanitizer, an address sanity checker.
-//
-// Some globals in a separate file.
-//===----------------------------------------------------------------------===//
-#include "asan_test_utils.h"
-
-char glob1[1];
-char glob2[2];
-char glob3[3];
-char glob4[4];
-char glob5[5];
-char glob6[6];
-char glob7[7];
-char glob8[8];
-char glob9[9];
-char glob10[10];
-char glob11[11];
-char glob12[12];
-char glob13[13];
-char glob14[14];
-char glob15[15];
-char glob16[16];
-char glob17[17];
-char glob1000[1000];
-char glob10000[10000];
-char glob100000[100000];
-
-static char static10[10];
-
-int GlobalsTest(int zero) {
- static char func_static15[15];
- glob5[zero] = 0;
- static10[zero] = 0;
- func_static15[zero] = 0;
- return glob5[1] + func_static15[2];
-}
diff --git a/contrib/compiler-rt/lib/asan/tests/asan_interface_test.cc b/contrib/compiler-rt/lib/asan/tests/asan_interface_test.cc
deleted file mode 100644
index a34c8528eae0..000000000000
--- a/contrib/compiler-rt/lib/asan/tests/asan_interface_test.cc
+++ /dev/null
@@ -1,433 +0,0 @@
-//===-- asan_interface_test.cc --------------------------------------------===//
-//
-// 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 AddressSanitizer, an address sanity checker.
-//
-//===----------------------------------------------------------------------===//
-#include "asan_test_utils.h"
-#include <sanitizer/allocator_interface.h>
-#include <sanitizer/asan_interface.h>
-
-TEST(AddressSanitizerInterface, GetEstimatedAllocatedSize) {
- EXPECT_EQ(0U, __sanitizer_get_estimated_allocated_size(0));
- const size_t sizes[] = { 1, 30, 1<<30 };
- for (size_t i = 0; i < 3; i++) {
- EXPECT_EQ(sizes[i], __sanitizer_get_estimated_allocated_size(sizes[i]));
- }
-}
-
-static const char* kGetAllocatedSizeErrorMsg =
- "attempting to call __sanitizer_get_allocated_size";
-
-TEST(AddressSanitizerInterface, GetAllocatedSizeAndOwnershipTest) {
- const size_t kArraySize = 100;
- char *array = Ident((char*)malloc(kArraySize));
- int *int_ptr = Ident(new int);
-
- // Allocated memory is owned by allocator. Allocated size should be
- // equal to requested size.
- EXPECT_EQ(true, __sanitizer_get_ownership(array));
- EXPECT_EQ(kArraySize, __sanitizer_get_allocated_size(array));
- EXPECT_EQ(true, __sanitizer_get_ownership(int_ptr));
- EXPECT_EQ(sizeof(int), __sanitizer_get_allocated_size(int_ptr));
-
- // We cannot call GetAllocatedSize from the memory we didn't map,
- // and from the interior pointers (not returned by previous malloc).
- void *wild_addr = (void*)0x1;
- EXPECT_FALSE(__sanitizer_get_ownership(wild_addr));
- EXPECT_DEATH(__sanitizer_get_allocated_size(wild_addr),
- kGetAllocatedSizeErrorMsg);
- EXPECT_FALSE(__sanitizer_get_ownership(array + kArraySize / 2));
- EXPECT_DEATH(__sanitizer_get_allocated_size(array + kArraySize / 2),
- kGetAllocatedSizeErrorMsg);
-
- // NULL is not owned, but is a valid argument for
- // __sanitizer_get_allocated_size().
- EXPECT_FALSE(__sanitizer_get_ownership(NULL));
- EXPECT_EQ(0U, __sanitizer_get_allocated_size(NULL));
-
- // When memory is freed, it's not owned, and call to GetAllocatedSize
- // is forbidden.
- free(array);
- EXPECT_FALSE(__sanitizer_get_ownership(array));
- EXPECT_DEATH(__sanitizer_get_allocated_size(array),
- kGetAllocatedSizeErrorMsg);
- delete int_ptr;
-
- void *zero_alloc = Ident(malloc(0));
- if (zero_alloc != 0) {
- // If malloc(0) is not null, this pointer is owned and should have valid
- // allocated size.
- EXPECT_TRUE(__sanitizer_get_ownership(zero_alloc));
- // Allocated size is 0 or 1 depending on the allocator used.
- EXPECT_LT(__sanitizer_get_allocated_size(zero_alloc), 2U);
- }
- free(zero_alloc);
-}
-
-TEST(AddressSanitizerInterface, GetCurrentAllocatedBytesTest) {
- size_t before_malloc, after_malloc, after_free;
- char *array;
- const size_t kMallocSize = 100;
- before_malloc = __sanitizer_get_current_allocated_bytes();
-
- array = Ident((char*)malloc(kMallocSize));
- after_malloc = __sanitizer_get_current_allocated_bytes();
- EXPECT_EQ(before_malloc + kMallocSize, after_malloc);
-
- free(array);
- after_free = __sanitizer_get_current_allocated_bytes();
- EXPECT_EQ(before_malloc, after_free);
-}
-
-TEST(AddressSanitizerInterface, GetHeapSizeTest) {
- // ASan allocator does not keep huge chunks in free list, but unmaps them.
- // The chunk should be greater than the quarantine size,
- // otherwise it will be stuck in quarantine instead of being unmaped.
- static const size_t kLargeMallocSize = (1 << 28) + 1; // 256M
- free(Ident(malloc(kLargeMallocSize))); // Drain quarantine.
- size_t old_heap_size = __sanitizer_get_heap_size();
- for (int i = 0; i < 3; i++) {
- // fprintf(stderr, "allocating %zu bytes:\n", kLargeMallocSize);
- free(Ident(malloc(kLargeMallocSize)));
- EXPECT_EQ(old_heap_size, __sanitizer_get_heap_size());
- }
-}
-
-static const size_t kManyThreadsMallocSizes[] = {5, 1UL<<10, 1UL<<14, 357};
-static const size_t kManyThreadsIterations = 250;
-static const size_t kManyThreadsNumThreads =
- (SANITIZER_WORDSIZE == 32) ? 40 : 200;
-
-static void *ManyThreadsWithStatsWorker(void *arg) {
- (void)arg;
- for (size_t iter = 0; iter < kManyThreadsIterations; iter++) {
- for (size_t size_index = 0; size_index < 4; size_index++) {
- free(Ident(malloc(kManyThreadsMallocSizes[size_index])));
- }
- }
- // Just one large allocation.
- free(Ident(malloc(1 << 20)));
- return 0;
-}
-
-TEST(AddressSanitizerInterface, ManyThreadsWithStatsStressTest) {
- size_t before_test, after_test, i;
- pthread_t threads[kManyThreadsNumThreads];
- before_test = __sanitizer_get_current_allocated_bytes();
- for (i = 0; i < kManyThreadsNumThreads; i++) {
- PTHREAD_CREATE(&threads[i], 0,
- (void* (*)(void *x))ManyThreadsWithStatsWorker, (void*)i);
- }
- for (i = 0; i < kManyThreadsNumThreads; i++) {
- PTHREAD_JOIN(threads[i], 0);
- }
- after_test = __sanitizer_get_current_allocated_bytes();
- // ASan stats also reflect memory usage of internal ASan RTL structs,
- // so we can't check for equality here.
- EXPECT_LT(after_test, before_test + (1UL<<20));
-}
-
-static void DoDoubleFree() {
- int *x = Ident(new int);
- delete Ident(x);
- delete Ident(x);
-}
-
-TEST(AddressSanitizerInterface, ExitCode) {
- int original_exit_code = __asan_set_error_exit_code(7);
- EXPECT_EXIT(DoDoubleFree(), ::testing::ExitedWithCode(7), "");
- EXPECT_EQ(7, __asan_set_error_exit_code(8));
- EXPECT_EXIT(DoDoubleFree(), ::testing::ExitedWithCode(8), "");
- EXPECT_EQ(8, __asan_set_error_exit_code(original_exit_code));
- EXPECT_EXIT(DoDoubleFree(),
- ::testing::ExitedWithCode(original_exit_code), "");
-}
-
-static void MyDeathCallback() {
- fprintf(stderr, "MyDeathCallback\n");
- fflush(0); // On Windows, stderr doesn't flush on crash.
-}
-
-TEST(AddressSanitizerInterface, DeathCallbackTest) {
- __asan_set_death_callback(MyDeathCallback);
- EXPECT_DEATH(DoDoubleFree(), "MyDeathCallback");
- __asan_set_death_callback(NULL);
-}
-
-static const char* kUseAfterPoisonErrorMessage = "use-after-poison";
-
-#define GOOD_ACCESS(ptr, offset) \
- EXPECT_FALSE(__asan_address_is_poisoned(ptr + offset))
-
-#define BAD_ACCESS(ptr, offset) \
- EXPECT_TRUE(__asan_address_is_poisoned(ptr + offset))
-
-TEST(AddressSanitizerInterface, SimplePoisonMemoryRegionTest) {
- char *array = Ident((char*)malloc(120));
- // poison array[40..80)
- __asan_poison_memory_region(array + 40, 40);
- GOOD_ACCESS(array, 39);
- GOOD_ACCESS(array, 80);
- BAD_ACCESS(array, 40);
- BAD_ACCESS(array, 60);
- BAD_ACCESS(array, 79);
- char value;
- EXPECT_DEATH(value = Ident(array[40]), kUseAfterPoisonErrorMessage);
- __asan_unpoison_memory_region(array + 40, 40);
- // access previously poisoned memory.
- GOOD_ACCESS(array, 40);
- GOOD_ACCESS(array, 79);
- free(array);
-}
-
-TEST(AddressSanitizerInterface, OverlappingPoisonMemoryRegionTest) {
- char *array = Ident((char*)malloc(120));
- // Poison [0..40) and [80..120)
- __asan_poison_memory_region(array, 40);
- __asan_poison_memory_region(array + 80, 40);
- BAD_ACCESS(array, 20);
- GOOD_ACCESS(array, 60);
- BAD_ACCESS(array, 100);
- // Poison whole array - [0..120)
- __asan_poison_memory_region(array, 120);
- BAD_ACCESS(array, 60);
- // Unpoison [24..96)
- __asan_unpoison_memory_region(array + 24, 72);
- BAD_ACCESS(array, 23);
- GOOD_ACCESS(array, 24);
- GOOD_ACCESS(array, 60);
- GOOD_ACCESS(array, 95);
- BAD_ACCESS(array, 96);
- free(array);
-}
-
-TEST(AddressSanitizerInterface, PushAndPopWithPoisoningTest) {
- // Vector of capacity 20
- char *vec = Ident((char*)malloc(20));
- __asan_poison_memory_region(vec, 20);
- for (size_t i = 0; i < 7; i++) {
- // Simulate push_back.
- __asan_unpoison_memory_region(vec + i, 1);
- GOOD_ACCESS(vec, i);
- BAD_ACCESS(vec, i + 1);
- }
- for (size_t i = 7; i > 0; i--) {
- // Simulate pop_back.
- __asan_poison_memory_region(vec + i - 1, 1);
- BAD_ACCESS(vec, i - 1);
- if (i > 1) GOOD_ACCESS(vec, i - 2);
- }
- free(vec);
-}
-
-// Make sure that each aligned block of size "2^granularity" doesn't have
-// "true" value before "false" value.
-static void MakeShadowValid(bool *shadow, int length, int granularity) {
- bool can_be_poisoned = true;
- for (int i = length - 1; i >= 0; i--) {
- if (!shadow[i])
- can_be_poisoned = false;
- if (!can_be_poisoned)
- shadow[i] = false;
- if (i % (1 << granularity) == 0) {
- can_be_poisoned = true;
- }
- }
-}
-
-TEST(AddressSanitizerInterface, PoisoningStressTest) {
- const size_t kSize = 24;
- bool expected[kSize];
- char *arr = Ident((char*)malloc(kSize));
- for (size_t l1 = 0; l1 < kSize; l1++) {
- for (size_t s1 = 1; l1 + s1 <= kSize; s1++) {
- for (size_t l2 = 0; l2 < kSize; l2++) {
- for (size_t s2 = 1; l2 + s2 <= kSize; s2++) {
- // Poison [l1, l1+s1), [l2, l2+s2) and check result.
- __asan_unpoison_memory_region(arr, kSize);
- __asan_poison_memory_region(arr + l1, s1);
- __asan_poison_memory_region(arr + l2, s2);
- memset(expected, false, kSize);
- memset(expected + l1, true, s1);
- MakeShadowValid(expected, kSize, /*granularity*/ 3);
- memset(expected + l2, true, s2);
- MakeShadowValid(expected, kSize, /*granularity*/ 3);
- for (size_t i = 0; i < kSize; i++) {
- ASSERT_EQ(expected[i], __asan_address_is_poisoned(arr + i));
- }
- // Unpoison [l1, l1+s1) and [l2, l2+s2) and check result.
- __asan_poison_memory_region(arr, kSize);
- __asan_unpoison_memory_region(arr + l1, s1);
- __asan_unpoison_memory_region(arr + l2, s2);
- memset(expected, true, kSize);
- memset(expected + l1, false, s1);
- MakeShadowValid(expected, kSize, /*granularity*/ 3);
- memset(expected + l2, false, s2);
- MakeShadowValid(expected, kSize, /*granularity*/ 3);
- for (size_t i = 0; i < kSize; i++) {
- ASSERT_EQ(expected[i], __asan_address_is_poisoned(arr + i));
- }
- }
- }
- }
- }
- free(arr);
-}
-
-TEST(AddressSanitizerInterface, GlobalRedzones) {
- GOOD_ACCESS(glob1, 1 - 1);
- GOOD_ACCESS(glob2, 2 - 1);
- GOOD_ACCESS(glob3, 3 - 1);
- GOOD_ACCESS(glob4, 4 - 1);
- GOOD_ACCESS(glob5, 5 - 1);
- GOOD_ACCESS(glob6, 6 - 1);
- GOOD_ACCESS(glob7, 7 - 1);
- GOOD_ACCESS(glob8, 8 - 1);
- GOOD_ACCESS(glob9, 9 - 1);
- GOOD_ACCESS(glob10, 10 - 1);
- GOOD_ACCESS(glob11, 11 - 1);
- GOOD_ACCESS(glob12, 12 - 1);
- GOOD_ACCESS(glob13, 13 - 1);
- GOOD_ACCESS(glob14, 14 - 1);
- GOOD_ACCESS(glob15, 15 - 1);
- GOOD_ACCESS(glob16, 16 - 1);
- GOOD_ACCESS(glob17, 17 - 1);
- GOOD_ACCESS(glob1000, 1000 - 1);
- GOOD_ACCESS(glob10000, 10000 - 1);
- GOOD_ACCESS(glob100000, 100000 - 1);
-
- BAD_ACCESS(glob1, 1);
- BAD_ACCESS(glob2, 2);
- BAD_ACCESS(glob3, 3);
- BAD_ACCESS(glob4, 4);
- BAD_ACCESS(glob5, 5);
- BAD_ACCESS(glob6, 6);
- BAD_ACCESS(glob7, 7);
- BAD_ACCESS(glob8, 8);
- BAD_ACCESS(glob9, 9);
- BAD_ACCESS(glob10, 10);
- BAD_ACCESS(glob11, 11);
- BAD_ACCESS(glob12, 12);
- BAD_ACCESS(glob13, 13);
- BAD_ACCESS(glob14, 14);
- BAD_ACCESS(glob15, 15);
- BAD_ACCESS(glob16, 16);
- BAD_ACCESS(glob17, 17);
- BAD_ACCESS(glob1000, 1000);
- BAD_ACCESS(glob1000, 1100); // Redzone is at least 101 bytes.
- BAD_ACCESS(glob10000, 10000);
- BAD_ACCESS(glob10000, 11000); // Redzone is at least 1001 bytes.
- BAD_ACCESS(glob100000, 100000);
- BAD_ACCESS(glob100000, 110000); // Redzone is at least 10001 bytes.
-}
-
-TEST(AddressSanitizerInterface, PoisonedRegion) {
- size_t rz = 16;
- for (size_t size = 1; size <= 64; size++) {
- char *p = new char[size];
- for (size_t beg = 0; beg < size + rz; beg++) {
- for (size_t end = beg; end < size + rz; end++) {
- void *first_poisoned = __asan_region_is_poisoned(p + beg, end - beg);
- if (beg == end) {
- EXPECT_FALSE(first_poisoned);
- } else if (beg < size && end <= size) {
- EXPECT_FALSE(first_poisoned);
- } else if (beg >= size) {
- EXPECT_EQ(p + beg, first_poisoned);
- } else {
- EXPECT_GT(end, size);
- EXPECT_EQ(p + size, first_poisoned);
- }
- }
- }
- delete [] p;
- }
-}
-
-// This is a performance benchmark for manual runs.
-// asan's memset interceptor calls mem_is_zero for the entire shadow region.
-// the profile should look like this:
-// 89.10% [.] __memset_sse2
-// 10.50% [.] __sanitizer::mem_is_zero
-// I.e. mem_is_zero should consume ~ SHADOW_GRANULARITY less CPU cycles
-// than memset itself.
-TEST(AddressSanitizerInterface, DISABLED_StressLargeMemset) {
- size_t size = 1 << 20;
- char *x = new char[size];
- for (int i = 0; i < 100000; i++)
- Ident(memset)(x, 0, size);
- delete [] x;
-}
-
-// Same here, but we run memset with small sizes.
-TEST(AddressSanitizerInterface, DISABLED_StressSmallMemset) {
- size_t size = 32;
- char *x = new char[size];
- for (int i = 0; i < 100000000; i++)
- Ident(memset)(x, 0, size);
- delete [] x;
-}
-static const char *kInvalidPoisonMessage = "invalid-poison-memory-range";
-static const char *kInvalidUnpoisonMessage = "invalid-unpoison-memory-range";
-
-TEST(AddressSanitizerInterface, DISABLED_InvalidPoisonAndUnpoisonCallsTest) {
- char *array = Ident((char*)malloc(120));
- __asan_unpoison_memory_region(array, 120);
- // Try to unpoison not owned memory
- EXPECT_DEATH(__asan_unpoison_memory_region(array, 121),
- kInvalidUnpoisonMessage);
- EXPECT_DEATH(__asan_unpoison_memory_region(array - 1, 120),
- kInvalidUnpoisonMessage);
-
- __asan_poison_memory_region(array, 120);
- // Try to poison not owned memory.
- EXPECT_DEATH(__asan_poison_memory_region(array, 121), kInvalidPoisonMessage);
- EXPECT_DEATH(__asan_poison_memory_region(array - 1, 120),
- kInvalidPoisonMessage);
- free(array);
-}
-
-#if !defined(_WIN32) // FIXME: This should really be a lit test.
-static void ErrorReportCallbackOneToZ(const char *report) {
- int report_len = strlen(report);
- ASSERT_EQ(6, write(2, "ABCDEF", 6));
- ASSERT_EQ(report_len, write(2, report, report_len));
- ASSERT_EQ(6, write(2, "ABCDEF", 6));
- _exit(1);
-}
-
-TEST(AddressSanitizerInterface, SetErrorReportCallbackTest) {
- __asan_set_error_report_callback(ErrorReportCallbackOneToZ);
- EXPECT_DEATH(__asan_report_error(0, 0, 0, 0, true, 1),
- ASAN_PCRE_DOTALL "ABCDEF.*AddressSanitizer.*WRITE.*ABCDEF");
- __asan_set_error_report_callback(NULL);
-}
-#endif
-
-TEST(AddressSanitizerInterface, GetOwnershipStressTest) {
- std::vector<char *> pointers;
- std::vector<size_t> sizes;
- const size_t kNumMallocs = 1 << 9;
- for (size_t i = 0; i < kNumMallocs; i++) {
- size_t size = i * 100 + 1;
- pointers.push_back((char*)malloc(size));
- sizes.push_back(size);
- }
- for (size_t i = 0; i < 4000000; i++) {
- EXPECT_FALSE(__sanitizer_get_ownership(&pointers));
- EXPECT_FALSE(__sanitizer_get_ownership((void*)0x1234));
- size_t idx = i % kNumMallocs;
- EXPECT_TRUE(__sanitizer_get_ownership(pointers[idx]));
- EXPECT_EQ(sizes[idx], __sanitizer_get_allocated_size(pointers[idx]));
- }
- for (size_t i = 0, n = pointers.size(); i < n; i++)
- free(pointers[i]);
-}
-
diff --git a/contrib/compiler-rt/lib/asan/tests/asan_mac_test.cc b/contrib/compiler-rt/lib/asan/tests/asan_mac_test.cc
deleted file mode 100644
index cabdfd711ea2..000000000000
--- a/contrib/compiler-rt/lib/asan/tests/asan_mac_test.cc
+++ /dev/null
@@ -1,236 +0,0 @@
-//===-- asan_test_mac.cc --------------------------------------------------===//
-//
-// 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 AddressSanitizer, an address sanity checker.
-//
-//===----------------------------------------------------------------------===//
-
-#include "asan_test_utils.h"
-
-#include "asan_mac_test.h"
-
-#include <malloc/malloc.h>
-#include <AvailabilityMacros.h> // For MAC_OS_X_VERSION_*
-#include <CoreFoundation/CFString.h>
-
-TEST(AddressSanitizerMac, CFAllocatorDefaultDoubleFree) {
- EXPECT_DEATH(
- CFAllocatorDefaultDoubleFree(NULL),
- "attempting double-free");
-}
-
-void CFAllocator_DoubleFreeOnPthread() {
- pthread_t child;
- PTHREAD_CREATE(&child, NULL, CFAllocatorDefaultDoubleFree, NULL);
- PTHREAD_JOIN(child, NULL); // Shouldn't be reached.
-}
-
-TEST(AddressSanitizerMac, CFAllocatorDefaultDoubleFree_ChildPhread) {
- EXPECT_DEATH(CFAllocator_DoubleFreeOnPthread(), "attempting double-free");
-}
-
-namespace {
-
-void *GLOB;
-
-void *CFAllocatorAllocateToGlob(void *unused) {
- GLOB = CFAllocatorAllocate(NULL, 100, /*hint*/0);
- return NULL;
-}
-
-void *CFAllocatorDeallocateFromGlob(void *unused) {
- char *p = (char*)GLOB;
- p[100] = 'A'; // ASan should report an error here.
- CFAllocatorDeallocate(NULL, GLOB);
- return NULL;
-}
-
-void CFAllocator_PassMemoryToAnotherThread() {
- pthread_t th1, th2;
- PTHREAD_CREATE(&th1, NULL, CFAllocatorAllocateToGlob, NULL);
- PTHREAD_JOIN(th1, NULL);
- PTHREAD_CREATE(&th2, NULL, CFAllocatorDeallocateFromGlob, NULL);
- PTHREAD_JOIN(th2, NULL);
-}
-
-TEST(AddressSanitizerMac, CFAllocator_PassMemoryToAnotherThread) {
- EXPECT_DEATH(CFAllocator_PassMemoryToAnotherThread(),
- "heap-buffer-overflow");
-}
-
-} // namespace
-
-// TODO(glider): figure out whether we still need these tests. Is it correct
-// to intercept the non-default CFAllocators?
-TEST(AddressSanitizerMac, DISABLED_CFAllocatorSystemDefaultDoubleFree) {
- EXPECT_DEATH(
- CFAllocatorSystemDefaultDoubleFree(),
- "attempting double-free");
-}
-
-// We're intercepting malloc, so kCFAllocatorMalloc is routed to ASan.
-TEST(AddressSanitizerMac, CFAllocatorMallocDoubleFree) {
- EXPECT_DEATH(CFAllocatorMallocDoubleFree(), "attempting double-free");
-}
-
-TEST(AddressSanitizerMac, DISABLED_CFAllocatorMallocZoneDoubleFree) {
- EXPECT_DEATH(CFAllocatorMallocZoneDoubleFree(), "attempting double-free");
-}
-
-// For libdispatch tests below we check that ASan got to the shadow byte
-// legend, i.e. managed to print the thread stacks (this almost certainly
-// means that the libdispatch task creation has been intercepted correctly).
-TEST(AddressSanitizerMac, GCDDispatchAsync) {
- // Make sure the whole ASan report is printed, i.e. that we don't die
- // on a CHECK.
- EXPECT_DEATH(TestGCDDispatchAsync(), "Shadow byte legend");
-}
-
-TEST(AddressSanitizerMac, GCDDispatchSync) {
- // Make sure the whole ASan report is printed, i.e. that we don't die
- // on a CHECK.
- EXPECT_DEATH(TestGCDDispatchSync(), "Shadow byte legend");
-}
-
-
-TEST(AddressSanitizerMac, GCDReuseWqthreadsAsync) {
- // Make sure the whole ASan report is printed, i.e. that we don't die
- // on a CHECK.
- EXPECT_DEATH(TestGCDReuseWqthreadsAsync(), "Shadow byte legend");
-}
-
-TEST(AddressSanitizerMac, GCDReuseWqthreadsSync) {
- // Make sure the whole ASan report is printed, i.e. that we don't die
- // on a CHECK.
- EXPECT_DEATH(TestGCDReuseWqthreadsSync(), "Shadow byte legend");
-}
-
-TEST(AddressSanitizerMac, GCDDispatchAfter) {
- // Make sure the whole ASan report is printed, i.e. that we don't die
- // on a CHECK.
- EXPECT_DEATH(TestGCDDispatchAfter(), "Shadow byte legend");
-}
-
-TEST(AddressSanitizerMac, GCDSourceEvent) {
- // Make sure the whole ASan report is printed, i.e. that we don't die
- // on a CHECK.
- EXPECT_DEATH(TestGCDSourceEvent(), "Shadow byte legend");
-}
-
-TEST(AddressSanitizerMac, GCDSourceCancel) {
- // Make sure the whole ASan report is printed, i.e. that we don't die
- // on a CHECK.
- EXPECT_DEATH(TestGCDSourceCancel(), "Shadow byte legend");
-}
-
-TEST(AddressSanitizerMac, GCDGroupAsync) {
- // Make sure the whole ASan report is printed, i.e. that we don't die
- // on a CHECK.
- EXPECT_DEATH(TestGCDGroupAsync(), "Shadow byte legend");
-}
-
-void *MallocIntrospectionLockWorker(void *_) {
- const int kNumPointers = 100;
- int i;
- void *pointers[kNumPointers];
- for (i = 0; i < kNumPointers; i++) {
- pointers[i] = malloc(i + 1);
- }
- for (i = 0; i < kNumPointers; i++) {
- free(pointers[i]);
- }
-
- return NULL;
-}
-
-void *MallocIntrospectionLockForker(void *_) {
- pid_t result = fork();
- if (result == -1) {
- perror("fork");
- }
- assert(result != -1);
- if (result == 0) {
- // Call malloc in the child process to make sure we won't deadlock.
- void *ptr = malloc(42);
- free(ptr);
- exit(0);
- } else {
- // Return in the parent process.
- return NULL;
- }
-}
-
-TEST(AddressSanitizerMac, MallocIntrospectionLock) {
- // Incorrect implementation of force_lock and force_unlock in our malloc zone
- // will cause forked processes to deadlock.
- // TODO(glider): need to detect that none of the child processes deadlocked.
- const int kNumWorkers = 5, kNumIterations = 100;
- int i, iter;
- for (iter = 0; iter < kNumIterations; iter++) {
- pthread_t workers[kNumWorkers], forker;
- for (i = 0; i < kNumWorkers; i++) {
- PTHREAD_CREATE(&workers[i], 0, MallocIntrospectionLockWorker, 0);
- }
- PTHREAD_CREATE(&forker, 0, MallocIntrospectionLockForker, 0);
- for (i = 0; i < kNumWorkers; i++) {
- PTHREAD_JOIN(workers[i], 0);
- }
- PTHREAD_JOIN(forker, 0);
- }
-}
-
-void *TSDAllocWorker(void *test_key) {
- if (test_key) {
- void *mem = malloc(10);
- pthread_setspecific(*(pthread_key_t*)test_key, mem);
- }
- return NULL;
-}
-
-TEST(AddressSanitizerMac, DISABLED_TSDWorkqueueTest) {
- pthread_t th;
- pthread_key_t test_key;
- pthread_key_create(&test_key, CallFreeOnWorkqueue);
- PTHREAD_CREATE(&th, NULL, TSDAllocWorker, &test_key);
- PTHREAD_JOIN(th, NULL);
- pthread_key_delete(test_key);
-}
-
-// Test that CFStringCreateCopy does not copy constant strings.
-TEST(AddressSanitizerMac, CFStringCreateCopy) {
- CFStringRef str = CFSTR("Hello world!\n");
- CFStringRef str2 = CFStringCreateCopy(0, str);
- EXPECT_EQ(str, str2);
-}
-
-TEST(AddressSanitizerMac, NSObjectOOB) {
- // Make sure that our allocators are used for NSObjects.
- EXPECT_DEATH(TestOOBNSObjects(), "heap-buffer-overflow");
-}
-
-// Make sure that correct pointer is passed to free() when deallocating a
-// NSURL object.
-// See http://code.google.com/p/address-sanitizer/issues/detail?id=70.
-TEST(AddressSanitizerMac, NSURLDeallocation) {
- TestNSURLDeallocation();
-}
-
-// See http://code.google.com/p/address-sanitizer/issues/detail?id=109.
-TEST(AddressSanitizerMac, Mstats) {
- malloc_statistics_t stats1, stats2;
- malloc_zone_statistics(/*all zones*/NULL, &stats1);
- const size_t kMallocSize = 100000;
- void *alloc = Ident(malloc(kMallocSize));
- malloc_zone_statistics(/*all zones*/NULL, &stats2);
- EXPECT_GT(stats2.blocks_in_use, stats1.blocks_in_use);
- EXPECT_GE(stats2.size_in_use - stats1.size_in_use, kMallocSize);
- free(alloc);
- // Even the default OSX allocator may not change the stats after free().
-}
-
diff --git a/contrib/compiler-rt/lib/asan/tests/asan_mac_test.h b/contrib/compiler-rt/lib/asan/tests/asan_mac_test.h
deleted file mode 100644
index 441547a5a3dc..000000000000
--- a/contrib/compiler-rt/lib/asan/tests/asan_mac_test.h
+++ /dev/null
@@ -1,19 +0,0 @@
-extern "C" {
- void *CFAllocatorDefaultDoubleFree(void *unused);
- void CFAllocatorSystemDefaultDoubleFree();
- void CFAllocatorMallocDoubleFree();
- void CFAllocatorMallocZoneDoubleFree();
- void CallFreeOnWorkqueue(void *mem);
- void TestGCDDispatchAsync();
- void TestGCDDispatchSync();
- void TestGCDReuseWqthreadsAsync();
- void TestGCDReuseWqthreadsSync();
- void TestGCDDispatchAfter();
- void TestGCDInTSDDestructor();
- void TestGCDSourceEvent();
- void TestGCDSourceCancel();
- void TestGCDGroupAsync();
- void TestOOBNSObjects();
- void TestNSURLDeallocation();
- void TestPassCFMemoryToAnotherThread();
-}
diff --git a/contrib/compiler-rt/lib/asan/tests/asan_mac_test_helpers.mm b/contrib/compiler-rt/lib/asan/tests/asan_mac_test_helpers.mm
deleted file mode 100644
index a7e4b9d1928b..000000000000
--- a/contrib/compiler-rt/lib/asan/tests/asan_mac_test_helpers.mm
+++ /dev/null
@@ -1,240 +0,0 @@
-// Mac OS X 10.6 or higher only.
-#include <dispatch/dispatch.h>
-#include <pthread.h> // for pthread_yield_np()
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#import <CoreFoundation/CFBase.h>
-#import <Foundation/NSObject.h>
-#import <Foundation/NSURL.h>
-
-// This is a (void*)(void*) function so it can be passed to pthread_create.
-void *CFAllocatorDefaultDoubleFree(void *unused) {
- void *mem = CFAllocatorAllocate(kCFAllocatorDefault, 5, 0);
- CFAllocatorDeallocate(kCFAllocatorDefault, mem);
- CFAllocatorDeallocate(kCFAllocatorDefault, mem);
- return 0;
-}
-
-void CFAllocatorSystemDefaultDoubleFree() {
- void *mem = CFAllocatorAllocate(kCFAllocatorSystemDefault, 5, 0);
- CFAllocatorDeallocate(kCFAllocatorSystemDefault, mem);
- CFAllocatorDeallocate(kCFAllocatorSystemDefault, mem);
-}
-
-void CFAllocatorMallocDoubleFree() {
- void *mem = CFAllocatorAllocate(kCFAllocatorMalloc, 5, 0);
- CFAllocatorDeallocate(kCFAllocatorMalloc, mem);
- CFAllocatorDeallocate(kCFAllocatorMalloc, mem);
-}
-
-void CFAllocatorMallocZoneDoubleFree() {
- void *mem = CFAllocatorAllocate(kCFAllocatorMallocZone, 5, 0);
- CFAllocatorDeallocate(kCFAllocatorMallocZone, mem);
- CFAllocatorDeallocate(kCFAllocatorMallocZone, mem);
-}
-
-__attribute__((noinline))
-void access_memory(char *a) {
- *a = 0;
-}
-
-// Test the +load instrumentation.
-// Because the +load methods are invoked before anything else is initialized,
-// it makes little sense to wrap the code below into a gTest test case.
-// If AddressSanitizer doesn't instrument the +load method below correctly,
-// everything will just crash.
-
-char kStartupStr[] =
- "If your test didn't crash, AddressSanitizer is instrumenting "
- "the +load methods correctly.";
-
-@interface LoadSomething : NSObject {
-}
-@end
-
-@implementation LoadSomething
-
-+(void) load {
- for (size_t i = 0; i < strlen(kStartupStr); i++) {
- access_memory(&kStartupStr[i]); // make sure no optimizations occur.
- }
- // Don't print anything here not to interfere with the death tests.
-}
-
-@end
-
-void worker_do_alloc(int size) {
- char * volatile mem = (char * volatile)malloc(size);
- mem[0] = 0; // Ok
- free(mem);
-}
-
-void worker_do_crash(int size) {
- char * volatile mem = (char * volatile)malloc(size);
- access_memory(&mem[size]); // BOOM
- free(mem);
-}
-
-// Used by the GCD tests to avoid a race between the worker thread reporting a
-// memory error and the main thread which may exit with exit code 0 before
-// that.
-void wait_forever() {
- volatile bool infinite = true;
- while (infinite) pthread_yield_np();
-}
-
-// Tests for the Grand Central Dispatch. See
-// http://developer.apple.com/library/mac/#documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html
-// for the reference.
-void TestGCDDispatchAsync() {
- dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
- dispatch_block_t block = ^{ worker_do_crash(1024); };
- // dispatch_async() runs the task on a worker thread that does not go through
- // pthread_create(). We need to verify that AddressSanitizer notices that the
- // thread has started.
- dispatch_async(queue, block);
- wait_forever();
-}
-
-void TestGCDDispatchSync() {
- dispatch_queue_t queue = dispatch_get_global_queue(2, 0);
- dispatch_block_t block = ^{ worker_do_crash(1024); };
- // dispatch_sync() runs the task on a worker thread that does not go through
- // pthread_create(). We need to verify that AddressSanitizer notices that the
- // thread has started.
- dispatch_sync(queue, block);
- wait_forever();
-}
-
-// libdispatch spawns a rather small number of threads and reuses them. We need
-// to make sure AddressSanitizer handles the reusing correctly.
-void TestGCDReuseWqthreadsAsync() {
- dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
- dispatch_block_t block_alloc = ^{ worker_do_alloc(1024); };
- dispatch_block_t block_crash = ^{ worker_do_crash(1024); };
- for (int i = 0; i < 100; i++) {
- dispatch_async(queue, block_alloc);
- }
- dispatch_async(queue, block_crash);
- wait_forever();
-}
-
-// Try to trigger abnormal behaviour of dispatch_sync() being unhandled by us.
-void TestGCDReuseWqthreadsSync() {
- dispatch_queue_t queue[4];
- queue[0] = dispatch_get_global_queue(2, 0);
- queue[1] = dispatch_get_global_queue(0, 0);
- queue[2] = dispatch_get_global_queue(-2, 0);
- queue[3] = dispatch_queue_create("my_queue", NULL);
- dispatch_block_t block_alloc = ^{ worker_do_alloc(1024); };
- dispatch_block_t block_crash = ^{ worker_do_crash(1024); };
- for (int i = 0; i < 1000; i++) {
- dispatch_sync(queue[i % 4], block_alloc);
- }
- dispatch_sync(queue[3], block_crash);
- wait_forever();
-}
-
-void TestGCDDispatchAfter() {
- dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
- dispatch_block_t block_crash = ^{ worker_do_crash(1024); };
- // Schedule the event one second from the current time.
- dispatch_time_t milestone =
- dispatch_time(DISPATCH_TIME_NOW, 1LL * NSEC_PER_SEC);
- dispatch_after(milestone, queue, block_crash);
- wait_forever();
-}
-
-void worker_do_deallocate(void *ptr) {
- free(ptr);
-}
-
-void CallFreeOnWorkqueue(void *tsd) {
- dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
- dispatch_block_t block_dealloc = ^{ worker_do_deallocate(tsd); };
- dispatch_async(queue, block_dealloc);
- // Do not wait for the worker to free the memory -- nobody is going to touch
- // it.
-}
-
-void TestGCDSourceEvent() {
- dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
- dispatch_source_t timer =
- dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
- // Schedule the timer one second from the current time.
- dispatch_time_t milestone =
- dispatch_time(DISPATCH_TIME_NOW, 1LL * NSEC_PER_SEC);
-
- dispatch_source_set_timer(timer, milestone, DISPATCH_TIME_FOREVER, 0);
- char * volatile mem = (char * volatile)malloc(10);
- dispatch_source_set_event_handler(timer, ^{
- access_memory(&mem[10]);
- });
- dispatch_resume(timer);
- wait_forever();
-}
-
-void TestGCDSourceCancel() {
- dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
- dispatch_source_t timer =
- dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
- // Schedule the timer one second from the current time.
- dispatch_time_t milestone =
- dispatch_time(DISPATCH_TIME_NOW, 1LL * NSEC_PER_SEC);
-
- dispatch_source_set_timer(timer, milestone, DISPATCH_TIME_FOREVER, 0);
- char * volatile mem = (char * volatile)malloc(10);
- // Both dispatch_source_set_cancel_handler() and
- // dispatch_source_set_event_handler() use dispatch_barrier_async_f().
- // It's tricky to test dispatch_source_set_cancel_handler() separately,
- // so we test both here.
- dispatch_source_set_event_handler(timer, ^{
- dispatch_source_cancel(timer);
- });
- dispatch_source_set_cancel_handler(timer, ^{
- access_memory(&mem[10]);
- });
- dispatch_resume(timer);
- wait_forever();
-}
-
-void TestGCDGroupAsync() {
- dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
- dispatch_group_t group = dispatch_group_create();
- char * volatile mem = (char * volatile)malloc(10);
- dispatch_group_async(group, queue, ^{
- access_memory(&mem[10]);
- });
- dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
- wait_forever();
-}
-
-@interface FixedArray : NSObject {
- int items[10];
-}
-@end
-
-@implementation FixedArray
--(int) access: (int)index {
- return items[index];
-}
-@end
-
-void TestOOBNSObjects() {
- id anObject = [FixedArray new];
- [anObject access:1];
- [anObject access:11];
- [anObject release];
-}
-
-void TestNSURLDeallocation() {
- NSURL *base =
- [[NSURL alloc] initWithString:@"file://localhost/Users/glider/Library/"];
- volatile NSURL *u =
- [[NSURL alloc] initWithString:@"Saved Application State"
- relativeToURL:base];
- [u release];
-}
diff --git a/contrib/compiler-rt/lib/asan/tests/asan_mem_test.cc b/contrib/compiler-rt/lib/asan/tests/asan_mem_test.cc
deleted file mode 100644
index 4a941faa0430..000000000000
--- a/contrib/compiler-rt/lib/asan/tests/asan_mem_test.cc
+++ /dev/null
@@ -1,241 +0,0 @@
-//===-- asan_mem_test.cc --------------------------------------------------===//
-//
-// 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 AddressSanitizer, an address sanity checker.
-//
-//===----------------------------------------------------------------------===//
-#include "asan_test_utils.h"
-
-template<typename T>
-void MemSetOOBTestTemplate(size_t length) {
- if (length == 0) return;
- size_t size = Ident(sizeof(T) * length);
- T *array = Ident((T*)malloc(size));
- int element = Ident(42);
- int zero = Ident(0);
- void *(*MEMSET)(void *s, int c, size_t n) = Ident(memset);
- // memset interval inside array
- MEMSET(array, element, size);
- MEMSET(array, element, size - 1);
- MEMSET(array + length - 1, element, sizeof(T));
- MEMSET(array, element, 1);
-
- // memset 0 bytes
- MEMSET(array - 10, element, zero);
- MEMSET(array - 1, element, zero);
- MEMSET(array, element, zero);
- MEMSET(array + length, 0, zero);
- MEMSET(array + length + 1, 0, zero);
-
- // try to memset bytes to the right of array
- EXPECT_DEATH(MEMSET(array, 0, size + 1),
- RightOOBWriteMessage(0));
- EXPECT_DEATH(MEMSET((char*)(array + length) - 1, element, 6),
- RightOOBWriteMessage(0));
- EXPECT_DEATH(MEMSET(array + 1, element, size + sizeof(T)),
- RightOOBWriteMessage(0));
- // whole interval is to the right
- EXPECT_DEATH(MEMSET(array + length + 1, 0, 10),
- RightOOBWriteMessage(sizeof(T)));
-
- // try to memset bytes to the left of array
- EXPECT_DEATH(MEMSET((char*)array - 1, element, size),
- LeftOOBWriteMessage(1));
- EXPECT_DEATH(MEMSET((char*)array - 5, 0, 6),
- LeftOOBWriteMessage(5));
- if (length >= 100) {
- // Large OOB, we find it only if the redzone is large enough.
- EXPECT_DEATH(memset(array - 5, element, size + 5 * sizeof(T)),
- LeftOOBWriteMessage(5 * sizeof(T)));
- }
- // whole interval is to the left
- EXPECT_DEATH(MEMSET(array - 2, 0, sizeof(T)),
- LeftOOBWriteMessage(2 * sizeof(T)));
-
- // try to memset bytes both to the left & to the right
- EXPECT_DEATH(MEMSET((char*)array - 2, element, size + 4),
- LeftOOBWriteMessage(2));
-
- free(array);
-}
-
-TEST(AddressSanitizer, MemSetOOBTest) {
- MemSetOOBTestTemplate<char>(100);
- MemSetOOBTestTemplate<int>(5);
- MemSetOOBTestTemplate<double>(256);
- // We can test arrays of structres/classes here, but what for?
-}
-
-// Try to allocate two arrays of 'size' bytes that are near each other.
-// Strictly speaking we are not guaranteed to find such two pointers,
-// but given the structure of asan's allocator we will.
-static bool AllocateTwoAdjacentArrays(char **x1, char **x2, size_t size) {
- vector<uintptr_t> v;
- bool res = false;
- for (size_t i = 0; i < 1000U && !res; i++) {
- v.push_back(reinterpret_cast<uintptr_t>(new char[size]));
- if (i == 0) continue;
- sort(v.begin(), v.end());
- for (size_t j = 1; j < v.size(); j++) {
- assert(v[j] > v[j-1]);
- if ((size_t)(v[j] - v[j-1]) < size * 2) {
- *x2 = reinterpret_cast<char*>(v[j]);
- *x1 = reinterpret_cast<char*>(v[j-1]);
- res = true;
- break;
- }
- }
- }
-
- for (size_t i = 0; i < v.size(); i++) {
- char *p = reinterpret_cast<char *>(v[i]);
- if (res && p == *x1) continue;
- if (res && p == *x2) continue;
- delete [] p;
- }
- return res;
-}
-
-TEST(AddressSanitizer, LargeOOBInMemset) {
- for (size_t size = 200; size < 100000; size += size / 2) {
- char *x1, *x2;
- if (!Ident(AllocateTwoAdjacentArrays)(&x1, &x2, size))
- continue;
- // fprintf(stderr, " large oob memset: %p %p %zd\n", x1, x2, size);
- // Do a memset on x1 with huge out-of-bound access that will end up in x2.
- EXPECT_DEATH(Ident(memset)(x1, 0, size * 2),
- "is located 0 bytes to the right");
- delete [] x1;
- delete [] x2;
- return;
- }
- assert(0 && "Did not find two adjacent malloc-ed pointers");
-}
-
-// Same test for memcpy and memmove functions
-template <typename T, class M>
-void MemTransferOOBTestTemplate(size_t length) {
- if (length == 0) return;
- size_t size = Ident(sizeof(T) * length);
- T *src = Ident((T*)malloc(size));
- T *dest = Ident((T*)malloc(size));
- int zero = Ident(0);
-
- // valid transfer of bytes between arrays
- M::transfer(dest, src, size);
- M::transfer(dest + 1, src, size - sizeof(T));
- M::transfer(dest, src + length - 1, sizeof(T));
- M::transfer(dest, src, 1);
-
- // transfer zero bytes
- M::transfer(dest - 1, src, 0);
- M::transfer(dest + length, src, zero);
- M::transfer(dest, src - 1, zero);
- M::transfer(dest, src, zero);
-
- // try to change mem to the right of dest
- EXPECT_DEATH(M::transfer(dest + 1, src, size),
- RightOOBWriteMessage(0));
- EXPECT_DEATH(M::transfer((char*)(dest + length) - 1, src, 5),
- RightOOBWriteMessage(0));
-
- // try to change mem to the left of dest
- EXPECT_DEATH(M::transfer(dest - 2, src, size),
- LeftOOBWriteMessage(2 * sizeof(T)));
- EXPECT_DEATH(M::transfer((char*)dest - 3, src, 4),
- LeftOOBWriteMessage(3));
-
- // try to access mem to the right of src
- EXPECT_DEATH(M::transfer(dest, src + 2, size),
- RightOOBReadMessage(0));
- EXPECT_DEATH(M::transfer(dest, (char*)(src + length) - 3, 6),
- RightOOBReadMessage(0));
-
- // try to access mem to the left of src
- EXPECT_DEATH(M::transfer(dest, src - 1, size),
- LeftOOBReadMessage(sizeof(T)));
- EXPECT_DEATH(M::transfer(dest, (char*)src - 6, 7),
- LeftOOBReadMessage(6));
-
- // Generally we don't need to test cases where both accessing src and writing
- // to dest address to poisoned memory.
-
- T *big_src = Ident((T*)malloc(size * 2));
- T *big_dest = Ident((T*)malloc(size * 2));
- // try to change mem to both sides of dest
- EXPECT_DEATH(M::transfer(dest - 1, big_src, size * 2),
- LeftOOBWriteMessage(sizeof(T)));
- // try to access mem to both sides of src
- EXPECT_DEATH(M::transfer(big_dest, src - 2, size * 2),
- LeftOOBReadMessage(2 * sizeof(T)));
-
- free(src);
- free(dest);
- free(big_src);
- free(big_dest);
-}
-
-class MemCpyWrapper {
- public:
- static void* transfer(void *to, const void *from, size_t size) {
- return Ident(memcpy)(to, from, size);
- }
-};
-
-TEST(AddressSanitizer, MemCpyOOBTest) {
- MemTransferOOBTestTemplate<char, MemCpyWrapper>(100);
- MemTransferOOBTestTemplate<int, MemCpyWrapper>(1024);
-}
-
-class MemMoveWrapper {
- public:
- static void* transfer(void *to, const void *from, size_t size) {
- return Ident(memmove)(to, from, size);
- }
-};
-
-TEST(AddressSanitizer, MemMoveOOBTest) {
- MemTransferOOBTestTemplate<char, MemMoveWrapper>(100);
- MemTransferOOBTestTemplate<int, MemMoveWrapper>(1024);
-}
-
-
-TEST(AddressSanitizer, MemCmpOOBTest) {
- size_t size = Ident(100);
- char *s1 = MallocAndMemsetString(size);
- char *s2 = MallocAndMemsetString(size);
- // Normal memcmp calls.
- Ident(memcmp(s1, s2, size));
- Ident(memcmp(s1 + size - 1, s2 + size - 1, 1));
- Ident(memcmp(s1 - 1, s2 - 1, 0));
- // One of arguments points to not allocated memory.
- EXPECT_DEATH(Ident(memcmp)(s1 - 1, s2, 1), LeftOOBReadMessage(1));
- EXPECT_DEATH(Ident(memcmp)(s1, s2 - 1, 1), LeftOOBReadMessage(1));
- EXPECT_DEATH(Ident(memcmp)(s1 + size, s2, 1), RightOOBReadMessage(0));
- EXPECT_DEATH(Ident(memcmp)(s1, s2 + size, 1), RightOOBReadMessage(0));
- // Hit unallocated memory and die.
- EXPECT_DEATH(Ident(memcmp)(s1 + 1, s2 + 1, size), RightOOBReadMessage(0));
- EXPECT_DEATH(Ident(memcmp)(s1 + size - 1, s2, 2), RightOOBReadMessage(0));
- // Zero bytes are not terminators and don't prevent from OOB.
- s1[size - 1] = '\0';
- s2[size - 1] = '\0';
- EXPECT_DEATH(Ident(memcmp)(s1, s2, size + 1), RightOOBReadMessage(0));
-
- // Even if the buffers differ in the first byte, we still assume that
- // memcmp may access the whole buffer and thus reporting the overflow here:
- s1[0] = 1;
- s2[0] = 123;
- EXPECT_DEATH(Ident(memcmp)(s1, s2, size + 1), RightOOBReadMessage(0));
-
- free(s1);
- free(s2);
-}
-
-
-
diff --git a/contrib/compiler-rt/lib/asan/tests/asan_noinst_test.cc b/contrib/compiler-rt/lib/asan/tests/asan_noinst_test.cc
deleted file mode 100644
index 6a428fbbc2b9..000000000000
--- a/contrib/compiler-rt/lib/asan/tests/asan_noinst_test.cc
+++ /dev/null
@@ -1,263 +0,0 @@
-//===-- asan_noinst_test.cc -----------------------------------------------===//
-//
-// 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 AddressSanitizer, an address sanity checker.
-//
-// This test file should be compiled w/o asan instrumentation.
-//===----------------------------------------------------------------------===//
-
-#include "asan_allocator.h"
-#include "asan_internal.h"
-#include "asan_mapping.h"
-#include "asan_test_utils.h"
-#include <sanitizer/allocator_interface.h>
-
-#include <assert.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h> // for memset()
-#include <algorithm>
-#include <vector>
-#include <limits>
-
-// ATTENTION!
-// Please don't call intercepted functions (including malloc() and friends)
-// in this test. The static runtime library is linked explicitly (without
-// -fsanitize=address), thus the interceptors do not work correctly on OS X.
-
-// Make sure __asan_init is called before any test case is run.
-struct AsanInitCaller {
- AsanInitCaller() {
- __asan::DisableReexec();
- __asan_init();
- }
-};
-static AsanInitCaller asan_init_caller;
-
-TEST(AddressSanitizer, InternalSimpleDeathTest) {
- EXPECT_DEATH(exit(1), "");
-}
-
-static void MallocStress(size_t n) {
- u32 seed = my_rand();
- BufferedStackTrace stack1;
- stack1.trace_buffer[0] = 0xa123;
- stack1.trace_buffer[1] = 0xa456;
- stack1.size = 2;
-
- BufferedStackTrace stack2;
- stack2.trace_buffer[0] = 0xb123;
- stack2.trace_buffer[1] = 0xb456;
- stack2.size = 2;
-
- BufferedStackTrace stack3;
- stack3.trace_buffer[0] = 0xc123;
- stack3.trace_buffer[1] = 0xc456;
- stack3.size = 2;
-
- std::vector<void *> vec;
- for (size_t i = 0; i < n; i++) {
- if ((i % 3) == 0) {
- if (vec.empty()) continue;
- size_t idx = my_rand_r(&seed) % vec.size();
- void *ptr = vec[idx];
- vec[idx] = vec.back();
- vec.pop_back();
- __asan::asan_free(ptr, &stack1, __asan::FROM_MALLOC);
- } else {
- size_t size = my_rand_r(&seed) % 1000 + 1;
- switch ((my_rand_r(&seed) % 128)) {
- case 0: size += 1024; break;
- case 1: size += 2048; break;
- case 2: size += 4096; break;
- }
- size_t alignment = 1 << (my_rand_r(&seed) % 10 + 1);
- char *ptr = (char*)__asan::asan_memalign(alignment, size,
- &stack2, __asan::FROM_MALLOC);
- EXPECT_EQ(size, __asan::asan_malloc_usable_size(ptr, 0, 0));
- vec.push_back(ptr);
- ptr[0] = 0;
- ptr[size-1] = 0;
- ptr[size/2] = 0;
- }
- }
- for (size_t i = 0; i < vec.size(); i++)
- __asan::asan_free(vec[i], &stack3, __asan::FROM_MALLOC);
-}
-
-
-TEST(AddressSanitizer, NoInstMallocTest) {
- MallocStress(ASAN_LOW_MEMORY ? 300000 : 1000000);
-}
-
-TEST(AddressSanitizer, ThreadedMallocStressTest) {
- const int kNumThreads = 4;
- const int kNumIterations = (ASAN_LOW_MEMORY) ? 10000 : 100000;
- pthread_t t[kNumThreads];
- for (int i = 0; i < kNumThreads; i++) {
- PTHREAD_CREATE(&t[i], 0, (void* (*)(void *x))MallocStress,
- (void*)kNumIterations);
- }
- for (int i = 0; i < kNumThreads; i++) {
- PTHREAD_JOIN(t[i], 0);
- }
-}
-
-static void PrintShadow(const char *tag, uptr ptr, size_t size) {
- fprintf(stderr, "%s shadow: %lx size % 3ld: ", tag, (long)ptr, (long)size);
- uptr prev_shadow = 0;
- for (sptr i = -32; i < (sptr)size + 32; i++) {
- uptr shadow = __asan::MemToShadow(ptr + i);
- if (i == 0 || i == (sptr)size)
- fprintf(stderr, ".");
- if (shadow != prev_shadow) {
- prev_shadow = shadow;
- fprintf(stderr, "%02x", (int)*(u8*)shadow);
- }
- }
- fprintf(stderr, "\n");
-}
-
-TEST(AddressSanitizer, DISABLED_InternalPrintShadow) {
- for (size_t size = 1; size <= 513; size++) {
- char *ptr = new char[size];
- PrintShadow("m", (uptr)ptr, size);
- delete [] ptr;
- PrintShadow("f", (uptr)ptr, size);
- }
-}
-
-TEST(AddressSanitizer, QuarantineTest) {
- BufferedStackTrace stack;
- stack.trace_buffer[0] = 0x890;
- stack.size = 1;
-
- const int size = 1024;
- void *p = __asan::asan_malloc(size, &stack);
- __asan::asan_free(p, &stack, __asan::FROM_MALLOC);
- size_t i;
- size_t max_i = 1 << 30;
- for (i = 0; i < max_i; i++) {
- void *p1 = __asan::asan_malloc(size, &stack);
- __asan::asan_free(p1, &stack, __asan::FROM_MALLOC);
- if (p1 == p) break;
- }
- EXPECT_GE(i, 10000U);
- EXPECT_LT(i, max_i);
-}
-
-void *ThreadedQuarantineTestWorker(void *unused) {
- (void)unused;
- u32 seed = my_rand();
- BufferedStackTrace stack;
- stack.trace_buffer[0] = 0x890;
- stack.size = 1;
-
- for (size_t i = 0; i < 1000; i++) {
- void *p = __asan::asan_malloc(1 + (my_rand_r(&seed) % 4000), &stack);
- __asan::asan_free(p, &stack, __asan::FROM_MALLOC);
- }
- return NULL;
-}
-
-// Check that the thread local allocators are flushed when threads are
-// destroyed.
-TEST(AddressSanitizer, ThreadedQuarantineTest) {
- const int n_threads = 3000;
- size_t mmaped1 = __sanitizer_get_heap_size();
- for (int i = 0; i < n_threads; i++) {
- pthread_t t;
- PTHREAD_CREATE(&t, NULL, ThreadedQuarantineTestWorker, 0);
- PTHREAD_JOIN(t, 0);
- size_t mmaped2 = __sanitizer_get_heap_size();
- EXPECT_LT(mmaped2 - mmaped1, 320U * (1 << 20));
- }
-}
-
-void *ThreadedOneSizeMallocStress(void *unused) {
- (void)unused;
- BufferedStackTrace stack;
- stack.trace_buffer[0] = 0x890;
- stack.size = 1;
- const size_t kNumMallocs = 1000;
- for (int iter = 0; iter < 1000; iter++) {
- void *p[kNumMallocs];
- for (size_t i = 0; i < kNumMallocs; i++) {
- p[i] = __asan::asan_malloc(32, &stack);
- }
- for (size_t i = 0; i < kNumMallocs; i++) {
- __asan::asan_free(p[i], &stack, __asan::FROM_MALLOC);
- }
- }
- return NULL;
-}
-
-TEST(AddressSanitizer, ThreadedOneSizeMallocStressTest) {
- const int kNumThreads = 4;
- pthread_t t[kNumThreads];
- for (int i = 0; i < kNumThreads; i++) {
- PTHREAD_CREATE(&t[i], 0, ThreadedOneSizeMallocStress, 0);
- }
- for (int i = 0; i < kNumThreads; i++) {
- PTHREAD_JOIN(t[i], 0);
- }
-}
-
-TEST(AddressSanitizer, ShadowRegionIsPoisonedTest) {
- using __asan::kHighMemEnd;
- // Check that __asan_region_is_poisoned works for shadow regions.
- uptr ptr = kLowShadowBeg + 200;
- EXPECT_EQ(ptr, __asan_region_is_poisoned(ptr, 100));
- ptr = kShadowGapBeg + 200;
- EXPECT_EQ(ptr, __asan_region_is_poisoned(ptr, 100));
- ptr = kHighShadowBeg + 200;
- EXPECT_EQ(ptr, __asan_region_is_poisoned(ptr, 100));
-}
-
-// Test __asan_load1 & friends.
-TEST(AddressSanitizer, LoadStoreCallbacks) {
- typedef void (*CB)(uptr p);
- CB cb[2][5] = {
- {
- __asan_load1, __asan_load2, __asan_load4, __asan_load8, __asan_load16,
- }, {
- __asan_store1, __asan_store2, __asan_store4, __asan_store8,
- __asan_store16,
- }
- };
-
- uptr buggy_ptr;
-
- __asan_test_only_reported_buggy_pointer = &buggy_ptr;
- BufferedStackTrace stack;
- stack.trace_buffer[0] = 0x890;
- stack.size = 1;
-
- for (uptr len = 16; len <= 32; len++) {
- char *ptr = (char*) __asan::asan_malloc(len, &stack);
- uptr p = reinterpret_cast<uptr>(ptr);
- for (uptr is_write = 0; is_write <= 1; is_write++) {
- for (uptr size_log = 0; size_log <= 4; size_log++) {
- uptr size = 1 << size_log;
- CB call = cb[is_write][size_log];
- // Iterate only size-aligned offsets.
- for (uptr offset = 0; offset <= len; offset += size) {
- buggy_ptr = 0;
- call(p + offset);
- if (offset + size <= len)
- EXPECT_EQ(buggy_ptr, 0U);
- else
- EXPECT_EQ(buggy_ptr, p + offset);
- }
- }
- }
- __asan::asan_free(ptr, &stack, __asan::FROM_MALLOC);
- }
- __asan_test_only_reported_buggy_pointer = 0;
-}
diff --git a/contrib/compiler-rt/lib/asan/tests/asan_oob_test.cc b/contrib/compiler-rt/lib/asan/tests/asan_oob_test.cc
deleted file mode 100644
index 0c6bea285864..000000000000
--- a/contrib/compiler-rt/lib/asan/tests/asan_oob_test.cc
+++ /dev/null
@@ -1,128 +0,0 @@
-//===-- asan_oob_test.cc --------------------------------------------------===//
-//
-// 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 AddressSanitizer, an address sanity checker.
-//
-//===----------------------------------------------------------------------===//
-#include "asan_test_utils.h"
-
-NOINLINE void asan_write_sized_aligned(uint8_t *p, size_t size) {
- EXPECT_EQ(0U, ((uintptr_t)p % size));
- if (size == 1) asan_write((uint8_t*)p);
- else if (size == 2) asan_write((uint16_t*)p);
- else if (size == 4) asan_write((uint32_t*)p);
- else if (size == 8) asan_write((uint64_t*)p);
-}
-
-template<typename T>
-NOINLINE void oob_test(int size, int off) {
- char *p = (char*)malloc_aaa(size);
- // fprintf(stderr, "writing %d byte(s) into [%p,%p) with offset %d\n",
- // sizeof(T), p, p + size, off);
- asan_write((T*)(p + off));
- free_aaa(p);
-}
-
-template<typename T>
-void OOBTest() {
- char expected_str[100];
- for (int size = sizeof(T); size < 20; size += 5) {
- for (int i = -5; i < 0; i++) {
- const char *str =
- "is located.*%d byte.*to the left";
- sprintf(expected_str, str, abs(i));
- EXPECT_DEATH(oob_test<T>(size, i), expected_str);
- }
-
- for (int i = 0; i < (int)(size - sizeof(T) + 1); i++)
- oob_test<T>(size, i);
-
- for (int i = size - sizeof(T) + 1; i <= (int)(size + 2 * sizeof(T)); i++) {
- const char *str =
- "is located.*%d byte.*to the right";
- int off = i >= size ? (i - size) : 0;
- // we don't catch unaligned partially OOB accesses.
- if (i % sizeof(T)) continue;
- sprintf(expected_str, str, off);
- EXPECT_DEATH(oob_test<T>(size, i), expected_str);
- }
- }
-
- EXPECT_DEATH(oob_test<T>(kLargeMalloc, -1),
- "is located.*1 byte.*to the left");
- EXPECT_DEATH(oob_test<T>(kLargeMalloc, kLargeMalloc),
- "is located.*0 byte.*to the right");
-}
-
-// TODO(glider): the following tests are EXTREMELY slow on Darwin:
-// AddressSanitizer.OOB_char (125503 ms)
-// AddressSanitizer.OOB_int (126890 ms)
-// AddressSanitizer.OOBRightTest (315605 ms)
-// AddressSanitizer.SimpleStackTest (366559 ms)
-
-TEST(AddressSanitizer, OOB_char) {
- OOBTest<U1>();
-}
-
-TEST(AddressSanitizer, OOB_int) {
- OOBTest<U4>();
-}
-
-TEST(AddressSanitizer, OOBRightTest) {
- size_t max_access_size = SANITIZER_WORDSIZE == 64 ? 8 : 4;
- for (size_t access_size = 1; access_size <= max_access_size;
- access_size *= 2) {
- for (size_t alloc_size = 1; alloc_size <= 8; alloc_size++) {
- for (size_t offset = 0; offset <= 8; offset += access_size) {
- void *p = malloc(alloc_size);
- // allocated: [p, p + alloc_size)
- // accessed: [p + offset, p + offset + access_size)
- uint8_t *addr = (uint8_t*)p + offset;
- if (offset + access_size <= alloc_size) {
- asan_write_sized_aligned(addr, access_size);
- } else {
- int outside_bytes = offset > alloc_size ? (offset - alloc_size) : 0;
- const char *str =
- "is located.%d *byte.*to the right";
- char expected_str[100];
- sprintf(expected_str, str, outside_bytes);
- EXPECT_DEATH(asan_write_sized_aligned(addr, access_size),
- expected_str);
- }
- free(p);
- }
- }
- }
-}
-
-TEST(AddressSanitizer, LargeOOBRightTest) {
- size_t large_power_of_two = 1 << 19;
- for (size_t i = 16; i <= 256; i *= 2) {
- size_t size = large_power_of_two - i;
- char *p = Ident(new char[size]);
- EXPECT_DEATH(p[size] = 0, "is located 0 bytes to the right");
- delete [] p;
- }
-}
-
-TEST(AddressSanitizer, DISABLED_DemoOOBLeftLow) {
- oob_test<U1>(10, -1);
-}
-
-TEST(AddressSanitizer, DISABLED_DemoOOBLeftHigh) {
- oob_test<U1>(kLargeMalloc, -1);
-}
-
-TEST(AddressSanitizer, DISABLED_DemoOOBRightLow) {
- oob_test<U1>(10, 10);
-}
-
-TEST(AddressSanitizer, DISABLED_DemoOOBRightHigh) {
- oob_test<U1>(kLargeMalloc, kLargeMalloc);
-}
diff --git a/contrib/compiler-rt/lib/asan/tests/asan_racy_double_free_test.cc b/contrib/compiler-rt/lib/asan/tests/asan_racy_double_free_test.cc
deleted file mode 100644
index 23240e714d56..000000000000
--- a/contrib/compiler-rt/lib/asan/tests/asan_racy_double_free_test.cc
+++ /dev/null
@@ -1,32 +0,0 @@
-#include <pthread.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-const int N = 1000;
-void *x[N];
-
-void *Thread1(void *unused) {
- for (int i = 0; i < N; i++) {
- fprintf(stderr, "%s %d\n", __func__, i);
- free(x[i]);
- }
- return NULL;
-}
-
-void *Thread2(void *unused) {
- for (int i = 0; i < N; i++) {
- fprintf(stderr, "%s %d\n", __func__, i);
- free(x[i]);
- }
- return NULL;
-}
-
-int main() {
- for (int i = 0; i < N; i++)
- x[i] = malloc(128);
- pthread_t t[2];
- pthread_create(&t[0], 0, Thread1, 0);
- pthread_create(&t[1], 0, Thread2, 0);
- pthread_join(t[0], 0);
- pthread_join(t[1], 0);
-}
diff --git a/contrib/compiler-rt/lib/asan/tests/asan_str_test.cc b/contrib/compiler-rt/lib/asan/tests/asan_str_test.cc
deleted file mode 100644
index 89b0d3d2d0f9..000000000000
--- a/contrib/compiler-rt/lib/asan/tests/asan_str_test.cc
+++ /dev/null
@@ -1,573 +0,0 @@
-//=-- asan_str_test.cc ----------------------------------------------------===//
-//
-// 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 AddressSanitizer, an address sanity checker.
-//
-//===----------------------------------------------------------------------===//
-#include "asan_test_utils.h"
-
-#if defined(__APPLE__)
-#include <AvailabilityMacros.h> // For MAC_OS_X_VERSION_*
-#endif
-
-// Used for string functions tests
-static char global_string[] = "global";
-static size_t global_string_length = 6;
-
-// Input to a test is a zero-terminated string str with given length
-// Accesses to the bytes to the left and to the right of str
-// are presumed to produce OOB errors
-void StrLenOOBTestTemplate(char *str, size_t length, bool is_global) {
- // Normal strlen calls
- EXPECT_EQ(strlen(str), length);
- if (length > 0) {
- EXPECT_EQ(length - 1, strlen(str + 1));
- EXPECT_EQ(0U, strlen(str + length));
- }
- // Arg of strlen is not malloced, OOB access
- if (!is_global) {
- // We don't insert RedZones to the left of global variables
- EXPECT_DEATH(Ident(strlen(str - 1)), LeftOOBReadMessage(1));
- EXPECT_DEATH(Ident(strlen(str - 5)), LeftOOBReadMessage(5));
- }
- EXPECT_DEATH(Ident(strlen(str + length + 1)), RightOOBReadMessage(0));
- // Overwrite terminator
- str[length] = 'a';
- // String is not zero-terminated, strlen will lead to OOB access
- EXPECT_DEATH(Ident(strlen(str)), RightOOBReadMessage(0));
- EXPECT_DEATH(Ident(strlen(str + length)), RightOOBReadMessage(0));
- // Restore terminator
- str[length] = 0;
-}
-TEST(AddressSanitizer, StrLenOOBTest) {
- // Check heap-allocated string
- size_t length = Ident(10);
- char *heap_string = Ident((char*)malloc(length + 1));
- char stack_string[10 + 1];
- break_optimization(&stack_string);
- for (size_t i = 0; i < length; i++) {
- heap_string[i] = 'a';
- stack_string[i] = 'b';
- }
- heap_string[length] = 0;
- stack_string[length] = 0;
- StrLenOOBTestTemplate(heap_string, length, false);
- // TODO(samsonov): Fix expected messages in StrLenOOBTestTemplate to
- // make test for stack_string work. Or move it to output tests.
- // StrLenOOBTestTemplate(stack_string, length, false);
- StrLenOOBTestTemplate(global_string, global_string_length, true);
- free(heap_string);
-}
-
-TEST(AddressSanitizer, WcsLenTest) {
- EXPECT_EQ(0U, wcslen(Ident(L"")));
- size_t hello_len = 13;
- size_t hello_size = (hello_len + 1) * sizeof(wchar_t);
- EXPECT_EQ(hello_len, wcslen(Ident(L"Hello, World!")));
- wchar_t *heap_string = Ident((wchar_t*)malloc(hello_size));
- memcpy(heap_string, L"Hello, World!", hello_size);
- EXPECT_EQ(hello_len, Ident(wcslen(heap_string)));
- EXPECT_DEATH(Ident(wcslen(heap_string + 14)), RightOOBReadMessage(0));
- free(heap_string);
-}
-
-#if SANITIZER_TEST_HAS_STRNLEN
-TEST(AddressSanitizer, StrNLenOOBTest) {
- size_t size = Ident(123);
- char *str = MallocAndMemsetString(size);
- // Normal strnlen calls.
- Ident(strnlen(str - 1, 0));
- Ident(strnlen(str, size));
- Ident(strnlen(str + size - 1, 1));
- str[size - 1] = '\0';
- Ident(strnlen(str, 2 * size));
- // Argument points to not allocated memory.
- EXPECT_DEATH(Ident(strnlen(str - 1, 1)), LeftOOBReadMessage(1));
- EXPECT_DEATH(Ident(strnlen(str + size, 1)), RightOOBReadMessage(0));
- // Overwrite the terminating '\0' and hit unallocated memory.
- str[size - 1] = 'z';
- EXPECT_DEATH(Ident(strnlen(str, size + 1)), RightOOBReadMessage(0));
- free(str);
-}
-#endif // SANITIZER_TEST_HAS_STRNLEN
-
-TEST(AddressSanitizer, StrDupOOBTest) {
- size_t size = Ident(42);
- char *str = MallocAndMemsetString(size);
- char *new_str;
- // Normal strdup calls.
- str[size - 1] = '\0';
- new_str = strdup(str);
- free(new_str);
- new_str = strdup(str + size - 1);
- free(new_str);
- // Argument points to not allocated memory.
- EXPECT_DEATH(Ident(strdup(str - 1)), LeftOOBReadMessage(1));
- EXPECT_DEATH(Ident(strdup(str + size)), RightOOBReadMessage(0));
- // Overwrite the terminating '\0' and hit unallocated memory.
- str[size - 1] = 'z';
- EXPECT_DEATH(Ident(strdup(str)), RightOOBReadMessage(0));
- free(str);
-}
-
-TEST(AddressSanitizer, StrCpyOOBTest) {
- size_t to_size = Ident(30);
- size_t from_size = Ident(6); // less than to_size
- char *to = Ident((char*)malloc(to_size));
- char *from = Ident((char*)malloc(from_size));
- // Normal strcpy calls.
- strcpy(from, "hello");
- strcpy(to, from);
- strcpy(to + to_size - from_size, from);
- // Length of "from" is too small.
- EXPECT_DEATH(Ident(strcpy(from, "hello2")), RightOOBWriteMessage(0));
- // "to" or "from" points to not allocated memory.
- EXPECT_DEATH(Ident(strcpy(to - 1, from)), LeftOOBWriteMessage(1));
- EXPECT_DEATH(Ident(strcpy(to, from - 1)), LeftOOBReadMessage(1));
- EXPECT_DEATH(Ident(strcpy(to, from + from_size)), RightOOBReadMessage(0));
- EXPECT_DEATH(Ident(strcpy(to + to_size, from)), RightOOBWriteMessage(0));
- // Overwrite the terminating '\0' character and hit unallocated memory.
- from[from_size - 1] = '!';
- EXPECT_DEATH(Ident(strcpy(to, from)), RightOOBReadMessage(0));
- free(to);
- free(from);
-}
-
-TEST(AddressSanitizer, StrNCpyOOBTest) {
- size_t to_size = Ident(20);
- size_t from_size = Ident(6); // less than to_size
- char *to = Ident((char*)malloc(to_size));
- // From is a zero-terminated string "hello\0" of length 6
- char *from = Ident((char*)malloc(from_size));
- strcpy(from, "hello");
- // copy 0 bytes
- strncpy(to, from, 0);
- strncpy(to - 1, from - 1, 0);
- // normal strncpy calls
- strncpy(to, from, from_size);
- strncpy(to, from, to_size);
- strncpy(to, from + from_size - 1, to_size);
- strncpy(to + to_size - 1, from, 1);
- // One of {to, from} points to not allocated memory
- EXPECT_DEATH(Ident(strncpy(to, from - 1, from_size)),
- LeftOOBReadMessage(1));
- EXPECT_DEATH(Ident(strncpy(to - 1, from, from_size)),
- LeftOOBWriteMessage(1));
- EXPECT_DEATH(Ident(strncpy(to, from + from_size, 1)),
- RightOOBReadMessage(0));
- EXPECT_DEATH(Ident(strncpy(to + to_size, from, 1)),
- RightOOBWriteMessage(0));
- // Length of "to" is too small
- EXPECT_DEATH(Ident(strncpy(to + to_size - from_size + 1, from, from_size)),
- RightOOBWriteMessage(0));
- EXPECT_DEATH(Ident(strncpy(to + 1, from, to_size)),
- RightOOBWriteMessage(0));
- // Overwrite terminator in from
- from[from_size - 1] = '!';
- // normal strncpy call
- strncpy(to, from, from_size);
- // Length of "from" is too small
- EXPECT_DEATH(Ident(strncpy(to, from, to_size)),
- RightOOBReadMessage(0));
- free(to);
- free(from);
-}
-
-// Users may have different definitions of "strchr" and "index", so provide
-// function pointer typedefs and overload RunStrChrTest implementation.
-// We can't use macro for RunStrChrTest body here, as this macro would
-// confuse EXPECT_DEATH gtest macro.
-typedef char*(*PointerToStrChr1)(const char*, int);
-typedef char*(*PointerToStrChr2)(char*, int);
-
-UNUSED static void RunStrChrTest(PointerToStrChr1 StrChr) {
- size_t size = Ident(100);
- char *str = MallocAndMemsetString(size);
- str[10] = 'q';
- str[11] = '\0';
- EXPECT_EQ(str, StrChr(str, 'z'));
- EXPECT_EQ(str + 10, StrChr(str, 'q'));
- EXPECT_EQ(NULL, StrChr(str, 'a'));
- // StrChr argument points to not allocated memory.
- EXPECT_DEATH(Ident(StrChr(str - 1, 'z')), LeftOOBReadMessage(1));
- EXPECT_DEATH(Ident(StrChr(str + size, 'z')), RightOOBReadMessage(0));
- // Overwrite the terminator and hit not allocated memory.
- str[11] = 'z';
- EXPECT_DEATH(Ident(StrChr(str, 'a')), RightOOBReadMessage(0));
- free(str);
-}
-UNUSED static void RunStrChrTest(PointerToStrChr2 StrChr) {
- size_t size = Ident(100);
- char *str = MallocAndMemsetString(size);
- str[10] = 'q';
- str[11] = '\0';
- EXPECT_EQ(str, StrChr(str, 'z'));
- EXPECT_EQ(str + 10, StrChr(str, 'q'));
- EXPECT_EQ(NULL, StrChr(str, 'a'));
- // StrChr argument points to not allocated memory.
- EXPECT_DEATH(Ident(StrChr(str - 1, 'z')), LeftOOBReadMessage(1));
- EXPECT_DEATH(Ident(StrChr(str + size, 'z')), RightOOBReadMessage(0));
- // Overwrite the terminator and hit not allocated memory.
- str[11] = 'z';
- EXPECT_DEATH(Ident(StrChr(str, 'a')), RightOOBReadMessage(0));
- free(str);
-}
-
-TEST(AddressSanitizer, StrChrAndIndexOOBTest) {
- RunStrChrTest(&strchr);
-// No index() on Windows and on Android L.
-#if !defined(_WIN32) && !defined(__ANDROID__)
- RunStrChrTest(&index);
-#endif
-}
-
-TEST(AddressSanitizer, StrCmpAndFriendsLogicTest) {
- // strcmp
- EXPECT_EQ(0, strcmp("", ""));
- EXPECT_EQ(0, strcmp("abcd", "abcd"));
- EXPECT_GT(0, strcmp("ab", "ac"));
- EXPECT_GT(0, strcmp("abc", "abcd"));
- EXPECT_LT(0, strcmp("acc", "abc"));
- EXPECT_LT(0, strcmp("abcd", "abc"));
-
- // strncmp
- EXPECT_EQ(0, strncmp("a", "b", 0));
- EXPECT_EQ(0, strncmp("abcd", "abcd", 10));
- EXPECT_EQ(0, strncmp("abcd", "abcef", 3));
- EXPECT_GT(0, strncmp("abcde", "abcfa", 4));
- EXPECT_GT(0, strncmp("a", "b", 5));
- EXPECT_GT(0, strncmp("bc", "bcde", 4));
- EXPECT_LT(0, strncmp("xyz", "xyy", 10));
- EXPECT_LT(0, strncmp("baa", "aaa", 1));
- EXPECT_LT(0, strncmp("zyx", "", 2));
-
-#if !defined(_WIN32) // no str[n]casecmp on Windows.
- // strcasecmp
- EXPECT_EQ(0, strcasecmp("", ""));
- EXPECT_EQ(0, strcasecmp("zzz", "zzz"));
- EXPECT_EQ(0, strcasecmp("abCD", "ABcd"));
- EXPECT_GT(0, strcasecmp("aB", "Ac"));
- EXPECT_GT(0, strcasecmp("ABC", "ABCd"));
- EXPECT_LT(0, strcasecmp("acc", "abc"));
- EXPECT_LT(0, strcasecmp("ABCd", "abc"));
-
- // strncasecmp
- EXPECT_EQ(0, strncasecmp("a", "b", 0));
- EXPECT_EQ(0, strncasecmp("abCD", "ABcd", 10));
- EXPECT_EQ(0, strncasecmp("abCd", "ABcef", 3));
- EXPECT_GT(0, strncasecmp("abcde", "ABCfa", 4));
- EXPECT_GT(0, strncasecmp("a", "B", 5));
- EXPECT_GT(0, strncasecmp("bc", "BCde", 4));
- EXPECT_LT(0, strncasecmp("xyz", "xyy", 10));
- EXPECT_LT(0, strncasecmp("Baa", "aaa", 1));
- EXPECT_LT(0, strncasecmp("zyx", "", 2));
-#endif
-
- // memcmp
- EXPECT_EQ(0, memcmp("a", "b", 0));
- EXPECT_EQ(0, memcmp("ab\0c", "ab\0c", 4));
- EXPECT_GT(0, memcmp("\0ab", "\0ac", 3));
- EXPECT_GT(0, memcmp("abb\0", "abba", 4));
- EXPECT_LT(0, memcmp("ab\0cd", "ab\0c\0", 5));
- EXPECT_LT(0, memcmp("zza", "zyx", 3));
-}
-
-typedef int(*PointerToStrCmp)(const char*, const char*);
-void RunStrCmpTest(PointerToStrCmp StrCmp) {
- size_t size = Ident(100);
- int fill = 'o';
- char *s1 = MallocAndMemsetString(size, fill);
- char *s2 = MallocAndMemsetString(size, fill);
- s1[size - 1] = '\0';
- s2[size - 1] = '\0';
- // Normal StrCmp calls
- Ident(StrCmp(s1, s2));
- Ident(StrCmp(s1, s2 + size - 1));
- Ident(StrCmp(s1 + size - 1, s2 + size - 1));
- // One of arguments points to not allocated memory.
- EXPECT_DEATH(Ident(StrCmp)(s1 - 1, s2), LeftOOBReadMessage(1));
- EXPECT_DEATH(Ident(StrCmp)(s1, s2 - 1), LeftOOBReadMessage(1));
- EXPECT_DEATH(Ident(StrCmp)(s1 + size, s2), RightOOBReadMessage(0));
- EXPECT_DEATH(Ident(StrCmp)(s1, s2 + size), RightOOBReadMessage(0));
- // Hit unallocated memory and die.
- s1[size - 1] = fill;
- EXPECT_DEATH(Ident(StrCmp)(s1, s1), RightOOBReadMessage(0));
- EXPECT_DEATH(Ident(StrCmp)(s1 + size - 1, s2), RightOOBReadMessage(0));
- free(s1);
- free(s2);
-}
-
-TEST(AddressSanitizer, StrCmpOOBTest) {
- RunStrCmpTest(&strcmp);
-}
-
-#if !defined(_WIN32) // no str[n]casecmp on Windows.
-TEST(AddressSanitizer, StrCaseCmpOOBTest) {
- RunStrCmpTest(&strcasecmp);
-}
-#endif
-
-typedef int(*PointerToStrNCmp)(const char*, const char*, size_t);
-void RunStrNCmpTest(PointerToStrNCmp StrNCmp) {
- size_t size = Ident(100);
- char *s1 = MallocAndMemsetString(size);
- char *s2 = MallocAndMemsetString(size);
- s1[size - 1] = '\0';
- s2[size - 1] = '\0';
- // Normal StrNCmp calls
- Ident(StrNCmp(s1, s2, size + 2));
- s1[size - 1] = 'z';
- s2[size - 1] = 'x';
- Ident(StrNCmp(s1 + size - 2, s2 + size - 2, size));
- s2[size - 1] = 'z';
- Ident(StrNCmp(s1 - 1, s2 - 1, 0));
- Ident(StrNCmp(s1 + size - 1, s2 + size - 1, 1));
- // One of arguments points to not allocated memory.
- EXPECT_DEATH(Ident(StrNCmp)(s1 - 1, s2, 1), LeftOOBReadMessage(1));
- EXPECT_DEATH(Ident(StrNCmp)(s1, s2 - 1, 1), LeftOOBReadMessage(1));
- EXPECT_DEATH(Ident(StrNCmp)(s1 + size, s2, 1), RightOOBReadMessage(0));
- EXPECT_DEATH(Ident(StrNCmp)(s1, s2 + size, 1), RightOOBReadMessage(0));
- // Hit unallocated memory and die.
- EXPECT_DEATH(Ident(StrNCmp)(s1 + 1, s2 + 1, size), RightOOBReadMessage(0));
- EXPECT_DEATH(Ident(StrNCmp)(s1 + size - 1, s2, 2), RightOOBReadMessage(0));
- free(s1);
- free(s2);
-}
-
-TEST(AddressSanitizer, StrNCmpOOBTest) {
- RunStrNCmpTest(&strncmp);
-}
-
-#if !defined(_WIN32) // no str[n]casecmp on Windows.
-TEST(AddressSanitizer, StrNCaseCmpOOBTest) {
- RunStrNCmpTest(&strncasecmp);
-}
-#endif
-
-TEST(AddressSanitizer, StrCatOOBTest) {
- // strcat() reads strlen(to) bytes from |to| before concatenating.
- size_t to_size = Ident(100);
- char *to = MallocAndMemsetString(to_size);
- to[0] = '\0';
- size_t from_size = Ident(20);
- char *from = MallocAndMemsetString(from_size);
- from[from_size - 1] = '\0';
- // Normal strcat calls.
- strcat(to, from);
- strcat(to, from);
- strcat(to + from_size, from + from_size - 2);
- // Passing an invalid pointer is an error even when concatenating an empty
- // string.
- EXPECT_DEATH(strcat(to - 1, from + from_size - 1), LeftOOBAccessMessage(1));
- // One of arguments points to not allocated memory.
- EXPECT_DEATH(strcat(to - 1, from), LeftOOBAccessMessage(1));
- EXPECT_DEATH(strcat(to, from - 1), LeftOOBReadMessage(1));
- EXPECT_DEATH(strcat(to, from + from_size), RightOOBReadMessage(0));
-
- // "from" is not zero-terminated.
- from[from_size - 1] = 'z';
- EXPECT_DEATH(strcat(to, from), RightOOBReadMessage(0));
- from[from_size - 1] = '\0';
- // "to" is too short to fit "from".
- memset(to, 'z', to_size);
- to[to_size - from_size + 1] = '\0';
- EXPECT_DEATH(strcat(to, from), RightOOBWriteMessage(0));
- // length of "to" is just enough.
- strcat(to, from + 1);
-
- free(to);
- free(from);
-}
-
-TEST(AddressSanitizer, StrNCatOOBTest) {
- // strncat() reads strlen(to) bytes from |to| before concatenating.
- size_t to_size = Ident(100);
- char *to = MallocAndMemsetString(to_size);
- to[0] = '\0';
- size_t from_size = Ident(20);
- char *from = MallocAndMemsetString(from_size);
- // Normal strncat calls.
- strncat(to, from, 0);
- strncat(to, from, from_size);
- from[from_size - 1] = '\0';
- strncat(to, from, 2 * from_size);
- // Catenating empty string with an invalid string is still an error.
- EXPECT_DEATH(strncat(to - 1, from, 0), LeftOOBAccessMessage(1));
- strncat(to, from + from_size - 1, 10);
- // One of arguments points to not allocated memory.
- EXPECT_DEATH(strncat(to - 1, from, 2), LeftOOBAccessMessage(1));
- EXPECT_DEATH(strncat(to, from - 1, 2), LeftOOBReadMessage(1));
- EXPECT_DEATH(strncat(to, from + from_size, 2), RightOOBReadMessage(0));
-
- memset(from, 'z', from_size);
- memset(to, 'z', to_size);
- to[0] = '\0';
- // "from" is too short.
- EXPECT_DEATH(strncat(to, from, from_size + 1), RightOOBReadMessage(0));
- // "to" is too short to fit "from".
- to[0] = 'z';
- to[to_size - from_size + 1] = '\0';
- EXPECT_DEATH(strncat(to, from, from_size - 1), RightOOBWriteMessage(0));
- // "to" is just enough.
- strncat(to, from, from_size - 2);
-
- free(to);
- free(from);
-}
-
-static string OverlapErrorMessage(const string &func) {
- return func + "-param-overlap";
-}
-
-TEST(AddressSanitizer, StrArgsOverlapTest) {
- size_t size = Ident(100);
- char *str = Ident((char*)malloc(size));
-
-// Do not check memcpy() on OS X 10.7 and later, where it actually aliases
-// memmove().
-#if !defined(__APPLE__) || !defined(MAC_OS_X_VERSION_10_7) || \
- (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7)
- // Check "memcpy". Use Ident() to avoid inlining.
- memset(str, 'z', size);
- Ident(memcpy)(str + 1, str + 11, 10);
- Ident(memcpy)(str, str, 0);
- EXPECT_DEATH(Ident(memcpy)(str, str + 14, 15), OverlapErrorMessage("memcpy"));
- EXPECT_DEATH(Ident(memcpy)(str + 14, str, 15), OverlapErrorMessage("memcpy"));
-#endif
-
- // We do not treat memcpy with to==from as a bug.
- // See http://llvm.org/bugs/show_bug.cgi?id=11763.
- // EXPECT_DEATH(Ident(memcpy)(str + 20, str + 20, 1),
- // OverlapErrorMessage("memcpy"));
-
- // Check "strcpy".
- memset(str, 'z', size);
- str[9] = '\0';
- strcpy(str + 10, str);
- EXPECT_DEATH(strcpy(str + 9, str), OverlapErrorMessage("strcpy"));
- EXPECT_DEATH(strcpy(str, str + 4), OverlapErrorMessage("strcpy"));
- strcpy(str, str + 5);
-
- // Check "strncpy".
- memset(str, 'z', size);
- strncpy(str, str + 10, 10);
- EXPECT_DEATH(strncpy(str, str + 9, 10), OverlapErrorMessage("strncpy"));
- EXPECT_DEATH(strncpy(str + 9, str, 10), OverlapErrorMessage("strncpy"));
- str[10] = '\0';
- strncpy(str + 11, str, 20);
- EXPECT_DEATH(strncpy(str + 10, str, 20), OverlapErrorMessage("strncpy"));
-
- // Check "strcat".
- memset(str, 'z', size);
- str[10] = '\0';
- str[20] = '\0';
- strcat(str, str + 10);
- EXPECT_DEATH(strcat(str, str + 11), OverlapErrorMessage("strcat"));
- str[10] = '\0';
- strcat(str + 11, str);
- EXPECT_DEATH(strcat(str, str + 9), OverlapErrorMessage("strcat"));
- EXPECT_DEATH(strcat(str + 9, str), OverlapErrorMessage("strcat"));
- EXPECT_DEATH(strcat(str + 10, str), OverlapErrorMessage("strcat"));
-
- // Check "strncat".
- memset(str, 'z', size);
- str[10] = '\0';
- strncat(str, str + 10, 10); // from is empty
- EXPECT_DEATH(strncat(str, str + 11, 10), OverlapErrorMessage("strncat"));
- str[10] = '\0';
- str[20] = '\0';
- strncat(str + 5, str, 5);
- str[10] = '\0';
- EXPECT_DEATH(strncat(str + 5, str, 6), OverlapErrorMessage("strncat"));
- EXPECT_DEATH(strncat(str, str + 9, 10), OverlapErrorMessage("strncat"));
-
- free(str);
-}
-
-typedef void(*PointerToCallAtoi)(const char*);
-
-void RunAtoiOOBTest(PointerToCallAtoi Atoi) {
- char *array = MallocAndMemsetString(10, '1');
- // Invalid pointer to the string.
- EXPECT_DEATH(Atoi(array + 11), RightOOBReadMessage(1));
- EXPECT_DEATH(Atoi(array - 1), LeftOOBReadMessage(1));
- // Die if a buffer doesn't have terminating NULL.
- EXPECT_DEATH(Atoi(array), RightOOBReadMessage(0));
- // Make last symbol a terminating NULL
- array[9] = '\0';
- Atoi(array);
- // Sometimes we need to detect overflow if no digits are found.
- memset(array, ' ', 10);
- EXPECT_DEATH(Atoi(array), RightOOBReadMessage(0));
- array[9] = '-';
- EXPECT_DEATH(Atoi(array), RightOOBReadMessage(0));
- EXPECT_DEATH(Atoi(array + 9), RightOOBReadMessage(0));
- free(array);
-}
-
-#if !defined(_WIN32) // FIXME: Fix and enable on Windows.
-void CallAtoi(const char *nptr) {
- Ident(atoi(nptr));
-}
-void CallAtol(const char *nptr) {
- Ident(atol(nptr));
-}
-void CallAtoll(const char *nptr) {
- Ident(atoll(nptr));
-}
-TEST(AddressSanitizer, AtoiAndFriendsOOBTest) {
- RunAtoiOOBTest(&CallAtoi);
- RunAtoiOOBTest(&CallAtol);
- RunAtoiOOBTest(&CallAtoll);
-}
-#endif
-
-typedef void(*PointerToCallStrtol)(const char*, char**, int);
-
-void RunStrtolOOBTest(PointerToCallStrtol Strtol) {
- char *array = MallocAndMemsetString(3);
- array[0] = '1';
- array[1] = '2';
- array[2] = '3';
- // Invalid pointer to the string.
- EXPECT_DEATH(Strtol(array + 3, NULL, 0), RightOOBReadMessage(0));
- EXPECT_DEATH(Strtol(array - 1, NULL, 0), LeftOOBReadMessage(1));
- // Buffer overflow if there is no terminating null (depends on base).
- EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBReadMessage(0));
- array[2] = 'z';
- EXPECT_DEATH(Strtol(array, NULL, 36), RightOOBReadMessage(0));
- // Add terminating zero to get rid of overflow.
- array[2] = '\0';
- Strtol(array, NULL, 36);
- // Sometimes we need to detect overflow if no digits are found.
- array[0] = array[1] = array[2] = ' ';
- EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBReadMessage(0));
- array[2] = '+';
- EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBReadMessage(0));
- array[2] = '-';
- EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBReadMessage(0));
- free(array);
-}
-
-#if !defined(_WIN32) // FIXME: Fix and enable on Windows.
-void CallStrtol(const char *nptr, char **endptr, int base) {
- Ident(strtol(nptr, endptr, base));
-}
-void CallStrtoll(const char *nptr, char **endptr, int base) {
- Ident(strtoll(nptr, endptr, base));
-}
-TEST(AddressSanitizer, StrtollOOBTest) {
- RunStrtolOOBTest(&CallStrtoll);
-}
-TEST(AddressSanitizer, StrtolOOBTest) {
- RunStrtolOOBTest(&CallStrtol);
-}
-#endif
-
-
diff --git a/contrib/compiler-rt/lib/asan/tests/asan_test.cc b/contrib/compiler-rt/lib/asan/tests/asan_test.cc
deleted file mode 100644
index 07d59e09a72f..000000000000
--- a/contrib/compiler-rt/lib/asan/tests/asan_test.cc
+++ /dev/null
@@ -1,1319 +0,0 @@
-//===-- asan_test.cc ------------------------------------------------------===//
-//
-// 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 AddressSanitizer, an address sanity checker.
-//
-//===----------------------------------------------------------------------===//
-#include "asan_test_utils.h"
-
-NOINLINE void *malloc_fff(size_t size) {
- void *res = malloc/**/(size); break_optimization(0); return res;}
-NOINLINE void *malloc_eee(size_t size) {
- void *res = malloc_fff(size); break_optimization(0); return res;}
-NOINLINE void *malloc_ddd(size_t size) {
- void *res = malloc_eee(size); break_optimization(0); return res;}
-NOINLINE void *malloc_ccc(size_t size) {
- void *res = malloc_ddd(size); break_optimization(0); return res;}
-NOINLINE void *malloc_bbb(size_t size) {
- void *res = malloc_ccc(size); break_optimization(0); return res;}
-NOINLINE void *malloc_aaa(size_t size) {
- void *res = malloc_bbb(size); break_optimization(0); return res;}
-
-NOINLINE void free_ccc(void *p) { free(p); break_optimization(0);}
-NOINLINE void free_bbb(void *p) { free_ccc(p); break_optimization(0);}
-NOINLINE void free_aaa(void *p) { free_bbb(p); break_optimization(0);}
-
-template<typename T>
-NOINLINE void uaf_test(int size, int off) {
- void *p = malloc_aaa(size);
- free_aaa(p);
- for (int i = 1; i < 100; i++)
- free_aaa(malloc_aaa(i));
- fprintf(stderr, "writing %ld byte(s) at %p with offset %d\n",
- (long)sizeof(T), p, off);
- asan_write((T *)((char *)p + off));
-}
-
-TEST(AddressSanitizer, HasFeatureAddressSanitizerTest) {
-#if defined(__has_feature) && __has_feature(address_sanitizer)
- bool asan = 1;
-#elif defined(__SANITIZE_ADDRESS__)
- bool asan = 1;
-#else
- bool asan = 0;
-#endif
- EXPECT_EQ(true, asan);
-}
-
-TEST(AddressSanitizer, SimpleDeathTest) {
- EXPECT_DEATH(exit(1), "");
-}
-
-TEST(AddressSanitizer, VariousMallocsTest) {
- int *a = (int*)malloc(100 * sizeof(int));
- a[50] = 0;
- free(a);
-
- int *r = (int*)malloc(10);
- r = (int*)realloc(r, 2000 * sizeof(int));
- r[1000] = 0;
- free(r);
-
- int *b = new int[100];
- b[50] = 0;
- delete [] b;
-
- int *c = new int;
- *c = 0;
- delete c;
-
-#if SANITIZER_TEST_HAS_POSIX_MEMALIGN
- int *pm;
- int pm_res = posix_memalign((void**)&pm, kPageSize, kPageSize);
- EXPECT_EQ(0, pm_res);
- free(pm);
-#endif // SANITIZER_TEST_HAS_POSIX_MEMALIGN
-
-#if SANITIZER_TEST_HAS_MEMALIGN
- int *ma = (int*)memalign(kPageSize, kPageSize);
- EXPECT_EQ(0U, (uintptr_t)ma % kPageSize);
- ma[123] = 0;
- free(ma);
-#endif // SANITIZER_TEST_HAS_MEMALIGN
-}
-
-TEST(AddressSanitizer, CallocTest) {
- int *a = (int*)calloc(100, sizeof(int));
- EXPECT_EQ(0, a[10]);
- free(a);
-}
-
-TEST(AddressSanitizer, CallocReturnsZeroMem) {
- size_t sizes[] = {16, 1000, 10000, 100000, 2100000};
- for (size_t s = 0; s < sizeof(sizes)/sizeof(sizes[0]); s++) {
- size_t size = sizes[s];
- for (size_t iter = 0; iter < 5; iter++) {
- char *x = Ident((char*)calloc(1, size));
- EXPECT_EQ(x[0], 0);
- EXPECT_EQ(x[size - 1], 0);
- EXPECT_EQ(x[size / 2], 0);
- EXPECT_EQ(x[size / 3], 0);
- EXPECT_EQ(x[size / 4], 0);
- memset(x, 0x42, size);
- free(Ident(x));
-#if !defined(_WIN32)
- // FIXME: OOM on Windows. We should just make this a lit test
- // with quarantine size set to 1.
- free(Ident(malloc(Ident(1 << 27)))); // Try to drain the quarantine.
-#endif
- }
- }
-}
-
-// No valloc on Windows or Android.
-#if !defined(_WIN32) && !defined(__ANDROID__)
-TEST(AddressSanitizer, VallocTest) {
- void *a = valloc(100);
- EXPECT_EQ(0U, (uintptr_t)a % kPageSize);
- free(a);
-}
-#endif
-
-#if SANITIZER_TEST_HAS_PVALLOC
-TEST(AddressSanitizer, PvallocTest) {
- char *a = (char*)pvalloc(kPageSize + 100);
- EXPECT_EQ(0U, (uintptr_t)a % kPageSize);
- a[kPageSize + 101] = 1; // we should not report an error here.
- free(a);
-
- a = (char*)pvalloc(0); // pvalloc(0) should allocate at least one page.
- EXPECT_EQ(0U, (uintptr_t)a % kPageSize);
- a[101] = 1; // we should not report an error here.
- free(a);
-}
-#endif // SANITIZER_TEST_HAS_PVALLOC
-
-#if !defined(_WIN32)
-// FIXME: Use an equivalent of pthread_setspecific on Windows.
-void *TSDWorker(void *test_key) {
- if (test_key) {
- pthread_setspecific(*(pthread_key_t*)test_key, (void*)0xfeedface);
- }
- return NULL;
-}
-
-void TSDDestructor(void *tsd) {
- // Spawning a thread will check that the current thread id is not -1.
- pthread_t th;
- PTHREAD_CREATE(&th, NULL, TSDWorker, NULL);
- PTHREAD_JOIN(th, NULL);
-}
-
-// This tests triggers the thread-specific data destruction fiasco which occurs
-// if we don't manage the TSD destructors ourselves. We create a new pthread
-// key with a non-NULL destructor which is likely to be put after the destructor
-// of AsanThread in the list of destructors.
-// In this case the TSD for AsanThread will be destroyed before TSDDestructor
-// is called for the child thread, and a CHECK will fail when we call
-// pthread_create() to spawn the grandchild.
-TEST(AddressSanitizer, DISABLED_TSDTest) {
- pthread_t th;
- pthread_key_t test_key;
- pthread_key_create(&test_key, TSDDestructor);
- PTHREAD_CREATE(&th, NULL, TSDWorker, &test_key);
- PTHREAD_JOIN(th, NULL);
- pthread_key_delete(test_key);
-}
-#endif
-
-TEST(AddressSanitizer, UAF_char) {
- const char *uaf_string = "AddressSanitizer:.*heap-use-after-free";
- EXPECT_DEATH(uaf_test<U1>(1, 0), uaf_string);
- EXPECT_DEATH(uaf_test<U1>(10, 0), uaf_string);
- EXPECT_DEATH(uaf_test<U1>(10, 10), uaf_string);
- EXPECT_DEATH(uaf_test<U1>(kLargeMalloc, 0), uaf_string);
- EXPECT_DEATH(uaf_test<U1>(kLargeMalloc, kLargeMalloc / 2), uaf_string);
-}
-
-TEST(AddressSanitizer, UAF_long_double) {
- if (sizeof(long double) == sizeof(double)) return;
- long double *p = Ident(new long double[10]);
- EXPECT_DEATH(Ident(p)[12] = 0, "WRITE of size 1[026]");
- EXPECT_DEATH(Ident(p)[0] = Ident(p)[12], "READ of size 1[026]");
- delete [] Ident(p);
-}
-
-#if !defined(_WIN32)
-struct Packed5 {
- int x;
- char c;
-} __attribute__((packed));
-#else
-# pragma pack(push, 1)
-struct Packed5 {
- int x;
- char c;
-};
-# pragma pack(pop)
-#endif
-
-TEST(AddressSanitizer, UAF_Packed5) {
- static_assert(sizeof(Packed5) == 5, "Please check the keywords used");
- Packed5 *p = Ident(new Packed5[2]);
- EXPECT_DEATH(p[0] = p[3], "READ of size 5");
- EXPECT_DEATH(p[3] = p[0], "WRITE of size 5");
- delete [] Ident(p);
-}
-
-#if ASAN_HAS_BLACKLIST
-TEST(AddressSanitizer, IgnoreTest) {
- int *x = Ident(new int);
- delete Ident(x);
- *x = 0;
-}
-#endif // ASAN_HAS_BLACKLIST
-
-struct StructWithBitField {
- int bf1:1;
- int bf2:1;
- int bf3:1;
- int bf4:29;
-};
-
-TEST(AddressSanitizer, BitFieldPositiveTest) {
- StructWithBitField *x = new StructWithBitField;
- delete Ident(x);
- EXPECT_DEATH(x->bf1 = 0, "use-after-free");
- EXPECT_DEATH(x->bf2 = 0, "use-after-free");
- EXPECT_DEATH(x->bf3 = 0, "use-after-free");
- EXPECT_DEATH(x->bf4 = 0, "use-after-free");
-}
-
-struct StructWithBitFields_8_24 {
- int a:8;
- int b:24;
-};
-
-TEST(AddressSanitizer, BitFieldNegativeTest) {
- StructWithBitFields_8_24 *x = Ident(new StructWithBitFields_8_24);
- x->a = 0;
- x->b = 0;
- delete Ident(x);
-}
-
-#if ASAN_NEEDS_SEGV
-namespace {
-
-const char kUnknownCrash[] = "AddressSanitizer: SEGV on unknown address";
-const char kOverriddenHandler[] = "ASan signal handler has been overridden\n";
-
-TEST(AddressSanitizer, WildAddressTest) {
- char *c = (char*)0x123;
- EXPECT_DEATH(*c = 0, kUnknownCrash);
-}
-
-void my_sigaction_sighandler(int, siginfo_t*, void*) {
- fprintf(stderr, kOverriddenHandler);
- exit(1);
-}
-
-void my_signal_sighandler(int signum) {
- fprintf(stderr, kOverriddenHandler);
- exit(1);
-}
-
-TEST(AddressSanitizer, SignalTest) {
- struct sigaction sigact;
- memset(&sigact, 0, sizeof(sigact));
- sigact.sa_sigaction = my_sigaction_sighandler;
- sigact.sa_flags = SA_SIGINFO;
- // ASan should silently ignore sigaction()...
- EXPECT_EQ(0, sigaction(SIGSEGV, &sigact, 0));
-#ifdef __APPLE__
- EXPECT_EQ(0, sigaction(SIGBUS, &sigact, 0));
-#endif
- char *c = (char*)0x123;
- EXPECT_DEATH(*c = 0, kUnknownCrash);
- // ... and signal().
- EXPECT_EQ(0, signal(SIGSEGV, my_signal_sighandler));
- EXPECT_DEATH(*c = 0, kUnknownCrash);
-}
-} // namespace
-#endif
-
-static void TestLargeMalloc(size_t size) {
- char buff[1024];
- sprintf(buff, "is located 1 bytes to the left of %lu-byte", (long)size);
- EXPECT_DEATH(Ident((char*)malloc(size))[-1] = 0, buff);
-}
-
-TEST(AddressSanitizer, LargeMallocTest) {
- const int max_size = (SANITIZER_WORDSIZE == 32) ? 1 << 26 : 1 << 28;
- for (int i = 113; i < max_size; i = i * 2 + 13) {
- TestLargeMalloc(i);
- }
-}
-
-TEST(AddressSanitizer, HugeMallocTest) {
- if (SANITIZER_WORDSIZE != 64 || ASAN_AVOID_EXPENSIVE_TESTS) return;
- size_t n_megs = 4100;
- EXPECT_DEATH(Ident((char*)malloc(n_megs << 20))[-1] = 0,
- "is located 1 bytes to the left|"
- "AddressSanitizer failed to allocate");
-}
-
-#if SANITIZER_TEST_HAS_MEMALIGN
-void MemalignRun(size_t align, size_t size, int idx) {
- char *p = (char *)memalign(align, size);
- Ident(p)[idx] = 0;
- free(p);
-}
-
-TEST(AddressSanitizer, memalign) {
- for (int align = 16; align <= (1 << 23); align *= 2) {
- size_t size = align * 5;
- EXPECT_DEATH(MemalignRun(align, size, -1),
- "is located 1 bytes to the left");
- EXPECT_DEATH(MemalignRun(align, size, size + 1),
- "is located 1 bytes to the right");
- }
-}
-#endif // SANITIZER_TEST_HAS_MEMALIGN
-
-void *ManyThreadsWorker(void *a) {
- for (int iter = 0; iter < 100; iter++) {
- for (size_t size = 100; size < 2000; size *= 2) {
- free(Ident(malloc(size)));
- }
- }
- return 0;
-}
-
-TEST(AddressSanitizer, ManyThreadsTest) {
- const size_t kNumThreads =
- (SANITIZER_WORDSIZE == 32 || ASAN_AVOID_EXPENSIVE_TESTS) ? 30 : 1000;
- pthread_t t[kNumThreads];
- for (size_t i = 0; i < kNumThreads; i++) {
- PTHREAD_CREATE(&t[i], 0, ManyThreadsWorker, (void*)i);
- }
- for (size_t i = 0; i < kNumThreads; i++) {
- PTHREAD_JOIN(t[i], 0);
- }
-}
-
-TEST(AddressSanitizer, ReallocTest) {
- const int kMinElem = 5;
- int *ptr = (int*)malloc(sizeof(int) * kMinElem);
- ptr[3] = 3;
- for (int i = 0; i < 10000; i++) {
- ptr = (int*)realloc(ptr,
- (my_rand() % 1000 + kMinElem) * sizeof(int));
- EXPECT_EQ(3, ptr[3]);
- }
- free(ptr);
- // Realloc pointer returned by malloc(0).
- int *ptr2 = Ident((int*)malloc(0));
- ptr2 = Ident((int*)realloc(ptr2, sizeof(*ptr2)));
- *ptr2 = 42;
- EXPECT_EQ(42, *ptr2);
- free(ptr2);
-}
-
-TEST(AddressSanitizer, ReallocFreedPointerTest) {
- void *ptr = Ident(malloc(42));
- ASSERT_TRUE(NULL != ptr);
- free(ptr);
- EXPECT_DEATH(ptr = realloc(ptr, 77), "attempting double-free");
-}
-
-TEST(AddressSanitizer, ReallocInvalidPointerTest) {
- void *ptr = Ident(malloc(42));
- EXPECT_DEATH(ptr = realloc((int*)ptr + 1, 77), "attempting free.*not malloc");
- free(ptr);
-}
-
-TEST(AddressSanitizer, ZeroSizeMallocTest) {
- // Test that malloc(0) and similar functions don't return NULL.
- void *ptr = Ident(malloc(0));
- EXPECT_TRUE(NULL != ptr);
- free(ptr);
-#if SANITIZER_TEST_HAS_POSIX_MEMALIGN
- int pm_res = posix_memalign(&ptr, 1<<20, 0);
- EXPECT_EQ(0, pm_res);
- EXPECT_TRUE(NULL != ptr);
- free(ptr);
-#endif // SANITIZER_TEST_HAS_POSIX_MEMALIGN
- int *int_ptr = new int[0];
- int *int_ptr2 = new int[0];
- EXPECT_TRUE(NULL != int_ptr);
- EXPECT_TRUE(NULL != int_ptr2);
- EXPECT_NE(int_ptr, int_ptr2);
- delete[] int_ptr;
- delete[] int_ptr2;
-}
-
-#if SANITIZER_TEST_HAS_MALLOC_USABLE_SIZE
-static const char *kMallocUsableSizeErrorMsg =
- "AddressSanitizer: attempting to call malloc_usable_size()";
-
-TEST(AddressSanitizer, MallocUsableSizeTest) {
- const size_t kArraySize = 100;
- char *array = Ident((char*)malloc(kArraySize));
- int *int_ptr = Ident(new int);
- EXPECT_EQ(0U, malloc_usable_size(NULL));
- EXPECT_EQ(kArraySize, malloc_usable_size(array));
- EXPECT_EQ(sizeof(int), malloc_usable_size(int_ptr));
- EXPECT_DEATH(malloc_usable_size((void*)0x123), kMallocUsableSizeErrorMsg);
- EXPECT_DEATH(malloc_usable_size(array + kArraySize / 2),
- kMallocUsableSizeErrorMsg);
- free(array);
- EXPECT_DEATH(malloc_usable_size(array), kMallocUsableSizeErrorMsg);
- delete int_ptr;
-}
-#endif // SANITIZER_TEST_HAS_MALLOC_USABLE_SIZE
-
-void WrongFree() {
- int *x = (int*)malloc(100 * sizeof(int));
- // Use the allocated memory, otherwise Clang will optimize it out.
- Ident(x);
- free(x + 1);
-}
-
-#if !defined(_WIN32) // FIXME: This should be a lit test.
-TEST(AddressSanitizer, WrongFreeTest) {
- EXPECT_DEATH(WrongFree(), ASAN_PCRE_DOTALL
- "ERROR: AddressSanitizer: attempting free.*not malloc"
- ".*is located 4 bytes inside of 400-byte region"
- ".*allocated by thread");
-}
-#endif
-
-void DoubleFree() {
- int *x = (int*)malloc(100 * sizeof(int));
- fprintf(stderr, "DoubleFree: x=%p\n", (void *)x);
- free(x);
- free(x);
- fprintf(stderr, "should have failed in the second free(%p)\n", (void *)x);
- abort();
-}
-
-#if !defined(_WIN32) // FIXME: This should be a lit test.
-TEST(AddressSanitizer, DoubleFreeTest) {
- EXPECT_DEATH(DoubleFree(), ASAN_PCRE_DOTALL
- "ERROR: AddressSanitizer: attempting double-free"
- ".*is located 0 bytes inside of 400-byte region"
- ".*freed by thread T0 here"
- ".*previously allocated by thread T0 here");
-}
-#endif
-
-template<int kSize>
-NOINLINE void SizedStackTest() {
- char a[kSize];
- char *A = Ident((char*)&a);
- const char *expected_death = "AddressSanitizer: stack-buffer-";
- for (size_t i = 0; i < kSize; i++)
- A[i] = i;
- EXPECT_DEATH(A[-1] = 0, expected_death);
- EXPECT_DEATH(A[-5] = 0, expected_death);
- EXPECT_DEATH(A[kSize] = 0, expected_death);
- EXPECT_DEATH(A[kSize + 1] = 0, expected_death);
- EXPECT_DEATH(A[kSize + 5] = 0, expected_death);
- if (kSize > 16)
- EXPECT_DEATH(A[kSize + 31] = 0, expected_death);
-}
-
-TEST(AddressSanitizer, SimpleStackTest) {
- SizedStackTest<1>();
- SizedStackTest<2>();
- SizedStackTest<3>();
- SizedStackTest<4>();
- SizedStackTest<5>();
- SizedStackTest<6>();
- SizedStackTest<7>();
- SizedStackTest<16>();
- SizedStackTest<25>();
- SizedStackTest<34>();
- SizedStackTest<43>();
- SizedStackTest<51>();
- SizedStackTest<62>();
- SizedStackTest<64>();
- SizedStackTest<128>();
-}
-
-#if !defined(_WIN32)
-// FIXME: It's a bit hard to write multi-line death test expectations
-// in a portable way. Anyways, this should just be turned into a lit test.
-TEST(AddressSanitizer, ManyStackObjectsTest) {
- char XXX[10];
- char YYY[20];
- char ZZZ[30];
- Ident(XXX);
- Ident(YYY);
- EXPECT_DEATH(Ident(ZZZ)[-1] = 0, ASAN_PCRE_DOTALL "XXX.*YYY.*ZZZ");
-}
-#endif
-
-#if 0 // This test requires online symbolizer.
-// Moved to lit_tests/stack-oob-frames.cc.
-// Reenable here once we have online symbolizer by default.
-NOINLINE static void Frame0(int frame, char *a, char *b, char *c) {
- char d[4] = {0};
- char *D = Ident(d);
- switch (frame) {
- case 3: a[5]++; break;
- case 2: b[5]++; break;
- case 1: c[5]++; break;
- case 0: D[5]++; break;
- }
-}
-NOINLINE static void Frame1(int frame, char *a, char *b) {
- char c[4] = {0}; Frame0(frame, a, b, c);
- break_optimization(0);
-}
-NOINLINE static void Frame2(int frame, char *a) {
- char b[4] = {0}; Frame1(frame, a, b);
- break_optimization(0);
-}
-NOINLINE static void Frame3(int frame) {
- char a[4] = {0}; Frame2(frame, a);
- break_optimization(0);
-}
-
-TEST(AddressSanitizer, GuiltyStackFrame0Test) {
- EXPECT_DEATH(Frame3(0), "located .*in frame <.*Frame0");
-}
-TEST(AddressSanitizer, GuiltyStackFrame1Test) {
- EXPECT_DEATH(Frame3(1), "located .*in frame <.*Frame1");
-}
-TEST(AddressSanitizer, GuiltyStackFrame2Test) {
- EXPECT_DEATH(Frame3(2), "located .*in frame <.*Frame2");
-}
-TEST(AddressSanitizer, GuiltyStackFrame3Test) {
- EXPECT_DEATH(Frame3(3), "located .*in frame <.*Frame3");
-}
-#endif
-
-NOINLINE void LongJmpFunc1(jmp_buf buf) {
- // create three red zones for these two stack objects.
- int a;
- int b;
-
- int *A = Ident(&a);
- int *B = Ident(&b);
- *A = *B;
- longjmp(buf, 1);
-}
-
-NOINLINE void TouchStackFunc() {
- int a[100]; // long array will intersect with redzones from LongJmpFunc1.
- int *A = Ident(a);
- for (int i = 0; i < 100; i++)
- A[i] = i*i;
-}
-
-// Test that we handle longjmp and do not report false positives on stack.
-TEST(AddressSanitizer, LongJmpTest) {
- static jmp_buf buf;
- if (!setjmp(buf)) {
- LongJmpFunc1(buf);
- } else {
- TouchStackFunc();
- }
-}
-
-#if !defined(_WIN32) // Only basic longjmp is available on Windows.
-NOINLINE void UnderscopeLongJmpFunc1(jmp_buf buf) {
- // create three red zones for these two stack objects.
- int a;
- int b;
-
- int *A = Ident(&a);
- int *B = Ident(&b);
- *A = *B;
- _longjmp(buf, 1);
-}
-
-NOINLINE void SigLongJmpFunc1(sigjmp_buf buf) {
- // create three red zones for these two stack objects.
- int a;
- int b;
-
- int *A = Ident(&a);
- int *B = Ident(&b);
- *A = *B;
- siglongjmp(buf, 1);
-}
-
-#if !defined(__ANDROID__) && !defined(__arm__) && \
- !defined(__powerpc64__) && !defined(__powerpc__) && \
- !defined(__aarch64__) && !defined(__mips__) && \
- !defined(__mips64)
-NOINLINE void BuiltinLongJmpFunc1(jmp_buf buf) {
- // create three red zones for these two stack objects.
- int a;
- int b;
-
- int *A = Ident(&a);
- int *B = Ident(&b);
- *A = *B;
- __builtin_longjmp((void**)buf, 1);
-}
-
-// Does not work on Power and ARM:
-// https://code.google.com/p/address-sanitizer/issues/detail?id=185
-TEST(AddressSanitizer, BuiltinLongJmpTest) {
- static jmp_buf buf;
- if (!__builtin_setjmp((void**)buf)) {
- BuiltinLongJmpFunc1(buf);
- } else {
- TouchStackFunc();
- }
-}
-#endif // !defined(__ANDROID__) && !defined(__powerpc64__) &&
- // !defined(__powerpc__) && !defined(__arm__) &&
- // !defined(__mips__) && !defined(__mips64)
-
-TEST(AddressSanitizer, UnderscopeLongJmpTest) {
- static jmp_buf buf;
- if (!_setjmp(buf)) {
- UnderscopeLongJmpFunc1(buf);
- } else {
- TouchStackFunc();
- }
-}
-
-TEST(AddressSanitizer, SigLongJmpTest) {
- static sigjmp_buf buf;
- if (!sigsetjmp(buf, 1)) {
- SigLongJmpFunc1(buf);
- } else {
- TouchStackFunc();
- }
-}
-#endif
-
-// FIXME: Why does clang-cl define __EXCEPTIONS?
-#if defined(__EXCEPTIONS) && !defined(_WIN32)
-NOINLINE void ThrowFunc() {
- // create three red zones for these two stack objects.
- int a;
- int b;
-
- int *A = Ident(&a);
- int *B = Ident(&b);
- *A = *B;
- ASAN_THROW(1);
-}
-
-TEST(AddressSanitizer, CxxExceptionTest) {
- if (ASAN_UAR) return;
- // TODO(kcc): this test crashes on 32-bit for some reason...
- if (SANITIZER_WORDSIZE == 32) return;
- try {
- ThrowFunc();
- } catch(...) {}
- TouchStackFunc();
-}
-#endif
-
-void *ThreadStackReuseFunc1(void *unused) {
- // create three red zones for these two stack objects.
- int a;
- int b;
-
- int *A = Ident(&a);
- int *B = Ident(&b);
- *A = *B;
- pthread_exit(0);
- return 0;
-}
-
-void *ThreadStackReuseFunc2(void *unused) {
- TouchStackFunc();
- return 0;
-}
-
-TEST(AddressSanitizer, ThreadStackReuseTest) {
- pthread_t t;
- PTHREAD_CREATE(&t, 0, ThreadStackReuseFunc1, 0);
- PTHREAD_JOIN(t, 0);
- PTHREAD_CREATE(&t, 0, ThreadStackReuseFunc2, 0);
- PTHREAD_JOIN(t, 0);
-}
-
-#if defined(__i686__) || defined(__x86_64__)
-#include <emmintrin.h>
-TEST(AddressSanitizer, Store128Test) {
- char *a = Ident((char*)malloc(Ident(12)));
- char *p = a;
- if (((uintptr_t)a % 16) != 0)
- p = a + 8;
- assert(((uintptr_t)p % 16) == 0);
- __m128i value_wide = _mm_set1_epi16(0x1234);
- EXPECT_DEATH(_mm_store_si128((__m128i*)p, value_wide),
- "AddressSanitizer: heap-buffer-overflow");
- EXPECT_DEATH(_mm_store_si128((__m128i*)p, value_wide),
- "WRITE of size 16");
- EXPECT_DEATH(_mm_store_si128((__m128i*)p, value_wide),
- "located 0 bytes to the right of 12-byte");
- free(a);
-}
-#endif
-
-// FIXME: All tests that use this function should be turned into lit tests.
-string RightOOBErrorMessage(int oob_distance, bool is_write) {
- assert(oob_distance >= 0);
- char expected_str[100];
- sprintf(expected_str, ASAN_PCRE_DOTALL
-#if !GTEST_USES_SIMPLE_RE
- "buffer-overflow.*%s.*"
-#endif
- "located %d bytes to the right",
-#if !GTEST_USES_SIMPLE_RE
- is_write ? "WRITE" : "READ",
-#endif
- oob_distance);
- return string(expected_str);
-}
-
-string RightOOBWriteMessage(int oob_distance) {
- return RightOOBErrorMessage(oob_distance, /*is_write*/true);
-}
-
-string RightOOBReadMessage(int oob_distance) {
- return RightOOBErrorMessage(oob_distance, /*is_write*/false);
-}
-
-// FIXME: All tests that use this function should be turned into lit tests.
-string LeftOOBErrorMessage(int oob_distance, bool is_write) {
- assert(oob_distance > 0);
- char expected_str[100];
- sprintf(expected_str,
-#if !GTEST_USES_SIMPLE_RE
- ASAN_PCRE_DOTALL "%s.*"
-#endif
- "located %d bytes to the left",
-#if !GTEST_USES_SIMPLE_RE
- is_write ? "WRITE" : "READ",
-#endif
- oob_distance);
- return string(expected_str);
-}
-
-string LeftOOBWriteMessage(int oob_distance) {
- return LeftOOBErrorMessage(oob_distance, /*is_write*/true);
-}
-
-string LeftOOBReadMessage(int oob_distance) {
- return LeftOOBErrorMessage(oob_distance, /*is_write*/false);
-}
-
-string LeftOOBAccessMessage(int oob_distance) {
- assert(oob_distance > 0);
- char expected_str[100];
- sprintf(expected_str, "located %d bytes to the left", oob_distance);
- return string(expected_str);
-}
-
-char* MallocAndMemsetString(size_t size, char ch) {
- char *s = Ident((char*)malloc(size));
- memset(s, ch, size);
- return s;
-}
-
-char* MallocAndMemsetString(size_t size) {
- return MallocAndMemsetString(size, 'z');
-}
-
-#if defined(__linux__) && !defined(__ANDROID__)
-#define READ_TEST(READ_N_BYTES) \
- char *x = new char[10]; \
- int fd = open("/proc/self/stat", O_RDONLY); \
- ASSERT_GT(fd, 0); \
- EXPECT_DEATH(READ_N_BYTES, \
- ASAN_PCRE_DOTALL \
- "AddressSanitizer: heap-buffer-overflow" \
- ".* is located 0 bytes to the right of 10-byte region"); \
- close(fd); \
- delete [] x; \
-
-TEST(AddressSanitizer, pread) {
- READ_TEST(pread(fd, x, 15, 0));
-}
-
-TEST(AddressSanitizer, pread64) {
- READ_TEST(pread64(fd, x, 15, 0));
-}
-
-TEST(AddressSanitizer, read) {
- READ_TEST(read(fd, x, 15));
-}
-#endif // defined(__linux__) && !defined(__ANDROID__)
-
-// This test case fails
-// Clang optimizes memcpy/memset calls which lead to unaligned access
-TEST(AddressSanitizer, DISABLED_MemIntrinsicUnalignedAccessTest) {
- int size = Ident(4096);
- char *s = Ident((char*)malloc(size));
- EXPECT_DEATH(memset(s + size - 1, 0, 2), RightOOBWriteMessage(0));
- free(s);
-}
-
-// TODO(samsonov): Add a test with malloc(0)
-// TODO(samsonov): Add tests for str* and mem* functions.
-
-NOINLINE static int LargeFunction(bool do_bad_access) {
- int *x = new int[100];
- x[0]++;
- x[1]++;
- x[2]++;
- x[3]++;
- x[4]++;
- x[5]++;
- x[6]++;
- x[7]++;
- x[8]++;
- x[9]++;
-
- x[do_bad_access ? 100 : 0]++; int res = __LINE__;
-
- x[10]++;
- x[11]++;
- x[12]++;
- x[13]++;
- x[14]++;
- x[15]++;
- x[16]++;
- x[17]++;
- x[18]++;
- x[19]++;
-
- delete[] x;
- return res;
-}
-
-// Test the we have correct debug info for the failing instruction.
-// This test requires the in-process symbolizer to be enabled by default.
-TEST(AddressSanitizer, DISABLED_LargeFunctionSymbolizeTest) {
- int failing_line = LargeFunction(false);
- char expected_warning[128];
- sprintf(expected_warning, "LargeFunction.*asan_test.*:%d", failing_line);
- EXPECT_DEATH(LargeFunction(true), expected_warning);
-}
-
-// Check that we unwind and symbolize correctly.
-TEST(AddressSanitizer, DISABLED_MallocFreeUnwindAndSymbolizeTest) {
- int *a = (int*)malloc_aaa(sizeof(int));
- *a = 1;
- free_aaa(a);
- EXPECT_DEATH(*a = 1, "free_ccc.*free_bbb.*free_aaa.*"
- "malloc_fff.*malloc_eee.*malloc_ddd");
-}
-
-static bool TryToSetThreadName(const char *name) {
-#if defined(__linux__) && defined(PR_SET_NAME)
- return 0 == prctl(PR_SET_NAME, (unsigned long)name, 0, 0, 0);
-#else
- return false;
-#endif
-}
-
-void *ThreadedTestAlloc(void *a) {
- EXPECT_EQ(true, TryToSetThreadName("AllocThr"));
- int **p = (int**)a;
- *p = new int;
- return 0;
-}
-
-void *ThreadedTestFree(void *a) {
- EXPECT_EQ(true, TryToSetThreadName("FreeThr"));
- int **p = (int**)a;
- delete *p;
- return 0;
-}
-
-void *ThreadedTestUse(void *a) {
- EXPECT_EQ(true, TryToSetThreadName("UseThr"));
- int **p = (int**)a;
- **p = 1;
- return 0;
-}
-
-void ThreadedTestSpawn() {
- pthread_t t;
- int *x;
- PTHREAD_CREATE(&t, 0, ThreadedTestAlloc, &x);
- PTHREAD_JOIN(t, 0);
- PTHREAD_CREATE(&t, 0, ThreadedTestFree, &x);
- PTHREAD_JOIN(t, 0);
- PTHREAD_CREATE(&t, 0, ThreadedTestUse, &x);
- PTHREAD_JOIN(t, 0);
-}
-
-#if !defined(_WIN32) // FIXME: This should be a lit test.
-TEST(AddressSanitizer, ThreadedTest) {
- EXPECT_DEATH(ThreadedTestSpawn(),
- ASAN_PCRE_DOTALL
- "Thread T.*created"
- ".*Thread T.*created"
- ".*Thread T.*created");
-}
-#endif
-
-void *ThreadedTestFunc(void *unused) {
- // Check if prctl(PR_SET_NAME) is supported. Return if not.
- if (!TryToSetThreadName("TestFunc"))
- return 0;
- EXPECT_DEATH(ThreadedTestSpawn(),
- ASAN_PCRE_DOTALL
- "WRITE .*thread T. .UseThr."
- ".*freed by thread T. .FreeThr. here:"
- ".*previously allocated by thread T. .AllocThr. here:"
- ".*Thread T. .UseThr. created by T.*TestFunc"
- ".*Thread T. .FreeThr. created by T"
- ".*Thread T. .AllocThr. created by T"
- "");
- return 0;
-}
-
-TEST(AddressSanitizer, ThreadNamesTest) {
- // Run ThreadedTestFunc in a separate thread because it tries to set a
- // thread name and we don't want to change the main thread's name.
- pthread_t t;
- PTHREAD_CREATE(&t, 0, ThreadedTestFunc, 0);
- PTHREAD_JOIN(t, 0);
-}
-
-#if ASAN_NEEDS_SEGV
-TEST(AddressSanitizer, ShadowGapTest) {
-#if SANITIZER_WORDSIZE == 32
- char *addr = (char*)0x22000000;
-#else
-# if defined(__powerpc64__)
- char *addr = (char*)0x024000800000;
-# else
- char *addr = (char*)0x0000100000080000;
-# endif
-#endif
- EXPECT_DEATH(*addr = 1, "AddressSanitizer: SEGV on unknown");
-}
-#endif // ASAN_NEEDS_SEGV
-
-extern "C" {
-NOINLINE static void UseThenFreeThenUse() {
- char *x = Ident((char*)malloc(8));
- *x = 1;
- free_aaa(x);
- *x = 2;
-}
-}
-
-TEST(AddressSanitizer, UseThenFreeThenUseTest) {
- EXPECT_DEATH(UseThenFreeThenUse(), "freed by thread");
-}
-
-TEST(AddressSanitizer, StrDupTest) {
- free(strdup(Ident("123")));
-}
-
-// Currently we create and poison redzone at right of global variables.
-static char static110[110];
-const char ConstGlob[7] = {1, 2, 3, 4, 5, 6, 7};
-static const char StaticConstGlob[3] = {9, 8, 7};
-
-TEST(AddressSanitizer, GlobalTest) {
- static char func_static15[15];
-
- static char fs1[10];
- static char fs2[10];
- static char fs3[10];
-
- glob5[Ident(0)] = 0;
- glob5[Ident(1)] = 0;
- glob5[Ident(2)] = 0;
- glob5[Ident(3)] = 0;
- glob5[Ident(4)] = 0;
-
- EXPECT_DEATH(glob5[Ident(5)] = 0,
- "0 bytes to the right of global variable.*glob5.* size 5");
- EXPECT_DEATH(glob5[Ident(5+6)] = 0,
- "6 bytes to the right of global variable.*glob5.* size 5");
- Ident(static110); // avoid optimizations
- static110[Ident(0)] = 0;
- static110[Ident(109)] = 0;
- EXPECT_DEATH(static110[Ident(110)] = 0,
- "0 bytes to the right of global variable");
- EXPECT_DEATH(static110[Ident(110+7)] = 0,
- "7 bytes to the right of global variable");
-
- Ident(func_static15); // avoid optimizations
- func_static15[Ident(0)] = 0;
- EXPECT_DEATH(func_static15[Ident(15)] = 0,
- "0 bytes to the right of global variable");
- EXPECT_DEATH(func_static15[Ident(15 + 9)] = 0,
- "9 bytes to the right of global variable");
-
- Ident(fs1);
- Ident(fs2);
- Ident(fs3);
-
- // We don't create left redzones, so this is not 100% guaranteed to fail.
- // But most likely will.
- EXPECT_DEATH(fs2[Ident(-1)] = 0, "is located.*of global variable");
-
- EXPECT_DEATH(Ident(Ident(ConstGlob)[8]),
- "is located 1 bytes to the right of .*ConstGlob");
- EXPECT_DEATH(Ident(Ident(StaticConstGlob)[5]),
- "is located 2 bytes to the right of .*StaticConstGlob");
-
- // call stuff from another file.
- GlobalsTest(0);
-}
-
-TEST(AddressSanitizer, GlobalStringConstTest) {
- static const char *zoo = "FOOBAR123";
- const char *p = Ident(zoo);
- EXPECT_DEATH(Ident(p[15]), "is ascii string 'FOOBAR123'");
-}
-
-TEST(AddressSanitizer, FileNameInGlobalReportTest) {
- static char zoo[10];
- const char *p = Ident(zoo);
- // The file name should be present in the report.
- EXPECT_DEATH(Ident(p[15]), "zoo.*asan_test.");
-}
-
-int *ReturnsPointerToALocalObject() {
- int a = 0;
- return Ident(&a);
-}
-
-#if ASAN_UAR == 1
-TEST(AddressSanitizer, LocalReferenceReturnTest) {
- int *(*f)() = Ident(ReturnsPointerToALocalObject);
- int *p = f();
- // Call 'f' a few more times, 'p' should still be poisoned.
- for (int i = 0; i < 32; i++)
- f();
- EXPECT_DEATH(*p = 1, "AddressSanitizer: stack-use-after-return");
- EXPECT_DEATH(*p = 1, "is located.*in frame .*ReturnsPointerToALocal");
-}
-#endif
-
-template <int kSize>
-NOINLINE static void FuncWithStack() {
- char x[kSize];
- Ident(x)[0] = 0;
- Ident(x)[kSize-1] = 0;
-}
-
-static void LotsOfStackReuse() {
- int LargeStack[10000];
- Ident(LargeStack)[0] = 0;
- for (int i = 0; i < 10000; i++) {
- FuncWithStack<128 * 1>();
- FuncWithStack<128 * 2>();
- FuncWithStack<128 * 4>();
- FuncWithStack<128 * 8>();
- FuncWithStack<128 * 16>();
- FuncWithStack<128 * 32>();
- FuncWithStack<128 * 64>();
- FuncWithStack<128 * 128>();
- FuncWithStack<128 * 256>();
- FuncWithStack<128 * 512>();
- Ident(LargeStack)[0] = 0;
- }
-}
-
-TEST(AddressSanitizer, StressStackReuseTest) {
- LotsOfStackReuse();
-}
-
-TEST(AddressSanitizer, ThreadedStressStackReuseTest) {
- const int kNumThreads = 20;
- pthread_t t[kNumThreads];
- for (int i = 0; i < kNumThreads; i++) {
- PTHREAD_CREATE(&t[i], 0, (void* (*)(void *x))LotsOfStackReuse, 0);
- }
- for (int i = 0; i < kNumThreads; i++) {
- PTHREAD_JOIN(t[i], 0);
- }
-}
-
-static void *PthreadExit(void *a) {
- pthread_exit(0);
- return 0;
-}
-
-TEST(AddressSanitizer, PthreadExitTest) {
- pthread_t t;
- for (int i = 0; i < 1000; i++) {
- PTHREAD_CREATE(&t, 0, PthreadExit, 0);
- PTHREAD_JOIN(t, 0);
- }
-}
-
-// FIXME: Why does clang-cl define __EXCEPTIONS?
-#if defined(__EXCEPTIONS) && !defined(_WIN32)
-NOINLINE static void StackReuseAndException() {
- int large_stack[1000];
- Ident(large_stack);
- ASAN_THROW(1);
-}
-
-// TODO(kcc): support exceptions with use-after-return.
-TEST(AddressSanitizer, DISABLED_StressStackReuseAndExceptionsTest) {
- for (int i = 0; i < 10000; i++) {
- try {
- StackReuseAndException();
- } catch(...) {
- }
- }
-}
-#endif
-
-#if !defined(_WIN32)
-TEST(AddressSanitizer, MlockTest) {
- EXPECT_EQ(0, mlockall(MCL_CURRENT));
- EXPECT_EQ(0, mlock((void*)0x12345, 0x5678));
- EXPECT_EQ(0, munlockall());
- EXPECT_EQ(0, munlock((void*)0x987, 0x654));
-}
-#endif
-
-struct LargeStruct {
- int foo[100];
-};
-
-// Test for bug http://llvm.org/bugs/show_bug.cgi?id=11763.
-// Struct copy should not cause asan warning even if lhs == rhs.
-TEST(AddressSanitizer, LargeStructCopyTest) {
- LargeStruct a;
- *Ident(&a) = *Ident(&a);
-}
-
-ATTRIBUTE_NO_SANITIZE_ADDRESS
-static void NoSanitizeAddress() {
- char *foo = new char[10];
- Ident(foo)[10] = 0;
- delete [] foo;
-}
-
-TEST(AddressSanitizer, AttributeNoSanitizeAddressTest) {
- Ident(NoSanitizeAddress)();
-}
-
-// The new/delete/etc mismatch checks don't work on Android,
-// as calls to new/delete go through malloc/free.
-// OS X support is tracked here:
-// https://code.google.com/p/address-sanitizer/issues/detail?id=131
-// Windows support is tracked here:
-// https://code.google.com/p/address-sanitizer/issues/detail?id=309
-#if !defined(__ANDROID__) && \
- !defined(__APPLE__) && \
- !defined(_WIN32)
-static string MismatchStr(const string &str) {
- return string("AddressSanitizer: alloc-dealloc-mismatch \\(") + str;
-}
-
-TEST(AddressSanitizer, AllocDeallocMismatch) {
- EXPECT_DEATH(free(Ident(new int)),
- MismatchStr("operator new vs free"));
- EXPECT_DEATH(free(Ident(new int[2])),
- MismatchStr("operator new \\[\\] vs free"));
- EXPECT_DEATH(delete (Ident(new int[2])),
- MismatchStr("operator new \\[\\] vs operator delete"));
- EXPECT_DEATH(delete (Ident((int*)malloc(2 * sizeof(int)))),
- MismatchStr("malloc vs operator delete"));
- EXPECT_DEATH(delete [] (Ident(new int)),
- MismatchStr("operator new vs operator delete \\[\\]"));
- EXPECT_DEATH(delete [] (Ident((int*)malloc(2 * sizeof(int)))),
- MismatchStr("malloc vs operator delete \\[\\]"));
-}
-#endif
-
-// ------------------ demo tests; run each one-by-one -------------
-// e.g. --gtest_filter=*DemoOOBLeftHigh --gtest_also_run_disabled_tests
-TEST(AddressSanitizer, DISABLED_DemoThreadedTest) {
- ThreadedTestSpawn();
-}
-
-void *SimpleBugOnSTack(void *x = 0) {
- char a[20];
- Ident(a)[20] = 0;
- return 0;
-}
-
-TEST(AddressSanitizer, DISABLED_DemoStackTest) {
- SimpleBugOnSTack();
-}
-
-TEST(AddressSanitizer, DISABLED_DemoThreadStackTest) {
- pthread_t t;
- PTHREAD_CREATE(&t, 0, SimpleBugOnSTack, 0);
- PTHREAD_JOIN(t, 0);
-}
-
-TEST(AddressSanitizer, DISABLED_DemoUAFLowIn) {
- uaf_test<U1>(10, 0);
-}
-TEST(AddressSanitizer, DISABLED_DemoUAFLowLeft) {
- uaf_test<U1>(10, -2);
-}
-TEST(AddressSanitizer, DISABLED_DemoUAFLowRight) {
- uaf_test<U1>(10, 10);
-}
-
-TEST(AddressSanitizer, DISABLED_DemoUAFHigh) {
- uaf_test<U1>(kLargeMalloc, 0);
-}
-
-TEST(AddressSanitizer, DISABLED_DemoOOM) {
- size_t size = SANITIZER_WORDSIZE == 64 ? (size_t)(1ULL << 40) : (0xf0000000);
- printf("%p\n", malloc(size));
-}
-
-TEST(AddressSanitizer, DISABLED_DemoDoubleFreeTest) {
- DoubleFree();
-}
-
-TEST(AddressSanitizer, DISABLED_DemoNullDerefTest) {
- int *a = 0;
- Ident(a)[10] = 0;
-}
-
-TEST(AddressSanitizer, DISABLED_DemoFunctionStaticTest) {
- static char a[100];
- static char b[100];
- static char c[100];
- Ident(a);
- Ident(b);
- Ident(c);
- Ident(a)[5] = 0;
- Ident(b)[105] = 0;
- Ident(a)[5] = 0;
-}
-
-TEST(AddressSanitizer, DISABLED_DemoTooMuchMemoryTest) {
- const size_t kAllocSize = (1 << 28) - 1024;
- size_t total_size = 0;
- while (true) {
- void *x = malloc(kAllocSize);
- memset(x, 0, kAllocSize);
- total_size += kAllocSize;
- fprintf(stderr, "total: %ldM %p\n", (long)total_size >> 20, x);
- }
-}
-
-// http://code.google.com/p/address-sanitizer/issues/detail?id=66
-TEST(AddressSanitizer, BufferOverflowAfterManyFrees) {
- for (int i = 0; i < 1000000; i++) {
- delete [] (Ident(new char [8644]));
- }
- char *x = new char[8192];
- EXPECT_DEATH(x[Ident(8192)] = 0, "AddressSanitizer: heap-buffer-overflow");
- delete [] Ident(x);
-}
-
-
-// Test that instrumentation of stack allocations takes into account
-// AllocSize of a type, and not its StoreSize (16 vs 10 bytes for long double).
-// See http://llvm.org/bugs/show_bug.cgi?id=12047 for more details.
-TEST(AddressSanitizer, LongDoubleNegativeTest) {
- long double a, b;
- static long double c;
- memcpy(Ident(&a), Ident(&b), sizeof(long double));
- memcpy(Ident(&c), Ident(&b), sizeof(long double));
-}
-
-#if !defined(_WIN32)
-TEST(AddressSanitizer, pthread_getschedparam) {
- int policy;
- struct sched_param param;
- EXPECT_DEATH(
- pthread_getschedparam(pthread_self(), &policy, Ident(&param) + 2),
- "AddressSanitizer: stack-buffer-.*flow");
- EXPECT_DEATH(
- pthread_getschedparam(pthread_self(), Ident(&policy) - 1, &param),
- "AddressSanitizer: stack-buffer-.*flow");
- int res = pthread_getschedparam(pthread_self(), &policy, &param);
- ASSERT_EQ(0, res);
-}
-#endif
-
-#if SANITIZER_TEST_HAS_PRINTF_L
-static int vsnprintf_l_wrapper(char *s, size_t n,
- locale_t l, const char *format, ...) {
- va_list va;
- va_start(va, format);
- int res = vsnprintf_l(s, n , l, format, va);
- va_end(va);
- return res;
-}
-
-TEST(AddressSanitizer, snprintf_l) {
- char buff[5];
- // Check that snprintf_l() works fine with Asan.
- int res = snprintf_l(buff, 5,
- _LIBCPP_GET_C_LOCALE, "%s", "snprintf_l()");
- EXPECT_EQ(12, res);
- // Check that vsnprintf_l() works fine with Asan.
- res = vsnprintf_l_wrapper(buff, 5,
- _LIBCPP_GET_C_LOCALE, "%s", "vsnprintf_l()");
- EXPECT_EQ(13, res);
-
- EXPECT_DEATH(snprintf_l(buff, 10,
- _LIBCPP_GET_C_LOCALE, "%s", "snprintf_l()"),
- "AddressSanitizer: stack-buffer-overflow");
- EXPECT_DEATH(vsnprintf_l_wrapper(buff, 10,
- _LIBCPP_GET_C_LOCALE, "%s", "vsnprintf_l()"),
- "AddressSanitizer: stack-buffer-overflow");
-}
-#endif
diff --git a/contrib/compiler-rt/lib/asan/tests/asan_test.ignore b/contrib/compiler-rt/lib/asan/tests/asan_test.ignore
deleted file mode 100644
index ea5c26099e75..000000000000
--- a/contrib/compiler-rt/lib/asan/tests/asan_test.ignore
+++ /dev/null
@@ -1,3 +0,0 @@
-# blacklisted functions for instrumented ASan unit test
-fun:*IgnoreTest*
-fun:*SomeOtherFunc*
diff --git a/contrib/compiler-rt/lib/asan/tests/asan_test_config.h b/contrib/compiler-rt/lib/asan/tests/asan_test_config.h
deleted file mode 100644
index 92f276307481..000000000000
--- a/contrib/compiler-rt/lib/asan/tests/asan_test_config.h
+++ /dev/null
@@ -1,54 +0,0 @@
-//===-- asan_test_config.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 AddressSanitizer, an address sanity checker.
-//
-//===----------------------------------------------------------------------===//
-#if !defined(INCLUDED_FROM_ASAN_TEST_UTILS_H)
-# error "This file should be included into asan_test_utils.h only"
-#endif
-
-#ifndef ASAN_TEST_CONFIG_H
-#define ASAN_TEST_CONFIG_H
-
-#include <vector>
-#include <string>
-#include <map>
-
-using std::string;
-using std::vector;
-using std::map;
-
-#ifndef ASAN_UAR
-# error "please define ASAN_UAR"
-#endif
-
-#ifndef ASAN_HAS_EXCEPTIONS
-# error "please define ASAN_HAS_EXCEPTIONS"
-#endif
-
-#ifndef ASAN_HAS_BLACKLIST
-# error "please define ASAN_HAS_BLACKLIST"
-#endif
-
-#ifndef ASAN_NEEDS_SEGV
-# if defined(_WIN32)
-# define ASAN_NEEDS_SEGV 0
-# else
-# define ASAN_NEEDS_SEGV 1
-# endif
-#endif
-
-#ifndef ASAN_AVOID_EXPENSIVE_TESTS
-# define ASAN_AVOID_EXPENSIVE_TESTS 0
-#endif
-
-#define ASAN_PCRE_DOTALL ""
-
-#endif // ASAN_TEST_CONFIG_H
diff --git a/contrib/compiler-rt/lib/asan/tests/asan_test_main.cc b/contrib/compiler-rt/lib/asan/tests/asan_test_main.cc
deleted file mode 100644
index 1746c5f4837b..000000000000
--- a/contrib/compiler-rt/lib/asan/tests/asan_test_main.cc
+++ /dev/null
@@ -1,19 +0,0 @@
-//===-- asan_test_main.cc -------------------------------------------------===//
-//
-// 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 AddressSanitizer, an address sanity checker.
-//
-//===----------------------------------------------------------------------===//
-#include "asan_test_utils.h"
-
-int main(int argc, char **argv) {
- testing::GTEST_FLAG(death_test_style) = "threadsafe";
- testing::InitGoogleTest(&argc, argv);
- return RUN_ALL_TESTS();
-}
diff --git a/contrib/compiler-rt/lib/asan/tests/asan_test_utils.h b/contrib/compiler-rt/lib/asan/tests/asan_test_utils.h
deleted file mode 100644
index 03d17cfb26a7..000000000000
--- a/contrib/compiler-rt/lib/asan/tests/asan_test_utils.h
+++ /dev/null
@@ -1,107 +0,0 @@
-//===-- asan_test_utils.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 AddressSanitizer, an address sanity checker.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef ASAN_TEST_UTILS_H
-#define ASAN_TEST_UTILS_H
-
-#if !defined(SANITIZER_EXTERNAL_TEST_CONFIG)
-# define INCLUDED_FROM_ASAN_TEST_UTILS_H
-# include "asan_test_config.h"
-# undef INCLUDED_FROM_ASAN_TEST_UTILS_H
-#endif
-
-#include "sanitizer_test_utils.h"
-#include "sanitizer_pthread_wrappers.h"
-
-#include <stdio.h>
-#include <signal.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdint.h>
-#include <assert.h>
-#include <algorithm>
-
-#if !defined(_WIN32)
-# include <strings.h>
-# include <sys/mman.h>
-# include <setjmp.h>
-#endif
-
-#ifdef __linux__
-# include <sys/prctl.h>
-# include <sys/types.h>
-# include <sys/stat.h>
-# include <fcntl.h>
-#include <unistd.h>
-#endif
-
-#if !defined(__APPLE__) && !defined(__FreeBSD__)
-#include <malloc.h>
-#endif
-
-#if ASAN_HAS_EXCEPTIONS
-# define ASAN_THROW(x) throw (x)
-#else
-# define ASAN_THROW(x)
-#endif
-
-typedef uint8_t U1;
-typedef uint16_t U2;
-typedef uint32_t U4;
-typedef uint64_t U8;
-
-static const int kPageSize = 4096;
-
-const size_t kLargeMalloc = 1 << 24;
-
-extern void free_aaa(void *p);
-extern void *malloc_aaa(size_t size);
-
-template<typename T>
-NOINLINE void asan_write(T *a) {
- *a = 0;
-}
-
-string RightOOBErrorMessage(int oob_distance, bool is_write);
-string RightOOBWriteMessage(int oob_distance);
-string RightOOBReadMessage(int oob_distance);
-string LeftOOBErrorMessage(int oob_distance, bool is_write);
-string LeftOOBWriteMessage(int oob_distance);
-string LeftOOBReadMessage(int oob_distance);
-string LeftOOBAccessMessage(int oob_distance);
-char* MallocAndMemsetString(size_t size, char ch);
-char* MallocAndMemsetString(size_t size);
-
-extern char glob1[1];
-extern char glob2[2];
-extern char glob3[3];
-extern char glob4[4];
-extern char glob5[5];
-extern char glob6[6];
-extern char glob7[7];
-extern char glob8[8];
-extern char glob9[9];
-extern char glob10[10];
-extern char glob11[11];
-extern char glob12[12];
-extern char glob13[13];
-extern char glob14[14];
-extern char glob15[15];
-extern char glob16[16];
-extern char glob17[17];
-extern char glob1000[1000];
-extern char glob10000[10000];
-extern char glob100000[100000];
-extern int GlobalsTest(int x);
-
-#endif // ASAN_TEST_UTILS_H
diff --git a/contrib/compiler-rt/lib/builtins/README.txt b/contrib/compiler-rt/lib/builtins/README.txt
index 1c08e7415e64..ad36e4e5279a 100644
--- a/contrib/compiler-rt/lib/builtins/README.txt
+++ b/contrib/compiler-rt/lib/builtins/README.txt
@@ -220,7 +220,9 @@ _Unwind_Reason_Code __gcc_personality_v0(int version, _Unwind_Action actions,
// for use with some implementations of assert() in <assert.h>
void __eprintf(const char* format, const char* assertion_expression,
const char* line, const char* file);
-
+
+// for systems with emulated thread local storage
+void* __emutls_get_address(struct __emutls_control*);
// Power PC specific functions
diff --git a/contrib/compiler-rt/lib/builtins/arm/aeabi_cdcmp.S b/contrib/compiler-rt/lib/builtins/arm/aeabi_cdcmp.S
new file mode 100644
index 000000000000..036a6f542f79
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/arm/aeabi_cdcmp.S
@@ -0,0 +1,96 @@
+//===-- aeabi_cdcmp.S - EABI cdcmp* implementation ------------------------===//
+//
+// 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.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+#if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__
+#error big endian support not implemented
+#endif
+
+#define APSR_Z (1 << 30)
+#define APSR_C (1 << 29)
+
+// void __aeabi_cdcmpeq(double a, double b) {
+// if (isnan(a) || isnan(b)) {
+// Z = 0; C = 1;
+// } else {
+// __aeabi_cdcmple(a, b);
+// }
+// }
+
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__aeabi_cdcmpeq)
+ push {r0-r3, lr}
+ bl __aeabi_cdcmpeq_check_nan
+ cmp r0, #1
+ pop {r0-r3, lr}
+
+ // NaN has been ruled out, so __aeabi_cdcmple can't trap
+ bne __aeabi_cdcmple
+
+ msr CPSR_f, #APSR_C
+ JMP(lr)
+END_COMPILERRT_FUNCTION(__aeabi_cdcmpeq)
+
+
+// void __aeabi_cdcmple(double a, double b) {
+// if (__aeabi_dcmplt(a, b)) {
+// Z = 0; C = 0;
+// } else if (__aeabi_dcmpeq(a, b)) {
+// Z = 1; C = 1;
+// } else {
+// Z = 0; C = 1;
+// }
+// }
+
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__aeabi_cdcmple)
+ // Per the RTABI, this function must preserve r0-r11.
+ // Save lr in the same instruction for compactness
+ push {r0-r3, lr}
+
+ bl __aeabi_dcmplt
+ cmp r0, #1
+ moveq ip, #0
+ beq 1f
+
+ ldm sp, {r0-r3}
+ bl __aeabi_dcmpeq
+ cmp r0, #1
+ moveq ip, #(APSR_C | APSR_Z)
+ movne ip, #(APSR_C)
+
+1:
+ msr CPSR_f, ip
+ pop {r0-r3}
+ POP_PC()
+END_COMPILERRT_FUNCTION(__aeabi_cdcmple)
+
+// int __aeabi_cdrcmple(double a, double b) {
+// return __aeabi_cdcmple(b, a);
+// }
+
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__aeabi_cdrcmple)
+ // Swap r0 and r2
+ mov ip, r0
+ mov r0, r2
+ mov r2, ip
+
+ // Swap r1 and r3
+ mov ip, r1
+ mov r1, r3
+ mov r3, ip
+
+ b __aeabi_cdcmple
+END_COMPILERRT_FUNCTION(__aeabi_cdrcmple)
+
diff --git a/contrib/compiler-rt/lib/builtins/arm/aeabi_cdcmpeq_check_nan.c b/contrib/compiler-rt/lib/builtins/arm/aeabi_cdcmpeq_check_nan.c
new file mode 100644
index 000000000000..577f6b2c5535
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/arm/aeabi_cdcmpeq_check_nan.c
@@ -0,0 +1,16 @@
+//===-- lib/arm/aeabi_cdcmpeq_helper.c - Helper for cdcmpeq ---------------===//
+//
+// 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.
+//
+//===----------------------------------------------------------------------===//
+
+#include <stdint.h>
+
+__attribute__((pcs("aapcs")))
+__attribute__((visibility("hidden")))
+int __aeabi_cdcmpeq_check_nan(double a, double b) {
+ return __builtin_isnan(a) || __builtin_isnan(b);
+}
diff --git a/contrib/compiler-rt/lib/builtins/arm/aeabi_cfcmp.S b/contrib/compiler-rt/lib/builtins/arm/aeabi_cfcmp.S
new file mode 100644
index 000000000000..43594e5c3936
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/arm/aeabi_cfcmp.S
@@ -0,0 +1,91 @@
+//===-- aeabi_cfcmp.S - EABI cfcmp* implementation ------------------------===//
+//
+// 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.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+#if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__
+#error big endian support not implemented
+#endif
+
+#define APSR_Z (1 << 30)
+#define APSR_C (1 << 29)
+
+// void __aeabi_cfcmpeq(float a, float b) {
+// if (isnan(a) || isnan(b)) {
+// Z = 0; C = 1;
+// } else {
+// __aeabi_cfcmple(a, b);
+// }
+// }
+
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__aeabi_cfcmpeq)
+ push {r0-r3, lr}
+ bl __aeabi_cfcmpeq_check_nan
+ cmp r0, #1
+ pop {r0-r3, lr}
+
+ // NaN has been ruled out, so __aeabi_cfcmple can't trap
+ bne __aeabi_cfcmple
+
+ msr CPSR_f, #APSR_C
+ JMP(lr)
+END_COMPILERRT_FUNCTION(__aeabi_cfcmpeq)
+
+
+// void __aeabi_cfcmple(float a, float b) {
+// if (__aeabi_fcmplt(a, b)) {
+// Z = 0; C = 0;
+// } else if (__aeabi_fcmpeq(a, b)) {
+// Z = 1; C = 1;
+// } else {
+// Z = 0; C = 1;
+// }
+// }
+
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__aeabi_cfcmple)
+ // Per the RTABI, this function must preserve r0-r11.
+ // Save lr in the same instruction for compactness
+ push {r0-r3, lr}
+
+ bl __aeabi_fcmplt
+ cmp r0, #1
+ moveq ip, #0
+ beq 1f
+
+ ldm sp, {r0-r3}
+ bl __aeabi_fcmpeq
+ cmp r0, #1
+ moveq ip, #(APSR_C | APSR_Z)
+ movne ip, #(APSR_C)
+
+1:
+ msr CPSR_f, ip
+ pop {r0-r3}
+ POP_PC()
+END_COMPILERRT_FUNCTION(__aeabi_cfcmple)
+
+// int __aeabi_cfrcmple(float a, float b) {
+// return __aeabi_cfcmple(b, a);
+// }
+
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__aeabi_cfrcmple)
+ // Swap r0 and r1
+ mov ip, r0
+ mov r0, r1
+ mov r1, ip
+
+ b __aeabi_cfcmple
+END_COMPILERRT_FUNCTION(__aeabi_cfrcmple)
+
diff --git a/contrib/compiler-rt/lib/builtins/arm/aeabi_cfcmpeq_check_nan.c b/contrib/compiler-rt/lib/builtins/arm/aeabi_cfcmpeq_check_nan.c
new file mode 100644
index 000000000000..992e31fbd8d6
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/arm/aeabi_cfcmpeq_check_nan.c
@@ -0,0 +1,16 @@
+//===-- lib/arm/aeabi_cfcmpeq_helper.c - Helper for cdcmpeq ---------------===//
+//
+// 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.
+//
+//===----------------------------------------------------------------------===//
+
+#include <stdint.h>
+
+__attribute__((pcs("aapcs")))
+__attribute__((visibility("hidden")))
+int __aeabi_cfcmpeq_check_nan(float a, float b) {
+ return __builtin_isnan(a) || __builtin_isnan(b);
+}
diff --git a/contrib/compiler-rt/lib/builtins/arm/aeabi_drsub.c b/contrib/compiler-rt/lib/builtins/arm/aeabi_drsub.c
new file mode 100644
index 000000000000..fc17d5a4cc76
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/arm/aeabi_drsub.c
@@ -0,0 +1,19 @@
+//===-- lib/arm/aeabi_drsub.c - Double-precision subtraction --------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#define DOUBLE_PRECISION
+#include "../fp_lib.h"
+
+COMPILER_RT_ABI fp_t
+__aeabi_dsub(fp_t, fp_t);
+
+COMPILER_RT_ABI fp_t
+__aeabi_drsub(fp_t a, fp_t b) {
+ return __aeabi_dsub(b, a);
+}
diff --git a/contrib/compiler-rt/lib/builtins/arm/aeabi_frsub.c b/contrib/compiler-rt/lib/builtins/arm/aeabi_frsub.c
new file mode 100644
index 000000000000..64258dc7e070
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/arm/aeabi_frsub.c
@@ -0,0 +1,19 @@
+//===-- lib/arm/aeabi_frsub.c - Single-precision subtraction --------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#define SINGLE_PRECISION
+#include "../fp_lib.h"
+
+COMPILER_RT_ABI fp_t
+__aeabi_fsub(fp_t, fp_t);
+
+COMPILER_RT_ABI fp_t
+__aeabi_frsub(fp_t a, fp_t b) {
+ return __aeabi_fsub(b, a);
+}
diff --git a/contrib/compiler-rt/lib/builtins/assembly.h b/contrib/compiler-rt/lib/builtins/assembly.h
index 8bb0ddc106bd..c28970534cc4 100644
--- a/contrib/compiler-rt/lib/builtins/assembly.h
+++ b/contrib/compiler-rt/lib/builtins/assembly.h
@@ -73,6 +73,15 @@
#define JMPc(r, c) mov##c pc, r
#endif
+// pop {pc} can't switch Thumb mode on ARMv4T
+#if __ARM_ARCH >= 5
+#define POP_PC() pop {pc}
+#else
+#define POP_PC() \
+ pop {ip}; \
+ JMP(ip)
+#endif
+
#if __ARM_ARCH_ISA_THUMB == 2
#define IT(cond) it cond
#define ITT(cond) itt cond
diff --git a/contrib/compiler-rt/lib/builtins/atomic.c b/contrib/compiler-rt/lib/builtins/atomic.c
index 35c8837dcecf..f1ddc3e0c522 100644
--- a/contrib/compiler-rt/lib/builtins/atomic.c
+++ b/contrib/compiler-rt/lib/builtins/atomic.c
@@ -56,13 +56,13 @@ static const long SPINLOCK_MASK = SPINLOCK_COUNT - 1;
#include <machine/atomic.h>
#include <sys/umtx.h>
typedef struct _usem Lock;
-inline static void unlock(Lock *l) {
+__inline static void unlock(Lock *l) {
__c11_atomic_store((_Atomic(uint32_t)*)&l->_count, 1, __ATOMIC_RELEASE);
__c11_atomic_thread_fence(__ATOMIC_SEQ_CST);
if (l->_has_waiters)
_umtx_op(l, UMTX_OP_SEM_WAKE, 1, 0, 0);
}
-inline static void lock(Lock *l) {
+__inline static void lock(Lock *l) {
uint32_t old = 1;
while (!__c11_atomic_compare_exchange_weak((_Atomic(uint32_t)*)&l->_count, &old,
0, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) {
@@ -76,12 +76,12 @@ static Lock locks[SPINLOCK_COUNT] = { [0 ... SPINLOCK_COUNT-1] = {0,1,0} };
#elif defined(__APPLE__)
#include <libkern/OSAtomic.h>
typedef OSSpinLock Lock;
-inline static void unlock(Lock *l) {
+__inline static void unlock(Lock *l) {
OSSpinLockUnlock(l);
}
/// Locks a lock. In the current implementation, this is potentially
/// unbounded in the contended case.
-inline static void lock(Lock *l) {
+__inline static void lock(Lock *l) {
OSSpinLockLock(l);
}
static Lock locks[SPINLOCK_COUNT]; // initialized to OS_SPINLOCK_INIT which is 0
@@ -89,12 +89,12 @@ static Lock locks[SPINLOCK_COUNT]; // initialized to OS_SPINLOCK_INIT which is 0
#else
typedef _Atomic(uintptr_t) Lock;
/// Unlock a lock. This is a release operation.
-inline static void unlock(Lock *l) {
+__inline static void unlock(Lock *l) {
__c11_atomic_store(l, 0, __ATOMIC_RELEASE);
}
/// Locks a lock. In the current implementation, this is potentially
/// unbounded in the contended case.
-inline static void lock(Lock *l) {
+__inline static void lock(Lock *l) {
uintptr_t old = 0;
while (!__c11_atomic_compare_exchange_weak(l, &old, 1, __ATOMIC_ACQUIRE,
__ATOMIC_RELAXED))
@@ -106,7 +106,7 @@ static Lock locks[SPINLOCK_COUNT];
/// Returns a lock to use for a given pointer.
-static inline Lock *lock_for_pointer(void *ptr) {
+static __inline Lock *lock_for_pointer(void *ptr) {
intptr_t hash = (intptr_t)ptr;
// Disregard the lowest 4 bits. We want all values that may be part of the
// same memory operation to hash to the same value and therefore use the same
diff --git a/contrib/compiler-rt/lib/builtins/atomic_flag_clear.c b/contrib/compiler-rt/lib/builtins/atomic_flag_clear.c
index 15984cd5267d..da912af64312 100644
--- a/contrib/compiler-rt/lib/builtins/atomic_flag_clear.c
+++ b/contrib/compiler-rt/lib/builtins/atomic_flag_clear.c
@@ -12,8 +12,16 @@
*===------------------------------------------------------------------------===
*/
+#ifndef __has_include
+#define __has_include(inc) 0
+#endif
+
+#if __has_include(<stdatomic.h>)
+
#include <stdatomic.h>
#undef atomic_flag_clear
void atomic_flag_clear(volatile atomic_flag *object) {
- return __c11_atomic_store(&(object)->_Value, 0, __ATOMIC_SEQ_CST);
+ __c11_atomic_store(&(object)->_Value, 0, __ATOMIC_SEQ_CST);
}
+
+#endif
diff --git a/contrib/compiler-rt/lib/builtins/atomic_flag_clear_explicit.c b/contrib/compiler-rt/lib/builtins/atomic_flag_clear_explicit.c
index 0f7859c2cd82..1059b787f169 100644
--- a/contrib/compiler-rt/lib/builtins/atomic_flag_clear_explicit.c
+++ b/contrib/compiler-rt/lib/builtins/atomic_flag_clear_explicit.c
@@ -12,9 +12,17 @@
*===------------------------------------------------------------------------===
*/
+#ifndef __has_include
+#define __has_include(inc) 0
+#endif
+
+#if __has_include(<stdatomic.h>)
+
#include <stdatomic.h>
#undef atomic_flag_clear_explicit
void atomic_flag_clear_explicit(volatile atomic_flag *object,
memory_order order) {
- return __c11_atomic_store(&(object)->_Value, 0, order);
+ __c11_atomic_store(&(object)->_Value, 0, order);
}
+
+#endif
diff --git a/contrib/compiler-rt/lib/builtins/atomic_flag_test_and_set.c b/contrib/compiler-rt/lib/builtins/atomic_flag_test_and_set.c
index 07209fc02d5e..e8811d39ef25 100644
--- a/contrib/compiler-rt/lib/builtins/atomic_flag_test_and_set.c
+++ b/contrib/compiler-rt/lib/builtins/atomic_flag_test_and_set.c
@@ -12,8 +12,16 @@
*===------------------------------------------------------------------------===
*/
+#ifndef __has_include
+#define __has_include(inc) 0
+#endif
+
+#if __has_include(<stdatomic.h>)
+
#include <stdatomic.h>
#undef atomic_flag_test_and_set
_Bool atomic_flag_test_and_set(volatile atomic_flag *object) {
return __c11_atomic_exchange(&(object)->_Value, 1, __ATOMIC_SEQ_CST);
}
+
+#endif
diff --git a/contrib/compiler-rt/lib/builtins/atomic_flag_test_and_set_explicit.c b/contrib/compiler-rt/lib/builtins/atomic_flag_test_and_set_explicit.c
index eaa5be08df46..5c8c2df90543 100644
--- a/contrib/compiler-rt/lib/builtins/atomic_flag_test_and_set_explicit.c
+++ b/contrib/compiler-rt/lib/builtins/atomic_flag_test_and_set_explicit.c
@@ -12,9 +12,17 @@
*===------------------------------------------------------------------------===
*/
+#ifndef __has_include
+#define __has_include(inc) 0
+#endif
+
+#if __has_include(<stdatomic.h>)
+
#include <stdatomic.h>
#undef atomic_flag_test_and_set_explicit
_Bool atomic_flag_test_and_set_explicit(volatile atomic_flag *object,
memory_order order) {
return __c11_atomic_exchange(&(object)->_Value, 1, order);
}
+
+#endif
diff --git a/contrib/compiler-rt/lib/builtins/atomic_signal_fence.c b/contrib/compiler-rt/lib/builtins/atomic_signal_fence.c
index ad292d2f1c72..9ccc2ae60ad8 100644
--- a/contrib/compiler-rt/lib/builtins/atomic_signal_fence.c
+++ b/contrib/compiler-rt/lib/builtins/atomic_signal_fence.c
@@ -12,8 +12,16 @@
*===------------------------------------------------------------------------===
*/
+#ifndef __has_include
+#define __has_include(inc) 0
+#endif
+
+#if __has_include(<stdatomic.h>)
+
#include <stdatomic.h>
#undef atomic_signal_fence
void atomic_signal_fence(memory_order order) {
__c11_atomic_signal_fence(order);
}
+
+#endif
diff --git a/contrib/compiler-rt/lib/builtins/atomic_thread_fence.c b/contrib/compiler-rt/lib/builtins/atomic_thread_fence.c
index 71f698c9de75..d22560151bc8 100644
--- a/contrib/compiler-rt/lib/builtins/atomic_thread_fence.c
+++ b/contrib/compiler-rt/lib/builtins/atomic_thread_fence.c
@@ -12,8 +12,16 @@
*===------------------------------------------------------------------------===
*/
+#ifndef __has_include
+#define __has_include(inc) 0
+#endif
+
+#if __has_include(<stdatomic.h>)
+
#include <stdatomic.h>
#undef atomic_thread_fence
void atomic_thread_fence(memory_order order) {
__c11_atomic_thread_fence(order);
}
+
+#endif
diff --git a/contrib/compiler-rt/lib/builtins/comparedf2.c b/contrib/compiler-rt/lib/builtins/comparedf2.c
index 64eea1249055..9e29752231e9 100644
--- a/contrib/compiler-rt/lib/builtins/comparedf2.c
+++ b/contrib/compiler-rt/lib/builtins/comparedf2.c
@@ -80,6 +80,11 @@ __ledf2(fp_t a, fp_t b) {
}
}
+#if defined(__ELF__)
+// Alias for libgcc compatibility
+FNALIAS(__cmpdf2, __ledf2);
+#endif
+
enum GE_RESULT {
GE_LESS = -1,
GE_EQUAL = 0,
diff --git a/contrib/compiler-rt/lib/builtins/comparesf2.c b/contrib/compiler-rt/lib/builtins/comparesf2.c
index 442289c1004e..1fd50636abaf 100644
--- a/contrib/compiler-rt/lib/builtins/comparesf2.c
+++ b/contrib/compiler-rt/lib/builtins/comparesf2.c
@@ -80,6 +80,11 @@ __lesf2(fp_t a, fp_t b) {
}
}
+#if defined(__ELF__)
+// Alias for libgcc compatibility
+FNALIAS(__cmpsf2, __lesf2);
+#endif
+
enum GE_RESULT {
GE_LESS = -1,
GE_EQUAL = 0,
diff --git a/contrib/compiler-rt/lib/builtins/comparetf2.c b/contrib/compiler-rt/lib/builtins/comparetf2.c
index a6436de89e76..c0ad8ed0aecd 100644
--- a/contrib/compiler-rt/lib/builtins/comparetf2.c
+++ b/contrib/compiler-rt/lib/builtins/comparetf2.c
@@ -79,6 +79,11 @@ COMPILER_RT_ABI enum LE_RESULT __letf2(fp_t a, fp_t b) {
}
}
+#if defined(__ELF__)
+// Alias for libgcc compatibility
+FNALIAS(__cmptf2, __letf2);
+#endif
+
enum GE_RESULT {
GE_LESS = -1,
GE_EQUAL = 0,
diff --git a/contrib/compiler-rt/lib/builtins/divdc3.c b/contrib/compiler-rt/lib/builtins/divdc3.c
index 7de78c8711e1..3c88390b5e77 100644
--- a/contrib/compiler-rt/lib/builtins/divdc3.c
+++ b/contrib/compiler-rt/lib/builtins/divdc3.c
@@ -17,7 +17,7 @@
/* Returns: the quotient of (a + ib) / (c + id) */
-COMPILER_RT_ABI double _Complex
+COMPILER_RT_ABI Dcomplex
__divdc3(double __a, double __b, double __c, double __d)
{
int __ilogbw = 0;
@@ -29,31 +29,31 @@ __divdc3(double __a, double __b, double __c, double __d)
__d = crt_scalbn(__d, -__ilogbw);
}
double __denom = __c * __c + __d * __d;
- double _Complex z;
- __real__ z = crt_scalbn((__a * __c + __b * __d) / __denom, -__ilogbw);
- __imag__ z = crt_scalbn((__b * __c - __a * __d) / __denom, -__ilogbw);
- if (crt_isnan(__real__ z) && crt_isnan(__imag__ z))
+ Dcomplex z;
+ COMPLEX_REAL(z) = crt_scalbn((__a * __c + __b * __d) / __denom, -__ilogbw);
+ COMPLEX_IMAGINARY(z) = crt_scalbn((__b * __c - __a * __d) / __denom, -__ilogbw);
+ if (crt_isnan(COMPLEX_REAL(z)) && crt_isnan(COMPLEX_IMAGINARY(z)))
{
if ((__denom == 0.0) && (!crt_isnan(__a) || !crt_isnan(__b)))
{
- __real__ z = crt_copysign(CRT_INFINITY, __c) * __a;
- __imag__ z = crt_copysign(CRT_INFINITY, __c) * __b;
+ COMPLEX_REAL(z) = crt_copysign(CRT_INFINITY, __c) * __a;
+ COMPLEX_IMAGINARY(z) = crt_copysign(CRT_INFINITY, __c) * __b;
}
else if ((crt_isinf(__a) || crt_isinf(__b)) &&
crt_isfinite(__c) && crt_isfinite(__d))
{
__a = crt_copysign(crt_isinf(__a) ? 1.0 : 0.0, __a);
__b = crt_copysign(crt_isinf(__b) ? 1.0 : 0.0, __b);
- __real__ z = CRT_INFINITY * (__a * __c + __b * __d);
- __imag__ z = CRT_INFINITY * (__b * __c - __a * __d);
+ COMPLEX_REAL(z) = CRT_INFINITY * (__a * __c + __b * __d);
+ COMPLEX_IMAGINARY(z) = CRT_INFINITY * (__b * __c - __a * __d);
}
else if (crt_isinf(__logbw) && __logbw > 0.0 &&
crt_isfinite(__a) && crt_isfinite(__b))
{
__c = crt_copysign(crt_isinf(__c) ? 1.0 : 0.0, __c);
__d = crt_copysign(crt_isinf(__d) ? 1.0 : 0.0, __d);
- __real__ z = 0.0 * (__a * __c + __b * __d);
- __imag__ z = 0.0 * (__b * __c - __a * __d);
+ COMPLEX_REAL(z) = 0.0 * (__a * __c + __b * __d);
+ COMPLEX_IMAGINARY(z) = 0.0 * (__b * __c - __a * __d);
}
}
return z;
diff --git a/contrib/compiler-rt/lib/builtins/divsc3.c b/contrib/compiler-rt/lib/builtins/divsc3.c
index 710d5320803f..42a48315e66d 100644
--- a/contrib/compiler-rt/lib/builtins/divsc3.c
+++ b/contrib/compiler-rt/lib/builtins/divsc3.c
@@ -17,7 +17,7 @@
/* Returns: the quotient of (a + ib) / (c + id) */
-COMPILER_RT_ABI float _Complex
+COMPILER_RT_ABI Fcomplex
__divsc3(float __a, float __b, float __c, float __d)
{
int __ilogbw = 0;
@@ -29,31 +29,31 @@ __divsc3(float __a, float __b, float __c, float __d)
__d = crt_scalbnf(__d, -__ilogbw);
}
float __denom = __c * __c + __d * __d;
- float _Complex z;
- __real__ z = crt_scalbnf((__a * __c + __b * __d) / __denom, -__ilogbw);
- __imag__ z = crt_scalbnf((__b * __c - __a * __d) / __denom, -__ilogbw);
- if (crt_isnan(__real__ z) && crt_isnan(__imag__ z))
+ Fcomplex z;
+ COMPLEX_REAL(z) = crt_scalbnf((__a * __c + __b * __d) / __denom, -__ilogbw);
+ COMPLEX_IMAGINARY(z) = crt_scalbnf((__b * __c - __a * __d) / __denom, -__ilogbw);
+ if (crt_isnan(COMPLEX_REAL(z)) && crt_isnan(COMPLEX_IMAGINARY(z)))
{
if ((__denom == 0) && (!crt_isnan(__a) || !crt_isnan(__b)))
{
- __real__ z = crt_copysignf(CRT_INFINITY, __c) * __a;
- __imag__ z = crt_copysignf(CRT_INFINITY, __c) * __b;
+ COMPLEX_REAL(z) = crt_copysignf(CRT_INFINITY, __c) * __a;
+ COMPLEX_IMAGINARY(z) = crt_copysignf(CRT_INFINITY, __c) * __b;
}
else if ((crt_isinf(__a) || crt_isinf(__b)) &&
crt_isfinite(__c) && crt_isfinite(__d))
{
__a = crt_copysignf(crt_isinf(__a) ? 1 : 0, __a);
__b = crt_copysignf(crt_isinf(__b) ? 1 : 0, __b);
- __real__ z = CRT_INFINITY * (__a * __c + __b * __d);
- __imag__ z = CRT_INFINITY * (__b * __c - __a * __d);
+ COMPLEX_REAL(z) = CRT_INFINITY * (__a * __c + __b * __d);
+ COMPLEX_IMAGINARY(z) = CRT_INFINITY * (__b * __c - __a * __d);
}
else if (crt_isinf(__logbw) && __logbw > 0 &&
crt_isfinite(__a) && crt_isfinite(__b))
{
__c = crt_copysignf(crt_isinf(__c) ? 1 : 0, __c);
__d = crt_copysignf(crt_isinf(__d) ? 1 : 0, __d);
- __real__ z = 0 * (__a * __c + __b * __d);
- __imag__ z = 0 * (__b * __c - __a * __d);
+ COMPLEX_REAL(z) = 0 * (__a * __c + __b * __d);
+ COMPLEX_IMAGINARY(z) = 0 * (__b * __c - __a * __d);
}
}
return z;
diff --git a/contrib/compiler-rt/lib/builtins/divtc3.c b/contrib/compiler-rt/lib/builtins/divtc3.c
new file mode 100644
index 000000000000..04693df471ff
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/divtc3.c
@@ -0,0 +1,60 @@
+/*===-- divtc3.c - Implement __divtc3 -------------------------------------===
+ *
+ * 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 __divtc3 for the compiler_rt library.
+ *
+ *===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+#include "int_math.h"
+
+/* Returns: the quotient of (a + ib) / (c + id) */
+
+COMPILER_RT_ABI long double _Complex
+__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)));
+ if (crt_isfinite(__logbw))
+ {
+ __ilogbw = (int)__logbw;
+ __c = crt_scalbnl(__c, -__ilogbw);
+ __d = crt_scalbnl(__d, -__ilogbw);
+ }
+ long double __denom = __c * __c + __d * __d;
+ long double _Complex z;
+ __real__ z = crt_scalbnl((__a * __c + __b * __d) / __denom, -__ilogbw);
+ __imag__ z = crt_scalbnl((__b * __c - __a * __d) / __denom, -__ilogbw);
+ if (crt_isnan(__real__ z) && crt_isnan(__imag__ z))
+ {
+ if ((__denom == 0.0) && (!crt_isnan(__a) || !crt_isnan(__b)))
+ {
+ __real__ z = crt_copysignl(CRT_INFINITY, __c) * __a;
+ __imag__ z = crt_copysignl(CRT_INFINITY, __c) * __b;
+ }
+ else if ((crt_isinf(__a) || crt_isinf(__b)) &&
+ crt_isfinite(__c) && crt_isfinite(__d))
+ {
+ __a = crt_copysignl(crt_isinf(__a) ? 1.0 : 0.0, __a);
+ __b = crt_copysignl(crt_isinf(__b) ? 1.0 : 0.0, __b);
+ __real__ z = CRT_INFINITY * (__a * __c + __b * __d);
+ __imag__ z = CRT_INFINITY * (__b * __c - __a * __d);
+ }
+ else if (crt_isinf(__logbw) && __logbw > 0.0 &&
+ crt_isfinite(__a) && crt_isfinite(__b))
+ {
+ __c = crt_copysignl(crt_isinf(__c) ? 1.0 : 0.0, __c);
+ __d = crt_copysignl(crt_isinf(__d) ? 1.0 : 0.0, __d);
+ __real__ z = 0.0 * (__a * __c + __b * __d);
+ __imag__ z = 0.0 * (__b * __c - __a * __d);
+ }
+ }
+ return z;
+}
diff --git a/contrib/compiler-rt/lib/builtins/divxc3.c b/contrib/compiler-rt/lib/builtins/divxc3.c
index 175ae3cf4aee..6f49280e5f61 100644
--- a/contrib/compiler-rt/lib/builtins/divxc3.c
+++ b/contrib/compiler-rt/lib/builtins/divxc3.c
@@ -18,7 +18,7 @@
/* Returns: the quotient of (a + ib) / (c + id) */
-COMPILER_RT_ABI long double _Complex
+COMPILER_RT_ABI Lcomplex
__divxc3(long double __a, long double __b, long double __c, long double __d)
{
int __ilogbw = 0;
@@ -30,31 +30,31 @@ __divxc3(long double __a, long double __b, long double __c, long double __d)
__d = crt_scalbnl(__d, -__ilogbw);
}
long double __denom = __c * __c + __d * __d;
- long double _Complex z;
- __real__ z = crt_scalbnl((__a * __c + __b * __d) / __denom, -__ilogbw);
- __imag__ z = crt_scalbnl((__b * __c - __a * __d) / __denom, -__ilogbw);
- if (crt_isnan(__real__ z) && crt_isnan(__imag__ z))
+ Lcomplex z;
+ COMPLEX_REAL(z) = crt_scalbnl((__a * __c + __b * __d) / __denom, -__ilogbw);
+ COMPLEX_IMAGINARY(z) = crt_scalbnl((__b * __c - __a * __d) / __denom, -__ilogbw);
+ if (crt_isnan(COMPLEX_REAL(z)) && crt_isnan(COMPLEX_IMAGINARY(z)))
{
if ((__denom == 0) && (!crt_isnan(__a) || !crt_isnan(__b)))
{
- __real__ z = crt_copysignl(CRT_INFINITY, __c) * __a;
- __imag__ z = crt_copysignl(CRT_INFINITY, __c) * __b;
+ COMPLEX_REAL(z) = crt_copysignl(CRT_INFINITY, __c) * __a;
+ COMPLEX_IMAGINARY(z) = crt_copysignl(CRT_INFINITY, __c) * __b;
}
else if ((crt_isinf(__a) || crt_isinf(__b)) &&
crt_isfinite(__c) && crt_isfinite(__d))
{
__a = crt_copysignl(crt_isinf(__a) ? 1 : 0, __a);
__b = crt_copysignl(crt_isinf(__b) ? 1 : 0, __b);
- __real__ z = CRT_INFINITY * (__a * __c + __b * __d);
- __imag__ z = CRT_INFINITY * (__b * __c - __a * __d);
+ COMPLEX_REAL(z) = CRT_INFINITY * (__a * __c + __b * __d);
+ COMPLEX_IMAGINARY(z) = CRT_INFINITY * (__b * __c - __a * __d);
}
else if (crt_isinf(__logbw) && __logbw > 0 &&
crt_isfinite(__a) && crt_isfinite(__b))
{
__c = crt_copysignl(crt_isinf(__c) ? 1 : 0, __c);
__d = crt_copysignl(crt_isinf(__d) ? 1 : 0, __d);
- __real__ z = 0 * (__a * __c + __b * __d);
- __imag__ z = 0 * (__b * __c - __a * __d);
+ COMPLEX_REAL(z) = 0 * (__a * __c + __b * __d);
+ COMPLEX_IMAGINARY(z) = 0 * (__b * __c - __a * __d);
}
}
return z;
diff --git a/contrib/compiler-rt/lib/builtins/emutls.c b/contrib/compiler-rt/lib/builtins/emutls.c
new file mode 100644
index 000000000000..09e79568bd56
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/emutls.c
@@ -0,0 +1,183 @@
+/* ===---------- emutls.c - Implements __emutls_get_address ---------------===
+ *
+ * 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.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+#include <pthread.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "int_lib.h"
+#include "int_util.h"
+
+/* Default is not to use posix_memalign, so systems like Android
+ * can use thread local data without heavier POSIX memory allocators.
+ */
+#ifndef EMUTLS_USE_POSIX_MEMALIGN
+#define EMUTLS_USE_POSIX_MEMALIGN 0
+#endif
+
+/* For every TLS variable xyz,
+ * there is one __emutls_control variable named __emutls_v.xyz.
+ * If xyz has non-zero initial value, __emutls_v.xyz's "value"
+ * will point to __emutls_t.xyz, which has the initial value.
+ */
+typedef struct __emutls_control {
+ size_t size; /* size of the object in bytes */
+ size_t align; /* alignment of the object in bytes */
+ union {
+ uintptr_t index; /* data[index-1] is the object address */
+ void* address; /* object address, when in single thread env */
+ } object;
+ void* value; /* null or non-zero initial value for the object */
+} __emutls_control;
+
+static __inline void *emutls_memalign_alloc(size_t align, size_t size) {
+ void *base;
+#if EMUTLS_USE_POSIX_MEMALIGN
+ if (posix_memalign(&base, align, size) != 0)
+ abort();
+#else
+ #define EXTRA_ALIGN_PTR_BYTES (align - 1 + sizeof(void*))
+ char* object;
+ if ((object = malloc(EXTRA_ALIGN_PTR_BYTES + size)) == NULL)
+ abort();
+ base = (void*)(((uintptr_t)(object + EXTRA_ALIGN_PTR_BYTES))
+ & ~(uintptr_t)(align - 1));
+
+ ((void**)base)[-1] = object;
+#endif
+ return base;
+}
+
+static __inline void emutls_memalign_free(void *base) {
+#if EMUTLS_USE_POSIX_MEMALIGN
+ free(base);
+#else
+ /* The mallocated address is in ((void**)base)[-1] */
+ free(((void**)base)[-1]);
+#endif
+}
+
+/* Emulated TLS objects are always allocated at run-time. */
+static __inline void *emutls_allocate_object(__emutls_control *control) {
+ /* Use standard C types, check with gcc's emutls.o. */
+ typedef unsigned int gcc_word __attribute__((mode(word)));
+ typedef unsigned int gcc_pointer __attribute__((mode(pointer)));
+ COMPILE_TIME_ASSERT(sizeof(size_t) == sizeof(gcc_word));
+ COMPILE_TIME_ASSERT(sizeof(uintptr_t) == sizeof(gcc_pointer));
+ COMPILE_TIME_ASSERT(sizeof(uintptr_t) == sizeof(void*));
+
+ size_t size = control->size;
+ size_t align = control->align;
+ if (align < sizeof(void*))
+ align = sizeof(void*);
+ /* Make sure that align is power of 2. */
+ if ((align & (align - 1)) != 0)
+ abort();
+
+ void* base = emutls_memalign_alloc(align, size);
+ if (control->value)
+ memcpy(base, control->value, size);
+ else
+ memset(base, 0, size);
+ return base;
+}
+
+static pthread_mutex_t emutls_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static size_t emutls_num_object = 0; /* number of allocated TLS objects */
+
+typedef struct emutls_address_array {
+ uintptr_t size; /* number of elements in the 'data' array */
+ void* data[];
+} emutls_address_array;
+
+static pthread_key_t emutls_pthread_key;
+
+static void emutls_key_destructor(void* ptr) {
+ emutls_address_array* array = (emutls_address_array*)ptr;
+ uintptr_t i;
+ for (i = 0; i < array->size; ++i) {
+ if (array->data[i])
+ emutls_memalign_free(array->data[i]);
+ }
+ free(ptr);
+}
+
+static void emutls_init(void) {
+ if (pthread_key_create(&emutls_pthread_key, emutls_key_destructor) != 0)
+ abort();
+}
+
+/* Returns control->object.index; set index if not allocated yet. */
+static __inline uintptr_t emutls_get_index(__emutls_control *control) {
+ uintptr_t index = __atomic_load_n(&control->object.index, __ATOMIC_ACQUIRE);
+ if (!index) {
+ static pthread_once_t once = PTHREAD_ONCE_INIT;
+ pthread_once(&once, emutls_init);
+ pthread_mutex_lock(&emutls_mutex);
+ index = control->object.index;
+ if (!index) {
+ index = ++emutls_num_object;
+ __atomic_store_n(&control->object.index, index, __ATOMIC_RELEASE);
+ }
+ pthread_mutex_unlock(&emutls_mutex);
+ }
+ return index;
+}
+
+/* Updates newly allocated thread local emutls_address_array. */
+static __inline void emutls_check_array_set_size(emutls_address_array *array,
+ uintptr_t size) {
+ if (array == NULL)
+ abort();
+ array->size = size;
+ pthread_setspecific(emutls_pthread_key, (void*)array);
+}
+
+/* Returns the new 'data' array size, number of elements,
+ * which must be no smaller than the given index.
+ */
+static __inline uintptr_t emutls_new_data_array_size(uintptr_t index) {
+ /* Need to allocate emutls_address_array with one extra slot
+ * to store the data array size.
+ * Round up the emutls_address_array size to multiple of 16.
+ */
+ return ((index + 1 + 15) & ~((uintptr_t)15)) - 1;
+}
+
+/* Returns the thread local emutls_address_array.
+ * Extends its size if necessary to hold address at index.
+ */
+static __inline emutls_address_array *
+emutls_get_address_array(uintptr_t index) {
+ emutls_address_array* array = pthread_getspecific(emutls_pthread_key);
+ if (array == NULL) {
+ uintptr_t new_size = emutls_new_data_array_size(index);
+ array = calloc(new_size + 1, sizeof(void*));
+ emutls_check_array_set_size(array, new_size);
+ } else if (index > array->size) {
+ uintptr_t orig_size = array->size;
+ uintptr_t new_size = emutls_new_data_array_size(index);
+ array = realloc(array, (new_size + 1) * sizeof(void*));
+ if (array)
+ memset(array->data + orig_size, 0,
+ (new_size - orig_size) * sizeof(void*));
+ emutls_check_array_set_size(array, new_size);
+ }
+ return array;
+}
+
+void* __emutls_get_address(__emutls_control* control) {
+ uintptr_t index = emutls_get_index(control);
+ emutls_address_array* array = emutls_get_address_array(index);
+ if (array->data[index - 1] == NULL)
+ array->data[index - 1] = emutls_allocate_object(control);
+ return array->data[index - 1];
+}
diff --git a/contrib/compiler-rt/lib/builtins/enable_execute_stack.c b/contrib/compiler-rt/lib/builtins/enable_execute_stack.c
index 23e494051adf..0dc3482c4467 100644
--- a/contrib/compiler-rt/lib/builtins/enable_execute_stack.c
+++ b/contrib/compiler-rt/lib/builtins/enable_execute_stack.c
@@ -21,8 +21,8 @@
#define HAVE_SYSCONF 1
#ifdef _WIN32
-#include <windef.h>
-#include <winbase.h>
+#define WIN32_LEAN_AND_MEAN
+#include <Windows.h>
#else
#ifndef __APPLE__
#include <unistd.h>
diff --git a/contrib/compiler-rt/lib/builtins/extendhfsf2.c b/contrib/compiler-rt/lib/builtins/extendhfsf2.c
index 7524e2ea7ed6..27115a48c184 100644
--- a/contrib/compiler-rt/lib/builtins/extendhfsf2.c
+++ b/contrib/compiler-rt/lib/builtins/extendhfsf2.c
@@ -12,9 +12,11 @@
#define DST_SINGLE
#include "fp_extend_impl.inc"
+ARM_EABI_FNALIAS(h2f, extendhfsf2)
+
// Use a forwarding definition and noinline to implement a poor man's alias,
// as there isn't a good cross-platform way of defining one.
-COMPILER_RT_ABI __attribute__((noinline)) float __extendhfsf2(uint16_t a) {
+COMPILER_RT_ABI NOINLINE float __extendhfsf2(uint16_t a) {
return __extendXfYf2__(a);
}
diff --git a/contrib/compiler-rt/lib/builtins/fixunsdfdi.c b/contrib/compiler-rt/lib/builtins/fixunsdfdi.c
index 2e0d87eacf05..4b0bc9e1d051 100644
--- a/contrib/compiler-rt/lib/builtins/fixunsdfdi.c
+++ b/contrib/compiler-rt/lib/builtins/fixunsdfdi.c
@@ -22,8 +22,8 @@ COMPILER_RT_ABI du_int
__fixunsdfdi(double a)
{
if (a <= 0.0) return 0;
- su_int high = a/0x1p32f;
- su_int low = a - (double)high*0x1p32f;
+ su_int high = a / 4294967296.f; /* a / 0x1p32f; */
+ su_int low = a - (double)high * 4294967296.f; /* high * 0x1p32f; */
return ((du_int)high << 32) | low;
}
diff --git a/contrib/compiler-rt/lib/builtins/fixunssfdi.c b/contrib/compiler-rt/lib/builtins/fixunssfdi.c
index 5a154e82cff4..f8ebab854f95 100644
--- a/contrib/compiler-rt/lib/builtins/fixunssfdi.c
+++ b/contrib/compiler-rt/lib/builtins/fixunssfdi.c
@@ -23,8 +23,8 @@ __fixunssfdi(float a)
{
if (a <= 0.0f) return 0;
double da = a;
- su_int high = da/0x1p32f;
- su_int low = da - (double)high*0x1p32f;
+ su_int high = da / 4294967296.f; /* da / 0x1p32f; */
+ su_int low = da - (double)high * 4294967296.f; /* high * 0x1p32f; */
return ((du_int)high << 32) | low;
}
diff --git a/contrib/compiler-rt/lib/builtins/floatdidf.c b/contrib/compiler-rt/lib/builtins/floatdidf.c
index e53fa2580f6e..a300c9f312d2 100644
--- a/contrib/compiler-rt/lib/builtins/floatdidf.c
+++ b/contrib/compiler-rt/lib/builtins/floatdidf.c
@@ -32,8 +32,8 @@ ARM_EABI_FNALIAS(l2d, floatdidf)
COMPILER_RT_ABI double
__floatdidf(di_int a)
{
- static const double twop52 = 0x1.0p52;
- static const double twop32 = 0x1.0p32;
+ static const double twop52 = 4503599627370496.0; // 0x1.0p52
+ static const double twop32 = 4294967296.0; // 0x1.0p32
union { int64_t x; double d; } low = { .d = twop52 };
diff --git a/contrib/compiler-rt/lib/builtins/floatditf.c b/contrib/compiler-rt/lib/builtins/floatditf.c
index 1a5f8e539470..cd51dd8aade4 100644
--- a/contrib/compiler-rt/lib/builtins/floatditf.c
+++ b/contrib/compiler-rt/lib/builtins/floatditf.c
@@ -27,19 +27,17 @@ COMPILER_RT_ABI fp_t __floatditf(di_int a) {
// All other cases begin by extracting the sign and absolute value of a
rep_t sign = 0;
- unsigned aAbs = (unsigned)a;
+ du_int aAbs = (du_int)a;
if (a < 0) {
sign = signBit;
- aAbs += 0x80000000;
+ aAbs = ~(du_int)a + 1U;
}
// Exponent of (fp_t)a is the width of abs(a).
- const int exponent = (aWidth - 1) - __builtin_clzll(a);
+ const int exponent = (aWidth - 1) - __builtin_clzll(aAbs);
rep_t result;
- // Shift a into the significand field and clear the implicit bit. Extra
- // cast to unsigned int is necessary to get the correct behavior for
- // the input INT_MIN.
+ // Shift a into the significand field, rounding if it is a right-shift
const int shift = significandBits - exponent;
result = (rep_t)aAbs << shift ^ implicitBit;
diff --git a/contrib/compiler-rt/lib/builtins/floatsitf.c b/contrib/compiler-rt/lib/builtins/floatsitf.c
index 85346933f81e..f0abca363b5e 100644
--- a/contrib/compiler-rt/lib/builtins/floatsitf.c
+++ b/contrib/compiler-rt/lib/builtins/floatsitf.c
@@ -30,16 +30,14 @@ COMPILER_RT_ABI fp_t __floatsitf(int a) {
unsigned aAbs = (unsigned)a;
if (a < 0) {
sign = signBit;
- aAbs += 0x80000000;
+ aAbs = ~(unsigned)a + 1U;
}
// Exponent of (fp_t)a is the width of abs(a).
- const int exponent = (aWidth - 1) - __builtin_clz(a);
+ const int exponent = (aWidth - 1) - __builtin_clz(aAbs);
rep_t result;
- // Shift a into the significand field and clear the implicit bit. Extra
- // cast to unsigned int is necessary to get the correct behavior for
- // the input INT_MIN.
+ // Shift a into the significand field and clear the implicit bit.
const int shift = significandBits - exponent;
result = (rep_t)aAbs << shift ^ implicitBit;
diff --git a/contrib/compiler-rt/lib/builtins/floatundidf.c b/contrib/compiler-rt/lib/builtins/floatundidf.c
index 73b8bac1c1a1..67aa86e5e5b8 100644
--- a/contrib/compiler-rt/lib/builtins/floatundidf.c
+++ b/contrib/compiler-rt/lib/builtins/floatundidf.c
@@ -32,9 +32,9 @@ ARM_EABI_FNALIAS(ul2d, floatundidf)
COMPILER_RT_ABI double
__floatundidf(du_int a)
{
- static const double twop52 = 0x1.0p52;
- static const double twop84 = 0x1.0p84;
- static const double twop84_plus_twop52 = 0x1.00000001p84;
+ static const double twop52 = 4503599627370496.0; // 0x1.0p52
+ static const double twop84 = 19342813113834066795298816.0; // 0x1.0p84
+ static const double twop84_plus_twop52 = 19342813118337666422669312.0; // 0x1.00000001p84
union { uint64_t x; double d; } high = { .d = twop84 };
union { uint64_t x; double d; } low = { .d = twop52 };
diff --git a/contrib/compiler-rt/lib/builtins/fp_add_impl.inc b/contrib/compiler-rt/lib/builtins/fp_add_impl.inc
index 5741889728cd..b47be1b648e6 100644
--- a/contrib/compiler-rt/lib/builtins/fp_add_impl.inc
+++ b/contrib/compiler-rt/lib/builtins/fp_add_impl.inc
@@ -14,7 +14,7 @@
#include "fp_lib.h"
-static inline fp_t __addXf3__(fp_t a, fp_t b) {
+static __inline fp_t __addXf3__(fp_t a, fp_t b) {
rep_t aRep = toRep(a);
rep_t bRep = toRep(b);
const rep_t aAbs = aRep & absMask;
diff --git a/contrib/compiler-rt/lib/builtins/fp_extend.h b/contrib/compiler-rt/lib/builtins/fp_extend.h
index 5c2b92310df1..6d95a0680709 100644
--- a/contrib/compiler-rt/lib/builtins/fp_extend.h
+++ b/contrib/compiler-rt/lib/builtins/fp_extend.h
@@ -28,7 +28,7 @@ typedef double src_t;
typedef uint64_t src_rep_t;
#define SRC_REP_C UINT64_C
static const int srcSigBits = 52;
-static inline int src_rep_t_clz(src_rep_t a) {
+static __inline int src_rep_t_clz(src_rep_t a) {
#if defined __LP64__
return __builtin_clzl(a);
#else
@@ -75,12 +75,12 @@ static const int dstSigBits = 112;
// End of specialization parameters. Two helper routines for conversion to and
// from the representation of floating-point data as integer values follow.
-static inline src_rep_t srcToRep(src_t x) {
+static __inline src_rep_t srcToRep(src_t x) {
const union { src_t f; src_rep_t i; } rep = {.f = x};
return rep.i;
}
-static inline dst_t dstFromRep(dst_rep_t x) {
+static __inline dst_t dstFromRep(dst_rep_t x) {
const union { dst_t f; dst_rep_t i; } rep = {.i = x};
return rep.f;
}
diff --git a/contrib/compiler-rt/lib/builtins/fp_extend_impl.inc b/contrib/compiler-rt/lib/builtins/fp_extend_impl.inc
index edcfa8d2329d..b785cc7687ad 100644
--- a/contrib/compiler-rt/lib/builtins/fp_extend_impl.inc
+++ b/contrib/compiler-rt/lib/builtins/fp_extend_impl.inc
@@ -38,7 +38,7 @@
#include "fp_extend.h"
-static inline dst_t __extendXfYf2__(src_t a) {
+static __inline dst_t __extendXfYf2__(src_t a) {
// Various constants whose values follow from the type parameters.
// Any reasonable optimizer will fold and propagate all of these.
const int srcBits = sizeof(src_t)*CHAR_BIT;
diff --git a/contrib/compiler-rt/lib/builtins/fp_fixint_impl.inc b/contrib/compiler-rt/lib/builtins/fp_fixint_impl.inc
index 035e87ca10e0..da70d4d39301 100644
--- a/contrib/compiler-rt/lib/builtins/fp_fixint_impl.inc
+++ b/contrib/compiler-rt/lib/builtins/fp_fixint_impl.inc
@@ -14,7 +14,7 @@
#include "fp_lib.h"
-static inline fixint_t __fixint(fp_t a) {
+static __inline fixint_t __fixint(fp_t a) {
const fixint_t fixint_max = (fixint_t)((~(fixuint_t)0) / 2);
const fixint_t fixint_min = -fixint_max - 1;
// Break a into sign, exponent, significand
diff --git a/contrib/compiler-rt/lib/builtins/fp_fixuint_impl.inc b/contrib/compiler-rt/lib/builtins/fp_fixuint_impl.inc
index 5fefab0e2d8a..d68ccf27a79c 100644
--- a/contrib/compiler-rt/lib/builtins/fp_fixuint_impl.inc
+++ b/contrib/compiler-rt/lib/builtins/fp_fixuint_impl.inc
@@ -14,7 +14,7 @@
#include "fp_lib.h"
-static inline fixuint_t __fixuint(fp_t a) {
+static __inline fixuint_t __fixuint(fp_t a) {
// Break a into sign, exponent, significand
const rep_t aRep = toRep(a);
const rep_t aAbs = aRep & absMask;
@@ -27,7 +27,7 @@ static inline fixuint_t __fixuint(fp_t a) {
return 0;
// If the value is too large for the integer type, saturate.
- if ((unsigned)exponent > sizeof(fixuint_t) * CHAR_BIT)
+ if ((unsigned)exponent >= sizeof(fixuint_t) * CHAR_BIT)
return ~(fixuint_t)0;
// If 0 <= exponent < significandBits, right shift to get the result.
diff --git a/contrib/compiler-rt/lib/builtins/fp_lib.h b/contrib/compiler-rt/lib/builtins/fp_lib.h
index faebb99ecd5e..223fb980aaed 100644
--- a/contrib/compiler-rt/lib/builtins/fp_lib.h
+++ b/contrib/compiler-rt/lib/builtins/fp_lib.h
@@ -46,12 +46,12 @@ typedef float fp_t;
#define REP_C UINT32_C
#define significandBits 23
-static inline int rep_clz(rep_t a) {
+static __inline int rep_clz(rep_t a) {
return __builtin_clz(a);
}
// 32x32 --> 64 bit multiply
-static inline void wideMultiply(rep_t a, rep_t b, rep_t *hi, rep_t *lo) {
+static __inline void wideMultiply(rep_t a, rep_t b, rep_t *hi, rep_t *lo) {
const uint64_t product = (uint64_t)a*b;
*hi = product >> 32;
*lo = product;
@@ -66,7 +66,7 @@ typedef double fp_t;
#define REP_C UINT64_C
#define significandBits 52
-static inline int rep_clz(rep_t a) {
+static __inline int rep_clz(rep_t a) {
#if defined __LP64__
return __builtin_clzl(a);
#else
@@ -83,7 +83,7 @@ static inline int rep_clz(rep_t a) {
// 64x64 -> 128 wide multiply for platforms that don't have such an operation;
// many 64-bit platforms have this operation, but they tend to have hardware
// floating-point, so we don't bother with a special case for them here.
-static inline void wideMultiply(rep_t a, rep_t b, rep_t *hi, rep_t *lo) {
+static __inline void wideMultiply(rep_t a, rep_t b, rep_t *hi, rep_t *lo) {
// Each of the component 32x32 -> 64 products
const uint64_t plolo = loWord(a) * loWord(b);
const uint64_t plohi = loWord(a) * hiWord(b);
@@ -112,7 +112,7 @@ typedef long double fp_t;
// 128-bit integer, we let the constant be casted to 128-bit integer
#define significandBits 112
-static inline int rep_clz(rep_t a) {
+static __inline int rep_clz(rep_t a) {
const union
{
__uint128_t ll;
@@ -148,7 +148,7 @@ static inline int rep_clz(rep_t a) {
// 128x128 -> 256 wide multiply for platforms that don't have such an operation;
// many 64-bit platforms have this operation, but they tend to have hardware
// floating-point, so we don't bother with a special case for them here.
-static inline void wideMultiply(rep_t a, rep_t b, rep_t *hi, rep_t *lo) {
+static __inline void wideMultiply(rep_t a, rep_t b, rep_t *hi, rep_t *lo) {
const uint64_t product11 = Word_1(a) * Word_1(b);
const uint64_t product12 = Word_1(a) * Word_2(b);
@@ -228,28 +228,28 @@ static inline void wideMultiply(rep_t a, rep_t b, rep_t *hi, rep_t *lo) {
#define quietBit (implicitBit >> 1)
#define qnanRep (exponentMask | quietBit)
-static inline rep_t toRep(fp_t x) {
+static __inline rep_t toRep(fp_t x) {
const union { fp_t f; rep_t i; } rep = {.f = x};
return rep.i;
}
-static inline fp_t fromRep(rep_t x) {
+static __inline fp_t fromRep(rep_t x) {
const union { fp_t f; rep_t i; } rep = {.i = x};
return rep.f;
}
-static inline int normalize(rep_t *significand) {
+static __inline int normalize(rep_t *significand) {
const int shift = rep_clz(*significand) - rep_clz(implicitBit);
*significand <<= shift;
return 1 - shift;
}
-static inline void wideLeftShift(rep_t *hi, rep_t *lo, int count) {
+static __inline void wideLeftShift(rep_t *hi, rep_t *lo, int count) {
*hi = *hi << count | *lo >> (typeWidth - count);
*lo = *lo << count;
}
-static inline void wideRightShiftWithSticky(rep_t *hi, rep_t *lo, unsigned int count) {
+static __inline void wideRightShiftWithSticky(rep_t *hi, rep_t *lo, unsigned int count) {
if (count < typeWidth) {
const bool sticky = *lo << (typeWidth - count);
*lo = *hi << (typeWidth - count) | *lo >> count | sticky;
diff --git a/contrib/compiler-rt/lib/builtins/fp_mul_impl.inc b/contrib/compiler-rt/lib/builtins/fp_mul_impl.inc
index ca8a0bb98b10..b34aa1b8f544 100644
--- a/contrib/compiler-rt/lib/builtins/fp_mul_impl.inc
+++ b/contrib/compiler-rt/lib/builtins/fp_mul_impl.inc
@@ -14,7 +14,7 @@
#include "fp_lib.h"
-static inline fp_t __mulXf3__(fp_t a, fp_t b) {
+static __inline fp_t __mulXf3__(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 productSign = (toRep(a) ^ toRep(b)) & signBit;
diff --git a/contrib/compiler-rt/lib/builtins/fp_trunc.h b/contrib/compiler-rt/lib/builtins/fp_trunc.h
index 373ba1b0411d..d5e79bb5b863 100644
--- a/contrib/compiler-rt/lib/builtins/fp_trunc.h
+++ b/contrib/compiler-rt/lib/builtins/fp_trunc.h
@@ -63,12 +63,12 @@ static const int dstSigBits = 10;
// End of specialization parameters. Two helper routines for conversion to and
// from the representation of floating-point data as integer values follow.
-static inline src_rep_t srcToRep(src_t x) {
+static __inline src_rep_t srcToRep(src_t x) {
const union { src_t f; src_rep_t i; } rep = {.f = x};
return rep.i;
}
-static inline dst_t dstFromRep(dst_rep_t x) {
+static __inline dst_t dstFromRep(dst_rep_t x) {
const union { dst_t f; dst_rep_t i; } rep = {.i = x};
return rep.f;
}
diff --git a/contrib/compiler-rt/lib/builtins/fp_trunc_impl.inc b/contrib/compiler-rt/lib/builtins/fp_trunc_impl.inc
index 372e8d6014dd..d88ae060913f 100644
--- a/contrib/compiler-rt/lib/builtins/fp_trunc_impl.inc
+++ b/contrib/compiler-rt/lib/builtins/fp_trunc_impl.inc
@@ -39,7 +39,7 @@
#include "fp_trunc.h"
-static inline dst_t __truncXfYf2__(src_t a) {
+static __inline dst_t __truncXfYf2__(src_t a) {
// Various constants whose values follow from the type parameters.
// Any reasonable optimizer will fold and propagate all of these.
const int srcBits = sizeof(src_t)*CHAR_BIT;
diff --git a/contrib/compiler-rt/lib/builtins/gcc_personality_v0.c b/contrib/compiler-rt/lib/builtins/gcc_personality_v0.c
index 4b95cfd43b05..ed544d30b809 100644
--- a/contrib/compiler-rt/lib/builtins/gcc_personality_v0.c
+++ b/contrib/compiler-rt/lib/builtins/gcc_personality_v0.c
@@ -141,7 +141,8 @@ static uintptr_t readEncodedPointer(const uint8_t** data, uint8_t encoding)
* throw through a C function compiled with -fexceptions.
*/
#if __USING_SJLJ_EXCEPTIONS__
-// the setjump-longjump based exceptions personality routine has a different name
+/* the setjump-longjump based exceptions personality routine has a
+ * different name */
COMPILER_RT_ABI _Unwind_Reason_Code
__gcc_personality_sj0(int version, _Unwind_Action actions,
uint64_t exceptionClass, struct _Unwind_Exception* exceptionObject,
@@ -194,15 +195,15 @@ __gcc_personality_v0(int version, _Unwind_Action actions,
* Set Instruction Pointer to so we re-enter function
* at landing pad. The landing pad is created by the compiler
* to take two parameters in registers.
- */
- _Unwind_SetGR(context, __builtin_eh_return_data_regno(0),
- (uintptr_t)exceptionObject);
+ */
+ _Unwind_SetGR(context, __builtin_eh_return_data_regno(0),
+ (uintptr_t)exceptionObject);
_Unwind_SetGR(context, __builtin_eh_return_data_regno(1), 0);
- _Unwind_SetIP(context, funcStart+landingPad);
+ _Unwind_SetIP(context, (funcStart + landingPad));
return _URC_INSTALL_CONTEXT;
}
}
-
+
/* No landing pad found, continue unwinding. */
return _URC_CONTINUE_UNWIND;
}
diff --git a/contrib/compiler-rt/lib/builtins/i386/chkstk.S b/contrib/compiler-rt/lib/builtins/i386/chkstk.S
index 3733d722ef19..b59974868f21 100644
--- a/contrib/compiler-rt/lib/builtins/i386/chkstk.S
+++ b/contrib/compiler-rt/lib/builtins/i386/chkstk.S
@@ -19,13 +19,13 @@ DEFINE_COMPILERRT_FUNCTION(__chkstk_ms)
jb 1f
2:
sub $0x1000,%ecx
- orl $0,(%ecx)
+ test %ecx,(%ecx)
sub $0x1000,%eax
cmp $0x1000,%eax
ja 2b
1:
sub %eax,%ecx
- orl $0,(%ecx)
+ test %ecx,(%ecx)
pop %eax
pop %ecx
ret
diff --git a/contrib/compiler-rt/lib/builtins/i386/chkstk2.S b/contrib/compiler-rt/lib/builtins/i386/chkstk2.S
new file mode 100644
index 000000000000..7d65bb088928
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/i386/chkstk2.S
@@ -0,0 +1,40 @@
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+
+#include "../assembly.h"
+
+#ifdef __i386__
+
+// _chkstk (_alloca) routine - probe stack between %esp and (%esp-%eax) in 4k increments,
+// then decrement %esp by %eax. Preserves all registers except %esp and flags.
+// This routine is windows specific
+// http://msdn.microsoft.com/en-us/library/ms648426.aspx
+
+.text
+.balign 4
+DEFINE_COMPILERRT_FUNCTION(_alloca) // _chkstk and _alloca are the same function
+DEFINE_COMPILERRT_FUNCTION(__chkstk)
+ push %ecx
+ cmp $0x1000,%eax
+ lea 8(%esp),%ecx // esp before calling this routine -> ecx
+ jb 1f
+2:
+ sub $0x1000,%ecx
+ test %ecx,(%ecx)
+ sub $0x1000,%eax
+ cmp $0x1000,%eax
+ ja 2b
+1:
+ sub %eax,%ecx
+ test %ecx,(%ecx)
+
+ lea 4(%esp),%eax // load pointer to the return address into eax
+ mov %ecx,%esp // install the new top of stack pointer into esp
+ mov -4(%eax),%ecx // restore ecx
+ push (%eax) // push return address onto the stack
+ sub %esp,%eax // restore the original value in eax
+ ret
+END_COMPILERRT_FUNCTION(__chkstk)
+END_COMPILERRT_FUNCTION(_alloca)
+
+#endif // __i386__
diff --git a/contrib/compiler-rt/lib/builtins/int_lib.h b/contrib/compiler-rt/lib/builtins/int_lib.h
index 985534ddfa07..0fb03ff0e31f 100644
--- a/contrib/compiler-rt/lib/builtins/int_lib.h
+++ b/contrib/compiler-rt/lib/builtins/int_lib.h
@@ -20,6 +20,13 @@
/* Assumption: Right shift of signed negative is arithmetic shift. */
/* Assumption: Endianness is little or big (not mixed). */
+#if defined(__ELF__)
+#define FNALIAS(alias_name, original_name) \
+ void alias_name() __attribute__((alias(#original_name)))
+#else
+#define FNALIAS(alias, name) _Pragma("GCC error(\"alias unsupported on this file format\")")
+#endif
+
/* ABI macro definitions */
#if __ARM_EABI__
@@ -36,13 +43,25 @@
#else
# define ARM_EABI_FNALIAS(aeabi_name, name)
-# if defined(__arm__) && defined(_WIN32)
+# if defined(__arm__) && defined(_WIN32) && (!defined(_MSC_VER) || defined(__clang__))
# define COMPILER_RT_ABI __attribute__((pcs("aapcs")))
# else
# define COMPILER_RT_ABI
# endif
#endif
+#ifdef _MSC_VER
+#define ALWAYS_INLINE __forceinline
+#define NOINLINE __declspec(noinline)
+#define NORETURN __declspec(noreturn)
+#define UNUSED
+#else
+#define ALWAYS_INLINE __attribute__((always_inline))
+#define NOINLINE __attribute__((noinline))
+#define NORETURN __attribute__((noreturn))
+#define UNUSED __attribute__((unused))
+#endif
+
#if defined(__NetBSD__) && (defined(_KERNEL) || defined(_STANDALONE))
/*
* Kernel and boot environment can't use normal headers,
@@ -101,4 +120,44 @@ COMPILER_RT_ABI si_int __clzti2(ti_int a);
COMPILER_RT_ABI tu_int __udivmodti4(tu_int a, tu_int b, tu_int* rem);
#endif
+/* Definitions for builtins unavailable on MSVC */
+#if defined(_MSC_VER) && !defined(__clang__)
+#include <intrin.h>
+
+uint32_t __inline __builtin_ctz(uint32_t value) {
+ uint32_t trailing_zero = 0;
+ if (_BitScanForward(&trailing_zero, value))
+ return trailing_zero;
+ return 32;
+}
+
+uint32_t __inline __builtin_clz(uint32_t value) {
+ uint32_t leading_zero = 0;
+ if (_BitScanReverse(&leading_zero, value))
+ return 31 - leading_zero;
+ return 32;
+}
+
+#if defined(_M_ARM) || defined(_M_X64)
+uint32_t __inline __builtin_clzll(uint64_t value) {
+ uint32_t leading_zero = 0;
+ if (_BitScanReverse64(&leading_zero, value))
+ return 63 - leading_zero;
+ return 64;
+}
+#else
+uint32_t __inline __builtin_clzll(uint64_t value) {
+ if (value == 0)
+ return 64;
+ uint32_t msh = (uint32_t)(value >> 32);
+ uint32_t lsh = (uint32_t)(value & 0xFFFFFFFF);
+ if (msh != 0)
+ return __builtin_clz(msh);
+ return 32 + __builtin_clz(lsh);
+}
+#endif
+
+#define __builtin_clzl __builtin_clzll
+#endif /* defined(_MSC_VER) && !defined(__clang__) */
+
#endif /* INT_LIB_H */
diff --git a/contrib/compiler-rt/lib/builtins/int_math.h b/contrib/compiler-rt/lib/builtins/int_math.h
index d6b4bdae162b..fc81fb7f0220 100644
--- a/contrib/compiler-rt/lib/builtins/int_math.h
+++ b/contrib/compiler-rt/lib/builtins/int_math.h
@@ -25,43 +25,90 @@
# define __has_builtin(x) 0
#endif
-#define CRT_INFINITY __builtin_huge_valf()
+#if defined(_MSC_VER) && !defined(__clang__)
+#include <math.h>
+#include <stdlib.h>
+#include <ymath.h>
+#endif
-#define crt_isinf(x) __builtin_isinf((x))
-#define crt_isnan(x) __builtin_isnan((x))
+#if defined(_MSC_VER) && !defined(__clang__)
+#define CRT_INFINITY INFINITY
+#else
+#define CRT_INFINITY __builtin_huge_valf()
+#endif
+#if defined(_MSC_VER) && !defined(__clang__)
+#define crt_isfinite(x) _finite((x))
+#define crt_isinf(x) !_finite((x))
+#define crt_isnan(x) _isnan((x))
+#else
/* Define crt_isfinite in terms of the builtin if available, otherwise provide
* an alternate version in terms of our other functions. This supports some
* versions of GCC which didn't have __builtin_isfinite.
*/
#if __has_builtin(__builtin_isfinite)
# define crt_isfinite(x) __builtin_isfinite((x))
-#else
+#elif defined(__GNUC__)
# define crt_isfinite(x) \
__extension__(({ \
__typeof((x)) x_ = (x); \
!crt_isinf(x_) && !crt_isnan(x_); \
}))
-#endif
+#else
+# error "Do not know how to check for infinity"
+#endif /* __has_builtin(__builtin_isfinite) */
+#define crt_isinf(x) __builtin_isinf((x))
+#define crt_isnan(x) __builtin_isnan((x))
+#endif /* _MSC_VER */
+#if defined(_MSC_VER) && !defined(__clang__)
+#define crt_copysign(x, y) copysign((x), (y))
+#define crt_copysignf(x, y) copysignf((x), (y))
+#define crt_copysignl(x, y) copysignl((x), (y))
+#else
#define crt_copysign(x, y) __builtin_copysign((x), (y))
#define crt_copysignf(x, y) __builtin_copysignf((x), (y))
#define crt_copysignl(x, y) __builtin_copysignl((x), (y))
+#endif
+#if defined(_MSC_VER) && !defined(__clang__)
+#define crt_fabs(x) fabs((x))
+#define crt_fabsf(x) fabsf((x))
+#define crt_fabsl(x) fabs((x))
+#else
#define crt_fabs(x) __builtin_fabs((x))
#define crt_fabsf(x) __builtin_fabsf((x))
#define crt_fabsl(x) __builtin_fabsl((x))
+#endif
+#if defined(_MSC_VER) && !defined(__clang__)
+#define crt_fmax(x, y) __max((x), (y))
+#define crt_fmaxf(x, y) __max((x), (y))
+#define crt_fmaxl(x, y) __max((x), (y))
+#else
#define crt_fmax(x, y) __builtin_fmax((x), (y))
#define crt_fmaxf(x, y) __builtin_fmaxf((x), (y))
#define crt_fmaxl(x, y) __builtin_fmaxl((x), (y))
+#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
+#if defined(_MSC_VER) && !defined(__clang__)
+#define crt_scalbn(x, y) scalbn((x), (y))
+#define crt_scalbnf(x, y) scalbnf((x), (y))
+#define crt_scalbnl(x, y) scalbnl((x), (y))
+#else
#define crt_scalbn(x, y) __builtin_scalbn((x), (y))
#define crt_scalbnf(x, y) __builtin_scalbnf((x), (y))
#define crt_scalbnl(x, y) __builtin_scalbnl((x), (y))
+#endif
#endif /* INT_MATH_H */
diff --git a/contrib/compiler-rt/lib/builtins/int_types.h b/contrib/compiler-rt/lib/builtins/int_types.h
index aedae14b2046..660385ecd6ae 100644
--- a/contrib/compiler-rt/lib/builtins/int_types.h
+++ b/contrib/compiler-rt/lib/builtins/int_types.h
@@ -20,6 +20,10 @@
#include "int_endianness.h"
+/* si_int is defined in Linux sysroot's asm-generic/siginfo.h */
+#ifdef si_int
+#undef si_int
+#endif
typedef int si_int;
typedef unsigned su_int;
@@ -57,7 +61,8 @@ typedef union
} udwords;
/* MIPS64 issue: PR 20098 */
-#if defined(__LP64__) && !(defined(__mips__) && defined(__clang__))
+#if (defined(__LP64__) || defined(__wasm__)) && \
+ !(defined(__mips__) && defined(__clang__))
#define CRT_HAS_128BIT
#endif
@@ -95,14 +100,14 @@ typedef union
}s;
} utwords;
-static inline ti_int make_ti(di_int h, di_int l) {
+static __inline ti_int make_ti(di_int h, di_int l) {
twords r;
r.s.high = h;
r.s.low = l;
return r.all;
}
-static inline tu_int make_tu(du_int h, du_int l) {
+static __inline tu_int make_tu(du_int h, du_int l) {
utwords r;
r.s.high = h;
r.s.low = l;
@@ -140,5 +145,22 @@ typedef union
long double f;
} long_double_bits;
+#if __STDC_VERSION__ >= 199901L
+typedef float _Complex Fcomplex;
+typedef double _Complex Dcomplex;
+typedef long double _Complex Lcomplex;
+
+#define COMPLEX_REAL(x) __real__(x)
+#define COMPLEX_IMAGINARY(x) __imag__(x)
+#else
+typedef struct { float real, imaginary; } Fcomplex;
+
+typedef struct { double real, imaginary; } Dcomplex;
+
+typedef struct { long double real, imaginary; } Lcomplex;
+
+#define COMPLEX_REAL(x) (x).real
+#define COMPLEX_IMAGINARY(x) (x).imaginary
+#endif
#endif /* INT_TYPES_H */
diff --git a/contrib/compiler-rt/lib/builtins/int_util.c b/contrib/compiler-rt/lib/builtins/int_util.c
index 323e46179e6c..420d1e237aae 100644
--- a/contrib/compiler-rt/lib/builtins/int_util.c
+++ b/contrib/compiler-rt/lib/builtins/int_util.c
@@ -8,8 +8,8 @@
* ===----------------------------------------------------------------------===
*/
-#include "int_util.h"
#include "int_lib.h"
+#include "int_util.h"
/* NOTE: The definitions in this file are declared weak because we clients to be
* able to arbitrarily package individual functions into separate .a files. If
@@ -23,7 +23,7 @@
#ifdef KERNEL_USE
-extern void panic(const char *, ...) __attribute__((noreturn));
+NORETURN extern void panic(const char *, ...);
#ifndef _WIN32
__attribute__((visibility("hidden")))
#endif
@@ -34,8 +34,8 @@ void compilerrt_abort_impl(const char *file, int line, const char *function) {
#elif __APPLE__
/* from libSystem.dylib */
-extern void __assert_rtn(const char *func, const char *file,
- int line, const char * message) __attribute__((noreturn));
+NORETURN extern void __assert_rtn(const char *func, const char *file, int line,
+ const char *message);
#ifndef _WIN32
__attribute__((weak))
diff --git a/contrib/compiler-rt/lib/builtins/int_util.h b/contrib/compiler-rt/lib/builtins/int_util.h
index a9b595db8d0f..a7b20ed66244 100644
--- a/contrib/compiler-rt/lib/builtins/int_util.h
+++ b/contrib/compiler-rt/lib/builtins/int_util.h
@@ -20,10 +20,14 @@
#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__)
-void compilerrt_abort_impl(const char *file, int line,
- const char *function) __attribute__((noreturn));
+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)
+#define COMPILE_TIME_ASSERT2(expr, cnt) \
+ typedef char ct_assert_##cnt[(expr) ? 1 : -1] UNUSED
#endif /* INT_UTIL_H */
diff --git a/contrib/compiler-rt/lib/builtins/muldc3.c b/contrib/compiler-rt/lib/builtins/muldc3.c
index 3bfae2c52224..16d8e98390a3 100644
--- a/contrib/compiler-rt/lib/builtins/muldc3.c
+++ b/contrib/compiler-rt/lib/builtins/muldc3.c
@@ -17,17 +17,17 @@
/* Returns: the product of a + ib and c + id */
-COMPILER_RT_ABI double _Complex
+COMPILER_RT_ABI Dcomplex
__muldc3(double __a, double __b, double __c, double __d)
{
double __ac = __a * __c;
double __bd = __b * __d;
double __ad = __a * __d;
double __bc = __b * __c;
- double _Complex z;
- __real__ z = __ac - __bd;
- __imag__ z = __ad + __bc;
- if (crt_isnan(__real__ z) && crt_isnan(__imag__ z))
+ Dcomplex z;
+ COMPLEX_REAL(z) = __ac - __bd;
+ COMPLEX_IMAGINARY(z) = __ad + __bc;
+ if (crt_isnan(COMPLEX_REAL(z)) && crt_isnan(COMPLEX_IMAGINARY(z)))
{
int __recalc = 0;
if (crt_isinf(__a) || crt_isinf(__b))
@@ -65,8 +65,8 @@ __muldc3(double __a, double __b, double __c, double __d)
}
if (__recalc)
{
- __real__ z = CRT_INFINITY * (__a * __c - __b * __d);
- __imag__ z = CRT_INFINITY * (__a * __d + __b * __c);
+ COMPLEX_REAL(z) = CRT_INFINITY * (__a * __c - __b * __d);
+ COMPLEX_IMAGINARY(z) = CRT_INFINITY * (__a * __d + __b * __c);
}
}
return z;
diff --git a/contrib/compiler-rt/lib/builtins/mulsc3.c b/contrib/compiler-rt/lib/builtins/mulsc3.c
index 29d46c63a799..c89cfd247a15 100644
--- a/contrib/compiler-rt/lib/builtins/mulsc3.c
+++ b/contrib/compiler-rt/lib/builtins/mulsc3.c
@@ -17,17 +17,17 @@
/* Returns: the product of a + ib and c + id */
-COMPILER_RT_ABI float _Complex
+COMPILER_RT_ABI Fcomplex
__mulsc3(float __a, float __b, float __c, float __d)
{
float __ac = __a * __c;
float __bd = __b * __d;
float __ad = __a * __d;
float __bc = __b * __c;
- float _Complex z;
- __real__ z = __ac - __bd;
- __imag__ z = __ad + __bc;
- if (crt_isnan(__real__ z) && crt_isnan(__imag__ z))
+ Fcomplex z;
+ COMPLEX_REAL(z) = __ac - __bd;
+ COMPLEX_IMAGINARY(z) = __ad + __bc;
+ if (crt_isnan(COMPLEX_REAL(z)) && crt_isnan(COMPLEX_IMAGINARY(z)))
{
int __recalc = 0;
if (crt_isinf(__a) || crt_isinf(__b))
@@ -65,8 +65,8 @@ __mulsc3(float __a, float __b, float __c, float __d)
}
if (__recalc)
{
- __real__ z = CRT_INFINITY * (__a * __c - __b * __d);
- __imag__ z = CRT_INFINITY * (__a * __d + __b * __c);
+ COMPLEX_REAL(z) = CRT_INFINITY * (__a * __c - __b * __d);
+ COMPLEX_IMAGINARY(z) = CRT_INFINITY * (__a * __d + __b * __c);
}
}
return z;
diff --git a/contrib/compiler-rt/lib/builtins/mulxc3.c b/contrib/compiler-rt/lib/builtins/mulxc3.c
index 161fd0ce0dd4..ba3221691821 100644
--- a/contrib/compiler-rt/lib/builtins/mulxc3.c
+++ b/contrib/compiler-rt/lib/builtins/mulxc3.c
@@ -19,17 +19,17 @@
/* Returns: the product of a + ib and c + id */
-COMPILER_RT_ABI long double _Complex
+COMPILER_RT_ABI Lcomplex
__mulxc3(long double __a, long double __b, long double __c, long double __d)
{
long double __ac = __a * __c;
long double __bd = __b * __d;
long double __ad = __a * __d;
long double __bc = __b * __c;
- long double _Complex z;
- __real__ z = __ac - __bd;
- __imag__ z = __ad + __bc;
- if (crt_isnan(__real__ z) && crt_isnan(__imag__ z))
+ Lcomplex z;
+ COMPLEX_REAL(z) = __ac - __bd;
+ COMPLEX_IMAGINARY(z) = __ad + __bc;
+ if (crt_isnan(COMPLEX_REAL(z)) && crt_isnan(COMPLEX_IMAGINARY(z)))
{
int __recalc = 0;
if (crt_isinf(__a) || crt_isinf(__b))
@@ -67,8 +67,8 @@ __mulxc3(long double __a, long double __b, long double __c, long double __d)
}
if (__recalc)
{
- __real__ z = CRT_INFINITY * (__a * __c - __b * __d);
- __imag__ z = CRT_INFINITY * (__a * __d + __b * __c);
+ COMPLEX_REAL(z) = CRT_INFINITY * (__a * __c - __b * __d);
+ COMPLEX_IMAGINARY(z) = CRT_INFINITY * (__a * __d + __b * __c);
}
}
return z;
diff --git a/contrib/compiler-rt/lib/builtins/ppc/DD.h b/contrib/compiler-rt/lib/builtins/ppc/DD.h
index fc3e41cbe07e..3e5f9e58c138 100644
--- a/contrib/compiler-rt/lib/builtins/ppc/DD.h
+++ b/contrib/compiler-rt/lib/builtins/ppc/DD.h
@@ -1,5 +1,5 @@
-#ifndef __DD_HEADER
-#define __DD_HEADER
+#ifndef COMPILERRT_DD_HEADER
+#define COMPILERRT_DD_HEADER
#include "../int_lib.h"
@@ -9,7 +9,7 @@ typedef union {
double hi;
double lo;
}s;
-}DD;
+} DD;
typedef union {
double d;
@@ -19,28 +19,27 @@ typedef union {
#define LOWORDER(xy,xHi,xLo,yHi,yLo) \
(((((xHi)*(yHi) - (xy)) + (xHi)*(yLo)) + (xLo)*(yHi)) + (xLo)*(yLo))
-static inline double __attribute__((always_inline))
-local_fabs(double x)
-{
- doublebits result = { .d = x };
- result.x &= UINT64_C(0x7fffffffffffffff);
- return result.d;
+static __inline ALWAYS_INLINE double local_fabs(double x) {
+ doublebits result = {.d = x};
+ result.x &= UINT64_C(0x7fffffffffffffff);
+ return result.d;
}
-static inline double __attribute__((always_inline))
-high26bits(double x)
-{
- doublebits result = { .d = x };
- result.x &= UINT64_C(0xfffffffff8000000);
- return result.d;
+static __inline ALWAYS_INLINE double high26bits(double x) {
+ doublebits result = {.d = x};
+ result.x &= UINT64_C(0xfffffffff8000000);
+ return result.d;
}
-static inline int __attribute__((always_inline))
-different_sign(double x, double y)
-{
- doublebits xsignbit = { .d = x }, ysignbit = { .d = y };
- int result = (int)(xsignbit.x >> 63) ^ (int)(ysignbit.x >> 63);
- return result;
+static __inline ALWAYS_INLINE int different_sign(double x, double y) {
+ doublebits xsignbit = {.d = x}, ysignbit = {.d = y};
+ int result = (int)(xsignbit.x >> 63) ^ (int)(ysignbit.x >> 63);
+ return result;
}
-#endif /* __DD_HEADER */
+long double __gcc_qadd(long double, long double);
+long double __gcc_qsub(long double, long double);
+long double __gcc_qmul(long double, long double);
+long double __gcc_qdiv(long double, long double);
+
+#endif /* COMPILERRT_DD_HEADER */
diff --git a/contrib/compiler-rt/lib/builtins/ppc/divtc3.c b/contrib/compiler-rt/lib/builtins/ppc/divtc3.c
index 299128186312..8ec41c528ab9 100644
--- a/contrib/compiler-rt/lib/builtins/ppc/divtc3.c
+++ b/contrib/compiler-rt/lib/builtins/ppc/divtc3.c
@@ -14,11 +14,6 @@
(x).s.lo = 0.0; \
}
-long double __gcc_qadd(long double, long double);
-long double __gcc_qsub(long double, long double);
-long double __gcc_qmul(long double, long double);
-long double __gcc_qdiv(long double, long double);
-
long double _Complex
__divtc3(long double a, long double b, long double c, long double d)
{
diff --git a/contrib/compiler-rt/lib/builtins/ppc/multc3.c b/contrib/compiler-rt/lib/builtins/ppc/multc3.c
index 738b65a83b03..9dd79c975dde 100644
--- a/contrib/compiler-rt/lib/builtins/ppc/multc3.c
+++ b/contrib/compiler-rt/lib/builtins/ppc/multc3.c
@@ -17,10 +17,6 @@
} \
}
-long double __gcc_qadd(long double, long double);
-long double __gcc_qsub(long double, long double);
-long double __gcc_qmul(long double, long double);
-
long double _Complex
__multc3(long double a, long double b, long double c, long double d)
{
diff --git a/contrib/compiler-rt/lib/builtins/subdf3.c b/contrib/compiler-rt/lib/builtins/subdf3.c
index 089e062415b7..7a79e5e7765d 100644
--- a/contrib/compiler-rt/lib/builtins/subdf3.c
+++ b/contrib/compiler-rt/lib/builtins/subdf3.c
@@ -23,4 +23,3 @@ __subdf3(fp_t a, fp_t b) {
return __adddf3(a, fromRep(toRep(b) ^ signBit));
}
-/* FIXME: rsub for ARM EABI */
diff --git a/contrib/compiler-rt/lib/builtins/subsf3.c b/contrib/compiler-rt/lib/builtins/subsf3.c
index 47f5e5e46ea8..c3b85144af48 100644
--- a/contrib/compiler-rt/lib/builtins/subsf3.c
+++ b/contrib/compiler-rt/lib/builtins/subsf3.c
@@ -23,4 +23,3 @@ __subsf3(fp_t a, fp_t b) {
return __addsf3(a, fromRep(toRep(b) ^ signBit));
}
-/* FIXME: rsub for ARM EABI */
diff --git a/contrib/compiler-rt/lib/builtins/truncdfhf2.c b/contrib/compiler-rt/lib/builtins/truncdfhf2.c
index 0852df369625..17195cd9e799 100644
--- a/contrib/compiler-rt/lib/builtins/truncdfhf2.c
+++ b/contrib/compiler-rt/lib/builtins/truncdfhf2.c
@@ -11,6 +11,8 @@
#define DST_HALF
#include "fp_trunc_impl.inc"
+ARM_EABI_FNALIAS(d2h, truncdfhf2)
+
COMPILER_RT_ABI uint16_t __truncdfhf2(double a) {
return __truncXfYf2__(a);
}
diff --git a/contrib/compiler-rt/lib/builtins/truncsfhf2.c b/contrib/compiler-rt/lib/builtins/truncsfhf2.c
index 381e590c342f..9d61895bfd88 100644
--- a/contrib/compiler-rt/lib/builtins/truncsfhf2.c
+++ b/contrib/compiler-rt/lib/builtins/truncsfhf2.c
@@ -11,9 +11,11 @@
#define DST_HALF
#include "fp_trunc_impl.inc"
+ARM_EABI_FNALIAS(f2h, truncsfhf2)
+
// Use a forwarding definition and noinline to implement a poor man's alias,
// as there isn't a good cross-platform way of defining one.
-COMPILER_RT_ABI __attribute__((noinline)) uint16_t __truncsfhf2(float a) {
+COMPILER_RT_ABI NOINLINE uint16_t __truncsfhf2(float a) {
return __truncXfYf2__(a);
}
diff --git a/contrib/compiler-rt/lib/builtins/x86_64/chkstk.S b/contrib/compiler-rt/lib/builtins/x86_64/chkstk.S
index 5759e84498c6..4149ac63d9d0 100644
--- a/contrib/compiler-rt/lib/builtins/x86_64/chkstk.S
+++ b/contrib/compiler-rt/lib/builtins/x86_64/chkstk.S
@@ -24,13 +24,13 @@ DEFINE_COMPILERRT_FUNCTION(___chkstk_ms)
jb 1f
2:
sub $0x1000,%rcx
- orl $0,(%rcx)
+ test %rcx,(%rcx)
sub $0x1000,%rax
cmp $0x1000,%rax
ja 2b
1:
sub %rax,%rcx
- orl $0,(%rcx)
+ test %rcx,(%rcx)
pop %rax
pop %rcx
ret
diff --git a/contrib/compiler-rt/lib/builtins/x86_64/chkstk2.S b/contrib/compiler-rt/lib/builtins/x86_64/chkstk2.S
new file mode 100644
index 000000000000..ac1eb920e0e8
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/x86_64/chkstk2.S
@@ -0,0 +1,42 @@
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+
+#include "../assembly.h"
+
+#ifdef __x86_64__
+
+// _chkstk (_alloca) routine - probe stack between %rsp and (%rsp-%rax) in 4k increments,
+// then decrement %rsp by %rax. Preserves all registers except %rsp and flags.
+// This routine is windows specific
+// http://msdn.microsoft.com/en-us/library/ms648426.aspx
+
+.text
+.balign 4
+DEFINE_COMPILERRT_FUNCTION(__alloca)
+ mov %rcx,%rax // x64 _alloca is a normal function with parameter in rcx
+ // fallthrough
+DEFINE_COMPILERRT_FUNCTION(___chkstk)
+ push %rcx
+ cmp $0x1000,%rax
+ lea 16(%rsp),%rcx // rsp before calling this routine -> rcx
+ jb 1f
+2:
+ sub $0x1000,%rcx
+ test %rcx,(%rcx)
+ sub $0x1000,%rax
+ cmp $0x1000,%rax
+ ja 2b
+1:
+ sub %rax,%rcx
+ test %rcx,(%rcx)
+
+ lea 8(%rsp),%rax // load pointer to the return address into rax
+ mov %rcx,%rsp // install the new top of stack pointer into rsp
+ mov -8(%rax),%rcx // restore rcx
+ push (%rax) // push return address onto the stack
+ sub %rsp,%rax // restore the original value in rax
+ ret
+END_COMPILERRT_FUNCTION(___chkstk)
+END_COMPILERRT_FUNCTION(__alloca)
+
+#endif // __x86_64__
diff --git a/contrib/compiler-rt/lib/cfi/cfi.cc b/contrib/compiler-rt/lib/cfi/cfi.cc
new file mode 100644
index 000000000000..711866f3fa0c
--- /dev/null
+++ b/contrib/compiler-rt/lib/cfi/cfi.cc
@@ -0,0 +1,271 @@
+//===-------- cfi.cc ------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the runtime support for the cross-DSO CFI.
+//
+//===----------------------------------------------------------------------===//
+
+// FIXME: Intercept dlopen/dlclose.
+// FIXME: Support diagnostic mode.
+// FIXME: Harden:
+// * mprotect shadow, use mremap for updates
+// * something else equally important
+
+#include <assert.h>
+#include <elf.h>
+#include <link.h>
+#include <string.h>
+
+typedef ElfW(Phdr) Elf_Phdr;
+typedef ElfW(Ehdr) Elf_Ehdr;
+
+#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"
+
+static uptr __cfi_shadow;
+static constexpr uptr kShadowGranularity = 12;
+static constexpr uptr kShadowAlign = 1UL << kShadowGranularity; // 4096
+
+static constexpr uint16_t kInvalidShadow = 0;
+static constexpr uint16_t kUncheckedShadow = 0xFFFFU;
+
+static uint16_t *mem_to_shadow(uptr x) {
+ return (uint16_t *)(__cfi_shadow + ((x >> kShadowGranularity) << 1));
+}
+
+typedef int (*CFICheckFn)(u64, void *);
+
+class ShadowValue {
+ uptr addr;
+ uint16_t v;
+ explicit ShadowValue(uptr addr, uint16_t v) : addr(addr), v(v) {}
+
+public:
+ bool is_invalid() const { return v == kInvalidShadow; }
+
+ bool is_unchecked() const { return v == kUncheckedShadow; }
+
+ CFICheckFn get_cfi_check() const {
+ assert(!is_invalid() && !is_unchecked());
+ uptr aligned_addr = addr & ~(kShadowAlign - 1);
+ uptr p = aligned_addr - (((uptr)v - 1) << kShadowGranularity);
+ return reinterpret_cast<CFICheckFn>(p);
+ }
+
+ // Load a shadow valud for the given application memory address.
+ static const ShadowValue load(uptr addr) {
+ return ShadowValue(addr, *mem_to_shadow(addr));
+ }
+};
+
+static void fill_shadow_constant(uptr begin, uptr end, uint16_t v) {
+ assert(v == kInvalidShadow || v == kUncheckedShadow);
+ uint16_t *shadow_begin = mem_to_shadow(begin);
+ uint16_t *shadow_end = mem_to_shadow(end - 1) + 1;
+ memset(shadow_begin, v, (shadow_end - shadow_begin) * sizeof(*shadow_begin));
+}
+
+static void fill_shadow(uptr begin, uptr end, uptr cfi_check) {
+ assert((cfi_check & (kShadowAlign - 1)) == 0);
+
+ // Don't fill anything below cfi_check. We can not represent those addresses
+ // in the shadow, and must make sure at codegen to place all valid call
+ // targets above cfi_check.
+ uptr p = Max(begin, cfi_check);
+ uint16_t *s = mem_to_shadow(p);
+ uint16_t *s_end = mem_to_shadow(end - 1) + 1;
+ uint16_t sv = ((p - cfi_check) >> kShadowGranularity) + 1;
+ for (; s < s_end; s++, sv++)
+ *s = sv;
+
+ // Sanity checks.
+ uptr q = p & ~(kShadowAlign - 1);
+ for (; q < end; q += kShadowAlign) {
+ assert((uptr)ShadowValue::load(q).get_cfi_check() == cfi_check);
+ assert((uptr)ShadowValue::load(q + kShadowAlign / 2).get_cfi_check() ==
+ cfi_check);
+ assert((uptr)ShadowValue::load(q + kShadowAlign - 1).get_cfi_check() ==
+ cfi_check);
+ }
+}
+
+// This is a workaround for a glibc bug:
+// https://sourceware.org/bugzilla/show_bug.cgi?id=15199
+// Other platforms can, hopefully, just do
+// dlopen(RTLD_NOLOAD | RTLD_LAZY)
+// dlsym("__cfi_check").
+static uptr find_cfi_check_in_dso(dl_phdr_info *info) {
+ const ElfW(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);
+ break;
+ }
+ }
+ if (!dynamic) return 0;
+ uptr strtab = 0, symtab = 0;
+ for (const ElfW(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)
+ strtab = p->d_un.d_ptr;
+ }
+
+ if (symtab > strtab) {
+ VReport(1, "Can not handle: symtab > strtab (%p > %zx)\n", symtab, strtab);
+ return 0;
+ }
+
+ // Verify that strtab and symtab are inside of the same LOAD segment.
+ // This excludes VDSO, which has (very high) bogus strtab and symtab pointers.
+ int phdr_idx;
+ for (phdr_idx = 0; phdr_idx < info->dlpi_phnum; phdr_idx++) {
+ const Elf_Phdr *phdr = &info->dlpi_phdr[phdr_idx];
+ if (phdr->p_type == PT_LOAD) {
+ uptr beg = info->dlpi_addr + phdr->p_vaddr;
+ uptr end = beg + phdr->p_memsz;
+ if (strtab >= beg && strtab < end && symtab >= beg && symtab < end)
+ break;
+ }
+ }
+ if (phdr_idx == info->dlpi_phnum) {
+ // Nope, either different segments or just bogus pointers.
+ // Can not handle this.
+ VReport(1, "Can not handle: symtab %p, strtab %zx\n", symtab, strtab);
+ return 0;
+ }
+
+ for (const ElfW(Sym) *p = (const ElfW(Sym) *)symtab; (ElfW(Addr))p < strtab;
+ ++p) {
+ char *name = (char*)(strtab + p->st_name);
+ if (strcmp(name, "__cfi_check") == 0) {
+ assert(p->st_info == ELF32_ST_INFO(STB_GLOBAL, STT_FUNC));
+ uptr addr = info->dlpi_addr + p->st_value;
+ return addr;
+ }
+ }
+ return 0;
+}
+
+static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *data) {
+ uptr cfi_check = find_cfi_check_in_dso(info);
+ if (cfi_check)
+ VReport(1, "Module '%s' __cfi_check %zx\n", info->dlpi_name, cfi_check);
+
+ for (int i = 0; i < info->dlpi_phnum; i++) {
+ const Elf_Phdr *phdr = &info->dlpi_phdr[i];
+ if (phdr->p_type == PT_LOAD) {
+ // Jump tables are in the executable segment.
+ // VTables are in the non-executable one.
+ // Need to fill shadow for both.
+ // FIXME: reject writable if vtables are in the r/o segment. Depend on
+ // PT_RELRO?
+ uptr cur_beg = info->dlpi_addr + phdr->p_vaddr;
+ uptr cur_end = cur_beg + phdr->p_memsz;
+ if (cfi_check) {
+ VReport(1, " %zx .. %zx\n", cur_beg, cur_end);
+ fill_shadow(cur_beg, cur_end, cfi_check ? cfi_check : (uptr)(-1));
+ } else {
+ fill_shadow_constant(cur_beg, cur_end, kUncheckedShadow);
+ }
+ }
+ }
+ return 0;
+}
+
+// Fill shadow for the initial libraries.
+static void init_shadow() {
+ dl_iterate_phdr(dl_iterate_phdr_cb, nullptr);
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+void __cfi_slowpath(u64 CallSiteTypeId, void *Ptr) {
+ uptr Addr = (uptr)Ptr;
+ VReport(3, "__cfi_slowpath: %llx, %p\n", CallSiteTypeId, Ptr);
+ ShadowValue sv = ShadowValue::load(Addr);
+ if (sv.is_invalid()) {
+ VReport(2, "CFI: invalid memory region for a function pointer (shadow==0): %p\n", Ptr);
+ Die();
+ }
+ if (sv.is_unchecked()) {
+ VReport(2, "CFI: unchecked call (shadow=FFFF): %p\n", Ptr);
+ return;
+ }
+ CFICheckFn cfi_check = sv.get_cfi_check();
+ VReport(2, "__cfi_check at %p\n", cfi_check);
+ cfi_check(CallSiteTypeId, Ptr);
+}
+
+static void InitializeFlags() {
+ SetCommonFlagsDefaults();
+#ifdef CFI_ENABLE_DIAG
+ __ubsan::Flags *uf = __ubsan::flags();
+ uf->SetDefaults();
+#endif
+
+ FlagParser cfi_parser;
+ RegisterCommonFlags(&cfi_parser);
+ cfi_parser.ParseString(GetEnv("CFI_OPTIONS"));
+
+#ifdef CFI_ENABLE_DIAG
+ FlagParser ubsan_parser;
+ __ubsan::RegisterUbsanFlags(&ubsan_parser, uf);
+ RegisterCommonFlags(&ubsan_parser);
+
+ const char *ubsan_default_options = __ubsan::MaybeCallUbsanDefaultOptions();
+ ubsan_parser.ParseString(ubsan_default_options);
+ ubsan_parser.ParseString(GetEnv("UBSAN_OPTIONS"));
+#endif
+
+ SetVerbosity(common_flags()->verbosity);
+
+ if (Verbosity()) ReportUnrecognizedFlags();
+
+ if (common_flags()->help) {
+ cfi_parser.PrintFlagDescriptions();
+ }
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+#if !SANITIZER_CAN_USE_PREINIT_ARRAY
+// On ELF platforms, the constructor is invoked using .preinit_array (see below)
+__attribute__((constructor(0)))
+#endif
+void __cfi_init() {
+ SanitizerToolName = "CFI";
+ InitializeFlags();
+
+ uptr vma = GetMaxVirtualAddress();
+ // Shadow is 2 -> 2**kShadowGranularity.
+ uptr shadow_size = (vma >> (kShadowGranularity - 1)) + 1;
+ VReport(1, "CFI: VMA size %zx, shadow size %zx\n", vma, shadow_size);
+ void *shadow = MmapNoReserveOrDie(shadow_size, "CFI shadow");
+ VReport(1, "CFI: shadow at %zx .. %zx\n", shadow,
+ reinterpret_cast<uptr>(shadow) + shadow_size);
+ __cfi_shadow = (uptr)shadow;
+ init_shadow();
+
+#ifdef CFI_ENABLE_DIAG
+ __ubsan::InitAsPlugin();
+#endif
+}
+
+#if SANITIZER_CAN_USE_PREINIT_ARRAY
+// On ELF platforms, run cfi initialization before any other constructors.
+// On other platforms we use the constructor attribute to arrange to run our
+// initialization early.
+extern "C" {
+__attribute__((section(".preinit_array"),
+ used)) void (*__cfi_preinit)(void) = __cfi_init;
+}
+#endif
diff --git a/contrib/compiler-rt/lib/cfi/cfi_blacklist.txt b/contrib/compiler-rt/lib/cfi/cfi_blacklist.txt
new file mode 100644
index 000000000000..1f0eeb355617
--- /dev/null
+++ b/contrib/compiler-rt/lib/cfi/cfi_blacklist.txt
@@ -0,0 +1,26 @@
+# Standard library types.
+type:std::*
+
+# The stdext namespace contains Microsoft standard library extensions.
+type:stdext::*
+
+# Types with a uuid attribute, i.e. COM types.
+type:attr:uuid
+
+# STL allocators (T *allocator<T *>::allocate(size_type, const void*)).
+# The type signature mandates a cast from uninitialized void* to T*.
+# size_type can either be unsigned int (j) or unsigned long (m).
+fun:*8allocateEjPKv
+fun:*8allocateEmPKv
+
+# std::get_temporary_buffer, likewise (libstdc++, libc++).
+fun:_ZSt20get_temporary_buffer*
+fun:_ZNSt3__120get_temporary_buffer*
+
+# STL address-of magic (libstdc++, libc++).
+fun:*__addressof*
+fun:_ZNSt3__19addressof*
+
+# Windows C++ stdlib headers that contain bad unrelated casts.
+src:*xmemory0
+src:*xstddef
diff --git a/contrib/compiler-rt/lib/dfsan/dfsan.cc b/contrib/compiler-rt/lib/dfsan/dfsan.cc
index d2e137e129c1..7285f202d060 100644
--- a/contrib/compiler-rt/lib/dfsan/dfsan.cc
+++ b/contrib/compiler-rt/lib/dfsan/dfsan.cc
@@ -42,6 +42,8 @@ Flags __dfsan::flags_data;
SANITIZER_INTERFACE_ATTRIBUTE THREADLOCAL dfsan_label __dfsan_retval_tls;
SANITIZER_INTERFACE_ATTRIBUTE THREADLOCAL dfsan_label __dfsan_arg_tls[64];
+SANITIZER_INTERFACE_ATTRIBUTE uptr __dfsan_shadow_ptr_mask;
+
// On Linux/x86_64, memory is laid out as follows:
//
// +--------------------+ 0x800000000000 (top of memory)
@@ -80,24 +82,52 @@ SANITIZER_INTERFACE_ATTRIBUTE THREADLOCAL dfsan_label __dfsan_arg_tls[64];
// | reserved by kernel |
// +--------------------+ 0x0000000000
+// On Linux/AArch64 (39-bit VMA), memory is laid out as follow:
+//
+// +--------------------+ 0x8000000000 (top of memory)
+// | application memory |
+// +--------------------+ 0x7000008000 (kAppAddr)
+// | |
+// | unused |
+// | |
+// +--------------------+ 0x1200000000 (kUnusedAddr)
+// | union table |
+// +--------------------+ 0x1000000000 (kUnionTableAddr)
+// | shadow memory |
+// +--------------------+ 0x0000010000 (kShadowAddr)
+// | reserved by kernel |
+// +--------------------+ 0x0000000000
+
+// On Linux/AArch64 (42-bit VMA), memory is laid out as follow:
+//
+// +--------------------+ 0x40000000000 (top of memory)
+// | application memory |
+// +--------------------+ 0x3ff00008000 (kAppAddr)
+// | |
+// | unused |
+// | |
+// +--------------------+ 0x1200000000 (kUnusedAddr)
+// | union table |
+// +--------------------+ 0x8000000000 (kUnionTableAddr)
+// | shadow memory |
+// +--------------------+ 0x0000010000 (kShadowAddr)
+// | reserved by kernel |
+// +--------------------+ 0x0000000000
+
typedef atomic_dfsan_label dfsan_union_table_t[kNumLabels][kNumLabels];
-#if defined(__x86_64__)
-static const uptr kShadowAddr = 0x10000;
-static const uptr kUnionTableAddr = 0x200000000000;
-static const uptr kUnusedAddr = kUnionTableAddr + sizeof(dfsan_union_table_t);
-static const uptr kAppAddr = 0x700000008000;
-#elif defined(__mips64)
-static const uptr kShadowAddr = 0x10000;
-static const uptr kUnionTableAddr = 0x2000000000;
-static const uptr kUnusedAddr = kUnionTableAddr + sizeof(dfsan_union_table_t);
-static const uptr kAppAddr = 0xF000008000;
-#else
-# error "DFSan not supported for this platform!"
+#ifdef DFSAN_RUNTIME_VMA
+// Runtime detected VMA size.
+int __dfsan::vmaSize;
#endif
+static uptr UnusedAddr() {
+ return MappingArchImpl<MAPPING_UNION_TABLE_ADDR>()
+ + sizeof(dfsan_union_table_t);
+}
+
static atomic_dfsan_label *union_table(dfsan_label l1, dfsan_label l2) {
- return &(*(dfsan_union_table_t *) kUnionTableAddr)[l1][l2];
+ return &(*(dfsan_union_table_t *) UnionTableAddr())[l1][l2];
}
// Checks we do not run out of labels.
@@ -325,10 +355,30 @@ static void RegisterDfsanFlags(FlagParser *parser, Flags *f) {
}
static void InitializeFlags() {
+ SetCommonFlagsDefaults();
+ flags().SetDefaults();
+
FlagParser parser;
+ RegisterCommonFlags(&parser);
RegisterDfsanFlags(&parser, &flags());
- flags().SetDefaults();
parser.ParseString(GetEnv("DFSAN_OPTIONS"));
+ SetVerbosity(common_flags()->verbosity);
+ if (Verbosity()) ReportUnrecognizedFlags();
+ if (common_flags()->help) parser.PrintFlagDescriptions();
+}
+
+static void InitializePlatformEarly() {
+#ifdef DFSAN_RUNTIME_VMA
+ __dfsan::vmaSize =
+ (MostSignificantSetBitIndex(GET_CURRENT_FRAME()) + 1);
+ if (__dfsan::vmaSize == 39 || __dfsan::vmaSize == 42) {
+ __dfsan_shadow_ptr_mask = ShadowMask();
+ } else {
+ Printf("FATAL: DataFlowSanitizer: unsupported VMA range\n");
+ Printf("FATAL: Found %d - Supported 39 and 42\n", __dfsan::vmaSize);
+ Die();
+ }
+#endif
}
static void dfsan_fini() {
@@ -347,12 +397,12 @@ static void dfsan_fini() {
}
}
-#ifdef DFSAN_NOLIBC
-extern "C" void dfsan_init() {
-#else
static void dfsan_init(int argc, char **argv, char **envp) {
-#endif
- MmapFixedNoReserve(kShadowAddr, kUnusedAddr - kShadowAddr);
+ InitializeFlags();
+
+ InitializePlatformEarly();
+
+ MmapFixedNoReserve(ShadowAddr(), UnusedAddr() - ShadowAddr());
// Protect the region of memory we don't use, to preserve the one-to-one
// mapping from application to shadow memory. But if ASLR is disabled, Linux
@@ -360,21 +410,20 @@ static void dfsan_init(int argc, char **argv, char **envp) {
// works so long as the program doesn't use too much memory. We support this
// case by disabling memory protection when ASLR is disabled.
uptr init_addr = (uptr)&dfsan_init;
- if (!(init_addr >= kUnusedAddr && init_addr < kAppAddr))
- MmapNoAccess(kUnusedAddr, kAppAddr - kUnusedAddr);
+ if (!(init_addr >= UnusedAddr() && init_addr < AppAddr()))
+ MmapNoAccess(UnusedAddr(), AppAddr() - UnusedAddr());
- InitializeFlags();
InitializeInterceptors();
// Register the fini callback to run when the program terminates successfully
// or it is killed by the runtime.
Atexit(dfsan_fini);
- SetDieCallback(dfsan_fini);
+ AddDieCallback(dfsan_fini);
__dfsan_label_info[kInitializingLabel].desc = "<init label>";
}
-#if !defined(DFSAN_NOLIBC) && SANITIZER_CAN_USE_PREINIT_ARRAY
+#if SANITIZER_CAN_USE_PREINIT_ARRAY
__attribute__((section(".preinit_array"), used))
static void (*dfsan_init_ptr)(int, char **, char **) = dfsan_init;
#endif
diff --git a/contrib/compiler-rt/lib/dfsan/dfsan.h b/contrib/compiler-rt/lib/dfsan/dfsan.h
index ceba3533a233..81f949e3019e 100644
--- a/contrib/compiler-rt/lib/dfsan/dfsan.h
+++ b/contrib/compiler-rt/lib/dfsan/dfsan.h
@@ -16,6 +16,7 @@
#define DFSAN_H
#include "sanitizer_common/sanitizer_internal_defs.h"
+#include "dfsan_platform.h"
// Copy declarations from public sanitizer/dfsan_interface.h header here.
typedef u16 dfsan_label;
@@ -44,11 +45,7 @@ namespace __dfsan {
void InitializeInterceptors();
inline dfsan_label *shadow_for(void *ptr) {
-#if defined(__x86_64__)
- return (dfsan_label *) ((((uptr) ptr) & ~0x700000000000) << 1);
-#elif defined(__mips64)
- return (dfsan_label *) ((((uptr) ptr) & ~0xF000000000) << 1);
-#endif
+ return (dfsan_label *) ((((uptr) ptr) & ShadowMask()) << 1);
}
inline const dfsan_label *shadow_for(const void *ptr) {
diff --git a/contrib/compiler-rt/lib/dfsan/dfsan_custom.cc b/contrib/compiler-rt/lib/dfsan/dfsan_custom.cc
index c58b471db53c..e0cd16ab695c 100644
--- a/contrib/compiler-rt/lib/dfsan/dfsan_custom.cc
+++ b/contrib/compiler-rt/lib/dfsan/dfsan_custom.cc
@@ -43,6 +43,14 @@
using namespace __dfsan;
+#define CALL_WEAK_INTERCEPTOR_HOOK(f, ...) \
+ do { \
+ if (f) \
+ f(__VA_ARGS__); \
+ } while (false)
+#define DECLARE_WEAK_INTERCEPTOR_HOOK(f, ...) \
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void f(__VA_ARGS__);
+
extern "C" {
SANITIZER_INTERFACE_ATTRIBUTE int
__dfsw_stat(const char *path, struct stat *buf, dfsan_label path_label,
@@ -77,25 +85,23 @@ SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strchr(const char *s, int c,
*ret_label = dfsan_union(dfsan_read_label(s, i + 1),
dfsan_union(s_label, c_label));
}
- return s[i] == 0 ? 0 : const_cast<char *>(s+i);
+ return s[i] == 0 ? nullptr : const_cast<char *>(s+i);
}
}
}
-SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
-void
-dfsan_weak_hook_memcmp(uptr caller_pc, const void *s1, const void *s2, size_t n,
- dfsan_label s1_label, dfsan_label s2_label,
- dfsan_label n_label);
+DECLARE_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_memcmp, uptr caller_pc,
+ const void *s1, const void *s2, size_t n,
+ dfsan_label s1_label, dfsan_label s2_label,
+ dfsan_label n_label)
SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_memcmp(const void *s1, const void *s2,
size_t n, dfsan_label s1_label,
dfsan_label s2_label,
dfsan_label n_label,
dfsan_label *ret_label) {
- if (dfsan_weak_hook_memcmp)
- dfsan_weak_hook_memcmp(GET_CALLER_PC(), s1, s2, n, s1_label, s2_label,
- n_label);
+ CALL_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_memcmp, GET_CALLER_PC(), s1, s2, n,
+ s1_label, s2_label, n_label);
const char *cs1 = (const char *) s1, *cs2 = (const char *) s2;
for (size_t i = 0; i != n; ++i) {
if (cs1[i] != cs2[i]) {
@@ -118,10 +124,16 @@ SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_memcmp(const void *s1, const void *s2,
return 0;
}
+DECLARE_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_strcmp, uptr caller_pc,
+ const char *s1, const char *s2,
+ dfsan_label s1_label, dfsan_label s2_label)
+
SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_strcmp(const char *s1, const char *s2,
dfsan_label s1_label,
dfsan_label s2_label,
dfsan_label *ret_label) {
+ CALL_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_strcmp, GET_CALLER_PC(), s1, s2,
+ s1_label, s2_label);
for (size_t i = 0;; ++i) {
if (s1[i] != s2[i] || s1[i] == 0 || s2[i] == 0) {
if (flags().strict_data_dependencies) {
@@ -153,6 +165,11 @@ __dfsw_strcasecmp(const char *s1, const char *s2, dfsan_label s1_label,
return 0;
}
+DECLARE_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_strncmp, uptr caller_pc,
+ const char *s1, const char *s2, size_t n,
+ dfsan_label s1_label, dfsan_label s2_label,
+ dfsan_label n_label)
+
SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_strncmp(const char *s1, const char *s2,
size_t n, dfsan_label s1_label,
dfsan_label s2_label,
@@ -163,6 +180,9 @@ SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_strncmp(const char *s1, const char *s2,
return 0;
}
+ CALL_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_strncmp, GET_CALLER_PC(), s1, s2,
+ n, s1_label, s2_label, n_label);
+
for (size_t i = 0;; ++i) {
if (s1[i] != s2[i] || s1[i] == 0 || s2[i] == 0 || i == n - 1) {
if (flags().strict_data_dependencies) {
@@ -828,8 +848,8 @@ typedef void (*write_trampoline_t)(
// Calls to dfsan_set_write_callback() set the values in this struct.
// Calls to the custom version of write() read (and invoke) them.
static struct {
- write_trampoline_t write_callback_trampoline = NULL;
- void *write_callback = NULL;
+ write_trampoline_t write_callback_trampoline = nullptr;
+ void *write_callback = nullptr;
} write_callback_info;
SANITIZER_INTERFACE_ATTRIBUTE void
@@ -846,7 +866,7 @@ SANITIZER_INTERFACE_ATTRIBUTE int
__dfsw_write(int fd, const void *buf, size_t count,
dfsan_label fd_label, dfsan_label buf_label,
dfsan_label count_label, dfsan_label *ret_label) {
- if (write_callback_info.write_callback != NULL) {
+ if (write_callback_info.write_callback) {
write_callback_info.write_callback_trampoline(
write_callback_info.write_callback,
fd, buf, count,
@@ -856,7 +876,7 @@ __dfsw_write(int fd, const void *buf, size_t count,
*ret_label = 0;
return write(fd, buf, count);
}
-}
+} // namespace __dfsan
// Type used to extract a dfsan_label with va_arg()
typedef int dfsan_label_va;
@@ -1112,4 +1132,4 @@ int __dfsw_snprintf(char *str, size_t size, const char *format,
va_end(ap);
return ret;
}
-}
+} // extern "C"
diff --git a/contrib/compiler-rt/lib/dfsan/dfsan_platform.h b/contrib/compiler-rt/lib/dfsan/dfsan_platform.h
new file mode 100644
index 000000000000..f1d9f108e908
--- /dev/null
+++ b/contrib/compiler-rt/lib/dfsan/dfsan_platform.h
@@ -0,0 +1,107 @@
+//===-- dfsan_platform.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 DataFlowSanitizer.
+//
+// Platform specific information for DFSan.
+//===----------------------------------------------------------------------===//
+
+#ifndef DFSAN_PLATFORM_H
+#define DFSAN_PLATFORM_H
+
+namespace __dfsan {
+
+#if defined(__x86_64__)
+struct Mapping {
+ static const uptr kShadowAddr = 0x10000;
+ static const uptr kUnionTableAddr = 0x200000000000;
+ static const uptr kAppAddr = 0x700000008000;
+ static const uptr kShadowMask = ~0x700000000000;
+};
+#elif defined(__mips64)
+struct Mapping {
+ static const uptr kShadowAddr = 0x10000;
+ static const uptr kUnionTableAddr = 0x2000000000;
+ static const uptr kAppAddr = 0xF000008000;
+ static const uptr kShadowMask = ~0xF000000000;
+};
+#elif defined(__aarch64__)
+struct Mapping39 {
+ static const uptr kShadowAddr = 0x10000;
+ static const uptr kUnionTableAddr = 0x1000000000;
+ static const uptr kAppAddr = 0x7000008000;
+ static const uptr kShadowMask = ~0x7800000000;
+};
+
+struct Mapping42 {
+ static const uptr kShadowAddr = 0x10000;
+ static const uptr kUnionTableAddr = 0x8000000000;
+ static const uptr kAppAddr = 0x3ff00008000;
+ static const uptr kShadowMask = ~0x3c000000000;
+};
+
+extern int vmaSize;
+# define DFSAN_RUNTIME_VMA 1
+#else
+# error "DFSan not supported for this platform!"
+#endif
+
+enum MappingType {
+ MAPPING_SHADOW_ADDR,
+ MAPPING_UNION_TABLE_ADDR,
+ MAPPING_APP_ADDR,
+ MAPPING_SHADOW_MASK
+};
+
+template<typename Mapping, int Type>
+uptr MappingImpl(void) {
+ switch (Type) {
+ case MAPPING_SHADOW_ADDR: return Mapping::kShadowAddr;
+ case MAPPING_UNION_TABLE_ADDR: return Mapping::kUnionTableAddr;
+ case MAPPING_APP_ADDR: return Mapping::kAppAddr;
+ case MAPPING_SHADOW_MASK: return Mapping::kShadowMask;
+ }
+}
+
+template<int Type>
+uptr MappingArchImpl(void) {
+#ifdef __aarch64__
+ if (vmaSize == 39)
+ return MappingImpl<Mapping39, Type>();
+ else
+ return MappingImpl<Mapping42, Type>();
+ DCHECK(0);
+#else
+ return MappingImpl<Mapping, Type>();
+#endif
+}
+
+ALWAYS_INLINE
+uptr ShadowAddr() {
+ return MappingArchImpl<MAPPING_SHADOW_ADDR>();
+}
+
+ALWAYS_INLINE
+uptr UnionTableAddr() {
+ return MappingArchImpl<MAPPING_UNION_TABLE_ADDR>();
+}
+
+ALWAYS_INLINE
+uptr AppAddr() {
+ return MappingArchImpl<MAPPING_APP_ADDR>();
+}
+
+ALWAYS_INLINE
+uptr ShadowMask() {
+ return MappingArchImpl<MAPPING_SHADOW_MASK>();
+}
+
+} // namespace __dfsan
+
+#endif
diff --git a/contrib/compiler-rt/lib/dfsan/done_abilist.txt b/contrib/compiler-rt/lib/dfsan/done_abilist.txt
index e6c077ff1208..7ca8aeba32fe 100644
--- a/contrib/compiler-rt/lib/dfsan/done_abilist.txt
+++ b/contrib/compiler-rt/lib/dfsan/done_abilist.txt
@@ -266,10 +266,41 @@ fun:reflect.makeFuncStub=discard
# Replaces __sanitizer_cov_trace_cmp with __dfsw___sanitizer_cov_trace_cmp
fun:__sanitizer_cov_trace_cmp=custom
fun:__sanitizer_cov_trace_cmp=uninstrumented
+# Similar for __sanitizer_cov_trace_switch
+fun:__sanitizer_cov_trace_switch=custom
+fun:__sanitizer_cov_trace_switch=uninstrumented
# Ignores all other __sanitizer callbacks.
-fun:__sanitizer_*=uninstrumented
-fun:__sanitizer_*=discard
+fun:__sanitizer_cov=uninstrumented
+fun:__sanitizer_cov=discard
+fun:__sanitizer_cov_module_init=uninstrumented
+fun:__sanitizer_cov_module_init=discard
+fun:__sanitizer_cov_with_check=uninstrumented
+fun:__sanitizer_cov_with_check=discard
+fun:__sanitizer_cov_indir_call16=uninstrumented
+fun:__sanitizer_cov_indir_call16=discard
+fun:__sanitizer_cov_indir_call16=uninstrumented
+fun:__sanitizer_cov_indir_call16=discard
+fun:__sanitizer_reset_coverage=uninstrumented
+fun:__sanitizer_reset_coverage=discard
+fun:__sanitizer_set_death_callback=uninstrumented
+fun:__sanitizer_set_death_callback=discard
+fun:__sanitizer_get_coverage_guards=uninstrumented
+fun:__sanitizer_get_coverage_guards=discard
+fun:__sanitizer_get_number_of_counters=uninstrumented
+fun:__sanitizer_get_number_of_counters=discard
+fun:__sanitizer_update_counter_bitset_and_clear_counters=uninstrumented
+fun:__sanitizer_update_counter_bitset_and_clear_counters=discard
+fun:__sanitizer_get_total_unique_coverage=uninstrumented
+fun:__sanitizer_get_total_unique_coverage=discard
+fun:__sanitizer_get_total_unique_coverage=uninstrumented
+fun:__sanitizer_get_total_unique_coverage=discard
+fun:__sanitizer_update_counter_bitset_and_clear_counters=uninstrumented
+fun:__sanitizer_update_counter_bitset_and_clear_counters=discard
+
+# Ignores the dfsan wrappers.
+fun:__dfsw_*=uninstrumented
+fun:__dfsw_*=discard
# Don't add extra parameters to the Fuzzer callback.
fun:LLVMFuzzerTestOneInput=uninstrumented
diff --git a/contrib/compiler-rt/lib/dfsan/scripts/build-libc-list.py b/contrib/compiler-rt/lib/dfsan/scripts/build-libc-list.py
deleted file mode 100755
index eddb6c07e99d..000000000000
--- a/contrib/compiler-rt/lib/dfsan/scripts/build-libc-list.py
+++ /dev/null
@@ -1,96 +0,0 @@
-#!/usr/bin/env python
-#===- lib/dfsan/scripts/build-libc-list.py ---------------------------------===#
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-#===------------------------------------------------------------------------===#
-# The purpose of this script is to identify every function symbol in a set of
-# libraries (in this case, libc and libgcc) so that they can be marked as
-# uninstrumented, thus allowing the instrumentation pass to treat calls to those
-# functions correctly.
-
-import os
-import subprocess
-import sys
-from optparse import OptionParser
-
-def defined_function_list(object):
- functions = []
- readelf_proc = subprocess.Popen(['readelf', '-s', '-W', object],
- stdout=subprocess.PIPE)
- readelf = readelf_proc.communicate()[0].split('\n')
- if readelf_proc.returncode != 0:
- raise subprocess.CalledProcessError(readelf_proc.returncode, 'readelf')
- for line in readelf:
- if (line[31:35] == 'FUNC' or line[31:36] == 'IFUNC') and \
- line[39:44] != 'LOCAL' and \
- line[55:58] != 'UND':
- function_name = line[59:].split('@')[0]
- functions.append(function_name)
- return functions
-
-p = OptionParser()
-
-p.add_option('--libc-dso-path', metavar='PATH',
- help='path to libc DSO directory',
- default='/lib/x86_64-linux-gnu')
-p.add_option('--libc-archive-path', metavar='PATH',
- help='path to libc archive directory',
- default='/usr/lib/x86_64-linux-gnu')
-
-p.add_option('--libgcc-dso-path', metavar='PATH',
- help='path to libgcc DSO directory',
- default='/lib/x86_64-linux-gnu')
-p.add_option('--libgcc-archive-path', metavar='PATH',
- help='path to libgcc archive directory',
- default='/usr/lib/gcc/x86_64-linux-gnu/4.6')
-
-p.add_option('--with-libstdcxx', action='store_true',
- dest='with_libstdcxx',
- help='include libstdc++ in the list (inadvisable)')
-p.add_option('--libstdcxx-dso-path', metavar='PATH',
- help='path to libstdc++ DSO directory',
- default='/usr/lib/x86_64-linux-gnu')
-
-(options, args) = p.parse_args()
-
-libs = [os.path.join(options.libc_dso_path, name) for name in
- ['ld-linux-x86-64.so.2',
- 'libanl.so.1',
- 'libBrokenLocale.so.1',
- 'libcidn.so.1',
- 'libcrypt.so.1',
- 'libc.so.6',
- 'libdl.so.2',
- 'libm.so.6',
- 'libnsl.so.1',
- 'libpthread.so.0',
- 'libresolv.so.2',
- 'librt.so.1',
- 'libthread_db.so.1',
- 'libutil.so.1']]
-libs += [os.path.join(options.libc_archive_path, name) for name in
- ['libc_nonshared.a',
- 'libpthread_nonshared.a']]
-
-libs.append(os.path.join(options.libgcc_dso_path, 'libgcc_s.so.1'))
-libs.append(os.path.join(options.libgcc_archive_path, 'libgcc.a'))
-
-if options.with_libstdcxx:
- libs.append(os.path.join(options.libstdcxx_dso_path, 'libstdc++.so.6'))
-
-functions = []
-for l in libs:
- if os.path.exists(l):
- functions += defined_function_list(l)
- else:
- print >> sys.stderr, 'warning: library %s not found' % l
-
-functions = list(set(functions))
-functions.sort()
-
-for f in functions:
- print 'fun:%s=uninstrumented' % f
diff --git a/contrib/compiler-rt/lib/dfsan/scripts/check_custom_wrappers.sh b/contrib/compiler-rt/lib/dfsan/scripts/check_custom_wrappers.sh
deleted file mode 100755
index 99bf50cbbd08..000000000000
--- a/contrib/compiler-rt/lib/dfsan/scripts/check_custom_wrappers.sh
+++ /dev/null
@@ -1,52 +0,0 @@
-#!/bin/sh
-
-DFSAN_DIR=$(dirname "$0")/../
-DFSAN_CUSTOM_TESTS=${DFSAN_DIR}/../../test/dfsan/custom.cc
-DFSAN_CUSTOM_WRAPPERS=${DFSAN_DIR}/dfsan_custom.cc
-DFSAN_ABI_LIST=${DFSAN_DIR}/done_abilist.txt
-
-DIFFOUT=$(mktemp -q /tmp/tmp.XXXXXXXXXX)
-ERRORLOG=$(mktemp -q /tmp/tmp.XXXXXXXXXX)
-DIFF_A=$(mktemp -q /tmp/tmp.XXXXXXXXXX)
-DIFF_B=$(mktemp -q /tmp/tmp.XXXXXXXXXX)
-
-on_exit() {
- rm -f ${DIFFOUT} 2> /dev/null
- rm -f ${ERRORLOG} 2> /dev/null
- rm -f ${DIFF_A} 2> /dev/null
- rm -f ${DIFF_B} 2> /dev/null
-}
-
-# Ignore __sanitizer_cov_trace* because they are implemented elsewhere.
-trap on_exit EXIT
-grep -E "^fun:.*=custom" ${DFSAN_ABI_LIST} \
- | grep -v "dfsan_get_label\|__sanitizer_cov_trace" \
- | sed "s/^fun:\(.*\)=custom.*/\1/" | sort > $DIFF_A
-grep -E "__dfsw.*\(" ${DFSAN_CUSTOM_WRAPPERS} \
- | sed "s/.*__dfsw_\(.*\)(.*/\1/" | sort > $DIFF_B
-diff -u $DIFF_A $DIFF_B > ${DIFFOUT}
-if [ $? -ne 0 ]
-then
- echo -n "The following differences between the ABI list and ">> ${ERRORLOG}
- echo "the implemented custom wrappers have been found:" >> ${ERRORLOG}
- cat ${DIFFOUT} >> ${ERRORLOG}
-fi
-
-grep -E __dfsw_ ${DFSAN_CUSTOM_WRAPPERS} \
- | sed "s/.*__dfsw_\([^(]*\).*/\1/" | sort > $DIFF_A
-grep -E "^[[:space:]]*test_.*\(\);" ${DFSAN_CUSTOM_TESTS} \
- | sed "s/.*test_\(.*\)();/\1/" | sort > $DIFF_B
-diff -u $DIFF_A $DIFF_B > ${DIFFOUT}
-if [ $? -ne 0 ]
-then
- echo -n "The following differences between the implemented " >> ${ERRORLOG}
- echo "custom wrappers and the tests have been found:" >> ${ERRORLOG}
- cat ${DIFFOUT} >> ${ERRORLOG}
-fi
-
-if [ -s ${ERRORLOG} ]
-then
- cat ${ERRORLOG}
- exit 1
-fi
-
diff --git a/contrib/compiler-rt/lib/interception/interception_linux.h b/contrib/compiler-rt/lib/interception/interception_linux.h
index d3f774bede9f..27a66c882041 100644
--- a/contrib/compiler-rt/lib/interception/interception_linux.h
+++ b/contrib/compiler-rt/lib/interception/interception_linux.h
@@ -35,12 +35,12 @@ void *GetFuncAddrVer(const char *func_name, const char *ver);
(::__interception::uptr) & WRAP(func))
#if !defined(__ANDROID__) // android does not have dlvsym
-# define INTERCEPT_FUNCTION_VER_LINUX_OR_FREEBSD(func, symver) \
- ::__interception::real_##func = (func##_f)(unsigned long) \
- ::__interception::GetFuncAddrVer(#func, symver)
+#define INTERCEPT_FUNCTION_VER_LINUX_OR_FREEBSD(func, symver) \
+ (::__interception::real_##func = (func##_f)( \
+ unsigned long)::__interception::GetFuncAddrVer(#func, symver))
#else
-# define INTERCEPT_FUNCTION_VER_LINUX_OR_FREEBSD(func, symver) \
- INTERCEPT_FUNCTION_LINUX_OR_FREEBSD(func)
+#define INTERCEPT_FUNCTION_VER_LINUX_OR_FREEBSD(func, symver) \
+ INTERCEPT_FUNCTION_LINUX_OR_FREEBSD(func)
#endif // !defined(__ANDROID__)
#endif // INTERCEPTION_LINUX_H
diff --git a/contrib/compiler-rt/lib/interception/interception_win.cc b/contrib/compiler-rt/lib/interception/interception_win.cc
index 19cf184948b9..4c04c83b982b 100644
--- a/contrib/compiler-rt/lib/interception/interception_win.cc
+++ b/contrib/compiler-rt/lib/interception/interception_win.cc
@@ -15,6 +15,7 @@
#ifdef _WIN32
#include "interception.h"
+#define WIN32_LEAN_AND_MEAN
#include <windows.h>
namespace __interception {
@@ -182,7 +183,7 @@ bool OverrideFunction(uptr old_func, uptr new_func, uptr *orig_old_func) {
return true;
}
-static const void **InterestingDLLsAvailable() {
+static void **InterestingDLLsAvailable() {
const char *InterestingDLLs[] = {
"kernel32.dll",
"msvcr110.dll", // VS2012
@@ -198,14 +199,65 @@ static const void **InterestingDLLsAvailable() {
result[j++] = (void *)h;
}
}
- return (const void **)&result[0];
+ return &result[0];
+}
+
+namespace {
+// Utility for reading loaded PE images.
+template <typename T> class RVAPtr {
+ public:
+ RVAPtr(void *module, uptr rva)
+ : ptr_(reinterpret_cast<T *>(reinterpret_cast<char *>(module) + rva)) {}
+ operator T *() { return ptr_; }
+ T *operator->() { return ptr_; }
+ T *operator++() { return ++ptr_; }
+
+ private:
+ T *ptr_;
+};
+} // namespace
+
+// Internal implementation of GetProcAddress. At least since Windows 8,
+// GetProcAddress appears to initialize DLLs before returning function pointers
+// into them. This is problematic for the sanitizers, because they typically
+// want to intercept malloc *before* MSVCRT initializes. Our internal
+// implementation walks the export list manually without doing initialization.
+uptr InternalGetProcAddress(void *module, const char *func_name) {
+ // Check that the module header is full and present.
+ RVAPtr<IMAGE_DOS_HEADER> dos_stub(module, 0);
+ RVAPtr<IMAGE_NT_HEADERS> headers(module, dos_stub->e_lfanew);
+ if (!module || dos_stub->e_magic != IMAGE_DOS_SIGNATURE || // "MZ"
+ headers->Signature != IMAGE_NT_SIGNATURE || // "PE\0\0"
+ headers->FileHeader.SizeOfOptionalHeader <
+ sizeof(IMAGE_OPTIONAL_HEADER)) {
+ return 0;
+ }
+
+ IMAGE_DATA_DIRECTORY *export_directory =
+ &headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
+ RVAPtr<IMAGE_EXPORT_DIRECTORY> exports(module,
+ export_directory->VirtualAddress);
+ RVAPtr<DWORD> functions(module, exports->AddressOfFunctions);
+ RVAPtr<DWORD> names(module, exports->AddressOfNames);
+ RVAPtr<WORD> ordinals(module, exports->AddressOfNameOrdinals);
+
+ for (DWORD i = 0; i < exports->NumberOfNames; i++) {
+ RVAPtr<char> name(module, names[i]);
+ if (!strcmp(func_name, name)) {
+ DWORD index = ordinals[i];
+ RVAPtr<char> func(module, functions[index]);
+ return (uptr)(char *)func;
+ }
+ }
+
+ return 0;
}
static bool GetFunctionAddressInDLLs(const char *func_name, uptr *func_addr) {
*func_addr = 0;
- const void **DLLs = InterestingDLLsAvailable();
+ void **DLLs = InterestingDLLsAvailable();
for (size_t i = 0; *func_addr == 0 && DLLs[i]; ++i)
- *func_addr = (uptr)GetProcAddress((HMODULE)DLLs[i], func_name);
+ *func_addr = InternalGetProcAddress(DLLs[i], func_name);
return (*func_addr != 0);
}
diff --git a/contrib/compiler-rt/lib/interception/interception_win.h b/contrib/compiler-rt/lib/interception/interception_win.h
index ba768a7233f9..96c4a0c0f5a3 100644
--- a/contrib/compiler-rt/lib/interception/interception_win.h
+++ b/contrib/compiler-rt/lib/interception/interception_win.h
@@ -30,6 +30,10 @@ bool OverrideFunction(uptr old_func, uptr new_func, uptr *orig_old_func = 0);
// Overrides a function in a system DLL or DLL CRT by its exported name.
bool OverrideFunction(const char *name, uptr new_func, uptr *orig_old_func = 0);
+
+// Windows-only replacement for GetProcAddress. Useful for some sanitizers.
+uptr InternalGetProcAddress(void *module, const char *func_name);
+
} // namespace __interception
#if defined(INTERCEPTION_DYNAMIC_CRT)
diff --git a/contrib/compiler-rt/lib/lsan/lsan.cc b/contrib/compiler-rt/lib/lsan/lsan.cc
index 6018f7bf6f49..f3e6ad7c9cba 100644
--- a/contrib/compiler-rt/lib/lsan/lsan.cc
+++ b/contrib/compiler-rt/lib/lsan/lsan.cc
@@ -44,6 +44,7 @@ static void InitializeFlags() {
cf.external_symbolizer_path = GetEnv("LSAN_SYMBOLIZER_PATH");
cf.malloc_context_size = 30;
cf.detect_leaks = true;
+ cf.exitcode = 23;
OverrideCommonFlags(cf);
}
@@ -69,6 +70,7 @@ extern "C" void __lsan_init() {
return;
lsan_init_is_running = true;
SanitizerToolName = "LeakSanitizer";
+ CacheBinaryName();
InitializeFlags();
InitCommonLsan();
InitializeAllocator();
diff --git a/contrib/compiler-rt/lib/lsan/lsan_allocator.cc b/contrib/compiler-rt/lib/lsan/lsan_allocator.cc
index 67125dbb3e45..0a3678132ae1 100644
--- a/contrib/compiler-rt/lib/lsan/lsan_allocator.cc
+++ b/contrib/compiler-rt/lib/lsan/lsan_allocator.cc
@@ -26,13 +26,13 @@ extern "C" void *memset(void *ptr, int value, uptr num);
namespace __lsan {
struct ChunkMetadata {
- bool allocated : 8; // Must be first.
+ u8 allocated : 8; // Must be first.
ChunkTag tag : 2;
uptr requested_size : 54;
u32 stack_trace_id;
};
-#if defined(__mips64)
+#if defined(__mips64) || defined(__aarch64__)
static const uptr kMaxAllowedMallocSize = 4UL << 30;
static const uptr kRegionSizeLog = 20;
static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog;
@@ -91,7 +91,7 @@ void *Allocate(const StackTrace &stack, uptr size, uptr alignment,
size = 1;
if (size > kMaxAllowedMallocSize) {
Report("WARNING: LeakSanitizer failed to allocate %zu bytes\n", size);
- return 0;
+ return nullptr;
}
void *p = allocator.Allocate(&cache, size, alignment, false);
// Do not rely on the allocator to clear the memory (it's slow).
@@ -114,7 +114,7 @@ void *Reallocate(const StackTrace &stack, void *p, uptr new_size,
if (new_size > kMaxAllowedMallocSize) {
Report("WARNING: LeakSanitizer failed to allocate %zu bytes\n", new_size);
allocator.Deallocate(&cache, p);
- return 0;
+ return nullptr;
}
p = allocator.Reallocate(&cache, p, new_size, alignment);
RegisterAllocation(stack, p, new_size);
@@ -212,7 +212,7 @@ IgnoreObjectResult IgnoreObjectLocked(const void *p) {
return kIgnoreObjectInvalid;
}
}
-} // namespace __lsan
+} // namespace __lsan
using namespace __lsan;
@@ -241,10 +241,10 @@ SANITIZER_INTERFACE_ATTRIBUTE
uptr __sanitizer_get_estimated_allocated_size(uptr size) { return size; }
SANITIZER_INTERFACE_ATTRIBUTE
-int __sanitizer_get_ownership(const void *p) { return Metadata(p) != 0; }
+int __sanitizer_get_ownership(const void *p) { return Metadata(p) != nullptr; }
SANITIZER_INTERFACE_ATTRIBUTE
uptr __sanitizer_get_allocated_size(const void *p) {
return GetMallocUsableSize(p);
}
-} // extern "C"
+} // extern "C"
diff --git a/contrib/compiler-rt/lib/lsan/lsan_common.cc b/contrib/compiler-rt/lib/lsan/lsan_common.cc
index 0ffba505cc70..1cffac44395c 100644
--- a/contrib/compiler-rt/lib/lsan/lsan_common.cc
+++ b/contrib/compiler-rt/lib/lsan/lsan_common.cc
@@ -119,6 +119,10 @@ static inline bool CanBeAHeapPointer(uptr p) {
return ((p >> 47) == 0);
#elif defined(__mips64)
return ((p >> 40) == 0);
+#elif defined(__aarch64__)
+ unsigned runtimeVMA =
+ (MostSignificantSetBitIndex(GET_CURRENT_FRAME()) + 1);
+ return ((p >> runtimeVMA) == 0);
#else
return true;
#endif
@@ -243,8 +247,8 @@ static void ProcessRootRegion(Frontier *frontier, uptr root_begin,
MemoryMappingLayout proc_maps(/*cache_enabled*/true);
uptr begin, end, prot;
while (proc_maps.Next(&begin, &end,
- /*offset*/ 0, /*filename*/ 0, /*filename_size*/ 0,
- &prot)) {
+ /*offset*/ nullptr, /*filename*/ nullptr,
+ /*filename_size*/ 0, &prot)) {
uptr intersection_begin = Max(root_begin, begin);
uptr intersection_end = Min(end, root_end);
if (intersection_begin >= intersection_end) continue;
@@ -375,8 +379,8 @@ static void PrintMatchedSuppressions() {
Printf("Suppressions used:\n");
Printf(" count bytes template\n");
for (uptr i = 0; i < matched.size(); i++)
- Printf("%7zu %10zu %s\n", static_cast<uptr>(matched[i]->hit_count),
- matched[i]->weight, matched[i]->templ);
+ Printf("%7zu %10zu %s\n", static_cast<uptr>(atomic_load_relaxed(
+ &matched[i]->hit_count)), matched[i]->weight, matched[i]->templ);
Printf("%s\n\n", line);
}
@@ -444,10 +448,8 @@ void DoLeakCheck() {
if (!have_leaks) {
return;
}
- if (flags()->exitcode) {
- if (common_flags()->coverage)
- __sanitizer_cov_dump();
- internal__exit(flags()->exitcode);
+ if (common_flags()->exitcode) {
+ Die();
}
}
@@ -486,7 +488,7 @@ static Suppression *GetSuppressionForStack(u32 stack_trace_id) {
StackTrace::GetPreviousInstructionPc(stack.trace[i]));
if (s) return s;
}
- return 0;
+ return nullptr;
}
///// LeakReport implementation. /////
@@ -600,7 +602,8 @@ void LeakReport::ApplySuppressions() {
Suppression *s = GetSuppressionForStack(leaks_[i].stack_trace_id);
if (s) {
s->weight += leaks_[i].total_size;
- s->hit_count += leaks_[i].hit_count;
+ atomic_store_relaxed(&s->hit_count, atomic_load_relaxed(&s->hit_count) +
+ leaks_[i].hit_count);
leaks_[i].is_suppressed = true;
}
}
@@ -613,8 +616,8 @@ uptr LeakReport::UnsuppressedLeakCount() {
return result;
}
-} // namespace __lsan
-#endif // CAN_SANITIZE_LEAKS
+} // namespace __lsan
+#endif // CAN_SANITIZE_LEAKS
using namespace __lsan; // NOLINT
@@ -635,7 +638,7 @@ void __lsan_ignore_object(const void *p) {
"heap object at %p is already being ignored\n", p);
if (res == kIgnoreObjectSuccess)
VReport(1, "__lsan_ignore_object(): ignoring heap object at %p\n", p);
-#endif // CAN_SANITIZE_LEAKS
+#endif // CAN_SANITIZE_LEAKS
}
SANITIZER_INTERFACE_ATTRIBUTE
@@ -646,7 +649,7 @@ void __lsan_register_root_region(const void *begin, uptr size) {
RootRegion region = {begin, size};
root_regions->push_back(region);
VReport(1, "Registered root region at %p of size %llu\n", begin, size);
-#endif // CAN_SANITIZE_LEAKS
+#endif // CAN_SANITIZE_LEAKS
}
SANITIZER_INTERFACE_ATTRIBUTE
@@ -673,7 +676,7 @@ void __lsan_unregister_root_region(const void *begin, uptr size) {
begin, size);
Die();
}
-#endif // CAN_SANITIZE_LEAKS
+#endif // CAN_SANITIZE_LEAKS
}
SANITIZER_INTERFACE_ATTRIBUTE
@@ -699,7 +702,7 @@ void __lsan_do_leak_check() {
#if CAN_SANITIZE_LEAKS
if (common_flags()->detect_leaks)
__lsan::DoLeakCheck();
-#endif // CAN_SANITIZE_LEAKS
+#endif // CAN_SANITIZE_LEAKS
}
SANITIZER_INTERFACE_ATTRIBUTE
@@ -707,7 +710,7 @@ int __lsan_do_recoverable_leak_check() {
#if CAN_SANITIZE_LEAKS
if (common_flags()->detect_leaks)
return __lsan::DoRecoverableLeakCheck();
-#endif // CAN_SANITIZE_LEAKS
+#endif // CAN_SANITIZE_LEAKS
return 0;
}
@@ -717,4 +720,4 @@ int __lsan_is_turned_off() {
return 0;
}
#endif
-} // extern "C"
+} // extern "C"
diff --git a/contrib/compiler-rt/lib/lsan/lsan_common.h b/contrib/compiler-rt/lib/lsan/lsan_common.h
index 4f9d24fb3ab9..0dfd0d4c9890 100644
--- a/contrib/compiler-rt/lib/lsan/lsan_common.h
+++ b/contrib/compiler-rt/lib/lsan/lsan_common.h
@@ -22,8 +22,8 @@
#include "sanitizer_common/sanitizer_stoptheworld.h"
#include "sanitizer_common/sanitizer_symbolizer.h"
-#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__mips64)) \
- && (SANITIZER_WORDSIZE == 64)
+#if (SANITIZER_LINUX && !SANITIZER_ANDROID) && (SANITIZER_WORDSIZE == 64) \
+ && (defined(__x86_64__) || defined(__mips64) || defined(__aarch64__))
#define CAN_SANITIZE_LEAKS 1
#else
#define CAN_SANITIZE_LEAKS 0
diff --git a/contrib/compiler-rt/lib/lsan/lsan_common_linux.cc b/contrib/compiler-rt/lib/lsan/lsan_common_linux.cc
index 2955343e1f0b..1dc0561dab71 100644
--- a/contrib/compiler-rt/lib/lsan/lsan_common_linux.cc
+++ b/contrib/compiler-rt/lib/lsan/lsan_common_linux.cc
@@ -29,7 +29,7 @@ static const char kLinkerName[] = "ld";
// We request 2 modules matching "ld", so we can print a warning if there's more
// than one match. But only the first one is actually used.
static char linker_placeholder[2 * sizeof(LoadedModule)] ALIGNED(64);
-static LoadedModule *linker = 0;
+static LoadedModule *linker = nullptr;
static bool IsLinker(const char* full_name) {
return LibraryNameIs(full_name, kLinkerName);
@@ -49,7 +49,7 @@ void InitializePlatformSpecificModules() {
else if (num_matches > 1)
VReport(1, "LeakSanitizer: Multiple modules match \"%s\". "
"TLS will not be handled correctly.\n", kLinkerName);
- linker = 0;
+ linker = nullptr;
}
static int ProcessGlobalRegionsCallback(struct dl_phdr_info *info, size_t size,
@@ -174,5 +174,6 @@ void DoStopTheWorld(StopTheWorldCallback callback, void *argument) {
dl_iterate_phdr(DoStopTheWorldCallback, &param);
}
-} // namespace __lsan
-#endif // CAN_SANITIZE_LEAKS && SANITIZER_LINUX
+} // namespace __lsan
+
+#endif // CAN_SANITIZE_LEAKS && SANITIZER_LINUX
diff --git a/contrib/compiler-rt/lib/lsan/lsan_flags.inc b/contrib/compiler-rt/lib/lsan/lsan_flags.inc
index b19b3452b2fc..c405005deed5 100644
--- a/contrib/compiler-rt/lib/lsan/lsan_flags.inc
+++ b/contrib/compiler-rt/lib/lsan/lsan_flags.inc
@@ -24,8 +24,6 @@ LSAN_FLAG(
"Aggregate two objects into one leak if this many stack frames match. If "
"zero, the entire stack trace must match.")
LSAN_FLAG(int, max_leaks, 0, "The number of leaks reported.")
-LSAN_FLAG(int, exitcode, 23,
- "If nonzero kill the process with this exit code upon finding leaks.")
// Flags controlling the root set of reachable memory.
LSAN_FLAG(bool, use_globals, true,
diff --git a/contrib/compiler-rt/lib/lsan/lsan_interceptors.cc b/contrib/compiler-rt/lib/lsan/lsan_interceptors.cc
index 61a92154d95e..be0d0ddc282e 100644
--- a/contrib/compiler-rt/lib/lsan/lsan_interceptors.cc
+++ b/contrib/compiler-rt/lib/lsan/lsan_interceptors.cc
@@ -71,7 +71,7 @@ INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) {
CHECK(allocated < kCallocPoolSize);
return mem;
}
- if (CallocShouldReturnNullDueToOverflow(size, nmemb)) return 0;
+ if (CallocShouldReturnNullDueToOverflow(size, nmemb)) return nullptr;
ENSURE_LSAN_INITED;
GET_STACK_TRACE_MALLOC;
size *= nmemb;
@@ -164,9 +164,9 @@ void *operator new[](uptr size, std::nothrow_t const&) { OPERATOR_NEW_BODY; }
Deallocate(ptr);
INTERCEPTOR_ATTRIBUTE
-void operator delete(void *ptr) throw() { OPERATOR_DELETE_BODY; }
+void operator delete(void *ptr) NOEXCEPT { OPERATOR_DELETE_BODY; }
INTERCEPTOR_ATTRIBUTE
-void operator delete[](void *ptr) throw() { OPERATOR_DELETE_BODY; }
+void operator delete[](void *ptr) NOEXCEPT { OPERATOR_DELETE_BODY; }
INTERCEPTOR_ATTRIBUTE
void operator delete(void *ptr, std::nothrow_t const&) { OPERATOR_DELETE_BODY; }
INTERCEPTOR_ATTRIBUTE
@@ -226,7 +226,7 @@ INTERCEPTOR(int, pthread_create, void *th, void *attr,
ENSURE_LSAN_INITED;
EnsureMainThreadIDIsCorrect();
__sanitizer_pthread_attr_t myattr;
- if (attr == 0) {
+ if (!attr) {
pthread_attr_init(&myattr);
attr = &myattr;
}
@@ -284,4 +284,4 @@ void InitializeInterceptors() {
}
}
-} // namespace __lsan
+} // namespace __lsan
diff --git a/contrib/compiler-rt/lib/lsan/lsan_thread.cc b/contrib/compiler-rt/lib/lsan/lsan_thread.cc
index 0f8efc093b56..10ac2c9f499d 100644
--- a/contrib/compiler-rt/lib/lsan/lsan_thread.cc
+++ b/contrib/compiler-rt/lib/lsan/lsan_thread.cc
@@ -79,7 +79,7 @@ void ThreadContext::OnFinished() {
u32 ThreadCreate(u32 parent_tid, uptr user_id, bool detached) {
return thread_registry->CreateThread(user_id, detached, parent_tid,
- /* arg */ 0);
+ /* arg */ nullptr);
}
void ThreadStart(u32 tid, uptr os_id) {
@@ -99,9 +99,9 @@ void ThreadFinish() {
}
ThreadContext *CurrentThreadContext() {
- if (!thread_registry) return 0;
+ if (!thread_registry) return nullptr;
if (GetCurrentThread() == kInvalidTid)
- return 0;
+ return nullptr;
// No lock needed when getting current thread.
return (ThreadContext *)thread_registry->GetThreadLocked(GetCurrentThread());
}
@@ -120,7 +120,7 @@ u32 ThreadTid(uptr uid) {
void ThreadJoin(u32 tid) {
CHECK_NE(tid, kInvalidTid);
- thread_registry->JoinThread(tid, /* arg */0);
+ thread_registry->JoinThread(tid, /* arg */nullptr);
}
void EnsureMainThreadIDIsCorrect() {
@@ -157,4 +157,4 @@ void UnlockThreadRegistry() {
thread_registry->Unlock();
}
-} // namespace __lsan
+} // namespace __lsan
diff --git a/contrib/compiler-rt/lib/msan/msan.cc b/contrib/compiler-rt/lib/msan/msan.cc
index 163d59dabfa8..9949db4c13a0 100644
--- a/contrib/compiler-rt/lib/msan/msan.cc
+++ b/contrib/compiler-rt/lib/msan/msan.cc
@@ -55,7 +55,7 @@ SANITIZER_INTERFACE_ATTRIBUTE
THREADLOCAL u32 __msan_retval_origin_tls;
SANITIZER_INTERFACE_ATTRIBUTE
-THREADLOCAL u64 __msan_va_arg_tls[kMsanParamTlsSize / sizeof(u64)];
+ALIGNED(16) THREADLOCAL u64 __msan_va_arg_tls[kMsanParamTlsSize / sizeof(u64)];
SANITIZER_INTERFACE_ATTRIBUTE
THREADLOCAL u64 __msan_va_arg_overflow_size_tls;
@@ -90,8 +90,6 @@ bool msan_init_is_running;
int msan_report_count = 0;
-void (*death_callback)(void);
-
// Array of stack origins.
// FIXME: make it resizable.
static const uptr kNumStackOriginDescrs = 1024 * 1024;
@@ -145,6 +143,7 @@ static void InitializeFlags() {
// FIXME: test and enable.
cf.check_printf = false;
cf.intercept_tls_get_addr = true;
+ cf.exitcode = 77;
OverrideCommonFlags(cf);
}
@@ -185,11 +184,18 @@ static void InitializeFlags() {
if (common_flags()->help) parser.PrintFlagDescriptions();
- // Check flag values:
- if (f->exit_code < 0 || f->exit_code > 127) {
- Printf("Exit code not in [0, 128) range: %d\n", f->exit_code);
- Die();
+ // Check if deprecated exit_code MSan flag is set.
+ if (f->exit_code != -1) {
+ if (Verbosity())
+ Printf("MSAN_OPTIONS=exit_code is deprecated! "
+ "Please use MSAN_OPTIONS=exitcode instead.\n");
+ CommonFlags cf;
+ cf.CopyFrom(*common_flags());
+ cf.exitcode = f->exit_code;
+ OverrideCommonFlags(cf);
}
+
+ // Check flag values:
if (f->origin_history_size < 0 ||
f->origin_history_size > Origin::kMaxDepth) {
Printf(
@@ -217,9 +223,9 @@ void GetStackTrace(BufferedStackTrace *stack, uptr max_s, uptr pc, uptr bp,
if (!t || !StackTrace::WillUseFastUnwind(request_fast_unwind)) {
// Block reports from our interceptors during _Unwind_Backtrace.
SymbolizerScope sym_scope;
- return stack->Unwind(max_s, pc, bp, 0, 0, 0, request_fast_unwind);
+ return stack->Unwind(max_s, pc, bp, nullptr, 0, 0, request_fast_unwind);
}
- stack->Unwind(max_s, pc, bp, 0, t->stack_top(), t->stack_bottom(),
+ stack->Unwind(max_s, pc, bp, nullptr, t->stack_top(), t->stack_bottom(),
request_fast_unwind);
}
@@ -299,7 +305,7 @@ u32 ChainOrigin(u32 id, StackTrace *stack) {
return chained.raw_id();
}
-} // namespace __msan
+} // namespace __msan
// Interface.
@@ -369,11 +375,11 @@ void __msan_init() {
msan_init_is_running = 1;
SanitizerToolName = "MemorySanitizer";
- SetDieCallback(MsanDie);
InitTlsSize();
- InitializeFlags();
CacheBinaryName();
+ InitializeFlags();
+
__sanitizer_set_report_path(common_flags()->log_path);
InitializeInterceptors();
@@ -407,7 +413,9 @@ void __msan_init() {
MsanTSDInit(MsanTSDDtor);
- MsanThread *main_thread = MsanThread::Create(0, 0);
+ MsanAllocatorInit();
+
+ MsanThread *main_thread = MsanThread::Create(nullptr, nullptr);
SetCurrentThread(main_thread);
main_thread->ThreadStart();
@@ -421,10 +429,6 @@ void __msan_init() {
msan_inited = 1;
}
-void __msan_set_exit_code(int exit_code) {
- flags()->exit_code = exit_code;
-}
-
void __msan_set_keep_going(int keep_going) {
flags()->halt_on_error = !keep_going;
}
@@ -511,7 +515,7 @@ void __msan_partial_poison(const void* data, void* shadow, uptr size) {
internal_memcpy((void*)MEM_TO_SHADOW((uptr)data), shadow, size);
}
-void __msan_load_unpoisoned(void *src, uptr size, void *dst) {
+void __msan_load_unpoisoned(const void *src, uptr size, void *dst) {
internal_memcpy(dst, src, size);
__msan_unpoison(dst, size);
}
@@ -619,7 +623,7 @@ void __sanitizer_unaligned_store64(uu64 *p, u64 x) {
}
void __msan_set_death_callback(void (*callback)(void)) {
- death_callback = callback;
+ SetUserDieCallback(callback);
}
#if !SANITIZER_SUPPORTS_WEAK_HOOKS
@@ -635,4 +639,4 @@ void __sanitizer_print_stack_trace() {
GET_FATAL_STACK_TRACE_PC_BP(StackTrace::GetCurrentPc(), GET_CURRENT_FRAME());
stack.Print();
}
-} // extern "C"
+} // extern "C"
diff --git a/contrib/compiler-rt/lib/msan/msan.h b/contrib/compiler-rt/lib/msan/msan.h
index cd8bc19f51ef..2079a592b7b9 100644
--- a/contrib/compiler-rt/lib/msan/msan.h
+++ b/contrib/compiler-rt/lib/msan/msan.h
@@ -52,6 +52,61 @@ const MappingDesc kMemoryLayout[] = {
#define MEM_TO_SHADOW(mem) (((uptr)(mem)) & ~0x4000000000ULL)
#define SHADOW_TO_ORIGIN(shadow) (((uptr)(shadow)) + 0x002000000000)
+#elif SANITIZER_LINUX && defined(__aarch64__)
+
+// The mapping describes both 39-bits and 42-bits. AArch64 maps:
+// - 0x00000000000-0x00010000000: 39/42-bits program own segments
+// - 0x05500000000-0x05600000000: 39-bits PIE program segments
+// - 0x07f80000000-0x07fffffffff: 39-bits libraries segments
+// - 0x2aa00000000-0x2ab00000000: 42-bits PIE program segments
+// - 0x3ff00000000-0x3ffffffffff: 42-bits libraries segments
+// It is fragmented in multiples segments to increase the memory available
+// on 42-bits (12.21% of total VMA available for 42-bits and 13.28 for
+// 39 bits).
+const MappingDesc kMemoryLayout[] = {
+ {0x00000000000ULL, 0x01000000000ULL, MappingDesc::INVALID, "invalid"},
+ {0x01000000000ULL, 0x02000000000ULL, MappingDesc::SHADOW, "shadow-2"},
+ {0x02000000000ULL, 0x03000000000ULL, MappingDesc::ORIGIN, "origin-2"},
+ {0x03000000000ULL, 0x04000000000ULL, MappingDesc::SHADOW, "shadow-1"},
+ {0x04000000000ULL, 0x05000000000ULL, MappingDesc::ORIGIN, "origin-1"},
+ {0x05000000000ULL, 0x06000000000ULL, MappingDesc::APP, "app-1"},
+ {0x06000000000ULL, 0x07000000000ULL, MappingDesc::INVALID, "invalid"},
+ {0x07000000000ULL, 0x08000000000ULL, MappingDesc::APP, "app-2"},
+ {0x08000000000ULL, 0x09000000000ULL, MappingDesc::INVALID, "invalid"},
+ // The mappings below are used only for 42-bits VMA.
+ {0x09000000000ULL, 0x0A000000000ULL, MappingDesc::SHADOW, "shadow-3"},
+ {0x0A000000000ULL, 0x0B000000000ULL, MappingDesc::ORIGIN, "origin-3"},
+ {0x0B000000000ULL, 0x0F000000000ULL, MappingDesc::INVALID, "invalid"},
+ {0x0F000000000ULL, 0x10000000000ULL, MappingDesc::APP, "app-3"},
+ {0x10000000000ULL, 0x11000000000ULL, MappingDesc::INVALID, "invalid"},
+ {0x11000000000ULL, 0x12000000000ULL, MappingDesc::APP, "app-4"},
+ {0x12000000000ULL, 0x17000000000ULL, MappingDesc::INVALID, "invalid"},
+ {0x17000000000ULL, 0x18000000000ULL, MappingDesc::SHADOW, "shadow-4"},
+ {0x18000000000ULL, 0x19000000000ULL, MappingDesc::ORIGIN, "origin-4"},
+ {0x19000000000ULL, 0x20000000000ULL, MappingDesc::INVALID, "invalid"},
+ {0x20000000000ULL, 0x21000000000ULL, MappingDesc::APP, "app-5"},
+ {0x21000000000ULL, 0x26000000000ULL, MappingDesc::INVALID, "invalid"},
+ {0x26000000000ULL, 0x27000000000ULL, MappingDesc::SHADOW, "shadow-5"},
+ {0x27000000000ULL, 0x28000000000ULL, MappingDesc::ORIGIN, "origin-5"},
+ {0x28000000000ULL, 0x29000000000ULL, MappingDesc::SHADOW, "shadow-7"},
+ {0x29000000000ULL, 0x2A000000000ULL, MappingDesc::ORIGIN, "origin-7"},
+ {0x2A000000000ULL, 0x2B000000000ULL, MappingDesc::APP, "app-6"},
+ {0x2B000000000ULL, 0x2C000000000ULL, MappingDesc::INVALID, "invalid"},
+ {0x2C000000000ULL, 0x2D000000000ULL, MappingDesc::SHADOW, "shadow-6"},
+ {0x2D000000000ULL, 0x2E000000000ULL, MappingDesc::ORIGIN, "origin-6"},
+ {0x2E000000000ULL, 0x2F000000000ULL, MappingDesc::APP, "app-7"},
+ {0x2F000000000ULL, 0x39000000000ULL, MappingDesc::INVALID, "invalid"},
+ {0x39000000000ULL, 0x3A000000000ULL, MappingDesc::SHADOW, "shadow-9"},
+ {0x3A000000000ULL, 0x3B000000000ULL, MappingDesc::ORIGIN, "origin-9"},
+ {0x3B000000000ULL, 0x3C000000000ULL, MappingDesc::APP, "app-8"},
+ {0x3C000000000ULL, 0x3D000000000ULL, MappingDesc::INVALID, "invalid"},
+ {0x3D000000000ULL, 0x3E000000000ULL, MappingDesc::SHADOW, "shadow-8"},
+ {0x3E000000000ULL, 0x3F000000000ULL, MappingDesc::ORIGIN, "origin-8"},
+ {0x3F000000000ULL, 0x40000000000ULL, MappingDesc::APP, "app-9"},
+};
+# define MEM_TO_SHADOW(mem) ((uptr)mem ^ 0x6000000000ULL)
+# define SHADOW_TO_ORIGIN(shadow) (((uptr)(shadow)) + 0x1000000000ULL)
+
#elif SANITIZER_LINUX && defined(__powerpc64__)
const MappingDesc kMemoryLayout[] = {
@@ -94,6 +149,7 @@ const MappingDesc kMemoryLayout[] = {
#elif SANITIZER_LINUX && SANITIZER_WORDSIZE == 64
+#ifdef MSAN_LINUX_X86_64_OLD_MAPPING
// Requries PIE binary and ASLR enabled.
// Main thread stack and DSOs at 0x7f0000000000 (sometimes 0x7e0000000000).
// Heap at 0x600000000000.
@@ -105,6 +161,28 @@ const MappingDesc kMemoryLayout[] = {
#define MEM_TO_SHADOW(mem) (((uptr)(mem)) & ~0x400000000000ULL)
#define SHADOW_TO_ORIGIN(mem) (((uptr)(mem)) + 0x200000000000ULL)
+#else // MSAN_LINUX_X86_64_OLD_MAPPING
+// All of the following configurations are supported.
+// ASLR disabled: main executable and DSOs at 0x555550000000
+// PIE and ASLR: main executable and DSOs at 0x7f0000000000
+// non-PIE: main executable below 0x100000000, DSOs at 0x7f0000000000
+// Heap at 0x700000000000.
+const MappingDesc kMemoryLayout[] = {
+ {0x000000000000ULL, 0x010000000000ULL, MappingDesc::APP, "app-1"},
+ {0x010000000000ULL, 0x100000000000ULL, MappingDesc::SHADOW, "shadow-2"},
+ {0x100000000000ULL, 0x110000000000ULL, MappingDesc::INVALID, "invalid"},
+ {0x110000000000ULL, 0x200000000000ULL, MappingDesc::ORIGIN, "origin-2"},
+ {0x200000000000ULL, 0x300000000000ULL, MappingDesc::SHADOW, "shadow-3"},
+ {0x300000000000ULL, 0x400000000000ULL, MappingDesc::ORIGIN, "origin-3"},
+ {0x400000000000ULL, 0x500000000000ULL, MappingDesc::INVALID, "invalid"},
+ {0x500000000000ULL, 0x510000000000ULL, MappingDesc::SHADOW, "shadow-1"},
+ {0x510000000000ULL, 0x600000000000ULL, MappingDesc::APP, "app-2"},
+ {0x600000000000ULL, 0x610000000000ULL, MappingDesc::ORIGIN, "origin-1"},
+ {0x610000000000ULL, 0x700000000000ULL, MappingDesc::INVALID, "invalid"},
+ {0x700000000000ULL, 0x800000000000ULL, MappingDesc::APP, "app-3"}};
+#define MEM_TO_SHADOW(mem) (((uptr)(mem)) ^ 0x500000000000ULL)
+#define SHADOW_TO_ORIGIN(mem) (((uptr)(mem)) + 0x100000000000ULL)
+#endif // MSAN_LINUX_X86_64_OLD_MAPPING
#else
#error "Unsupported platform"
@@ -148,6 +226,7 @@ bool InitShadow(bool init_origins);
char *GetProcSelfMaps();
void InitializeInterceptors();
+void MsanAllocatorInit();
void MsanAllocatorThreadFinish();
void *MsanCalloc(StackTrace *stack, uptr nmemb, uptr size);
void *MsanReallocate(StackTrace *stack, void *oldp, uptr size,
@@ -167,7 +246,6 @@ struct SymbolizerScope {
~SymbolizerScope() { ExitSymbolizer(); }
};
-void MsanDie();
void PrintWarning(uptr pc, uptr bp);
void PrintWarningWithOrigin(uptr pc, uptr bp, u32 origin);
@@ -224,8 +302,6 @@ class ScopedThreadLocalStateBackup {
u64 va_arg_overflow_size_tls;
};
-extern void (*death_callback)(void);
-
void MsanTSDInit(void (*destructor)(void *tsd));
void *MsanTSDGet();
void MsanTSDSet(void *tsd);
diff --git a/contrib/compiler-rt/lib/msan/msan_allocator.cc b/contrib/compiler-rt/lib/msan/msan_allocator.cc
index 6df35664279f..b7d394729bfc 100644
--- a/contrib/compiler-rt/lib/msan/msan_allocator.cc
+++ b/contrib/compiler-rt/lib/msan/msan_allocator.cc
@@ -49,15 +49,21 @@ struct MsanMapUnmapCallback {
typedef SizeClassAllocator32<0, SANITIZER_MMAP_RANGE_SIZE, sizeof(Metadata),
SizeClassMap, kRegionSizeLog, ByteMap,
MsanMapUnmapCallback> PrimaryAllocator;
+
#elif defined(__x86_64__)
+#if SANITIZER_LINUX && !defined(MSAN_LINUX_X86_64_OLD_MAPPING)
+ static const uptr kAllocatorSpace = 0x700000000000ULL;
+#else
static const uptr kAllocatorSpace = 0x600000000000ULL;
- static const uptr kAllocatorSize = 0x80000000000; // 8T.
+#endif
+ static const uptr kAllocatorSize = 0x80000000000; // 8T.
static const uptr kMetadataSize = sizeof(Metadata);
static const uptr kMaxAllowedMallocSize = 8UL << 30;
typedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize, kMetadataSize,
DefaultSizeClassMap,
MsanMapUnmapCallback> PrimaryAllocator;
+
#elif defined(__powerpc64__)
static const uptr kAllocatorSpace = 0x300000000000;
static const uptr kAllocatorSize = 0x020000000000; // 2T
@@ -67,6 +73,16 @@ struct MsanMapUnmapCallback {
typedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize, kMetadataSize,
DefaultSizeClassMap,
MsanMapUnmapCallback> PrimaryAllocator;
+#elif defined(__aarch64__)
+ 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;
+ typedef CompactSizeClassMap SizeClassMap;
+
+ typedef SizeClassAllocator32<0, SANITIZER_MMAP_RANGE_SIZE, sizeof(Metadata),
+ SizeClassMap, kRegionSizeLog, ByteMap,
+ MsanMapUnmapCallback> PrimaryAllocator;
#endif
typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache;
typedef LargeMmapAllocator<MsanMapUnmapCallback> SecondaryAllocator;
@@ -77,12 +93,7 @@ static Allocator allocator;
static AllocatorCache fallback_allocator_cache;
static SpinMutex fallback_mutex;
-static int inited = 0;
-
-static inline void Init() {
- if (inited) return;
- __msan_init();
- inited = true; // this must happen before any threads are created.
+void MsanAllocatorInit() {
allocator.Init(common_flags()->allocator_may_return_null);
}
@@ -98,7 +109,6 @@ void MsanThreadLocalMallocStorage::CommitBack() {
static void *MsanAllocate(StackTrace *stack, uptr size, uptr alignment,
bool zeroise) {
- Init();
if (size > kMaxAllowedMallocSize) {
Report("WARNING: MemorySanitizer failed to allocate %p bytes\n",
(void *)size);
@@ -133,7 +143,6 @@ static void *MsanAllocate(StackTrace *stack, uptr size, uptr alignment,
void MsanDeallocate(StackTrace *stack, void *p) {
CHECK(p);
- Init();
MSAN_FREE_HOOK(p);
Metadata *meta = reinterpret_cast<Metadata *>(allocator.GetMetaData(p));
uptr size = meta->requested_size;
@@ -160,10 +169,9 @@ void MsanDeallocate(StackTrace *stack, void *p) {
}
void *MsanCalloc(StackTrace *stack, uptr nmemb, uptr size) {
- Init();
if (CallocShouldReturnNullDueToOverflow(size, nmemb))
return allocator.ReturnNullOrDie();
- return MsanReallocate(stack, 0, nmemb * size, sizeof(u64), true);
+ return MsanReallocate(stack, nullptr, nmemb * size, sizeof(u64), true);
}
void *MsanReallocate(StackTrace *stack, void *old_p, uptr new_size,
@@ -172,7 +180,7 @@ void *MsanReallocate(StackTrace *stack, void *old_p, uptr new_size,
return MsanAllocate(stack, new_size, alignment, zeroise);
if (!new_size) {
MsanDeallocate(stack, old_p);
- return 0;
+ return nullptr;
}
Metadata *meta = reinterpret_cast<Metadata*>(allocator.GetMetaData(old_p));
uptr old_size = meta->requested_size;
@@ -202,14 +210,14 @@ void *MsanReallocate(StackTrace *stack, void *old_p, uptr new_size,
}
static uptr AllocationSize(const void *p) {
- if (p == 0) return 0;
+ if (!p) return 0;
const void *beg = allocator.GetBlockBegin(p);
if (beg != p) return 0;
Metadata *b = (Metadata *)allocator.GetMetaData(p);
return b->requested_size;
}
-} // namespace __msan
+} // namespace __msan
using namespace __msan;
diff --git a/contrib/compiler-rt/lib/msan/msan_chained_origin_depot.cc b/contrib/compiler-rt/lib/msan/msan_chained_origin_depot.cc
index c21e8e82746a..e2796fd46464 100644
--- a/contrib/compiler-rt/lib/msan/msan_chained_origin_depot.cc
+++ b/contrib/compiler-rt/lib/msan/msan_chained_origin_depot.cc
@@ -28,12 +28,15 @@ struct ChainedOriginDepotNode {
u32 prev_id;
typedef ChainedOriginDepotDesc args_type;
+
bool eq(u32 hash, const args_type &args) const {
return here_id == args.here_id && prev_id == args.prev_id;
}
+
static uptr storage_size(const args_type &args) {
return sizeof(ChainedOriginDepotNode);
}
+
/* This is murmur2 hash for the 64->32 bit case.
It does not behave all that well because the keys have a very biased
distribution (I've seen 7-element buckets with the table only 14% full).
@@ -76,19 +79,22 @@ struct ChainedOriginDepotNode {
here_id = args.here_id;
prev_id = args.prev_id;
}
+
args_type load() const {
args_type ret = {here_id, prev_id};
return ret;
}
+
struct Handle {
ChainedOriginDepotNode *node_;
- Handle() : node_(0) {}
+ Handle() : node_(nullptr) {}
explicit Handle(ChainedOriginDepotNode *node) : node_(node) {}
bool valid() { return node_; }
u32 id() { return node_->id; }
int here_id() { return node_->here_id; }
int prev_id() { return node_->prev_id; }
};
+
Handle get_handle() { return Handle(this); }
typedef Handle handle_type;
@@ -123,4 +129,4 @@ void ChainedOriginDepotUnlockAll() {
chainedOriginDepot.UnlockAll();
}
-} // namespace __msan
+} // namespace __msan
diff --git a/contrib/compiler-rt/lib/msan/msan_flags.inc b/contrib/compiler-rt/lib/msan/msan_flags.inc
index cb58ffc4aba7..a7ff6c586071 100644
--- a/contrib/compiler-rt/lib/msan/msan_flags.inc
+++ b/contrib/compiler-rt/lib/msan/msan_flags.inc
@@ -17,13 +17,15 @@
// MSAN_FLAG(Type, Name, DefaultValue, Description)
// See COMMON_FLAG in sanitizer_flags.inc for more details.
-MSAN_FLAG(int, exit_code, 77, "")
+MSAN_FLAG(int, exit_code, -1,
+ "DEPRECATED. Use exitcode from common flags instead.")
MSAN_FLAG(int, origin_history_size, Origin::kMaxDepth, "")
MSAN_FLAG(int, origin_history_per_stack_limit, 20000, "")
MSAN_FLAG(bool, poison_heap_with_zeroes, false, "")
MSAN_FLAG(bool, poison_stack_with_zeroes, false, "")
MSAN_FLAG(bool, poison_in_malloc, true, "")
MSAN_FLAG(bool, poison_in_free, true, "")
+MSAN_FLAG(bool, poison_in_dtor, false, "")
MSAN_FLAG(bool, report_umrs, true, "")
MSAN_FLAG(bool, wrap_signals, true, "")
MSAN_FLAG(bool, print_stats, false, "")
diff --git a/contrib/compiler-rt/lib/msan/msan_interceptors.cc b/contrib/compiler-rt/lib/msan/msan_interceptors.cc
index 6d5a056a3bb3..fc28e080f262 100644
--- a/contrib/compiler-rt/lib/msan/msan_interceptors.cc
+++ b/contrib/compiler-rt/lib/msan/msan_interceptors.cc
@@ -166,7 +166,7 @@ INTERCEPTOR(int, posix_memalign, void **memptr, SIZE_T alignment, SIZE_T size) {
GET_MALLOC_STACK_TRACE;
CHECK_EQ(alignment & (alignment - 1), 0);
CHECK_NE(memptr, 0);
- *memptr = MsanReallocate(&stack, 0, size, alignment, false);
+ *memptr = MsanReallocate(&stack, nullptr, size, alignment, false);
CHECK_NE(*memptr, 0);
__msan_unpoison(memptr, sizeof(*memptr));
return 0;
@@ -176,7 +176,7 @@ INTERCEPTOR(int, posix_memalign, void **memptr, SIZE_T alignment, SIZE_T size) {
INTERCEPTOR(void *, memalign, SIZE_T boundary, SIZE_T size) {
GET_MALLOC_STACK_TRACE;
CHECK_EQ(boundary & (boundary - 1), 0);
- void *ptr = MsanReallocate(&stack, 0, size, boundary, false);
+ void *ptr = MsanReallocate(&stack, nullptr, size, boundary, false);
return ptr;
}
#define MSAN_MAYBE_INTERCEPT_MEMALIGN INTERCEPT_FUNCTION(memalign)
@@ -187,21 +187,21 @@ INTERCEPTOR(void *, memalign, SIZE_T boundary, SIZE_T size) {
INTERCEPTOR(void *, aligned_alloc, SIZE_T boundary, SIZE_T size) {
GET_MALLOC_STACK_TRACE;
CHECK_EQ(boundary & (boundary - 1), 0);
- void *ptr = MsanReallocate(&stack, 0, size, boundary, false);
+ void *ptr = MsanReallocate(&stack, nullptr, size, boundary, false);
return ptr;
}
INTERCEPTOR(void *, __libc_memalign, SIZE_T boundary, SIZE_T size) {
GET_MALLOC_STACK_TRACE;
CHECK_EQ(boundary & (boundary - 1), 0);
- void *ptr = MsanReallocate(&stack, 0, size, boundary, false);
+ void *ptr = MsanReallocate(&stack, nullptr, size, boundary, false);
DTLS_on_libc_memalign(ptr, size * boundary);
return ptr;
}
INTERCEPTOR(void *, valloc, SIZE_T size) {
GET_MALLOC_STACK_TRACE;
- void *ptr = MsanReallocate(&stack, 0, size, GetPageSizeCached(), false);
+ void *ptr = MsanReallocate(&stack, nullptr, size, GetPageSizeCached(), false);
return ptr;
}
@@ -214,7 +214,7 @@ INTERCEPTOR(void *, pvalloc, SIZE_T size) {
// pvalloc(0) should allocate one page.
size = PageSize;
}
- void *ptr = MsanReallocate(&stack, 0, size, PageSize, false);
+ void *ptr = MsanReallocate(&stack, nullptr, size, PageSize, false);
return ptr;
}
#define MSAN_MAYBE_INTERCEPT_PVALLOC INTERCEPT_FUNCTION(pvalloc)
@@ -224,14 +224,14 @@ INTERCEPTOR(void *, pvalloc, SIZE_T size) {
INTERCEPTOR(void, free, void *ptr) {
GET_MALLOC_STACK_TRACE;
- if (ptr == 0) return;
+ if (!ptr) return;
MsanDeallocate(&stack, ptr);
}
#if !SANITIZER_FREEBSD
INTERCEPTOR(void, cfree, void *ptr) {
GET_MALLOC_STACK_TRACE;
- if (ptr == 0) return;
+ if (!ptr) return;
MsanDeallocate(&stack, ptr);
}
#define MSAN_MAYBE_INTERCEPT_CFREE INTERCEPT_FUNCTION(cfree)
@@ -245,9 +245,15 @@ INTERCEPTOR(uptr, malloc_usable_size, void *ptr) {
#if !SANITIZER_FREEBSD
// This function actually returns a struct by value, but we can't unpoison a
-// temporary! The following is equivalent on all supported platforms, and we
-// have a test to confirm that.
+// 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));
__msan_unpoison(sret, sizeof(*sret));
}
@@ -994,7 +1000,7 @@ INTERCEPTOR(void *, realloc, void *ptr, SIZE_T size) {
INTERCEPTOR(void *, malloc, SIZE_T size) {
GET_MALLOC_STACK_TRACE;
- return MsanReallocate(&stack, 0, size, sizeof(u64), false);
+ return MsanReallocate(&stack, nullptr, size, sizeof(u64), false);
}
void __msan_allocated_memory(const void *data, uptr size) {
@@ -1005,6 +1011,19 @@ void __msan_allocated_memory(const void *data, uptr size) {
}
}
+void __msan_copy_shadow(void *dest, const void *src, uptr n) {
+ GET_STORE_STACK_TRACE;
+ MoveShadowAndOrigin(dest, src, n, &stack);
+}
+
+void __sanitizer_dtor_callback(const void *data, uptr size) {
+ GET_MALLOC_STACK_TRACE;
+ if (flags()->poison_in_dtor) {
+ stack.tag = STACK_TRACE_TAG_POISON;
+ PoisonMemory(data, size, &stack);
+ }
+}
+
INTERCEPTOR(void *, mmap, void *addr, SIZE_T length, int prot, int flags,
int fd, OFF_T offset) {
if (msan_init_is_running)
@@ -1015,7 +1034,7 @@ INTERCEPTOR(void *, mmap, void *addr, SIZE_T length, int prot, int flags,
*__errno_location() = errno_EINVAL;
return (void *)-1;
} else {
- addr = 0;
+ addr = nullptr;
}
}
void *res = REAL(mmap)(addr, length, prot, flags, fd, offset);
@@ -1033,7 +1052,7 @@ INTERCEPTOR(void *, mmap64, void *addr, SIZE_T length, int prot, int flags,
*__errno_location() = errno_EINVAL;
return (void *)-1;
} else {
- addr = 0;
+ addr = nullptr;
}
}
void *res = REAL(mmap64)(addr, length, prot, flags, fd, offset);
@@ -1069,7 +1088,7 @@ INTERCEPTOR(int, dladdr, void *addr, dlinfo *info) {
INTERCEPTOR(char *, dlerror, int fake) {
ENSURE_MSAN_INITED();
char *res = REAL(dlerror)(fake);
- if (res != 0) __msan_unpoison(res, REAL(strlen)(res) + 1);
+ if (res) __msan_unpoison(res, REAL(strlen)(res) + 1);
return res;
}
@@ -1084,6 +1103,8 @@ static int msan_dl_iterate_phdr_cb(__sanitizer_dl_phdr_info *info, SIZE_T size,
void *data) {
if (info) {
__msan_unpoison(info, size);
+ if (info->dlpi_phdr && info->dlpi_phnum)
+ __msan_unpoison(info->dlpi_phdr, struct_ElfW_Phdr_sz * info->dlpi_phnum);
if (info->dlpi_name)
__msan_unpoison(info->dlpi_name, REAL(strlen)(info->dlpi_name) + 1);
}
@@ -1164,7 +1185,7 @@ INTERCEPTOR(int, sigaction, int signo, const __sanitizer_sigaction *act,
CHECK_LT(signo, kMaxSignals);
uptr old_cb = atomic_load(&sigactions[signo], memory_order_relaxed);
__sanitizer_sigaction new_act;
- __sanitizer_sigaction *pnew_act = act ? &new_act : 0;
+ __sanitizer_sigaction *pnew_act = act ? &new_act : nullptr;
if (act) {
REAL(memcpy)(pnew_act, act, sizeof(__sanitizer_sigaction));
uptr cb = (uptr)pnew_act->sigaction;
@@ -1221,7 +1242,7 @@ INTERCEPTOR(int, pthread_create, void *th, void *attr, void *(*callback)(void*),
void * param) {
ENSURE_MSAN_INITED(); // for GetTlsSize()
__sanitizer_pthread_attr_t myattr;
- if (attr == 0) {
+ if (!attr) {
pthread_attr_init(&myattr);
attr = &myattr;
}
@@ -1327,6 +1348,28 @@ INTERCEPTOR(int, fork, void) {
return pid;
}
+INTERCEPTOR(int, openpty, int *amaster, int *aslave, char *name,
+ const void *termp, const void *winp) {
+ ENSURE_MSAN_INITED();
+ InterceptorScope interceptor_scope;
+ int res = REAL(openpty)(amaster, aslave, name, termp, winp);
+ if (!res) {
+ __msan_unpoison(amaster, sizeof(*amaster));
+ __msan_unpoison(aslave, sizeof(*aslave));
+ }
+ return res;
+}
+
+INTERCEPTOR(int, forkpty, int *amaster, char *name, const void *termp,
+ const void *winp) {
+ ENSURE_MSAN_INITED();
+ InterceptorScope interceptor_scope;
+ int res = REAL(forkpty)(amaster, name, termp, winp);
+ if (res != -1)
+ __msan_unpoison(amaster, sizeof(*amaster));
+ return res;
+}
+
struct MSanInterceptorContext {
bool in_interceptor_scope;
};
@@ -1338,7 +1381,7 @@ int OnExit() {
return 0;
}
-} // namespace __msan
+} // namespace __msan
// A version of CHECK_UNPOISONED using a saved scope value. Used in common
// interceptors.
@@ -1391,10 +1434,11 @@ int OnExit() {
} while (false) // FIXME
#define COMMON_INTERCEPTOR_BLOCK_REAL(name) REAL(name)
#define COMMON_INTERCEPTOR_ON_EXIT(ctx) OnExit()
-#define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, handle) \
- do { \
- link_map *map = GET_LINK_MAP_BY_DLOPEN_HANDLE((handle)); \
- if (map) ForEachMappedRegion(map, __msan_unpoison); \
+#define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, handle) \
+ do { \
+ link_map *map = GET_LINK_MAP_BY_DLOPEN_HANDLE((handle)); \
+ if (filename && map) \
+ ForEachMappedRegion(map, __msan_unpoison); \
} while (false)
#define COMMON_INTERCEPTOR_GET_TLS_RANGE(begin, end) \
@@ -1591,7 +1635,9 @@ void InitializeInterceptors() {
INTERCEPT_FUNCTION(__cxa_atexit);
INTERCEPT_FUNCTION(shmat);
INTERCEPT_FUNCTION(fork);
+ INTERCEPT_FUNCTION(openpty);
+ INTERCEPT_FUNCTION(forkpty);
inited = 1;
}
-} // namespace __msan
+} // namespace __msan
diff --git a/contrib/compiler-rt/lib/msan/msan_interface_internal.h b/contrib/compiler-rt/lib/msan/msan_interface_internal.h
index f4d37d96c5b5..c1e02ce72bf4 100644
--- a/contrib/compiler-rt/lib/msan/msan_interface_internal.h
+++ b/contrib/compiler-rt/lib/msan/msan_interface_internal.h
@@ -27,7 +27,7 @@ SANITIZER_INTERFACE_ATTRIBUTE
void __msan_init();
// Print a warning and maybe return.
-// This function can die based on flags()->exit_code.
+// This function can die based on common_flags()->exitcode.
SANITIZER_INTERFACE_ATTRIBUTE
void __msan_warning();
@@ -106,10 +106,6 @@ int __msan_origin_is_descendant_or_same(u32 this_id, u32 prev_id);
SANITIZER_INTERFACE_ATTRIBUTE
void __msan_clear_on_return();
-// Default: -1 (don't exit on error).
-SANITIZER_INTERFACE_ATTRIBUTE
-void __msan_set_exit_code(int exit_code);
-
SANITIZER_INTERFACE_ATTRIBUTE
void __msan_set_keep_going(int keep_going);
@@ -140,6 +136,11 @@ void __msan_partial_poison(const void* data, void* shadow, uptr size);
SANITIZER_INTERFACE_ATTRIBUTE
void __msan_allocated_memory(const void* data, uptr size);
+// Tell MSan about newly destroyed memory. Memory will be marked
+// uninitialized.
+SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_dtor_callback(const void* data, uptr size);
+
SANITIZER_INTERFACE_ATTRIBUTE
u16 __sanitizer_unaligned_load16(const uu16 *p);
@@ -160,6 +161,9 @@ void __sanitizer_unaligned_store64(uu64 *p, u64 x);
SANITIZER_INTERFACE_ATTRIBUTE
void __msan_set_death_callback(void (*callback)(void));
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_copy_shadow(void *dst, const void *src, uptr size);
} // extern "C"
#endif // MSAN_INTERFACE_INTERNAL_H
diff --git a/contrib/compiler-rt/lib/msan/msan_linux.cc b/contrib/compiler-rt/lib/msan/msan_linux.cc
index 7025ef6c812d..ab3be91fcf8d 100644
--- a/contrib/compiler-rt/lib/msan/msan_linux.cc
+++ b/contrib/compiler-rt/lib/msan/msan_linux.cc
@@ -56,7 +56,7 @@ static bool CheckMemoryRangeAvailability(uptr beg, uptr size) {
static bool ProtectMemoryRange(uptr beg, uptr size, const char *name) {
if (size > 0) {
void *addr = MmapNoAccess(beg, size, name);
- if (beg == 0 && addr != 0) {
+ if (beg == 0 && addr) {
// Depending on the kernel configuration, we may not be able to protect
// the page at address zero.
uptr gap = 16 * GetPageSizeCached();
@@ -119,12 +119,18 @@ bool InitShadow(bool init_origins) {
return false;
}
+ const uptr maxVirtualAddress = GetMaxVirtualAddress();
+
for (unsigned i = 0; i < kMemoryLayoutSize; ++i) {
uptr start = kMemoryLayout[i].start;
uptr end = kMemoryLayout[i].end;
uptr size= end - start;
MappingDesc::Type type = kMemoryLayout[i].type;
+ // Check if the segment should be mapped based on platform constraints.
+ if (start >= maxVirtualAddress)
+ continue;
+
bool map = type == MappingDesc::SHADOW ||
(init_origins && type == MappingDesc::ORIGIN);
bool protect = type == MappingDesc::INVALID ||
@@ -151,20 +157,13 @@ bool InitShadow(bool init_origins) {
return true;
}
-void MsanDie() {
- if (common_flags()->coverage)
- __sanitizer_cov_dump();
- if (death_callback)
- death_callback();
- internal__exit(flags()->exit_code);
-}
-
static void MsanAtExit(void) {
if (flags()->print_stats && (flags()->atexit || msan_report_count > 0))
ReportStats();
if (msan_report_count > 0) {
ReportAtExitStatistics();
- if (flags()->exit_code) _exit(flags()->exit_code);
+ if (common_flags()->exitcode)
+ internal__exit(common_flags()->exitcode);
}
}
@@ -211,6 +210,6 @@ void MsanTSDDtor(void *tsd) {
MsanThread::TSDDtor(tsd);
}
-} // namespace __msan
+} // namespace __msan
-#endif // SANITIZER_FREEBSD || SANITIZER_LINUX
+#endif // SANITIZER_FREEBSD || SANITIZER_LINUX
diff --git a/contrib/compiler-rt/lib/msan/msan_new_delete.cc b/contrib/compiler-rt/lib/msan/msan_new_delete.cc
index c8bc0651b507..540100316693 100644
--- a/contrib/compiler-rt/lib/msan/msan_new_delete.cc
+++ b/contrib/compiler-rt/lib/msan/msan_new_delete.cc
@@ -45,9 +45,9 @@ void *operator new[](size_t size, std::nothrow_t const&) { OPERATOR_NEW_BODY; }
if (ptr) MsanDeallocate(&stack, ptr)
INTERCEPTOR_ATTRIBUTE
-void operator delete(void *ptr) throw() { OPERATOR_DELETE_BODY; }
+void operator delete(void *ptr) NOEXCEPT { OPERATOR_DELETE_BODY; }
INTERCEPTOR_ATTRIBUTE
-void operator delete[](void *ptr) throw() { OPERATOR_DELETE_BODY; }
+void operator delete[](void *ptr) NOEXCEPT { OPERATOR_DELETE_BODY; }
INTERCEPTOR_ATTRIBUTE
void operator delete(void *ptr, std::nothrow_t const&) { OPERATOR_DELETE_BODY; }
INTERCEPTOR_ATTRIBUTE
diff --git a/contrib/compiler-rt/lib/msan/msan_thread.h b/contrib/compiler-rt/lib/msan/msan_thread.h
index bc605b89a505..ed22e67edd50 100644
--- a/contrib/compiler-rt/lib/msan/msan_thread.h
+++ b/contrib/compiler-rt/lib/msan/msan_thread.h
@@ -32,7 +32,7 @@ class MsanThread {
uptr stack_bottom() { return stack_bottom_; }
uptr tls_begin() { return tls_begin_; }
uptr tls_end() { return tls_end_; }
- bool IsMainThread() { return start_routine_ == 0; }
+ bool IsMainThread() { return start_routine_ == nullptr; }
bool AddrIsInStack(uptr addr) {
return addr >= stack_bottom_ && addr < stack_top_;
diff --git a/contrib/compiler-rt/lib/msan/tests/msan_loadable.cc b/contrib/compiler-rt/lib/msan/tests/msan_loadable.cc
deleted file mode 100644
index 06e880f90dee..000000000000
--- a/contrib/compiler-rt/lib/msan/tests/msan_loadable.cc
+++ /dev/null
@@ -1,27 +0,0 @@
-//===-- msan_loadable.cc --------------------------------------------------===//
-//
-// 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 MemorySanitizer.
-//
-// MemorySanitizer unit tests.
-//===----------------------------------------------------------------------===//
-
-#include "msan/msan_interface_internal.h"
-#include <stdlib.h>
-
-static void *dso_global;
-
-// No name mangling.
-extern "C" {
-
-void **get_dso_global() {
- return &dso_global;
-}
-
-}
diff --git a/contrib/compiler-rt/lib/msan/tests/msan_test.cc b/contrib/compiler-rt/lib/msan/tests/msan_test.cc
deleted file mode 100644
index 00dd20a3d775..000000000000
--- a/contrib/compiler-rt/lib/msan/tests/msan_test.cc
+++ /dev/null
@@ -1,4287 +0,0 @@
-//===-- msan_test.cc ------------------------------------------------------===//
-//
-// 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 MemorySanitizer.
-//
-// MemorySanitizer unit tests.
-//===----------------------------------------------------------------------===//
-
-#ifndef MSAN_EXTERNAL_TEST_CONFIG
-#include "msan_test_config.h"
-#endif // MSAN_EXTERNAL_TEST_CONFIG
-
-#include "sanitizer_common/tests/sanitizer_test_utils.h"
-
-#include "sanitizer/allocator_interface.h"
-#include "sanitizer/msan_interface.h"
-
-#if defined(__FreeBSD__)
-# define _KERNEL // To declare 'shminfo' structure.
-# include <sys/shm.h>
-# undef _KERNEL
-extern "C" {
-// <sys/shm.h> doesn't declare these functions in _KERNEL mode.
-void *shmat(int, const void *, int);
-int shmget(key_t, size_t, int);
-int shmctl(int, int, struct shmid_ds *);
-int shmdt(const void *);
-}
-#endif
-
-#include <inttypes.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <wchar.h>
-#include <math.h>
-
-#include <arpa/inet.h>
-#include <dlfcn.h>
-#include <grp.h>
-#include <unistd.h>
-#include <link.h>
-#include <limits.h>
-#include <sys/time.h>
-#include <poll.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <sys/resource.h>
-#include <sys/ioctl.h>
-#include <sys/statvfs.h>
-#include <sys/utsname.h>
-#include <sys/mman.h>
-#include <dirent.h>
-#include <pwd.h>
-#include <sys/socket.h>
-#include <netdb.h>
-#include <wordexp.h>
-#include <sys/ipc.h>
-#include <sys/shm.h>
-
-#if !defined(__FreeBSD__)
-# include <malloc.h>
-# include <sys/sysinfo.h>
-# include <sys/vfs.h>
-# include <mntent.h>
-# include <netinet/ether.h>
-#else
-# include <signal.h>
-# include <netinet/in.h>
-# include <pthread_np.h>
-# include <sys/uio.h>
-# include <sys/mount.h>
-# include <sys/sysctl.h>
-# include <net/ethernet.h>
-# define f_namelen f_namemax // FreeBSD names this statfs field so.
-# define cpu_set_t cpuset_t
-extern "C" {
-// FreeBSD's <ssp/string.h> defines mempcpy() to be a macro expanding into
-// a __builtin___mempcpy_chk() call, but since Msan RTL defines it as an
-// ordinary function, we can declare it here to complete the tests.
-void *mempcpy(void *dest, const void *src, size_t n);
-}
-#endif
-
-#if defined(__i386__) || defined(__x86_64__)
-# include <emmintrin.h>
-# define MSAN_HAS_M128 1
-#else
-# define MSAN_HAS_M128 0
-#endif
-
-#ifdef __AVX2__
-# include <immintrin.h>
-#endif
-
-// On FreeBSD procfs is not enabled by default.
-#if defined(__FreeBSD__)
-# define FILE_TO_READ "/bin/cat"
-# define DIR_TO_READ "/bin"
-# define SUBFILE_TO_READ "cat"
-# define SYMLINK_TO_READ "/usr/bin/tar"
-# define SUPERUSER_GROUP "wheel"
-#else
-# define FILE_TO_READ "/proc/self/stat"
-# define DIR_TO_READ "/proc/self"
-# define SUBFILE_TO_READ "stat"
-# define SYMLINK_TO_READ "/proc/self/exe"
-# define SUPERUSER_GROUP "root"
-#endif
-
-const size_t kPageSize = 4096;
-const size_t kMaxPathLength = 4096;
-
-typedef unsigned char U1;
-typedef unsigned short U2; // NOLINT
-typedef unsigned int U4;
-typedef unsigned long long U8; // NOLINT
-typedef signed char S1;
-typedef signed short S2; // NOLINT
-typedef signed int S4;
-typedef signed long long S8; // NOLINT
-#define NOINLINE __attribute__((noinline))
-#define INLINE __attribute__((always_inline))
-
-static bool TrackingOrigins() {
- S8 x;
- __msan_set_origin(&x, sizeof(x), 0x1234);
- U4 origin = __msan_get_origin(&x);
- __msan_set_origin(&x, sizeof(x), 0);
- return __msan_origin_is_descendant_or_same(origin, 0x1234);
-}
-
-#define EXPECT_ORIGIN(expected, origin) \
- EXPECT_TRUE(__msan_origin_is_descendant_or_same((origin), (expected)))
-
-#define EXPECT_UMR(action) \
- do { \
- __msan_set_expect_umr(1); \
- action; \
- __msan_set_expect_umr(0); \
- } while (0)
-
-#define EXPECT_UMR_O(action, origin) \
- do { \
- __msan_set_expect_umr(1); \
- action; \
- __msan_set_expect_umr(0); \
- if (TrackingOrigins()) EXPECT_ORIGIN(origin, __msan_get_umr_origin()); \
- } while (0)
-
-#define EXPECT_POISONED(x) ExpectPoisoned(x)
-
-template<typename T>
-void ExpectPoisoned(const T& t) {
- EXPECT_NE(-1, __msan_test_shadow((void*)&t, sizeof(t)));
-}
-
-#define EXPECT_POISONED_O(x, origin) \
- ExpectPoisonedWithOrigin(x, origin)
-
-template<typename T>
-void ExpectPoisonedWithOrigin(const T& t, unsigned origin) {
- EXPECT_NE(-1, __msan_test_shadow((void*)&t, sizeof(t)));
- if (TrackingOrigins()) EXPECT_ORIGIN(origin, __msan_get_origin((void *)&t));
-}
-
-#define EXPECT_NOT_POISONED(x) EXPECT_EQ(true, TestForNotPoisoned((x)))
-
-template<typename T>
-bool TestForNotPoisoned(const T& t) {
- return __msan_test_shadow((void*)&t, sizeof(t)) == -1;
-}
-
-static U8 poisoned_array[100];
-template<class T>
-T *GetPoisoned(int i = 0, T val = 0) {
- T *res = (T*)&poisoned_array[i];
- *res = val;
- __msan_poison(&poisoned_array[i], sizeof(T));
- return res;
-}
-
-template<class T>
-T *GetPoisonedO(int i, U4 origin, T val = 0) {
- T *res = (T*)&poisoned_array[i];
- *res = val;
- __msan_poison(&poisoned_array[i], sizeof(T));
- __msan_set_origin(&poisoned_array[i], sizeof(T), origin);
- return res;
-}
-
-template<typename T>
-T Poisoned(T v = 0, T s = (T)(-1)) {
- __msan_partial_poison(&v, &s, sizeof(T));
- return v;
-}
-
-template<class T> NOINLINE T ReturnPoisoned() { return *GetPoisoned<T>(); }
-
-static volatile int g_one = 1;
-static volatile int g_zero = 0;
-static volatile int g_0 = 0;
-static volatile int g_1 = 1;
-
-S4 a_s4[100];
-S8 a_s8[100];
-
-// Check that malloc poisons memory.
-// A lot of tests below depend on this.
-TEST(MemorySanitizerSanity, PoisonInMalloc) {
- int *x = (int*)malloc(sizeof(int));
- EXPECT_POISONED(*x);
- free(x);
-}
-
-TEST(MemorySanitizer, NegativeTest1) {
- S4 *x = GetPoisoned<S4>();
- if (g_one)
- *x = 0;
- EXPECT_NOT_POISONED(*x);
-}
-
-TEST(MemorySanitizer, PositiveTest1) {
- // Load to store.
- EXPECT_POISONED(*GetPoisoned<S1>());
- EXPECT_POISONED(*GetPoisoned<S2>());
- EXPECT_POISONED(*GetPoisoned<S4>());
- EXPECT_POISONED(*GetPoisoned<S8>());
-
- // S->S conversions.
- EXPECT_POISONED(*GetPoisoned<S1>());
- EXPECT_POISONED(*GetPoisoned<S1>());
- EXPECT_POISONED(*GetPoisoned<S1>());
-
- EXPECT_POISONED(*GetPoisoned<S2>());
- EXPECT_POISONED(*GetPoisoned<S2>());
- EXPECT_POISONED(*GetPoisoned<S2>());
-
- EXPECT_POISONED(*GetPoisoned<S4>());
- EXPECT_POISONED(*GetPoisoned<S4>());
- EXPECT_POISONED(*GetPoisoned<S4>());
-
- EXPECT_POISONED(*GetPoisoned<S8>());
- EXPECT_POISONED(*GetPoisoned<S8>());
- EXPECT_POISONED(*GetPoisoned<S8>());
-
- // ZExt
- EXPECT_POISONED(*GetPoisoned<U1>());
- EXPECT_POISONED(*GetPoisoned<U1>());
- EXPECT_POISONED(*GetPoisoned<U1>());
- EXPECT_POISONED(*GetPoisoned<U2>());
- EXPECT_POISONED(*GetPoisoned<U2>());
- EXPECT_POISONED(*GetPoisoned<U4>());
-
- // Unary ops.
- EXPECT_POISONED(- *GetPoisoned<S4>());
-
- EXPECT_UMR(a_s4[g_zero] = 100 / *GetPoisoned<S4>(0, 1));
-
-
- a_s4[g_zero] = 1 - *GetPoisoned<S4>();
- a_s4[g_zero] = 1 + *GetPoisoned<S4>();
-}
-
-TEST(MemorySanitizer, Phi1) {
- S4 c;
- if (g_one) {
- c = *GetPoisoned<S4>();
- } else {
- break_optimization(0);
- c = 0;
- }
- EXPECT_POISONED(c);
-}
-
-TEST(MemorySanitizer, Phi2) {
- S4 i = *GetPoisoned<S4>();
- S4 n = g_one;
- EXPECT_UMR(for (; i < g_one; i++););
- EXPECT_POISONED(i);
-}
-
-NOINLINE void Arg1ExpectUMR(S4 a1) { EXPECT_POISONED(a1); }
-NOINLINE void Arg2ExpectUMR(S4 a1, S4 a2) { EXPECT_POISONED(a2); }
-NOINLINE void Arg3ExpectUMR(S1 a1, S4 a2, S8 a3) { EXPECT_POISONED(a3); }
-
-TEST(MemorySanitizer, ArgTest) {
- Arg1ExpectUMR(*GetPoisoned<S4>());
- Arg2ExpectUMR(0, *GetPoisoned<S4>());
- Arg3ExpectUMR(0, 1, *GetPoisoned<S8>());
-}
-
-
-TEST(MemorySanitizer, CallAndRet) {
- ReturnPoisoned<S1>();
- ReturnPoisoned<S2>();
- ReturnPoisoned<S4>();
- ReturnPoisoned<S8>();
-
- EXPECT_POISONED(ReturnPoisoned<S1>());
- EXPECT_POISONED(ReturnPoisoned<S2>());
- EXPECT_POISONED(ReturnPoisoned<S4>());
- EXPECT_POISONED(ReturnPoisoned<S8>());
-}
-
-// malloc() in the following test may be optimized to produce a compile-time
-// undef value. Check that we trap on the volatile assignment anyway.
-TEST(MemorySanitizer, DISABLED_MallocNoIdent) {
- S4 *x = (int*)malloc(sizeof(S4));
- EXPECT_POISONED(*x);
- free(x);
-}
-
-TEST(MemorySanitizer, Malloc) {
- S4 *x = (int*)Ident(malloc(sizeof(S4)));
- EXPECT_POISONED(*x);
- free(x);
-}
-
-TEST(MemorySanitizer, Realloc) {
- S4 *x = (int*)Ident(realloc(0, sizeof(S4)));
- EXPECT_POISONED(x[0]);
- x[0] = 1;
- x = (int*)Ident(realloc(x, 2 * sizeof(S4)));
- EXPECT_NOT_POISONED(x[0]); // Ok, was inited before.
- EXPECT_POISONED(x[1]);
- x = (int*)Ident(realloc(x, 3 * sizeof(S4)));
- EXPECT_NOT_POISONED(x[0]); // Ok, was inited before.
- EXPECT_POISONED(x[2]);
- EXPECT_POISONED(x[1]);
- x[2] = 1; // Init this here. Check that after realloc it is poisoned again.
- x = (int*)Ident(realloc(x, 2 * sizeof(S4)));
- EXPECT_NOT_POISONED(x[0]); // Ok, was inited before.
- EXPECT_POISONED(x[1]);
- x = (int*)Ident(realloc(x, 3 * sizeof(S4)));
- EXPECT_POISONED(x[1]);
- EXPECT_POISONED(x[2]);
- free(x);
-}
-
-TEST(MemorySanitizer, Calloc) {
- S4 *x = (int*)Ident(calloc(1, sizeof(S4)));
- EXPECT_NOT_POISONED(*x); // Should not be poisoned.
- EXPECT_EQ(0, *x);
- free(x);
-}
-
-TEST(MemorySanitizer, CallocReturnsZeroMem) {
- size_t sizes[] = {16, 1000, 10000, 100000, 2100000};
- for (size_t s = 0; s < sizeof(sizes)/sizeof(sizes[0]); s++) {
- size_t size = sizes[s];
- for (size_t iter = 0; iter < 5; iter++) {
- char *x = Ident((char*)calloc(1, size));
- EXPECT_EQ(x[0], 0);
- EXPECT_EQ(x[size - 1], 0);
- EXPECT_EQ(x[size / 2], 0);
- EXPECT_EQ(x[size / 3], 0);
- EXPECT_EQ(x[size / 4], 0);
- memset(x, 0x42, size);
- free(Ident(x));
- }
- }
-}
-
-TEST(MemorySanitizer, AndOr) {
- U4 *p = GetPoisoned<U4>();
- // We poison two bytes in the midle of a 4-byte word to make the test
- // correct regardless of endianness.
- ((U1*)p)[1] = 0;
- ((U1*)p)[2] = 0xff;
- EXPECT_NOT_POISONED(*p & 0x00ffff00);
- EXPECT_NOT_POISONED(*p & 0x00ff0000);
- EXPECT_NOT_POISONED(*p & 0x0000ff00);
- EXPECT_POISONED(*p & 0xff000000);
- EXPECT_POISONED(*p & 0x000000ff);
- EXPECT_POISONED(*p & 0x0000ffff);
- EXPECT_POISONED(*p & 0xffff0000);
-
- EXPECT_NOT_POISONED(*p | 0xff0000ff);
- EXPECT_NOT_POISONED(*p | 0xff00ffff);
- EXPECT_NOT_POISONED(*p | 0xffff00ff);
- EXPECT_POISONED(*p | 0xff000000);
- EXPECT_POISONED(*p | 0x000000ff);
- EXPECT_POISONED(*p | 0x0000ffff);
- EXPECT_POISONED(*p | 0xffff0000);
-
- EXPECT_POISONED(*GetPoisoned<bool>() & *GetPoisoned<bool>());
-}
-
-template<class T>
-static bool applyNot(T value, T shadow) {
- __msan_partial_poison(&value, &shadow, sizeof(T));
- return !value;
-}
-
-TEST(MemorySanitizer, Not) {
- EXPECT_NOT_POISONED(applyNot<U4>(0x0, 0x0));
- EXPECT_NOT_POISONED(applyNot<U4>(0xFFFFFFFF, 0x0));
- EXPECT_POISONED(applyNot<U4>(0xFFFFFFFF, 0xFFFFFFFF));
- EXPECT_NOT_POISONED(applyNot<U4>(0xFF000000, 0x0FFFFFFF));
- EXPECT_NOT_POISONED(applyNot<U4>(0xFF000000, 0x00FFFFFF));
- EXPECT_NOT_POISONED(applyNot<U4>(0xFF000000, 0x0000FFFF));
- EXPECT_NOT_POISONED(applyNot<U4>(0xFF000000, 0x00000000));
- EXPECT_POISONED(applyNot<U4>(0xFF000000, 0xFF000000));
- EXPECT_NOT_POISONED(applyNot<U4>(0xFF800000, 0xFF000000));
- EXPECT_POISONED(applyNot<U4>(0x00008000, 0x00008000));
-
- EXPECT_NOT_POISONED(applyNot<U1>(0x0, 0x0));
- EXPECT_NOT_POISONED(applyNot<U1>(0xFF, 0xFE));
- EXPECT_NOT_POISONED(applyNot<U1>(0xFF, 0x0));
- EXPECT_POISONED(applyNot<U1>(0xFF, 0xFF));
-
- EXPECT_POISONED(applyNot<void*>((void*)0xFFFFFF, (void*)(-1)));
- EXPECT_NOT_POISONED(applyNot<void*>((void*)0xFFFFFF, (void*)(-2)));
-}
-
-TEST(MemorySanitizer, Shift) {
- U4 *up = GetPoisoned<U4>();
- ((U1*)up)[0] = 0;
- ((U1*)up)[3] = 0xff;
- EXPECT_NOT_POISONED(*up >> 30);
- EXPECT_NOT_POISONED(*up >> 24);
- EXPECT_POISONED(*up >> 23);
- EXPECT_POISONED(*up >> 10);
-
- EXPECT_NOT_POISONED(*up << 30);
- EXPECT_NOT_POISONED(*up << 24);
- EXPECT_POISONED(*up << 23);
- EXPECT_POISONED(*up << 10);
-
- S4 *sp = (S4*)up;
- EXPECT_NOT_POISONED(*sp >> 30);
- EXPECT_NOT_POISONED(*sp >> 24);
- EXPECT_POISONED(*sp >> 23);
- EXPECT_POISONED(*sp >> 10);
-
- sp = GetPoisoned<S4>();
- ((S1*)sp)[1] = 0;
- ((S1*)sp)[2] = 0;
- EXPECT_POISONED(*sp >> 31);
-
- EXPECT_POISONED(100 >> *GetPoisoned<S4>());
- EXPECT_POISONED(100U >> *GetPoisoned<S4>());
-}
-
-NOINLINE static int GetPoisonedZero() {
- int *zero = new int;
- *zero = 0;
- __msan_poison(zero, sizeof(*zero));
- int res = *zero;
- delete zero;
- return res;
-}
-
-TEST(MemorySanitizer, LoadFromDirtyAddress) {
- int *a = new int;
- *a = 0;
- EXPECT_UMR(break_optimization((void*)(U8)a[GetPoisonedZero()]));
- delete a;
-}
-
-TEST(MemorySanitizer, StoreToDirtyAddress) {
- int *a = new int;
- EXPECT_UMR(a[GetPoisonedZero()] = 0);
- break_optimization(a);
- delete a;
-}
-
-
-NOINLINE void StackTestFunc() {
- S4 p4;
- S4 ok4 = 1;
- S2 p2;
- S2 ok2 = 1;
- S1 p1;
- S1 ok1 = 1;
- break_optimization(&p4);
- break_optimization(&ok4);
- break_optimization(&p2);
- break_optimization(&ok2);
- break_optimization(&p1);
- break_optimization(&ok1);
-
- EXPECT_POISONED(p4);
- EXPECT_POISONED(p2);
- EXPECT_POISONED(p1);
- EXPECT_NOT_POISONED(ok1);
- EXPECT_NOT_POISONED(ok2);
- EXPECT_NOT_POISONED(ok4);
-}
-
-TEST(MemorySanitizer, StackTest) {
- StackTestFunc();
-}
-
-NOINLINE void StackStressFunc() {
- int foo[10000];
- break_optimization(foo);
-}
-
-TEST(MemorySanitizer, DISABLED_StackStressTest) {
- for (int i = 0; i < 1000000; i++)
- StackStressFunc();
-}
-
-template<class T>
-void TestFloatingPoint() {
- static volatile T v;
- static T g[100];
- break_optimization(&g);
- T *x = GetPoisoned<T>();
- T *y = GetPoisoned<T>(1);
- EXPECT_POISONED(*x);
- EXPECT_POISONED((long long)*x);
- EXPECT_POISONED((int)*x);
- g[0] = *x;
- g[1] = *x + *y;
- g[2] = *x - *y;
- g[3] = *x * *y;
-}
-
-TEST(MemorySanitizer, FloatingPointTest) {
- TestFloatingPoint<float>();
- TestFloatingPoint<double>();
-}
-
-TEST(MemorySanitizer, DynMem) {
- S4 x = 0;
- S4 *y = GetPoisoned<S4>();
- memcpy(y, &x, g_one * sizeof(S4));
- EXPECT_NOT_POISONED(*y);
-}
-
-static char *DynRetTestStr;
-
-TEST(MemorySanitizer, DynRet) {
- ReturnPoisoned<S8>();
- EXPECT_NOT_POISONED(atoi("0"));
-}
-
-TEST(MemorySanitizer, DynRet1) {
- ReturnPoisoned<S8>();
-}
-
-struct LargeStruct {
- S4 x[10];
-};
-
-NOINLINE
-LargeStruct LargeRetTest() {
- LargeStruct res;
- res.x[0] = *GetPoisoned<S4>();
- res.x[1] = *GetPoisoned<S4>();
- res.x[2] = *GetPoisoned<S4>();
- res.x[3] = *GetPoisoned<S4>();
- res.x[4] = *GetPoisoned<S4>();
- res.x[5] = *GetPoisoned<S4>();
- res.x[6] = *GetPoisoned<S4>();
- res.x[7] = *GetPoisoned<S4>();
- res.x[8] = *GetPoisoned<S4>();
- res.x[9] = *GetPoisoned<S4>();
- return res;
-}
-
-TEST(MemorySanitizer, strcmp) {
- char s1[10];
- char s2[10];
- strncpy(s1, "foo", 10);
- s2[0] = 'f';
- s2[1] = 'n';
- EXPECT_GT(strcmp(s1, s2), 0);
- s2[1] = 'o';
- int res;
- EXPECT_UMR(res = strcmp(s1, s2));
- EXPECT_NOT_POISONED(res);
- EXPECT_EQ(strncmp(s1, s2, 1), 0);
-}
-
-TEST(MemorySanitizer, LargeRet) {
- LargeStruct a = LargeRetTest();
- EXPECT_POISONED(a.x[0]);
- EXPECT_POISONED(a.x[9]);
-}
-
-TEST(MemorySanitizer, strerror) {
- char *buf = strerror(EINVAL);
- EXPECT_NOT_POISONED(strlen(buf));
- buf = strerror(123456);
- EXPECT_NOT_POISONED(strlen(buf));
-}
-
-TEST(MemorySanitizer, strerror_r) {
- errno = 0;
- char buf[1000];
- char *res = (char*) (size_t) strerror_r(EINVAL, buf, sizeof(buf));
- ASSERT_EQ(0, errno);
- if (!res) res = buf; // POSIX version success.
- EXPECT_NOT_POISONED(strlen(res));
-}
-
-TEST(MemorySanitizer, fread) {
- char *x = new char[32];
- FILE *f = fopen(FILE_TO_READ, "r");
- ASSERT_TRUE(f != NULL);
- fread(x, 1, 32, f);
- EXPECT_NOT_POISONED(x[0]);
- EXPECT_NOT_POISONED(x[16]);
- EXPECT_NOT_POISONED(x[31]);
- fclose(f);
- delete[] x;
-}
-
-TEST(MemorySanitizer, read) {
- char *x = new char[32];
- int fd = open(FILE_TO_READ, O_RDONLY);
- ASSERT_GT(fd, 0);
- int sz = read(fd, x, 32);
- ASSERT_EQ(sz, 32);
- EXPECT_NOT_POISONED(x[0]);
- EXPECT_NOT_POISONED(x[16]);
- EXPECT_NOT_POISONED(x[31]);
- close(fd);
- delete[] x;
-}
-
-TEST(MemorySanitizer, pread) {
- char *x = new char[32];
- int fd = open(FILE_TO_READ, O_RDONLY);
- ASSERT_GT(fd, 0);
- int sz = pread(fd, x, 32, 0);
- ASSERT_EQ(sz, 32);
- EXPECT_NOT_POISONED(x[0]);
- EXPECT_NOT_POISONED(x[16]);
- EXPECT_NOT_POISONED(x[31]);
- close(fd);
- delete[] x;
-}
-
-TEST(MemorySanitizer, readv) {
- char buf[2011];
- struct iovec iov[2];
- iov[0].iov_base = buf + 1;
- iov[0].iov_len = 5;
- iov[1].iov_base = buf + 10;
- iov[1].iov_len = 2000;
- int fd = open(FILE_TO_READ, O_RDONLY);
- ASSERT_GT(fd, 0);
- int sz = readv(fd, iov, 2);
- ASSERT_GE(sz, 0);
- ASSERT_LE(sz, 5 + 2000);
- ASSERT_GT((size_t)sz, iov[0].iov_len);
- EXPECT_POISONED(buf[0]);
- EXPECT_NOT_POISONED(buf[1]);
- EXPECT_NOT_POISONED(buf[5]);
- EXPECT_POISONED(buf[6]);
- EXPECT_POISONED(buf[9]);
- EXPECT_NOT_POISONED(buf[10]);
- EXPECT_NOT_POISONED(buf[10 + (sz - 1) - 5]);
- EXPECT_POISONED(buf[11 + (sz - 1) - 5]);
- close(fd);
-}
-
-TEST(MemorySanitizer, preadv) {
- char buf[2011];
- struct iovec iov[2];
- iov[0].iov_base = buf + 1;
- iov[0].iov_len = 5;
- iov[1].iov_base = buf + 10;
- iov[1].iov_len = 2000;
- int fd = open(FILE_TO_READ, O_RDONLY);
- ASSERT_GT(fd, 0);
- int sz = preadv(fd, iov, 2, 3);
- ASSERT_GE(sz, 0);
- ASSERT_LE(sz, 5 + 2000);
- ASSERT_GT((size_t)sz, iov[0].iov_len);
- EXPECT_POISONED(buf[0]);
- EXPECT_NOT_POISONED(buf[1]);
- EXPECT_NOT_POISONED(buf[5]);
- EXPECT_POISONED(buf[6]);
- EXPECT_POISONED(buf[9]);
- EXPECT_NOT_POISONED(buf[10]);
- EXPECT_NOT_POISONED(buf[10 + (sz - 1) - 5]);
- EXPECT_POISONED(buf[11 + (sz - 1) - 5]);
- close(fd);
-}
-
-// FIXME: fails now.
-TEST(MemorySanitizer, DISABLED_ioctl) {
- struct winsize ws;
- EXPECT_EQ(ioctl(2, TIOCGWINSZ, &ws), 0);
- EXPECT_NOT_POISONED(ws.ws_col);
-}
-
-TEST(MemorySanitizer, readlink) {
- char *x = new char[1000];
- readlink(SYMLINK_TO_READ, x, 1000);
- EXPECT_NOT_POISONED(x[0]);
- delete [] x;
-}
-
-TEST(MemorySanitizer, stat) {
- struct stat* st = new struct stat;
- int res = stat(FILE_TO_READ, st);
- ASSERT_EQ(0, res);
- EXPECT_NOT_POISONED(st->st_dev);
- EXPECT_NOT_POISONED(st->st_mode);
- EXPECT_NOT_POISONED(st->st_size);
-}
-
-TEST(MemorySanitizer, fstatat) {
- struct stat* st = new struct stat;
- int dirfd = open(DIR_TO_READ, O_RDONLY);
- ASSERT_GT(dirfd, 0);
- int res = fstatat(dirfd, SUBFILE_TO_READ, st, 0);
- ASSERT_EQ(0, res);
- EXPECT_NOT_POISONED(st->st_dev);
- EXPECT_NOT_POISONED(st->st_mode);
- EXPECT_NOT_POISONED(st->st_size);
- close(dirfd);
-}
-
-TEST(MemorySanitizer, statfs) {
- struct statfs st;
- int res = statfs("/", &st);
- ASSERT_EQ(0, res);
- EXPECT_NOT_POISONED(st.f_type);
- EXPECT_NOT_POISONED(st.f_bfree);
- EXPECT_NOT_POISONED(st.f_namelen);
-}
-
-TEST(MemorySanitizer, statvfs) {
- struct statvfs st;
- int res = statvfs("/", &st);
- ASSERT_EQ(0, res);
- EXPECT_NOT_POISONED(st.f_bsize);
- EXPECT_NOT_POISONED(st.f_blocks);
- EXPECT_NOT_POISONED(st.f_bfree);
- EXPECT_NOT_POISONED(st.f_namemax);
-}
-
-TEST(MemorySanitizer, fstatvfs) {
- struct statvfs st;
- int fd = open("/", O_RDONLY | O_DIRECTORY);
- int res = fstatvfs(fd, &st);
- ASSERT_EQ(0, res);
- EXPECT_NOT_POISONED(st.f_bsize);
- EXPECT_NOT_POISONED(st.f_blocks);
- EXPECT_NOT_POISONED(st.f_bfree);
- EXPECT_NOT_POISONED(st.f_namemax);
- close(fd);
-}
-
-TEST(MemorySanitizer, pipe) {
- int* pipefd = new int[2];
- int res = pipe(pipefd);
- ASSERT_EQ(0, res);
- EXPECT_NOT_POISONED(pipefd[0]);
- EXPECT_NOT_POISONED(pipefd[1]);
- close(pipefd[0]);
- close(pipefd[1]);
-}
-
-TEST(MemorySanitizer, pipe2) {
- int* pipefd = new int[2];
- int res = pipe2(pipefd, O_NONBLOCK);
- ASSERT_EQ(0, res);
- EXPECT_NOT_POISONED(pipefd[0]);
- EXPECT_NOT_POISONED(pipefd[1]);
- close(pipefd[0]);
- close(pipefd[1]);
-}
-
-TEST(MemorySanitizer, socketpair) {
- int sv[2];
- int res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv);
- ASSERT_EQ(0, res);
- EXPECT_NOT_POISONED(sv[0]);
- EXPECT_NOT_POISONED(sv[1]);
- close(sv[0]);
- close(sv[1]);
-}
-
-TEST(MemorySanitizer, poll) {
- int* pipefd = new int[2];
- int res = pipe(pipefd);
- ASSERT_EQ(0, res);
-
- char data = 42;
- res = write(pipefd[1], &data, 1);
- ASSERT_EQ(1, res);
-
- pollfd fds[2];
- fds[0].fd = pipefd[0];
- fds[0].events = POLLIN;
- fds[1].fd = pipefd[1];
- fds[1].events = POLLIN;
- res = poll(fds, 2, 500);
- ASSERT_EQ(1, res);
- EXPECT_NOT_POISONED(fds[0].revents);
- EXPECT_NOT_POISONED(fds[1].revents);
-
- close(pipefd[0]);
- close(pipefd[1]);
-}
-
-// There is no ppoll() on FreeBSD.
-#if !defined (__FreeBSD__)
-TEST(MemorySanitizer, ppoll) {
- int* pipefd = new int[2];
- int res = pipe(pipefd);
- ASSERT_EQ(0, res);
-
- char data = 42;
- res = write(pipefd[1], &data, 1);
- ASSERT_EQ(1, res);
-
- pollfd fds[2];
- fds[0].fd = pipefd[0];
- fds[0].events = POLLIN;
- fds[1].fd = pipefd[1];
- fds[1].events = POLLIN;
- sigset_t ss;
- sigemptyset(&ss);
- res = ppoll(fds, 2, NULL, &ss);
- ASSERT_EQ(1, res);
- EXPECT_NOT_POISONED(fds[0].revents);
- EXPECT_NOT_POISONED(fds[1].revents);
-
- close(pipefd[0]);
- close(pipefd[1]);
-}
-#endif
-
-TEST(MemorySanitizer, poll_positive) {
- int* pipefd = new int[2];
- int res = pipe(pipefd);
- ASSERT_EQ(0, res);
-
- pollfd fds[2];
- fds[0].fd = pipefd[0];
- fds[0].events = POLLIN;
- // fds[1].fd uninitialized
- fds[1].events = POLLIN;
- EXPECT_UMR(poll(fds, 2, 0));
-
- close(pipefd[0]);
- close(pipefd[1]);
-}
-
-TEST(MemorySanitizer, bind_getsockname) {
- int sock = socket(AF_UNIX, SOCK_STREAM, 0);
-
- struct sockaddr_in sai;
- memset(&sai, 0, sizeof(sai));
- sai.sin_family = AF_UNIX;
- int res = bind(sock, (struct sockaddr *)&sai, sizeof(sai));
-
- ASSERT_EQ(0, res);
- char buf[200];
- socklen_t addrlen;
- EXPECT_UMR(getsockname(sock, (struct sockaddr *)&buf, &addrlen));
-
- addrlen = sizeof(buf);
- res = getsockname(sock, (struct sockaddr *)&buf, &addrlen);
- EXPECT_NOT_POISONED(addrlen);
- EXPECT_NOT_POISONED(buf[0]);
- EXPECT_NOT_POISONED(buf[addrlen - 1]);
- EXPECT_POISONED(buf[addrlen]);
- close(sock);
-}
-
-TEST(MemorySanitizer, accept) {
- int listen_socket = socket(AF_INET, SOCK_STREAM, 0);
- ASSERT_LT(0, listen_socket);
-
- struct sockaddr_in sai;
- memset(&sai, 0, sizeof(sai));
- sai.sin_family = AF_INET;
- sai.sin_port = 0;
- sai.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
- int res = bind(listen_socket, (struct sockaddr *)&sai, sizeof(sai));
- ASSERT_EQ(0, res);
-
- res = listen(listen_socket, 1);
- ASSERT_EQ(0, res);
-
- socklen_t sz = sizeof(sai);
- res = getsockname(listen_socket, (struct sockaddr *)&sai, &sz);
- ASSERT_EQ(0, res);
- ASSERT_EQ(sizeof(sai), sz);
-
- int connect_socket = socket(AF_INET, SOCK_STREAM, 0);
- ASSERT_LT(0, connect_socket);
- res = fcntl(connect_socket, F_SETFL, O_NONBLOCK);
- ASSERT_EQ(0, res);
- res = connect(connect_socket, (struct sockaddr *)&sai, sizeof(sai));
- // On FreeBSD this connection completes immediately.
- if (res != 0) {
- ASSERT_EQ(-1, res);
- ASSERT_EQ(EINPROGRESS, errno);
- }
-
- __msan_poison(&sai, sizeof(sai));
- int new_sock = accept(listen_socket, (struct sockaddr *)&sai, &sz);
- ASSERT_LT(0, new_sock);
- ASSERT_EQ(sizeof(sai), sz);
- EXPECT_NOT_POISONED(sai);
-
- __msan_poison(&sai, sizeof(sai));
- res = getpeername(new_sock, (struct sockaddr *)&sai, &sz);
- ASSERT_EQ(0, res);
- ASSERT_EQ(sizeof(sai), sz);
- EXPECT_NOT_POISONED(sai);
-
- close(new_sock);
- close(connect_socket);
- close(listen_socket);
-}
-
-TEST(MemorySanitizer, getaddrinfo) {
- struct addrinfo *ai;
- struct addrinfo hints;
- memset(&hints, 0, sizeof(hints));
- hints.ai_family = AF_INET;
- int res = getaddrinfo("localhost", NULL, &hints, &ai);
- ASSERT_EQ(0, res);
- EXPECT_NOT_POISONED(*ai);
- ASSERT_EQ(sizeof(sockaddr_in), ai->ai_addrlen);
- EXPECT_NOT_POISONED(*(sockaddr_in*)ai->ai_addr);
-}
-
-TEST(MemorySanitizer, getnameinfo) {
- struct sockaddr_in sai;
- memset(&sai, 0, sizeof(sai));
- sai.sin_family = AF_INET;
- sai.sin_port = 80;
- sai.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
- char host[500];
- char serv[500];
- int res = getnameinfo((struct sockaddr *)&sai, sizeof(sai), host,
- sizeof(host), serv, sizeof(serv), 0);
- ASSERT_EQ(0, res);
- EXPECT_NOT_POISONED(host[0]);
- EXPECT_POISONED(host[sizeof(host) - 1]);
-
- ASSERT_NE(0U, strlen(host));
- EXPECT_NOT_POISONED(serv[0]);
- EXPECT_POISONED(serv[sizeof(serv) - 1]);
- ASSERT_NE(0U, strlen(serv));
-}
-
-#define EXPECT_HOSTENT_NOT_POISONED(he) \
- do { \
- EXPECT_NOT_POISONED(*(he)); \
- ASSERT_NE((void *) 0, (he)->h_name); \
- ASSERT_NE((void *) 0, (he)->h_aliases); \
- ASSERT_NE((void *) 0, (he)->h_addr_list); \
- EXPECT_NOT_POISONED(strlen((he)->h_name)); \
- char **p = (he)->h_aliases; \
- while (*p) { \
- EXPECT_NOT_POISONED(strlen(*p)); \
- ++p; \
- } \
- char **q = (he)->h_addr_list; \
- while (*q) { \
- EXPECT_NOT_POISONED(*q[0]); \
- ++q; \
- } \
- EXPECT_NOT_POISONED(*q); \
- } while (0)
-
-TEST(MemorySanitizer, gethostent) {
- struct hostent *he = gethostent();
- ASSERT_NE((void *)NULL, he);
- EXPECT_HOSTENT_NOT_POISONED(he);
-}
-
-#ifndef MSAN_TEST_DISABLE_GETHOSTBYNAME
-
-TEST(MemorySanitizer, gethostbyname) {
- struct hostent *he = gethostbyname("localhost");
- ASSERT_NE((void *)NULL, he);
- EXPECT_HOSTENT_NOT_POISONED(he);
-}
-
-#endif // MSAN_TEST_DISABLE_GETHOSTBYNAME
-
-TEST(MemorySanitizer, recvmsg) {
- int server_socket = socket(AF_INET, SOCK_DGRAM, 0);
- ASSERT_LT(0, server_socket);
-
- struct sockaddr_in sai;
- memset(&sai, 0, sizeof(sai));
- sai.sin_family = AF_INET;
- sai.sin_port = 0;
- sai.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
- int res = bind(server_socket, (struct sockaddr *)&sai, sizeof(sai));
- ASSERT_EQ(0, res);
-
- socklen_t sz = sizeof(sai);
- res = getsockname(server_socket, (struct sockaddr *)&sai, &sz);
- ASSERT_EQ(0, res);
- ASSERT_EQ(sizeof(sai), sz);
-
-
- int client_socket = socket(AF_INET, SOCK_DGRAM, 0);
- ASSERT_LT(0, client_socket);
-
- struct sockaddr_in client_sai;
- memset(&client_sai, 0, sizeof(client_sai));
- client_sai.sin_family = AF_INET;
- client_sai.sin_port = 0;
- client_sai.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
- res = bind(client_socket, (struct sockaddr *)&client_sai, sizeof(client_sai));
- ASSERT_EQ(0, res);
-
- sz = sizeof(client_sai);
- res = getsockname(client_socket, (struct sockaddr *)&client_sai, &sz);
- ASSERT_EQ(0, res);
- ASSERT_EQ(sizeof(client_sai), sz);
-
- const char *s = "message text";
- struct iovec iov;
- iov.iov_base = (void *)s;
- iov.iov_len = strlen(s) + 1;
- struct msghdr msg;
- memset(&msg, 0, sizeof(msg));
- msg.msg_name = &sai;
- msg.msg_namelen = sizeof(sai);
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
- res = sendmsg(client_socket, &msg, 0);
- ASSERT_LT(0, res);
-
-
- char buf[1000];
- struct iovec recv_iov;
- recv_iov.iov_base = (void *)&buf;
- recv_iov.iov_len = sizeof(buf);
- struct sockaddr_in recv_sai;
- struct msghdr recv_msg;
- memset(&recv_msg, 0, sizeof(recv_msg));
- recv_msg.msg_name = &recv_sai;
- recv_msg.msg_namelen = sizeof(recv_sai);
- recv_msg.msg_iov = &recv_iov;
- recv_msg.msg_iovlen = 1;
- res = recvmsg(server_socket, &recv_msg, 0);
- ASSERT_LT(0, res);
-
- ASSERT_EQ(sizeof(recv_sai), recv_msg.msg_namelen);
- EXPECT_NOT_POISONED(*(struct sockaddr_in *)recv_msg.msg_name);
- EXPECT_STREQ(s, buf);
-
- close(server_socket);
- close(client_socket);
-}
-
-TEST(MemorySanitizer, gethostbyname2) {
- struct hostent *he = gethostbyname2("localhost", AF_INET);
- ASSERT_NE((void *)NULL, he);
- EXPECT_HOSTENT_NOT_POISONED(he);
-}
-
-TEST(MemorySanitizer, gethostbyaddr) {
- in_addr_t addr = inet_addr("127.0.0.1");
- EXPECT_NOT_POISONED(addr);
- struct hostent *he = gethostbyaddr(&addr, sizeof(addr), AF_INET);
- ASSERT_NE((void *)NULL, he);
- EXPECT_HOSTENT_NOT_POISONED(he);
-}
-
-TEST(MemorySanitizer, gethostent_r) {
- char buf[2000];
- struct hostent he;
- struct hostent *result;
- int err;
- int res = gethostent_r(&he, buf, sizeof(buf), &result, &err);
- ASSERT_EQ(0, res);
- EXPECT_NOT_POISONED(result);
- ASSERT_NE((void *)NULL, result);
- EXPECT_HOSTENT_NOT_POISONED(result);
- EXPECT_NOT_POISONED(err);
-}
-
-TEST(MemorySanitizer, gethostbyname_r) {
- char buf[2000];
- struct hostent he;
- struct hostent *result;
- int err;
- int res = gethostbyname_r("localhost", &he, buf, sizeof(buf), &result, &err);
- ASSERT_EQ(0, res);
- EXPECT_NOT_POISONED(result);
- ASSERT_NE((void *)NULL, result);
- EXPECT_HOSTENT_NOT_POISONED(result);
- EXPECT_NOT_POISONED(err);
-}
-
-TEST(MemorySanitizer, gethostbyname_r_bad_host_name) {
- char buf[2000];
- struct hostent he;
- struct hostent *result;
- int err;
- int res = gethostbyname_r("bad-host-name", &he, buf, sizeof(buf), &result, &err);
- ASSERT_EQ((struct hostent *)0, result);
- EXPECT_NOT_POISONED(err);
-}
-
-TEST(MemorySanitizer, gethostbyname_r_erange) {
- char buf[5];
- struct hostent he;
- struct hostent *result;
- int err;
- int res = gethostbyname_r("localhost", &he, buf, sizeof(buf), &result, &err);
- ASSERT_EQ(ERANGE, res);
- EXPECT_NOT_POISONED(err);
-}
-
-TEST(MemorySanitizer, gethostbyname2_r) {
- char buf[2000];
- struct hostent he;
- struct hostent *result;
- int err;
- int res = gethostbyname2_r("localhost", AF_INET, &he, buf, sizeof(buf),
- &result, &err);
- ASSERT_EQ(0, res);
- EXPECT_NOT_POISONED(result);
- ASSERT_NE((void *)NULL, result);
- EXPECT_HOSTENT_NOT_POISONED(result);
- EXPECT_NOT_POISONED(err);
-}
-
-TEST(MemorySanitizer, gethostbyaddr_r) {
- char buf[2000];
- struct hostent he;
- struct hostent *result;
- int err;
- in_addr_t addr = inet_addr("127.0.0.1");
- EXPECT_NOT_POISONED(addr);
- int res = gethostbyaddr_r(&addr, sizeof(addr), AF_INET, &he, buf, sizeof(buf),
- &result, &err);
- ASSERT_EQ(0, res);
- EXPECT_NOT_POISONED(result);
- ASSERT_NE((void *)NULL, result);
- EXPECT_HOSTENT_NOT_POISONED(result);
- EXPECT_NOT_POISONED(err);
-}
-
-TEST(MemorySanitizer, getsockopt) {
- int sock = socket(AF_UNIX, SOCK_STREAM, 0);
- struct linger l[2];
- socklen_t sz = sizeof(l[0]);
- int res = getsockopt(sock, SOL_SOCKET, SO_LINGER, &l[0], &sz);
- ASSERT_EQ(0, res);
- ASSERT_EQ(sizeof(l[0]), sz);
- EXPECT_NOT_POISONED(l[0]);
- EXPECT_POISONED(*(char *)(l + 1));
-}
-
-TEST(MemorySanitizer, getcwd) {
- char path[PATH_MAX + 1];
- char* res = getcwd(path, sizeof(path));
- ASSERT_TRUE(res != NULL);
- EXPECT_NOT_POISONED(path[0]);
-}
-
-TEST(MemorySanitizer, getcwd_gnu) {
- char* res = getcwd(NULL, 0);
- ASSERT_TRUE(res != NULL);
- EXPECT_NOT_POISONED(res[0]);
- free(res);
-}
-
-// There's no get_current_dir_name() on FreeBSD.
-#if !defined(__FreeBSD__)
-TEST(MemorySanitizer, get_current_dir_name) {
- char* res = get_current_dir_name();
- ASSERT_TRUE(res != NULL);
- EXPECT_NOT_POISONED(res[0]);
- free(res);
-}
-#endif
-
-TEST(MemorySanitizer, shmctl) {
- int id = shmget(IPC_PRIVATE, 4096, 0644 | IPC_CREAT);
- ASSERT_GT(id, -1);
-
- struct shmid_ds ds;
- int res = shmctl(id, IPC_STAT, &ds);
- ASSERT_GT(res, -1);
- EXPECT_NOT_POISONED(ds);
-
- // FreeBSD does not support shmctl(IPC_INFO) and shmctl(SHM_INFO).
-#if !defined(__FreeBSD__)
- struct shminfo si;
- res = shmctl(id, IPC_INFO, (struct shmid_ds *)&si);
- ASSERT_GT(res, -1);
- EXPECT_NOT_POISONED(si);
-
- struct shm_info s_i;
- res = shmctl(id, SHM_INFO, (struct shmid_ds *)&s_i);
- ASSERT_GT(res, -1);
- EXPECT_NOT_POISONED(s_i);
-#endif
-
- res = shmctl(id, IPC_RMID, 0);
- ASSERT_GT(res, -1);
-}
-
-TEST(MemorySanitizer, shmat) {
- void *p = mmap(NULL, 4096, PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
- ASSERT_NE(MAP_FAILED, p);
-
- ((char *)p)[10] = *GetPoisoned<U1>();
- ((char *)p)[4095] = *GetPoisoned<U1>();
-
- int res = munmap(p, 4096);
- ASSERT_EQ(0, res);
-
- int id = shmget(IPC_PRIVATE, 4096, 0644 | IPC_CREAT);
- ASSERT_GT(id, -1);
-
- void *q = shmat(id, p, 0);
- ASSERT_EQ(p, q);
-
- EXPECT_NOT_POISONED(((char *)q)[0]);
- EXPECT_NOT_POISONED(((char *)q)[10]);
- EXPECT_NOT_POISONED(((char *)q)[4095]);
-
- res = shmdt(q);
- ASSERT_EQ(0, res);
-
- res = shmctl(id, IPC_RMID, 0);
- ASSERT_GT(res, -1);
-}
-
-// There's no random_r() on FreeBSD.
-#if !defined(__FreeBSD__)
-TEST(MemorySanitizer, random_r) {
- int32_t x;
- char z[64];
- memset(z, 0, sizeof(z));
-
- struct random_data buf;
- memset(&buf, 0, sizeof(buf));
-
- int res = initstate_r(0, z, sizeof(z), &buf);
- ASSERT_EQ(0, res);
-
- res = random_r(&buf, &x);
- ASSERT_EQ(0, res);
- EXPECT_NOT_POISONED(x);
-}
-#endif
-
-TEST(MemorySanitizer, confstr) {
- char buf[3];
- size_t res = confstr(_CS_PATH, buf, sizeof(buf));
- ASSERT_GT(res, sizeof(buf));
- EXPECT_NOT_POISONED(buf[0]);
- EXPECT_NOT_POISONED(buf[sizeof(buf) - 1]);
-
- char buf2[1000];
- res = confstr(_CS_PATH, buf2, sizeof(buf2));
- ASSERT_LT(res, sizeof(buf2));
- EXPECT_NOT_POISONED(buf2[0]);
- EXPECT_NOT_POISONED(buf2[res - 1]);
- EXPECT_POISONED(buf2[res]);
- ASSERT_EQ(res, strlen(buf2) + 1);
-}
-
-TEST(MemorySanitizer, opendir) {
- DIR *dir = opendir(".");
- closedir(dir);
-
- char name[10] = ".";
- __msan_poison(name, sizeof(name));
- EXPECT_UMR(dir = opendir(name));
- closedir(dir);
-}
-
-TEST(MemorySanitizer, readdir) {
- DIR *dir = opendir(".");
- struct dirent *d = readdir(dir);
- ASSERT_TRUE(d != NULL);
- EXPECT_NOT_POISONED(d->d_name[0]);
- closedir(dir);
-}
-
-TEST(MemorySanitizer, readdir_r) {
- DIR *dir = opendir(".");
- struct dirent d;
- struct dirent *pd;
- int res = readdir_r(dir, &d, &pd);
- ASSERT_EQ(0, res);
- EXPECT_NOT_POISONED(pd);
- EXPECT_NOT_POISONED(d.d_name[0]);
- closedir(dir);
-}
-
-TEST(MemorySanitizer, realpath) {
- const char* relpath = ".";
- char path[PATH_MAX + 1];
- char* res = realpath(relpath, path);
- ASSERT_TRUE(res != NULL);
- EXPECT_NOT_POISONED(path[0]);
-}
-
-TEST(MemorySanitizer, realpath_null) {
- const char* relpath = ".";
- char* res = realpath(relpath, NULL);
- printf("%d, %s\n", errno, strerror(errno));
- ASSERT_TRUE(res != NULL);
- EXPECT_NOT_POISONED(res[0]);
- free(res);
-}
-
-// There's no canonicalize_file_name() on FreeBSD.
-#if !defined(__FreeBSD__)
-TEST(MemorySanitizer, canonicalize_file_name) {
- const char* relpath = ".";
- char* res = canonicalize_file_name(relpath);
- ASSERT_TRUE(res != NULL);
- EXPECT_NOT_POISONED(res[0]);
- free(res);
-}
-#endif
-
-extern char **environ;
-
-TEST(MemorySanitizer, setenv) {
- setenv("AAA", "BBB", 1);
- for (char **envp = environ; *envp; ++envp) {
- EXPECT_NOT_POISONED(*envp);
- EXPECT_NOT_POISONED(*envp[0]);
- }
-}
-
-TEST(MemorySanitizer, putenv) {
- char s[] = "AAA=BBB";
- putenv(s);
- for (char **envp = environ; *envp; ++envp) {
- EXPECT_NOT_POISONED(*envp);
- EXPECT_NOT_POISONED(*envp[0]);
- }
-}
-
-TEST(MemorySanitizer, memcpy) {
- char* x = new char[2];
- char* y = new char[2];
- x[0] = 1;
- x[1] = *GetPoisoned<char>();
- memcpy(y, x, 2);
- EXPECT_NOT_POISONED(y[0]);
- EXPECT_POISONED(y[1]);
-}
-
-void TestUnalignedMemcpy(unsigned left, unsigned right, bool src_is_aligned,
- bool src_is_poisoned, bool dst_is_poisoned) {
- fprintf(stderr, "%s(%d, %d, %d, %d, %d)\n", __func__, left, right,
- src_is_aligned, src_is_poisoned, dst_is_poisoned);
-
- const unsigned sz = 20;
- U4 dst_origin, src_origin;
- char *dst = (char *)malloc(sz);
- if (dst_is_poisoned)
- dst_origin = __msan_get_origin(dst);
- else
- memset(dst, 0, sz);
-
- char *src = (char *)malloc(sz);
- if (src_is_poisoned)
- src_origin = __msan_get_origin(src);
- else
- memset(src, 0, sz);
-
- memcpy(dst + left, src_is_aligned ? src + left : src, sz - left - right);
-
- for (unsigned i = 0; i < (left & (~3U)); ++i)
- if (dst_is_poisoned)
- EXPECT_POISONED_O(dst[i], dst_origin);
- else
- EXPECT_NOT_POISONED(dst[i]);
-
- for (unsigned i = 0; i < (right & (~3U)); ++i)
- if (dst_is_poisoned)
- EXPECT_POISONED_O(dst[sz - i - 1], dst_origin);
- else
- EXPECT_NOT_POISONED(dst[sz - i - 1]);
-
- for (unsigned i = left; i < sz - right; ++i)
- if (src_is_poisoned)
- EXPECT_POISONED_O(dst[i], src_origin);
- else
- EXPECT_NOT_POISONED(dst[i]);
-
- free(dst);
- free(src);
-}
-
-TEST(MemorySanitizer, memcpy_unaligned) {
- for (int i = 0; i < 10; ++i)
- for (int j = 0; j < 10; ++j)
- for (int aligned = 0; aligned < 2; ++aligned)
- for (int srcp = 0; srcp < 2; ++srcp)
- for (int dstp = 0; dstp < 2; ++dstp)
- TestUnalignedMemcpy(i, j, aligned, srcp, dstp);
-}
-
-TEST(MemorySanitizer, memmove) {
- char* x = new char[2];
- char* y = new char[2];
- x[0] = 1;
- x[1] = *GetPoisoned<char>();
- memmove(y, x, 2);
- EXPECT_NOT_POISONED(y[0]);
- EXPECT_POISONED(y[1]);
-}
-
-TEST(MemorySanitizer, memccpy_nomatch) {
- char* x = new char[5];
- char* y = new char[5];
- strcpy(x, "abc");
- memccpy(y, x, 'd', 4);
- EXPECT_NOT_POISONED(y[0]);
- EXPECT_NOT_POISONED(y[1]);
- EXPECT_NOT_POISONED(y[2]);
- EXPECT_NOT_POISONED(y[3]);
- EXPECT_POISONED(y[4]);
- delete[] x;
- delete[] y;
-}
-
-TEST(MemorySanitizer, memccpy_match) {
- char* x = new char[5];
- char* y = new char[5];
- strcpy(x, "abc");
- memccpy(y, x, 'b', 4);
- EXPECT_NOT_POISONED(y[0]);
- EXPECT_NOT_POISONED(y[1]);
- EXPECT_POISONED(y[2]);
- EXPECT_POISONED(y[3]);
- EXPECT_POISONED(y[4]);
- delete[] x;
- delete[] y;
-}
-
-TEST(MemorySanitizer, memccpy_nomatch_positive) {
- char* x = new char[5];
- char* y = new char[5];
- strcpy(x, "abc");
- EXPECT_UMR(memccpy(y, x, 'd', 5));
- delete[] x;
- delete[] y;
-}
-
-TEST(MemorySanitizer, memccpy_match_positive) {
- char* x = new char[5];
- char* y = new char[5];
- x[0] = 'a';
- x[2] = 'b';
- EXPECT_UMR(memccpy(y, x, 'b', 5));
- delete[] x;
- delete[] y;
-}
-
-TEST(MemorySanitizer, bcopy) {
- char* x = new char[2];
- char* y = new char[2];
- x[0] = 1;
- x[1] = *GetPoisoned<char>();
- bcopy(x, y, 2);
- EXPECT_NOT_POISONED(y[0]);
- EXPECT_POISONED(y[1]);
-}
-
-TEST(MemorySanitizer, strdup) {
- char buf[4] = "abc";
- __msan_poison(buf + 2, sizeof(*buf));
- char *x = strdup(buf);
- EXPECT_NOT_POISONED(x[0]);
- EXPECT_NOT_POISONED(x[1]);
- EXPECT_POISONED(x[2]);
- EXPECT_NOT_POISONED(x[3]);
- free(x);
-}
-
-TEST(MemorySanitizer, strndup) {
- char buf[4] = "abc";
- __msan_poison(buf + 2, sizeof(*buf));
- char *x = strndup(buf, 3);
- EXPECT_NOT_POISONED(x[0]);
- EXPECT_NOT_POISONED(x[1]);
- EXPECT_POISONED(x[2]);
- EXPECT_NOT_POISONED(x[3]);
- free(x);
-}
-
-TEST(MemorySanitizer, strndup_short) {
- char buf[4] = "abc";
- __msan_poison(buf + 1, sizeof(*buf));
- __msan_poison(buf + 2, sizeof(*buf));
- char *x = strndup(buf, 2);
- EXPECT_NOT_POISONED(x[0]);
- EXPECT_POISONED(x[1]);
- EXPECT_NOT_POISONED(x[2]);
- free(x);
-}
-
-
-template<class T, int size>
-void TestOverlapMemmove() {
- T *x = new T[size];
- ASSERT_GE(size, 3);
- x[2] = 0;
- memmove(x, x + 1, (size - 1) * sizeof(T));
- EXPECT_NOT_POISONED(x[1]);
- EXPECT_POISONED(x[0]);
- EXPECT_POISONED(x[2]);
- delete [] x;
-}
-
-TEST(MemorySanitizer, overlap_memmove) {
- TestOverlapMemmove<U1, 10>();
- TestOverlapMemmove<U1, 1000>();
- TestOverlapMemmove<U8, 4>();
- TestOverlapMemmove<U8, 1000>();
-}
-
-TEST(MemorySanitizer, strcpy) { // NOLINT
- char* x = new char[3];
- char* y = new char[3];
- x[0] = 'a';
- x[1] = *GetPoisoned<char>(1, 1);
- x[2] = 0;
- strcpy(y, x); // NOLINT
- EXPECT_NOT_POISONED(y[0]);
- EXPECT_POISONED(y[1]);
- EXPECT_NOT_POISONED(y[2]);
-}
-
-TEST(MemorySanitizer, strncpy) { // NOLINT
- char* x = new char[3];
- char* y = new char[5];
- x[0] = 'a';
- x[1] = *GetPoisoned<char>(1, 1);
- x[2] = '\0';
- strncpy(y, x, 4); // NOLINT
- EXPECT_NOT_POISONED(y[0]);
- EXPECT_POISONED(y[1]);
- EXPECT_NOT_POISONED(y[2]);
- EXPECT_NOT_POISONED(y[3]);
- EXPECT_POISONED(y[4]);
-}
-
-TEST(MemorySanitizer, stpcpy) { // NOLINT
- char* x = new char[3];
- char* y = new char[3];
- x[0] = 'a';
- x[1] = *GetPoisoned<char>(1, 1);
- x[2] = 0;
- char *res = stpcpy(y, x); // NOLINT
- ASSERT_EQ(res, y + 2);
- EXPECT_NOT_POISONED(y[0]);
- EXPECT_POISONED(y[1]);
- EXPECT_NOT_POISONED(y[2]);
-}
-
-TEST(MemorySanitizer, strcat) { // NOLINT
- char a[10];
- char b[] = "def";
- strcpy(a, "abc");
- __msan_poison(b + 1, 1);
- strcat(a, b);
- EXPECT_NOT_POISONED(a[3]);
- EXPECT_POISONED(a[4]);
- EXPECT_NOT_POISONED(a[5]);
- EXPECT_NOT_POISONED(a[6]);
- EXPECT_POISONED(a[7]);
-}
-
-TEST(MemorySanitizer, strncat) { // NOLINT
- char a[10];
- char b[] = "def";
- strcpy(a, "abc");
- __msan_poison(b + 1, 1);
- strncat(a, b, 5);
- EXPECT_NOT_POISONED(a[3]);
- EXPECT_POISONED(a[4]);
- EXPECT_NOT_POISONED(a[5]);
- EXPECT_NOT_POISONED(a[6]);
- EXPECT_POISONED(a[7]);
-}
-
-TEST(MemorySanitizer, strncat_overflow) { // NOLINT
- char a[10];
- char b[] = "def";
- strcpy(a, "abc");
- __msan_poison(b + 1, 1);
- strncat(a, b, 2);
- EXPECT_NOT_POISONED(a[3]);
- EXPECT_POISONED(a[4]);
- EXPECT_NOT_POISONED(a[5]);
- EXPECT_POISONED(a[6]);
- EXPECT_POISONED(a[7]);
-}
-
-#define TEST_STRTO_INT(func_name, char_type, str_prefix) \
- TEST(MemorySanitizer, func_name) { \
- char_type *e; \
- EXPECT_EQ(1U, func_name(str_prefix##"1", &e, 10)); \
- EXPECT_NOT_POISONED((S8)e); \
- }
-
-#define TEST_STRTO_FLOAT(func_name, char_type, str_prefix) \
- TEST(MemorySanitizer, func_name) { \
- char_type *e; \
- EXPECT_NE(0, func_name(str_prefix##"1.5", &e)); \
- EXPECT_NOT_POISONED((S8)e); \
- }
-
-#define TEST_STRTO_FLOAT_LOC(func_name, char_type, str_prefix) \
- TEST(MemorySanitizer, func_name) { \
- locale_t loc = newlocale(LC_NUMERIC_MASK, "C", (locale_t)0); \
- char_type *e; \
- EXPECT_NE(0, func_name(str_prefix##"1.5", &e, loc)); \
- EXPECT_NOT_POISONED((S8)e); \
- freelocale(loc); \
- }
-
-#define TEST_STRTO_INT_LOC(func_name, char_type, str_prefix) \
- TEST(MemorySanitizer, func_name) { \
- locale_t loc = newlocale(LC_NUMERIC_MASK, "C", (locale_t)0); \
- char_type *e; \
- ASSERT_EQ(1U, func_name(str_prefix##"1", &e, 10, loc)); \
- EXPECT_NOT_POISONED((S8)e); \
- freelocale(loc); \
- }
-
-TEST_STRTO_INT(strtol, char, )
-TEST_STRTO_INT(strtoll, char, )
-TEST_STRTO_INT(strtoul, char, )
-TEST_STRTO_INT(strtoull, char, )
-
-TEST_STRTO_FLOAT(strtof, char, )
-TEST_STRTO_FLOAT(strtod, char, )
-TEST_STRTO_FLOAT(strtold, char, )
-
-TEST_STRTO_FLOAT_LOC(strtof_l, char, )
-TEST_STRTO_FLOAT_LOC(strtod_l, char, )
-TEST_STRTO_FLOAT_LOC(strtold_l, char, )
-
-TEST_STRTO_INT_LOC(strtol_l, char, )
-TEST_STRTO_INT_LOC(strtoll_l, char, )
-TEST_STRTO_INT_LOC(strtoul_l, char, )
-TEST_STRTO_INT_LOC(strtoull_l, char, )
-
-TEST_STRTO_INT(wcstol, wchar_t, L)
-TEST_STRTO_INT(wcstoll, wchar_t, L)
-TEST_STRTO_INT(wcstoul, wchar_t, L)
-TEST_STRTO_INT(wcstoull, wchar_t, L)
-
-TEST_STRTO_FLOAT(wcstof, wchar_t, L)
-TEST_STRTO_FLOAT(wcstod, wchar_t, L)
-TEST_STRTO_FLOAT(wcstold, wchar_t, L)
-
-TEST_STRTO_FLOAT_LOC(wcstof_l, wchar_t, L)
-TEST_STRTO_FLOAT_LOC(wcstod_l, wchar_t, L)
-TEST_STRTO_FLOAT_LOC(wcstold_l, wchar_t, L)
-
-TEST_STRTO_INT_LOC(wcstol_l, wchar_t, L)
-TEST_STRTO_INT_LOC(wcstoll_l, wchar_t, L)
-TEST_STRTO_INT_LOC(wcstoul_l, wchar_t, L)
-TEST_STRTO_INT_LOC(wcstoull_l, wchar_t, L)
-
-
-TEST(MemorySanitizer, strtoimax) {
- char *e;
- ASSERT_EQ(1, strtoimax("1", &e, 10));
- EXPECT_NOT_POISONED((S8) e);
-}
-
-TEST(MemorySanitizer, strtoumax) {
- char *e;
- ASSERT_EQ(1U, strtoumax("1", &e, 10));
- EXPECT_NOT_POISONED((S8) e);
-}
-
-#ifdef __GLIBC__
-extern "C" float __strtof_l(const char *nptr, char **endptr, locale_t loc);
-TEST_STRTO_FLOAT_LOC(__strtof_l, char, )
-extern "C" double __strtod_l(const char *nptr, char **endptr, locale_t loc);
-TEST_STRTO_FLOAT_LOC(__strtod_l, char, )
-extern "C" long double __strtold_l(const char *nptr, char **endptr,
- locale_t loc);
-TEST_STRTO_FLOAT_LOC(__strtold_l, char, )
-
-extern "C" float __wcstof_l(const wchar_t *nptr, wchar_t **endptr, locale_t loc);
-TEST_STRTO_FLOAT_LOC(__wcstof_l, wchar_t, L)
-extern "C" double __wcstod_l(const wchar_t *nptr, wchar_t **endptr, locale_t loc);
-TEST_STRTO_FLOAT_LOC(__wcstod_l, wchar_t, L)
-extern "C" long double __wcstold_l(const wchar_t *nptr, wchar_t **endptr,
- locale_t loc);
-TEST_STRTO_FLOAT_LOC(__wcstold_l, wchar_t, L)
-#endif // __GLIBC__
-
-TEST(MemorySanitizer, modf) {
- double x, y;
- x = modf(2.1, &y);
- EXPECT_NOT_POISONED(y);
-}
-
-TEST(MemorySanitizer, modff) {
- float x, y;
- x = modff(2.1, &y);
- EXPECT_NOT_POISONED(y);
-}
-
-TEST(MemorySanitizer, modfl) {
- long double x, y;
- x = modfl(2.1, &y);
- EXPECT_NOT_POISONED(y);
-}
-
-// There's no sincos() on FreeBSD.
-#if !defined(__FreeBSD__)
-TEST(MemorySanitizer, sincos) {
- double s, c;
- sincos(0.2, &s, &c);
- EXPECT_NOT_POISONED(s);
- EXPECT_NOT_POISONED(c);
-}
-#endif
-
-// There's no sincosf() on FreeBSD.
-#if !defined(__FreeBSD__)
-TEST(MemorySanitizer, sincosf) {
- float s, c;
- sincosf(0.2, &s, &c);
- EXPECT_NOT_POISONED(s);
- EXPECT_NOT_POISONED(c);
-}
-#endif
-
-// There's no sincosl() on FreeBSD.
-#if !defined(__FreeBSD__)
-TEST(MemorySanitizer, sincosl) {
- long double s, c;
- sincosl(0.2, &s, &c);
- EXPECT_NOT_POISONED(s);
- EXPECT_NOT_POISONED(c);
-}
-#endif
-
-TEST(MemorySanitizer, remquo) {
- int quo;
- double res = remquo(29.0, 3.0, &quo);
- ASSERT_NE(0.0, res);
- EXPECT_NOT_POISONED(quo);
-}
-
-TEST(MemorySanitizer, remquof) {
- int quo;
- float res = remquof(29.0, 3.0, &quo);
- ASSERT_NE(0.0, res);
- EXPECT_NOT_POISONED(quo);
-}
-
-TEST(MemorySanitizer, remquol) {
- int quo;
- long double res = remquof(29.0, 3.0, &quo);
- ASSERT_NE(0.0, res);
- EXPECT_NOT_POISONED(quo);
-}
-
-TEST(MemorySanitizer, lgamma) {
- double res = lgamma(1.1);
- ASSERT_NE(0.0, res);
- EXPECT_NOT_POISONED(signgam);
-}
-
-TEST(MemorySanitizer, lgammaf) {
- float res = lgammaf(1.1);
- ASSERT_NE(0.0, res);
- EXPECT_NOT_POISONED(signgam);
-}
-
-TEST(MemorySanitizer, lgammal) {
- long double res = lgammal(1.1);
- ASSERT_NE(0.0, res);
- EXPECT_NOT_POISONED(signgam);
-}
-
-TEST(MemorySanitizer, lgamma_r) {
- int sgn;
- double res = lgamma_r(1.1, &sgn);
- ASSERT_NE(0.0, res);
- EXPECT_NOT_POISONED(sgn);
-}
-
-TEST(MemorySanitizer, lgammaf_r) {
- int sgn;
- float res = lgammaf_r(1.1, &sgn);
- ASSERT_NE(0.0, res);
- EXPECT_NOT_POISONED(sgn);
-}
-
-// There's no lgammal_r() on FreeBSD.
-#if !defined(__FreeBSD__)
-TEST(MemorySanitizer, lgammal_r) {
- int sgn;
- long double res = lgammal_r(1.1, &sgn);
- ASSERT_NE(0.0, res);
- EXPECT_NOT_POISONED(sgn);
-}
-#endif
-
-// There's no drand48_r() on FreeBSD.
-#if !defined(__FreeBSD__)
-TEST(MemorySanitizer, drand48_r) {
- struct drand48_data buf;
- srand48_r(0, &buf);
- double d;
- drand48_r(&buf, &d);
- EXPECT_NOT_POISONED(d);
-}
-#endif
-
-// There's no lrand48_r() on FreeBSD.
-#if !defined(__FreeBSD__)
-TEST(MemorySanitizer, lrand48_r) {
- struct drand48_data buf;
- srand48_r(0, &buf);
- long d;
- lrand48_r(&buf, &d);
- EXPECT_NOT_POISONED(d);
-}
-#endif
-
-TEST(MemorySanitizer, sprintf) { // NOLINT
- char buff[10];
- break_optimization(buff);
- EXPECT_POISONED(buff[0]);
- int res = sprintf(buff, "%d", 1234567); // NOLINT
- ASSERT_EQ(res, 7);
- ASSERT_EQ(buff[0], '1');
- ASSERT_EQ(buff[1], '2');
- ASSERT_EQ(buff[2], '3');
- ASSERT_EQ(buff[6], '7');
- ASSERT_EQ(buff[7], 0);
- EXPECT_POISONED(buff[8]);
-}
-
-TEST(MemorySanitizer, snprintf) {
- char buff[10];
- break_optimization(buff);
- EXPECT_POISONED(buff[0]);
- int res = snprintf(buff, sizeof(buff), "%d", 1234567);
- ASSERT_EQ(res, 7);
- ASSERT_EQ(buff[0], '1');
- ASSERT_EQ(buff[1], '2');
- ASSERT_EQ(buff[2], '3');
- ASSERT_EQ(buff[6], '7');
- ASSERT_EQ(buff[7], 0);
- EXPECT_POISONED(buff[8]);
-}
-
-TEST(MemorySanitizer, swprintf) {
- wchar_t buff[10];
- ASSERT_EQ(4U, sizeof(wchar_t));
- break_optimization(buff);
- EXPECT_POISONED(buff[0]);
- int res = swprintf(buff, 9, L"%d", 1234567);
- ASSERT_EQ(res, 7);
- ASSERT_EQ(buff[0], '1');
- ASSERT_EQ(buff[1], '2');
- ASSERT_EQ(buff[2], '3');
- ASSERT_EQ(buff[6], '7');
- ASSERT_EQ(buff[7], 0);
- EXPECT_POISONED(buff[8]);
-}
-
-TEST(MemorySanitizer, asprintf) { // NOLINT
- char *pbuf;
- EXPECT_POISONED(pbuf);
- int res = asprintf(&pbuf, "%d", 1234567); // NOLINT
- ASSERT_EQ(res, 7);
- EXPECT_NOT_POISONED(pbuf);
- ASSERT_EQ(pbuf[0], '1');
- ASSERT_EQ(pbuf[1], '2');
- ASSERT_EQ(pbuf[2], '3');
- ASSERT_EQ(pbuf[6], '7');
- ASSERT_EQ(pbuf[7], 0);
- free(pbuf);
-}
-
-TEST(MemorySanitizer, mbstowcs) {
- const char *x = "abc";
- wchar_t buff[10];
- int res = mbstowcs(buff, x, 2);
- EXPECT_EQ(2, res);
- EXPECT_EQ(L'a', buff[0]);
- EXPECT_EQ(L'b', buff[1]);
- EXPECT_POISONED(buff[2]);
- res = mbstowcs(buff, x, 10);
- EXPECT_EQ(3, res);
- EXPECT_NOT_POISONED(buff[3]);
-}
-
-TEST(MemorySanitizer, wcstombs) {
- const wchar_t *x = L"abc";
- char buff[10];
- int res = wcstombs(buff, x, 4);
- EXPECT_EQ(res, 3);
- EXPECT_EQ(buff[0], 'a');
- EXPECT_EQ(buff[1], 'b');
- EXPECT_EQ(buff[2], 'c');
-}
-
-TEST(MemorySanitizer, wcsrtombs) {
- const wchar_t *x = L"abc";
- const wchar_t *p = x;
- char buff[10];
- mbstate_t mbs;
- memset(&mbs, 0, sizeof(mbs));
- int res = wcsrtombs(buff, &p, 4, &mbs);
- EXPECT_EQ(res, 3);
- EXPECT_EQ(buff[0], 'a');
- EXPECT_EQ(buff[1], 'b');
- EXPECT_EQ(buff[2], 'c');
- EXPECT_EQ(buff[3], '\0');
- EXPECT_POISONED(buff[4]);
-}
-
-TEST(MemorySanitizer, wcsnrtombs) {
- const wchar_t *x = L"abc";
- const wchar_t *p = x;
- char buff[10];
- mbstate_t mbs;
- memset(&mbs, 0, sizeof(mbs));
- int res = wcsnrtombs(buff, &p, 2, 4, &mbs);
- EXPECT_EQ(res, 2);
- EXPECT_EQ(buff[0], 'a');
- EXPECT_EQ(buff[1], 'b');
- EXPECT_POISONED(buff[2]);
-}
-
-TEST(MemorySanitizer, wmemset) {
- wchar_t x[25];
- break_optimization(x);
- EXPECT_POISONED(x[0]);
- wmemset(x, L'A', 10);
- EXPECT_EQ(x[0], L'A');
- EXPECT_EQ(x[9], L'A');
- EXPECT_POISONED(x[10]);
-}
-
-TEST(MemorySanitizer, mbtowc) {
- const char *x = "abc";
- wchar_t wx;
- int res = mbtowc(&wx, x, 3);
- EXPECT_GT(res, 0);
- EXPECT_NOT_POISONED(wx);
-}
-
-TEST(MemorySanitizer, mbrtowc) {
- const char *x = "abc";
- wchar_t wx;
- mbstate_t mbs;
- memset(&mbs, 0, sizeof(mbs));
- int res = mbrtowc(&wx, x, 3, &mbs);
- EXPECT_GT(res, 0);
- EXPECT_NOT_POISONED(wx);
-}
-
-TEST(MemorySanitizer, wcsftime) {
- wchar_t x[100];
- time_t t = time(NULL);
- struct tm tms;
- struct tm *tmres = localtime_r(&t, &tms);
- ASSERT_NE((void *)0, tmres);
- size_t res = wcsftime(x, sizeof(x) / sizeof(x[0]), L"%Y-%m-%d", tmres);
- EXPECT_GT(res, 0UL);
- EXPECT_EQ(res, wcslen(x));
-}
-
-TEST(MemorySanitizer, gettimeofday) {
- struct timeval tv;
- struct timezone tz;
- break_optimization(&tv);
- break_optimization(&tz);
- ASSERT_EQ(16U, sizeof(tv));
- ASSERT_EQ(8U, sizeof(tz));
- EXPECT_POISONED(tv.tv_sec);
- EXPECT_POISONED(tv.tv_usec);
- EXPECT_POISONED(tz.tz_minuteswest);
- EXPECT_POISONED(tz.tz_dsttime);
- ASSERT_EQ(0, gettimeofday(&tv, &tz));
- EXPECT_NOT_POISONED(tv.tv_sec);
- EXPECT_NOT_POISONED(tv.tv_usec);
- EXPECT_NOT_POISONED(tz.tz_minuteswest);
- EXPECT_NOT_POISONED(tz.tz_dsttime);
-}
-
-TEST(MemorySanitizer, clock_gettime) {
- struct timespec tp;
- EXPECT_POISONED(tp.tv_sec);
- EXPECT_POISONED(tp.tv_nsec);
- ASSERT_EQ(0, clock_gettime(CLOCK_REALTIME, &tp));
- EXPECT_NOT_POISONED(tp.tv_sec);
- EXPECT_NOT_POISONED(tp.tv_nsec);
-}
-
-TEST(MemorySanitizer, clock_getres) {
- struct timespec tp;
- EXPECT_POISONED(tp.tv_sec);
- EXPECT_POISONED(tp.tv_nsec);
- ASSERT_EQ(0, clock_getres(CLOCK_REALTIME, 0));
- EXPECT_POISONED(tp.tv_sec);
- EXPECT_POISONED(tp.tv_nsec);
- ASSERT_EQ(0, clock_getres(CLOCK_REALTIME, &tp));
- EXPECT_NOT_POISONED(tp.tv_sec);
- EXPECT_NOT_POISONED(tp.tv_nsec);
-}
-
-TEST(MemorySanitizer, getitimer) {
- struct itimerval it1, it2;
- int res;
- EXPECT_POISONED(it1.it_interval.tv_sec);
- EXPECT_POISONED(it1.it_interval.tv_usec);
- EXPECT_POISONED(it1.it_value.tv_sec);
- EXPECT_POISONED(it1.it_value.tv_usec);
- res = getitimer(ITIMER_VIRTUAL, &it1);
- ASSERT_EQ(0, res);
- EXPECT_NOT_POISONED(it1.it_interval.tv_sec);
- EXPECT_NOT_POISONED(it1.it_interval.tv_usec);
- EXPECT_NOT_POISONED(it1.it_value.tv_sec);
- EXPECT_NOT_POISONED(it1.it_value.tv_usec);
-
- it1.it_interval.tv_sec = it1.it_value.tv_sec = 10000;
- it1.it_interval.tv_usec = it1.it_value.tv_usec = 0;
-
- res = setitimer(ITIMER_VIRTUAL, &it1, &it2);
- ASSERT_EQ(0, res);
- EXPECT_NOT_POISONED(it2.it_interval.tv_sec);
- EXPECT_NOT_POISONED(it2.it_interval.tv_usec);
- EXPECT_NOT_POISONED(it2.it_value.tv_sec);
- EXPECT_NOT_POISONED(it2.it_value.tv_usec);
-
- // Check that old_value can be 0, and disable the timer.
- memset(&it1, 0, sizeof(it1));
- res = setitimer(ITIMER_VIRTUAL, &it1, 0);
- ASSERT_EQ(0, res);
-}
-
-TEST(MemorySanitizer, setitimer_null) {
- setitimer(ITIMER_VIRTUAL, 0, 0);
- // Not testing the return value, since it the behaviour seems to differ
- // between libc implementations and POSIX.
- // Should never crash, though.
-}
-
-TEST(MemorySanitizer, time) {
- time_t t;
- EXPECT_POISONED(t);
- time_t t2 = time(&t);
- ASSERT_NE(t2, (time_t)-1);
- EXPECT_NOT_POISONED(t);
-}
-
-TEST(MemorySanitizer, strptime) {
- struct tm time;
- char *p = strptime("11/1/2013-05:39", "%m/%d/%Y-%H:%M", &time);
- ASSERT_TRUE(p != NULL);
- EXPECT_NOT_POISONED(time.tm_sec);
- EXPECT_NOT_POISONED(time.tm_hour);
- EXPECT_NOT_POISONED(time.tm_year);
-}
-
-TEST(MemorySanitizer, localtime) {
- time_t t = 123;
- struct tm *time = localtime(&t);
- ASSERT_TRUE(time != NULL);
- EXPECT_NOT_POISONED(time->tm_sec);
- EXPECT_NOT_POISONED(time->tm_hour);
- EXPECT_NOT_POISONED(time->tm_year);
- EXPECT_NOT_POISONED(time->tm_isdst);
- EXPECT_NE(0U, strlen(time->tm_zone));
-}
-
-TEST(MemorySanitizer, localtime_r) {
- time_t t = 123;
- struct tm time;
- struct tm *res = localtime_r(&t, &time);
- ASSERT_TRUE(res != NULL);
- EXPECT_NOT_POISONED(time.tm_sec);
- EXPECT_NOT_POISONED(time.tm_hour);
- EXPECT_NOT_POISONED(time.tm_year);
- EXPECT_NOT_POISONED(time.tm_isdst);
- EXPECT_NE(0U, strlen(time.tm_zone));
-}
-
-// There's no getmntent() on FreeBSD.
-#if !defined(__FreeBSD__)
-TEST(MemorySanitizer, getmntent) {
- FILE *fp = setmntent("/etc/fstab", "r");
- struct mntent *mnt = getmntent(fp);
- ASSERT_TRUE(mnt != NULL);
- ASSERT_NE(0U, strlen(mnt->mnt_fsname));
- ASSERT_NE(0U, strlen(mnt->mnt_dir));
- ASSERT_NE(0U, strlen(mnt->mnt_type));
- ASSERT_NE(0U, strlen(mnt->mnt_opts));
- EXPECT_NOT_POISONED(mnt->mnt_freq);
- EXPECT_NOT_POISONED(mnt->mnt_passno);
- fclose(fp);
-}
-#endif
-
-// There's no getmntent_r() on FreeBSD.
-#if !defined(__FreeBSD__)
-TEST(MemorySanitizer, getmntent_r) {
- FILE *fp = setmntent("/etc/fstab", "r");
- struct mntent mntbuf;
- char buf[1000];
- struct mntent *mnt = getmntent_r(fp, &mntbuf, buf, sizeof(buf));
- ASSERT_TRUE(mnt != NULL);
- ASSERT_NE(0U, strlen(mnt->mnt_fsname));
- ASSERT_NE(0U, strlen(mnt->mnt_dir));
- ASSERT_NE(0U, strlen(mnt->mnt_type));
- ASSERT_NE(0U, strlen(mnt->mnt_opts));
- EXPECT_NOT_POISONED(mnt->mnt_freq);
- EXPECT_NOT_POISONED(mnt->mnt_passno);
- fclose(fp);
-}
-#endif
-
-TEST(MemorySanitizer, ether) {
- const char *asc = "11:22:33:44:55:66";
- struct ether_addr *paddr = ether_aton(asc);
- EXPECT_NOT_POISONED(*paddr);
-
- struct ether_addr addr;
- paddr = ether_aton_r(asc, &addr);
- ASSERT_EQ(paddr, &addr);
- EXPECT_NOT_POISONED(addr);
-
- char *s = ether_ntoa(&addr);
- ASSERT_NE(0U, strlen(s));
-
- char buf[100];
- s = ether_ntoa_r(&addr, buf);
- ASSERT_EQ(s, buf);
- ASSERT_NE(0U, strlen(buf));
-}
-
-TEST(MemorySanitizer, mmap) {
- const int size = 4096;
- void *p1, *p2;
- p1 = mmap(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0);
- __msan_poison(p1, size);
- munmap(p1, size);
- for (int i = 0; i < 1000; i++) {
- p2 = mmap(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0);
- if (p2 == p1)
- break;
- else
- munmap(p2, size);
- }
- if (p1 == p2) {
- EXPECT_NOT_POISONED(*(char*)p2);
- munmap(p2, size);
- }
-}
-
-// There's no fcvt() on FreeBSD.
-#if !defined(__FreeBSD__)
-// FIXME: enable and add ecvt.
-// FIXME: check why msandr does nt handle fcvt.
-TEST(MemorySanitizer, fcvt) {
- int a, b;
- break_optimization(&a);
- break_optimization(&b);
- EXPECT_POISONED(a);
- EXPECT_POISONED(b);
- char *str = fcvt(12345.6789, 10, &a, &b);
- EXPECT_NOT_POISONED(a);
- EXPECT_NOT_POISONED(b);
- ASSERT_NE(nullptr, str);
- EXPECT_NOT_POISONED(str[0]);
- ASSERT_NE(0U, strlen(str));
-}
-#endif
-
-// There's no fcvt_long() on FreeBSD.
-#if !defined(__FreeBSD__)
-TEST(MemorySanitizer, fcvt_long) {
- int a, b;
- break_optimization(&a);
- break_optimization(&b);
- EXPECT_POISONED(a);
- EXPECT_POISONED(b);
- char *str = fcvt(111111112345.6789, 10, &a, &b);
- EXPECT_NOT_POISONED(a);
- EXPECT_NOT_POISONED(b);
- ASSERT_NE(nullptr, str);
- EXPECT_NOT_POISONED(str[0]);
- ASSERT_NE(0U, strlen(str));
-}
-#endif
-
-TEST(MemorySanitizer, memchr) {
- char x[10];
- break_optimization(x);
- EXPECT_POISONED(x[0]);
- x[2] = '2';
- void *res;
- EXPECT_UMR(res = memchr(x, '2', 10));
- EXPECT_NOT_POISONED(res);
- x[0] = '0';
- x[1] = '1';
- res = memchr(x, '2', 10);
- EXPECT_EQ(&x[2], res);
- EXPECT_UMR(res = memchr(x, '3', 10));
- EXPECT_NOT_POISONED(res);
-}
-
-TEST(MemorySanitizer, memrchr) {
- char x[10];
- break_optimization(x);
- EXPECT_POISONED(x[0]);
- x[9] = '9';
- void *res;
- EXPECT_UMR(res = memrchr(x, '9', 10));
- EXPECT_NOT_POISONED(res);
- x[0] = '0';
- x[1] = '1';
- res = memrchr(x, '0', 2);
- EXPECT_EQ(&x[0], res);
- EXPECT_UMR(res = memrchr(x, '7', 10));
- EXPECT_NOT_POISONED(res);
-}
-
-TEST(MemorySanitizer, frexp) {
- int x;
- x = *GetPoisoned<int>();
- double r = frexp(1.1, &x);
- EXPECT_NOT_POISONED(r);
- EXPECT_NOT_POISONED(x);
-
- x = *GetPoisoned<int>();
- float rf = frexpf(1.1, &x);
- EXPECT_NOT_POISONED(rf);
- EXPECT_NOT_POISONED(x);
-
- x = *GetPoisoned<int>();
- double rl = frexpl(1.1, &x);
- EXPECT_NOT_POISONED(rl);
- EXPECT_NOT_POISONED(x);
-}
-
-namespace {
-
-static int cnt;
-
-void SigactionHandler(int signo, siginfo_t* si, void* uc) {
- ASSERT_EQ(signo, SIGPROF);
- ASSERT_TRUE(si != NULL);
- EXPECT_NOT_POISONED(si->si_errno);
- EXPECT_NOT_POISONED(si->si_pid);
-#if __linux__
-# if defined(__x86_64__)
- EXPECT_NOT_POISONED(((ucontext_t*)uc)->uc_mcontext.gregs[REG_RIP]);
-# elif defined(__i386__)
- EXPECT_NOT_POISONED(((ucontext_t*)uc)->uc_mcontext.gregs[REG_EIP]);
-# endif
-#endif
- ++cnt;
-}
-
-TEST(MemorySanitizer, sigaction) {
- struct sigaction act = {};
- struct sigaction oldact = {};
- struct sigaction origact = {};
-
- sigaction(SIGPROF, 0, &origact);
-
- act.sa_flags |= SA_SIGINFO;
- act.sa_sigaction = &SigactionHandler;
- sigaction(SIGPROF, &act, 0);
-
- kill(getpid(), SIGPROF);
-
- act.sa_flags &= ~SA_SIGINFO;
- act.sa_handler = SIG_DFL;
- sigaction(SIGPROF, &act, 0);
-
- act.sa_flags &= ~SA_SIGINFO;
- act.sa_handler = SIG_IGN;
- sigaction(SIGPROF, &act, &oldact);
- EXPECT_FALSE(oldact.sa_flags & SA_SIGINFO);
- EXPECT_EQ(SIG_DFL, oldact.sa_handler);
- kill(getpid(), SIGPROF);
-
- act.sa_flags |= SA_SIGINFO;
- act.sa_sigaction = &SigactionHandler;
- sigaction(SIGPROF, &act, &oldact);
- EXPECT_FALSE(oldact.sa_flags & SA_SIGINFO);
- EXPECT_EQ(SIG_IGN, oldact.sa_handler);
- kill(getpid(), SIGPROF);
-
- act.sa_flags &= ~SA_SIGINFO;
- act.sa_handler = SIG_DFL;
- sigaction(SIGPROF, &act, &oldact);
- EXPECT_TRUE(oldact.sa_flags & SA_SIGINFO);
- EXPECT_EQ(&SigactionHandler, oldact.sa_sigaction);
- EXPECT_EQ(2, cnt);
-
- sigaction(SIGPROF, &origact, 0);
-}
-
-} // namespace
-
-
-TEST(MemorySanitizer, sigemptyset) {
- sigset_t s;
- EXPECT_POISONED(s);
- int res = sigemptyset(&s);
- ASSERT_EQ(0, res);
- EXPECT_NOT_POISONED(s);
-}
-
-TEST(MemorySanitizer, sigfillset) {
- sigset_t s;
- EXPECT_POISONED(s);
- int res = sigfillset(&s);
- ASSERT_EQ(0, res);
- EXPECT_NOT_POISONED(s);
-}
-
-TEST(MemorySanitizer, sigpending) {
- sigset_t s;
- EXPECT_POISONED(s);
- int res = sigpending(&s);
- ASSERT_EQ(0, res);
- EXPECT_NOT_POISONED(s);
-}
-
-TEST(MemorySanitizer, sigprocmask) {
- sigset_t s;
- EXPECT_POISONED(s);
- int res = sigprocmask(SIG_BLOCK, 0, &s);
- ASSERT_EQ(0, res);
- EXPECT_NOT_POISONED(s);
-}
-
-struct StructWithDtor {
- ~StructWithDtor();
-};
-
-NOINLINE StructWithDtor::~StructWithDtor() {
- break_optimization(0);
-}
-
-TEST(MemorySanitizer, Invoke) {
- StructWithDtor s; // Will cause the calls to become invokes.
- EXPECT_NOT_POISONED(0);
- EXPECT_POISONED(*GetPoisoned<int>());
- EXPECT_NOT_POISONED(0);
- EXPECT_POISONED(*GetPoisoned<int>());
- EXPECT_POISONED(ReturnPoisoned<S4>());
-}
-
-TEST(MemorySanitizer, ptrtoint) {
- // Test that shadow is propagated through pointer-to-integer conversion.
- void* p = (void*)0xABCD;
- __msan_poison(((char*)&p) + 1, sizeof(p));
- EXPECT_NOT_POISONED((((uintptr_t)p) & 0xFF) == 0);
-
- void* q = (void*)0xABCD;
- __msan_poison(&q, sizeof(q) - 1);
- EXPECT_POISONED((((uintptr_t)q) & 0xFF) == 0);
-}
-
-static void vaargsfn2(int guard, ...) {
- va_list vl;
- va_start(vl, guard);
- EXPECT_NOT_POISONED(va_arg(vl, int));
- EXPECT_NOT_POISONED(va_arg(vl, int));
- EXPECT_NOT_POISONED(va_arg(vl, int));
- EXPECT_POISONED(va_arg(vl, double));
- va_end(vl);
-}
-
-static void vaargsfn(int guard, ...) {
- va_list vl;
- va_start(vl, guard);
- EXPECT_NOT_POISONED(va_arg(vl, int));
- EXPECT_POISONED(va_arg(vl, int));
- // The following call will overwrite __msan_param_tls.
- // Checks after it test that arg shadow was somehow saved across the call.
- vaargsfn2(1, 2, 3, 4, *GetPoisoned<double>());
- EXPECT_NOT_POISONED(va_arg(vl, int));
- EXPECT_POISONED(va_arg(vl, int));
- va_end(vl);
-}
-
-TEST(MemorySanitizer, VAArgTest) {
- int* x = GetPoisoned<int>();
- int* y = GetPoisoned<int>(4);
- vaargsfn(1, 13, *x, 42, *y);
-}
-
-static void vaargsfn_many(int guard, ...) {
- va_list vl;
- va_start(vl, guard);
- EXPECT_NOT_POISONED(va_arg(vl, int));
- EXPECT_POISONED(va_arg(vl, int));
- EXPECT_NOT_POISONED(va_arg(vl, int));
- EXPECT_NOT_POISONED(va_arg(vl, int));
- EXPECT_NOT_POISONED(va_arg(vl, int));
- EXPECT_NOT_POISONED(va_arg(vl, int));
- EXPECT_NOT_POISONED(va_arg(vl, int));
- EXPECT_NOT_POISONED(va_arg(vl, int));
- EXPECT_NOT_POISONED(va_arg(vl, int));
- EXPECT_POISONED(va_arg(vl, int));
- va_end(vl);
-}
-
-TEST(MemorySanitizer, VAArgManyTest) {
- int* x = GetPoisoned<int>();
- int* y = GetPoisoned<int>(4);
- vaargsfn_many(1, 2, *x, 3, 4, 5, 6, 7, 8, 9, *y);
-}
-
-static void vaargsfn_pass2(va_list vl) {
- EXPECT_NOT_POISONED(va_arg(vl, int));
- EXPECT_NOT_POISONED(va_arg(vl, int));
- EXPECT_POISONED(va_arg(vl, int));
-}
-
-static void vaargsfn_pass(int guard, ...) {
- va_list vl;
- va_start(vl, guard);
- EXPECT_POISONED(va_arg(vl, int));
- vaargsfn_pass2(vl);
- va_end(vl);
-}
-
-TEST(MemorySanitizer, VAArgPass) {
- int* x = GetPoisoned<int>();
- int* y = GetPoisoned<int>(4);
- vaargsfn_pass(1, *x, 2, 3, *y);
-}
-
-static void vaargsfn_copy2(va_list vl) {
- EXPECT_NOT_POISONED(va_arg(vl, int));
- EXPECT_POISONED(va_arg(vl, int));
-}
-
-static void vaargsfn_copy(int guard, ...) {
- va_list vl;
- va_start(vl, guard);
- EXPECT_NOT_POISONED(va_arg(vl, int));
- EXPECT_POISONED(va_arg(vl, int));
- va_list vl2;
- va_copy(vl2, vl);
- vaargsfn_copy2(vl2);
- EXPECT_NOT_POISONED(va_arg(vl, int));
- EXPECT_POISONED(va_arg(vl, int));
- va_end(vl);
-}
-
-TEST(MemorySanitizer, VAArgCopy) {
- int* x = GetPoisoned<int>();
- int* y = GetPoisoned<int>(4);
- vaargsfn_copy(1, 2, *x, 3, *y);
-}
-
-static void vaargsfn_ptr(int guard, ...) {
- va_list vl;
- va_start(vl, guard);
- EXPECT_NOT_POISONED(va_arg(vl, int*));
- EXPECT_POISONED(va_arg(vl, int*));
- EXPECT_NOT_POISONED(va_arg(vl, int*));
- EXPECT_POISONED(va_arg(vl, double*));
- va_end(vl);
-}
-
-TEST(MemorySanitizer, VAArgPtr) {
- int** x = GetPoisoned<int*>();
- double** y = GetPoisoned<double*>(8);
- int z;
- vaargsfn_ptr(1, &z, *x, &z, *y);
-}
-
-static void vaargsfn_overflow(int guard, ...) {
- va_list vl;
- va_start(vl, guard);
- EXPECT_NOT_POISONED(va_arg(vl, int));
- EXPECT_NOT_POISONED(va_arg(vl, int));
- EXPECT_POISONED(va_arg(vl, int));
- EXPECT_NOT_POISONED(va_arg(vl, int));
- EXPECT_NOT_POISONED(va_arg(vl, int));
- EXPECT_NOT_POISONED(va_arg(vl, int));
-
- EXPECT_NOT_POISONED(va_arg(vl, double));
- EXPECT_NOT_POISONED(va_arg(vl, double));
- EXPECT_NOT_POISONED(va_arg(vl, double));
- EXPECT_POISONED(va_arg(vl, double));
- EXPECT_NOT_POISONED(va_arg(vl, double));
- EXPECT_POISONED(va_arg(vl, int*));
- EXPECT_NOT_POISONED(va_arg(vl, double));
- EXPECT_NOT_POISONED(va_arg(vl, double));
-
- EXPECT_POISONED(va_arg(vl, int));
- EXPECT_POISONED(va_arg(vl, double));
- EXPECT_POISONED(va_arg(vl, int*));
-
- EXPECT_NOT_POISONED(va_arg(vl, int));
- EXPECT_NOT_POISONED(va_arg(vl, double));
- EXPECT_NOT_POISONED(va_arg(vl, int*));
-
- EXPECT_POISONED(va_arg(vl, int));
- EXPECT_POISONED(va_arg(vl, double));
- EXPECT_POISONED(va_arg(vl, int*));
-
- va_end(vl);
-}
-
-TEST(MemorySanitizer, VAArgOverflow) {
- int* x = GetPoisoned<int>();
- double* y = GetPoisoned<double>(8);
- int** p = GetPoisoned<int*>(16);
- int z;
- vaargsfn_overflow(1,
- 1, 2, *x, 4, 5, 6,
- 1.1, 2.2, 3.3, *y, 5.5, *p, 7.7, 8.8,
- // the following args will overflow for sure
- *x, *y, *p,
- 7, 9.9, &z,
- *x, *y, *p);
-}
-
-static void vaargsfn_tlsoverwrite2(int guard, ...) {
- va_list vl;
- va_start(vl, guard);
- for (int i = 0; i < 20; ++i)
- EXPECT_NOT_POISONED(va_arg(vl, int));
- va_end(vl);
-}
-
-static void vaargsfn_tlsoverwrite(int guard, ...) {
- // This call will overwrite TLS contents unless it's backed up somewhere.
- vaargsfn_tlsoverwrite2(2,
- 42, 42, 42, 42, 42,
- 42, 42, 42, 42, 42,
- 42, 42, 42, 42, 42,
- 42, 42, 42, 42, 42); // 20x
- va_list vl;
- va_start(vl, guard);
- for (int i = 0; i < 20; ++i)
- EXPECT_POISONED(va_arg(vl, int));
- va_end(vl);
-}
-
-TEST(MemorySanitizer, VAArgTLSOverwrite) {
- int* x = GetPoisoned<int>();
- vaargsfn_tlsoverwrite(1,
- *x, *x, *x, *x, *x,
- *x, *x, *x, *x, *x,
- *x, *x, *x, *x, *x,
- *x, *x, *x, *x, *x); // 20x
-
-}
-
-struct StructByVal {
- int a, b, c, d, e, f;
-};
-
-static void vaargsfn_structbyval(int guard, ...) {
- va_list vl;
- va_start(vl, guard);
- {
- StructByVal s = va_arg(vl, StructByVal);
- EXPECT_NOT_POISONED(s.a);
- EXPECT_POISONED(s.b);
- EXPECT_NOT_POISONED(s.c);
- EXPECT_POISONED(s.d);
- EXPECT_NOT_POISONED(s.e);
- EXPECT_POISONED(s.f);
- }
- {
- StructByVal s = va_arg(vl, StructByVal);
- EXPECT_NOT_POISONED(s.a);
- EXPECT_POISONED(s.b);
- EXPECT_NOT_POISONED(s.c);
- EXPECT_POISONED(s.d);
- EXPECT_NOT_POISONED(s.e);
- EXPECT_POISONED(s.f);
- }
- va_end(vl);
-}
-
-TEST(MemorySanitizer, VAArgStructByVal) {
- StructByVal s;
- s.a = 1;
- s.b = *GetPoisoned<int>();
- s.c = 2;
- s.d = *GetPoisoned<int>();
- s.e = 3;
- s.f = *GetPoisoned<int>();
- vaargsfn_structbyval(0, s, s);
-}
-
-NOINLINE void StructByValTestFunc(struct StructByVal s) {
- EXPECT_NOT_POISONED(s.a);
- EXPECT_POISONED(s.b);
- EXPECT_NOT_POISONED(s.c);
- EXPECT_POISONED(s.d);
- EXPECT_NOT_POISONED(s.e);
- EXPECT_POISONED(s.f);
-}
-
-NOINLINE void StructByValTestFunc1(struct StructByVal s) {
- StructByValTestFunc(s);
-}
-
-NOINLINE void StructByValTestFunc2(int z, struct StructByVal s) {
- StructByValTestFunc(s);
-}
-
-TEST(MemorySanitizer, StructByVal) {
- // Large aggregates are passed as "byval" pointer argument in LLVM.
- struct StructByVal s;
- s.a = 1;
- s.b = *GetPoisoned<int>();
- s.c = 2;
- s.d = *GetPoisoned<int>();
- s.e = 3;
- s.f = *GetPoisoned<int>();
- StructByValTestFunc(s);
- StructByValTestFunc1(s);
- StructByValTestFunc2(0, s);
-}
-
-
-#if MSAN_HAS_M128
-NOINLINE __m128i m128Eq(__m128i *a, __m128i *b) { return _mm_cmpeq_epi16(*a, *b); }
-NOINLINE __m128i m128Lt(__m128i *a, __m128i *b) { return _mm_cmplt_epi16(*a, *b); }
-TEST(MemorySanitizer, m128) {
- __m128i a = _mm_set1_epi16(0x1234);
- __m128i b = _mm_set1_epi16(0x7890);
- EXPECT_NOT_POISONED(m128Eq(&a, &b));
- EXPECT_NOT_POISONED(m128Lt(&a, &b));
-}
-// FIXME: add more tests for __m128i.
-#endif // MSAN_HAS_M128
-
-// We should not complain when copying this poisoned hole.
-struct StructWithHole {
- U4 a;
- // 4-byte hole.
- U8 b;
-};
-
-NOINLINE StructWithHole ReturnStructWithHole() {
- StructWithHole res;
- __msan_poison(&res, sizeof(res));
- res.a = 1;
- res.b = 2;
- return res;
-}
-
-TEST(MemorySanitizer, StructWithHole) {
- StructWithHole a = ReturnStructWithHole();
- break_optimization(&a);
-}
-
-template <class T>
-NOINLINE T ReturnStruct() {
- T res;
- __msan_poison(&res, sizeof(res));
- res.a = 1;
- return res;
-}
-
-template <class T>
-NOINLINE void TestReturnStruct() {
- T s1 = ReturnStruct<T>();
- EXPECT_NOT_POISONED(s1.a);
- EXPECT_POISONED(s1.b);
-}
-
-struct SSS1 {
- int a, b, c;
-};
-struct SSS2 {
- int b, a, c;
-};
-struct SSS3 {
- int b, c, a;
-};
-struct SSS4 {
- int c, b, a;
-};
-
-struct SSS5 {
- int a;
- float b;
-};
-struct SSS6 {
- int a;
- double b;
-};
-struct SSS7 {
- S8 b;
- int a;
-};
-struct SSS8 {
- S2 b;
- S8 a;
-};
-
-TEST(MemorySanitizer, IntStruct3) {
- TestReturnStruct<SSS1>();
- TestReturnStruct<SSS2>();
- TestReturnStruct<SSS3>();
- TestReturnStruct<SSS4>();
- TestReturnStruct<SSS5>();
- TestReturnStruct<SSS6>();
- TestReturnStruct<SSS7>();
- TestReturnStruct<SSS8>();
-}
-
-struct LongStruct {
- U1 a1, b1;
- U2 a2, b2;
- U4 a4, b4;
- U8 a8, b8;
-};
-
-NOINLINE LongStruct ReturnLongStruct1() {
- LongStruct res;
- __msan_poison(&res, sizeof(res));
- res.a1 = res.a2 = res.a4 = res.a8 = 111;
- // leaves b1, .., b8 poisoned.
- return res;
-}
-
-NOINLINE LongStruct ReturnLongStruct2() {
- LongStruct res;
- __msan_poison(&res, sizeof(res));
- res.b1 = res.b2 = res.b4 = res.b8 = 111;
- // leaves a1, .., a8 poisoned.
- return res;
-}
-
-TEST(MemorySanitizer, LongStruct) {
- LongStruct s1 = ReturnLongStruct1();
- __msan_print_shadow(&s1, sizeof(s1));
- EXPECT_NOT_POISONED(s1.a1);
- EXPECT_NOT_POISONED(s1.a2);
- EXPECT_NOT_POISONED(s1.a4);
- EXPECT_NOT_POISONED(s1.a8);
-
- EXPECT_POISONED(s1.b1);
- EXPECT_POISONED(s1.b2);
- EXPECT_POISONED(s1.b4);
- EXPECT_POISONED(s1.b8);
-
- LongStruct s2 = ReturnLongStruct2();
- __msan_print_shadow(&s2, sizeof(s2));
- EXPECT_NOT_POISONED(s2.b1);
- EXPECT_NOT_POISONED(s2.b2);
- EXPECT_NOT_POISONED(s2.b4);
- EXPECT_NOT_POISONED(s2.b8);
-
- EXPECT_POISONED(s2.a1);
- EXPECT_POISONED(s2.a2);
- EXPECT_POISONED(s2.a4);
- EXPECT_POISONED(s2.a8);
-}
-
-TEST(MemorySanitizer, getrlimit) {
- struct rlimit limit;
- __msan_poison(&limit, sizeof(limit));
- int result = getrlimit(RLIMIT_DATA, &limit);
- ASSERT_EQ(result, 0);
- EXPECT_NOT_POISONED(limit.rlim_cur);
- EXPECT_NOT_POISONED(limit.rlim_max);
-}
-
-TEST(MemorySanitizer, getrusage) {
- struct rusage usage;
- __msan_poison(&usage, sizeof(usage));
- int result = getrusage(RUSAGE_SELF, &usage);
- ASSERT_EQ(result, 0);
- EXPECT_NOT_POISONED(usage.ru_utime.tv_sec);
- EXPECT_NOT_POISONED(usage.ru_utime.tv_usec);
- EXPECT_NOT_POISONED(usage.ru_stime.tv_sec);
- EXPECT_NOT_POISONED(usage.ru_stime.tv_usec);
- EXPECT_NOT_POISONED(usage.ru_maxrss);
- EXPECT_NOT_POISONED(usage.ru_minflt);
- EXPECT_NOT_POISONED(usage.ru_majflt);
- EXPECT_NOT_POISONED(usage.ru_inblock);
- EXPECT_NOT_POISONED(usage.ru_oublock);
- EXPECT_NOT_POISONED(usage.ru_nvcsw);
- EXPECT_NOT_POISONED(usage.ru_nivcsw);
-}
-
-#if defined(__FreeBSD__)
-static void GetProgramPath(char *buf, size_t sz) {
- int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
- int res = sysctl(mib, 4, buf, &sz, NULL, 0);
- ASSERT_EQ(0, res);
-}
-#elif defined(__GLIBC__)
-static void GetProgramPath(char *buf, size_t sz) {
- extern char *program_invocation_name;
- int res = snprintf(buf, sz, "%s", program_invocation_name);
- ASSERT_GE(res, 0);
- ASSERT_LT((size_t)res, sz);
-}
-#else
-# error "TODO: port this"
-#endif
-
-static void dladdr_testfn() {}
-
-TEST(MemorySanitizer, dladdr) {
- Dl_info info;
- __msan_poison(&info, sizeof(info));
- int result = dladdr((const void*)dladdr_testfn, &info);
- ASSERT_NE(result, 0);
- EXPECT_NOT_POISONED((unsigned long)info.dli_fname);
- if (info.dli_fname)
- EXPECT_NOT_POISONED(strlen(info.dli_fname));
- EXPECT_NOT_POISONED((unsigned long)info.dli_fbase);
- EXPECT_NOT_POISONED((unsigned long)info.dli_sname);
- if (info.dli_sname)
- EXPECT_NOT_POISONED(strlen(info.dli_sname));
- EXPECT_NOT_POISONED((unsigned long)info.dli_saddr);
-}
-
-#ifndef MSAN_TEST_DISABLE_DLOPEN
-
-static int dl_phdr_callback(struct dl_phdr_info *info, size_t size, void *data) {
- (*(int *)data)++;
- EXPECT_NOT_POISONED(info->dlpi_addr);
- EXPECT_NOT_POISONED(strlen(info->dlpi_name));
- EXPECT_NOT_POISONED(info->dlpi_phnum);
- for (int i = 0; i < info->dlpi_phnum; ++i)
- EXPECT_NOT_POISONED(info->dlpi_phdr[i]);
- return 0;
-}
-
-// Compute the path to our loadable DSO. We assume it's in the same
-// directory. Only use string routines that we intercept so far to do this.
-static void GetPathToLoadable(char *buf, size_t sz) {
- char program_path[kMaxPathLength];
- GetProgramPath(program_path, sizeof(program_path));
-
- const char *last_slash = strrchr(program_path, '/');
- ASSERT_NE(nullptr, last_slash);
- size_t dir_len = (size_t)(last_slash - program_path);
-#if defined(__x86_64__)
- static const char basename[] = "libmsan_loadable.x86_64.so";
-#elif defined(__MIPSEB__) || defined(MIPSEB)
- static const char basename[] = "libmsan_loadable.mips64.so";
-#elif defined(__mips64)
- static const char basename[] = "libmsan_loadable.mips64el.so";
-#endif
- int res = snprintf(buf, sz, "%.*s/%s",
- (int)dir_len, program_path, basename);
- ASSERT_GE(res, 0);
- ASSERT_LT((size_t)res, sz);
-}
-
-TEST(MemorySanitizer, dl_iterate_phdr) {
- char path[kMaxPathLength];
- GetPathToLoadable(path, sizeof(path));
-
- // Having at least one dlopen'ed library in the process makes this more
- // entertaining.
- void *lib = dlopen(path, RTLD_LAZY);
- ASSERT_NE((void*)0, lib);
-
- int count = 0;
- int result = dl_iterate_phdr(dl_phdr_callback, &count);
- ASSERT_GT(count, 0);
-
- dlclose(lib);
-}
-
-TEST(MemorySanitizer, dlopen) {
- char path[kMaxPathLength];
- GetPathToLoadable(path, sizeof(path));
-
- // We need to clear shadow for globals when doing dlopen. In order to test
- // this, we have to poison the shadow for the DSO before we load it. In
- // general this is difficult, but the loader tends to reload things in the
- // same place, so we open, close, and then reopen. The global should always
- // start out clean after dlopen.
- for (int i = 0; i < 2; i++) {
- void *lib = dlopen(path, RTLD_LAZY);
- if (lib == NULL) {
- printf("dlerror: %s\n", dlerror());
- ASSERT_TRUE(lib != NULL);
- }
- void **(*get_dso_global)() = (void **(*)())dlsym(lib, "get_dso_global");
- ASSERT_TRUE(get_dso_global != NULL);
- void **dso_global = get_dso_global();
- EXPECT_NOT_POISONED(*dso_global);
- __msan_poison(dso_global, sizeof(*dso_global));
- EXPECT_POISONED(*dso_global);
- dlclose(lib);
- }
-}
-
-// Regression test for a crash in dlopen() interceptor.
-TEST(MemorySanitizer, dlopenFailed) {
- const char *path = "/libmsan_loadable_does_not_exist.so";
- void *lib = dlopen(path, RTLD_LAZY);
- ASSERT_TRUE(lib == NULL);
-}
-
-#endif // MSAN_TEST_DISABLE_DLOPEN
-
-// There's no sched_getaffinity() on FreeBSD.
-#if !defined(__FreeBSD__)
-TEST(MemorySanitizer, sched_getaffinity) {
- cpu_set_t mask;
- int res = sched_getaffinity(getpid(), sizeof(mask), &mask);
- ASSERT_EQ(0, res);
- EXPECT_NOT_POISONED(mask);
-}
-#endif
-
-TEST(MemorySanitizer, scanf) {
- const char *input = "42 hello";
- int* d = new int;
- char* s = new char[7];
- int res = sscanf(input, "%d %5s", d, s);
- printf("res %d\n", res);
- ASSERT_EQ(res, 2);
- EXPECT_NOT_POISONED(*d);
- EXPECT_NOT_POISONED(s[0]);
- EXPECT_NOT_POISONED(s[1]);
- EXPECT_NOT_POISONED(s[2]);
- EXPECT_NOT_POISONED(s[3]);
- EXPECT_NOT_POISONED(s[4]);
- EXPECT_NOT_POISONED(s[5]);
- EXPECT_POISONED(s[6]);
- delete[] s;
- delete d;
-}
-
-static void *SimpleThread_threadfn(void* data) {
- return new int;
-}
-
-TEST(MemorySanitizer, SimpleThread) {
- pthread_t t;
- void *p;
- int res = pthread_create(&t, NULL, SimpleThread_threadfn, NULL);
- ASSERT_EQ(0, res);
- EXPECT_NOT_POISONED(t);
- res = pthread_join(t, &p);
- ASSERT_EQ(0, res);
- EXPECT_NOT_POISONED(p);
- delete (int*)p;
-}
-
-static void *SmallStackThread_threadfn(void* data) {
- return 0;
-}
-
-TEST(MemorySanitizer, SmallStackThread) {
- pthread_attr_t attr;
- pthread_t t;
- void *p;
- int res;
- res = pthread_attr_init(&attr);
- ASSERT_EQ(0, res);
- res = pthread_attr_setstacksize(&attr, 64 * 1024);
- ASSERT_EQ(0, res);
- res = pthread_create(&t, &attr, SmallStackThread_threadfn, NULL);
- ASSERT_EQ(0, res);
- res = pthread_join(t, &p);
- ASSERT_EQ(0, res);
- res = pthread_attr_destroy(&attr);
- ASSERT_EQ(0, res);
-}
-
-TEST(MemorySanitizer, SmallPreAllocatedStackThread) {
- pthread_attr_t attr;
- pthread_t t;
- int res;
- res = pthread_attr_init(&attr);
- ASSERT_EQ(0, res);
- void *stack;
- const size_t kStackSize = 16 * 1024;
- res = posix_memalign(&stack, 4096, kStackSize);
- ASSERT_EQ(0, res);
- res = pthread_attr_setstack(&attr, stack, kStackSize);
- ASSERT_EQ(0, res);
- res = pthread_create(&t, &attr, SmallStackThread_threadfn, NULL);
- EXPECT_EQ(0, res);
- res = pthread_join(t, NULL);
- ASSERT_EQ(0, res);
- res = pthread_attr_destroy(&attr);
- ASSERT_EQ(0, res);
-}
-
-TEST(MemorySanitizer, pthread_attr_get) {
- pthread_attr_t attr;
- int res;
- res = pthread_attr_init(&attr);
- ASSERT_EQ(0, res);
- {
- int v;
- res = pthread_attr_getdetachstate(&attr, &v);
- ASSERT_EQ(0, res);
- EXPECT_NOT_POISONED(v);
- }
- {
- size_t v;
- res = pthread_attr_getguardsize(&attr, &v);
- ASSERT_EQ(0, res);
- EXPECT_NOT_POISONED(v);
- }
- {
- struct sched_param v;
- res = pthread_attr_getschedparam(&attr, &v);
- ASSERT_EQ(0, res);
- EXPECT_NOT_POISONED(v);
- }
- {
- int v;
- res = pthread_attr_getschedpolicy(&attr, &v);
- ASSERT_EQ(0, res);
- EXPECT_NOT_POISONED(v);
- }
- {
- int v;
- res = pthread_attr_getinheritsched(&attr, &v);
- ASSERT_EQ(0, res);
- EXPECT_NOT_POISONED(v);
- }
- {
- int v;
- res = pthread_attr_getscope(&attr, &v);
- ASSERT_EQ(0, res);
- EXPECT_NOT_POISONED(v);
- }
- {
- size_t v;
- res = pthread_attr_getstacksize(&attr, &v);
- ASSERT_EQ(0, res);
- EXPECT_NOT_POISONED(v);
- }
- {
- void *v;
- size_t w;
- res = pthread_attr_getstack(&attr, &v, &w);
- ASSERT_EQ(0, res);
- EXPECT_NOT_POISONED(v);
- EXPECT_NOT_POISONED(w);
- }
- {
- cpu_set_t v;
- res = pthread_attr_getaffinity_np(&attr, sizeof(v), &v);
- ASSERT_EQ(0, res);
- EXPECT_NOT_POISONED(v);
- }
- res = pthread_attr_destroy(&attr);
- ASSERT_EQ(0, res);
-}
-
-TEST(MemorySanitizer, pthread_getschedparam) {
- int policy;
- struct sched_param param;
- int res = pthread_getschedparam(pthread_self(), &policy, &param);
- ASSERT_EQ(0, res);
- EXPECT_NOT_POISONED(policy);
- EXPECT_NOT_POISONED(param.sched_priority);
-}
-
-TEST(MemorySanitizer, pthread_key_create) {
- pthread_key_t key;
- int res = pthread_key_create(&key, NULL);
- ASSERT_EQ(0, res);
- EXPECT_NOT_POISONED(key);
- res = pthread_key_delete(key);
- ASSERT_EQ(0, res);
-}
-
-namespace {
-struct SignalCondArg {
- pthread_cond_t* cond;
- pthread_mutex_t* mu;
- bool broadcast;
-};
-
-void *SignalCond(void *param) {
- SignalCondArg *arg = reinterpret_cast<SignalCondArg *>(param);
- pthread_mutex_lock(arg->mu);
- if (arg->broadcast)
- pthread_cond_broadcast(arg->cond);
- else
- pthread_cond_signal(arg->cond);
- pthread_mutex_unlock(arg->mu);
- return 0;
-}
-} // namespace
-
-TEST(MemorySanitizer, pthread_cond_wait) {
- pthread_cond_t cond;
- pthread_mutex_t mu;
- SignalCondArg args = {&cond, &mu, false};
- pthread_cond_init(&cond, 0);
- pthread_mutex_init(&mu, 0);
- pthread_mutex_lock(&mu);
-
- // signal
- pthread_t thr;
- pthread_create(&thr, 0, SignalCond, &args);
- int res = pthread_cond_wait(&cond, &mu);
- ASSERT_EQ(0, res);
- pthread_join(thr, 0);
-
- // broadcast
- args.broadcast = true;
- pthread_create(&thr, 0, SignalCond, &args);
- res = pthread_cond_wait(&cond, &mu);
- ASSERT_EQ(0, res);
- pthread_join(thr, 0);
-
- pthread_mutex_unlock(&mu);
- pthread_mutex_destroy(&mu);
- pthread_cond_destroy(&cond);
-}
-
-TEST(MemorySanitizer, tmpnam) {
- char s[L_tmpnam];
- char *res = tmpnam(s);
- ASSERT_EQ(s, res);
- EXPECT_NOT_POISONED(strlen(res));
-}
-
-TEST(MemorySanitizer, tempnam) {
- char *res = tempnam(NULL, "zzz");
- EXPECT_NOT_POISONED(strlen(res));
- free(res);
-}
-
-TEST(MemorySanitizer, posix_memalign) {
- void *p;
- EXPECT_POISONED(p);
- int res = posix_memalign(&p, 4096, 13);
- ASSERT_EQ(0, res);
- EXPECT_NOT_POISONED(p);
- EXPECT_EQ(0U, (uintptr_t)p % 4096);
- free(p);
-}
-
-// There's no memalign() on FreeBSD.
-#if !defined(__FreeBSD__)
-TEST(MemorySanitizer, memalign) {
- void *p = memalign(4096, 13);
- EXPECT_EQ(0U, (uintptr_t)p % kPageSize);
- free(p);
-}
-#endif
-
-TEST(MemorySanitizer, valloc) {
- void *a = valloc(100);
- EXPECT_EQ(0U, (uintptr_t)a % kPageSize);
- free(a);
-}
-
-// There's no pvalloc() on FreeBSD.
-#if !defined(__FreeBSD__)
-TEST(MemorySanitizer, pvalloc) {
- void *p = pvalloc(kPageSize + 100);
- EXPECT_EQ(0U, (uintptr_t)p % kPageSize);
- EXPECT_EQ(2 * kPageSize, __sanitizer_get_allocated_size(p));
- free(p);
-
- p = pvalloc(0); // pvalloc(0) should allocate at least one page.
- EXPECT_EQ(0U, (uintptr_t)p % kPageSize);
- EXPECT_EQ(kPageSize, __sanitizer_get_allocated_size(p));
- free(p);
-}
-#endif
-
-TEST(MemorySanitizer, inet_pton) {
- const char *s = "1:0:0:0:0:0:0:8";
- unsigned char buf[sizeof(struct in6_addr)];
- int res = inet_pton(AF_INET6, s, buf);
- ASSERT_EQ(1, res);
- EXPECT_NOT_POISONED(buf[0]);
- EXPECT_NOT_POISONED(buf[sizeof(struct in6_addr) - 1]);
-
- char s_out[INET6_ADDRSTRLEN];
- EXPECT_POISONED(s_out[3]);
- const char *q = inet_ntop(AF_INET6, buf, s_out, INET6_ADDRSTRLEN);
- ASSERT_NE((void*)0, q);
- EXPECT_NOT_POISONED(s_out[3]);
-}
-
-TEST(MemorySanitizer, inet_aton) {
- const char *s = "127.0.0.1";
- struct in_addr in[2];
- int res = inet_aton(s, in);
- ASSERT_NE(0, res);
- EXPECT_NOT_POISONED(in[0]);
- EXPECT_POISONED(*(char *)(in + 1));
-}
-
-TEST(MemorySanitizer, uname) {
- struct utsname u;
- int res = uname(&u);
- ASSERT_EQ(0, res);
- EXPECT_NOT_POISONED(strlen(u.sysname));
- EXPECT_NOT_POISONED(strlen(u.nodename));
- EXPECT_NOT_POISONED(strlen(u.release));
- EXPECT_NOT_POISONED(strlen(u.version));
- EXPECT_NOT_POISONED(strlen(u.machine));
-}
-
-TEST(MemorySanitizer, gethostname) {
- char buf[100];
- int res = gethostname(buf, 100);
- ASSERT_EQ(0, res);
- EXPECT_NOT_POISONED(strlen(buf));
-}
-
-// There's no sysinfo() on FreeBSD.
-#if !defined(__FreeBSD__)
-TEST(MemorySanitizer, sysinfo) {
- struct sysinfo info;
- int res = sysinfo(&info);
- ASSERT_EQ(0, res);
- EXPECT_NOT_POISONED(info);
-}
-#endif
-
-TEST(MemorySanitizer, getpwuid) {
- struct passwd *p = getpwuid(0); // root
- ASSERT_TRUE(p != NULL);
- EXPECT_NOT_POISONED(p->pw_name);
- ASSERT_TRUE(p->pw_name != NULL);
- EXPECT_NOT_POISONED(p->pw_name[0]);
- EXPECT_NOT_POISONED(p->pw_uid);
- ASSERT_EQ(0U, p->pw_uid);
-}
-
-TEST(MemorySanitizer, getpwuid_r) {
- struct passwd pwd;
- struct passwd *pwdres;
- char buf[10000];
- int res = getpwuid_r(0, &pwd, buf, sizeof(buf), &pwdres);
- ASSERT_EQ(0, res);
- EXPECT_NOT_POISONED(pwd.pw_name);
- ASSERT_TRUE(pwd.pw_name != NULL);
- EXPECT_NOT_POISONED(pwd.pw_name[0]);
- EXPECT_NOT_POISONED(pwd.pw_uid);
- ASSERT_EQ(0U, pwd.pw_uid);
- EXPECT_NOT_POISONED(pwdres);
-}
-
-TEST(MemorySanitizer, getpwnam_r) {
- struct passwd pwd;
- struct passwd *pwdres;
- char buf[10000];
- int res = getpwnam_r("root", &pwd, buf, sizeof(buf), &pwdres);
- ASSERT_EQ(0, res);
- EXPECT_NOT_POISONED(pwd.pw_name);
- ASSERT_TRUE(pwd.pw_name != NULL);
- EXPECT_NOT_POISONED(pwd.pw_name[0]);
- EXPECT_NOT_POISONED(pwd.pw_uid);
- ASSERT_EQ(0U, pwd.pw_uid);
- EXPECT_NOT_POISONED(pwdres);
-}
-
-TEST(MemorySanitizer, getpwnam_r_positive) {
- struct passwd pwd;
- struct passwd *pwdres;
- char s[5];
- strncpy(s, "abcd", 5);
- __msan_poison(s, 5);
- char buf[10000];
- int res;
- EXPECT_UMR(res = getpwnam_r(s, &pwd, buf, sizeof(buf), &pwdres));
-}
-
-TEST(MemorySanitizer, getgrnam_r) {
- struct group grp;
- struct group *grpres;
- char buf[10000];
- int res = getgrnam_r(SUPERUSER_GROUP, &grp, buf, sizeof(buf), &grpres);
- ASSERT_EQ(0, res);
- // Note that getgrnam_r() returns 0 if the matching group is not found.
- ASSERT_NE(nullptr, grpres);
- EXPECT_NOT_POISONED(grp.gr_name);
- ASSERT_TRUE(grp.gr_name != NULL);
- EXPECT_NOT_POISONED(grp.gr_name[0]);
- EXPECT_NOT_POISONED(grp.gr_gid);
- EXPECT_NOT_POISONED(grpres);
-}
-
-TEST(MemorySanitizer, getpwent) {
- setpwent();
- struct passwd *p = getpwent();
- ASSERT_TRUE(p != NULL);
- EXPECT_NOT_POISONED(p->pw_name);
- ASSERT_TRUE(p->pw_name != NULL);
- EXPECT_NOT_POISONED(p->pw_name[0]);
- EXPECT_NOT_POISONED(p->pw_uid);
-}
-
-TEST(MemorySanitizer, getpwent_r) {
- struct passwd pwd;
- struct passwd *pwdres;
- char buf[10000];
- setpwent();
- int res = getpwent_r(&pwd, buf, sizeof(buf), &pwdres);
- ASSERT_EQ(0, res);
- EXPECT_NOT_POISONED(pwd.pw_name);
- ASSERT_TRUE(pwd.pw_name != NULL);
- EXPECT_NOT_POISONED(pwd.pw_name[0]);
- EXPECT_NOT_POISONED(pwd.pw_uid);
- EXPECT_NOT_POISONED(pwdres);
-}
-
-// There's no fgetpwent() on FreeBSD.
-#if !defined(__FreeBSD__)
-TEST(MemorySanitizer, fgetpwent) {
- FILE *fp = fopen("/etc/passwd", "r");
- struct passwd *p = fgetpwent(fp);
- ASSERT_TRUE(p != NULL);
- EXPECT_NOT_POISONED(p->pw_name);
- ASSERT_TRUE(p->pw_name != NULL);
- EXPECT_NOT_POISONED(p->pw_name[0]);
- EXPECT_NOT_POISONED(p->pw_uid);
- fclose(fp);
-}
-#endif
-
-TEST(MemorySanitizer, getgrent) {
- setgrent();
- struct group *p = getgrent();
- ASSERT_TRUE(p != NULL);
- EXPECT_NOT_POISONED(p->gr_name);
- ASSERT_TRUE(p->gr_name != NULL);
- EXPECT_NOT_POISONED(p->gr_name[0]);
- EXPECT_NOT_POISONED(p->gr_gid);
-}
-
-// There's no fgetgrent() on FreeBSD.
-#if !defined(__FreeBSD__)
-TEST(MemorySanitizer, fgetgrent) {
- FILE *fp = fopen("/etc/group", "r");
- struct group *grp = fgetgrent(fp);
- ASSERT_TRUE(grp != NULL);
- EXPECT_NOT_POISONED(grp->gr_name);
- ASSERT_TRUE(grp->gr_name != NULL);
- EXPECT_NOT_POISONED(grp->gr_name[0]);
- EXPECT_NOT_POISONED(grp->gr_gid);
- for (char **p = grp->gr_mem; *p; ++p) {
- EXPECT_NOT_POISONED((*p)[0]);
- EXPECT_TRUE(strlen(*p) > 0);
- }
- fclose(fp);
-}
-#endif
-
-TEST(MemorySanitizer, getgrent_r) {
- struct group grp;
- struct group *grpres;
- char buf[10000];
- setgrent();
- int res = getgrent_r(&grp, buf, sizeof(buf), &grpres);
- ASSERT_EQ(0, res);
- EXPECT_NOT_POISONED(grp.gr_name);
- ASSERT_TRUE(grp.gr_name != NULL);
- EXPECT_NOT_POISONED(grp.gr_name[0]);
- EXPECT_NOT_POISONED(grp.gr_gid);
- EXPECT_NOT_POISONED(grpres);
-}
-
-// There's no fgetgrent_r() on FreeBSD.
-#if !defined(__FreeBSD__)
-TEST(MemorySanitizer, fgetgrent_r) {
- FILE *fp = fopen("/etc/group", "r");
- struct group grp;
- struct group *grpres;
- char buf[10000];
- setgrent();
- int res = fgetgrent_r(fp, &grp, buf, sizeof(buf), &grpres);
- ASSERT_EQ(0, res);
- EXPECT_NOT_POISONED(grp.gr_name);
- ASSERT_TRUE(grp.gr_name != NULL);
- EXPECT_NOT_POISONED(grp.gr_name[0]);
- EXPECT_NOT_POISONED(grp.gr_gid);
- EXPECT_NOT_POISONED(grpres);
- fclose(fp);
-}
-#endif
-
-TEST(MemorySanitizer, getgroups) {
- int n = getgroups(0, 0);
- gid_t *gids = new gid_t[n];
- int res = getgroups(n, gids);
- ASSERT_EQ(n, res);
- for (int i = 0; i < n; ++i)
- EXPECT_NOT_POISONED(gids[i]);
-}
-
-TEST(MemorySanitizer, wordexp) {
- wordexp_t w;
- int res = wordexp("a b c", &w, 0);
- ASSERT_EQ(0, res);
- ASSERT_EQ(3U, w.we_wordc);
- ASSERT_STREQ("a", w.we_wordv[0]);
- ASSERT_STREQ("b", w.we_wordv[1]);
- ASSERT_STREQ("c", w.we_wordv[2]);
-}
-
-template<class T>
-static bool applySlt(T value, T shadow) {
- __msan_partial_poison(&value, &shadow, sizeof(T));
- volatile bool zzz = true;
- // This "|| zzz" trick somehow makes LLVM emit "icmp slt" instead of
- // a shift-and-trunc to get at the highest bit.
- volatile bool v = value < 0 || zzz;
- return v;
-}
-
-TEST(MemorySanitizer, SignedCompareWithZero) {
- EXPECT_NOT_POISONED(applySlt<S4>(0xF, 0xF));
- EXPECT_NOT_POISONED(applySlt<S4>(0xF, 0xFF));
- EXPECT_NOT_POISONED(applySlt<S4>(0xF, 0xFFFFFF));
- EXPECT_NOT_POISONED(applySlt<S4>(0xF, 0x7FFFFFF));
- EXPECT_UMR(applySlt<S4>(0xF, 0x80FFFFFF));
- EXPECT_UMR(applySlt<S4>(0xF, 0xFFFFFFFF));
-}
-
-template <class T, class S>
-static T poisoned(T Va, S Sa) {
- char SIZE_CHECK1[(ssize_t)sizeof(T) - (ssize_t)sizeof(S)];
- char SIZE_CHECK2[(ssize_t)sizeof(S) - (ssize_t)sizeof(T)];
- T a;
- a = Va;
- __msan_partial_poison(&a, &Sa, sizeof(T));
- return a;
-}
-
-TEST(MemorySanitizer, ICmpRelational) {
- EXPECT_NOT_POISONED(poisoned(0, 0) < poisoned(0, 0));
- EXPECT_NOT_POISONED(poisoned(0U, 0) < poisoned(0U, 0));
- EXPECT_NOT_POISONED(poisoned(0LL, 0LLU) < poisoned(0LL, 0LLU));
- EXPECT_NOT_POISONED(poisoned(0LLU, 0LLU) < poisoned(0LLU, 0LLU));
- EXPECT_POISONED(poisoned(0xFF, 0xFF) < poisoned(0xFF, 0xFF));
- EXPECT_POISONED(poisoned(0xFFFFFFFFU, 0xFFFFFFFFU) <
- poisoned(0xFFFFFFFFU, 0xFFFFFFFFU));
- EXPECT_POISONED(poisoned(-1, 0xFFFFFFFFU) <
- poisoned(-1, 0xFFFFFFFFU));
-
- EXPECT_NOT_POISONED(poisoned(0, 0) <= poisoned(0, 0));
- EXPECT_NOT_POISONED(poisoned(0U, 0) <= poisoned(0U, 0));
- EXPECT_NOT_POISONED(poisoned(0LL, 0LLU) <= poisoned(0LL, 0LLU));
- EXPECT_NOT_POISONED(poisoned(0LLU, 0LLU) <= poisoned(0LLU, 0LLU));
- EXPECT_POISONED(poisoned(0xFF, 0xFF) <= poisoned(0xFF, 0xFF));
- EXPECT_POISONED(poisoned(0xFFFFFFFFU, 0xFFFFFFFFU) <=
- poisoned(0xFFFFFFFFU, 0xFFFFFFFFU));
- EXPECT_POISONED(poisoned(-1, 0xFFFFFFFFU) <=
- poisoned(-1, 0xFFFFFFFFU));
-
- EXPECT_NOT_POISONED(poisoned(0, 0) > poisoned(0, 0));
- EXPECT_NOT_POISONED(poisoned(0U, 0) > poisoned(0U, 0));
- EXPECT_NOT_POISONED(poisoned(0LL, 0LLU) > poisoned(0LL, 0LLU));
- EXPECT_NOT_POISONED(poisoned(0LLU, 0LLU) > poisoned(0LLU, 0LLU));
- EXPECT_POISONED(poisoned(0xFF, 0xFF) > poisoned(0xFF, 0xFF));
- EXPECT_POISONED(poisoned(0xFFFFFFFFU, 0xFFFFFFFFU) >
- poisoned(0xFFFFFFFFU, 0xFFFFFFFFU));
- EXPECT_POISONED(poisoned(-1, 0xFFFFFFFFU) >
- poisoned(-1, 0xFFFFFFFFU));
-
- EXPECT_NOT_POISONED(poisoned(0, 0) >= poisoned(0, 0));
- EXPECT_NOT_POISONED(poisoned(0U, 0) >= poisoned(0U, 0));
- EXPECT_NOT_POISONED(poisoned(0LL, 0LLU) >= poisoned(0LL, 0LLU));
- EXPECT_NOT_POISONED(poisoned(0LLU, 0LLU) >= poisoned(0LLU, 0LLU));
- EXPECT_POISONED(poisoned(0xFF, 0xFF) >= poisoned(0xFF, 0xFF));
- EXPECT_POISONED(poisoned(0xFFFFFFFFU, 0xFFFFFFFFU) >=
- poisoned(0xFFFFFFFFU, 0xFFFFFFFFU));
- EXPECT_POISONED(poisoned(-1, 0xFFFFFFFFU) >=
- poisoned(-1, 0xFFFFFFFFU));
-
- EXPECT_POISONED(poisoned(6, 0xF) > poisoned(7, 0));
- EXPECT_POISONED(poisoned(0xF, 0xF) > poisoned(7, 0));
-
- EXPECT_NOT_POISONED(poisoned(-1, 0x80000000U) >= poisoned(-1, 0U));
-}
-
-#if MSAN_HAS_M128
-TEST(MemorySanitizer, ICmpVectorRelational) {
- EXPECT_NOT_POISONED(
- _mm_cmplt_epi16(poisoned(_mm_set1_epi16(0), _mm_set1_epi16(0)),
- poisoned(_mm_set1_epi16(0), _mm_set1_epi16(0))));
- EXPECT_NOT_POISONED(
- _mm_cmplt_epi16(poisoned(_mm_set1_epi32(0), _mm_set1_epi32(0)),
- poisoned(_mm_set1_epi32(0), _mm_set1_epi32(0))));
- EXPECT_POISONED(
- _mm_cmplt_epi16(poisoned(_mm_set1_epi16(0), _mm_set1_epi16(0xFFFF)),
- poisoned(_mm_set1_epi16(0), _mm_set1_epi16(0xFFFF))));
- EXPECT_POISONED(_mm_cmpgt_epi16(poisoned(_mm_set1_epi16(6), _mm_set1_epi16(0xF)),
- poisoned(_mm_set1_epi16(7), _mm_set1_epi16(0))));
-}
-#endif
-
-// Volatile bitfield store is implemented as load-mask-store
-// Test that we don't warn on the store of (uninitialized) padding.
-struct VolatileBitfieldStruct {
- volatile unsigned x : 1;
- unsigned y : 1;
-};
-
-TEST(MemorySanitizer, VolatileBitfield) {
- VolatileBitfieldStruct *S = new VolatileBitfieldStruct;
- S->x = 1;
- EXPECT_NOT_POISONED((unsigned)S->x);
- EXPECT_POISONED((unsigned)S->y);
-}
-
-TEST(MemorySanitizer, UnalignedLoad) {
- char x[32] __attribute__((aligned(8)));
- U4 origin = __LINE__;
- for (unsigned i = 0; i < sizeof(x) / 4; ++i)
- __msan_set_origin(x + 4 * i, 4, origin + i);
-
- memset(x + 8, 0, 16);
- EXPECT_POISONED_O(__sanitizer_unaligned_load16(x + 6), origin + 1);
- EXPECT_POISONED_O(__sanitizer_unaligned_load16(x + 7), origin + 1);
- EXPECT_NOT_POISONED(__sanitizer_unaligned_load16(x + 8));
- EXPECT_NOT_POISONED(__sanitizer_unaligned_load16(x + 9));
- EXPECT_NOT_POISONED(__sanitizer_unaligned_load16(x + 22));
- EXPECT_POISONED_O(__sanitizer_unaligned_load16(x + 23), origin + 6);
- EXPECT_POISONED_O(__sanitizer_unaligned_load16(x + 24), origin + 6);
-
- EXPECT_POISONED_O(__sanitizer_unaligned_load32(x + 4), origin + 1);
- EXPECT_POISONED_O(__sanitizer_unaligned_load32(x + 7), origin + 1);
- EXPECT_NOT_POISONED(__sanitizer_unaligned_load32(x + 8));
- EXPECT_NOT_POISONED(__sanitizer_unaligned_load32(x + 9));
- EXPECT_NOT_POISONED(__sanitizer_unaligned_load32(x + 20));
- EXPECT_POISONED_O(__sanitizer_unaligned_load32(x + 21), origin + 6);
- EXPECT_POISONED_O(__sanitizer_unaligned_load32(x + 24), origin + 6);
-
- EXPECT_POISONED_O(__sanitizer_unaligned_load64(x), origin);
- EXPECT_POISONED_O(__sanitizer_unaligned_load64(x + 1), origin);
- EXPECT_POISONED_O(__sanitizer_unaligned_load64(x + 7), origin + 1);
- EXPECT_NOT_POISONED(__sanitizer_unaligned_load64(x + 8));
- EXPECT_NOT_POISONED(__sanitizer_unaligned_load64(x + 9));
- EXPECT_NOT_POISONED(__sanitizer_unaligned_load64(x + 16));
- EXPECT_POISONED_O(__sanitizer_unaligned_load64(x + 17), origin + 6);
- EXPECT_POISONED_O(__sanitizer_unaligned_load64(x + 21), origin + 6);
- EXPECT_POISONED_O(__sanitizer_unaligned_load64(x + 24), origin + 6);
-}
-
-TEST(MemorySanitizer, UnalignedStore16) {
- char x[5] __attribute__((aligned(4)));
- U2 y2 = 0;
- U4 origin = __LINE__;
- __msan_poison(&y2, 1);
- __msan_set_origin(&y2, 1, origin);
-
- __sanitizer_unaligned_store16(x + 1, y2);
- EXPECT_POISONED_O(x[0], origin);
- EXPECT_POISONED_O(x[1], origin);
- EXPECT_NOT_POISONED(x[2]);
- EXPECT_POISONED_O(x[3], origin);
-}
-
-TEST(MemorySanitizer, UnalignedStore32) {
- char x[8] __attribute__((aligned(4)));
- U4 y4 = 0;
- U4 origin = __LINE__;
- __msan_poison(&y4, 2);
- __msan_set_origin(&y4, 2, origin);
-
- __sanitizer_unaligned_store32(x + 3, y4);
- EXPECT_POISONED_O(x[0], origin);
- EXPECT_POISONED_O(x[1], origin);
- EXPECT_POISONED_O(x[2], origin);
- EXPECT_POISONED_O(x[3], origin);
- EXPECT_POISONED_O(x[4], origin);
- EXPECT_NOT_POISONED(x[5]);
- EXPECT_NOT_POISONED(x[6]);
- EXPECT_POISONED_O(x[7], origin);
-}
-
-TEST(MemorySanitizer, UnalignedStore64) {
- char x[16] __attribute__((aligned(8)));
- U8 y8 = 0;
- U4 origin = __LINE__;
- __msan_poison(&y8, 3);
- __msan_poison(((char *)&y8) + sizeof(y8) - 2, 1);
- __msan_set_origin(&y8, 8, origin);
-
- __sanitizer_unaligned_store64(x + 3, y8);
- EXPECT_POISONED_O(x[0], origin);
- EXPECT_POISONED_O(x[1], origin);
- EXPECT_POISONED_O(x[2], origin);
- EXPECT_POISONED_O(x[3], origin);
- EXPECT_POISONED_O(x[4], origin);
- EXPECT_POISONED_O(x[5], origin);
- EXPECT_NOT_POISONED(x[6]);
- EXPECT_NOT_POISONED(x[7]);
- EXPECT_NOT_POISONED(x[8]);
- EXPECT_POISONED_O(x[9], origin);
- EXPECT_NOT_POISONED(x[10]);
- EXPECT_POISONED_O(x[11], origin);
-}
-
-TEST(MemorySanitizer, UnalignedStore16_precise) {
- char x[8] __attribute__((aligned(4)));
- U2 y = 0;
- U4 originx1 = __LINE__;
- U4 originx2 = __LINE__;
- U4 originy = __LINE__;
- __msan_poison(x, sizeof(x));
- __msan_set_origin(x, 4, originx1);
- __msan_set_origin(x + 4, 4, originx2);
- __msan_poison(((char *)&y) + 1, 1);
- __msan_set_origin(&y, sizeof(y), originy);
-
- __sanitizer_unaligned_store16(x + 3, y);
- EXPECT_POISONED_O(x[0], originx1);
- EXPECT_POISONED_O(x[1], originx1);
- EXPECT_POISONED_O(x[2], originx1);
- EXPECT_NOT_POISONED(x[3]);
- EXPECT_POISONED_O(x[4], originy);
- EXPECT_POISONED_O(x[5], originy);
- EXPECT_POISONED_O(x[6], originy);
- EXPECT_POISONED_O(x[7], originy);
-}
-
-TEST(MemorySanitizer, UnalignedStore16_precise2) {
- char x[8] __attribute__((aligned(4)));
- U2 y = 0;
- U4 originx1 = __LINE__;
- U4 originx2 = __LINE__;
- U4 originy = __LINE__;
- __msan_poison(x, sizeof(x));
- __msan_set_origin(x, 4, originx1);
- __msan_set_origin(x + 4, 4, originx2);
- __msan_poison(((char *)&y), 1);
- __msan_set_origin(&y, sizeof(y), originy);
-
- __sanitizer_unaligned_store16(x + 3, y);
- EXPECT_POISONED_O(x[0], originy);
- EXPECT_POISONED_O(x[1], originy);
- EXPECT_POISONED_O(x[2], originy);
- EXPECT_POISONED_O(x[3], originy);
- EXPECT_NOT_POISONED(x[4]);
- EXPECT_POISONED_O(x[5], originx2);
- EXPECT_POISONED_O(x[6], originx2);
- EXPECT_POISONED_O(x[7], originx2);
-}
-
-TEST(MemorySanitizer, UnalignedStore64_precise) {
- char x[12] __attribute__((aligned(8)));
- U8 y = 0;
- U4 originx1 = __LINE__;
- U4 originx2 = __LINE__;
- U4 originx3 = __LINE__;
- U4 originy = __LINE__;
- __msan_poison(x, sizeof(x));
- __msan_set_origin(x, 4, originx1);
- __msan_set_origin(x + 4, 4, originx2);
- __msan_set_origin(x + 8, 4, originx3);
- __msan_poison(((char *)&y) + 1, 1);
- __msan_poison(((char *)&y) + 7, 1);
- __msan_set_origin(&y, sizeof(y), originy);
-
- __sanitizer_unaligned_store64(x + 2, y);
- EXPECT_POISONED_O(x[0], originy);
- EXPECT_POISONED_O(x[1], originy);
- EXPECT_NOT_POISONED(x[2]);
- EXPECT_POISONED_O(x[3], originy);
-
- EXPECT_NOT_POISONED(x[4]);
- EXPECT_NOT_POISONED(x[5]);
- EXPECT_NOT_POISONED(x[6]);
- EXPECT_NOT_POISONED(x[7]);
-
- EXPECT_NOT_POISONED(x[8]);
- EXPECT_POISONED_O(x[9], originy);
- EXPECT_POISONED_O(x[10], originy);
- EXPECT_POISONED_O(x[11], originy);
-}
-
-TEST(MemorySanitizer, UnalignedStore64_precise2) {
- char x[12] __attribute__((aligned(8)));
- U8 y = 0;
- U4 originx1 = __LINE__;
- U4 originx2 = __LINE__;
- U4 originx3 = __LINE__;
- U4 originy = __LINE__;
- __msan_poison(x, sizeof(x));
- __msan_set_origin(x, 4, originx1);
- __msan_set_origin(x + 4, 4, originx2);
- __msan_set_origin(x + 8, 4, originx3);
- __msan_poison(((char *)&y) + 3, 3);
- __msan_set_origin(&y, sizeof(y), originy);
-
- __sanitizer_unaligned_store64(x + 2, y);
- EXPECT_POISONED_O(x[0], originx1);
- EXPECT_POISONED_O(x[1], originx1);
- EXPECT_NOT_POISONED(x[2]);
- EXPECT_NOT_POISONED(x[3]);
-
- EXPECT_NOT_POISONED(x[4]);
- EXPECT_POISONED_O(x[5], originy);
- EXPECT_POISONED_O(x[6], originy);
- EXPECT_POISONED_O(x[7], originy);
-
- EXPECT_NOT_POISONED(x[8]);
- EXPECT_NOT_POISONED(x[9]);
- EXPECT_POISONED_O(x[10], originx3);
- EXPECT_POISONED_O(x[11], originx3);
-}
-
-#if (defined(__x86_64__) && defined(__clang__))
-namespace {
-typedef U1 V16x8 __attribute__((__vector_size__(16)));
-typedef U2 V8x16 __attribute__((__vector_size__(16)));
-typedef U4 V4x32 __attribute__((__vector_size__(16)));
-typedef U8 V2x64 __attribute__((__vector_size__(16)));
-typedef U4 V8x32 __attribute__((__vector_size__(32)));
-typedef U8 V4x64 __attribute__((__vector_size__(32)));
-typedef U4 V2x32 __attribute__((__vector_size__(8)));
-typedef U2 V4x16 __attribute__((__vector_size__(8)));
-typedef U1 V8x8 __attribute__((__vector_size__(8)));
-
-
-V8x16 shift_sse2_left_scalar(V8x16 x, U4 y) {
- return _mm_slli_epi16(x, y);
-}
-
-V8x16 shift_sse2_left(V8x16 x, V8x16 y) {
- return _mm_sll_epi16(x, y);
-}
-
-TEST(VectorShiftTest, sse2_left_scalar) {
- V8x16 v = {Poisoned<U2>(0, 3), Poisoned<U2>(0, 7), 2, 3, 4, 5, 6, 7};
- V8x16 u = shift_sse2_left_scalar(v, 2);
- EXPECT_POISONED(u[0]);
- EXPECT_POISONED(u[1]);
- EXPECT_NOT_POISONED(u[0] | (3U << 2));
- EXPECT_NOT_POISONED(u[1] | (7U << 2));
- u[0] = u[1] = 0;
- EXPECT_NOT_POISONED(u);
-}
-
-TEST(VectorShiftTest, sse2_left_scalar_by_uninit) {
- V8x16 v = {0, 1, 2, 3, 4, 5, 6, 7};
- V8x16 u = shift_sse2_left_scalar(v, Poisoned<U4>());
- EXPECT_POISONED(u[0]);
- EXPECT_POISONED(u[1]);
- EXPECT_POISONED(u[2]);
- EXPECT_POISONED(u[3]);
- EXPECT_POISONED(u[4]);
- EXPECT_POISONED(u[5]);
- EXPECT_POISONED(u[6]);
- EXPECT_POISONED(u[7]);
-}
-
-TEST(VectorShiftTest, sse2_left) {
- V8x16 v = {Poisoned<U2>(0, 3), Poisoned<U2>(0, 7), 2, 3, 4, 5, 6, 7};
- // Top 64 bits of shift count don't affect the result.
- V2x64 s = {2, Poisoned<U8>()};
- V8x16 u = shift_sse2_left(v, s);
- EXPECT_POISONED(u[0]);
- EXPECT_POISONED(u[1]);
- EXPECT_NOT_POISONED(u[0] | (3U << 2));
- EXPECT_NOT_POISONED(u[1] | (7U << 2));
- u[0] = u[1] = 0;
- EXPECT_NOT_POISONED(u);
-}
-
-TEST(VectorShiftTest, sse2_left_by_uninit) {
- V8x16 v = {Poisoned<U2>(0, 3), Poisoned<U2>(0, 7), 2, 3, 4, 5, 6, 7};
- V2x64 s = {Poisoned<U8>(), Poisoned<U8>()};
- V8x16 u = shift_sse2_left(v, s);
- EXPECT_POISONED(u[0]);
- EXPECT_POISONED(u[1]);
- EXPECT_POISONED(u[2]);
- EXPECT_POISONED(u[3]);
- EXPECT_POISONED(u[4]);
- EXPECT_POISONED(u[5]);
- EXPECT_POISONED(u[6]);
- EXPECT_POISONED(u[7]);
-}
-
-#ifdef __AVX2__
-V4x32 shift_avx2_left(V4x32 x, V4x32 y) {
- return _mm_sllv_epi32(x, y);
-}
-// This is variable vector shift that's only available starting with AVX2.
-// V4x32 shift_avx2_left(V4x32 x, V4x32 y) {
-TEST(VectorShiftTest, avx2_left) {
- V4x32 v = {Poisoned<U2>(0, 3), Poisoned<U2>(0, 7), 2, 3};
- V4x32 s = {2, Poisoned<U4>(), 3, Poisoned<U4>()};
- V4x32 u = shift_avx2_left(v, s);
- EXPECT_POISONED(u[0]);
- EXPECT_NOT_POISONED(u[0] | (~7U));
- EXPECT_POISONED(u[1]);
- EXPECT_POISONED(u[1] | (~31U));
- EXPECT_NOT_POISONED(u[2]);
- EXPECT_POISONED(u[3]);
- EXPECT_POISONED(u[3] | (~31U));
-}
-#endif // __AVX2__
-} // namespace
-
-TEST(VectorPackTest, sse2_packssdw_128) {
- const unsigned S2_max = (1 << 15) - 1;
- V4x32 a = {Poisoned<U4>(0, 0xFF0000), Poisoned<U4>(0, 0xFFFF0000),
- S2_max + 100, 4};
- V4x32 b = {Poisoned<U4>(0, 0xFF), S2_max + 10000, Poisoned<U4>(0, 0xFF00),
- S2_max};
-
- V8x16 c = _mm_packs_epi32(a, b);
-
- EXPECT_POISONED(c[0]);
- EXPECT_POISONED(c[1]);
- EXPECT_NOT_POISONED(c[2]);
- EXPECT_NOT_POISONED(c[3]);
- EXPECT_POISONED(c[4]);
- EXPECT_NOT_POISONED(c[5]);
- EXPECT_POISONED(c[6]);
- EXPECT_NOT_POISONED(c[7]);
-
- EXPECT_EQ(c[2], S2_max);
- EXPECT_EQ(c[3], 4);
- EXPECT_EQ(c[5], S2_max);
- EXPECT_EQ(c[7], S2_max);
-}
-
-TEST(VectorPackTest, mmx_packuswb) {
- const unsigned U1_max = (1 << 8) - 1;
- V4x16 a = {Poisoned<U2>(0, 0xFF00), Poisoned<U2>(0, 0xF000U), U1_max + 100,
- 4};
- V4x16 b = {Poisoned<U2>(0, 0xFF), U1_max - 1, Poisoned<U2>(0, 0xF), U1_max};
- V8x8 c = _mm_packs_pu16(a, b);
-
- EXPECT_POISONED(c[0]);
- EXPECT_POISONED(c[1]);
- EXPECT_NOT_POISONED(c[2]);
- EXPECT_NOT_POISONED(c[3]);
- EXPECT_POISONED(c[4]);
- EXPECT_NOT_POISONED(c[5]);
- EXPECT_POISONED(c[6]);
- EXPECT_NOT_POISONED(c[7]);
-
- EXPECT_EQ(c[2], U1_max);
- EXPECT_EQ(c[3], 4);
- EXPECT_EQ(c[5], U1_max - 1);
- EXPECT_EQ(c[7], U1_max);
-}
-
-TEST(VectorSadTest, sse2_psad_bw) {
- V16x8 a = {Poisoned<U1>(), 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
- V16x8 b = {100, 101, 102, 103, 104, 105, 106, 107,
- 108, 109, 110, 111, 112, 113, 114, 115};
- V2x64 c = _mm_sad_epu8(a, b);
-
- EXPECT_POISONED(c[0]);
- EXPECT_NOT_POISONED(c[1]);
-
- EXPECT_EQ(800U, c[1]);
-}
-
-TEST(VectorMaddTest, mmx_pmadd_wd) {
- V4x16 a = {Poisoned<U2>(), 1, 2, 3};
- V4x16 b = {100, 101, 102, 103};
- V2x32 c = _mm_madd_pi16(a, b);
-
- EXPECT_POISONED(c[0]);
- EXPECT_NOT_POISONED(c[1]);
-
- EXPECT_EQ((unsigned)(2 * 102 + 3 * 103), c[1]);
-}
-#endif // defined(__clang__)
-
-TEST(MemorySanitizerOrigins, SetGet) {
- EXPECT_EQ(TrackingOrigins(), !!__msan_get_track_origins());
- if (!TrackingOrigins()) return;
- int x;
- __msan_set_origin(&x, sizeof(x), 1234);
- EXPECT_ORIGIN(1234U, __msan_get_origin(&x));
- __msan_set_origin(&x, sizeof(x), 5678);
- EXPECT_ORIGIN(5678U, __msan_get_origin(&x));
- __msan_set_origin(&x, sizeof(x), 0);
- EXPECT_ORIGIN(0U, __msan_get_origin(&x));
-}
-
-namespace {
-struct S {
- U4 dummy;
- U2 a;
- U2 b;
-};
-
-TEST(MemorySanitizerOrigins, InitializedStoreDoesNotChangeOrigin) {
- if (!TrackingOrigins()) return;
-
- S s;
- U4 origin = rand(); // NOLINT
- s.a = *GetPoisonedO<U2>(0, origin);
- EXPECT_ORIGIN(origin, __msan_get_origin(&s.a));
- EXPECT_ORIGIN(origin, __msan_get_origin(&s.b));
-
- s.b = 42;
- EXPECT_ORIGIN(origin, __msan_get_origin(&s.a));
- EXPECT_ORIGIN(origin, __msan_get_origin(&s.b));
-}
-} // namespace
-
-template<class T, class BinaryOp>
-INLINE
-void BinaryOpOriginTest(BinaryOp op) {
- U4 ox = rand(); //NOLINT
- U4 oy = rand(); //NOLINT
- T *x = GetPoisonedO<T>(0, ox, 0);
- T *y = GetPoisonedO<T>(1, oy, 0);
- T *z = GetPoisonedO<T>(2, 0, 0);
-
- *z = op(*x, *y);
- U4 origin = __msan_get_origin(z);
- EXPECT_POISONED_O(*z, origin);
- EXPECT_EQ(true, __msan_origin_is_descendant_or_same(origin, ox) ||
- __msan_origin_is_descendant_or_same(origin, oy));
-
- // y is poisoned, x is not.
- *x = 10101;
- *y = *GetPoisonedO<T>(1, oy);
- break_optimization(x);
- __msan_set_origin(z, sizeof(*z), 0);
- *z = op(*x, *y);
- EXPECT_POISONED_O(*z, oy);
- EXPECT_ORIGIN(oy, __msan_get_origin(z));
-
- // x is poisoned, y is not.
- *x = *GetPoisonedO<T>(0, ox);
- *y = 10101010;
- break_optimization(y);
- __msan_set_origin(z, sizeof(*z), 0);
- *z = op(*x, *y);
- EXPECT_POISONED_O(*z, ox);
- EXPECT_ORIGIN(ox, __msan_get_origin(z));
-}
-
-template<class T> INLINE T XOR(const T &a, const T&b) { return a ^ b; }
-template<class T> INLINE T ADD(const T &a, const T&b) { return a + b; }
-template<class T> INLINE T SUB(const T &a, const T&b) { return a - b; }
-template<class T> INLINE T MUL(const T &a, const T&b) { return a * b; }
-template<class T> INLINE T AND(const T &a, const T&b) { return a & b; }
-template<class T> INLINE T OR (const T &a, const T&b) { return a | b; }
-
-TEST(MemorySanitizerOrigins, BinaryOp) {
- if (!TrackingOrigins()) return;
- BinaryOpOriginTest<S8>(XOR<S8>);
- BinaryOpOriginTest<U8>(ADD<U8>);
- BinaryOpOriginTest<S4>(SUB<S4>);
- BinaryOpOriginTest<S4>(MUL<S4>);
- BinaryOpOriginTest<U4>(OR<U4>);
- BinaryOpOriginTest<U4>(AND<U4>);
- BinaryOpOriginTest<double>(ADD<U4>);
- BinaryOpOriginTest<float>(ADD<S4>);
- BinaryOpOriginTest<double>(ADD<double>);
- BinaryOpOriginTest<float>(ADD<double>);
-}
-
-TEST(MemorySanitizerOrigins, Unary) {
- if (!TrackingOrigins()) return;
- EXPECT_POISONED_O(*GetPoisonedO<S8>(0, __LINE__), __LINE__);
- EXPECT_POISONED_O(*GetPoisonedO<S8>(0, __LINE__), __LINE__);
- EXPECT_POISONED_O(*GetPoisonedO<S8>(0, __LINE__), __LINE__);
- EXPECT_POISONED_O(*GetPoisonedO<S8>(0, __LINE__), __LINE__);
-
- EXPECT_POISONED_O(*GetPoisonedO<S4>(0, __LINE__), __LINE__);
- EXPECT_POISONED_O(*GetPoisonedO<S4>(0, __LINE__), __LINE__);
- EXPECT_POISONED_O(*GetPoisonedO<S4>(0, __LINE__), __LINE__);
- EXPECT_POISONED_O(*GetPoisonedO<S4>(0, __LINE__), __LINE__);
-
- EXPECT_POISONED_O(*GetPoisonedO<U4>(0, __LINE__), __LINE__);
- EXPECT_POISONED_O(*GetPoisonedO<U4>(0, __LINE__), __LINE__);
- EXPECT_POISONED_O(*GetPoisonedO<U4>(0, __LINE__), __LINE__);
- EXPECT_POISONED_O(*GetPoisonedO<U4>(0, __LINE__), __LINE__);
-
- EXPECT_POISONED_O(*GetPoisonedO<S4>(0, __LINE__), __LINE__);
- EXPECT_POISONED_O(*GetPoisonedO<S4>(0, __LINE__), __LINE__);
- EXPECT_POISONED_O(*GetPoisonedO<S4>(0, __LINE__), __LINE__);
- EXPECT_POISONED_O(*GetPoisonedO<S4>(0, __LINE__), __LINE__);
-
- EXPECT_POISONED_O((void*)*GetPoisonedO<S8>(0, __LINE__), __LINE__);
- EXPECT_POISONED_O((U8)*GetPoisonedO<void*>(0, __LINE__), __LINE__);
-}
-
-TEST(MemorySanitizerOrigins, EQ) {
- if (!TrackingOrigins()) return;
- EXPECT_POISONED_O(*GetPoisonedO<S4>(0, __LINE__) <= 11, __LINE__);
- EXPECT_POISONED_O(*GetPoisonedO<S4>(0, __LINE__) == 11, __LINE__);
- EXPECT_POISONED_O(*GetPoisonedO<float>(0, __LINE__) == 1.1, __LINE__);
-}
-
-TEST(MemorySanitizerOrigins, DIV) {
- if (!TrackingOrigins()) return;
- EXPECT_POISONED_O(*GetPoisonedO<U8>(0, __LINE__) / 100, __LINE__);
- unsigned o = __LINE__;
- EXPECT_UMR_O(volatile unsigned y = 100 / *GetPoisonedO<S4>(0, o, 1), o);
-}
-
-TEST(MemorySanitizerOrigins, SHIFT) {
- if (!TrackingOrigins()) return;
- EXPECT_POISONED_O(*GetPoisonedO<U8>(0, __LINE__) >> 10, __LINE__);
- EXPECT_POISONED_O(*GetPoisonedO<S8>(0, __LINE__) >> 10, __LINE__);
- EXPECT_POISONED_O(*GetPoisonedO<S8>(0, __LINE__) << 10, __LINE__);
- EXPECT_POISONED_O(10U << *GetPoisonedO<U8>(0, __LINE__), __LINE__);
- EXPECT_POISONED_O(-10 >> *GetPoisonedO<S8>(0, __LINE__), __LINE__);
- EXPECT_POISONED_O(-10 << *GetPoisonedO<S8>(0, __LINE__), __LINE__);
-}
-
-template<class T, int N>
-void MemCpyTest() {
- int ox = __LINE__;
- T *x = new T[N];
- T *y = new T[N];
- T *z = new T[N];
- T *q = new T[N];
- __msan_poison(x, N * sizeof(T));
- __msan_set_origin(x, N * sizeof(T), ox);
- __msan_set_origin(y, N * sizeof(T), 777777);
- __msan_set_origin(z, N * sizeof(T), 888888);
- EXPECT_NOT_POISONED(x);
- memcpy(y, x, N * sizeof(T));
- EXPECT_POISONED_O(y[0], ox);
- EXPECT_POISONED_O(y[N/2], ox);
- EXPECT_POISONED_O(y[N-1], ox);
- EXPECT_NOT_POISONED(x);
- void *res = mempcpy(q, x, N * sizeof(T));
- ASSERT_EQ(q + N, res);
- EXPECT_POISONED_O(q[0], ox);
- EXPECT_POISONED_O(q[N/2], ox);
- EXPECT_POISONED_O(q[N-1], ox);
- EXPECT_NOT_POISONED(x);
- memmove(z, x, N * sizeof(T));
- EXPECT_POISONED_O(z[0], ox);
- EXPECT_POISONED_O(z[N/2], ox);
- EXPECT_POISONED_O(z[N-1], ox);
-}
-
-TEST(MemorySanitizerOrigins, LargeMemCpy) {
- if (!TrackingOrigins()) return;
- MemCpyTest<U1, 10000>();
- MemCpyTest<U8, 10000>();
-}
-
-TEST(MemorySanitizerOrigins, SmallMemCpy) {
- if (!TrackingOrigins()) return;
- MemCpyTest<U8, 1>();
- MemCpyTest<U8, 2>();
- MemCpyTest<U8, 3>();
-}
-
-TEST(MemorySanitizerOrigins, Select) {
- if (!TrackingOrigins()) return;
- EXPECT_NOT_POISONED(g_one ? 1 : *GetPoisonedO<S4>(0, __LINE__));
- EXPECT_POISONED_O(*GetPoisonedO<S4>(0, __LINE__), __LINE__);
- S4 x;
- break_optimization(&x);
- x = g_1 ? *GetPoisonedO<S4>(0, __LINE__) : 0;
-
- EXPECT_POISONED_O(g_1 ? *GetPoisonedO<S4>(0, __LINE__) : 1, __LINE__);
- EXPECT_POISONED_O(g_0 ? 1 : *GetPoisonedO<S4>(0, __LINE__), __LINE__);
-}
-
-NOINLINE int RetvalOriginTest(U4 origin) {
- int *a = new int;
- break_optimization(a);
- __msan_set_origin(a, sizeof(*a), origin);
- int res = *a;
- delete a;
- return res;
-}
-
-TEST(MemorySanitizerOrigins, Retval) {
- if (!TrackingOrigins()) return;
- EXPECT_POISONED_O(RetvalOriginTest(__LINE__), __LINE__);
-}
-
-NOINLINE void ParamOriginTest(int param, U4 origin) {
- EXPECT_POISONED_O(param, origin);
-}
-
-TEST(MemorySanitizerOrigins, Param) {
- if (!TrackingOrigins()) return;
- int *a = new int;
- U4 origin = __LINE__;
- break_optimization(a);
- __msan_set_origin(a, sizeof(*a), origin);
- ParamOriginTest(*a, origin);
- delete a;
-}
-
-TEST(MemorySanitizerOrigins, Invoke) {
- if (!TrackingOrigins()) return;
- StructWithDtor s; // Will cause the calls to become invokes.
- EXPECT_POISONED_O(RetvalOriginTest(__LINE__), __LINE__);
-}
-
-TEST(MemorySanitizerOrigins, strlen) {
- S8 alignment;
- break_optimization(&alignment);
- char x[4] = {'a', 'b', 0, 0};
- __msan_poison(&x[2], 1);
- U4 origin = __LINE__;
- __msan_set_origin(x, sizeof(x), origin);
- EXPECT_UMR_O(volatile unsigned y = strlen(x), origin);
-}
-
-TEST(MemorySanitizerOrigins, wcslen) {
- wchar_t w[3] = {'a', 'b', 0};
- U4 origin = __LINE__;
- __msan_set_origin(w, sizeof(w), origin);
- __msan_poison(&w[2], sizeof(wchar_t));
- EXPECT_UMR_O(volatile unsigned y = wcslen(w), origin);
-}
-
-#if MSAN_HAS_M128
-TEST(MemorySanitizerOrigins, StoreIntrinsic) {
- __m128 x, y;
- U4 origin = __LINE__;
- __msan_set_origin(&x, sizeof(x), origin);
- __msan_poison(&x, sizeof(x));
- __builtin_ia32_storeups((float*)&y, x);
- EXPECT_POISONED_O(y, origin);
-}
-#endif
-
-NOINLINE void RecursiveMalloc(int depth) {
- static int count;
- count++;
- if ((count % (1024 * 1024)) == 0)
- printf("RecursiveMalloc: %d\n", count);
- int *x1 = new int;
- int *x2 = new int;
- break_optimization(x1);
- break_optimization(x2);
- if (depth > 0) {
- RecursiveMalloc(depth-1);
- RecursiveMalloc(depth-1);
- }
- delete x1;
- delete x2;
-}
-
-TEST(MemorySanitizer, Select) {
- int x;
- int volatile* p = &x;
- int z = *p ? 1 : 0;
- EXPECT_POISONED(z);
-}
-
-TEST(MemorySanitizer, SelectPartial) {
- // Precise instrumentation of select.
- // Some bits of the result do not depend on select condition, and must stay
- // initialized even if select condition is not. These are the bits that are
- // equal and initialized in both left and right select arguments.
- U4 x = 0xFFFFABCDU;
- U4 x_s = 0xFFFF0000U;
- __msan_partial_poison(&x, &x_s, sizeof(x));
- U4 y = 0xAB00U;
- U1 cond = true;
- __msan_poison(&cond, sizeof(cond));
- U4 z = cond ? x : y;
- __msan_print_shadow(&z, sizeof(z));
- EXPECT_POISONED(z & 0xFFU);
- EXPECT_NOT_POISONED(z & 0xFF00U);
- EXPECT_POISONED(z & 0xFF0000U);
- EXPECT_POISONED(z & 0xFF000000U);
- EXPECT_EQ(0xAB00U, z & 0xFF00U);
-}
-
-TEST(MemorySanitizerStress, DISABLED_MallocStackTrace) {
- RecursiveMalloc(22);
-}
-
-TEST(MemorySanitizerAllocator, get_estimated_allocated_size) {
- size_t sizes[] = {0, 20, 5000, 1<<20};
- for (size_t i = 0; i < sizeof(sizes) / sizeof(*sizes); ++i) {
- size_t alloc_size = __sanitizer_get_estimated_allocated_size(sizes[i]);
- EXPECT_EQ(alloc_size, sizes[i]);
- }
-}
-
-TEST(MemorySanitizerAllocator, get_allocated_size_and_ownership) {
- char *array = reinterpret_cast<char*>(malloc(100));
- int *int_ptr = new int;
-
- EXPECT_TRUE(__sanitizer_get_ownership(array));
- EXPECT_EQ(100U, __sanitizer_get_allocated_size(array));
-
- EXPECT_TRUE(__sanitizer_get_ownership(int_ptr));
- EXPECT_EQ(sizeof(*int_ptr), __sanitizer_get_allocated_size(int_ptr));
-
- void *wild_addr = reinterpret_cast<void*>(0x1);
- EXPECT_FALSE(__sanitizer_get_ownership(wild_addr));
- EXPECT_EQ(0U, __sanitizer_get_allocated_size(wild_addr));
-
- EXPECT_FALSE(__sanitizer_get_ownership(array + 50));
- EXPECT_EQ(0U, __sanitizer_get_allocated_size(array + 50));
-
- // NULL is a valid argument for GetAllocatedSize but is not owned.
- EXPECT_FALSE(__sanitizer_get_ownership(NULL));
- EXPECT_EQ(0U, __sanitizer_get_allocated_size(NULL));
-
- free(array);
- EXPECT_FALSE(__sanitizer_get_ownership(array));
- EXPECT_EQ(0U, __sanitizer_get_allocated_size(array));
-
- delete int_ptr;
-}
-
-TEST(MemorySanitizer, MlockTest) {
- EXPECT_EQ(0, mlockall(MCL_CURRENT));
- EXPECT_EQ(0, mlock((void*)0x12345, 0x5678));
- EXPECT_EQ(0, munlockall());
- EXPECT_EQ(0, munlock((void*)0x987, 0x654));
-}
-
-// Test that LargeAllocator unpoisons memory before releasing it to the OS.
-TEST(MemorySanitizer, LargeAllocatorUnpoisonsOnFree) {
- void *p = malloc(1024 * 1024);
- free(p);
-
- typedef void *(*mmap_fn)(void *, size_t, int, int, int, off_t);
- mmap_fn real_mmap = (mmap_fn)dlsym(RTLD_NEXT, "mmap");
-
- // Allocate the page that was released to the OS in free() with the real mmap,
- // bypassing the interceptor.
- char *q = (char *)real_mmap(p, 4096, PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
- ASSERT_NE((char *)0, q);
-
- ASSERT_TRUE(q <= p);
- ASSERT_TRUE(q + 4096 > p);
-
- EXPECT_NOT_POISONED(q[0]);
- EXPECT_NOT_POISONED(q[10]);
- EXPECT_NOT_POISONED(q[100]);
-
- munmap(q, 4096);
-}
-
-#if SANITIZER_TEST_HAS_MALLOC_USABLE_SIZE
-TEST(MemorySanitizer, MallocUsableSizeTest) {
- const size_t kArraySize = 100;
- char *array = Ident((char*)malloc(kArraySize));
- int *int_ptr = Ident(new int);
- EXPECT_EQ(0U, malloc_usable_size(NULL));
- EXPECT_EQ(kArraySize, malloc_usable_size(array));
- EXPECT_EQ(sizeof(int), malloc_usable_size(int_ptr));
- free(array);
- delete int_ptr;
-}
-#endif // SANITIZER_TEST_HAS_MALLOC_USABLE_SIZE
diff --git a/contrib/compiler-rt/lib/msan/tests/msan_test_config.h b/contrib/compiler-rt/lib/msan/tests/msan_test_config.h
deleted file mode 100644
index 5404c434d09f..000000000000
--- a/contrib/compiler-rt/lib/msan/tests/msan_test_config.h
+++ /dev/null
@@ -1,20 +0,0 @@
-//===-- msan_test_config.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 MemorySanitizer.
-//
-// MemorySanitizer unit tests.
-//===----------------------------------------------------------------------===//
-
-#ifndef MSAN_TEST_CONFIG_H
-#define MSAN_TEST_CONFIG_H
-
-#include "gtest/gtest.h"
-
-#endif // MSAN_TEST_CONFIG_H
diff --git a/contrib/compiler-rt/lib/msan/tests/msan_test_main.cc b/contrib/compiler-rt/lib/msan/tests/msan_test_main.cc
deleted file mode 100644
index c8c5fefb19f5..000000000000
--- a/contrib/compiler-rt/lib/msan/tests/msan_test_main.cc
+++ /dev/null
@@ -1,21 +0,0 @@
-//===-- msan_test_main.cc -------------------------------------------------===//
-//
-// 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 MemorySanitizer.
-//
-//===----------------------------------------------------------------------===//
-#ifndef MSAN_EXTERNAL_TEST_CONFIG
-#include "msan_test_config.h"
-#endif // MSAN_EXTERNAL_TEST_CONFIG
-
-int main(int argc, char **argv) {
- testing::GTEST_FLAG(death_test_style) = "threadsafe";
- testing::InitGoogleTest(&argc, argv);
- return RUN_ALL_TESTS();
-}
diff --git a/contrib/compiler-rt/lib/profile/GCDAProfiling.c b/contrib/compiler-rt/lib/profile/GCDAProfiling.c
index aec232856e74..2338761ae1ab 100644
--- a/contrib/compiler-rt/lib/profile/GCDAProfiling.c
+++ b/contrib/compiler-rt/lib/profile/GCDAProfiling.c
@@ -27,8 +27,13 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+
+#if defined(_WIN32)
+#include "WindowsMMap.h"
+#else
#include <sys/mman.h>
#include <sys/file.h>
+#endif
#define I386_FREEBSD (defined(__FreeBSD__) && defined(__i386__))
@@ -37,6 +42,7 @@
#endif
#if defined(_MSC_VER)
+typedef unsigned char uint8_t;
typedef unsigned int uint32_t;
typedef unsigned long long uint64_t;
#elif I386_FREEBSD
diff --git a/contrib/compiler-rt/lib/profile/InstrProfData.inc b/contrib/compiler-rt/lib/profile/InstrProfData.inc
new file mode 100644
index 000000000000..33c7d94aea2a
--- /dev/null
+++ b/contrib/compiler-rt/lib/profile/InstrProfData.inc
@@ -0,0 +1,767 @@
+/*===-- InstrProfData.inc - instr profiling runtime structures -*- C++ -*-=== *\
+|*
+|* The LLVM Compiler Infrastructure
+|*
+|* This file is distributed under the University of Illinois Open Source
+|* License. See LICENSE.TXT for details.
+|*
+\*===----------------------------------------------------------------------===*/
+/*
+ * This is the master file that defines all the data structure, signature,
+ * constant literals that are shared across profiling runtime library,
+ * compiler (instrumentation), and host tools (reader/writer). The entities
+ * defined in this file affect the profile runtime ABI, the raw profile format,
+ * or both.
+ *
+ * The file has two identical copies. The master copy lives in LLVM and
+ * the other one sits in compiler-rt/lib/profile directory. To make changes
+ * in this file, first modify the master copy and copy it over to compiler-rt.
+ * Testing of any change in this file can start only after the two copies are
+ * synced up.
+ *
+ * The first part of the file includes macros that defines types, names, and
+ * initializers for the member fields of the core data structures. The field
+ * declarations for one structure is enabled by defining the field activation
+ * macro associated with that structure. Only one field activation record
+ * can be defined at one time and the rest definitions will be filtered out by
+ * the preprocessor.
+ *
+ * Examples of how the template is used to instantiate structure definition:
+ * 1. To declare a structure:
+ *
+ * struct ProfData {
+ * #define INSTR_PROF_DATA(Type, LLVMType, Name, Initializer) \
+ * Type Name;
+ * #include "llvm/ProfileData/InstrProfData.inc"
+ * };
+ *
+ * 2. To construct LLVM type arrays for the struct type:
+ *
+ * Type *DataTypes[] = {
+ * #define INSTR_PROF_DATA(Type, LLVMType, Name, Initializer) \
+ * LLVMType,
+ * #include "llvm/ProfileData/InstrProfData.inc"
+ * };
+ *
+ * 4. To construct constant array for the initializers:
+ * #define INSTR_PROF_DATA(Type, LLVMType, Name, Initializer) \
+ * Initializer,
+ * Constant *ConstantVals[] = {
+ * #include "llvm/ProfileData/InstrProfData.inc"
+ * };
+ *
+ *
+ * The second part of the file includes definitions all other entities that
+ * are related to runtime ABI and format. When no field activation macro is
+ * defined, this file can be included to introduce the definitions.
+ *
+\*===----------------------------------------------------------------------===*/
+
+/* INSTR_PROF_DATA start. */
+/* Definition of member fields of the per-function control structure. */
+#ifndef INSTR_PROF_DATA
+#define INSTR_PROF_DATA(Type, LLVMType, Name, Initializer)
+#else
+#define INSTR_PROF_DATA_DEFINED
+#endif
+
+INSTR_PROF_DATA(const uint32_t, llvm::Type::getInt32Ty(Ctx), NameSize, \
+ ConstantInt::get(llvm::Type::getInt32Ty(Ctx), \
+ NamePtr->getType()->getPointerElementType()->getArrayNumElements()))
+INSTR_PROF_DATA(const uint32_t, llvm::Type::getInt32Ty(Ctx), NumCounters, \
+ ConstantInt::get(llvm::Type::getInt32Ty(Ctx), NumCounters))
+INSTR_PROF_DATA(const uint64_t, llvm::Type::getInt64Ty(Ctx), FuncHash, \
+ ConstantInt::get(llvm::Type::getInt64Ty(Ctx), \
+ Inc->getHash()->getZExtValue()))
+INSTR_PROF_DATA(const IntPtrT, llvm::Type::getInt8PtrTy(Ctx), NamePtr, \
+ ConstantExpr::getBitCast(NamePtr, llvm::Type::getInt8PtrTy(Ctx)))
+INSTR_PROF_DATA(const IntPtrT, llvm::Type::getInt64PtrTy(Ctx), CounterPtr, \
+ ConstantExpr::getBitCast(CounterPtr, \
+ llvm::Type::getInt64PtrTy(Ctx)))
+INSTR_PROF_DATA(const IntPtrT, llvm::Type::getInt8PtrTy(Ctx), FunctionPointer, \
+ FunctionAddr)
+INSTR_PROF_DATA(IntPtrT, llvm::Type::getInt8PtrTy(Ctx), Values, \
+ ConstantPointerNull::get(Int8PtrTy))
+INSTR_PROF_DATA(const uint16_t, Int16ArrayTy, NumValueSites[IPVK_Last+1], \
+ ConstantArray::get(Int16ArrayTy, Int16ArrayVals))
+#undef INSTR_PROF_DATA
+/* INSTR_PROF_DATA end. */
+
+/* INSTR_PROF_RAW_HEADER start */
+/* Definition of member fields of the raw profile header data structure. */
+#ifndef INSTR_PROF_RAW_HEADER
+#define INSTR_PROF_RAW_HEADER(Type, Name, Initializer)
+#else
+#define INSTR_PROF_DATA_DEFINED
+#endif
+INSTR_PROF_RAW_HEADER(uint64_t, Magic, __llvm_profile_get_magic())
+INSTR_PROF_RAW_HEADER(uint64_t, Version, __llvm_profile_get_version())
+INSTR_PROF_RAW_HEADER(uint64_t, DataSize, DataSize)
+INSTR_PROF_RAW_HEADER(uint64_t, CountersSize, CountersSize)
+INSTR_PROF_RAW_HEADER(uint64_t, NamesSize, NamesSize)
+INSTR_PROF_RAW_HEADER(uint64_t, CountersDelta, (uintptr_t)CountersBegin)
+INSTR_PROF_RAW_HEADER(uint64_t, NamesDelta, (uintptr_t)NamesBegin)
+INSTR_PROF_RAW_HEADER(uint64_t, ValueKindLast, IPVK_Last)
+INSTR_PROF_RAW_HEADER(uint64_t, ValueDataSize, ValueDataSize)
+INSTR_PROF_RAW_HEADER(uint64_t, ValueDataDelta, (uintptr_t)ValueDataBegin)
+#undef INSTR_PROF_RAW_HEADER
+/* INSTR_PROF_RAW_HEADER end */
+
+/* VALUE_PROF_FUNC_PARAM start */
+/* Definition of parameter types of the runtime API used to do value profiling
+ * for a given value site.
+ */
+#ifndef VALUE_PROF_FUNC_PARAM
+#define VALUE_PROF_FUNC_PARAM(ArgType, ArgName, ArgLLVMType)
+#define INSTR_PROF_COMMA
+#else
+#define INSTR_PROF_DATA_DEFINED
+#define INSTR_PROF_COMMA ,
+#endif
+VALUE_PROF_FUNC_PARAM(uint64_t, TargetValue, Type::getInt64Ty(Ctx)) \
+ INSTR_PROF_COMMA
+VALUE_PROF_FUNC_PARAM(void *, Data, Type::getInt8PtrTy(Ctx)) INSTR_PROF_COMMA
+VALUE_PROF_FUNC_PARAM(uint32_t, CounterIndex, Type::getInt32Ty(Ctx))
+#undef VALUE_PROF_FUNC_PARAM
+#undef INSTR_PROF_COMMA
+/* VALUE_PROF_FUNC_PARAM end */
+
+/* VALUE_PROF_KIND start */
+#ifndef VALUE_PROF_KIND
+#define VALUE_PROF_KIND(Enumerator, Value)
+#else
+#define INSTR_PROF_DATA_DEFINED
+#endif
+VALUE_PROF_KIND(IPVK_IndirectCallTarget, 0)
+/* These two kinds must be the last to be
+ * declared. This is to make sure the string
+ * array created with the template can be
+ * indexed with the kind value.
+ */
+VALUE_PROF_KIND(IPVK_First, IPVK_IndirectCallTarget)
+VALUE_PROF_KIND(IPVK_Last, IPVK_IndirectCallTarget)
+
+#undef VALUE_PROF_KIND
+/* VALUE_PROF_KIND end */
+
+/* COVMAP_FUNC_RECORD start */
+/* Definition of member fields of the function record structure in coverage
+ * map.
+ */
+#ifndef COVMAP_FUNC_RECORD
+#define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Initializer)
+#else
+#define INSTR_PROF_DATA_DEFINED
+#endif
+COVMAP_FUNC_RECORD(const IntPtrT, llvm::Type::getInt8PtrTy(Ctx), \
+ NamePtr, llvm::ConstantExpr::getBitCast(NamePtr, \
+ llvm::Type::getInt8PtrTy(Ctx)))
+COVMAP_FUNC_RECORD(const uint32_t, llvm::Type::getInt32Ty(Ctx), NameSize, \
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(Ctx),\
+ NameValue.size()))
+COVMAP_FUNC_RECORD(const uint32_t, llvm::Type::getInt32Ty(Ctx), DataSize, \
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(Ctx),\
+ CoverageMapping.size()))
+COVMAP_FUNC_RECORD(const uint64_t, llvm::Type::getInt64Ty(Ctx), FuncHash, \
+ llvm::ConstantInt::get(llvm::Type::getInt64Ty(Ctx), FuncHash))
+#undef COVMAP_FUNC_RECORD
+/* COVMAP_FUNC_RECORD end. */
+
+/* COVMAP_HEADER start */
+/* Definition of member fields of coverage map header.
+ */
+#ifndef COVMAP_HEADER
+#define COVMAP_HEADER(Type, LLVMType, Name, Initializer)
+#else
+#define INSTR_PROF_DATA_DEFINED
+#endif
+COVMAP_HEADER(uint32_t, Int32Ty, NRecords, \
+ llvm::ConstantInt::get(Int32Ty, FunctionRecords.size()))
+COVMAP_HEADER(uint32_t, Int32Ty, FilenamesSize, \
+ llvm::ConstantInt::get(Int32Ty, FilenamesSize))
+COVMAP_HEADER(uint32_t, Int32Ty, CoverageSize, \
+ llvm::ConstantInt::get(Int32Ty, CoverageMappingSize))
+COVMAP_HEADER(uint32_t, Int32Ty, Version, \
+ llvm::ConstantInt::get(Int32Ty, CoverageMappingCurrentVersion))
+#undef COVMAP_HEADER
+/* COVMAP_HEADER end. */
+
+
+#ifdef INSTR_PROF_VALUE_PROF_DATA
+#define INSTR_PROF_DATA_DEFINED
+
+#define INSTR_PROF_MAX_NUM_VAL_PER_SITE 255
+/*!
+ * This is the header of the data structure that defines the on-disk
+ * layout of the value profile data of a particular kind for one function.
+ */
+typedef struct ValueProfRecord {
+ /* The kind of the value profile record. */
+ uint32_t Kind;
+ /*
+ * The number of value profile sites. It is guaranteed to be non-zero;
+ * otherwise the record for this kind won't be emitted.
+ */
+ uint32_t NumValueSites;
+ /*
+ * The first element of the array that stores the number of profiled
+ * values for each value site. The size of the array is NumValueSites.
+ * Since NumValueSites is greater than zero, there is at least one
+ * element in the array.
+ */
+ uint8_t SiteCountArray[1];
+
+ /*
+ * The fake declaration is for documentation purpose only.
+ * Align the start of next field to be on 8 byte boundaries.
+ uint8_t Padding[X];
+ */
+
+ /* The array of value profile data. The size of the array is the sum
+ * of all elements in SiteCountArray[].
+ InstrProfValueData ValueData[];
+ */
+
+#ifdef __cplusplus
+ /*!
+ * \brief Return the number of value sites.
+ */
+ uint32_t getNumValueSites() const { return NumValueSites; }
+ /*!
+ * \brief Read data from this record and save it to Record.
+ */
+ void deserializeTo(InstrProfRecord &Record,
+ InstrProfRecord::ValueMapType *VMap);
+ /*
+ * In-place byte swap:
+ * Do byte swap for this instance. \c Old is the original order before
+ * the swap, and \c New is the New byte order.
+ */
+ void swapBytes(support::endianness Old, support::endianness New);
+#endif
+} ValueProfRecord;
+
+/*!
+ * Per-function header/control data structure for value profiling
+ * data in indexed format.
+ */
+typedef struct ValueProfData {
+ /*
+ * Total size in bytes including this field. It must be a multiple
+ * of sizeof(uint64_t).
+ */
+ uint32_t TotalSize;
+ /*
+ *The number of value profile kinds that has value profile data.
+ * In this implementation, a value profile kind is considered to
+ * have profile data if the number of value profile sites for the
+ * kind is not zero. More aggressively, the implementation can
+ * choose to check the actual data value: if none of the value sites
+ * has any profiled values, the kind can be skipped.
+ */
+ uint32_t NumValueKinds;
+
+ /*
+ * Following are a sequence of variable length records. The prefix/header
+ * of each record is defined by ValueProfRecord type. The number of
+ * records is NumValueKinds.
+ * ValueProfRecord Record_1;
+ * ValueProfRecord Record_N;
+ */
+
+#if __cplusplus
+ /*!
+ * Return the total size in bytes of the on-disk value profile data
+ * given the data stored in Record.
+ */
+ static uint32_t getSize(const InstrProfRecord &Record);
+ /*!
+ * Return a pointer to \c ValueProfData instance ready to be streamed.
+ */
+ static std::unique_ptr<ValueProfData>
+ serializeFrom(const InstrProfRecord &Record);
+ /*!
+ * Check the integrity of the record. Return the error code when
+ * an error is detected, otherwise return instrprof_error::success.
+ */
+ instrprof_error checkIntegrity();
+ /*!
+ * Return a pointer to \c ValueProfileData instance ready to be read.
+ * All data in the instance are properly byte swapped. The input
+ * data is assumed to be in little endian order.
+ */
+ static ErrorOr<std::unique_ptr<ValueProfData>>
+ getValueProfData(const unsigned char *SrcBuffer,
+ const unsigned char *const SrcBufferEnd,
+ support::endianness SrcDataEndianness);
+ /*!
+ * Swap byte order from \c Endianness order to host byte order.
+ */
+ void swapBytesToHost(support::endianness Endianness);
+ /*!
+ * Swap byte order from host byte order to \c Endianness order.
+ */
+ void swapBytesFromHost(support::endianness Endianness);
+ /*!
+ * Return the total size of \c ValueProfileData.
+ */
+ uint32_t getSize() const { return TotalSize; }
+ /*!
+ * Read data from this data and save it to \c Record.
+ */
+ void deserializeTo(InstrProfRecord &Record,
+ InstrProfRecord::ValueMapType *VMap);
+ void operator delete(void *ptr) { ::operator delete(ptr); }
+#endif
+} ValueProfData;
+
+/*
+ * The closure is designed to abstact away two types of value profile data:
+ * - InstrProfRecord which is the primary data structure used to
+ * represent profile data in host tools (reader, writer, and profile-use)
+ * - value profile runtime data structure suitable to be used by C
+ * runtime library.
+ *
+ * Both sources of data need to serialize to disk/memory-buffer in common
+ * format: ValueProfData. The abstraction allows compiler-rt's raw profiler
+ * writer to share the same format and code with indexed profile writer.
+ *
+ * For documentation of the member methods below, refer to corresponding methods
+ * in class InstrProfRecord.
+ */
+typedef struct ValueProfRecordClosure {
+ const void *Record;
+ uint32_t (*GetNumValueKinds)(const void *Record);
+ uint32_t (*GetNumValueSites)(const void *Record, uint32_t VKind);
+ uint32_t (*GetNumValueData)(const void *Record, uint32_t VKind);
+ uint32_t (*GetNumValueDataForSite)(const void *R, uint32_t VK, uint32_t S);
+
+ /*
+ * After extracting the value profile data from the value profile record,
+ * this method is used to map the in-memory value to on-disk value. If
+ * the method is null, value will be written out untranslated.
+ */
+ uint64_t (*RemapValueData)(uint32_t, uint64_t Value);
+ void (*GetValueForSite)(const void *R, InstrProfValueData *Dst, uint32_t K,
+ uint32_t S, uint64_t (*Mapper)(uint32_t, uint64_t));
+ ValueProfData *(*AllocValueProfData)(size_t TotalSizeInBytes);
+} ValueProfRecordClosure;
+
+/*
+ * A wrapper struct that represents value profile runtime data.
+ * Like InstrProfRecord class which is used by profiling host tools,
+ * ValueProfRuntimeRecord also implements the abstract intefaces defined in
+ * ValueProfRecordClosure so that the runtime data can be serialized using
+ * shared C implementation. In this structure, NumValueSites and Nodes
+ * members are the primary fields while other fields hold the derived
+ * information for fast implementation of closure interfaces.
+ */
+typedef struct ValueProfRuntimeRecord {
+ /* Number of sites for each value profile kind. */
+ const uint16_t *NumValueSites;
+ /* An array of linked-list headers. The size of of the array is the
+ * total number of value profile sites : sum(NumValueSites[*])). Each
+ * linked-list stores the values profiled for a value profile site. */
+ ValueProfNode **Nodes;
+
+ /* Total number of value profile kinds which have at least one
+ * value profile sites. */
+ uint32_t NumValueKinds;
+ /* An array recording the number of values tracked at each site.
+ * The size of the array is TotalNumValueSites. */
+ uint8_t *SiteCountArray[IPVK_Last + 1];
+ ValueProfNode **NodesKind[IPVK_Last + 1];
+} ValueProfRuntimeRecord;
+
+/* Forward declarations of C interfaces. */
+int initializeValueProfRuntimeRecord(ValueProfRuntimeRecord *RuntimeRecord,
+ const uint16_t *NumValueSites,
+ ValueProfNode **Nodes);
+void finalizeValueProfRuntimeRecord(ValueProfRuntimeRecord *RuntimeRecord);
+uint32_t getValueProfDataSizeRT(const ValueProfRuntimeRecord *Record);
+ValueProfData *
+serializeValueProfDataFromRT(const ValueProfRuntimeRecord *Record,
+ ValueProfData *Dst);
+uint32_t getNumValueKindsRT(const void *R);
+
+#undef INSTR_PROF_VALUE_PROF_DATA
+#endif /* INSTR_PROF_VALUE_PROF_DATA */
+
+
+#ifdef INSTR_PROF_COMMON_API_IMPL
+#define INSTR_PROF_DATA_DEFINED
+#ifdef __cplusplus
+#define INSTR_PROF_INLINE inline
+#else
+#define INSTR_PROF_INLINE
+#endif
+
+#ifndef offsetof
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#endif
+
+/*!
+ * \brief Return the \c ValueProfRecord header size including the
+ * padding bytes.
+ */
+INSTR_PROF_INLINE
+uint32_t getValueProfRecordHeaderSize(uint32_t NumValueSites) {
+ uint32_t Size = offsetof(ValueProfRecord, SiteCountArray) +
+ sizeof(uint8_t) * NumValueSites;
+ /* Round the size to multiple of 8 bytes. */
+ Size = (Size + 7) & ~7;
+ return Size;
+}
+
+/*!
+ * \brief Return the total size of the value profile record including the
+ * header and the value data.
+ */
+INSTR_PROF_INLINE
+uint32_t getValueProfRecordSize(uint32_t NumValueSites,
+ uint32_t NumValueData) {
+ return getValueProfRecordHeaderSize(NumValueSites) +
+ sizeof(InstrProfValueData) * NumValueData;
+}
+
+/*!
+ * \brief Return the pointer to the start of value data array.
+ */
+INSTR_PROF_INLINE
+InstrProfValueData *getValueProfRecordValueData(ValueProfRecord *This) {
+ return (InstrProfValueData *)((char *)This + getValueProfRecordHeaderSize(
+ This->NumValueSites));
+}
+
+/*!
+ * \brief Return the total number of value data for \c This record.
+ */
+INSTR_PROF_INLINE
+uint32_t getValueProfRecordNumValueData(ValueProfRecord *This) {
+ uint32_t NumValueData = 0;
+ uint32_t I;
+ for (I = 0; I < This->NumValueSites; I++)
+ NumValueData += This->SiteCountArray[I];
+ return NumValueData;
+}
+
+/*!
+ * \brief Use this method to advance to the next \c This \c ValueProfRecord.
+ */
+INSTR_PROF_INLINE
+ValueProfRecord *getValueProfRecordNext(ValueProfRecord *This) {
+ uint32_t NumValueData = getValueProfRecordNumValueData(This);
+ return (ValueProfRecord *)((char *)This +
+ getValueProfRecordSize(This->NumValueSites,
+ NumValueData));
+}
+
+/*!
+ * \brief Return the first \c ValueProfRecord instance.
+ */
+INSTR_PROF_INLINE
+ValueProfRecord *getFirstValueProfRecord(ValueProfData *This) {
+ return (ValueProfRecord *)((char *)This + sizeof(ValueProfData));
+}
+
+/* Closure based interfaces. */
+
+/*!
+ * Return the total size in bytes of the on-disk value profile data
+ * given the data stored in Record.
+ */
+uint32_t getValueProfDataSize(ValueProfRecordClosure *Closure) {
+ uint32_t Kind;
+ uint32_t TotalSize = sizeof(ValueProfData);
+ const void *Record = Closure->Record;
+ uint32_t NumValueKinds = Closure->GetNumValueKinds(Record);
+ if (NumValueKinds == 0)
+ return TotalSize;
+
+ for (Kind = IPVK_First; Kind <= IPVK_Last; Kind++) {
+ uint32_t NumValueSites = Closure->GetNumValueSites(Record, Kind);
+ if (!NumValueSites)
+ continue;
+ TotalSize += getValueProfRecordSize(NumValueSites,
+ Closure->GetNumValueData(Record, Kind));
+ }
+ return TotalSize;
+}
+
+/*!
+ * Extract value profile data of a function for the profile kind \c ValueKind
+ * from the \c Closure and serialize the data into \c This record instance.
+ */
+void serializeValueProfRecordFrom(ValueProfRecord *This,
+ ValueProfRecordClosure *Closure,
+ uint32_t ValueKind, uint32_t NumValueSites) {
+ uint32_t S;
+ const void *Record = Closure->Record;
+ This->Kind = ValueKind;
+ This->NumValueSites = NumValueSites;
+ InstrProfValueData *DstVD = getValueProfRecordValueData(This);
+
+ for (S = 0; S < NumValueSites; S++) {
+ uint32_t ND = Closure->GetNumValueDataForSite(Record, ValueKind, S);
+ This->SiteCountArray[S] = ND;
+ Closure->GetValueForSite(Record, DstVD, ValueKind, S,
+ Closure->RemapValueData);
+ DstVD += ND;
+ }
+}
+
+/*!
+ * Extract value profile data of a function from the \c Closure
+ * and serialize the data into \c DstData if it is not NULL or heap
+ * memory allocated by the \c Closure's allocator method.
+ */
+ValueProfData *serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
+ ValueProfData *DstData) {
+ uint32_t Kind;
+ uint32_t TotalSize = getValueProfDataSize(Closure);
+
+ ValueProfData *VPD =
+ DstData ? DstData : Closure->AllocValueProfData(TotalSize);
+
+ VPD->TotalSize = TotalSize;
+ VPD->NumValueKinds = Closure->GetNumValueKinds(Closure->Record);
+ ValueProfRecord *VR = getFirstValueProfRecord(VPD);
+ for (Kind = IPVK_First; Kind <= IPVK_Last; Kind++) {
+ uint32_t NumValueSites = Closure->GetNumValueSites(Closure->Record, Kind);
+ if (!NumValueSites)
+ continue;
+ serializeValueProfRecordFrom(VR, Closure, Kind, NumValueSites);
+ VR = getValueProfRecordNext(VR);
+ }
+ return VPD;
+}
+
+/*
+ * The value profiler runtime library stores the value profile data
+ * for a given function in \c NumValueSites and \c Nodes structures.
+ * \c ValueProfRuntimeRecord class is used to encapsulate the runtime
+ * profile data and provides fast interfaces to retrieve the profile
+ * information. This interface is used to initialize the runtime record
+ * and pre-compute the information needed for efficient implementation
+ * of callbacks required by ValueProfRecordClosure class.
+ */
+int initializeValueProfRuntimeRecord(ValueProfRuntimeRecord *RuntimeRecord,
+ const uint16_t *NumValueSites,
+ ValueProfNode **Nodes) {
+ unsigned I, J, S = 0, NumValueKinds = 0;
+ RuntimeRecord->NumValueSites = NumValueSites;
+ RuntimeRecord->Nodes = Nodes;
+ for (I = 0; I <= IPVK_Last; I++) {
+ uint16_t N = NumValueSites[I];
+ if (!N) {
+ RuntimeRecord->SiteCountArray[I] = 0;
+ continue;
+ }
+ NumValueKinds++;
+ RuntimeRecord->SiteCountArray[I] = (uint8_t *)calloc(N, 1);
+ if (!RuntimeRecord->SiteCountArray[I])
+ return 1;
+ RuntimeRecord->NodesKind[I] = Nodes ? &Nodes[S] : NULL;
+ for (J = 0; J < N; J++) {
+ /* Compute value count for each site. */
+ uint32_t C = 0;
+ ValueProfNode *Site = Nodes ? RuntimeRecord->NodesKind[I][J] : NULL;
+ while (Site) {
+ C++;
+ Site = Site->Next;
+ }
+ if (C > UCHAR_MAX)
+ C = UCHAR_MAX;
+ RuntimeRecord->SiteCountArray[I][J] = C;
+ }
+ S += N;
+ }
+ RuntimeRecord->NumValueKinds = NumValueKinds;
+ return 0;
+}
+
+void finalizeValueProfRuntimeRecord(ValueProfRuntimeRecord *RuntimeRecord) {
+ unsigned I;
+ for (I = 0; I <= IPVK_Last; I++) {
+ if (RuntimeRecord->SiteCountArray[I])
+ free(RuntimeRecord->SiteCountArray[I]);
+ }
+}
+
+/* ValueProfRecordClosure Interface implementation for
+ * ValueProfDataRuntimeRecord. */
+uint32_t getNumValueKindsRT(const void *R) {
+ return ((const ValueProfRuntimeRecord *)R)->NumValueKinds;
+}
+
+uint32_t getNumValueSitesRT(const void *R, uint32_t VK) {
+ return ((const ValueProfRuntimeRecord *)R)->NumValueSites[VK];
+}
+
+uint32_t getNumValueDataForSiteRT(const void *R, uint32_t VK, uint32_t S) {
+ const ValueProfRuntimeRecord *Record = (const ValueProfRuntimeRecord *)R;
+ return Record->SiteCountArray[VK][S];
+}
+
+uint32_t getNumValueDataRT(const void *R, uint32_t VK) {
+ unsigned I, S = 0;
+ const ValueProfRuntimeRecord *Record = (const ValueProfRuntimeRecord *)R;
+ if (Record->SiteCountArray[VK] == 0)
+ return 0;
+ for (I = 0; I < Record->NumValueSites[VK]; I++)
+ S += Record->SiteCountArray[VK][I];
+ return S;
+}
+
+void getValueForSiteRT(const void *R, InstrProfValueData *Dst, uint32_t VK,
+ uint32_t S, uint64_t (*Mapper)(uint32_t, uint64_t)) {
+ unsigned I, N = 0;
+ const ValueProfRuntimeRecord *Record = (const ValueProfRuntimeRecord *)R;
+ N = getNumValueDataForSiteRT(R, VK, S);
+ if (N == 0)
+ return;
+ ValueProfNode *VNode = Record->NodesKind[VK][S];
+ for (I = 0; I < N; I++) {
+ Dst[I] = VNode->VData;
+ VNode = VNode->Next;
+ }
+}
+
+ValueProfData *allocValueProfDataRT(size_t TotalSizeInBytes) {
+ return (ValueProfData *)calloc(TotalSizeInBytes, 1);
+}
+
+static ValueProfRecordClosure RTRecordClosure = {0,
+ getNumValueKindsRT,
+ getNumValueSitesRT,
+ getNumValueDataRT,
+ getNumValueDataForSiteRT,
+ 0,
+ getValueForSiteRT,
+ allocValueProfDataRT};
+
+/*
+ * Return the size of ValueProfData structure to store data
+ * recorded in the runtime record.
+ */
+uint32_t getValueProfDataSizeRT(const ValueProfRuntimeRecord *Record) {
+ RTRecordClosure.Record = Record;
+ return getValueProfDataSize(&RTRecordClosure);
+}
+
+/*
+ * Return a ValueProfData instance that stores the data collected
+ * from runtime. If \c DstData is provided by the caller, the value
+ * profile data will be store in *DstData and DstData is returned,
+ * otherwise the method will allocate space for the value data and
+ * return pointer to the newly allocated space.
+ */
+ValueProfData *
+serializeValueProfDataFromRT(const ValueProfRuntimeRecord *Record,
+ ValueProfData *DstData) {
+ RTRecordClosure.Record = Record;
+ return serializeValueProfDataFrom(&RTRecordClosure, DstData);
+}
+
+
+#undef INSTR_PROF_COMMON_API_IMPL
+#endif /* INSTR_PROF_COMMON_API_IMPL */
+
+/*============================================================================*/
+
+
+#ifndef INSTR_PROF_DATA_DEFINED
+
+#ifndef INSTR_PROF_DATA_INC_
+#define INSTR_PROF_DATA_INC_
+
+/* Helper macros. */
+#define INSTR_PROF_SIMPLE_QUOTE(x) #x
+#define INSTR_PROF_QUOTE(x) INSTR_PROF_SIMPLE_QUOTE(x)
+#define INSTR_PROF_SIMPLE_CONCAT(x,y) x ## y
+#define INSTR_PROF_CONCAT(x,y) INSTR_PROF_SIMPLE_CONCAT(x,y)
+
+/* Magic number to detect file format and endianness.
+ * Use 255 at one end, since no UTF-8 file can use that character. Avoid 0,
+ * so that utilities, like strings, don't grab it as a string. 129 is also
+ * invalid UTF-8, and high enough to be interesting.
+ * Use "lprofr" in the centre to stand for "LLVM Profile Raw", or "lprofR"
+ * for 32-bit platforms.
+ */
+#define INSTR_PROF_RAW_MAGIC_64 (uint64_t)255 << 56 | (uint64_t)'l' << 48 | \
+ (uint64_t)'p' << 40 | (uint64_t)'r' << 32 | (uint64_t)'o' << 24 | \
+ (uint64_t)'f' << 16 | (uint64_t)'r' << 8 | (uint64_t)129
+#define INSTR_PROF_RAW_MAGIC_32 (uint64_t)255 << 56 | (uint64_t)'l' << 48 | \
+ (uint64_t)'p' << 40 | (uint64_t)'r' << 32 | (uint64_t)'o' << 24 | \
+ (uint64_t)'f' << 16 | (uint64_t)'R' << 8 | (uint64_t)129
+
+/* Raw profile format version. */
+#define INSTR_PROF_RAW_VERSION 2
+#define INSTR_PROF_INDEX_VERSION 3
+#define INSTR_PROF_COVMAP_VERSION 0
+
+/* Profile version is always of type uint_64_t. Reserve the upper 8 bits in the
+ * version for other variants of profile. We set the lowest bit of the upper 8
+ * bits (i.e. bit 56) to 1 to indicate if this is an IR-level instrumentaiton
+ * generated profile, and 0 if this is a Clang FE generated profile.
+*/
+#define VARIANT_MASKS_ALL 0xff00000000000000ULL
+#define GET_VERSION(V) ((V) & ~VARIANT_MASKS_ALL)
+
+/* Runtime section names and name strings. */
+#define INSTR_PROF_DATA_SECT_NAME __llvm_prf_data
+#define INSTR_PROF_NAME_SECT_NAME __llvm_prf_names
+#define INSTR_PROF_CNTS_SECT_NAME __llvm_prf_cnts
+#define INSTR_PROF_COVMAP_SECT_NAME __llvm_covmap
+
+#define INSTR_PROF_DATA_SECT_NAME_STR \
+ INSTR_PROF_QUOTE(INSTR_PROF_DATA_SECT_NAME)
+#define INSTR_PROF_NAME_SECT_NAME_STR \
+ INSTR_PROF_QUOTE(INSTR_PROF_NAME_SECT_NAME)
+#define INSTR_PROF_CNTS_SECT_NAME_STR \
+ INSTR_PROF_QUOTE(INSTR_PROF_CNTS_SECT_NAME)
+#define INSTR_PROF_COVMAP_SECT_NAME_STR \
+ INSTR_PROF_QUOTE(INSTR_PROF_COVMAP_SECT_NAME)
+
+/* Macros to define start/stop section symbol for a given
+ * section on Linux. For instance
+ * INSTR_PROF_SECT_START(INSTR_PROF_DATA_SECT_NAME) will
+ * expand to __start___llvm_prof_data
+ */
+#define INSTR_PROF_SECT_START(Sect) \
+ INSTR_PROF_CONCAT(__start_,Sect)
+#define INSTR_PROF_SECT_STOP(Sect) \
+ INSTR_PROF_CONCAT(__stop_,Sect)
+
+/* Value Profiling API linkage name. */
+#define INSTR_PROF_VALUE_PROF_FUNC __llvm_profile_instrument_target
+#define INSTR_PROF_VALUE_PROF_FUNC_STR \
+ INSTR_PROF_QUOTE(INSTR_PROF_VALUE_PROF_FUNC)
+
+/* InstrProfile per-function control data alignment. */
+#define INSTR_PROF_DATA_ALIGNMENT 8
+
+/* The data structure that represents a tracked value by the
+ * value profiler.
+ */
+typedef struct InstrProfValueData {
+ /* Profiled value. */
+ uint64_t Value;
+ /* Number of times the value appears in the training run. */
+ uint64_t Count;
+} InstrProfValueData;
+
+/* This is an internal data structure used by value profiler. It
+ * is defined here to allow serialization code sharing by LLVM
+ * to be used in unit test.
+ */
+typedef struct ValueProfNode {
+ InstrProfValueData VData;
+ struct ValueProfNode *Next;
+} ValueProfNode;
+
+#endif /* INSTR_PROF_DATA_INC_ */
+
+#else
+#undef INSTR_PROF_DATA_DEFINED
+#endif
diff --git a/contrib/compiler-rt/lib/profile/InstrProfiling.c b/contrib/compiler-rt/lib/profile/InstrProfiling.c
index 8d010df28f18..711f2b608a5f 100644
--- a/contrib/compiler-rt/lib/profile/InstrProfiling.c
+++ b/contrib/compiler-rt/lib/profile/InstrProfiling.c
@@ -8,41 +8,62 @@
\*===----------------------------------------------------------------------===*/
#include "InstrProfiling.h"
+#include "InstrProfilingInternal.h"
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
+#define INSTR_PROF_VALUE_PROF_DATA
+#include "InstrProfData.inc"
-__attribute__((visibility("hidden")))
-uint64_t __llvm_profile_get_magic(void) {
- /* Magic number to detect file format and endianness.
- *
- * Use 255 at one end, since no UTF-8 file can use that character. Avoid 0,
- * so that utilities, like strings, don't grab it as a string. 129 is also
- * invalid UTF-8, and high enough to be interesting.
- *
- * Use "lprofr" in the centre to stand for "LLVM Profile Raw", or "lprofR"
- * for 32-bit platforms.
- */
- unsigned char R = sizeof(void *) == sizeof(uint64_t) ? 'r' : 'R';
- return
- (uint64_t)255 << 56 |
- (uint64_t)'l' << 48 |
- (uint64_t)'p' << 40 |
- (uint64_t)'r' << 32 |
- (uint64_t)'o' << 24 |
- (uint64_t)'f' << 16 |
- (uint64_t) R << 8 |
- (uint64_t)129;
+char *(*GetEnvHook)(const char *) = 0;
+
+COMPILER_RT_WEAK uint64_t __llvm_profile_raw_version = INSTR_PROF_RAW_VERSION;
+
+COMPILER_RT_VISIBILITY uint64_t __llvm_profile_get_magic(void) {
+ return sizeof(void *) == sizeof(uint64_t) ? (INSTR_PROF_RAW_MAGIC_64)
+ : (INSTR_PROF_RAW_MAGIC_32);
}
-__attribute__((visibility("hidden")))
-uint64_t __llvm_profile_get_version(void) {
- /* This should be bumped any time the output format changes. */
- return 1;
+/* Return the number of bytes needed to add to SizeInBytes to make it
+ * the result a multiple of 8.
+ */
+COMPILER_RT_VISIBILITY uint8_t
+__llvm_profile_get_num_padding_bytes(uint64_t SizeInBytes) {
+ return 7 & (sizeof(uint64_t) - SizeInBytes % sizeof(uint64_t));
}
-__attribute__((visibility("hidden")))
-void __llvm_profile_reset_counters(void) {
+COMPILER_RT_VISIBILITY uint64_t __llvm_profile_get_version(void) {
+ return __llvm_profile_raw_version;
+}
+
+COMPILER_RT_VISIBILITY void __llvm_profile_reset_counters(void) {
uint64_t *I = __llvm_profile_begin_counters();
uint64_t *E = __llvm_profile_end_counters();
- memset(I, 0, sizeof(uint64_t)*(E - I));
+ memset(I, 0, sizeof(uint64_t) * (E - I));
+
+ const __llvm_profile_data *DataBegin = __llvm_profile_begin_data();
+ const __llvm_profile_data *DataEnd = __llvm_profile_end_data();
+ const __llvm_profile_data *DI;
+ for (DI = DataBegin; DI != DataEnd; ++DI) {
+ uint64_t CurrentVSiteCount = 0;
+ uint32_t VKI, i;
+ if (!DI->Values)
+ continue;
+
+ ValueProfNode **ValueCounters = (ValueProfNode **)DI->Values;
+
+ for (VKI = IPVK_First; VKI <= IPVK_Last; ++VKI)
+ CurrentVSiteCount += DI->NumValueSites[VKI];
+
+ for (i = 0; i < CurrentVSiteCount; ++i) {
+ ValueProfNode *CurrentVNode = ValueCounters[i];
+
+ while (CurrentVNode) {
+ CurrentVNode->VData.Count = 0;
+ CurrentVNode = CurrentVNode->Next;
+ }
+ }
+ }
}
diff --git a/contrib/compiler-rt/lib/profile/InstrProfiling.h b/contrib/compiler-rt/lib/profile/InstrProfiling.h
index 3778a88893e6..d27ca569d535 100644
--- a/contrib/compiler-rt/lib/profile/InstrProfiling.h
+++ b/contrib/compiler-rt/lib/profile/InstrProfiling.h
@@ -10,32 +10,31 @@
#ifndef PROFILE_INSTRPROFILING_H_
#define PROFILE_INSTRPROFILING_H_
-#if defined(__FreeBSD__) && defined(__i386__)
-
-/* System headers define 'size_t' incorrectly on x64 FreeBSD (prior to
- * FreeBSD 10, r232261) when compiled in 32-bit mode.
- */
-#define PRIu64 "llu"
-typedef unsigned int uint32_t;
-typedef unsigned long long uint64_t;
-typedef uint32_t uintptr_t;
-
-#else /* defined(__FreeBSD__) && defined(__i386__) */
-
-#include <inttypes.h>
-#include <stdint.h>
-
-#endif /* defined(__FreeBSD__) && defined(__i386__) */
+#include "InstrProfilingPort.h"
+#include "InstrProfData.inc"
+
+enum ValueKind {
+#define VALUE_PROF_KIND(Enumerator, Value) Enumerator = Value,
+#include "InstrProfData.inc"
+};
+
+typedef void *IntPtrT;
+typedef struct COMPILER_RT_ALIGNAS(INSTR_PROF_DATA_ALIGNMENT)
+ __llvm_profile_data {
+#define INSTR_PROF_DATA(Type, LLVMType, Name, Initializer) Type Name;
+#include "InstrProfData.inc"
+} __llvm_profile_data;
-#define PROFILE_HEADER_SIZE 7
+typedef struct __llvm_profile_header {
+#define INSTR_PROF_RAW_HEADER(Type, Name, Initializer) Type Name;
+#include "InstrProfData.inc"
+} __llvm_profile_header;
-typedef struct __llvm_profile_data {
- const uint32_t NameSize;
- const uint32_t NumCounters;
- const uint64_t FuncHash;
- const char *const Name;
- uint64_t *const Counters;
-} __llvm_profile_data;
+/*!
+ * \brief Get number of bytes necessary to pad the argument to eight
+ * byte boundary.
+ */
+uint8_t __llvm_profile_get_num_padding_bytes(uint64_t SizeInBytes);
/*!
* \brief Get required size for profile buffer.
@@ -58,9 +57,37 @@ uint64_t *__llvm_profile_begin_counters(void);
uint64_t *__llvm_profile_end_counters(void);
/*!
+ * \brief Clear profile counters to zero.
+ *
+ */
+void __llvm_profile_reset_counters(void);
+
+/*!
+ * \brief Counts the number of times a target value is seen.
+ *
+ * Records the target value for the CounterIndex if not seen before. Otherwise,
+ * increments the counter associated w/ the target value.
+ * void __llvm_profile_instrument_target(uint64_t TargetValue, void *Data,
+ * uint32_t CounterIndex);
+ */
+void INSTR_PROF_VALUE_PROF_FUNC(
+#define VALUE_PROF_FUNC_PARAM(ArgType, ArgName, ArgLLVMType) ArgType ArgName
+#include "InstrProfData.inc"
+);
+
+/*!
+ * \brief Prepares the value profiling data for output.
+ *
+ * Returns an array of pointers to value profile data.
+ */
+struct ValueProfData;
+struct ValueProfData **__llvm_profile_gather_value_data(uint64_t *Size);
+
+/*!
* \brief Write instrumentation data to the current file.
*
- * Writes to the file with the last name given to \a __llvm_profile_set_filename(),
+ * Writes to the file with the last name given to \a *
+ * __llvm_profile_set_filename(),
* or if it hasn't been called, the \c LLVM_PROFILE_FILE environment variable,
* or if that's not set, the last name given to
* \a __llvm_profile_override_default_filename(), or if that's not set,
diff --git a/contrib/compiler-rt/lib/profile/InstrProfilingBuffer.c b/contrib/compiler-rt/lib/profile/InstrProfilingBuffer.c
index 3c429c8a85ea..4227ca6b66ea 100644
--- a/contrib/compiler-rt/lib/profile/InstrProfilingBuffer.c
+++ b/contrib/compiler-rt/lib/profile/InstrProfilingBuffer.c
@@ -10,9 +10,7 @@
#include "InstrProfiling.h"
#include "InstrProfilingInternal.h"
-#include <string.h>
-
-__attribute__((visibility("hidden")))
+COMPILER_RT_VISIBILITY
uint64_t __llvm_profile_get_size_for_buffer(void) {
const __llvm_profile_data *DataBegin = __llvm_profile_begin_data();
const __llvm_profile_data *DataEnd = __llvm_profile_end_data();
@@ -27,78 +25,28 @@ uint64_t __llvm_profile_get_size_for_buffer(void) {
#define PROFILE_RANGE_SIZE(Range) (Range##End - Range##Begin)
-__attribute__((visibility("hidden")))
+COMPILER_RT_VISIBILITY
uint64_t __llvm_profile_get_size_for_buffer_internal(
- const __llvm_profile_data *DataBegin,
- const __llvm_profile_data *DataEnd, const uint64_t *CountersBegin,
- const uint64_t *CountersEnd, const char *NamesBegin,
- const char *NamesEnd) {
+ const __llvm_profile_data *DataBegin, const __llvm_profile_data *DataEnd,
+ const uint64_t *CountersBegin, const uint64_t *CountersEnd,
+ const char *NamesBegin, const char *NamesEnd) {
/* Match logic in __llvm_profile_write_buffer(). */
const uint64_t NamesSize = PROFILE_RANGE_SIZE(Names) * sizeof(char);
- const uint64_t Padding = sizeof(uint64_t) - NamesSize % sizeof(uint64_t);
- return sizeof(uint64_t) * PROFILE_HEADER_SIZE +
- PROFILE_RANGE_SIZE(Data) * sizeof(__llvm_profile_data) +
- PROFILE_RANGE_SIZE(Counters) * sizeof(uint64_t) +
- NamesSize + Padding;
+ const uint8_t Padding = __llvm_profile_get_num_padding_bytes(NamesSize);
+ return sizeof(__llvm_profile_header) +
+ PROFILE_RANGE_SIZE(Data) * sizeof(__llvm_profile_data) +
+ PROFILE_RANGE_SIZE(Counters) * sizeof(uint64_t) + NamesSize + Padding;
}
-__attribute__((visibility("hidden")))
-int __llvm_profile_write_buffer(char *Buffer) {
- /* Match logic in __llvm_profile_get_size_for_buffer().
- * Match logic in __llvm_profile_write_file().
- */
- const __llvm_profile_data *DataBegin = __llvm_profile_begin_data();
- const __llvm_profile_data *DataEnd = __llvm_profile_end_data();
- const uint64_t *CountersBegin = __llvm_profile_begin_counters();
- const uint64_t *CountersEnd = __llvm_profile_end_counters();
- const char *NamesBegin = __llvm_profile_begin_names();
- const char *NamesEnd = __llvm_profile_end_names();
-
- return __llvm_profile_write_buffer_internal(Buffer, DataBegin, DataEnd,
- CountersBegin, CountersEnd,
- NamesBegin, NamesEnd);
+COMPILER_RT_VISIBILITY int __llvm_profile_write_buffer(char *Buffer) {
+ return llvmWriteProfData(llvmBufferWriter, Buffer, 0, 0);
}
-__attribute__((visibility("hidden")))
-int __llvm_profile_write_buffer_internal(
+COMPILER_RT_VISIBILITY int __llvm_profile_write_buffer_internal(
char *Buffer, const __llvm_profile_data *DataBegin,
const __llvm_profile_data *DataEnd, const uint64_t *CountersBegin,
const uint64_t *CountersEnd, const char *NamesBegin, const char *NamesEnd) {
- /* Match logic in __llvm_profile_get_size_for_buffer().
- * Match logic in __llvm_profile_write_file().
- */
-
- /* Calculate size of sections. */
- const uint64_t DataSize = DataEnd - DataBegin;
- const uint64_t CountersSize = CountersEnd - CountersBegin;
- const uint64_t NamesSize = NamesEnd - NamesBegin;
- const uint64_t Padding = sizeof(uint64_t) - NamesSize % sizeof(uint64_t);
-
- /* Enough zeroes for padding. */
- const char Zeroes[sizeof(uint64_t)] = {0};
-
- /* Create the header. */
- uint64_t Header[PROFILE_HEADER_SIZE];
- Header[0] = __llvm_profile_get_magic();
- Header[1] = __llvm_profile_get_version();
- Header[2] = DataSize;
- Header[3] = CountersSize;
- Header[4] = NamesSize;
- Header[5] = (uintptr_t)CountersBegin;
- Header[6] = (uintptr_t)NamesBegin;
-
- /* Write the data. */
-#define UPDATE_memcpy(Data, Size) \
- do { \
- memcpy(Buffer, Data, Size); \
- Buffer += Size; \
- } while (0)
- UPDATE_memcpy(Header, PROFILE_HEADER_SIZE * sizeof(uint64_t));
- UPDATE_memcpy(DataBegin, DataSize * sizeof(__llvm_profile_data));
- UPDATE_memcpy(CountersBegin, CountersSize * sizeof(uint64_t));
- UPDATE_memcpy(NamesBegin, NamesSize * sizeof(char));
- UPDATE_memcpy(Zeroes, Padding * sizeof(char));
-#undef UPDATE_memcpy
-
- return 0;
+ return llvmWriteProfDataImpl(llvmBufferWriter, Buffer, DataBegin, DataEnd,
+ CountersBegin, CountersEnd, 0, 0, NamesBegin,
+ NamesEnd);
}
diff --git a/contrib/compiler-rt/lib/profile/InstrProfilingFile.c b/contrib/compiler-rt/lib/profile/InstrProfilingFile.c
index 68e8c7b07871..68d088a1956a 100644
--- a/contrib/compiler-rt/lib/profile/InstrProfilingFile.c
+++ b/contrib/compiler-rt/lib/profile/InstrProfilingFile.c
@@ -8,6 +8,7 @@
\*===----------------------------------------------------------------------===*/
#include "InstrProfiling.h"
+#include "InstrProfilingInternal.h"
#include "InstrProfilingUtil.h"
#include <errno.h>
#include <stdio.h>
@@ -16,47 +17,43 @@
#define UNCONST(ptr) ((void *)(uintptr_t)(ptr))
-static int writeFile(FILE *File) {
- /* Match logic in __llvm_profile_write_buffer(). */
- const __llvm_profile_data *DataBegin = __llvm_profile_begin_data();
- const __llvm_profile_data *DataEnd = __llvm_profile_end_data();
- const uint64_t *CountersBegin = __llvm_profile_begin_counters();
- const uint64_t *CountersEnd = __llvm_profile_end_counters();
- const char *NamesBegin = __llvm_profile_begin_names();
- const char *NamesEnd = __llvm_profile_end_names();
-
- /* Calculate size of sections. */
- const uint64_t DataSize = DataEnd - DataBegin;
- const uint64_t CountersSize = CountersEnd - CountersBegin;
- const uint64_t NamesSize = NamesEnd - NamesBegin;
- const uint64_t Padding = sizeof(uint64_t) - NamesSize % sizeof(uint64_t);
-
- /* Enough zeroes for padding. */
- const char Zeroes[sizeof(uint64_t)] = {0};
-
- /* Create the header. */
- uint64_t Header[PROFILE_HEADER_SIZE];
- Header[0] = __llvm_profile_get_magic();
- Header[1] = __llvm_profile_get_version();
- Header[2] = DataSize;
- Header[3] = CountersSize;
- Header[4] = NamesSize;
- Header[5] = (uintptr_t)CountersBegin;
- Header[6] = (uintptr_t)NamesBegin;
-
- /* Write the data. */
-#define CHECK_fwrite(Data, Size, Length, File) \
- do { if (fwrite(Data, Size, Length, File) != Length) return -1; } while (0)
- CHECK_fwrite(Header, sizeof(uint64_t), PROFILE_HEADER_SIZE, File);
- CHECK_fwrite(DataBegin, sizeof(__llvm_profile_data), DataSize, File);
- CHECK_fwrite(CountersBegin, sizeof(uint64_t), CountersSize, File);
- CHECK_fwrite(NamesBegin, sizeof(char), NamesSize, File);
- CHECK_fwrite(Zeroes, sizeof(char), Padding, File);
-#undef CHECK_fwrite
-
+#ifdef _MSC_VER
+#define snprintf _snprintf
+#endif
+
+/* Return 1 if there is an error, otherwise return 0. */
+static uint32_t fileWriter(ProfDataIOVec *IOVecs, uint32_t NumIOVecs,
+ void **WriterCtx) {
+ uint32_t I;
+ FILE *File = (FILE *)*WriterCtx;
+ for (I = 0; I < NumIOVecs; I++) {
+ if (fwrite(IOVecs[I].Data, IOVecs[I].ElmSize, IOVecs[I].NumElm, File) !=
+ IOVecs[I].NumElm)
+ return 1;
+ }
return 0;
}
+COMPILER_RT_VISIBILITY ProfBufferIO *
+llvmCreateBufferIOInternal(void *File, uint32_t BufferSz) {
+ CallocHook = calloc;
+ FreeHook = free;
+ return llvmCreateBufferIO(fileWriter, File, BufferSz);
+}
+
+static int writeFile(FILE *File) {
+ const char *BufferSzStr = 0;
+ uint64_t ValueDataSize = 0;
+ struct ValueProfData **ValueDataArray =
+ __llvm_profile_gather_value_data(&ValueDataSize);
+ FreeHook = &free;
+ CallocHook = &calloc;
+ BufferSzStr = getenv("LLVM_VP_BUFFER_SIZE");
+ if (BufferSzStr && BufferSzStr[0])
+ VPBufferSize = atoi(BufferSzStr);
+ return llvmWriteProfData(fileWriter, File, ValueDataArray, ValueDataSize);
+}
+
static int writeFileWithName(const char *OutputName) {
int RetVal;
FILE *OutputFile;
@@ -64,7 +61,7 @@ static int writeFileWithName(const char *OutputName) {
return -1;
/* Append to the file to support profiling multiple shared objects. */
- OutputFile = fopen(OutputName, "a");
+ OutputFile = fopen(OutputName, "ab");
if (!OutputFile)
return -1;
@@ -74,8 +71,8 @@ static int writeFileWithName(const char *OutputName) {
return RetVal;
}
-__attribute__((weak)) int __llvm_profile_OwnsFilename = 0;
-__attribute__((weak)) const char *__llvm_profile_CurrentFilename = NULL;
+COMPILER_RT_WEAK int __llvm_profile_OwnsFilename = 0;
+COMPILER_RT_WEAK const char *__llvm_profile_CurrentFilename = NULL;
static void truncateCurrentFile(void) {
const char *Filename;
@@ -182,7 +179,7 @@ static void setFilenameAutomatically(void) {
resetFilenameToDefault();
}
-__attribute__((visibility("hidden")))
+COMPILER_RT_VISIBILITY
void __llvm_profile_initialize_file(void) {
/* Check if the filename has been initialized. */
if (__llvm_profile_CurrentFilename)
@@ -192,12 +189,12 @@ void __llvm_profile_initialize_file(void) {
setFilenameAutomatically();
}
-__attribute__((visibility("hidden")))
+COMPILER_RT_VISIBILITY
void __llvm_profile_set_filename(const char *Filename) {
setFilenamePossiblyWithPid(Filename);
}
-__attribute__((visibility("hidden")))
+COMPILER_RT_VISIBILITY
void __llvm_profile_override_default_filename(const char *Filename) {
/* If the env var is set, skip setting filename from argument. */
const char *Env_Filename = getenv("LLVM_PROFILE_FILE");
@@ -206,27 +203,37 @@ void __llvm_profile_override_default_filename(const char *Filename) {
setFilenamePossiblyWithPid(Filename);
}
-__attribute__((visibility("hidden")))
+COMPILER_RT_VISIBILITY
int __llvm_profile_write_file(void) {
int rc;
+ GetEnvHook = &getenv;
/* Check the filename. */
- if (!__llvm_profile_CurrentFilename)
+ if (!__llvm_profile_CurrentFilename) {
+ PROF_ERR("LLVM Profile: Failed to write file : %s\n", "Filename not set");
+ return -1;
+ }
+
+ /* Check if there is llvm/runtime version mismatch. */
+ if (GET_VERSION(__llvm_profile_get_version()) != INSTR_PROF_RAW_VERSION) {
+ PROF_ERR("LLVM Profile: runtime and instrumentation version mismatch : "
+ "expected %d, but get %d\n",
+ INSTR_PROF_RAW_VERSION,
+ (int)GET_VERSION(__llvm_profile_get_version()));
return -1;
+ }
/* Write the file. */
rc = writeFileWithName(__llvm_profile_CurrentFilename);
- if (rc && getenv("LLVM_PROFILE_VERBOSE_ERRORS"))
- fprintf(stderr, "LLVM Profile: Failed to write file \"%s\": %s\n",
+ if (rc)
+ PROF_ERR("LLVM Profile: Failed to write file \"%s\": %s\n",
__llvm_profile_CurrentFilename, strerror(errno));
return rc;
}
-static void writeFileWithoutReturn(void) {
- __llvm_profile_write_file();
-}
+static void writeFileWithoutReturn(void) { __llvm_profile_write_file(); }
-__attribute__((visibility("hidden")))
+COMPILER_RT_VISIBILITY
int __llvm_profile_register_write_file_atexit(void) {
static int HasBeenRegistered = 0;
diff --git a/contrib/compiler-rt/lib/profile/InstrProfilingInternal.h b/contrib/compiler-rt/lib/profile/InstrProfilingInternal.h
index ede39cd9d713..4aab78ea509c 100644
--- a/contrib/compiler-rt/lib/profile/InstrProfilingInternal.h
+++ b/contrib/compiler-rt/lib/profile/InstrProfilingInternal.h
@@ -11,6 +11,7 @@
#define PROFILE_INSTRPROFILING_INTERNALH_
#include "InstrProfiling.h"
+#include "stddef.h"
/*!
* \brief Write instrumentation data to the given buffer, given explicit
@@ -37,4 +38,81 @@ int __llvm_profile_write_buffer_internal(
const __llvm_profile_data *DataEnd, const uint64_t *CountersBegin,
const uint64_t *CountersEnd, const char *NamesBegin, const char *NamesEnd);
+/*!
+ * The data structure describing the data to be written by the
+ * low level writer callback function.
+ */
+typedef struct ProfDataIOVec {
+ const void *Data;
+ size_t ElmSize;
+ size_t NumElm;
+} ProfDataIOVec;
+
+typedef uint32_t (*WriterCallback)(ProfDataIOVec *, uint32_t NumIOVecs,
+ void **WriterCtx);
+
+/*!
+ * The data structure for buffered IO of profile data.
+ */
+typedef struct ProfBufferIO {
+ /* File handle. */
+ void *File;
+ /* Low level IO callback. */
+ WriterCallback FileWriter;
+ /* The start of the buffer. */
+ uint8_t *BufferStart;
+ /* Total size of the buffer. */
+ uint32_t BufferSz;
+ /* Current byte offset from the start of the buffer. */
+ uint32_t CurOffset;
+} ProfBufferIO;
+
+/* The creator interface used by testing. */
+ProfBufferIO *llvmCreateBufferIOInternal(void *File, uint32_t DefaultBufferSz);
+/*!
+ * This is the interface to create a handle for buffered IO.
+ */
+ProfBufferIO *llvmCreateBufferIO(WriterCallback FileWriter, void *File,
+ uint32_t DefaultBufferSz);
+/*!
+ * The interface to destroy the bufferIO handle and reclaim
+ * the memory.
+ */
+void llvmDeleteBufferIO(ProfBufferIO *BufferIO);
+
+/*!
+ * This is the interface to write \c Data of \c Size bytes through
+ * \c BufferIO. Returns 0 if successful, otherwise return -1.
+ */
+int llvmBufferIOWrite(ProfBufferIO *BufferIO, const uint8_t *Data,
+ uint32_t Size);
+/*!
+ * The interface to flush the remaining data in the buffer.
+ * through the low level writer callback.
+ */
+int llvmBufferIOFlush(ProfBufferIO *BufferIO);
+
+/* The low level interface to write data into a buffer. It is used as the
+ * callback by other high level writer methods such as buffered IO writer
+ * and profile data writer. */
+uint32_t llvmBufferWriter(ProfDataIOVec *IOVecs, uint32_t NumIOVecs,
+ void **WriterCtx);
+
+int llvmWriteProfData(WriterCallback Writer, void *WriterCtx,
+ struct ValueProfData **ValueDataArray,
+ const uint64_t ValueDataSize);
+int llvmWriteProfDataImpl(WriterCallback Writer, void *WriterCtx,
+ const __llvm_profile_data *DataBegin,
+ const __llvm_profile_data *DataEnd,
+ const uint64_t *CountersBegin,
+ const uint64_t *CountersEnd,
+ struct ValueProfData **ValueDataBeginArray,
+ const uint64_t ValueDataSize, const char *NamesBegin,
+ const char *NamesEnd);
+
+extern char *(*GetEnvHook)(const char *);
+extern void (*FreeHook)(void *);
+extern void* (*CallocHook)(size_t, size_t);
+extern uint32_t VPBufferSize;
+
#endif
diff --git a/contrib/compiler-rt/lib/profile/InstrProfilingPlatformDarwin.c b/contrib/compiler-rt/lib/profile/InstrProfilingPlatformDarwin.c
index 02299cc4630c..30ddbd2e4982 100644
--- a/contrib/compiler-rt/lib/profile/InstrProfilingPlatformDarwin.c
+++ b/contrib/compiler-rt/lib/profile/InstrProfilingPlatformDarwin.c
@@ -11,33 +11,36 @@
#if defined(__APPLE__)
/* Use linker magic to find the bounds of the Data section. */
-__attribute__((visibility("hidden")))
-extern __llvm_profile_data DataStart __asm("section$start$__DATA$__llvm_prf_data");
-__attribute__((visibility("hidden")))
-extern __llvm_profile_data DataEnd __asm("section$end$__DATA$__llvm_prf_data");
-__attribute__((visibility("hidden")))
-extern char NamesStart __asm("section$start$__DATA$__llvm_prf_names");
-__attribute__((visibility("hidden")))
-extern char NamesEnd __asm("section$end$__DATA$__llvm_prf_names");
-__attribute__((visibility("hidden")))
-extern uint64_t CountersStart __asm("section$start$__DATA$__llvm_prf_cnts");
-__attribute__((visibility("hidden")))
-extern uint64_t CountersEnd __asm("section$end$__DATA$__llvm_prf_cnts");
+COMPILER_RT_VISIBILITY
+extern __llvm_profile_data
+ DataStart __asm("section$start$__DATA$" INSTR_PROF_DATA_SECT_NAME_STR);
+COMPILER_RT_VISIBILITY
+extern __llvm_profile_data
+ DataEnd __asm("section$end$__DATA$" INSTR_PROF_DATA_SECT_NAME_STR);
+COMPILER_RT_VISIBILITY
+extern char
+ NamesStart __asm("section$start$__DATA$" INSTR_PROF_NAME_SECT_NAME_STR);
+COMPILER_RT_VISIBILITY
+extern char NamesEnd __asm("section$end$__DATA$" INSTR_PROF_NAME_SECT_NAME_STR);
+COMPILER_RT_VISIBILITY
+extern uint64_t
+ CountersStart __asm("section$start$__DATA$" INSTR_PROF_CNTS_SECT_NAME_STR);
+COMPILER_RT_VISIBILITY
+extern uint64_t
+ CountersEnd __asm("section$end$__DATA$" INSTR_PROF_CNTS_SECT_NAME_STR);
-__attribute__((visibility("hidden")))
+COMPILER_RT_VISIBILITY
const __llvm_profile_data *__llvm_profile_begin_data(void) {
return &DataStart;
}
-__attribute__((visibility("hidden")))
-const __llvm_profile_data *__llvm_profile_end_data(void) {
- return &DataEnd;
-}
-__attribute__((visibility("hidden")))
+COMPILER_RT_VISIBILITY
+const __llvm_profile_data *__llvm_profile_end_data(void) { return &DataEnd; }
+COMPILER_RT_VISIBILITY
const char *__llvm_profile_begin_names(void) { return &NamesStart; }
-__attribute__((visibility("hidden")))
+COMPILER_RT_VISIBILITY
const char *__llvm_profile_end_names(void) { return &NamesEnd; }
-__attribute__((visibility("hidden")))
+COMPILER_RT_VISIBILITY
uint64_t *__llvm_profile_begin_counters(void) { return &CountersStart; }
-__attribute__((visibility("hidden")))
+COMPILER_RT_VISIBILITY
uint64_t *__llvm_profile_end_counters(void) { return &CountersEnd; }
#endif
diff --git a/contrib/compiler-rt/lib/profile/InstrProfilingPlatformLinux.c b/contrib/compiler-rt/lib/profile/InstrProfilingPlatformLinux.c
new file mode 100644
index 000000000000..7843f47caa1b
--- /dev/null
+++ b/contrib/compiler-rt/lib/profile/InstrProfilingPlatformLinux.c
@@ -0,0 +1,59 @@
+/*===- InstrProfilingPlatformLinux.c - Profile data Linux platform ------===*\
+|*
+|* The LLVM Compiler Infrastructure
+|*
+|* This file is distributed under the University of Illinois Open Source
+|* License. See LICENSE.TXT for details.
+|*
+\*===----------------------------------------------------------------------===*/
+
+#include "InstrProfiling.h"
+
+#if defined(__linux__) || defined(__FreeBSD__)
+#include <stdlib.h>
+
+#define PROF_DATA_START INSTR_PROF_SECT_START(INSTR_PROF_DATA_SECT_NAME)
+#define PROF_DATA_STOP INSTR_PROF_SECT_STOP(INSTR_PROF_DATA_SECT_NAME)
+#define PROF_NAME_START INSTR_PROF_SECT_START(INSTR_PROF_NAME_SECT_NAME)
+#define PROF_NAME_STOP INSTR_PROF_SECT_STOP(INSTR_PROF_NAME_SECT_NAME)
+#define PROF_CNTS_START INSTR_PROF_SECT_START(INSTR_PROF_CNTS_SECT_NAME)
+#define PROF_CNTS_STOP INSTR_PROF_SECT_STOP(INSTR_PROF_CNTS_SECT_NAME)
+
+/* Declare section start and stop symbols for various sections
+ * generated by compiler instrumentation.
+ */
+extern __llvm_profile_data PROF_DATA_START COMPILER_RT_VISIBILITY;
+extern __llvm_profile_data PROF_DATA_STOP COMPILER_RT_VISIBILITY;
+extern uint64_t PROF_CNTS_START COMPILER_RT_VISIBILITY;
+extern uint64_t PROF_CNTS_STOP COMPILER_RT_VISIBILITY;
+extern char PROF_NAME_START COMPILER_RT_VISIBILITY;
+extern char PROF_NAME_STOP COMPILER_RT_VISIBILITY;
+
+/* Add dummy data to ensure the section is always created. */
+__llvm_profile_data
+ __prof_data_sect_data[0] COMPILER_RT_SECTION(INSTR_PROF_DATA_SECT_NAME_STR);
+uint64_t
+ __prof_cnts_sect_data[0] COMPILER_RT_SECTION(INSTR_PROF_CNTS_SECT_NAME_STR);
+char __prof_nms_sect_data[0] COMPILER_RT_SECTION(INSTR_PROF_NAME_SECT_NAME_STR);
+
+COMPILER_RT_VISIBILITY const __llvm_profile_data *
+__llvm_profile_begin_data(void) {
+ return &PROF_DATA_START;
+}
+COMPILER_RT_VISIBILITY const __llvm_profile_data *
+__llvm_profile_end_data(void) {
+ return &PROF_DATA_STOP;
+}
+COMPILER_RT_VISIBILITY const char *__llvm_profile_begin_names(void) {
+ return &PROF_NAME_START;
+}
+COMPILER_RT_VISIBILITY const char *__llvm_profile_end_names(void) {
+ return &PROF_NAME_STOP;
+}
+COMPILER_RT_VISIBILITY uint64_t *__llvm_profile_begin_counters(void) {
+ return &PROF_CNTS_START;
+}
+COMPILER_RT_VISIBILITY uint64_t *__llvm_profile_end_counters(void) {
+ return &PROF_CNTS_STOP;
+}
+#endif
diff --git a/contrib/compiler-rt/lib/profile/InstrProfilingPlatformOther.c b/contrib/compiler-rt/lib/profile/InstrProfilingPlatformOther.c
index 548d6a396b76..58ceb3458a0a 100644
--- a/contrib/compiler-rt/lib/profile/InstrProfilingPlatformOther.c
+++ b/contrib/compiler-rt/lib/profile/InstrProfilingPlatformOther.c
@@ -9,7 +9,7 @@
#include "InstrProfiling.h"
-#if !defined(__APPLE__)
+#if !defined(__APPLE__) && !defined(__linux__) && !defined(__FreeBSD__)
#include <stdlib.h>
static const __llvm_profile_data *DataFirst = NULL;
@@ -26,49 +26,43 @@ static uint64_t *CountersLast = NULL;
* calls are only required (and only emitted) on targets where we haven't
* implemented linker magic to find the bounds of the sections.
*/
-__attribute__((visibility("hidden")))
+COMPILER_RT_VISIBILITY
void __llvm_profile_register_function(void *Data_) {
/* TODO: Only emit this function if we can't use linker magic. */
- const __llvm_profile_data *Data = (__llvm_profile_data*)Data_;
+ const __llvm_profile_data *Data = (__llvm_profile_data *)Data_;
if (!DataFirst) {
DataFirst = Data;
DataLast = Data + 1;
- NamesFirst = Data->Name;
- NamesLast = Data->Name + Data->NameSize;
- CountersFirst = Data->Counters;
- CountersLast = Data->Counters + Data->NumCounters;
+ NamesFirst = Data->NamePtr;
+ NamesLast = (const char *)Data->NamePtr + Data->NameSize;
+ CountersFirst = Data->CounterPtr;
+ CountersLast = (uint64_t *)Data->CounterPtr + Data->NumCounters;
return;
}
-#define UPDATE_FIRST(First, New) \
- First = New < First ? New : First
+#define UPDATE_FIRST(First, New) First = New < First ? New : First
UPDATE_FIRST(DataFirst, Data);
- UPDATE_FIRST(NamesFirst, Data->Name);
- UPDATE_FIRST(CountersFirst, Data->Counters);
+ UPDATE_FIRST(NamesFirst, (const char *)Data->NamePtr);
+ UPDATE_FIRST(CountersFirst, (uint64_t *)Data->CounterPtr);
#undef UPDATE_FIRST
-#define UPDATE_LAST(Last, New) \
- Last = New > Last ? New : Last
+#define UPDATE_LAST(Last, New) Last = New > Last ? New : Last
UPDATE_LAST(DataLast, Data + 1);
- UPDATE_LAST(NamesLast, Data->Name + Data->NameSize);
- UPDATE_LAST(CountersLast, Data->Counters + Data->NumCounters);
+ UPDATE_LAST(NamesLast, (const char *)Data->NamePtr + Data->NameSize);
+ UPDATE_LAST(CountersLast, (uint64_t *)Data->CounterPtr + Data->NumCounters);
#undef UPDATE_LAST
}
-__attribute__((visibility("hidden")))
-const __llvm_profile_data *__llvm_profile_begin_data(void) {
- return DataFirst;
-}
-__attribute__((visibility("hidden")))
-const __llvm_profile_data *__llvm_profile_end_data(void) {
- return DataLast;
-}
-__attribute__((visibility("hidden")))
+COMPILER_RT_VISIBILITY
+const __llvm_profile_data *__llvm_profile_begin_data(void) { return DataFirst; }
+COMPILER_RT_VISIBILITY
+const __llvm_profile_data *__llvm_profile_end_data(void) { return DataLast; }
+COMPILER_RT_VISIBILITY
const char *__llvm_profile_begin_names(void) { return NamesFirst; }
-__attribute__((visibility("hidden")))
+COMPILER_RT_VISIBILITY
const char *__llvm_profile_end_names(void) { return NamesLast; }
-__attribute__((visibility("hidden")))
+COMPILER_RT_VISIBILITY
uint64_t *__llvm_profile_begin_counters(void) { return CountersFirst; }
-__attribute__((visibility("hidden")))
+COMPILER_RT_VISIBILITY
uint64_t *__llvm_profile_end_counters(void) { return CountersLast; }
#endif
diff --git a/contrib/compiler-rt/lib/profile/InstrProfilingPort.h b/contrib/compiler-rt/lib/profile/InstrProfilingPort.h
new file mode 100644
index 000000000000..e07f59878730
--- /dev/null
+++ b/contrib/compiler-rt/lib/profile/InstrProfilingPort.h
@@ -0,0 +1,62 @@
+/*===- InstrProfilingPort.h- Support library for PGO instrumentation ------===*\
+|*
+|* The LLVM Compiler Infrastructure
+|*
+|* This file is distributed under the University of Illinois Open Source
+|* License. See LICENSE.TXT for details.
+|*
+\*===----------------------------------------------------------------------===*/
+
+#ifndef PROFILE_INSTRPROFILING_PORT_H_
+#define PROFILE_INSTRPROFILING_PORT_H_
+
+#ifdef _MSC_VER
+#define COMPILER_RT_ALIGNAS(x) __declspec(align(x))
+#define COMPILER_RT_VISIBILITY
+#define COMPILER_RT_WEAK __declspec(selectany)
+#elif __GNUC__
+#define COMPILER_RT_ALIGNAS(x) __attribute__((aligned(x)))
+#define COMPILER_RT_VISIBILITY __attribute__((visibility("hidden")))
+#define COMPILER_RT_WEAK __attribute__((weak))
+#endif
+
+#define COMPILER_RT_SECTION(Sect) __attribute__((section(Sect)))
+
+#if COMPILER_RT_HAS_ATOMICS == 1
+#ifdef _MSC_VER
+#include <windows.h>
+#if defined(_WIN64)
+#define COMPILER_RT_BOOL_CMPXCHG(Ptr, OldV, NewV) \
+ (InterlockedCompareExchange64((LONGLONG volatile *)Ptr, (LONGLONG)NewV, \
+ (LONGLONG)OldV) == (LONGLONG)OldV)
+#else /* !defined(_WIN64) */
+#define COMPILER_RT_BOOL_CMPXCHG(Ptr, OldV, NewV) \
+ (InterlockedCompareExchange((LONG volatile *)Ptr, (LONG)NewV, (LONG)OldV) == \
+ (LONG)OldV)
+#endif
+#else /* !defined(_MSC_VER) */
+#define COMPILER_RT_BOOL_CMPXCHG(Ptr, OldV, NewV) \
+ __sync_bool_compare_and_swap(Ptr, OldV, NewV)
+#endif
+#else /* COMPILER_RT_HAS_ATOMICS != 1 */
+#define COMPILER_RT_BOOL_CMPXCHG(Ptr, OldV, NewV) \
+ BoolCmpXchg((void **)Ptr, OldV, NewV)
+#endif
+
+#define PROF_ERR(Format, ...) \
+ if (GetEnvHook && GetEnvHook("LLVM_PROFILE_VERBOSE_ERRORS")) \
+ fprintf(stderr, Format, __VA_ARGS__);
+
+#if defined(__FreeBSD__)
+
+#include <inttypes.h>
+#include <sys/types.h>
+
+#else /* defined(__FreeBSD__) */
+
+#include <inttypes.h>
+#include <stdint.h>
+
+#endif /* defined(__FreeBSD__) && defined(__i386__) */
+
+#endif /* PROFILE_INSTRPROFILING_PORT_H_ */
diff --git a/contrib/compiler-rt/lib/profile/InstrProfilingRuntime.cc b/contrib/compiler-rt/lib/profile/InstrProfilingRuntime.cc
index 081ecb29e987..12ad9f1573f4 100644
--- a/contrib/compiler-rt/lib/profile/InstrProfilingRuntime.cc
+++ b/contrib/compiler-rt/lib/profile/InstrProfilingRuntime.cc
@@ -11,8 +11,7 @@ extern "C" {
#include "InstrProfiling.h"
-__attribute__((visibility("hidden"))) int __llvm_profile_runtime;
-
+COMPILER_RT_VISIBILITY int __llvm_profile_runtime;
}
namespace {
diff --git a/contrib/compiler-rt/lib/profile/InstrProfilingUtil.c b/contrib/compiler-rt/lib/profile/InstrProfilingUtil.c
index e146dfca83c8..6f0443d3bb5d 100644
--- a/contrib/compiler-rt/lib/profile/InstrProfilingUtil.c
+++ b/contrib/compiler-rt/lib/profile/InstrProfilingUtil.c
@@ -8,6 +8,7 @@
\*===----------------------------------------------------------------------===*/
#include "InstrProfilingUtil.h"
+#include "InstrProfiling.h"
#ifdef _WIN32
#include <direct.h>
@@ -18,7 +19,7 @@ int mkdir(const char*, unsigned short);
#include <sys/types.h>
#endif
-__attribute__((visibility("hidden")))
+COMPILER_RT_VISIBILITY
void __llvm_profile_recursive_mkdir(char *path) {
int i;
diff --git a/contrib/compiler-rt/lib/profile/InstrProfilingValue.c b/contrib/compiler-rt/lib/profile/InstrProfilingValue.c
new file mode 100644
index 000000000000..68e16cff9cbc
--- /dev/null
+++ b/contrib/compiler-rt/lib/profile/InstrProfilingValue.c
@@ -0,0 +1,180 @@
+/*===- InstrProfilingValue.c - Support library for PGO instrumentation ----===*\
+|*
+|* The LLVM Compiler Infrastructure
+|*
+|* This file is distributed under the University of Illinois Open Source
+|* License. See LICENSE.TXT for details.
+|*
+\*===----------------------------------------------------------------------===*/
+
+#include "InstrProfiling.h"
+#include "InstrProfilingInternal.h"
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#define INSTR_PROF_VALUE_PROF_DATA
+#define INSTR_PROF_COMMON_API_IMPL
+#include "InstrProfData.inc"
+
+#define PROF_OOM(Msg) PROF_ERR(Msg ":%s\n", "Out of memory");
+#define PROF_OOM_RETURN(Msg) \
+ { \
+ PROF_OOM(Msg) \
+ free(ValueDataArray); \
+ return NULL; \
+ }
+
+#if COMPILER_RT_HAS_ATOMICS != 1
+COMPILER_RT_VISIBILITY
+uint32_t BoolCmpXchg(void **Ptr, void *OldV, void *NewV) {
+ void *R = *Ptr;
+ if (R == OldV) {
+ *Ptr = NewV;
+ return 1;
+ }
+ return 0;
+}
+#endif
+
+/* This method is only used in value profiler mock testing. */
+COMPILER_RT_VISIBILITY void
+__llvm_profile_set_num_value_sites(__llvm_profile_data *Data,
+ uint32_t ValueKind, uint16_t NumValueSites) {
+ *((uint16_t *)&Data->NumValueSites[ValueKind]) = NumValueSites;
+}
+
+/* This method is only used in value profiler mock testing. */
+COMPILER_RT_VISIBILITY const __llvm_profile_data *
+__llvm_profile_iterate_data(const __llvm_profile_data *Data) {
+ return Data + 1;
+}
+
+/* This method is only used in value profiler mock testing. */
+COMPILER_RT_VISIBILITY void *
+__llvm_get_function_addr(const __llvm_profile_data *Data) {
+ return Data->FunctionPointer;
+}
+
+/* Allocate an array that holds the pointers to the linked lists of
+ * value profile counter nodes. The number of element of the array
+ * is the total number of value profile sites instrumented. Returns
+ * 0 if allocation fails.
+ */
+
+static int allocateValueProfileCounters(__llvm_profile_data *Data) {
+ uint64_t NumVSites = 0;
+ uint32_t VKI;
+ for (VKI = IPVK_First; VKI <= IPVK_Last; ++VKI)
+ NumVSites += Data->NumValueSites[VKI];
+
+ ValueProfNode **Mem =
+ (ValueProfNode **)calloc(NumVSites, sizeof(ValueProfNode *));
+ if (!Mem)
+ return 0;
+ if (!COMPILER_RT_BOOL_CMPXCHG(&Data->Values, 0, Mem)) {
+ free(Mem);
+ return 0;
+ }
+ return 1;
+}
+
+COMPILER_RT_VISIBILITY void
+__llvm_profile_instrument_target(uint64_t TargetValue, void *Data,
+ uint32_t CounterIndex) {
+
+ __llvm_profile_data *PData = (__llvm_profile_data *)Data;
+ if (!PData)
+ return;
+
+ if (!PData->Values) {
+ if (!allocateValueProfileCounters(PData))
+ return;
+ }
+
+ ValueProfNode **ValueCounters = (ValueProfNode **)PData->Values;
+ ValueProfNode *PrevVNode = NULL;
+ ValueProfNode *CurrentVNode = ValueCounters[CounterIndex];
+
+ uint8_t VDataCount = 0;
+ while (CurrentVNode) {
+ if (TargetValue == CurrentVNode->VData.Value) {
+ CurrentVNode->VData.Count++;
+ return;
+ }
+ PrevVNode = CurrentVNode;
+ CurrentVNode = CurrentVNode->Next;
+ ++VDataCount;
+ }
+
+ if (VDataCount >= INSTR_PROF_MAX_NUM_VAL_PER_SITE)
+ return;
+
+ CurrentVNode = (ValueProfNode *)calloc(1, sizeof(ValueProfNode));
+ if (!CurrentVNode)
+ return;
+
+ CurrentVNode->VData.Value = TargetValue;
+ CurrentVNode->VData.Count++;
+
+ uint32_t Success = 0;
+ if (!ValueCounters[CounterIndex])
+ Success =
+ COMPILER_RT_BOOL_CMPXCHG(&ValueCounters[CounterIndex], 0, CurrentVNode);
+ else if (PrevVNode && !PrevVNode->Next)
+ Success = COMPILER_RT_BOOL_CMPXCHG(&(PrevVNode->Next), 0, CurrentVNode);
+
+ if (!Success) {
+ free(CurrentVNode);
+ return;
+ }
+}
+
+COMPILER_RT_VISIBILITY ValueProfData **
+__llvm_profile_gather_value_data(uint64_t *ValueDataSize) {
+ size_t S = 0;
+ __llvm_profile_data *I;
+ ValueProfData **ValueDataArray;
+
+ const __llvm_profile_data *DataEnd = __llvm_profile_end_data();
+ const __llvm_profile_data *DataBegin = __llvm_profile_begin_data();
+
+ if (!ValueDataSize)
+ return NULL;
+
+ ValueDataArray =
+ (ValueProfData **)calloc(DataEnd - DataBegin, sizeof(void *));
+ if (!ValueDataArray)
+ PROF_OOM_RETURN("Failed to write value profile data ");
+
+ /*
+ * Compute the total Size of the buffer to hold ValueProfData
+ * structures for functions with value profile data.
+ */
+ for (I = (__llvm_profile_data *)DataBegin; I != DataEnd; ++I) {
+ ValueProfRuntimeRecord R;
+ if (initializeValueProfRuntimeRecord(&R, I->NumValueSites, I->Values))
+ PROF_OOM_RETURN("Failed to write value profile data ");
+
+ /* Compute the size of ValueProfData from this runtime record. */
+ if (getNumValueKindsRT(&R) != 0) {
+ ValueProfData *VD = NULL;
+ uint32_t VS = getValueProfDataSizeRT(&R);
+ VD = (ValueProfData *)calloc(VS, sizeof(uint8_t));
+ if (!VD)
+ PROF_OOM_RETURN("Failed to write value profile data ");
+ serializeValueProfDataFromRT(&R, VD);
+ ValueDataArray[I - DataBegin] = VD;
+ S += VS;
+ }
+ finalizeValueProfRuntimeRecord(&R);
+ }
+
+ if (!S) {
+ free(ValueDataArray);
+ ValueDataArray = NULL;
+ }
+
+ *ValueDataSize = S;
+ return ValueDataArray;
+}
diff --git a/contrib/compiler-rt/lib/profile/InstrProfilingWriter.c b/contrib/compiler-rt/lib/profile/InstrProfilingWriter.c
new file mode 100644
index 000000000000..a07bc538ed4b
--- /dev/null
+++ b/contrib/compiler-rt/lib/profile/InstrProfilingWriter.c
@@ -0,0 +1,175 @@
+/*===- InstrProfilingWriter.c - Write instrumentation to a file or buffer -===*\
+|*
+|* The LLVM Compiler Infrastructure
+|*
+|* This file is distributed under the University of Illinois Open Source
+|* License. See LICENSE.TXT for details.
+|*
+\*===----------------------------------------------------------------------===*/
+
+#include "InstrProfiling.h"
+#include "InstrProfilingInternal.h"
+#include <string.h>
+
+#define INSTR_PROF_VALUE_PROF_DATA
+#include "InstrProfData.inc"
+void (*FreeHook)(void *) = NULL;
+void* (*CallocHook)(size_t, size_t) = NULL;
+uint32_t VPBufferSize = 0;
+
+/* The buffer writer is reponsponsible in keeping writer state
+ * across the call.
+ */
+COMPILER_RT_VISIBILITY uint32_t llvmBufferWriter(ProfDataIOVec *IOVecs,
+ uint32_t NumIOVecs,
+ void **WriterCtx) {
+ uint32_t I;
+ char **Buffer = (char **)WriterCtx;
+ for (I = 0; I < NumIOVecs; I++) {
+ size_t Length = IOVecs[I].ElmSize * IOVecs[I].NumElm;
+ memcpy(*Buffer, IOVecs[I].Data, Length);
+ *Buffer += Length;
+ }
+ return 0;
+}
+
+static void llvmInitBufferIO(ProfBufferIO *BufferIO, WriterCallback FileWriter,
+ void *File, uint8_t *Buffer, uint32_t BufferSz) {
+ BufferIO->File = File;
+ BufferIO->FileWriter = FileWriter;
+ BufferIO->BufferStart = Buffer;
+ BufferIO->BufferSz = BufferSz;
+ BufferIO->CurOffset = 0;
+}
+
+COMPILER_RT_VISIBILITY ProfBufferIO *
+llvmCreateBufferIO(WriterCallback FileWriter, void *File, uint32_t BufferSz) {
+ ProfBufferIO *BufferIO = (ProfBufferIO *)CallocHook(1, sizeof(ProfBufferIO));
+ uint8_t *Buffer = (uint8_t *)CallocHook(1, BufferSz);
+ if (!Buffer) {
+ FreeHook(BufferIO);
+ return 0;
+ }
+ llvmInitBufferIO(BufferIO, FileWriter, File, Buffer, BufferSz);
+ return BufferIO;
+}
+
+COMPILER_RT_VISIBILITY void llvmDeleteBufferIO(ProfBufferIO *BufferIO) {
+ FreeHook(BufferIO->BufferStart);
+ FreeHook(BufferIO);
+}
+
+COMPILER_RT_VISIBILITY int
+llvmBufferIOWrite(ProfBufferIO *BufferIO, const uint8_t *Data, uint32_t Size) {
+ /* Buffer is not large enough, it is time to flush. */
+ if (Size + BufferIO->CurOffset > BufferIO->BufferSz) {
+ if (llvmBufferIOFlush(BufferIO) != 0)
+ return -1;
+ }
+ /* Special case, bypass the buffer completely. */
+ ProfDataIOVec IO[] = {{Data, sizeof(uint8_t), Size}};
+ if (Size > BufferIO->BufferSz) {
+ if (BufferIO->FileWriter(IO, 1, &BufferIO->File))
+ return -1;
+ } else {
+ /* Write the data to buffer */
+ uint8_t *Buffer = BufferIO->BufferStart + BufferIO->CurOffset;
+ llvmBufferWriter(IO, 1, (void **)&Buffer);
+ BufferIO->CurOffset = Buffer - BufferIO->BufferStart;
+ }
+ return 0;
+}
+
+COMPILER_RT_VISIBILITY int llvmBufferIOFlush(ProfBufferIO *BufferIO) {
+ if (BufferIO->CurOffset) {
+ ProfDataIOVec IO[] = {
+ {BufferIO->BufferStart, sizeof(uint8_t), BufferIO->CurOffset}};
+ if (BufferIO->FileWriter(IO, 1, &BufferIO->File))
+ return -1;
+ BufferIO->CurOffset = 0;
+ }
+ return 0;
+}
+
+COMPILER_RT_VISIBILITY int llvmWriteProfData(WriterCallback Writer,
+ void *WriterCtx,
+ ValueProfData **ValueDataArray,
+ const uint64_t ValueDataSize) {
+ /* Match logic in __llvm_profile_write_buffer(). */
+ const __llvm_profile_data *DataBegin = __llvm_profile_begin_data();
+ const __llvm_profile_data *DataEnd = __llvm_profile_end_data();
+ const uint64_t *CountersBegin = __llvm_profile_begin_counters();
+ const uint64_t *CountersEnd = __llvm_profile_end_counters();
+ const char *NamesBegin = __llvm_profile_begin_names();
+ const char *NamesEnd = __llvm_profile_end_names();
+ return llvmWriteProfDataImpl(Writer, WriterCtx, DataBegin, DataEnd,
+ CountersBegin, CountersEnd, ValueDataArray,
+ ValueDataSize, NamesBegin, NamesEnd);
+}
+
+#define VP_BUFFER_SIZE 8 * 1024
+static int writeValueProfData(WriterCallback Writer, void *WriterCtx,
+ ValueProfData **ValueDataBegin,
+ uint64_t NumVData) {
+ ProfBufferIO *BufferIO;
+ uint32_t I = 0, BufferSz;
+
+ if (!ValueDataBegin)
+ return 0;
+
+ BufferSz = VPBufferSize ? VPBufferSize : VP_BUFFER_SIZE;
+ BufferIO = llvmCreateBufferIO(Writer, WriterCtx, BufferSz);
+
+ for (I = 0; I < NumVData; I++) {
+ ValueProfData *CurVData = ValueDataBegin[I];
+ if (!CurVData)
+ continue;
+ if (llvmBufferIOWrite(BufferIO, (const uint8_t *)CurVData,
+ CurVData->TotalSize) != 0)
+ return -1;
+ }
+
+ if (llvmBufferIOFlush(BufferIO) != 0)
+ return -1;
+ llvmDeleteBufferIO(BufferIO);
+
+ return 0;
+}
+
+COMPILER_RT_VISIBILITY int llvmWriteProfDataImpl(
+ WriterCallback Writer, void *WriterCtx,
+ const __llvm_profile_data *DataBegin, const __llvm_profile_data *DataEnd,
+ const uint64_t *CountersBegin, const uint64_t *CountersEnd,
+ ValueProfData **ValueDataBegin, const uint64_t ValueDataSize,
+ const char *NamesBegin, const char *NamesEnd) {
+
+ /* Calculate size of sections. */
+ const uint64_t DataSize = DataEnd - DataBegin;
+ const uint64_t CountersSize = CountersEnd - CountersBegin;
+ const uint64_t NamesSize = NamesEnd - NamesBegin;
+ const uint64_t Padding = __llvm_profile_get_num_padding_bytes(NamesSize);
+
+ /* Enough zeroes for padding. */
+ const char Zeroes[sizeof(uint64_t)] = {0};
+
+ /* Create the header. */
+ __llvm_profile_header Header;
+
+ if (!DataSize)
+ return 0;
+
+ /* Initialize header struture. */
+#define INSTR_PROF_RAW_HEADER(Type, Name, Init) Header.Name = Init;
+#include "InstrProfData.inc"
+
+ /* Write the data. */
+ ProfDataIOVec IOVec[] = {{&Header, sizeof(__llvm_profile_header), 1},
+ {DataBegin, sizeof(__llvm_profile_data), DataSize},
+ {CountersBegin, sizeof(uint64_t), CountersSize},
+ {NamesBegin, sizeof(uint8_t), NamesSize},
+ {Zeroes, sizeof(uint8_t), Padding}};
+ if (Writer(IOVec, sizeof(IOVec) / sizeof(*IOVec), &WriterCtx))
+ return -1;
+
+ return writeValueProfData(Writer, WriterCtx, ValueDataBegin, DataSize);
+}
diff --git a/contrib/compiler-rt/lib/profile/WindowsMMap.c b/contrib/compiler-rt/lib/profile/WindowsMMap.c
new file mode 100644
index 000000000000..1f7342050032
--- /dev/null
+++ b/contrib/compiler-rt/lib/profile/WindowsMMap.c
@@ -0,0 +1,128 @@
+/*
+ * This code is derived from uClibc (original license follows).
+ * https://git.uclibc.org/uClibc/tree/utils/mmap-windows.c
+ */
+ /* mmap() replacement for Windows
+ *
+ * Author: Mike Frysinger <vapier@gentoo.org>
+ * Placed into the public domain
+ */
+
+/* References:
+ * CreateFileMapping: http://msdn.microsoft.com/en-us/library/aa366537(VS.85).aspx
+ * CloseHandle: http://msdn.microsoft.com/en-us/library/ms724211(VS.85).aspx
+ * MapViewOfFile: http://msdn.microsoft.com/en-us/library/aa366761(VS.85).aspx
+ * UnmapViewOfFile: http://msdn.microsoft.com/en-us/library/aa366882(VS.85).aspx
+ */
+
+#if defined(_WIN32)
+
+#include "WindowsMMap.h"
+#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)
+{
+ if (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC))
+ return MAP_FAILED;
+ if (fd == -1) {
+ if (!(flags & MAP_ANON) || offset)
+ return MAP_FAILED;
+ } else if (flags & MAP_ANON)
+ return MAP_FAILED;
+
+ DWORD flProtect;
+ if (prot & PROT_WRITE) {
+ if (prot & PROT_EXEC)
+ flProtect = PAGE_EXECUTE_READWRITE;
+ else
+ flProtect = PAGE_READWRITE;
+ } else if (prot & PROT_EXEC) {
+ if (prot & PROT_READ)
+ flProtect = PAGE_EXECUTE_READ;
+ else if (prot & PROT_EXEC)
+ flProtect = PAGE_EXECUTE;
+ } else
+ flProtect = PAGE_READONLY;
+
+ off_t end = length + offset;
+ HANDLE mmap_fd, h;
+ if (fd == -1)
+ mmap_fd = INVALID_HANDLE_VALUE;
+ else
+ mmap_fd = (HANDLE)_get_osfhandle(fd);
+ h = CreateFileMapping(mmap_fd, NULL, flProtect, DWORD_HI(end), DWORD_LO(end), NULL);
+ if (h == NULL)
+ return MAP_FAILED;
+
+ DWORD dwDesiredAccess;
+ if (prot & PROT_WRITE)
+ dwDesiredAccess = FILE_MAP_WRITE;
+ else
+ dwDesiredAccess = FILE_MAP_READ;
+ if (prot & PROT_EXEC)
+ dwDesiredAccess |= FILE_MAP_EXECUTE;
+ if (flags & MAP_PRIVATE)
+ dwDesiredAccess |= FILE_MAP_COPY;
+ void *ret = MapViewOfFile(h, dwDesiredAccess, DWORD_HI(offset), DWORD_LO(offset), length);
+ if (ret == NULL) {
+ CloseHandle(h);
+ ret = MAP_FAILED;
+ }
+ return ret;
+}
+
+COMPILER_RT_VISIBILITY
+void munmap(void *addr, size_t length)
+{
+ UnmapViewOfFile(addr);
+ /* ruh-ro, we leaked handle from CreateFileMapping() ... */
+}
+
+COMPILER_RT_VISIBILITY
+int msync(void *addr, size_t length, int flags)
+{
+ if (flags & MS_INVALIDATE)
+ return -1; /* Not supported. */
+
+ /* Exactly one of MS_ASYNC or MS_SYNC must be specified. */
+ switch (flags & (MS_ASYNC | MS_SYNC)) {
+ case MS_SYNC:
+ case MS_ASYNC:
+ break;
+ default:
+ return -1;
+ }
+
+ if (!FlushViewOfFile(addr, length))
+ return -1;
+
+ if (flags & MS_SYNC) {
+ /* FIXME: No longer have access to handle from CreateFileMapping(). */
+ /*
+ * if (!FlushFileBuffers(h))
+ * return -1;
+ */
+ }
+
+ return 0;
+}
+
+COMPILER_RT_VISIBILITY
+int flock(int fd, int operation)
+{
+ return -1; /* Not supported. */
+}
+
+#undef DWORD_HI
+#undef DWORD_LO
+
+#endif /* _WIN32 */
diff --git a/contrib/compiler-rt/lib/profile/WindowsMMap.h b/contrib/compiler-rt/lib/profile/WindowsMMap.h
new file mode 100644
index 000000000000..7b94eb28230c
--- /dev/null
+++ b/contrib/compiler-rt/lib/profile/WindowsMMap.h
@@ -0,0 +1,65 @@
+/*===- WindowsMMap.h - Support library for PGO instrumentation ------------===*\
+|*
+|* The LLVM Compiler Infrastructure
+|*
+|* This file is distributed under the University of Illinois Open Source
+|* License. See LICENSE.TXT for details.
+|*
+\*===----------------------------------------------------------------------===*/
+
+#ifndef PROFILE_INSTRPROFILING_WINDOWS_MMAP_H
+#define PROFILE_INSTRPROFILING_WINDOWS_MMAP_H
+
+#if defined(_WIN32)
+
+#include <BaseTsd.h>
+#include <io.h>
+#include <sys/types.h>
+
+/*
+ * mmap() flags
+ */
+#define PROT_READ 0x1
+#define PROT_WRITE 0x2
+/* This flag is only available in WinXP+ */
+#ifdef FILE_MAP_EXECUTE
+#define PROT_EXEC 0x4
+#else
+#define PROT_EXEC 0x0
+#define FILE_MAP_EXECUTE 0
+#endif
+
+#define MAP_FILE 0x00
+#define MAP_SHARED 0x01
+#define MAP_PRIVATE 0x02
+#define MAP_ANONYMOUS 0x20
+#define MAP_ANON MAP_ANONYMOUS
+#define MAP_FAILED ((void *) -1)
+
+/*
+ * msync() flags
+ */
+#define MS_ASYNC 0x0001 /* return immediately */
+#define MS_INVALIDATE 0x0002 /* invalidate all cached data */
+#define MS_SYNC 0x0010 /* msync synchronously */
+
+/*
+ * flock() operations
+ */
+#define LOCK_SH 1 /* shared lock */
+#define LOCK_EX 2 /* exclusive lock */
+#define LOCK_NB 4 /* don't block when locking */
+#define LOCK_UN 8 /* unlock */
+
+void *mmap(void *start, size_t length, int prot, int flags, int fd,
+ off_t offset);
+
+void munmap(void *addr, size_t length);
+
+int msync(void *addr, size_t length, int flags);
+
+int flock(int fd, int operation);
+
+#endif /* _WIN32 */
+
+#endif /* PROFILE_INSTRPROFILING_WINDOWS_MMAP_H */
diff --git a/contrib/compiler-rt/lib/safestack/CMakeLists.txt b/contrib/compiler-rt/lib/safestack/CMakeLists.txt
deleted file mode 100644
index 1c15d079dbb5..000000000000
--- a/contrib/compiler-rt/lib/safestack/CMakeLists.txt
+++ /dev/null
@@ -1,28 +0,0 @@
-add_custom_target(safestack)
-
-set(SAFESTACK_SOURCES safestack.cc)
-
-include_directories(..)
-
-set(SAFESTACK_CFLAGS ${SANITIZER_COMMON_CFLAGS})
-
-if(APPLE)
- # Build universal binary on APPLE.
- add_compiler_rt_osx_static_runtime(clang_rt.safestack_osx
- ARCH ${SAFESTACK_SUPPORTED_ARCH}
- SOURCES ${SAFESTACK_SOURCES}
- $<TARGET_OBJECTS:RTInterception.osx>
- $<TARGET_OBJECTS:RTSanitizerCommon.osx>
- CFLAGS ${SAFESTACK_CFLAGS})
- add_dependencies(safestack clang_rt.safestack_osx)
-else()
- # Otherwise, build separate libraries for each target.
- foreach(arch ${SAFESTACK_SUPPORTED_ARCH})
- add_compiler_rt_runtime(clang_rt.safestack-${arch} ${arch} STATIC
- SOURCES ${SAFESTACK_SOURCES}
- $<TARGET_OBJECTS:RTInterception.${arch}>
- $<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
- CFLAGS ${SAFESTACK_CFLAGS})
- add_dependencies(safestack clang_rt.safestack-${arch})
- endforeach()
-endif()
diff --git a/contrib/compiler-rt/lib/safestack/safestack.cc b/contrib/compiler-rt/lib/safestack/safestack.cc
index 504bd3cd0d99..92c24b35d6d0 100644
--- a/contrib/compiler-rt/lib/safestack/safestack.cc
+++ b/contrib/compiler-rt/lib/safestack/safestack.cc
@@ -18,6 +18,7 @@
#include <pthread.h>
#include <stddef.h>
#include <stdint.h>
+#include <unistd.h>
#include <sys/resource.h>
#include <sys/types.h>
#include <sys/user.h>
@@ -68,6 +69,9 @@ const unsigned kStackAlign = 16;
/// size rlimit is set to infinity.
const unsigned kDefaultUnsafeStackSize = 0x2800000;
+/// Runtime page size obtained through sysconf
+static unsigned pageSize;
+
// TODO: To make accessing the unsafe stack pointer faster, we plan to
// eventually store it directly in the thread control block data structure on
// platforms where this structure is pointed to by %fs or %gs. This is exactly
@@ -171,7 +175,7 @@ INTERCEPTOR(int, pthread_create, pthread_t *thread,
size_t size = 0;
size_t guard = 0;
- if (attr != NULL) {
+ if (attr) {
pthread_attr_getstacksize(attr, &size);
pthread_attr_getguardsize(attr, &guard);
} else {
@@ -185,7 +189,7 @@ INTERCEPTOR(int, pthread_create, pthread_t *thread,
CHECK_NE(size, 0);
CHECK_EQ((size & (kStackAlign - 1)), 0);
- CHECK_EQ((guard & (PAGE_SIZE - 1)), 0);
+ CHECK_EQ((guard & (pageSize - 1)), 0);
void *addr = unsafe_stack_alloc(size, guard);
struct tinfo *tinfo =
@@ -217,6 +221,7 @@ void __safestack_init() {
void *addr = unsafe_stack_alloc(size, guard);
unsafe_stack_setup(addr, size, guard);
+ pageSize = sysconf(_SC_PAGESIZE);
// Initialize pthread interceptors for thread allocation
INTERCEPT_FUNCTION(pthread_create);
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_addrhashmap.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_addrhashmap.h
index acf4ff020939..e55fc4f95a9a 100644
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_addrhashmap.h
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_addrhashmap.h
@@ -143,7 +143,7 @@ bool AddrHashMap<T, kSize>::Handle::created() const {
template<typename T, uptr kSize>
bool AddrHashMap<T, kSize>::Handle::exists() const {
- return cell_ != 0;
+ return cell_ != nullptr;
}
template<typename T, uptr kSize>
@@ -160,7 +160,7 @@ void AddrHashMap<T, kSize>::acquire(Handle *h) {
h->created_ = false;
h->addidx_ = -1U;
h->bucket_ = b;
- h->cell_ = 0;
+ h->cell_ = nullptr;
// If we want to remove the element, we need exclusive access to the bucket,
// so skip the lock-free phase.
@@ -250,7 +250,7 @@ void AddrHashMap<T, kSize>::acquire(Handle *h) {
}
// Store in the add cells.
- if (add == 0) {
+ if (!add) {
// Allocate a new add array.
const uptr kInitSize = 64;
add = (AddBucket*)InternalAlloc(kInitSize);
@@ -282,7 +282,7 @@ void AddrHashMap<T, kSize>::acquire(Handle *h) {
template<typename T, uptr kSize>
void AddrHashMap<T, kSize>::release(Handle *h) {
- if (h->cell_ == 0)
+ if (!h->cell_)
return;
Bucket *b = h->bucket_;
Cell *c = h->cell_;
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_allocator.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_allocator.cc
index 03b3e83153de..538e2db95d4e 100644
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_allocator.cc
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_allocator.cc
@@ -11,6 +11,7 @@
// run-time libraries.
// This allocator is used inside run-times.
//===----------------------------------------------------------------------===//
+
#include "sanitizer_allocator.h"
#include "sanitizer_allocator_internal.h"
#include "sanitizer_common.h"
@@ -44,7 +45,7 @@ InternalAllocator *internal_allocator() {
return 0;
}
-#else // SANITIZER_GO
+#else // SANITIZER_GO
static ALIGNED(64) char internal_alloc_placeholder[sizeof(InternalAllocator)];
static atomic_uint8_t internal_allocator_initialized;
@@ -77,29 +78,29 @@ static void *RawInternalAlloc(uptr size, InternalAllocatorCache *cache) {
}
static void RawInternalFree(void *ptr, InternalAllocatorCache *cache) {
- if (cache == 0) {
+ if (!cache) {
SpinMutexLock l(&internal_allocator_cache_mu);
return internal_allocator()->Deallocate(&internal_allocator_cache, ptr);
}
internal_allocator()->Deallocate(cache, ptr);
}
-#endif // SANITIZER_GO
+#endif // SANITIZER_GO
const u64 kBlockMagic = 0x6A6CB03ABCEBC041ull;
void *InternalAlloc(uptr size, InternalAllocatorCache *cache) {
if (size + sizeof(u64) < size)
- return 0;
+ return nullptr;
void *p = RawInternalAlloc(size + sizeof(u64), cache);
- if (p == 0)
- return 0;
+ if (!p)
+ return nullptr;
((u64*)p)[0] = kBlockMagic;
return (char*)p + sizeof(u64);
}
void InternalFree(void *addr, InternalAllocatorCache *cache) {
- if (addr == 0)
+ if (!addr)
return;
addr = (char*)addr - sizeof(u64);
CHECK_EQ(kBlockMagic, ((u64*)addr)[0]);
@@ -147,4 +148,4 @@ void NORETURN ReportAllocatorCannotReturnNull() {
Die();
}
-} // namespace __sanitizer
+} // namespace __sanitizer
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_allocator.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_allocator.h
index deaffef7150d..44d6fce3b291 100644
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_allocator.h
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_allocator.h
@@ -347,7 +347,7 @@ class SizeClassAllocator64 {
CHECK_LT(class_id, kNumClasses);
RegionInfo *region = GetRegionInfo(class_id);
Batch *b = region->free_list.Pop();
- if (b == 0)
+ if (!b)
b = PopulateFreeList(stat, c, class_id, region);
region->n_allocated += b->count;
return b;
@@ -371,16 +371,16 @@ class SizeClassAllocator64 {
void *GetBlockBegin(const void *p) {
uptr class_id = GetSizeClass(p);
uptr size = SizeClassMap::Size(class_id);
- if (!size) return 0;
+ if (!size) return nullptr;
uptr chunk_idx = GetChunkIdx((uptr)p, size);
uptr reg_beg = (uptr)p & ~(kRegionSize - 1);
uptr beg = chunk_idx * size;
uptr next_beg = beg + size;
- if (class_id >= kNumClasses) return 0;
+ if (class_id >= kNumClasses) return nullptr;
RegionInfo *region = GetRegionInfo(class_id);
if (region->mapped_user >= next_beg)
return reinterpret_cast<void*>(reg_beg + beg);
- return 0;
+ return nullptr;
}
static uptr GetActuallyAllocatedSize(void *p) {
@@ -609,6 +609,7 @@ class TwoLevelByteMap {
internal_memset(map1_, 0, sizeof(map1_));
mu_.Init();
}
+
void TestOnlyUnmap() {
for (uptr i = 0; i < kSize1; i++) {
u8 *p = Get(i);
@@ -822,6 +823,10 @@ class SizeClassAllocator32 {
void PrintStats() {
}
+ static uptr AdditionalSize() {
+ return 0;
+ }
+
typedef SizeClassMap SizeClassMapT;
static const uptr kNumClasses = SizeClassMap::kNumClasses;
@@ -868,9 +873,9 @@ class SizeClassAllocator32 {
uptr reg = AllocateRegion(stat, class_id);
uptr n_chunks = kRegionSize / (size + kMetadataSize);
uptr max_count = SizeClassMap::MaxCached(class_id);
- Batch *b = 0;
+ Batch *b = nullptr;
for (uptr i = reg; i < reg + n_chunks * size; i += size) {
- if (b == 0) {
+ if (!b) {
if (SizeClassMap::SizeClassRequiresSeparateTransferBatch(class_id))
b = (Batch*)c->Allocate(this, SizeClassMap::ClassID(sizeof(Batch)));
else
@@ -881,7 +886,7 @@ class SizeClassAllocator32 {
if (b->count == max_count) {
CHECK_GT(b->count, 0);
sci->free_list.push_back(b);
- b = 0;
+ b = nullptr;
}
}
if (b) {
@@ -1061,7 +1066,7 @@ class LargeMmapAllocator {
void *ReturnNullOrDie() {
if (atomic_load(&may_return_null_, memory_order_acquire))
- return 0;
+ return nullptr;
ReportAllocatorCannotReturnNull();
}
@@ -1101,7 +1106,7 @@ class LargeMmapAllocator {
}
bool PointerIsMine(const void *p) {
- return GetBlockBegin(p) != 0;
+ return GetBlockBegin(p) != nullptr;
}
uptr GetActuallyAllocatedSize(void *p) {
@@ -1130,13 +1135,13 @@ class LargeMmapAllocator {
nearest_chunk = ch;
}
if (!nearest_chunk)
- return 0;
+ return nullptr;
Header *h = reinterpret_cast<Header *>(nearest_chunk);
CHECK_GE(nearest_chunk, h->map_beg);
CHECK_LT(nearest_chunk, h->map_beg + h->map_size);
CHECK_LE(nearest_chunk, p);
if (h->map_beg + h->map_size <= p)
- return 0;
+ return nullptr;
return GetUser(h);
}
@@ -1146,7 +1151,7 @@ class LargeMmapAllocator {
mutex_.CheckLocked();
uptr p = reinterpret_cast<uptr>(ptr);
uptr n = n_chunks_;
- if (!n) return 0;
+ if (!n) return nullptr;
if (!chunks_sorted_) {
// Do one-time sort. chunks_sorted_ is reset in Allocate/Deallocate.
SortArray(reinterpret_cast<uptr*>(chunks_), n);
@@ -1158,7 +1163,7 @@ class LargeMmapAllocator {
chunks_[n - 1]->map_size;
}
if (p < min_mmap_ || p >= max_mmap_)
- return 0;
+ return nullptr;
uptr beg = 0, end = n - 1;
// This loop is a log(n) lower_bound. It does not check for the exact match
// to avoid expensive cache-thrashing loads.
@@ -1179,7 +1184,7 @@ class LargeMmapAllocator {
Header *h = chunks_[beg];
if (h->map_beg + h->map_size <= p || p < h->map_beg)
- return 0;
+ return nullptr;
return GetUser(h);
}
@@ -1308,7 +1313,7 @@ class CombinedAllocator {
void *ReturnNullOrDie() {
if (MayReturnNull())
- return 0;
+ return nullptr;
ReportAllocatorCannotReturnNull();
}
@@ -1340,7 +1345,7 @@ class CombinedAllocator {
return Allocate(cache, new_size, alignment);
if (!new_size) {
Deallocate(cache, p);
- return 0;
+ return nullptr;
}
CHECK(PointerIsMine(p));
uptr old_size = GetActuallyAllocatedSize(p);
@@ -1445,7 +1450,6 @@ class CombinedAllocator {
// Returns true if calloc(size, n) should return 0 due to overflow in size*n.
bool CallocShouldReturnNullDueToOverflow(uptr size, uptr n);
-} // namespace __sanitizer
-
-#endif // SANITIZER_ALLOCATOR_H
+} // namespace __sanitizer
+#endif // SANITIZER_ALLOCATOR_H
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_internal.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_internal.h
index 9b9cfd0b5931..3dcfccd7cba3 100644
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_internal.h
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_internal.h
@@ -1,4 +1,4 @@
-//===-- sanitizer_allocator_internal.h -------------------------- C++ -----===//
+//===-- sanitizer_allocator_internal.h --------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -45,19 +45,19 @@ typedef SizeClassAllocatorLocalCache<PrimaryInternalAllocator>
typedef CombinedAllocator<PrimaryInternalAllocator, InternalAllocatorCache,
LargeMmapAllocator<> > InternalAllocator;
-void *InternalAlloc(uptr size, InternalAllocatorCache *cache = 0);
-void InternalFree(void *p, InternalAllocatorCache *cache = 0);
+void *InternalAlloc(uptr size, InternalAllocatorCache *cache = nullptr);
+void InternalFree(void *p, InternalAllocatorCache *cache = nullptr);
InternalAllocator *internal_allocator();
enum InternalAllocEnum {
INTERNAL_ALLOC
};
-} // namespace __sanitizer
+} // namespace __sanitizer
inline void *operator new(__sanitizer::operator_new_size_type size,
InternalAllocEnum) {
return InternalAlloc(size);
}
-#endif // SANITIZER_ALLOCATOR_INTERNAL_H
+#endif // SANITIZER_ALLOCATOR_INTERNAL_H
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_asm.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_asm.h
index 906012a96f11..47c2b12a2049 100644
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_asm.h
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_asm.h
@@ -23,8 +23,11 @@
# define CFI_STARTPROC .cfi_startproc
# define CFI_ENDPROC .cfi_endproc
# define CFI_ADJUST_CFA_OFFSET(n) .cfi_adjust_cfa_offset n
+# define CFI_DEF_CFA_OFFSET(n) .cfi_def_cfa_offset n
# define CFI_REL_OFFSET(reg, n) .cfi_rel_offset reg, n
+# define CFI_OFFSET(reg, n) .cfi_offset reg, n
# define CFI_DEF_CFA_REGISTER(reg) .cfi_def_cfa_register reg
+# define CFI_DEF_CFA(reg, n) .cfi_def_cfa reg, n
# define CFI_RESTORE(reg) .cfi_restore reg
#else // No CFI
@@ -32,9 +35,24 @@
# define CFI_STARTPROC
# define CFI_ENDPROC
# define CFI_ADJUST_CFA_OFFSET(n)
+# define CFI_DEF_CFA_OFFSET(n)
# define CFI_REL_OFFSET(reg, n)
+# define CFI_OFFSET(reg, n)
# define CFI_DEF_CFA_REGISTER(reg)
+# define CFI_DEF_CFA(reg, n)
# define CFI_RESTORE(reg)
#endif
-
+#if !defined(__APPLE__)
+# define ASM_HIDDEN(symbol) .hidden symbol
+# define ASM_TYPE_FUNCTION(symbol) .type symbol, @function
+# define ASM_SIZE(symbol) .size symbol, .-symbol
+# define ASM_TSAN_SYMBOL(symbol) symbol
+# define ASM_TSAN_SYMBOL_INTERCEPTOR(symbol) symbol
+#else
+# define ASM_HIDDEN(symbol)
+# define ASM_TYPE_FUNCTION(symbol)
+# define ASM_SIZE(symbol)
+# define ASM_TSAN_SYMBOL(symbol) _##symbol
+# define ASM_TSAN_SYMBOL_INTERCEPTOR(symbol) _wrap_##symbol
+#endif
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_atomic.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_atomic.h
index 7e3374aadd0c..b26693e24f8d 100644
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_atomic.h
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_atomic.h
@@ -63,4 +63,20 @@ struct atomic_uintptr_t {
# error "Unsupported compiler"
#endif
+namespace __sanitizer {
+
+// Clutter-reducing helpers.
+
+template<typename T>
+INLINE typename T::Type atomic_load_relaxed(const volatile T *a) {
+ return atomic_load(a, memory_order_relaxed);
+}
+
+template<typename T>
+INLINE void atomic_store_relaxed(volatile T *a, typename T::Type v) {
+ atomic_store(a, v, memory_order_relaxed);
+}
+
+} // namespace __sanitizer
+
#endif // SANITIZER_ATOMIC_H
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common.cc
index d14e98824d99..9b41a3aa0af9 100644
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common.cc
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common.cc
@@ -57,7 +57,7 @@ void ReportFile::ReopenIfNecessary() {
CloseFile(fd);
}
- const char *exe_name = GetBinaryBasename();
+ const char *exe_name = GetProcessName();
if (common_flags()->log_exe_name && exe_name) {
internal_snprintf(full_path, kMaxPathLength, "%s.%s.%zu", path_prefix,
exe_name, pid);
@@ -105,24 +105,47 @@ uptr stoptheworld_tracer_pid = 0;
// writing to the same log file.
uptr stoptheworld_tracer_ppid = 0;
-static DieCallbackType InternalDieCallback, UserDieCallback;
-void SetDieCallback(DieCallbackType callback) {
- InternalDieCallback = callback;
+static const int kMaxNumOfInternalDieCallbacks = 5;
+static DieCallbackType InternalDieCallbacks[kMaxNumOfInternalDieCallbacks];
+
+bool AddDieCallback(DieCallbackType callback) {
+ for (int i = 0; i < kMaxNumOfInternalDieCallbacks; i++) {
+ if (InternalDieCallbacks[i] == nullptr) {
+ InternalDieCallbacks[i] = callback;
+ return true;
+ }
+ }
+ return false;
}
-void SetUserDieCallback(DieCallbackType callback) {
- UserDieCallback = callback;
+
+bool RemoveDieCallback(DieCallbackType callback) {
+ for (int i = 0; i < kMaxNumOfInternalDieCallbacks; i++) {
+ if (InternalDieCallbacks[i] == callback) {
+ internal_memmove(&InternalDieCallbacks[i], &InternalDieCallbacks[i + 1],
+ sizeof(InternalDieCallbacks[0]) *
+ (kMaxNumOfInternalDieCallbacks - i - 1));
+ InternalDieCallbacks[kMaxNumOfInternalDieCallbacks - 1] = nullptr;
+ return true;
+ }
+ }
+ return false;
}
-DieCallbackType GetDieCallback() {
- return InternalDieCallback;
+static DieCallbackType UserDieCallback;
+void SetUserDieCallback(DieCallbackType callback) {
+ UserDieCallback = callback;
}
void NORETURN Die() {
if (UserDieCallback)
UserDieCallback();
- if (InternalDieCallback)
- InternalDieCallback();
- internal__exit(1);
+ for (int i = kMaxNumOfInternalDieCallbacks - 1; i >= 0; i--) {
+ if (InternalDieCallbacks[i])
+ InternalDieCallbacks[i]();
+ }
+ if (common_flags()->abort_on_error)
+ Abort();
+ internal__exit(common_flags()->exitcode);
}
static CheckFailedCallbackType CheckFailedCallback;
@@ -140,40 +163,60 @@ void NORETURN CheckFailed(const char *file, int line, const char *cond,
Die();
}
-uptr ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size,
- uptr max_len, error_t *errno_p) {
+void NORETURN ReportMmapFailureAndDie(uptr size, const char *mem_type,
+ const char *mmap_type, error_t err,
+ bool raw_report) {
+ static int recursion_count;
+ if (raw_report || recursion_count) {
+ // If raw report is requested or we went into recursion, just die.
+ // The Report() and CHECK calls below may call mmap recursively and fail.
+ RawWrite("ERROR: Failed to mmap\n");
+ Die();
+ }
+ recursion_count++;
+ Report("ERROR: %s failed to "
+ "%s 0x%zx (%zd) bytes of %s (error code: %d)\n",
+ SanitizerToolName, mmap_type, size, size, mem_type, err);
+#ifndef SANITIZER_GO
+ DumpProcessMap();
+#endif
+ UNREACHABLE("unable to mmap");
+}
+
+bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size,
+ uptr *read_len, uptr max_len, error_t *errno_p) {
uptr PageSize = GetPageSizeCached();
uptr kMinFileLen = PageSize;
- uptr read_len = 0;
- *buff = 0;
+ *buff = nullptr;
*buff_size = 0;
+ *read_len = 0;
// The files we usually open are not seekable, so try different buffer sizes.
for (uptr size = kMinFileLen; size <= max_len; size *= 2) {
fd_t fd = OpenFile(file_name, RdOnly, errno_p);
- if (fd == kInvalidFd) return 0;
+ if (fd == kInvalidFd) return false;
UnmapOrDie(*buff, *buff_size);
*buff = (char*)MmapOrDie(size, __func__);
*buff_size = size;
+ *read_len = 0;
// Read up to one page at a time.
- read_len = 0;
bool reached_eof = false;
- while (read_len + PageSize <= size) {
+ while (*read_len + PageSize <= size) {
uptr just_read;
- if (!ReadFromFile(fd, *buff + read_len, PageSize, &just_read, errno_p)) {
+ if (!ReadFromFile(fd, *buff + *read_len, PageSize, &just_read, errno_p)) {
UnmapOrDie(*buff, *buff_size);
- return 0;
+ return false;
}
if (just_read == 0) {
reached_eof = true;
break;
}
- read_len += just_read;
+ *read_len += just_read;
}
CloseFile(fd);
if (reached_eof) // We've read the whole file.
break;
}
- return read_len;
+ return true;
}
typedef bool UptrComparisonFunction(const uptr &a, const uptr &b);
@@ -210,8 +253,8 @@ void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type) {
const char *StripPathPrefix(const char *filepath,
const char *strip_path_prefix) {
- if (filepath == 0) return 0;
- if (strip_path_prefix == 0) return filepath;
+ if (!filepath) return nullptr;
+ if (!strip_path_prefix) return filepath;
const char *res = filepath;
if (const char *pos = internal_strstr(filepath, strip_path_prefix))
res = pos + internal_strlen(strip_path_prefix);
@@ -221,8 +264,8 @@ const char *StripPathPrefix(const char *filepath,
}
const char *StripModuleName(const char *module) {
- if (module == 0)
- return 0;
+ if (!module)
+ return nullptr;
if (SANITIZER_WINDOWS) {
// On Windows, both slash and backslash are possible.
// Pick the one that goes last.
@@ -255,6 +298,40 @@ void ReportErrorSummary(const char *error_type, const AddressInfo &info) {
}
#endif
+// Removes the ANSI escape sequences from the input string (in-place).
+void RemoveANSIEscapeSequencesFromString(char *str) {
+ if (!str)
+ return;
+
+ // We are going to remove the escape sequences in place.
+ char *s = str;
+ char *z = str;
+ while (*s != '\0') {
+ CHECK_GE(s, z);
+ // Skip over ANSI escape sequences with pointer 's'.
+ if (*s == '\033' && *(s + 1) == '[') {
+ s = internal_strchrnul(s, 'm');
+ if (*s == '\0') {
+ break;
+ }
+ s++;
+ continue;
+ }
+ // 's' now points at a character we want to keep. Copy over the buffer
+ // content if the escape sequence has been perviously skipped andadvance
+ // both pointers.
+ if (s != z)
+ *z = *s;
+
+ // If we have not seen an escape sequence, just advance both pointers.
+ z++;
+ s++;
+ }
+
+ // Null terminate the string.
+ *z = '\0';
+}
+
void LoadedModule::set(const char *module_name, uptr base_address) {
clear();
full_name_ = internal_strdup(module_name);
@@ -303,7 +380,7 @@ void DecreaseTotalMmap(uptr size) {
}
bool TemplateMatch(const char *templ, const char *str) {
- if (str == 0 || str[0] == 0)
+ if ((!str) || str[0] == 0)
return false;
bool start = false;
if (templ && templ[0] == '^') {
@@ -324,9 +401,9 @@ bool TemplateMatch(const char *templ, const char *str) {
return false;
char *tpos = (char*)internal_strchr(templ, '*');
char *tpos1 = (char*)internal_strchr(templ, '$');
- if (tpos == 0 || (tpos1 && tpos1 < tpos))
+ if ((!tpos) || (tpos1 && tpos1 < tpos))
tpos = tpos1;
- if (tpos != 0)
+ if (tpos)
tpos[0] = 0;
const char *str0 = str;
const char *spos = internal_strstr(str, templ);
@@ -334,7 +411,7 @@ bool TemplateMatch(const char *templ, const char *str) {
templ = tpos;
if (tpos)
tpos[0] = tpos == tpos1 ? '$' : '*';
- if (spos == 0)
+ if (!spos)
return false;
if (start && spos != str0)
return false;
@@ -344,11 +421,52 @@ bool TemplateMatch(const char *templ, const char *str) {
return true;
}
+static const char kPathSeparator = SANITIZER_WINDOWS ? ';' : ':';
+
+char *FindPathToBinary(const char *name) {
+ const char *path = GetEnv("PATH");
+ if (!path)
+ return nullptr;
+ uptr name_len = internal_strlen(name);
+ InternalScopedBuffer<char> buffer(kMaxPathLength);
+ const char *beg = path;
+ while (true) {
+ const char *end = internal_strchrnul(beg, kPathSeparator);
+ uptr prefix_len = end - beg;
+ if (prefix_len + name_len + 2 <= kMaxPathLength) {
+ internal_memcpy(buffer.data(), beg, prefix_len);
+ buffer[prefix_len] = '/';
+ internal_memcpy(&buffer[prefix_len + 1], name, name_len);
+ buffer[prefix_len + 1 + name_len] = '\0';
+ if (FileExists(buffer.data()))
+ return internal_strdup(buffer.data());
+ }
+ if (*end == '\0') break;
+ beg = end + 1;
+ }
+ return nullptr;
+}
+
static char binary_name_cache_str[kMaxPathLength];
-static const char *binary_basename_cache_str;
+static char process_name_cache_str[kMaxPathLength];
+
+const char *GetProcessName() {
+ return process_name_cache_str;
+}
+
+static uptr ReadProcessName(/*out*/ char *buf, uptr buf_len) {
+ ReadLongProcessName(buf, buf_len);
+ char *s = const_cast<char *>(StripModuleName(buf));
+ uptr len = internal_strlen(s);
+ if (s != buf) {
+ internal_memmove(buf, s, len);
+ buf[len] = '\0';
+ }
+ return len;
+}
-const char *GetBinaryBasename() {
- return binary_basename_cache_str;
+void UpdateProcessName() {
+ ReadProcessName(process_name_cache_str, sizeof(process_name_cache_str));
}
// Call once to make sure that binary_name_cache_str is initialized
@@ -356,7 +474,7 @@ void CacheBinaryName() {
if (binary_name_cache_str[0] != '\0')
return;
ReadBinaryName(binary_name_cache_str, sizeof(binary_name_cache_str));
- binary_basename_cache_str = StripModuleName(binary_name_cache_str);
+ ReadProcessName(process_name_cache_str, sizeof(process_name_cache_str));
}
uptr ReadBinaryNameCached(/*out*/char *buf, uptr buf_len) {
@@ -370,7 +488,7 @@ uptr ReadBinaryNameCached(/*out*/char *buf, uptr buf_len) {
return name_len;
}
-} // namespace __sanitizer
+} // namespace __sanitizer
using namespace __sanitizer; // NOLINT
@@ -387,4 +505,4 @@ SANITIZER_INTERFACE_ATTRIBUTE
void __sanitizer_set_death_callback(void (*callback)(void)) {
SetUserDieCallback(callback);
}
-} // extern "C"
+} // extern "C"
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common.h
index 2c5a8dbe1238..7e80507ba0cf 100644
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common.h
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common.h
@@ -49,6 +49,8 @@ static const uptr kMaxNumberOfModules = 1 << 14;
const uptr kMaxThreadStackSize = 1 << 30; // 1Gb
+static const uptr kErrorMessageBufferSize = 1 << 16;
+
// Denotes fake PC values that come from JIT/JAVA/etc.
// For such PC values __tsan_symbolize_external() will be called.
const u64 kExternalPCBit = 1ULL << 60;
@@ -76,7 +78,10 @@ void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
uptr *tls_addr, uptr *tls_size);
// Memory management
-void *MmapOrDie(uptr size, const char *mem_type);
+void *MmapOrDie(uptr size, const char *mem_type, bool raw_report = false);
+INLINE void *MmapOrDieQuietly(uptr size, const char *mem_type) {
+ return MmapOrDie(size, mem_type, /*raw_report*/ true);
+}
void UnmapOrDie(void *addr, uptr size);
void *MmapFixedNoReserve(uptr fixed_addr, uptr size,
const char *name = nullptr);
@@ -97,6 +102,8 @@ void DecreaseTotalMmap(uptr size);
uptr GetRSS();
void NoHugePagesInRegion(uptr addr, uptr length);
void DontDumpShadowMemory(uptr addr, uptr length);
+// Check if the built VMA size matches the runtime one.
+void CheckVMASize();
// InternalScopedBuffer can be used instead of large stack arrays to
// keep frame size low.
@@ -160,6 +167,7 @@ void SetLowLevelAllocateCallback(LowLevelAllocateCallback callback);
// IO
void RawWrite(const char *buffer);
bool ColorizeReports();
+void RemoveANSIEscapeSequencesFromString(char *buffer);
void Printf(const char *format, ...);
void Report(const char *format, ...);
void SetPrintfAndReportCallback(void (*callback)(const char *));
@@ -224,14 +232,23 @@ bool WriteToFile(fd_t fd, const void *buff, uptr buff_size,
bool RenameFile(const char *oldpath, const char *newpath,
error_t *error_p = nullptr);
+// Scoped file handle closer.
+struct FileCloser {
+ explicit FileCloser(fd_t fd) : fd(fd) {}
+ ~FileCloser() { CloseFile(fd); }
+ fd_t fd;
+};
+
bool SupportsColoredOutput(fd_t fd);
// Opens the file 'file_name" and reads up to 'max_len' bytes.
// The resulting buffer is mmaped and stored in '*buff'.
-// The size of the mmaped region is stored in '*buff_size',
-// Returns the number of read bytes or 0 if file can not be opened.
-uptr ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size,
- uptr max_len, error_t *errno_p = nullptr);
+// The size of the mmaped region is stored in '*buff_size'.
+// The total number of read bytes is stored in '*read_len'.
+// Returns true if file was successfully opened and read.
+bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size,
+ uptr *read_len, uptr max_len = 1 << 26,
+ error_t *errno_p = nullptr);
// Maps given file to virtual memory, and returns pointer to it
// (or NULL if mapping fails). Stores the size of mmaped region
// in '*buff_size'.
@@ -249,7 +266,9 @@ const char *StripModuleName(const char *module);
// OS
uptr ReadBinaryName(/*out*/char *buf, uptr buf_len);
uptr ReadBinaryNameCached(/*out*/char *buf, uptr buf_len);
-const char *GetBinaryBasename();
+uptr ReadLongProcessName(/*out*/ char *buf, uptr buf_len);
+const char *GetProcessName();
+void UpdateProcessName();
void CacheBinaryName();
void DisableCoreDumperIfNecessary();
void DumpProcessMap();
@@ -295,6 +314,9 @@ void NORETURN Abort();
void NORETURN Die();
void NORETURN
CheckFailed(const char *file, int line, const char *cond, u64 v1, u64 v2);
+void NORETURN ReportMmapFailureAndDie(uptr size, const char *mem_type,
+ const char *mmap_type, error_t err,
+ bool raw_report = false);
// Set the name of the current thread to 'name', return true on succees.
// The name may be truncated to a system-dependent limit.
@@ -306,9 +328,16 @@ bool SanitizerGetThreadName(char *name, int max_len);
// Specific tools may override behavior of "Die" and "CheckFailed" functions
// to do tool-specific job.
typedef void (*DieCallbackType)(void);
-void SetDieCallback(DieCallbackType);
-void SetUserDieCallback(DieCallbackType);
-DieCallbackType GetDieCallback();
+
+// It's possible to add several callbacks that would be run when "Die" is
+// called. The callbacks will be run in the opposite order. The tools are
+// strongly recommended to setup all callbacks during initialization, when there
+// is only a single thread.
+bool AddDieCallback(DieCallbackType callback);
+bool RemoveDieCallback(DieCallbackType callback);
+
+void SetUserDieCallback(DieCallbackType callback);
+
typedef void (*CheckFailedCallbackType)(const char *, int, const char *,
u64, u64);
void SetCheckFailedCallback(CheckFailedCallbackType callback);
@@ -400,7 +429,7 @@ INLINE uptr RoundUpToPowerOfTwo(uptr size) {
}
INLINE uptr RoundUpTo(uptr size, uptr boundary) {
- CHECK(IsPowerOfTwo(boundary));
+ RAW_CHECK(IsPowerOfTwo(boundary));
return (size + boundary - 1) & ~(boundary - 1);
}
@@ -626,17 +655,34 @@ enum AndroidApiLevel {
ANDROID_POST_LOLLIPOP = 23
};
-#if SANITIZER_ANDROID
+void WriteToSyslog(const char *buffer);
+
+#if SANITIZER_MAC
+void LogFullErrorReport(const char *buffer);
+#else
+INLINE void LogFullErrorReport(const char *buffer) {}
+#endif
+
+#if SANITIZER_LINUX || SANITIZER_MAC
+void WriteOneLineToSyslog(const char *s);
+void LogMessageOnPrintf(const char *str);
+#else
+INLINE void WriteOneLineToSyslog(const char *s) {}
+INLINE void LogMessageOnPrintf(const char *str) {}
+#endif
+
+#if SANITIZER_LINUX
// Initialize Android logging. Any writes before this are silently lost.
void AndroidLogInit();
-void AndroidLogWrite(const char *buffer);
-void GetExtraActivationFlags(char *buf, uptr size);
+#else
+INLINE void AndroidLogInit() {}
+#endif
+
+#if SANITIZER_ANDROID
void SanitizerInitializeUnwinder();
AndroidApiLevel AndroidGetApiLevel();
#else
-INLINE void AndroidLogInit() {}
INLINE void AndroidLogWrite(const char *buffer_unused) {}
-INLINE void GetExtraActivationFlags(char *buf, uptr size) { *buf = '\0'; }
INLINE void SanitizerInitializeUnwinder() {}
INLINE AndroidApiLevel AndroidGetApiLevel() { return ANDROID_NOT_ANDROID; }
#endif
@@ -685,6 +731,9 @@ struct SignalContext {
void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp);
+void DisableReexec();
+void MaybeReexec();
+
} // namespace __sanitizer
inline void *operator new(__sanitizer::operator_new_size_type size,
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc
index a7772b7394a5..2a748cdc6852 100644
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc
@@ -31,6 +31,7 @@
// COMMON_INTERCEPTOR_HANDLE_RECVMSG
// COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED
//===----------------------------------------------------------------------===//
+
#include "interception/interception.h"
#include "sanitizer_addrhashmap.h"
#include "sanitizer_placement_new.h"
@@ -39,6 +40,22 @@
#include <stdarg.h>
+#if SANITIZER_INTERCEPTOR_HOOKS
+#define CALL_WEAK_INTERCEPTOR_HOOK(f, ...) \
+ do { \
+ if (f) \
+ f(__VA_ARGS__); \
+ } while (false);
+#define DECLARE_WEAK_INTERCEPTOR_HOOK(f, ...) \
+ extern "C" { \
+ SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void f(__VA_ARGS__); \
+ } // extern "C"
+#else
+#define DECLARE_WEAK_INTERCEPTOR_HOOK(f, ...)
+#define CALL_WEAK_INTERCEPTOR_HOOK(f, ...)
+
+#endif // SANITIZER_INTERCEPTOR_HOOKS
+
#if SANITIZER_WINDOWS && !defined(va_copy)
#define va_copy(dst, src) ((dst) = (src))
#endif // _WIN32
@@ -118,6 +135,14 @@
#define COMMON_INTERCEPTOR_GET_TLS_RANGE(begin, end) *begin = *end = 0;
#endif
+#ifndef COMMON_INTERCEPTOR_ACQUIRE
+#define COMMON_INTERCEPTOR_ACQUIRE(ctx, u) {}
+#endif
+
+#ifndef COMMON_INTERCEPTOR_RELEASE
+#define COMMON_INTERCEPTOR_RELEASE(ctx, u) {}
+#endif
+
struct FileMetadata {
// For open_memstream().
char **addr;
@@ -188,6 +213,9 @@ static inline int CharCmpX(unsigned char c1, unsigned char c2) {
return (c1 == c2) ? 0 : (c1 < c2) ? -1 : 1;
}
+DECLARE_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strcmp, uptr called_pc,
+ const char *s1, const char *s2, int result)
+
INTERCEPTOR(int, strcmp, const char *s1, const char *s2) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, strcmp, s1, s2);
@@ -200,9 +228,16 @@ INTERCEPTOR(int, strcmp, const char *s1, const char *s2) {
}
COMMON_INTERCEPTOR_READ_STRING(ctx, s1, i + 1);
COMMON_INTERCEPTOR_READ_STRING(ctx, s2, i + 1);
- return CharCmpX(c1, c2);
+ int result = CharCmpX(c1, c2);
+ CALL_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strcmp, GET_CALLER_PC(), s1,
+ s2, result);
+ return result;
}
+DECLARE_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strncmp, uptr called_pc,
+ const char *s1, const char *s2, uptr n,
+ int result)
+
INTERCEPTOR(int, strncmp, const char *s1, const char *s2, uptr size) {
if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED)
return internal_strncmp(s1, s2, size);
@@ -217,7 +252,10 @@ INTERCEPTOR(int, strncmp, const char *s1, const char *s2, uptr size) {
}
COMMON_INTERCEPTOR_READ_RANGE(ctx, s1, Min(i + 1, size));
COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, Min(i + 1, size));
- return CharCmpX(c1, c2);
+ int result = CharCmpX(c1, c2);
+ CALL_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strncmp, GET_CALLER_PC(), s1,
+ s2, size, result);
+ return result;
}
#define INIT_STRCMP COMMON_INTERCEPT_FUNCTION(strcmp)
@@ -362,8 +400,57 @@ INTERCEPTOR(char *, strpbrk, const char *s1, const char *s2) {
#define INIT_STRPBRK
#endif
+#if SANITIZER_INTERCEPT_MEMCMP
+
+DECLARE_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_memcmp, uptr called_pc,
+ const void *s1, const void *s2, uptr n,
+ int result)
+
+INTERCEPTOR(int, memcmp, const void *a1, const void *a2, uptr size) {
+ if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED)
+ return internal_memcmp(a1, a2, size);
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, memcmp, a1, a2, size);
+ if (common_flags()->intercept_memcmp) {
+ if (common_flags()->strict_memcmp) {
+ // Check the entire regions even if the first bytes of the buffers are
+ // different.
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, a1, size);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, a2, size);
+ // Fallthrough to REAL(memcmp) below.
+ } else {
+ unsigned char c1 = 0, c2 = 0;
+ const unsigned char *s1 = (const unsigned char*)a1;
+ const unsigned char *s2 = (const unsigned char*)a2;
+ uptr i;
+ for (i = 0; i < size; i++) {
+ c1 = s1[i];
+ c2 = s2[i];
+ if (c1 != c2) break;
+ }
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, s1, Min(i + 1, size));
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, Min(i + 1, size));
+ int r = CharCmpX(c1, c2);
+ CALL_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_memcmp, GET_CALLER_PC(),
+ a1, a2, size, r);
+ return r;
+ }
+ }
+ int result = REAL(memcmp(a1, a2, size));
+ CALL_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_memcmp, GET_CALLER_PC(), a1,
+ a2, size, result);
+ return result;
+}
+
+#define INIT_MEMCMP COMMON_INTERCEPT_FUNCTION(memcmp)
+#else
+#define INIT_MEMCMP
+#endif
+
#if SANITIZER_INTERCEPT_MEMCHR
INTERCEPTOR(void*, memchr, const void *s, int c, SIZE_T n) {
+ if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED)
+ return internal_memchr(s, c, n);
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, memchr, s, c, n);
void *res = REAL(memchr)(s, c, n);
@@ -411,7 +498,7 @@ INTERCEPTOR(float, frexpf, float x, int *exp) {
COMMON_INTERCEPTOR_ENTER(ctx, frexpf, x, exp);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
float res = REAL(frexpf)(x, exp);
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, exp, sizeof(*exp));
return res;
@@ -422,7 +509,7 @@ INTERCEPTOR(long double, frexpl, long double x, int *exp) {
COMMON_INTERCEPTOR_ENTER(ctx, frexpl, x, exp);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
long double res = REAL(frexpl)(x, exp);
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, exp, sizeof(*exp));
return res;
@@ -463,7 +550,7 @@ INTERCEPTOR(SSIZE_T, read, int fd, void *ptr, SIZE_T count) {
COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
SSIZE_T res = REAL(read)(fd, ptr, count);
if (res > 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, res);
if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
@@ -481,7 +568,7 @@ INTERCEPTOR(SSIZE_T, pread, int fd, void *ptr, SIZE_T count, OFF_T offset) {
COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
SSIZE_T res = REAL(pread)(fd, ptr, count, offset);
if (res > 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, res);
if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
@@ -499,7 +586,7 @@ INTERCEPTOR(SSIZE_T, pread64, int fd, void *ptr, SIZE_T count, OFF64_T offset) {
COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
SSIZE_T res = REAL(pread64)(fd, ptr, count, offset);
if (res > 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, res);
if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
@@ -746,7 +833,7 @@ INTERCEPTOR(char *, ctime, unsigned long *timep) {
COMMON_INTERCEPTOR_ENTER(ctx, ctime, timep);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
char *res = REAL(ctime)(timep);
if (res) {
COMMON_INTERCEPTOR_READ_RANGE(ctx, timep, sizeof(*timep));
@@ -759,7 +846,7 @@ INTERCEPTOR(char *, ctime_r, unsigned long *timep, char *result) {
COMMON_INTERCEPTOR_ENTER(ctx, ctime_r, timep, result);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
char *res = REAL(ctime_r)(timep, result);
if (res) {
COMMON_INTERCEPTOR_READ_RANGE(ctx, timep, sizeof(*timep));
@@ -772,7 +859,7 @@ INTERCEPTOR(char *, asctime, __sanitizer_tm *tm) {
COMMON_INTERCEPTOR_ENTER(ctx, asctime, tm);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
char *res = REAL(asctime)(tm);
if (res) {
COMMON_INTERCEPTOR_READ_RANGE(ctx, tm, sizeof(*tm));
@@ -785,7 +872,7 @@ INTERCEPTOR(char *, asctime_r, __sanitizer_tm *tm, char *result) {
COMMON_INTERCEPTOR_ENTER(ctx, asctime_r, tm, result);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
char *res = REAL(asctime_r)(tm, result);
if (res) {
COMMON_INTERCEPTOR_READ_RANGE(ctx, tm, sizeof(*tm));
@@ -829,7 +916,7 @@ INTERCEPTOR(char *, strptime, char *s, char *format, __sanitizer_tm *tm) {
COMMON_INTERCEPTOR_READ_RANGE(ctx, format, REAL(strlen)(format) + 1);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
char *res = REAL(strptime)(s, format, tm);
COMMON_INTERCEPTOR_READ_STRING(ctx, s, res ? res - s : 0);
if (res && tm) {
@@ -966,7 +1053,7 @@ FORMAT_INTERCEPTOR_IMPL(__isoc99_sscanf, __isoc99_vsscanf, str, format)
// FIXME: under ASan the REAL() call below may write to freed memory and
// corrupt its metadata. See
-// https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+// https://github.com/google/sanitizers/issues/321.
#define VSPRINTF_INTERCEPTOR_IMPL(vname, str, ...) \
{ \
VPRINTF_INTERCEPTOR_ENTER(vname, str, __VA_ARGS__) \
@@ -983,7 +1070,7 @@ FORMAT_INTERCEPTOR_IMPL(__isoc99_sscanf, __isoc99_vsscanf, str, format)
// FIXME: under ASan the REAL() call below may write to freed memory and
// corrupt its metadata. See
-// https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+// https://github.com/google/sanitizers/issues/321.
#define VSNPRINTF_INTERCEPTOR_IMPL(vname, str, size, ...) \
{ \
VPRINTF_INTERCEPTOR_ENTER(vname, str, size, __VA_ARGS__) \
@@ -1000,7 +1087,7 @@ FORMAT_INTERCEPTOR_IMPL(__isoc99_sscanf, __isoc99_vsscanf, str, format)
// FIXME: under ASan the REAL() call below may write to freed memory and
// corrupt its metadata. See
-// https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+// https://github.com/google/sanitizers/issues/321.
#define VASPRINTF_INTERCEPTOR_IMPL(vname, strp, ...) \
{ \
VPRINTF_INTERCEPTOR_ENTER(vname, strp, __VA_ARGS__) \
@@ -1243,14 +1330,14 @@ INTERCEPTOR(__sanitizer_passwd *, getpwnam, const char *name) {
COMMON_INTERCEPTOR_ENTER(ctx, getpwnam, name);
COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1);
__sanitizer_passwd *res = REAL(getpwnam)(name);
- if (res != 0) unpoison_passwd(ctx, res);
+ if (res) unpoison_passwd(ctx, res);
return res;
}
INTERCEPTOR(__sanitizer_passwd *, getpwuid, u32 uid) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, getpwuid, uid);
__sanitizer_passwd *res = REAL(getpwuid)(uid);
- if (res != 0) unpoison_passwd(ctx, res);
+ if (res) unpoison_passwd(ctx, res);
return res;
}
INTERCEPTOR(__sanitizer_group *, getgrnam, const char *name) {
@@ -1258,14 +1345,14 @@ INTERCEPTOR(__sanitizer_group *, getgrnam, const char *name) {
COMMON_INTERCEPTOR_ENTER(ctx, getgrnam, name);
COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1);
__sanitizer_group *res = REAL(getgrnam)(name);
- if (res != 0) unpoison_group(ctx, res);
+ if (res) unpoison_group(ctx, res);
return res;
}
INTERCEPTOR(__sanitizer_group *, getgrgid, u32 gid) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, getgrgid, gid);
__sanitizer_group *res = REAL(getgrgid)(gid);
- if (res != 0) unpoison_group(ctx, res);
+ if (res) unpoison_group(ctx, res);
return res;
}
#define INIT_GETPWNAM_AND_FRIENDS \
@@ -1285,7 +1372,7 @@ INTERCEPTOR(int, getpwnam_r, const char *name, __sanitizer_passwd *pwd,
COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(getpwnam_r)(name, pwd, buf, buflen, result);
if (!res) {
if (result && *result) unpoison_passwd(ctx, *result);
@@ -1300,7 +1387,7 @@ INTERCEPTOR(int, getpwuid_r, u32 uid, __sanitizer_passwd *pwd, char *buf,
COMMON_INTERCEPTOR_ENTER(ctx, getpwuid_r, uid, pwd, buf, buflen, result);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(getpwuid_r)(uid, pwd, buf, buflen, result);
if (!res) {
if (result && *result) unpoison_passwd(ctx, *result);
@@ -1316,7 +1403,7 @@ INTERCEPTOR(int, getgrnam_r, const char *name, __sanitizer_group *grp,
COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(getgrnam_r)(name, grp, buf, buflen, result);
if (!res) {
if (result && *result) unpoison_group(ctx, *result);
@@ -1331,7 +1418,7 @@ INTERCEPTOR(int, getgrgid_r, u32 gid, __sanitizer_group *grp, char *buf,
COMMON_INTERCEPTOR_ENTER(ctx, getgrgid_r, gid, grp, buf, buflen, result);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(getgrgid_r)(gid, grp, buf, buflen, result);
if (!res) {
if (result && *result) unpoison_group(ctx, *result);
@@ -1354,14 +1441,14 @@ INTERCEPTOR(__sanitizer_passwd *, getpwent, int dummy) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, getpwent, dummy);
__sanitizer_passwd *res = REAL(getpwent)(dummy);
- if (res != 0) unpoison_passwd(ctx, res);
+ if (res) unpoison_passwd(ctx, res);
return res;
}
INTERCEPTOR(__sanitizer_group *, getgrent, int dummy) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, getgrent, dummy);
__sanitizer_group *res = REAL(getgrent)(dummy);
- if (res != 0) unpoison_group(ctx, res);;
+ if (res) unpoison_group(ctx, res);;
return res;
}
#define INIT_GETPWENT \
@@ -1376,14 +1463,14 @@ INTERCEPTOR(__sanitizer_passwd *, fgetpwent, void *fp) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, fgetpwent, fp);
__sanitizer_passwd *res = REAL(fgetpwent)(fp);
- if (res != 0) unpoison_passwd(ctx, res);
+ if (res) unpoison_passwd(ctx, res);
return res;
}
INTERCEPTOR(__sanitizer_group *, fgetgrent, void *fp) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, fgetgrent, fp);
__sanitizer_group *res = REAL(fgetgrent)(fp);
- if (res != 0) unpoison_group(ctx, res);
+ if (res) unpoison_group(ctx, res);
return res;
}
#define INIT_FGETPWENT \
@@ -1400,7 +1487,7 @@ INTERCEPTOR(int, getpwent_r, __sanitizer_passwd *pwbuf, char *buf,
COMMON_INTERCEPTOR_ENTER(ctx, getpwent_r, pwbuf, buf, buflen, pwbufp);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(getpwent_r)(pwbuf, buf, buflen, pwbufp);
if (!res) {
if (pwbufp && *pwbufp) unpoison_passwd(ctx, *pwbufp);
@@ -1415,7 +1502,7 @@ INTERCEPTOR(int, fgetpwent_r, void *fp, __sanitizer_passwd *pwbuf, char *buf,
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://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(fgetpwent_r)(fp, pwbuf, buf, buflen, pwbufp);
if (!res) {
if (pwbufp && *pwbufp) unpoison_passwd(ctx, *pwbufp);
@@ -1430,7 +1517,7 @@ INTERCEPTOR(int, getgrent_r, __sanitizer_group *pwbuf, char *buf, SIZE_T buflen,
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://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(getgrent_r)(pwbuf, buf, buflen, pwbufp);
if (!res) {
if (pwbufp && *pwbufp) unpoison_group(ctx, *pwbufp);
@@ -1445,7 +1532,7 @@ INTERCEPTOR(int, fgetgrent_r, void *fp, __sanitizer_group *pwbuf, char *buf,
COMMON_INTERCEPTOR_ENTER(ctx, fgetgrent_r, fp, pwbuf, buf, buflen, pwbufp);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(fgetgrent_r)(fp, pwbuf, buf, buflen, pwbufp);
if (!res) {
if (pwbufp && *pwbufp) unpoison_group(ctx, *pwbufp);
@@ -1502,7 +1589,7 @@ INTERCEPTOR(int, clock_getres, u32 clk_id, void *tp) {
COMMON_INTERCEPTOR_ENTER(ctx, clock_getres, clk_id, tp);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(clock_getres)(clk_id, tp);
if (!res && tp) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tp, struct_timespec_sz);
@@ -1514,7 +1601,7 @@ INTERCEPTOR(int, clock_gettime, u32 clk_id, void *tp) {
COMMON_INTERCEPTOR_ENTER(ctx, clock_gettime, clk_id, tp);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(clock_gettime)(clk_id, tp);
if (!res) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tp, struct_timespec_sz);
@@ -1541,7 +1628,7 @@ INTERCEPTOR(int, getitimer, int which, void *curr_value) {
COMMON_INTERCEPTOR_ENTER(ctx, getitimer, which, curr_value);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(getitimer)(which, curr_value);
if (!res && curr_value) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, curr_value, struct_itimerval_sz);
@@ -1555,7 +1642,7 @@ INTERCEPTOR(int, setitimer, int which, const void *new_value, void *old_value) {
COMMON_INTERCEPTOR_READ_RANGE(ctx, new_value, struct_itimerval_sz);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(setitimer)(which, new_value, old_value);
if (!res && old_value) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, old_value, struct_itimerval_sz);
@@ -1612,16 +1699,19 @@ static int wrapped_gl_stat(const char *s, void *st) {
return pglob_copy->gl_stat(s, st);
}
+static const __sanitizer_glob_t kGlobCopy = {
+ 0, 0, 0,
+ 0, wrapped_gl_closedir, wrapped_gl_readdir,
+ wrapped_gl_opendir, wrapped_gl_lstat, wrapped_gl_stat};
+
INTERCEPTOR(int, glob, const char *pattern, int flags,
int (*errfunc)(const char *epath, int eerrno),
__sanitizer_glob_t *pglob) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, glob, pattern, flags, errfunc, pglob);
COMMON_INTERCEPTOR_READ_STRING(ctx, pattern, 0);
- __sanitizer_glob_t glob_copy = {
- 0, 0, 0,
- 0, wrapped_gl_closedir, wrapped_gl_readdir,
- wrapped_gl_opendir, wrapped_gl_lstat, wrapped_gl_stat};
+ __sanitizer_glob_t glob_copy;
+ internal_memcpy(&glob_copy, &kGlobCopy, sizeof(glob_copy));
if (flags & glob_altdirfunc) {
Swap(pglob->gl_closedir, glob_copy.gl_closedir);
Swap(pglob->gl_readdir, glob_copy.gl_readdir);
@@ -1649,10 +1739,8 @@ INTERCEPTOR(int, glob64, const char *pattern, int flags,
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, glob64, pattern, flags, errfunc, pglob);
COMMON_INTERCEPTOR_READ_STRING(ctx, pattern, 0);
- __sanitizer_glob_t glob_copy = {
- 0, 0, 0,
- 0, wrapped_gl_closedir, wrapped_gl_readdir,
- wrapped_gl_opendir, wrapped_gl_lstat, wrapped_gl_stat};
+ __sanitizer_glob_t glob_copy;
+ internal_memcpy(&glob_copy, &kGlobCopy, sizeof(glob_copy));
if (flags & glob_altdirfunc) {
Swap(pglob->gl_closedir, glob_copy.gl_closedir);
Swap(pglob->gl_readdir, glob_copy.gl_readdir);
@@ -1689,7 +1777,7 @@ INTERCEPTOR_WITH_SUFFIX(int, wait, int *status) {
COMMON_INTERCEPTOR_ENTER(ctx, wait, status);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(wait)(status);
if (res != -1 && status)
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status));
@@ -1707,7 +1795,7 @@ INTERCEPTOR_WITH_SUFFIX(int, waitid, int idtype, int id, void *infop,
COMMON_INTERCEPTOR_ENTER(ctx, waitid, idtype, id, infop, options);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(waitid)(idtype, id, infop, options);
if (res != -1 && infop)
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, infop, siginfo_t_sz);
@@ -1718,7 +1806,7 @@ INTERCEPTOR_WITH_SUFFIX(int, waitpid, int pid, int *status, int options) {
COMMON_INTERCEPTOR_ENTER(ctx, waitpid, pid, status, options);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(waitpid)(pid, status, options);
if (res != -1 && status)
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status));
@@ -1729,7 +1817,7 @@ INTERCEPTOR(int, wait3, int *status, int options, void *rusage) {
COMMON_INTERCEPTOR_ENTER(ctx, wait3, status, options, rusage);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(wait3)(status, options, rusage);
if (res != -1) {
if (status) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status));
@@ -1743,7 +1831,7 @@ INTERCEPTOR(int, __wait4, int pid, int *status, int options, void *rusage) {
COMMON_INTERCEPTOR_ENTER(ctx, __wait4, pid, status, options, rusage);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(__wait4)(pid, status, options, rusage);
if (res != -1) {
if (status) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status));
@@ -1758,7 +1846,7 @@ INTERCEPTOR(int, wait4, int pid, int *status, int options, void *rusage) {
COMMON_INTERCEPTOR_ENTER(ctx, wait4, pid, status, options, rusage);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(wait4)(pid, status, options, rusage);
if (res != -1) {
if (status) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status));
@@ -1787,7 +1875,7 @@ INTERCEPTOR(char *, inet_ntop, int af, const void *src, char *dst, u32 size) {
// FIXME: figure out read size based on the address family.
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
char *res = REAL(inet_ntop)(af, src, dst, size);
if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
return res;
@@ -1799,7 +1887,7 @@ INTERCEPTOR(int, inet_pton, int af, const char *src, void *dst) {
// FIXME: figure out read size based on the address family.
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(inet_pton)(af, src, dst);
if (res == 1) {
uptr sz = __sanitizer_in_addr_sz(af);
@@ -1821,7 +1909,7 @@ INTERCEPTOR(int, inet_aton, const char *cp, void *dst) {
if (cp) COMMON_INTERCEPTOR_READ_RANGE(ctx, cp, REAL(strlen)(cp) + 1);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(inet_aton)(cp, dst);
if (res != 0) {
uptr sz = __sanitizer_in_addr_sz(af_inet);
@@ -1840,7 +1928,7 @@ INTERCEPTOR(int, pthread_getschedparam, uptr thread, int *policy, int *param) {
COMMON_INTERCEPTOR_ENTER(ctx, pthread_getschedparam, thread, policy, param);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(pthread_getschedparam)(thread, policy, param);
if (res == 0) {
if (policy) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, policy, sizeof(*policy));
@@ -1867,7 +1955,7 @@ INTERCEPTOR(int, getaddrinfo, char *node, char *service,
COMMON_INTERCEPTOR_READ_RANGE(ctx, hints, sizeof(__sanitizer_addrinfo));
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(getaddrinfo)(node, service, hints, out);
if (res == 0 && out) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, out, sizeof(*out));
@@ -1899,7 +1987,7 @@ INTERCEPTOR(int, getnameinfo, void *sockaddr, unsigned salen, char *host,
// There is padding in in_addr that may make this too noisy
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res =
REAL(getnameinfo)(sockaddr, salen, host, hostlen, serv, servlen, flags);
if (res == 0) {
@@ -1923,7 +2011,7 @@ INTERCEPTOR(int, getsockname, int sock_fd, void *addr, int *addrlen) {
int addrlen_in = *addrlen;
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(getsockname)(sock_fd, addr, addrlen);
if (res == 0) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, Min(addrlen_in, *addrlen));
@@ -2009,7 +2097,7 @@ INTERCEPTOR(int, gethostbyname_r, char *name, struct __sanitizer_hostent *ret,
h_errnop);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(gethostbyname_r)(name, ret, buf, buflen, result, h_errnop);
if (result) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
@@ -2032,7 +2120,7 @@ INTERCEPTOR(int, gethostent_r, struct __sanitizer_hostent *ret, char *buf,
h_errnop);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(gethostent_r)(ret, buf, buflen, result, h_errnop);
if (result) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
@@ -2058,7 +2146,7 @@ INTERCEPTOR(int, gethostbyaddr_r, void *addr, int len, int type,
COMMON_INTERCEPTOR_READ_RANGE(ctx, addr, len);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(gethostbyaddr_r)(addr, len, type, ret, buf, buflen, result,
h_errnop);
if (result) {
@@ -2084,7 +2172,7 @@ INTERCEPTOR(int, gethostbyname2_r, char *name, int af,
result, h_errnop);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res =
REAL(gethostbyname2_r)(name, af, ret, buf, buflen, result, h_errnop);
if (result) {
@@ -2110,7 +2198,7 @@ INTERCEPTOR(int, getsockopt, int sockfd, int level, int optname, void *optval,
if (optlen) COMMON_INTERCEPTOR_READ_RANGE(ctx, optlen, sizeof(*optlen));
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(getsockopt)(sockfd, level, optname, optval, optlen);
if (res == 0)
if (optval && optlen) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, optval, *optlen);
@@ -2154,7 +2242,7 @@ INTERCEPTOR(int, accept4, int fd, void *addr, unsigned *addrlen, int f) {
}
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int fd2 = REAL(accept4)(fd, addr, addrlen, f);
if (fd2 >= 0) {
if (fd >= 0) COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, fd2);
@@ -2174,7 +2262,7 @@ INTERCEPTOR(double, modf, double x, double *iptr) {
COMMON_INTERCEPTOR_ENTER(ctx, modf, x, iptr);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
double res = REAL(modf)(x, iptr);
if (iptr) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, iptr, sizeof(*iptr));
@@ -2186,7 +2274,7 @@ INTERCEPTOR(float, modff, float x, float *iptr) {
COMMON_INTERCEPTOR_ENTER(ctx, modff, x, iptr);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
float res = REAL(modff)(x, iptr);
if (iptr) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, iptr, sizeof(*iptr));
@@ -2198,7 +2286,7 @@ INTERCEPTOR(long double, modfl, long double x, long double *iptr) {
COMMON_INTERCEPTOR_ENTER(ctx, modfl, x, iptr);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
long double res = REAL(modfl)(x, iptr);
if (iptr) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, iptr, sizeof(*iptr));
@@ -2233,7 +2321,7 @@ INTERCEPTOR(SSIZE_T, recvmsg, int fd, struct __sanitizer_msghdr *msg,
COMMON_INTERCEPTOR_ENTER(ctx, recvmsg, fd, msg, flags);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
SSIZE_T res = REAL(recvmsg)(fd, msg, flags);
if (res >= 0) {
if (fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
@@ -2257,7 +2345,7 @@ INTERCEPTOR(int, getpeername, int sockfd, void *addr, unsigned *addrlen) {
if (addrlen) addr_sz = *addrlen;
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(getpeername)(sockfd, addr, addrlen);
if (!res && addr && addrlen)
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, Min(addr_sz, *addrlen));
@@ -2273,7 +2361,7 @@ INTERCEPTOR(int, sysinfo, void *info) {
void *ctx;
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
COMMON_INTERCEPTOR_ENTER(ctx, sysinfo, info);
int res = REAL(sysinfo)(info);
if (!res && info)
@@ -2291,7 +2379,7 @@ INTERCEPTOR(__sanitizer_dirent *, opendir, const char *path) {
COMMON_INTERCEPTOR_ENTER(ctx, opendir, path);
COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
__sanitizer_dirent *res = REAL(opendir)(path);
- if (res != 0)
+ if (res)
COMMON_INTERCEPTOR_DIR_ACQUIRE(ctx, path);
return res;
}
@@ -2301,7 +2389,7 @@ INTERCEPTOR(__sanitizer_dirent *, readdir, void *dirp) {
COMMON_INTERCEPTOR_ENTER(ctx, readdir, dirp);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
__sanitizer_dirent *res = REAL(readdir)(dirp);
if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, res->d_reclen);
return res;
@@ -2313,7 +2401,7 @@ INTERCEPTOR(int, readdir_r, void *dirp, __sanitizer_dirent *entry,
COMMON_INTERCEPTOR_ENTER(ctx, readdir_r, dirp, entry, result);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(readdir_r)(dirp, entry, result);
if (!res) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
@@ -2337,7 +2425,7 @@ INTERCEPTOR(__sanitizer_dirent64 *, readdir64, void *dirp) {
COMMON_INTERCEPTOR_ENTER(ctx, readdir64, dirp);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
__sanitizer_dirent64 *res = REAL(readdir64)(dirp);
if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, res->d_reclen);
return res;
@@ -2349,7 +2437,7 @@ INTERCEPTOR(int, readdir64_r, void *dirp, __sanitizer_dirent64 *entry,
COMMON_INTERCEPTOR_ENTER(ctx, readdir64_r, dirp, entry, result);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(readdir64_r)(dirp, entry, result);
if (!res) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
@@ -2369,6 +2457,7 @@ INTERCEPTOR(int, readdir64_r, void *dirp, __sanitizer_dirent64 *entry,
INTERCEPTOR(uptr, ptrace, int request, int pid, void *addr, void *data) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, ptrace, request, pid, addr, data);
+ __sanitizer_iovec local_iovec;
if (data) {
if (request == ptrace_setregs)
@@ -2377,17 +2466,25 @@ INTERCEPTOR(uptr, ptrace, int request, int pid, void *addr, void *data) {
COMMON_INTERCEPTOR_READ_RANGE(ctx, data, struct_user_fpregs_struct_sz);
else if (request == ptrace_setfpxregs)
COMMON_INTERCEPTOR_READ_RANGE(ctx, data, struct_user_fpxregs_struct_sz);
+ else if (request == ptrace_setvfpregs)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, data, struct_user_vfpregs_struct_sz);
else if (request == ptrace_setsiginfo)
COMMON_INTERCEPTOR_READ_RANGE(ctx, data, siginfo_t_sz);
- else if (request == ptrace_setregset) {
- __sanitizer_iovec *iov = (__sanitizer_iovec *)data;
- COMMON_INTERCEPTOR_READ_RANGE(ctx, iov->iov_base, iov->iov_len);
+ // Some kernel might zero the iovec::iov_base in case of invalid
+ // write access. In this case copy the invalid address for further
+ // inspection.
+ else if (request == ptrace_setregset || request == ptrace_getregset) {
+ __sanitizer_iovec *iovec = (__sanitizer_iovec*)data;
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, iovec, sizeof(*iovec));
+ local_iovec = *iovec;
+ if (request == ptrace_setregset)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, iovec->iov_base, iovec->iov_len);
}
}
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
uptr res = REAL(ptrace)(request, pid, addr, data);
if (!res && data) {
@@ -2399,13 +2496,17 @@ INTERCEPTOR(uptr, ptrace, int request, int pid, void *addr, void *data) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, struct_user_fpregs_struct_sz);
else if (request == ptrace_getfpxregs)
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, struct_user_fpxregs_struct_sz);
+ else if (request == ptrace_getvfpregs)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, struct_user_vfpregs_struct_sz);
else if (request == ptrace_getsiginfo)
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, siginfo_t_sz);
else if (request == ptrace_geteventmsg)
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, sizeof(unsigned long));
else if (request == ptrace_getregset) {
- __sanitizer_iovec *iov = (__sanitizer_iovec *)data;
- COMMON_INTERCEPTOR_WRITE_RANGE(ctx, iov->iov_base, iov->iov_len);
+ __sanitizer_iovec *iovec = (__sanitizer_iovec*)data;
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, iovec, sizeof(*iovec));
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, local_iovec.iov_base,
+ local_iovec.iov_len);
}
}
return res;
@@ -2438,7 +2539,7 @@ INTERCEPTOR(char *, getcwd, char *buf, SIZE_T size) {
COMMON_INTERCEPTOR_ENTER(ctx, getcwd, buf, size);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
char *res = REAL(getcwd)(buf, size);
if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
return res;
@@ -2454,7 +2555,7 @@ INTERCEPTOR(char *, get_current_dir_name, int fake) {
COMMON_INTERCEPTOR_ENTER(ctx, get_current_dir_name, fake);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
char *res = REAL(get_current_dir_name)(fake);
if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
return res;
@@ -2481,7 +2582,7 @@ UNUSED static inline void FixRealStrtolEndptr(const char *nptr, char **endptr) {
UNUSED static inline void StrtolFixAndCheck(void *ctx, const char *nptr,
char **endptr, char *real_endptr, int base) {
- if (endptr != 0) {
+ if (endptr) {
*endptr = real_endptr;
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, endptr, sizeof(*endptr));
}
@@ -2503,7 +2604,7 @@ INTERCEPTOR(INTMAX_T, strtoimax, const char *nptr, char **endptr, int base) {
COMMON_INTERCEPTOR_ENTER(ctx, strtoimax, nptr, endptr, base);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
char *real_endptr;
INTMAX_T res = REAL(strtoimax)(nptr, &real_endptr, base);
StrtolFixAndCheck(ctx, nptr, endptr, real_endptr, base);
@@ -2515,7 +2616,7 @@ INTERCEPTOR(INTMAX_T, strtoumax, const char *nptr, char **endptr, int base) {
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://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
char *real_endptr;
INTMAX_T res = REAL(strtoumax)(nptr, &real_endptr, base);
StrtolFixAndCheck(ctx, nptr, endptr, real_endptr, base);
@@ -2535,7 +2636,7 @@ INTERCEPTOR(SIZE_T, mbstowcs, wchar_t *dest, const char *src, SIZE_T len) {
COMMON_INTERCEPTOR_ENTER(ctx, mbstowcs, dest, src, len);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
SIZE_T res = REAL(mbstowcs)(dest, src, len);
if (res != (SIZE_T) - 1 && dest) {
SIZE_T write_cnt = res + (res < len);
@@ -2552,7 +2653,7 @@ INTERCEPTOR(SIZE_T, mbsrtowcs, wchar_t *dest, const char **src, SIZE_T len,
if (ps) COMMON_INTERCEPTOR_READ_RANGE(ctx, ps, mbstate_t_sz);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
SIZE_T res = REAL(mbsrtowcs)(dest, src, len, ps);
if (res != (SIZE_T)(-1) && dest && src) {
// This function, and several others, may or may not write the terminating
@@ -2582,7 +2683,7 @@ INTERCEPTOR(SIZE_T, mbsnrtowcs, wchar_t *dest, const char **src, SIZE_T nms,
if (ps) COMMON_INTERCEPTOR_READ_RANGE(ctx, ps, mbstate_t_sz);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
SIZE_T res = REAL(mbsnrtowcs)(dest, src, nms, len, ps);
if (res != (SIZE_T)(-1) && dest && src) {
SIZE_T write_cnt = res + !*src;
@@ -2602,7 +2703,7 @@ INTERCEPTOR(SIZE_T, wcstombs, char *dest, const wchar_t *src, SIZE_T len) {
COMMON_INTERCEPTOR_ENTER(ctx, wcstombs, dest, src, len);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
SIZE_T res = REAL(wcstombs)(dest, src, len);
if (res != (SIZE_T) - 1 && dest) {
SIZE_T write_cnt = res + (res < len);
@@ -2619,7 +2720,7 @@ INTERCEPTOR(SIZE_T, wcsrtombs, char *dest, const wchar_t **src, SIZE_T len,
if (ps) COMMON_INTERCEPTOR_READ_RANGE(ctx, ps, mbstate_t_sz);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
SIZE_T res = REAL(wcsrtombs)(dest, src, len, ps);
if (res != (SIZE_T) - 1 && dest && src) {
SIZE_T write_cnt = res + !*src;
@@ -2647,9 +2748,9 @@ INTERCEPTOR(SIZE_T, wcsnrtombs, char *dest, const wchar_t **src, SIZE_T nms,
if (ps) COMMON_INTERCEPTOR_READ_RANGE(ctx, ps, mbstate_t_sz);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
SIZE_T res = REAL(wcsnrtombs)(dest, src, nms, len, ps);
- if (res != (SIZE_T) - 1 && dest && src) {
+ if (res != ((SIZE_T)-1) && dest && src) {
SIZE_T write_cnt = res + !*src;
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, write_cnt);
}
@@ -2661,13 +2762,35 @@ INTERCEPTOR(SIZE_T, wcsnrtombs, char *dest, const wchar_t **src, SIZE_T nms,
#define INIT_WCSNRTOMBS
#endif
+
+#if SANITIZER_INTERCEPT_WCRTOMB
+INTERCEPTOR(SIZE_T, wcrtomb, char *dest, wchar_t src, void *ps) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, wcrtomb, dest, src, ps);
+ if (ps) COMMON_INTERCEPTOR_READ_RANGE(ctx, ps, mbstate_t_sz);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ SIZE_T res = REAL(wcrtomb)(dest, src, ps);
+ if (res != ((SIZE_T)-1) && dest) {
+ SIZE_T write_cnt = res;
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, write_cnt);
+ }
+ return res;
+}
+
+#define INIT_WCRTOMB COMMON_INTERCEPT_FUNCTION(wcrtomb);
+#else
+#define INIT_WCRTOMB
+#endif
+
#if SANITIZER_INTERCEPT_TCGETATTR
INTERCEPTOR(int, tcgetattr, int fd, void *termios_p) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, tcgetattr, fd, termios_p);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(tcgetattr)(fd, termios_p);
if (!res && termios_p)
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, termios_p, struct_termios_sz);
@@ -2689,7 +2812,7 @@ INTERCEPTOR(char *, realpath, const char *path, char *resolved_path) {
// version of a versioned symbol. For realpath(), this gives us something
// (called __old_realpath) that does not handle NULL in the second argument.
// Handle it as part of the interceptor.
- char *allocated_path = 0;
+ char *allocated_path = nullptr;
if (!resolved_path)
allocated_path = resolved_path = (char *)WRAP(malloc)(path_max + 1);
@@ -2724,7 +2847,7 @@ INTERCEPTOR(SIZE_T, confstr, int name, char *buf, SIZE_T len) {
COMMON_INTERCEPTOR_ENTER(ctx, confstr, name, buf, len);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
SIZE_T res = REAL(confstr)(name, buf, len);
if (buf && res)
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, res < len ? res : len);
@@ -2741,7 +2864,7 @@ INTERCEPTOR(int, sched_getaffinity, int pid, SIZE_T cpusetsize, void *mask) {
COMMON_INTERCEPTOR_ENTER(ctx, sched_getaffinity, pid, cpusetsize, mask);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(sched_getaffinity)(pid, cpusetsize, mask);
if (mask && !res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, mask, cpusetsize);
return res;
@@ -2783,7 +2906,7 @@ INTERCEPTOR(char *, strerror_r, int errnum, char *buf, SIZE_T buflen) {
COMMON_INTERCEPTOR_ENTER(ctx, strerror_r, errnum, buf, buflen);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
char *res = REAL(strerror_r)(errnum, buf, buflen);
// There are 2 versions of strerror_r:
// * POSIX version returns 0 on success, negative error code on failure,
@@ -2814,7 +2937,7 @@ INTERCEPTOR(int, __xpg_strerror_r, int errnum, char *buf, SIZE_T buflen) {
COMMON_INTERCEPTOR_ENTER(ctx, __xpg_strerror_r, errnum, buf, buflen);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(__xpg_strerror_r)(errnum, buf, buflen);
// This version always returns a null-terminated string.
if (buf && buflen)
@@ -2859,11 +2982,12 @@ INTERCEPTOR(int, scandir, char *dirp, __sanitizer_dirent ***namelist,
scandir_compar = compar;
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
- int res = REAL(scandir)(dirp, namelist, filter ? wrapped_scandir_filter : 0,
- compar ? wrapped_scandir_compar : 0);
- scandir_filter = 0;
- scandir_compar = 0;
+ // https://github.com/google/sanitizers/issues/321.
+ int res = REAL(scandir)(dirp, namelist,
+ filter ? wrapped_scandir_filter : nullptr,
+ compar ? wrapped_scandir_compar : nullptr);
+ scandir_filter = nullptr;
+ scandir_compar = nullptr;
if (namelist && res > 0) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, namelist, sizeof(*namelist));
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *namelist, sizeof(**namelist) * res);
@@ -2911,12 +3035,13 @@ INTERCEPTOR(int, scandir64, char *dirp, __sanitizer_dirent64 ***namelist,
scandir64_compar = compar;
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res =
- REAL(scandir64)(dirp, namelist, filter ? wrapped_scandir64_filter : 0,
- compar ? wrapped_scandir64_compar : 0);
- scandir64_filter = 0;
- scandir64_compar = 0;
+ REAL(scandir64)(dirp, namelist,
+ filter ? wrapped_scandir64_filter : nullptr,
+ compar ? wrapped_scandir64_compar : nullptr);
+ scandir64_filter = nullptr;
+ scandir64_compar = nullptr;
if (namelist && res > 0) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, namelist, sizeof(*namelist));
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *namelist, sizeof(**namelist) * res);
@@ -2937,7 +3062,7 @@ INTERCEPTOR(int, getgroups, int size, u32 *lst) {
COMMON_INTERCEPTOR_ENTER(ctx, getgroups, size, lst);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(getgroups)(size, lst);
if (res && lst) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, lst, res * sizeof(*lst));
return res;
@@ -3003,7 +3128,7 @@ INTERCEPTOR(int, wordexp, char *s, __sanitizer_wordexp_t *p, int flags) {
if (s) COMMON_INTERCEPTOR_READ_RANGE(ctx, s, REAL(strlen)(s) + 1);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(wordexp)(s, p, flags);
if (!res && p) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, sizeof(*p));
@@ -3029,7 +3154,7 @@ INTERCEPTOR(int, sigwait, __sanitizer_sigset_t *set, int *sig) {
// FIXME: read sigset_t when all of sigemptyset, etc are intercepted
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(sigwait)(set, sig);
if (!res && sig) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sig, sizeof(*sig));
return res;
@@ -3046,7 +3171,7 @@ INTERCEPTOR(int, sigwaitinfo, __sanitizer_sigset_t *set, void *info) {
// FIXME: read sigset_t when all of sigemptyset, etc are intercepted
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(sigwaitinfo)(set, info);
if (res > 0 && info) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, info, siginfo_t_sz);
return res;
@@ -3065,7 +3190,7 @@ INTERCEPTOR(int, sigtimedwait, __sanitizer_sigset_t *set, void *info,
// FIXME: read sigset_t when all of sigemptyset, etc are intercepted
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(sigtimedwait)(set, info, timeout);
if (res > 0 && info) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, info, siginfo_t_sz);
return res;
@@ -3081,7 +3206,7 @@ INTERCEPTOR(int, sigemptyset, __sanitizer_sigset_t *set) {
COMMON_INTERCEPTOR_ENTER(ctx, sigemptyset, set);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(sigemptyset)(set);
if (!res && set) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, set, sizeof(*set));
return res;
@@ -3092,7 +3217,7 @@ INTERCEPTOR(int, sigfillset, __sanitizer_sigset_t *set) {
COMMON_INTERCEPTOR_ENTER(ctx, sigfillset, set);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(sigfillset)(set);
if (!res && set) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, set, sizeof(*set));
return res;
@@ -3110,7 +3235,7 @@ INTERCEPTOR(int, sigpending, __sanitizer_sigset_t *set) {
COMMON_INTERCEPTOR_ENTER(ctx, sigpending, set);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(sigpending)(set);
if (!res && set) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, set, sizeof(*set));
return res;
@@ -3128,7 +3253,7 @@ INTERCEPTOR(int, sigprocmask, int how, __sanitizer_sigset_t *set,
// FIXME: read sigset_t when all of sigemptyset, etc are intercepted
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(sigprocmask)(how, set, oldset);
if (!res && oldset)
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, oldset, sizeof(*oldset));
@@ -3145,7 +3270,7 @@ INTERCEPTOR(int, backtrace, void **buffer, int size) {
COMMON_INTERCEPTOR_ENTER(ctx, backtrace, buffer, size);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(backtrace)(buffer, size);
if (res && buffer)
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buffer, res * sizeof(*buffer));
@@ -3159,7 +3284,7 @@ INTERCEPTOR(char **, backtrace_symbols, void **buffer, int size) {
COMMON_INTERCEPTOR_READ_RANGE(ctx, buffer, size * sizeof(*buffer));
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
char **res = REAL(backtrace_symbols)(buffer, size);
if (res && size) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, size * sizeof(*res));
@@ -3267,7 +3392,7 @@ INTERCEPTOR(int, statfs, char *path, void *buf) {
if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(statfs)(path, buf);
if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statfs_sz);
return res;
@@ -3277,7 +3402,7 @@ INTERCEPTOR(int, fstatfs, int fd, void *buf) {
COMMON_INTERCEPTOR_ENTER(ctx, fstatfs, fd, buf);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(fstatfs)(fd, buf);
if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statfs_sz);
return res;
@@ -3296,7 +3421,7 @@ INTERCEPTOR(int, statfs64, char *path, void *buf) {
if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(statfs64)(path, buf);
if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statfs64_sz);
return res;
@@ -3306,7 +3431,7 @@ INTERCEPTOR(int, fstatfs64, int fd, void *buf) {
COMMON_INTERCEPTOR_ENTER(ctx, fstatfs64, fd, buf);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(fstatfs64)(fd, buf);
if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statfs64_sz);
return res;
@@ -3325,7 +3450,7 @@ INTERCEPTOR(int, statvfs, char *path, void *buf) {
if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(statvfs)(path, buf);
if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs_sz);
return res;
@@ -3335,7 +3460,7 @@ INTERCEPTOR(int, fstatvfs, int fd, void *buf) {
COMMON_INTERCEPTOR_ENTER(ctx, fstatvfs, fd, buf);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(fstatvfs)(fd, buf);
if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs_sz);
return res;
@@ -3354,7 +3479,7 @@ INTERCEPTOR(int, statvfs64, char *path, void *buf) {
if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(statvfs64)(path, buf);
if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs64_sz);
return res;
@@ -3364,7 +3489,7 @@ INTERCEPTOR(int, fstatvfs64, int fd, void *buf) {
COMMON_INTERCEPTOR_ENTER(ctx, fstatvfs64, fd, buf);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(fstatvfs64)(fd, buf);
if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs64_sz);
return res;
@@ -3420,7 +3545,7 @@ INTERCEPTOR(int, ether_ntohost, char *hostname, __sanitizer_ether_addr *addr) {
if (addr) COMMON_INTERCEPTOR_READ_RANGE(ctx, addr, sizeof(*addr));
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(ether_ntohost)(hostname, addr);
if (!res && hostname)
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, hostname, REAL(strlen)(hostname) + 1);
@@ -3433,7 +3558,7 @@ INTERCEPTOR(int, ether_hostton, char *hostname, __sanitizer_ether_addr *addr) {
COMMON_INTERCEPTOR_READ_RANGE(ctx, hostname, REAL(strlen)(hostname) + 1);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(ether_hostton)(hostname, addr);
if (!res && addr) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, sizeof(*addr));
return res;
@@ -3445,7 +3570,7 @@ INTERCEPTOR(int, ether_line, char *line, __sanitizer_ether_addr *addr,
if (line) COMMON_INTERCEPTOR_READ_RANGE(ctx, line, REAL(strlen)(line) + 1);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(ether_line)(line, addr, hostname);
if (!res) {
if (addr) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, sizeof(*addr));
@@ -3469,7 +3594,7 @@ INTERCEPTOR(char *, ether_ntoa_r, __sanitizer_ether_addr *addr, char *buf) {
if (addr) COMMON_INTERCEPTOR_READ_RANGE(ctx, addr, sizeof(*addr));
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
char *res = REAL(ether_ntoa_r)(addr, buf);
if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
return res;
@@ -3481,7 +3606,7 @@ INTERCEPTOR(__sanitizer_ether_addr *, ether_aton_r, char *buf,
if (buf) COMMON_INTERCEPTOR_READ_RANGE(ctx, buf, REAL(strlen)(buf) + 1);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
__sanitizer_ether_addr *res = REAL(ether_aton_r)(buf, addr);
if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, sizeof(*res));
return res;
@@ -3499,7 +3624,7 @@ INTERCEPTOR(int, shmctl, int shmid, int cmd, void *buf) {
COMMON_INTERCEPTOR_ENTER(ctx, shmctl, shmid, cmd, buf);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(shmctl)(shmid, cmd, buf);
if (res >= 0) {
unsigned sz = 0;
@@ -3524,7 +3649,7 @@ INTERCEPTOR(int, random_r, void *buf, u32 *result) {
COMMON_INTERCEPTOR_ENTER(ctx, random_r, buf, result);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(random_r)(buf, result);
if (!res && result)
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
@@ -3537,7 +3662,7 @@ INTERCEPTOR(int, random_r, void *buf, u32 *result) {
// FIXME: under ASan the REAL() call below may write to freed memory and corrupt
// its metadata. See
-// https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+// https://github.com/google/sanitizers/issues/321.
#if SANITIZER_INTERCEPT_PTHREAD_ATTR_GET || \
SANITIZER_INTERCEPT_PTHREAD_ATTR_GETINHERITSSCHED || \
SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GET || \
@@ -3576,7 +3701,7 @@ INTERCEPTOR(int, pthread_attr_getstack, void *attr, void **addr, SIZE_T *size) {
COMMON_INTERCEPTOR_ENTER(ctx, pthread_attr_getstack, attr, addr, size);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(pthread_attr_getstack)(attr, addr, size);
if (!res) {
if (addr) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, sizeof(*addr));
@@ -3625,7 +3750,7 @@ INTERCEPTOR(int, pthread_attr_getaffinity_np, void *attr, SIZE_T cpusetsize,
cpuset);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(pthread_attr_getaffinity_np)(attr, cpusetsize, cpuset);
if (!res && cpusetsize && cpuset)
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cpuset, cpusetsize);
@@ -3735,7 +3860,7 @@ INTERCEPTOR(char *, tmpnam, char *s) {
if (s)
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, s, REAL(strlen)(s) + 1);
else
COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, REAL(strlen)(res) + 1);
@@ -3753,7 +3878,7 @@ INTERCEPTOR(char *, tmpnam_r, char *s) {
COMMON_INTERCEPTOR_ENTER(ctx, tmpnam_r, s);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
char *res = REAL(tmpnam_r)(s);
if (res && s) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, s, REAL(strlen)(s) + 1);
return res;
@@ -3797,7 +3922,7 @@ INTERCEPTOR(void, sincos, double x, double *sin, double *cos) {
COMMON_INTERCEPTOR_ENTER(ctx, sincos, x, sin, cos);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
REAL(sincos)(x, sin, cos);
if (sin) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sin, sizeof(*sin));
if (cos) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cos, sizeof(*cos));
@@ -3807,7 +3932,7 @@ INTERCEPTOR(void, sincosf, float x, float *sin, float *cos) {
COMMON_INTERCEPTOR_ENTER(ctx, sincosf, x, sin, cos);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
REAL(sincosf)(x, sin, cos);
if (sin) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sin, sizeof(*sin));
if (cos) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cos, sizeof(*cos));
@@ -3817,7 +3942,7 @@ INTERCEPTOR(void, sincosl, long double x, long double *sin, long double *cos) {
COMMON_INTERCEPTOR_ENTER(ctx, sincosl, x, sin, cos);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
REAL(sincosl)(x, sin, cos);
if (sin) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sin, sizeof(*sin));
if (cos) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cos, sizeof(*cos));
@@ -3836,7 +3961,7 @@ INTERCEPTOR(double, remquo, double x, double y, int *quo) {
COMMON_INTERCEPTOR_ENTER(ctx, remquo, x, y, quo);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
double res = REAL(remquo)(x, y, quo);
if (quo) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, quo, sizeof(*quo));
return res;
@@ -3846,7 +3971,7 @@ INTERCEPTOR(float, remquof, float x, float y, int *quo) {
COMMON_INTERCEPTOR_ENTER(ctx, remquof, x, y, quo);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
float res = REAL(remquof)(x, y, quo);
if (quo) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, quo, sizeof(*quo));
return res;
@@ -3856,7 +3981,7 @@ INTERCEPTOR(long double, remquol, long double x, long double y, int *quo) {
COMMON_INTERCEPTOR_ENTER(ctx, remquol, x, y, quo);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
long double res = REAL(remquol)(x, y, quo);
if (quo) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, quo, sizeof(*quo));
return res;
@@ -3906,7 +4031,7 @@ INTERCEPTOR(double, lgamma_r, double x, int *signp) {
COMMON_INTERCEPTOR_ENTER(ctx, lgamma_r, x, signp);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
double res = REAL(lgamma_r)(x, signp);
if (signp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, signp, sizeof(*signp));
return res;
@@ -3916,7 +4041,7 @@ INTERCEPTOR(float, lgammaf_r, float x, int *signp) {
COMMON_INTERCEPTOR_ENTER(ctx, lgammaf_r, x, signp);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
float res = REAL(lgammaf_r)(x, signp);
if (signp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, signp, sizeof(*signp));
return res;
@@ -3934,7 +4059,7 @@ INTERCEPTOR(long double, lgammal_r, long double x, int *signp) {
COMMON_INTERCEPTOR_ENTER(ctx, lgammal_r, x, signp);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
long double res = REAL(lgammal_r)(x, signp);
if (signp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, signp, sizeof(*signp));
return res;
@@ -3950,7 +4075,7 @@ INTERCEPTOR(int, drand48_r, void *buffer, double *result) {
COMMON_INTERCEPTOR_ENTER(ctx, drand48_r, buffer, result);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(drand48_r)(buffer, result);
if (result) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
return res;
@@ -3960,7 +4085,7 @@ INTERCEPTOR(int, lrand48_r, void *buffer, long *result) {
COMMON_INTERCEPTOR_ENTER(ctx, lrand48_r, buffer, result);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(lrand48_r)(buffer, result);
if (result) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
return res;
@@ -3990,7 +4115,7 @@ INTERCEPTOR(SSIZE_T, getline, char **lineptr, SIZE_T *n, void *stream) {
COMMON_INTERCEPTOR_ENTER(ctx, getline, lineptr, n, stream);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
SSIZE_T res = REAL(getline)(lineptr, n, stream);
if (res > 0) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, lineptr, sizeof(*lineptr));
@@ -4002,7 +4127,7 @@ INTERCEPTOR(SSIZE_T, getline, char **lineptr, SIZE_T *n, void *stream) {
// FIXME: under ASan the call below may write to freed memory and corrupt its
// metadata. See
-// https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+// https://github.com/google/sanitizers/issues/321.
#define GETDELIM_INTERCEPTOR_IMPL(vname) \
{ \
void *ctx; \
@@ -4046,10 +4171,10 @@ INTERCEPTOR(SIZE_T, iconv, void *cd, char **inbuf, SIZE_T *inbytesleft,
COMMON_INTERCEPTOR_READ_RANGE(ctx, *inbuf, *inbytesleft);
if (outbytesleft)
COMMON_INTERCEPTOR_READ_RANGE(ctx, outbytesleft, sizeof(*outbytesleft));
- void *outbuf_orig = outbuf ? *outbuf : 0;
+ void *outbuf_orig = outbuf ? *outbuf : nullptr;
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
SIZE_T res = REAL(iconv)(cd, inbuf, inbytesleft, outbuf, outbytesleft);
if (res != (SIZE_T) - 1 && outbuf && *outbuf > outbuf_orig) {
SIZE_T sz = (char *)*outbuf - (char *)outbuf_orig;
@@ -4068,7 +4193,7 @@ INTERCEPTOR(__sanitizer_clock_t, times, void *tms) {
COMMON_INTERCEPTOR_ENTER(ctx, times, tms);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
__sanitizer_clock_t res = REAL(times)(tms);
if (res != (__sanitizer_clock_t)-1 && tms)
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tms, struct_tms_sz);
@@ -4111,7 +4236,7 @@ INTERCEPTOR(SSIZE_T, listxattr, const char *path, char *list, SIZE_T size) {
if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
SSIZE_T res = REAL(listxattr)(path, list, size);
// Here and below, size == 0 is a special case where nothing is written to the
// buffer, and res contains the desired buffer size.
@@ -4124,7 +4249,7 @@ INTERCEPTOR(SSIZE_T, llistxattr, const char *path, char *list, SIZE_T size) {
if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
SSIZE_T res = REAL(llistxattr)(path, list, size);
if (size && res > 0 && list) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, list, res);
return res;
@@ -4134,7 +4259,7 @@ INTERCEPTOR(SSIZE_T, flistxattr, int fd, char *list, SIZE_T size) {
COMMON_INTERCEPTOR_ENTER(ctx, flistxattr, fd, list, size);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
SSIZE_T res = REAL(flistxattr)(fd, list, size);
if (size && res > 0 && list) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, list, res);
return res;
@@ -4156,7 +4281,7 @@ INTERCEPTOR(SSIZE_T, getxattr, const char *path, const char *name, char *value,
if (name) COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
SSIZE_T res = REAL(getxattr)(path, name, value, size);
if (size && res > 0 && value) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, value, res);
return res;
@@ -4169,7 +4294,7 @@ INTERCEPTOR(SSIZE_T, lgetxattr, const char *path, const char *name, char *value,
if (name) COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
SSIZE_T res = REAL(lgetxattr)(path, name, value, size);
if (size && res > 0 && value) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, value, res);
return res;
@@ -4181,7 +4306,7 @@ INTERCEPTOR(SSIZE_T, fgetxattr, int fd, const char *name, char *value,
if (name) COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
SSIZE_T res = REAL(fgetxattr)(fd, name, value, size);
if (size && res > 0 && value) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, value, res);
return res;
@@ -4200,7 +4325,7 @@ INTERCEPTOR(int, getresuid, void *ruid, void *euid, void *suid) {
COMMON_INTERCEPTOR_ENTER(ctx, getresuid, ruid, euid, suid);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(getresuid)(ruid, euid, suid);
if (res >= 0) {
if (ruid) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ruid, uid_t_sz);
@@ -4214,7 +4339,7 @@ INTERCEPTOR(int, getresgid, void *rgid, void *egid, void *sgid) {
COMMON_INTERCEPTOR_ENTER(ctx, getresgid, rgid, egid, sgid);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(getresgid)(rgid, egid, sgid);
if (res >= 0) {
if (rgid) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, rgid, gid_t_sz);
@@ -4239,7 +4364,7 @@ INTERCEPTOR(int, getifaddrs, __sanitizer_ifaddrs **ifap) {
COMMON_INTERCEPTOR_ENTER(ctx, getifaddrs, ifap);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(getifaddrs)(ifap);
if (res == 0 && ifap) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ifap, sizeof(void *));
@@ -4275,7 +4400,7 @@ INTERCEPTOR(char *, if_indextoname, unsigned int ifindex, char* ifname) {
COMMON_INTERCEPTOR_ENTER(ctx, if_indextoname, ifindex, ifname);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
char *res = REAL(if_indextoname)(ifindex, ifname);
if (res && ifname)
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ifname, REAL(strlen)(ifname) + 1);
@@ -4303,7 +4428,7 @@ INTERCEPTOR(int, capget, void *hdrp, void *datap) {
COMMON_INTERCEPTOR_READ_RANGE(ctx, hdrp, __user_cap_header_struct_sz);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(capget)(hdrp, datap);
if (res == 0 && datap)
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, datap, __user_cap_data_struct_sz);
@@ -4329,9 +4454,9 @@ INTERCEPTOR(int, capset, void *hdrp, const void *datap) {
#endif
#if SANITIZER_INTERCEPT_AEABI_MEM
-DECLARE_REAL_AND_INTERCEPTOR(void *, memmove, void *, const void *, uptr);
-DECLARE_REAL_AND_INTERCEPTOR(void *, memcpy, void *, const void *, uptr);
-DECLARE_REAL_AND_INTERCEPTOR(void *, memset, void *, int, uptr);
+DECLARE_REAL_AND_INTERCEPTOR(void *, memmove, void *, const void *, uptr)
+DECLARE_REAL_AND_INTERCEPTOR(void *, memcpy, void *, const void *, uptr)
+DECLARE_REAL_AND_INTERCEPTOR(void *, memset, void *, int, uptr)
INTERCEPTOR(void *, __aeabi_memmove, void *to, const void *from, uptr size) {
return WRAP(memmove)(to, from, size);
@@ -4404,7 +4529,7 @@ INTERCEPTOR(int, ftime, __sanitizer_timeb *tp) {
COMMON_INTERCEPTOR_ENTER(ctx, ftime, tp);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(ftime)(tp);
if (tp)
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tp, sizeof(*tp));
@@ -4422,7 +4547,7 @@ INTERCEPTOR(void, xdrmem_create, __sanitizer_XDR *xdrs, uptr addr,
COMMON_INTERCEPTOR_ENTER(ctx, xdrmem_create, xdrs, addr, size, op);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
REAL(xdrmem_create)(xdrs, addr, size, op);
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, xdrs, sizeof(*xdrs));
if (op == __sanitizer_XDR_ENCODE) {
@@ -4437,14 +4562,14 @@ INTERCEPTOR(void, xdrstdio_create, __sanitizer_XDR *xdrs, void *file, int op) {
COMMON_INTERCEPTOR_ENTER(ctx, xdrstdio_create, xdrs, file, op);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
REAL(xdrstdio_create)(xdrs, file, op);
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, xdrs, sizeof(*xdrs));
}
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
-// https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+// https://github.com/google/sanitizers/issues/321.
#define XDR_INTERCEPTOR(F, T) \
INTERCEPTOR(int, F, __sanitizer_XDR *xdrs, T *p) { \
void *ctx; \
@@ -4498,7 +4623,7 @@ INTERCEPTOR(int, xdr_bytes, __sanitizer_XDR *xdrs, char **p, unsigned *sizep,
}
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(xdr_bytes)(xdrs, p, sizep, maxsize);
if (p && sizep && xdrs->x_op == __sanitizer_XDR_DECODE) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, sizeof(*p));
@@ -4518,7 +4643,7 @@ INTERCEPTOR(int, xdr_string, __sanitizer_XDR *xdrs, char **p,
}
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(xdr_string)(xdrs, p, maxsize);
if (p && xdrs->x_op == __sanitizer_XDR_DECODE) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, sizeof(*p));
@@ -4570,7 +4695,7 @@ INTERCEPTOR(void *, tsearch, void *key, void **rootp,
COMMON_INTERCEPTOR_ENTER(ctx, tsearch, key, rootp, compar);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
void *res = REAL(tsearch)(key, rootp, compar);
if (res && *(void **)res == key)
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, sizeof(void *));
@@ -4652,7 +4777,7 @@ INTERCEPTOR(int, __woverflow, __sanitizer_FILE *fp, int ch) {
INTERCEPTOR(__sanitizer_FILE *, fopen, const char *path, const char *mode) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, fopen, path, mode);
- COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
+ if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
COMMON_INTERCEPTOR_READ_RANGE(ctx, mode, REAL(strlen)(mode) + 1);
__sanitizer_FILE *res = REAL(fopen)(path, mode);
COMMON_INTERCEPTOR_FILE_OPEN(ctx, res, path);
@@ -4671,7 +4796,7 @@ INTERCEPTOR(__sanitizer_FILE *, freopen, const char *path, const char *mode,
__sanitizer_FILE *fp) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, freopen, path, mode, fp);
- COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
+ if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
COMMON_INTERCEPTOR_READ_RANGE(ctx, mode, REAL(strlen)(mode) + 1);
COMMON_INTERCEPTOR_FILE_CLOSE(ctx, fp);
__sanitizer_FILE *res = REAL(freopen)(path, mode, fp);
@@ -4702,7 +4827,7 @@ INTERCEPTOR(__sanitizer_FILE *, freopen64, const char *path, const char *mode,
__sanitizer_FILE *fp) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, freopen64, path, mode, fp);
- COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
+ if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
COMMON_INTERCEPTOR_READ_RANGE(ctx, mode, REAL(strlen)(mode) + 1);
COMMON_INTERCEPTOR_FILE_CLOSE(ctx, fp);
__sanitizer_FILE *res = REAL(freopen64)(path, mode, fp);
@@ -4723,7 +4848,7 @@ INTERCEPTOR(__sanitizer_FILE *, open_memstream, char **ptr, SIZE_T *sizeloc) {
COMMON_INTERCEPTOR_ENTER(ctx, open_memstream, ptr, sizeloc);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
__sanitizer_FILE *res = REAL(open_memstream)(ptr, sizeloc);
if (res) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, sizeof(*ptr));
@@ -4754,7 +4879,7 @@ INTERCEPTOR(__sanitizer_FILE *, fmemopen, void *buf, SIZE_T size,
COMMON_INTERCEPTOR_ENTER(ctx, fmemopen, buf, size, mode);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
__sanitizer_FILE *res = REAL(fmemopen)(buf, size, mode);
if (res) unpoison_file(res);
return res;
@@ -4831,15 +4956,14 @@ INTERCEPTOR(int, fflush, __sanitizer_FILE *fp) {
INTERCEPTOR(int, fclose, __sanitizer_FILE *fp) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, fclose, fp);
- if (fp) {
- COMMON_INTERCEPTOR_FILE_CLOSE(ctx, fp);
- const FileMetadata *m = GetInterceptorMetadata(fp);
- if (m) {
- COMMON_INTERCEPTOR_INITIALIZE_RANGE(*m->addr, *m->size);
- DeleteInterceptorMetadata(fp);
- }
+ COMMON_INTERCEPTOR_FILE_CLOSE(ctx, fp);
+ const FileMetadata *m = GetInterceptorMetadata(fp);
+ int res = REAL(fclose)(fp);
+ if (m) {
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(*m->addr, *m->size);
+ DeleteInterceptorMetadata(fp);
}
- return REAL(fclose)(fp);
+ return res;
}
#define INIT_FCLOSE COMMON_INTERCEPT_FUNCTION(fclose);
#else
@@ -4922,7 +5046,7 @@ static void MlockIsUnsupported() {
static atomic_uint8_t printed;
if (atomic_exchange(&printed, 1, memory_order_relaxed))
return;
- VPrintf(1, "INFO: %s ignores mlock/mlockall/munlock/munlockall\n",
+ VPrintf(1, "%s ignores mlock/mlockall/munlock/munlockall\n",
SanitizerToolName);
}
@@ -5013,6 +5137,192 @@ INTERCEPTOR(__sanitizer_FILE *, fopencookie, void *cookie, const char *mode,
#define INIT_FOPENCOOKIE
#endif // SANITIZER_INTERCEPT_FOPENCOOKIE
+#if SANITIZER_INTERCEPT_SEM
+INTERCEPTOR(int, sem_init, __sanitizer_sem_t *s, int pshared, unsigned value) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, sem_init, s, pshared, value);
+ // Workaround a bug in glibc's "old" semaphore implementation by
+ // zero-initializing the sem_t contents. This has to be done here because
+ // interceptors bind to the lowest symbols version by default, hitting the
+ // buggy code path while the non-sanitized build of the same code works fine.
+ REAL(memset)(s, 0, sizeof(*s));
+ int res = REAL(sem_init)(s, pshared, value);
+ return res;
+}
+
+INTERCEPTOR(int, sem_destroy, __sanitizer_sem_t *s) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, sem_destroy, s);
+ int res = REAL(sem_destroy)(s);
+ return res;
+}
+
+INTERCEPTOR(int, sem_wait, __sanitizer_sem_t *s) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, sem_wait, s);
+ int res = COMMON_INTERCEPTOR_BLOCK_REAL(sem_wait)(s);
+ if (res == 0) {
+ COMMON_INTERCEPTOR_ACQUIRE(ctx, (uptr)s);
+ }
+ return res;
+}
+
+INTERCEPTOR(int, sem_trywait, __sanitizer_sem_t *s) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, sem_trywait, s);
+ int res = COMMON_INTERCEPTOR_BLOCK_REAL(sem_trywait)(s);
+ if (res == 0) {
+ COMMON_INTERCEPTOR_ACQUIRE(ctx, (uptr)s);
+ }
+ return res;
+}
+
+INTERCEPTOR(int, sem_timedwait, __sanitizer_sem_t *s, void *abstime) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, sem_timedwait, s, abstime);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, abstime, struct_timespec_sz);
+ int res = COMMON_INTERCEPTOR_BLOCK_REAL(sem_timedwait)(s, abstime);
+ if (res == 0) {
+ COMMON_INTERCEPTOR_ACQUIRE(ctx, (uptr)s);
+ }
+ return res;
+}
+
+INTERCEPTOR(int, sem_post, __sanitizer_sem_t *s) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, sem_post, s);
+ COMMON_INTERCEPTOR_RELEASE(ctx, (uptr)s);
+ int res = REAL(sem_post)(s);
+ return res;
+}
+
+INTERCEPTOR(int, sem_getvalue, __sanitizer_sem_t *s, int *sval) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, sem_getvalue, s, sval);
+ int res = REAL(sem_getvalue)(s, sval);
+ if (res == 0) {
+ COMMON_INTERCEPTOR_ACQUIRE(ctx, (uptr)s);
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sval, sizeof(*sval));
+ }
+ return res;
+}
+#define INIT_SEM \
+ COMMON_INTERCEPT_FUNCTION(sem_init); \
+ COMMON_INTERCEPT_FUNCTION(sem_destroy); \
+ COMMON_INTERCEPT_FUNCTION(sem_wait); \
+ COMMON_INTERCEPT_FUNCTION(sem_trywait); \
+ COMMON_INTERCEPT_FUNCTION(sem_timedwait); \
+ COMMON_INTERCEPT_FUNCTION(sem_post); \
+ COMMON_INTERCEPT_FUNCTION(sem_getvalue);
+#else
+#define INIT_SEM
+#endif // SANITIZER_INTERCEPT_SEM
+
+#if SANITIZER_INTERCEPT_PTHREAD_SETCANCEL
+INTERCEPTOR(int, pthread_setcancelstate, int state, int *oldstate) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, pthread_setcancelstate, state, oldstate);
+ int res = REAL(pthread_setcancelstate)(state, oldstate);
+ if (res == 0)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, oldstate, sizeof(*oldstate));
+ return res;
+}
+
+INTERCEPTOR(int, pthread_setcanceltype, int type, int *oldtype) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, pthread_setcanceltype, type, oldtype);
+ int res = REAL(pthread_setcanceltype)(type, oldtype);
+ if (res == 0)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, oldtype, sizeof(*oldtype));
+ return res;
+}
+#define INIT_PTHREAD_SETCANCEL \
+ COMMON_INTERCEPT_FUNCTION(pthread_setcancelstate); \
+ COMMON_INTERCEPT_FUNCTION(pthread_setcanceltype);
+#else
+#define INIT_PTHREAD_SETCANCEL
+#endif
+
+#if SANITIZER_INTERCEPT_MINCORE
+INTERCEPTOR(int, mincore, void *addr, uptr length, unsigned char *vec) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, mincore, addr, length, vec);
+ int res = REAL(mincore)(addr, length, vec);
+ if (res == 0) {
+ uptr page_size = GetPageSizeCached();
+ uptr vec_size = ((length + page_size - 1) & (~(page_size - 1))) / page_size;
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, vec, vec_size);
+ }
+ return res;
+}
+#define INIT_MINCORE COMMON_INTERCEPT_FUNCTION(mincore);
+#else
+#define INIT_MINCORE
+#endif
+
+#if SANITIZER_INTERCEPT_PROCESS_VM_READV
+INTERCEPTOR(SSIZE_T, process_vm_readv, int pid, __sanitizer_iovec *local_iov,
+ uptr liovcnt, __sanitizer_iovec *remote_iov, uptr riovcnt,
+ uptr flags) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, process_vm_readv, pid, local_iov, liovcnt,
+ remote_iov, riovcnt, flags);
+ SSIZE_T res = REAL(process_vm_readv)(pid, local_iov, liovcnt, remote_iov,
+ riovcnt, flags);
+ if (res > 0)
+ write_iovec(ctx, local_iov, liovcnt, res);
+ return res;
+}
+
+INTERCEPTOR(SSIZE_T, process_vm_writev, int pid, __sanitizer_iovec *local_iov,
+ uptr liovcnt, __sanitizer_iovec *remote_iov, uptr riovcnt,
+ uptr flags) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, process_vm_writev, pid, local_iov, liovcnt,
+ remote_iov, riovcnt, flags);
+ SSIZE_T res = REAL(process_vm_writev)(pid, local_iov, liovcnt, remote_iov,
+ riovcnt, flags);
+ if (res > 0)
+ read_iovec(ctx, local_iov, liovcnt, res);
+ return res;
+}
+#define INIT_PROCESS_VM_READV \
+ COMMON_INTERCEPT_FUNCTION(process_vm_readv); \
+ COMMON_INTERCEPT_FUNCTION(process_vm_writev);
+#else
+#define INIT_PROCESS_VM_READV
+#endif
+
+#if SANITIZER_INTERCEPT_CTERMID
+INTERCEPTOR(char *, ctermid, char *s) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, ctermid, s);
+ char *res = REAL(ctermid)(s);
+ if (res) {
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, REAL(strlen)(res) + 1);
+ }
+ return res;
+}
+#define INIT_CTERMID COMMON_INTERCEPT_FUNCTION(ctermid);
+#else
+#define INIT_CTERMID
+#endif
+
+#if SANITIZER_INTERCEPT_CTERMID_R
+INTERCEPTOR(char *, ctermid_r, char *s) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, ctermid_r, s);
+ char *res = REAL(ctermid_r)(s);
+ if (res) {
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, REAL(strlen)(res) + 1);
+ }
+ return res;
+}
+#define INIT_CTERMID_R COMMON_INTERCEPT_FUNCTION(ctermid_r);
+#else
+#define INIT_CTERMID_R
+#endif
+
static void InitializeCommonInterceptors() {
static u64 metadata_mem[sizeof(MetadataHashMap) / sizeof(u64) + 1];
interceptor_metadata_map = new((void *)&metadata_mem) MetadataHashMap();
@@ -5027,6 +5337,7 @@ static void InitializeCommonInterceptors() {
INIT_STRSPN;
INIT_STRPBRK;
INIT_MEMCHR;
+ INIT_MEMCMP;
INIT_MEMRCHR;
INIT_READ;
INIT_PREAD;
@@ -5092,6 +5403,7 @@ static void InitializeCommonInterceptors() {
INIT_MBSNRTOWCS;
INIT_WCSTOMBS;
INIT_WCSNRTOMBS;
+ INIT_WCRTOMB;
INIT_TCGETATTR;
INIT_REALPATH;
INIT_CANONICALIZE_FILE_NAME;
@@ -5181,4 +5493,10 @@ static void InitializeCommonInterceptors() {
INIT_TIMERFD;
INIT_MLOCKX;
INIT_FOPENCOOKIE;
+ INIT_SEM;
+ INIT_PTHREAD_SETCANCEL;
+ INIT_MINCORE;
+ INIT_PROCESS_VM_READV;
+ INIT_CTERMID;
+ INIT_CTERMID_R;
}
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_format.inc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_format.inc
index 8f94802aeae8..92318cda35fd 100644
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_format.inc
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_format.inc
@@ -13,6 +13,7 @@
// with a few common GNU extensions.
//
//===----------------------------------------------------------------------===//
+
#include <stdarg.h>
static const char *parse_number(const char *p, int *out) {
@@ -191,7 +192,7 @@ static const char *scanf_parse_next(const char *p, bool allowGnuMalloc,
continue;
}
if (*p == '\0') {
- return 0;
+ return nullptr;
}
// %n$
p = maybe_parse_param_index(p, &dir->argIdx);
@@ -206,7 +207,7 @@ static const char *scanf_parse_next(const char *p, bool allowGnuMalloc,
p = parse_number(p, &dir->fieldWidth);
CHECK(p);
if (dir->fieldWidth <= 0) // Width if at all must be non-zero
- return 0;
+ return nullptr;
}
// m
if (*p == 'm') {
@@ -226,8 +227,8 @@ static const char *scanf_parse_next(const char *p, bool allowGnuMalloc,
while (*p && *p != ']')
++p;
if (*p == 0)
- return 0; // unexpected end of string
- // Consume the closing ']'.
+ return nullptr; // unexpected end of string
+ // Consume the closing ']'.
++p;
}
// This is unfortunately ambiguous between old GNU extension
@@ -251,7 +252,7 @@ static const char *scanf_parse_next(const char *p, bool allowGnuMalloc,
while (*q && *q != ']' && *q != '%')
++q;
if (*q == 0 || *q == '%')
- return 0;
+ return nullptr;
p = q + 1; // Consume the closing ']'.
dir->maybeGnuMalloc = true;
}
@@ -395,7 +396,7 @@ static const char *printf_parse_next(const char *p, PrintfDirective *dir) {
continue;
}
if (*p == '\0') {
- return 0;
+ return nullptr;
}
// %n$
p = maybe_parse_param_index(p, &dir->precisionIdx);
@@ -408,7 +409,7 @@ static const char *printf_parse_next(const char *p, PrintfDirective *dir) {
p = maybe_parse_number_or_star(p, &dir->fieldWidth,
&dir->starredWidth);
if (!p)
- return 0;
+ return nullptr;
// Precision
if (*p == '.') {
++p;
@@ -416,7 +417,7 @@ static const char *printf_parse_next(const char *p, PrintfDirective *dir) {
p = maybe_parse_number_or_star(p, &dir->fieldPrecision,
&dir->starredPrecision);
if (!p)
- return 0;
+ return nullptr;
// m$
if (dir->starredPrecision) {
p = maybe_parse_param_index(p, &dir->precisionIdx);
@@ -556,4 +557,4 @@ static void printf_common(void *ctx, const char *format, va_list aq) {
}
}
-#endif // SANITIZER_INTERCEPT_PRINTF
+#endif // SANITIZER_INTERCEPT_PRINTF
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc
index b94c21c96aa0..fcd0a3d70f52 100755
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc
@@ -520,7 +520,7 @@ static const ioctl_desc *ioctl_table_lookup(unsigned req) {
if (left == right && ioctl_table[left].req == req)
return ioctl_table + left;
else
- return 0;
+ return nullptr;
}
static bool ioctl_decode(unsigned req, ioctl_desc *desc) {
@@ -567,7 +567,7 @@ static const ioctl_desc *ioctl_lookup(unsigned req) {
(desc->type == ioctl_desc::READWRITE || desc->type == ioctl_desc::WRITE ||
desc->type == ioctl_desc::READ))
return desc;
- return 0;
+ return nullptr;
}
static void ioctl_common_pre(void *ctx, const ioctl_desc *desc, int d,
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common_libcdep.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common_libcdep.cc
index 1b65bced75d5..596f5bcd3173 100644
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common_libcdep.cc
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common_libcdep.cc
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "sanitizer_common.h"
+
#include "sanitizer_flags.h"
#include "sanitizer_stackdepot.h"
#include "sanitizer_stacktrace.h"
@@ -46,6 +47,7 @@ void SetSandboxingCallback(void (*f)()) {
}
void ReportErrorSummary(const char *error_type, StackTrace *stack) {
+#if !SANITIZER_GO
if (!common_flags()->print_summary)
return;
if (stack->size == 0) {
@@ -58,6 +60,7 @@ void ReportErrorSummary(const char *error_type, StackTrace *stack) {
SymbolizedStack *frame = Symbolizer::GetOrInit()->SymbolizePC(pc);
ReportErrorSummary(error_type, frame->info);
frame->ClearAll();
+#endif
}
static void (*SoftRssLimitExceededCallback)(bool exceeded);
@@ -116,8 +119,27 @@ void BackgroundThread(void *arg) {
}
}
+void WriteToSyslog(const char *msg) {
+ InternalScopedString msg_copy(kErrorMessageBufferSize);
+ msg_copy.append("%s", msg);
+ char *p = msg_copy.data();
+ char *q;
+
+ // Print one line at a time.
+ // syslog, at least on Android, has an implicit message length limit.
+ do {
+ q = internal_strchr(p, '\n');
+ if (q)
+ *q = '\0';
+ WriteOneLineToSyslog(p);
+ if (q)
+ p = q + 1;
+ } while (q);
+}
+
void MaybeStartBackgroudThread() {
-#if SANITIZER_LINUX // Need to implement/test on other platforms.
+#if SANITIZER_LINUX && \
+ !SANITIZER_GO // Need to implement/test on other platforms.
// Start the background thread if one of the rss limits is given.
if (!common_flags()->hard_rss_limit_mb &&
!common_flags()->soft_rss_limit_mb) return;
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common_nolibc.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common_nolibc.cc
new file mode 100644
index 000000000000..9f4f97224e18
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common_nolibc.cc
@@ -0,0 +1,27 @@
+//===-- sanitizer_common_nolibc.cc ----------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains stubs for libc function to facilitate optional use of
+// libc in no-libcdep sources.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_platform.h"
+#include "sanitizer_common.h"
+#include "sanitizer_libc.h"
+
+namespace __sanitizer {
+
+#if SANITIZER_LINUX
+bool ShouldLogAfterPrintf() { return false; }
+void LogMessageOnPrintf(const char *str) {}
+#endif
+void WriteToSyslog(const char *buffer) {}
+void Abort() { internal__exit(1); }
+
+} // namespace __sanitizer
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common_syscalls.inc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common_syscalls.inc
index 5d4840f961ef..008e57745cc5 100644
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common_syscalls.inc
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common_syscalls.inc
@@ -2301,7 +2301,7 @@ POST_SYSCALL(ni_syscall)(long res) {}
PRE_SYSCALL(ptrace)(long request, long pid, long addr, long data) {
#if !SANITIZER_ANDROID && \
(defined(__i386) || defined(__x86_64) || defined(__mips64) || \
- defined(__powerpc64__))
+ defined(__powerpc64__) || defined(__aarch64__))
if (data) {
if (request == ptrace_setregs) {
PRE_READ((void *)data, struct_user_regs_struct_sz);
@@ -2322,7 +2322,7 @@ PRE_SYSCALL(ptrace)(long request, long pid, long addr, long data) {
POST_SYSCALL(ptrace)(long res, long request, long pid, long addr, long data) {
#if !SANITIZER_ANDROID && \
(defined(__i386) || defined(__x86_64) || defined(__mips64) || \
- defined(__powerpc64__))
+ defined(__powerpc64__) || defined(__aarch64__))
if (res >= 0 && data) {
// Note that this is different from the interceptor in
// sanitizer_common_interceptors.inc.
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_coverage_libcdep.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_coverage_libcdep.cc
index f511c996d8c2..eaa1446afd44 100644
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_coverage_libcdep.cc
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_coverage_libcdep.cc
@@ -53,6 +53,12 @@ static const u64 kMagic32 = 0xC0BFFFFFFFFFFF32ULL;
static atomic_uint32_t dump_once_guard; // Ensure that CovDump runs only once.
static atomic_uintptr_t coverage_counter;
+static atomic_uintptr_t caller_callee_counter;
+
+static void ResetGlobalCounters() {
+ return atomic_store(&coverage_counter, 0, memory_order_relaxed);
+ return atomic_store(&caller_callee_counter, 0, memory_order_relaxed);
+}
// pc_array is the array containing the covered PCs.
// To make the pc_array thread- and async-signal-safe it has to be large enough.
@@ -90,7 +96,7 @@ class CoverageData {
void DumpAll();
ALWAYS_INLINE
- void TraceBasicBlock(s32 *id);
+ void TraceBasicBlock(u32 *id);
void InitializeGuardArray(s32 *guards);
void InitializeGuards(s32 *guards, uptr n, const char *module_name,
@@ -102,6 +108,7 @@ class CoverageData {
uptr *data();
uptr size();
+ uptr *buffer() const { return pc_buffer; }
private:
void DirectOpen();
@@ -127,6 +134,8 @@ class CoverageData {
// Descriptor of the file mapped pc array.
fd_t pc_fd;
+ uptr *pc_buffer;
+
// Vector of coverage guard arrays, protected by mu.
InternalMmapVectorNoCtor<s32*> guard_array_vec;
@@ -203,6 +212,11 @@ void CoverageData::Enable() {
atomic_store(&pc_array_size, kPcArrayMaxSize, memory_order_relaxed);
}
+ pc_buffer = nullptr;
+ if (common_flags()->coverage_pc_buffer)
+ pc_buffer = reinterpret_cast<uptr *>(MmapNoReserveOrDie(
+ sizeof(uptr) * kPcArrayMaxSize, "CovInit::pc_buffer"));
+
cc_array = reinterpret_cast<uptr **>(MmapNoReserveOrDie(
sizeof(uptr *) * kCcArrayMaxSize, "CovInit::cc_array"));
atomic_store(&cc_array_size, kCcArrayMaxSize, memory_order_relaxed);
@@ -225,7 +239,8 @@ void CoverageData::InitializeGuardArray(s32 *guards) {
Enable(); // Make sure coverage is enabled at this point.
s32 n = guards[0];
for (s32 j = 1; j <= n; j++) {
- uptr idx = atomic_fetch_add(&pc_array_index, 1, memory_order_relaxed);
+ uptr idx = atomic_load_relaxed(&pc_array_index);
+ atomic_store_relaxed(&pc_array_index, idx + 1);
guards[j] = -static_cast<s32>(idx + 1);
}
}
@@ -239,6 +254,10 @@ void CoverageData::Disable() {
UnmapOrDie(cc_array, sizeof(uptr *) * kCcArrayMaxSize);
cc_array = nullptr;
}
+ if (pc_buffer) {
+ UnmapOrDie(pc_buffer, sizeof(uptr) * kPcArrayMaxSize);
+ pc_buffer = nullptr;
+ }
if (tr_event_array) {
UnmapOrDie(tr_event_array,
sizeof(tr_event_array[0]) * kTrEventArrayMaxSize +
@@ -407,6 +426,7 @@ void CoverageData::Add(uptr pc, u32 *guard) {
atomic_load(&pc_array_size, memory_order_acquire));
uptr counter = atomic_fetch_add(&coverage_counter, 1, memory_order_relaxed);
pc_array[idx] = BundlePcAndCounter(pc, counter);
+ if (pc_buffer) pc_buffer[counter] = pc;
}
// Registers a pair caller=>callee.
@@ -435,7 +455,7 @@ void CoverageData::IndirCall(uptr caller, uptr callee, uptr callee_cache[],
uptr was = 0;
if (atomic_compare_exchange_strong(&atomic_callee_cache[i], &was, callee,
memory_order_seq_cst)) {
- atomic_fetch_add(&coverage_counter, 1, memory_order_relaxed);
+ atomic_fetch_add(&caller_callee_counter, 1, memory_order_relaxed);
return;
}
if (was == callee) // Already have this callee.
@@ -675,11 +695,11 @@ void CoverageData::DumpCallerCalleePairs() {
// it once and then cache in the provided 'cache' storage.
//
// This function will eventually be inlined by the compiler.
-void CoverageData::TraceBasicBlock(s32 *id) {
+void CoverageData::TraceBasicBlock(u32 *id) {
// Will trap here if
// 1. coverage is not enabled at run-time.
// 2. The array tr_event_array is full.
- *tr_event_pointer = static_cast<u32>(*id - 1);
+ *tr_event_pointer = *id - 1;
tr_event_pointer++;
}
@@ -813,7 +833,7 @@ void CovPrepareForSandboxing(__sanitizer_sandbox_arguments *args) {
} else {
InternalScopedString path(kMaxPathLength);
// Pre-open the file now. The sandbox won't allow us to do it later.
- cov_fd = CovOpenFile(&path, true /* packed */, 0);
+ cov_fd = CovOpenFile(&path, true /* packed */, nullptr);
}
}
@@ -832,6 +852,11 @@ void CovAfterFork(int child_pid) {
coverage_data.AfterFork(child_pid);
}
+static void MaybeDumpCoverage() {
+ if (common_flags()->coverage)
+ __sanitizer_cov_dump();
+}
+
void InitializeCoverage(bool enabled, const char *dir) {
if (coverage_enabled)
return; // May happen if two sanitizer enable coverage in the same process.
@@ -840,6 +865,7 @@ void InitializeCoverage(bool enabled, const char *dir) {
coverage_data.Init();
if (enabled) coverage_data.Enable();
if (!common_flags()->coverage_direct) Atexit(__sanitizer_cov_dump);
+ AddDieCallback(MaybeDumpCoverage);
}
void ReInitializeCoverage(bool enabled, const char *dir) {
@@ -853,7 +879,7 @@ void CoverageUpdateMapping() {
CovUpdateMapping(coverage_dir);
}
-} // namespace __sanitizer
+} // namespace __sanitizer
extern "C" {
SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov(u32 *guard) {
@@ -902,15 +928,23 @@ uptr __sanitizer_get_total_unique_coverage() {
}
SANITIZER_INTERFACE_ATTRIBUTE
-void __sanitizer_cov_trace_func_enter(s32 *id) {
+uptr __sanitizer_get_total_unique_caller_callee_pairs() {
+ return atomic_load(&caller_callee_counter, memory_order_relaxed);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_cov_trace_func_enter(u32 *id) {
+ __sanitizer_cov_with_check(id);
coverage_data.TraceBasicBlock(id);
}
SANITIZER_INTERFACE_ATTRIBUTE
-void __sanitizer_cov_trace_basic_block(s32 *id) {
+void __sanitizer_cov_trace_basic_block(u32 *id) {
+ __sanitizer_cov_with_check(id);
coverage_data.TraceBasicBlock(id);
}
SANITIZER_INTERFACE_ATTRIBUTE
void __sanitizer_reset_coverage() {
+ ResetGlobalCounters();
coverage_data.ReinitializeGuards();
internal_bzero_aligned16(
coverage_data.data(),
@@ -923,6 +957,12 @@ uptr __sanitizer_get_coverage_guards(uptr **data) {
}
SANITIZER_INTERFACE_ATTRIBUTE
+uptr __sanitizer_get_coverage_pc_buffer(uptr **data) {
+ *data = coverage_data.buffer();
+ return __sanitizer_get_total_unique_coverage();
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
uptr __sanitizer_get_number_of_counters() {
return coverage_data.GetNumberOf8bitCounters();
}
@@ -931,7 +971,9 @@ SANITIZER_INTERFACE_ATTRIBUTE
uptr __sanitizer_update_counter_bitset_and_clear_counters(u8 *bitset) {
return coverage_data.Update8bitCounterBitsetAndClearCounters(bitset);
}
-// Default empty implementation (weak). Users should redefine it.
+// Default empty implementations (weak). Users should redefine them.
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
void __sanitizer_cov_trace_cmp() {}
-} // extern "C"
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+void __sanitizer_cov_trace_switch() {}
+} // extern "C"
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc
index a3d75abc0476..c8b5d9014ede 100644
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc
@@ -75,7 +75,7 @@ void CovUpdateMapping(const char *coverage_dir, uptr caller_pc) {
InternalScopedBuffer<LoadedModule> modules(kMaxNumberOfModules);
CHECK(modules.data());
int n_modules = GetListOfModules(modules.data(), kMaxNumberOfModules,
- /* filter */ 0);
+ /* filter */ nullptr);
text.append("%d\n", sizeof(uptr) * 8);
for (int i = 0; i < n_modules; ++i) {
@@ -124,4 +124,4 @@ void CovUpdateMapping(const char *coverage_dir, uptr caller_pc) {
}
}
-} // namespace __sanitizer
+} // namespace __sanitizer
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector1.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector1.cc
index 5890b54b933b..bd57a403bdcc 100644
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector1.cc
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector1.cc
@@ -71,7 +71,7 @@ DD::DD(const DDFlags *flags)
}
DDPhysicalThread* DD::CreatePhysicalThread() {
- return 0;
+ return nullptr;
}
void DD::DestroyPhysicalThread(DDPhysicalThread *pt) {
@@ -181,10 +181,10 @@ void DD::MutexDestroy(DDCallback *cb,
DDReport *DD::GetReport(DDCallback *cb) {
if (!cb->lt->report_pending)
- return 0;
+ return nullptr;
cb->lt->report_pending = false;
return &cb->lt->rep;
}
-} // namespace __sanitizer
-#endif // #if SANITIZER_DEADLOCK_DETECTOR_VERSION == 1
+} // namespace __sanitizer
+#endif // #if SANITIZER_DEADLOCK_DETECTOR_VERSION == 1
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector_interface.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector_interface.h
index 8cf26e0d5528..b6e91a16e257 100644
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector_interface.h
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector_interface.h
@@ -72,10 +72,10 @@ struct DDCallback {
struct DDetector {
static DDetector *Create(const DDFlags *flags);
- virtual DDPhysicalThread* CreatePhysicalThread() { return 0; }
+ virtual DDPhysicalThread* CreatePhysicalThread() { return nullptr; }
virtual void DestroyPhysicalThread(DDPhysicalThread *pt) {}
- virtual DDLogicalThread* CreateLogicalThread(u64 ctx) { return 0; }
+ virtual DDLogicalThread* CreateLogicalThread(u64 ctx) { return nullptr; }
virtual void DestroyLogicalThread(DDLogicalThread *lt) {}
virtual void MutexInit(DDCallback *cb, DDMutex *m) {}
@@ -85,7 +85,7 @@ struct DDetector {
virtual void MutexBeforeUnlock(DDCallback *cb, DDMutex *m, bool wlock) {}
virtual void MutexDestroy(DDCallback *cb, DDMutex *m) {}
- virtual DDReport *GetReport(DDCallback *cb) { return 0; }
+ virtual DDReport *GetReport(DDCallback *cb) { return nullptr; }
};
} // namespace __sanitizer
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_flag_parser.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_flag_parser.cc
index d125002daf4c..67830b2940bb 100644
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_flag_parser.cc
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_flag_parser.cc
@@ -127,6 +127,24 @@ void FlagParser::ParseString(const char *s) {
pos_ = old_pos_;
}
+bool FlagParser::ParseFile(const char *path, bool ignore_missing) {
+ static const uptr kMaxIncludeSize = 1 << 15;
+ char *data;
+ uptr data_mapped_size;
+ error_t err;
+ uptr len;
+ if (!ReadFileToBuffer(path, &data, &data_mapped_size, &len,
+ Max(kMaxIncludeSize, GetPageSizeCached()), &err)) {
+ if (ignore_missing)
+ return true;
+ Printf("Failed to read options from '%s': error %d\n", path, err);
+ return false;
+ }
+ ParseString(data);
+ UnmapOrDie(data, data_mapped_size);
+ return true;
+}
+
bool FlagParser::run_handler(const char *name, const char *value) {
for (int i = 0; i < n_flags_; ++i) {
if (internal_strcmp(name, flags_[i].name) == 0)
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_flag_parser.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_flag_parser.h
index 0ac7634cb876..2477aeddba5f 100644
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_flag_parser.h
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_flag_parser.h
@@ -93,6 +93,7 @@ class FlagParser {
void RegisterHandler(const char *name, FlagHandlerBase *handler,
const char *desc);
void ParseString(const char *s);
+ bool ParseFile(const char *path, bool ignore_missing);
void PrintFlagDescriptions();
static LowLevelAllocator Alloc;
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_flags.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_flags.cc
index 01098a3d6b87..18b9ea3df9e1 100644
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_flags.cc
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_flags.cc
@@ -45,34 +45,49 @@ void CommonFlags::CopyFrom(const CommonFlags &other) {
internal_memcpy(this, &other, sizeof(*this));
}
+// Copy the string from "s" to "out", replacing "%b" with the binary basename.
+static void SubstituteBinaryName(const char *s, char *out, uptr out_size) {
+ char *out_end = out + out_size;
+ while (*s && out < out_end - 1) {
+ if (s[0] != '%' || s[1] != 'b') { *out++ = *s++; continue; }
+ const char *base = GetProcessName();
+ CHECK(base);
+ while (*base && out < out_end - 1)
+ *out++ = *base++;
+ s += 2; // skip "%b"
+ }
+ *out = '\0';
+}
+
class FlagHandlerInclude : public FlagHandlerBase {
- static const uptr kMaxIncludeSize = 1 << 15;
FlagParser *parser_;
+ bool ignore_missing_;
public:
- explicit FlagHandlerInclude(FlagParser *parser) : parser_(parser) {}
+ explicit FlagHandlerInclude(FlagParser *parser, bool ignore_missing)
+ : parser_(parser), ignore_missing_(ignore_missing) {}
bool Parse(const char *value) final {
- char *data;
- uptr data_mapped_size;
- error_t err;
- uptr len =
- ReadFileToBuffer(value, &data, &data_mapped_size,
- Max(kMaxIncludeSize, GetPageSizeCached()), &err);
- if (!len) {
- Printf("Failed to read options from '%s': error %d\n", value, err);
- return false;
+ if (internal_strchr(value, '%')) {
+ char *buf = (char *)MmapOrDie(kMaxPathLength, "FlagHandlerInclude");
+ SubstituteBinaryName(value, buf, kMaxPathLength);
+ bool res = parser_->ParseFile(buf, ignore_missing_);
+ UnmapOrDie(buf, kMaxPathLength);
+ return res;
}
- parser_->ParseString(data);
- UnmapOrDie(data, data_mapped_size);
- return true;
+ return parser_->ParseFile(value, ignore_missing_);
}
};
-void RegisterIncludeFlag(FlagParser *parser, CommonFlags *cf) {
- FlagHandlerInclude *fh_include =
- new (FlagParser::Alloc) FlagHandlerInclude(parser); // NOLINT
+void RegisterIncludeFlags(FlagParser *parser, CommonFlags *cf) {
+ FlagHandlerInclude *fh_include = new (FlagParser::Alloc) // NOLINT
+ FlagHandlerInclude(parser, /*ignore_missing*/ false);
parser->RegisterHandler("include", fh_include,
"read more options from the given file");
+ FlagHandlerInclude *fh_include_if_exists = new (FlagParser::Alloc) // NOLINT
+ FlagHandlerInclude(parser, /*ignore_missing*/ true);
+ parser->RegisterHandler(
+ "include_if_exists", fh_include_if_exists,
+ "read more options from the given file (if it exists)");
}
void RegisterCommonFlags(FlagParser *parser, CommonFlags *cf) {
@@ -81,7 +96,7 @@ void RegisterCommonFlags(FlagParser *parser, CommonFlags *cf) {
#include "sanitizer_flags.inc"
#undef COMMON_FLAG
- RegisterIncludeFlag(parser, cf);
+ RegisterIncludeFlags(parser, cf);
}
} // namespace __sanitizer
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_flags.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_flags.h
index fda6d710757e..33c3c4512725 100644
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_flags.h
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_flags.h
@@ -49,7 +49,7 @@ inline void OverrideCommonFlags(const CommonFlags &cf) {
class FlagParser;
void RegisterCommonFlags(FlagParser *parser,
CommonFlags *cf = &common_flags_dont_use);
-void RegisterIncludeFlag(FlagParser *parser, CommonFlags *cf);
+void RegisterIncludeFlags(FlagParser *parser, CommonFlags *cf);
} // namespace __sanitizer
#endif // SANITIZER_FLAGS_H
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_flags.inc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_flags.inc
index bbb39c73e2d0..c28f7f4a6034 100644
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_flags.inc
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_flags.inc
@@ -10,6 +10,7 @@
// This file describes common flags available in all sanitizers.
//
//===----------------------------------------------------------------------===//
+
#ifndef COMMON_FLAG
#error "Define COMMON_FLAG prior to including this file!"
#endif
@@ -24,7 +25,7 @@ COMMON_FLAG(
"If set, use the online symbolizer from common sanitizer runtime to turn "
"virtual addresses to file/line locations.")
COMMON_FLAG(
- const char *, external_symbolizer_path, 0,
+ const char *, external_symbolizer_path, nullptr,
"Path to external symbolizer. If empty, the tool will search $PATH for "
"the symbolizer.")
COMMON_FLAG(
@@ -55,6 +56,10 @@ COMMON_FLAG(
"Mention name of executable when reporting error and "
"append executable name to logs (as in \"log_path.exe_name.pid\").")
COMMON_FLAG(
+ bool, log_to_syslog, SANITIZER_ANDROID || SANITIZER_MAC,
+ "Write all sanitizer output to syslog in addition to other means of "
+ "logging.")
+COMMON_FLAG(
int, verbosity, 0,
"Verbosity level (0 - silent, 1 - a bit of output, 2+ - more output).")
COMMON_FLAG(bool, detect_leaks, true, "Enable memory leak detection.")
@@ -74,6 +79,10 @@ COMMON_FLAG(bool, handle_segv, SANITIZER_NEEDS_SEGV,
"If set, registers the tool's custom SIGSEGV/SIGBUS handler.")
COMMON_FLAG(bool, handle_abort, false,
"If set, registers the tool's custom SIGABRT handler.")
+COMMON_FLAG(bool, handle_sigill, false,
+ "If set, registers the tool's custom SIGILL handler.")
+COMMON_FLAG(bool, handle_sigfpe, true,
+ "If set, registers the tool's custom SIGFPE handler.")
COMMON_FLAG(bool, allow_user_segv_handler, false,
"If set, allows user to register a SEGV handler even if the tool "
"registers one.")
@@ -135,6 +144,9 @@ COMMON_FLAG(bool, coverage_direct, SANITIZER_ANDROID,
COMMON_FLAG(const char *, coverage_dir, ".",
"Target directory for coverage dumps. Defaults to the current "
"directory.")
+COMMON_FLAG(bool, coverage_pc_buffer, true,
+ "If set (and if 'coverage' is set too), the pcs would be collected "
+ "in a buffer.")
COMMON_FLAG(bool, full_address_space, false,
"Sanitize complete address space; "
"by default kernel area on 32-bit platforms will not be sanitized")
@@ -170,6 +182,21 @@ COMMON_FLAG(bool, intercept_strspn, true,
COMMON_FLAG(bool, intercept_strpbrk, true,
"If set, uses custom wrappers for strpbrk function "
"to find more errors.")
+COMMON_FLAG(bool, intercept_memcmp, true,
+ "If set, uses custom wrappers for memcmp function "
+ "to find more errors.")
+COMMON_FLAG(bool, strict_memcmp, true,
+ "If true, assume that memcmp(p1, p2, n) always reads n bytes before "
+ "comparing p1 and p2.")
COMMON_FLAG(bool, decorate_proc_maps, false, "If set, decorate sanitizer "
"mappings in /proc/self/maps with "
"user-readable names")
+COMMON_FLAG(int, exitcode, 1, "Override the program exit status if the tool "
+ "found an error")
+COMMON_FLAG(
+ bool, abort_on_error, SANITIZER_MAC,
+ "If set, the tool calls abort() instead of _exit() after printing the "
+ "error report.")
+COMMON_FLAG(bool, suppress_equal_pcs, true,
+ "Deduplicate multiple reports for single source location in "
+ "halt_on_error=false mode (asan only).")
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_interface_internal.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_interface_internal.h
index 94d9f4e9524a..b11ae30106f7 100644
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_interface_internal.h
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_interface_internal.h
@@ -53,6 +53,9 @@ extern "C" {
SANITIZER_INTERFACE_ATTRIBUTE
int __sanitizer_verify_contiguous_container(const void *beg, const void *mid,
const void *end);
-} // extern "C"
+ SANITIZER_INTERFACE_ATTRIBUTE
+ const void *__sanitizer_contiguous_container_find_bad_address(
+ const void *beg, const void *mid, const void *end);
+ } // extern "C"
#endif // SANITIZER_INTERFACE_INTERNAL_H
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h
index b76c6023aba2..e83eed0830d8 100644
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h
@@ -117,7 +117,10 @@ using namespace __sanitizer; // NOLINT
// Common defs.
#define INLINE inline
#define INTERFACE_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
-#define WEAK SANITIZER_WEAK_ATTRIBUTE
+#define SANITIZER_WEAK_DEFAULT_IMPL \
+ extern "C" SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE NOINLINE
+#define SANITIZER_WEAK_CXX_DEFAULT_IMPL \
+ extern "C++" SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE NOINLINE
// Platform-specific defs.
#if defined(_MSC_VER)
@@ -129,7 +132,6 @@ using namespace __sanitizer; // NOLINT
# define NOINLINE __declspec(noinline)
# define NORETURN __declspec(noreturn)
# define THREADLOCAL __declspec(thread)
-# define NOTHROW
# define LIKELY(x) (x)
# define UNLIKELY(x) (x)
# define PREFETCH(x) /* _mm_prefetch(x, _MM_HINT_NTA) */
@@ -143,7 +145,6 @@ using namespace __sanitizer; // NOLINT
# define NOINLINE __attribute__((noinline))
# define NORETURN __attribute__((noreturn))
# define THREADLOCAL __thread
-# define NOTHROW throw()
# define LIKELY(x) __builtin_expect(!!(x), 1)
# define UNLIKELY(x) __builtin_expect(!!(x), 0)
# if defined(__i386__) || defined(__x86_64__)
@@ -162,6 +163,12 @@ using namespace __sanitizer; // NOLINT
# define USED
#endif
+#if !defined(_MSC_VER) || defined(__clang__) || MSC_PREREQ(1900)
+# define NOEXCEPT noexcept
+#else
+# define NOEXCEPT throw()
+#endif
+
// Unaligned versions of basic types.
typedef ALIGNED(1) u16 uu16;
typedef ALIGNED(1) u32 uu32;
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_lfstack.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_lfstack.h
index 088413908087..879cc80921c7 100644
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_lfstack.h
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_lfstack.h
@@ -49,8 +49,8 @@ struct LFStack {
u64 cmp = atomic_load(&head_, memory_order_acquire);
for (;;) {
T *cur = (T*)(uptr)(cmp & kPtrMask);
- if (cur == 0)
- return 0;
+ if (!cur)
+ return nullptr;
T *nxt = cur->next;
u64 cnt = (cmp & kCounterMask);
u64 xch = (u64)(uptr)nxt | cnt;
@@ -68,6 +68,6 @@ struct LFStack {
atomic_uint64_t head_;
};
-} // namespace __sanitizer
+} // namespace __sanitizer
-#endif // #ifndef SANITIZER_LFSTACK_H
+#endif // SANITIZER_LFSTACK_H
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_libc.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_libc.cc
index cb162a4c4984..cf31e689653f 100644
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_libc.cc
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_libc.cc
@@ -10,6 +10,7 @@
// This file is shared between AddressSanitizer and ThreadSanitizer
// run-time libraries. See sanitizer_libc.h for details.
//===----------------------------------------------------------------------===//
+
#include "sanitizer_allocator_internal.h"
#include "sanitizer_common.h"
#include "sanitizer_libc.h"
@@ -17,7 +18,7 @@
namespace __sanitizer {
s64 internal_atoll(const char *nptr) {
- return internal_simple_strtoll(nptr, (char**)0, 10);
+ return internal_simple_strtoll(nptr, nullptr, 10);
}
void *internal_memchr(const void *s, int c, uptr n) {
@@ -25,7 +26,7 @@ void *internal_memchr(const void *s, int c, uptr n) {
for (uptr i = 0; i < n; ++i, ++t)
if (*t == c)
return reinterpret_cast<void *>(const_cast<char *>(t));
- return 0;
+ return nullptr;
}
void *internal_memrchr(const void *s, int c, uptr n) {
@@ -77,7 +78,8 @@ void internal_bzero_aligned16(void *s, uptr n) {
CHECK_EQ((reinterpret_cast<uptr>(s) | n) & 15, 0);
for (S16 *p = reinterpret_cast<S16*>(s), *end = p + n / 16; p < end; p++) {
p->a = p->b = 0;
- SanitizerBreakOptimization(0); // Make sure this does not become memset.
+ // Make sure this does not become memset.
+ SanitizerBreakOptimization(nullptr);
}
}
@@ -96,7 +98,7 @@ void *internal_memset(void* s, int c, uptr n) {
uptr internal_strcspn(const char *s, const char *reject) {
uptr i;
for (i = 0; s[i]; i++) {
- if (internal_strchr(reject, s[i]) != 0)
+ if (internal_strchr(reject, s[i]))
return i;
}
return i;
@@ -147,7 +149,7 @@ char* internal_strchr(const char *s, int c) {
if (*s == (char)c)
return const_cast<char *>(s);
if (*s == 0)
- return 0;
+ return nullptr;
s++;
}
}
@@ -160,7 +162,7 @@ char *internal_strchrnul(const char *s, int c) {
}
char *internal_strrchr(const char *s, int c) {
- const char *res = 0;
+ const char *res = nullptr;
for (uptr i = 0; s[i]; i++) {
if (s[i] == c) res = s + i;
}
@@ -173,6 +175,19 @@ uptr internal_strlen(const char *s) {
return i;
}
+uptr internal_strlcat(char *dst, const char *src, uptr maxlen) {
+ const uptr srclen = internal_strlen(src);
+ const uptr dstlen = internal_strnlen(dst, maxlen);
+ if (dstlen == maxlen) return maxlen + srclen;
+ if (srclen < maxlen - dstlen) {
+ internal_memmove(dst + dstlen, src, srclen + 1);
+ } else {
+ internal_memmove(dst + dstlen, src, maxlen - dstlen - 1);
+ dst[maxlen - 1] = '\0';
+ }
+ return dstlen + srclen;
+}
+
char *internal_strncat(char *dst, const char *src, uptr n) {
uptr len = internal_strlen(dst);
uptr i;
@@ -182,6 +197,17 @@ char *internal_strncat(char *dst, const char *src, uptr n) {
return dst;
}
+uptr internal_strlcpy(char *dst, const char *src, uptr maxlen) {
+ const uptr srclen = internal_strlen(src);
+ if (srclen < maxlen) {
+ internal_memmove(dst, src, srclen + 1);
+ } else if (maxlen != 0) {
+ internal_memmove(dst, src, maxlen - 1);
+ dst[maxlen - 1] = '\0';
+ }
+ return srclen;
+}
+
char *internal_strncpy(char *dst, const char *src, uptr n) {
uptr i;
for (i = 0; i < n && src[i]; i++)
@@ -200,12 +226,12 @@ char *internal_strstr(const char *haystack, const char *needle) {
// This is O(N^2), but we are not using it in hot places.
uptr len1 = internal_strlen(haystack);
uptr len2 = internal_strlen(needle);
- if (len1 < len2) return 0;
+ if (len1 < len2) return nullptr;
for (uptr pos = 0; pos <= len1 - len2; pos++) {
if (internal_memcmp(haystack + pos, needle, len2) == 0)
return const_cast<char *>(haystack) + pos;
}
- return 0;
+ return nullptr;
}
s64 internal_simple_strtoll(const char *nptr, char **endptr, int base) {
@@ -229,7 +255,7 @@ s64 internal_simple_strtoll(const char *nptr, char **endptr, int base) {
have_digits = true;
nptr++;
}
- if (endptr != 0) {
+ if (endptr) {
*endptr = (have_digits) ? const_cast<char *>(nptr) : old_nptr;
}
if (sgn > 0) {
@@ -258,4 +284,4 @@ bool mem_is_zero(const char *beg, uptr size) {
return all == 0;
}
-} // namespace __sanitizer
+} // namespace __sanitizer
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_libc.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_libc.h
index ae4e938f4af9..df28677c6700 100644
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_libc.h
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_libc.h
@@ -13,6 +13,7 @@
// functions are intercepted. Instead, we implement a tiny subset of libc here.
// FIXME: Some of functions declared in this file are in fact POSIX, not libc.
//===----------------------------------------------------------------------===//
+
#ifndef SANITIZER_LIBC_H
#define SANITIZER_LIBC_H
@@ -42,8 +43,10 @@ uptr internal_strcspn(const char *s, const char *reject);
char *internal_strdup(const char *s);
char *internal_strndup(const char *s, uptr n);
uptr internal_strlen(const char *s);
+uptr internal_strlcat(char *dst, const char *src, uptr maxlen);
char *internal_strncat(char *dst, const char *src, uptr n);
int internal_strncmp(const char *s1, const char *s2, uptr n);
+uptr internal_strlcpy(char *dst, const char *src, uptr maxlen);
char *internal_strncpy(char *dst, const char *src, uptr n);
uptr internal_strnlen(const char *s, uptr maxlen);
char *internal_strrchr(const char *s, int c);
@@ -75,8 +78,8 @@ uptr internal_getppid();
uptr internal_sched_yield();
// Error handling
-bool internal_iserror(uptr retval, int *rverrno = 0);
+bool internal_iserror(uptr retval, int *rverrno = nullptr);
-} // namespace __sanitizer
+} // namespace __sanitizer
-#endif // SANITIZER_LIBC_H
+#endif // SANITIZER_LIBC_H
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_libignore.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_libignore.cc
index 8c4aeffda45e..545393966b38 100644
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_libignore.cc
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_libignore.cc
@@ -8,7 +8,8 @@
//===----------------------------------------------------------------------===//
#include "sanitizer_platform.h"
-#if SANITIZER_FREEBSD || SANITIZER_LINUX
+
+#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_MAC
#include "sanitizer_libignore.h"
#include "sanitizer_flags.h"
@@ -38,11 +39,11 @@ void LibIgnore::OnLibraryLoaded(const char *name) {
BlockingMutexLock lock(&mutex_);
// Try to match suppressions with symlink target.
InternalScopedString buf(kMaxPathLength);
- if (name != 0 && internal_readlink(name, buf.data(), buf.size() - 1) > 0 &&
+ if (name && internal_readlink(name, buf.data(), buf.size() - 1) > 0 &&
buf[0]) {
for (uptr i = 0; i < count_; i++) {
Lib *lib = &libs_[i];
- if (!lib->loaded && lib->real_name == 0 &&
+ if (!lib->loaded && (!lib->real_name) &&
TemplateMatch(lib->templ, name))
lib->real_name = internal_strdup(buf.data());
}
@@ -60,7 +61,7 @@ void LibIgnore::OnLibraryLoaded(const char *name) {
if ((prot & MemoryMappingLayout::kProtectionExecute) == 0)
continue;
if (TemplateMatch(lib->templ, module.data()) ||
- (lib->real_name != 0 &&
+ (lib->real_name &&
internal_strcmp(lib->real_name, module.data()) == 0)) {
if (loaded) {
Report("%s: called_from_lib suppression '%s' is matched against"
@@ -93,9 +94,9 @@ void LibIgnore::OnLibraryLoaded(const char *name) {
}
void LibIgnore::OnLibraryUnloaded() {
- OnLibraryLoaded(0);
+ OnLibraryLoaded(nullptr);
}
-} // namespace __sanitizer
+} // namespace __sanitizer
-#endif // #if SANITIZER_FREEBSD || SANITIZER_LINUX
+#endif // #if SANITIZER_FREEBSD || SANITIZER_LINUX
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_linux.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_linux.cc
index 98e5d122a0f9..cba38c8c3057 100644
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_linux.cc
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_linux.cc
@@ -13,9 +13,9 @@
//===----------------------------------------------------------------------===//
#include "sanitizer_platform.h"
+
#if SANITIZER_FREEBSD || SANITIZER_LINUX
-#include "sanitizer_allocator_internal.h"
#include "sanitizer_common.h"
#include "sanitizer_flags.h"
#include "sanitizer_internal_defs.h"
@@ -74,11 +74,6 @@ extern char **environ; // provided by crt1
#include <sys/signal.h>
#endif
-#if SANITIZER_ANDROID
-#include <android/log.h>
-#include <sys/system_properties.h>
-#endif
-
#if SANITIZER_LINUX
// <linux/time.h>
struct kernel_timeval {
@@ -94,7 +89,8 @@ const int FUTEX_WAKE = 1;
// Are we using 32-bit or 64-bit Linux syscalls?
// x32 (which defines __x86_64__) has SANITIZER_WORDSIZE == 32
// but it still needs to use 64-bit syscalls.
-#if SANITIZER_LINUX && (defined(__x86_64__) || SANITIZER_WORDSIZE == 64)
+#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__powerpc64__) || \
+ SANITIZER_WORDSIZE == 64)
# define SANITIZER_LINUX_USES_64BIT_SYSCALLS 1
#else
# define SANITIZER_LINUX_USES_64BIT_SYSCALLS 0
@@ -104,6 +100,8 @@ namespace __sanitizer {
#if SANITIZER_LINUX && defined(__x86_64__)
#include "sanitizer_syscall_linux_x86_64.inc"
+#elif SANITIZER_LINUX && defined(__aarch64__)
+#include "sanitizer_syscall_linux_aarch64.inc"
#else
#include "sanitizer_syscall_generic.inc"
#endif
@@ -375,23 +373,23 @@ const char *GetEnv(const char *name) {
if (!inited) {
inited = true;
uptr environ_size;
- len = ReadFileToBuffer("/proc/self/environ",
- &environ, &environ_size, 1 << 26);
+ if (!ReadFileToBuffer("/proc/self/environ", &environ, &environ_size, &len))
+ environ = nullptr;
}
- if (!environ || len == 0) return 0;
+ if (!environ || len == 0) return nullptr;
uptr namelen = internal_strlen(name);
const char *p = environ;
while (*p != '\0') { // will happen at the \0\0 that terminates the buffer
// proc file has the format NAME=value\0NAME=value\0NAME=value\0...
const char* endp =
(char*)internal_memchr(p, '\0', len - (p - environ));
- if (endp == 0) // this entry isn't NUL terminated
- return 0;
+ if (!endp) // this entry isn't NUL terminated
+ return nullptr;
else if (!internal_memcmp(p, name, namelen) && p[namelen] == '=') // Match.
return p + namelen + 1; // point after =
p = endp + 1;
}
- return 0; // Not found.
+ return nullptr; // Not found.
#else
#error "Unsupported platform"
#endif
@@ -405,9 +403,13 @@ extern "C" {
static void ReadNullSepFileToArray(const char *path, char ***arr,
int arr_size) {
char *buff;
- uptr buff_size = 0;
+ uptr buff_size;
+ uptr buff_len;
*arr = (char **)MmapOrDie(arr_size * sizeof(char *), "NullSepFileArray");
- ReadFileToBuffer(path, &buff, &buff_size, 1024 * 1024);
+ if (!ReadFileToBuffer(path, &buff, &buff_size, &buff_len, 1024 * 1024)) {
+ (*arr)[0] = nullptr;
+ return;
+ }
(*arr)[0] = buff;
int count, i;
for (count = 1, i = 1; ; i++) {
@@ -418,7 +420,7 @@ static void ReadNullSepFileToArray(const char *path, char ***arr,
count++;
}
}
- (*arr)[count] = 0;
+ (*arr)[count] = nullptr;
}
#endif
@@ -496,7 +498,7 @@ void BlockingMutex::CheckLocked() {
// Note that getdents64 uses a different structure format. We only provide the
// 32-bit syscall here.
struct linux_dirent {
-#if SANITIZER_X32
+#if SANITIZER_X32 || defined(__aarch64__)
u64 d_ino;
u64 d_off;
#else
@@ -504,6 +506,9 @@ struct linux_dirent {
unsigned long d_off;
#endif
unsigned short d_reclen;
+#ifdef __aarch64__
+ unsigned char d_type;
+#endif
char d_name[256];
};
@@ -585,8 +590,8 @@ int internal_sigaction_norestorer(int signum, const void *act, void *oldact) {
}
uptr result = internal_syscall(SYSCALL(rt_sigaction), (uptr)signum,
- (uptr)(u_act ? &k_act : NULL),
- (uptr)(u_oldact ? &k_oldact : NULL),
+ (uptr)(u_act ? &k_act : nullptr),
+ (uptr)(u_oldact ? &k_oldact : nullptr),
(uptr)sizeof(__sanitizer_kernel_sigset_t));
if ((result == 0) && u_oldact) {
@@ -732,6 +737,21 @@ uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) {
return module_name_len;
}
+uptr ReadLongProcessName(/*out*/ char *buf, uptr buf_len) {
+#if SANITIZER_LINUX
+ char *tmpbuf;
+ uptr tmpsize;
+ uptr tmplen;
+ if (ReadFileToBuffer("/proc/self/cmdline", &tmpbuf, &tmpsize, &tmplen,
+ 1024 * 1024)) {
+ internal_strncpy(buf, tmpbuf, buf_len);
+ UnmapOrDie(tmpbuf, tmpsize);
+ return internal_strlen(buf);
+ }
+#endif
+ return ReadBinaryName(buf, buf_len);
+}
+
// Match full names of the form /path/to/base_name{-,.}*
bool LibraryNameIs(const char *full_name, const char *base_name) {
const char *name = full_name;
@@ -913,41 +933,142 @@ uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
: "memory", "$29" );
return res;
}
-#endif // defined(__x86_64__) && SANITIZER_LINUX
+#elif defined(__aarch64__)
+uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
+ int *parent_tidptr, void *newtls, int *child_tidptr) {
+ long long res;
+ if (!fn || !child_stack)
+ return -EINVAL;
+ CHECK_EQ(0, (uptr)child_stack % 16);
+ child_stack = (char *)child_stack - 2 * sizeof(unsigned long long);
+ ((unsigned long long *)child_stack)[0] = (uptr)fn;
+ ((unsigned long long *)child_stack)[1] = (uptr)arg;
-#if SANITIZER_ANDROID
-static atomic_uint8_t android_log_initialized;
+ register int (*__fn)(void *) __asm__("x0") = fn;
+ register void *__stack __asm__("x1") = child_stack;
+ register int __flags __asm__("x2") = flags;
+ register void *__arg __asm__("x3") = arg;
+ register int *__ptid __asm__("x4") = parent_tidptr;
+ register void *__tls __asm__("x5") = newtls;
+ register int *__ctid __asm__("x6") = child_tidptr;
-void AndroidLogInit() {
- atomic_store(&android_log_initialized, 1, memory_order_release);
-}
-// This thing is not, strictly speaking, async signal safe, but it does not seem
-// to cause any issues. Alternative is writing to log devices directly, but
-// their location and message format might change in the future, so we'd really
-// like to avoid that.
-void AndroidLogWrite(const char *buffer) {
- if (!atomic_load(&android_log_initialized, memory_order_acquire))
- return;
+ __asm__ __volatile__(
+ "mov x0,x2\n" /* flags */
+ "mov x2,x4\n" /* ptid */
+ "mov x3,x5\n" /* tls */
+ "mov x4,x6\n" /* ctid */
+ "mov x8,%9\n" /* clone */
- char *copy = internal_strdup(buffer);
- char *p = copy;
- char *q;
- // __android_log_write has an implicit message length limit.
- // Print one line at a time.
- do {
- q = internal_strchr(p, '\n');
- if (q) *q = '\0';
- __android_log_write(ANDROID_LOG_INFO, NULL, p);
- if (q) p = q + 1;
- } while (q);
- InternalFree(copy);
+ "svc 0x0\n"
+
+ /* if (%r0 != 0)
+ * return %r0;
+ */
+ "cmp x0, #0\n"
+ "bne 1f\n"
+
+ /* In the child, now. Call "fn(arg)". */
+ "ldp x1, x0, [sp], #16\n"
+ "blr x1\n"
+
+ /* Call _exit(%r0). */
+ "mov x8, %10\n"
+ "svc 0x0\n"
+ "1:\n"
+
+ : "=r" (res)
+ : "i"(-EINVAL),
+ "r"(__fn), "r"(__stack), "r"(__flags), "r"(__arg),
+ "r"(__ptid), "r"(__tls), "r"(__ctid),
+ "i"(__NR_clone), "i"(__NR_exit)
+ : "x30", "memory");
+ return res;
}
+#elif defined(__powerpc64__)
+uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
+ int *parent_tidptr, void *newtls, int *child_tidptr) {
+ long long res;
+/* Stack frame offsets. */
+#if _CALL_ELF != 2
+#define FRAME_MIN_SIZE 112
+#define FRAME_TOC_SAVE 40
+#else
+#define FRAME_MIN_SIZE 32
+#define FRAME_TOC_SAVE 24
+#endif
+ if (!fn || !child_stack)
+ return -EINVAL;
+ CHECK_EQ(0, (uptr)child_stack % 16);
+ child_stack = (char *)child_stack - 2 * sizeof(unsigned long long);
+ ((unsigned long long *)child_stack)[0] = (uptr)fn;
+ ((unsigned long long *)child_stack)[1] = (uptr)arg;
-void GetExtraActivationFlags(char *buf, uptr size) {
- CHECK(size > PROP_VALUE_MAX);
- __system_property_get("asan.options", buf);
+ register int (*__fn)(void *) __asm__("r3") = fn;
+ register void *__cstack __asm__("r4") = child_stack;
+ register int __flags __asm__("r5") = flags;
+ register void * __arg __asm__("r6") = arg;
+ register int * __ptidptr __asm__("r7") = parent_tidptr;
+ register void * __newtls __asm__("r8") = newtls;
+ register int * __ctidptr __asm__("r9") = child_tidptr;
+
+ __asm__ __volatile__(
+ /* fn, arg, child_stack are saved acrVoss the syscall */
+ "mr 28, %5\n\t"
+ "mr 29, %6\n\t"
+ "mr 27, %8\n\t"
+
+ /* syscall
+ r3 == flags
+ r4 == child_stack
+ r5 == parent_tidptr
+ r6 == newtls
+ r7 == child_tidptr */
+ "mr 3, %7\n\t"
+ "mr 5, %9\n\t"
+ "mr 6, %10\n\t"
+ "mr 7, %11\n\t"
+ "li 0, %3\n\t"
+ "sc\n\t"
+
+ /* Test if syscall was successful */
+ "cmpdi cr1, 3, 0\n\t"
+ "crandc cr1*4+eq, cr1*4+eq, cr0*4+so\n\t"
+ "bne- cr1, 1f\n\t"
+
+ /* Do the function call */
+ "std 2, %13(1)\n\t"
+#if _CALL_ELF != 2
+ "ld 0, 0(28)\n\t"
+ "ld 2, 8(28)\n\t"
+ "mtctr 0\n\t"
+#else
+ "mr 12, 28\n\t"
+ "mtctr 12\n\t"
+#endif
+ "mr 3, 27\n\t"
+ "bctrl\n\t"
+ "ld 2, %13(1)\n\t"
+
+ /* Call _exit(r3) */
+ "li 0, %4\n\t"
+ "sc\n\t"
+
+ /* Return to parent */
+ "1:\n\t"
+ "mr %0, 3\n\t"
+ : "=r" (res)
+ : "0" (-1), "i" (EINVAL),
+ "i" (__NR_clone), "i" (__NR_exit),
+ "r" (__fn), "r" (__cstack), "r" (__flags),
+ "r" (__arg), "r" (__ptidptr), "r" (__newtls),
+ "r" (__ctidptr), "i" (FRAME_MIN_SIZE), "i" (FRAME_TOC_SAVE)
+ : "cr0", "cr1", "memory", "ctr",
+ "r0", "r29", "r27", "r28");
+ return res;
}
+#endif // defined(__x86_64__) && SANITIZER_LINUX
+#if SANITIZER_ANDROID
#if __ANDROID_API__ < 21
extern "C" __attribute__((weak)) int dl_iterate_phdr(
int (*)(struct dl_phdr_info *, size_t, void *), void *);
@@ -993,6 +1114,10 @@ AndroidApiLevel AndroidGetApiLevel() {
bool IsDeadlySignal(int signum) {
if (common_flags()->handle_abort && signum == SIGABRT)
return true;
+ if (common_flags()->handle_sigill && signum == SIGILL)
+ return true;
+ if (common_flags()->handle_sigfpe && signum == SIGFPE)
+ return true;
return (signum == SIGSEGV || signum == SIGBUS) && common_flags()->handle_segv;
}
@@ -1008,13 +1133,13 @@ void *internal_start_thread(void(*func)(void *arg), void *arg) {
#endif
internal_sigprocmask(SIG_SETMASK, &set, &old);
void *th;
- real_pthread_create(&th, 0, (void*(*)(void *arg))func, arg);
- internal_sigprocmask(SIG_SETMASK, &old, 0);
+ real_pthread_create(&th, nullptr, (void*(*)(void *arg))func, arg);
+ internal_sigprocmask(SIG_SETMASK, &old, nullptr);
return th;
}
void internal_join_thread(void *th) {
- real_pthread_join(th, 0);
+ real_pthread_join(th, nullptr);
}
#else
void *internal_start_thread(void (*func)(void *), void *arg) { return 0; }
@@ -1094,6 +1219,14 @@ void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
#endif
}
-} // namespace __sanitizer
+void DisableReexec() {
+ // No need to re-exec on Linux.
+}
+
+void MaybeReexec() {
+ // No need to re-exec on Linux.
+}
+
+} // namespace __sanitizer
-#endif // SANITIZER_FREEBSD || SANITIZER_LINUX
+#endif // SANITIZER_FREEBSD || SANITIZER_LINUX
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_linux.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_linux.h
index e9fc4ad448d8..77bfbd156815 100644
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_linux.h
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_linux.h
@@ -44,7 +44,8 @@ uptr internal_prctl(int option, uptr arg2, uptr arg3, uptr arg4, uptr arg5);
// internal_sigaction instead.
int internal_sigaction_norestorer(int signum, const void *act, void *oldact);
void internal_sigdelset(__sanitizer_sigset_t *set, int signum);
-#if defined(__x86_64__) || defined(__mips__)
+#if defined(__x86_64__) || defined(__mips__) || defined(__aarch64__) \
+ || defined(__powerpc64__)
uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
int *parent_tidptr, void *newtls, int *child_tidptr);
#endif
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cc
index 39eb1d216b2e..8cf2c73b1d53 100644
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cc
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cc
@@ -13,8 +13,10 @@
//===----------------------------------------------------------------------===//
#include "sanitizer_platform.h"
+
#if SANITIZER_FREEBSD || SANITIZER_LINUX
+#include "sanitizer_allocator_internal.h"
#include "sanitizer_atomic.h"
#include "sanitizer_common.h"
#include "sanitizer_flags.h"
@@ -47,6 +49,12 @@
#include <android/api-level.h>
#endif
+#if SANITIZER_ANDROID && __ANDROID_API__ < 21
+#include <android/log.h>
+#else
+#include <syslog.h>
+#endif
+
#if !SANITIZER_ANDROID
#include <elf.h>
#include <unistd.h>
@@ -54,20 +62,6 @@
namespace __sanitizer {
-// This function is defined elsewhere if we intercepted pthread_attr_getstack.
-extern "C" {
-SANITIZER_WEAK_ATTRIBUTE int
-real_pthread_attr_getstack(void *attr, void **addr, size_t *size);
-} // extern "C"
-
-static int my_pthread_attr_getstack(void *attr, void **addr, size_t *size) {
-#if !SANITIZER_GO
- if (&real_pthread_attr_getstack)
- return real_pthread_attr_getstack((pthread_attr_t *)attr, addr, size);
-#endif
- return pthread_attr_getstack((pthread_attr_t *)attr, addr, size);
-}
-
SANITIZER_WEAK_ATTRIBUTE int
real_sigaction(int signum, const void *act, void *oldact);
@@ -93,7 +87,8 @@ void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
MemoryMappingLayout proc_maps(/*cache_enabled*/true);
uptr start, end, offset;
uptr prev_end = 0;
- while (proc_maps.Next(&start, &end, &offset, 0, 0, /* protection */0)) {
+ while (proc_maps.Next(&start, &end, &offset, nullptr, 0,
+ /* protection */nullptr)) {
if ((uptr)&rl < end)
break;
prev_end = end;
@@ -118,8 +113,8 @@ void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
pthread_attr_init(&attr);
CHECK_EQ(pthread_getattr_np(pthread_self(), &attr), 0);
uptr stacksize = 0;
- void *stackaddr = 0;
- my_pthread_attr_getstack(&attr, &stackaddr, (size_t*)&stacksize);
+ void *stackaddr = nullptr;
+ my_pthread_attr_getstack(&attr, &stackaddr, &stacksize);
pthread_attr_destroy(&attr);
CHECK_LE(stacksize, kMaxThreadStackSize); // Sanity check.
@@ -130,7 +125,7 @@ void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
#if !SANITIZER_GO
bool SetEnv(const char *name, const char *value) {
void *f = dlsym(RTLD_NEXT, "setenv");
- if (f == 0)
+ if (!f)
return false;
typedef int(*setenv_ft)(const char *name, const char *value, int overwrite);
setenv_ft setenv_f;
@@ -161,7 +156,7 @@ bool SanitizerGetThreadName(char *name, int max_len) {
#endif
}
-#if !SANITIZER_FREEBSD
+#if !SANITIZER_FREEBSD && !SANITIZER_ANDROID && !SANITIZER_GO
static uptr g_tls_size;
#endif
@@ -171,11 +166,15 @@ static uptr g_tls_size;
# define DL_INTERNAL_FUNCTION
#endif
-#if defined(__mips__)
+#if defined(__mips__) || defined(__powerpc64__)
// TlsPreTcbSize includes size of struct pthread_descr and size of tcb
// head structure. It lies before the static tls blocks.
static uptr TlsPreTcbSize() {
- const uptr kTcbHead = 16;
+# if defined(__mips__)
+ const uptr kTcbHead = 16; // sizeof (tcbhead_t)
+# elif defined(__powerpc64__)
+ const uptr kTcbHead = 88; // sizeof (tcbhead_t)
+# endif
const uptr kTlsAlign = 16;
const uptr kTlsPreTcbSize =
(ThreadDescriptorSize() + kTcbHead + kTlsAlign - 1) & ~(kTlsAlign - 1);
@@ -187,6 +186,8 @@ static uptr TlsPreTcbSize() {
void InitTlsSize() {
#if !SANITIZER_FREEBSD && !SANITIZER_ANDROID && !SANITIZER_GO
+// all current supported platforms have 16 bytes stack alignment
+ const size_t kStackAlign = 16;
typedef void (*get_tls_func)(size_t*, size_t*) DL_INTERNAL_FUNCTION;
get_tls_func get_tls;
void *get_tls_static_info_ptr = dlsym(RTLD_NEXT, "_dl_get_tls_static_info");
@@ -197,13 +198,16 @@ void InitTlsSize() {
size_t tls_size = 0;
size_t tls_align = 0;
get_tls(&tls_size, &tls_align);
- g_tls_size = tls_size;
-#endif // !SANITIZER_FREEBSD && !SANITIZER_ANDROID
+ if (tls_align < kStackAlign)
+ tls_align = kStackAlign;
+ g_tls_size = RoundUpTo(tls_size, tls_align);
+#endif // !SANITIZER_FREEBSD && !SANITIZER_ANDROID && !SANITIZER_GO
}
-#if (defined(__x86_64__) || defined(__i386__) || defined(__mips__)) \
- && SANITIZER_LINUX
-// sizeof(struct thread) from glibc.
+#if (defined(__x86_64__) || defined(__i386__) || defined(__mips__) \
+ || defined(__aarch64__) || defined(__powerpc64__)) \
+ && SANITIZER_LINUX && !SANITIZER_ANDROID
+// sizeof(struct pthread) from glibc.
static atomic_uintptr_t kThreadDescriptorSize;
uptr ThreadDescriptorSize() {
@@ -218,7 +222,7 @@ uptr ThreadDescriptorSize() {
char *end;
int minor = internal_simple_strtoll(buf + 8, &end, 10);
if (end != buf + 8 && (*end == '\0' || *end == '.')) {
- /* sizeof(struct thread) values from various glibc versions. */
+ /* sizeof(struct pthread) values from various glibc versions. */
if (SANITIZER_X32)
val = 1728; // Assume only one particular version for x32.
else if (minor <= 3)
@@ -249,6 +253,15 @@ uptr ThreadDescriptorSize() {
if (val)
atomic_store(&kThreadDescriptorSize, val, memory_order_relaxed);
return val;
+#elif defined(__aarch64__)
+ // The sizeof (struct pthread) is the same from GLIBC 2.17 to 2.22.
+ val = 1776;
+ atomic_store(&kThreadDescriptorSize, val, memory_order_relaxed);
+ return val;
+#elif defined(__powerpc64__)
+ val = 1776; // from glibc.ppc64le 2.20-8.fc21
+ atomic_store(&kThreadDescriptorSize, val, memory_order_relaxed);
+ return val;
#endif
return 0;
}
@@ -278,6 +291,17 @@ uptr ThreadSelf() {
rdhwr %0,$29;\
.set pop" : "=r" (thread_pointer));
descr_addr = thread_pointer - kTlsTcbOffset - TlsPreTcbSize();
+# elif defined(__aarch64__)
+ descr_addr = reinterpret_cast<uptr>(__builtin_thread_pointer());
+# elif defined(__powerpc64__)
+ // PPC64LE uses TLS variant I. The thread pointer (in GPR 13)
+ // points to the end of the TCB + 0x7000. The pthread_descr structure is
+ // immediately in front of the TCB. TlsPreTcbSize() includes the size of the
+ // TCB and the size of pthread_descr.
+ const uptr kTlsTcbOffset = 0x7000;
+ uptr thread_pointer;
+ asm("addi %0,13,%1" : "=r"(thread_pointer) : "I"(-kTlsTcbOffset));
+ descr_addr = thread_pointer - TlsPreTcbSize();
# else
# error "unsupported CPU arch"
# endif
@@ -307,13 +331,13 @@ uptr ThreadSelf() {
#if !SANITIZER_GO
static void GetTls(uptr *addr, uptr *size) {
-#if SANITIZER_LINUX
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
# if defined(__x86_64__) || defined(__i386__)
*addr = ThreadSelf();
*size = GetTlsSize();
*addr -= *size;
*addr += ThreadDescriptorSize();
-# elif defined(__mips__)
+# elif defined(__mips__) || defined(__aarch64__) || defined(__powerpc64__)
*addr = ThreadSelf();
*size = GetTlsSize();
# else
@@ -333,6 +357,9 @@ static void GetTls(uptr *addr, uptr *size) {
*addr = (uptr) dtv[2];
*size = (*addr == 0) ? 0 : ((uptr) segbase[0] - (uptr) dtv[2]);
}
+#elif SANITIZER_ANDROID
+ *addr = 0;
+ *size = 0;
#else
# error "Unknown OS"
#endif
@@ -341,7 +368,7 @@ static void GetTls(uptr *addr, uptr *size) {
#if !SANITIZER_GO
uptr GetTlsSize() {
-#if SANITIZER_FREEBSD
+#if SANITIZER_FREEBSD || SANITIZER_ANDROID
uptr addr, size;
GetTls(&addr, &size);
return size;
@@ -376,31 +403,6 @@ void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
#endif
}
-void AdjustStackSize(void *attr_) {
- pthread_attr_t *attr = (pthread_attr_t *)attr_;
- uptr stackaddr = 0;
- size_t stacksize = 0;
- my_pthread_attr_getstack(attr, (void**)&stackaddr, &stacksize);
- // GLibC will return (0 - stacksize) as the stack address in the case when
- // stacksize is set, but stackaddr is not.
- bool stack_set = (stackaddr != 0) && (stackaddr + stacksize != 0);
- // We place a lot of tool data into TLS, account for that.
- const uptr minstacksize = GetTlsSize() + 128*1024;
- if (stacksize < minstacksize) {
- if (!stack_set) {
- if (stacksize != 0) {
- VPrintf(1, "Sanitizer: increasing stacksize %zu->%zu\n", stacksize,
- minstacksize);
- pthread_attr_setstacksize(attr, minstacksize);
- }
- } else {
- Printf("Sanitizer: pre-allocated stack size is insufficient: "
- "%zu < %zu\n", stacksize, minstacksize);
- Printf("Sanitizer: pthread_create is likely to fail.\n");
- }
- }
-}
-
# if !SANITIZER_FREEBSD
typedef ElfW(Phdr) Elf_Phdr;
# elif SANITIZER_WORDSIZE == 32 && __FreeBSD_version <= 902001 // v9.2
@@ -455,7 +457,7 @@ extern "C" __attribute__((weak)) int dl_iterate_phdr(
uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
string_predicate_t filter) {
-#if SANITIZER_ANDROID && __ANDROID_API__ < 21
+#if SANITIZER_ANDROID && __ANDROID_API__ <= 22
u32 api_level = AndroidGetApiLevel();
// Fall back to /proc/maps if dl_iterate_phdr is unavailable or broken.
// The runtime check allows the same library to work with
@@ -510,6 +512,42 @@ uptr GetRSS() {
return rss * GetPageSizeCached();
}
-} // namespace __sanitizer
+// 64-bit Android targets don't provide the deprecated __android_log_write.
+// Starting with the L release, syslog() works and is preferable to
+// __android_log_write.
+#if SANITIZER_LINUX
+
+#if SANITIZER_ANDROID
+static atomic_uint8_t android_log_initialized;
+
+void AndroidLogInit() {
+ atomic_store(&android_log_initialized, 1, memory_order_release);
+}
+
+static bool ShouldLogAfterPrintf() {
+ return atomic_load(&android_log_initialized, memory_order_acquire);
+}
+#else
+void AndroidLogInit() {}
+
+static bool ShouldLogAfterPrintf() { return true; }
+#endif // SANITIZER_ANDROID
+
+void WriteOneLineToSyslog(const char *s) {
+#if SANITIZER_ANDROID &&__ANDROID_API__ < 21
+ __android_log_write(ANDROID_LOG_INFO, NULL, s);
+#else
+ syslog(LOG_INFO, "%s", s);
+#endif
+}
+
+void LogMessageOnPrintf(const char *str) {
+ if (common_flags()->log_to_syslog && ShouldLogAfterPrintf())
+ WriteToSyslog(str);
+}
+
+#endif // SANITIZER_LINUX
+
+} // namespace __sanitizer
-#endif // SANITIZER_FREEBSD || SANITIZER_LINUX
+#endif // SANITIZER_FREEBSD || SANITIZER_LINUX
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_list.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_list.h
index 6dd9c8f7bca1..adbb97dc70dc 100644
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_list.h
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_list.h
@@ -11,6 +11,7 @@
// ThreadSanitizer, etc run-times.
//
//===----------------------------------------------------------------------===//
+
#ifndef SANITIZER_LIST_H
#define SANITIZER_LIST_H
@@ -29,7 +30,7 @@ struct IntrusiveList {
friend class Iterator;
void clear() {
- first_ = last_ = 0;
+ first_ = last_ = nullptr;
size_ = 0;
}
@@ -38,11 +39,11 @@ struct IntrusiveList {
void push_back(Item *x) {
if (empty()) {
- x->next = 0;
+ x->next = nullptr;
first_ = last_ = x;
size_ = 1;
} else {
- x->next = 0;
+ x->next = nullptr;
last_->next = x;
last_ = x;
size_++;
@@ -51,7 +52,7 @@ struct IntrusiveList {
void push_front(Item *x) {
if (empty()) {
- x->next = 0;
+ x->next = nullptr;
first_ = last_ = x;
size_ = 1;
} else {
@@ -64,8 +65,8 @@ struct IntrusiveList {
void pop_front() {
CHECK(!empty());
first_ = first_->next;
- if (first_ == 0)
- last_ = 0;
+ if (!first_)
+ last_ = nullptr;
size_--;
}
@@ -125,7 +126,7 @@ struct IntrusiveList {
if (current_) current_ = current_->next;
return ret;
}
- bool hasNext() const { return current_ != 0; }
+ bool hasNext() const { return current_ != nullptr; }
private:
ListTy *list_;
ItemTy *current_;
@@ -140,6 +141,6 @@ struct IntrusiveList {
Item *last_;
};
-} // namespace __sanitizer
+} // namespace __sanitizer
-#endif // SANITIZER_LIST_H
+#endif // SANITIZER_LIST_H
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_mac.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_mac.cc
index dddce1c1583c..715509d30746 100644
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_mac.cc
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_mac.cc
@@ -13,6 +13,7 @@
#include "sanitizer_platform.h"
#if SANITIZER_MAC
+#include "sanitizer_mac.h"
// Use 64-bit inodes in file operations. ASan does not support OS X 10.5, so
// the clients will most certainly use 64-bit ones as well.
@@ -25,7 +26,6 @@
#include "sanitizer_flags.h"
#include "sanitizer_internal_defs.h"
#include "sanitizer_libc.h"
-#include "sanitizer_mac.h"
#include "sanitizer_placement_new.h"
#include "sanitizer_platform_limits_posix.h"
#include "sanitizer_procmaps.h"
@@ -36,11 +36,29 @@
extern char **environ;
#endif
+#if defined(__has_include) && __has_include(<os/trace.h>)
+#define SANITIZER_OS_TRACE 1
+#include <os/trace.h>
+#else
+#define SANITIZER_OS_TRACE 0
+#endif
+
+#if !SANITIZER_IOS
+#include <crt_externs.h> // for _NSGetArgv and _NSGetEnviron
+#else
+extern "C" {
+ extern char ***_NSGetArgv(void);
+}
+#endif
+
+#include <asl.h>
+#include <dlfcn.h> // for dladdr()
#include <errno.h>
#include <fcntl.h>
#include <libkern/OSAtomic.h>
#include <mach-o/dyld.h>
#include <mach/mach.h>
+#include <mach/vm_statistics.h>
#include <pthread.h>
#include <sched.h>
#include <signal.h>
@@ -51,6 +69,7 @@ extern char **environ;
#include <sys/sysctl.h>
#include <sys/types.h>
#include <unistd.h>
+#include <util.h>
namespace __sanitizer {
@@ -59,6 +78,7 @@ namespace __sanitizer {
// ---------------------- sanitizer_libc.h
uptr internal_mmap(void *addr, size_t length, int prot, int flags,
int fd, u64 offset) {
+ if (fd == -1) fd = VM_MAKE_TAG(VM_MEMORY_ANALYSIS_TOOL);
return (uptr)mmap(addr, length, prot, flags, fd, offset);
}
@@ -145,9 +165,30 @@ uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set,
return sigprocmask(how, set, oldset);
}
+// Doesn't call pthread_atfork() handlers.
+extern "C" pid_t __fork(void);
+
int internal_fork() {
- // TODO(glider): this may call user's pthread_atfork() handlers which is bad.
- return fork();
+ return __fork();
+}
+
+int internal_forkpty(int *amaster) {
+ int master, slave;
+ if (openpty(&master, &slave, nullptr, nullptr, nullptr) == -1) return -1;
+ int pid = __fork();
+ if (pid == -1) {
+ close(master);
+ close(slave);
+ return -1;
+ }
+ if (pid == 0) {
+ close(master);
+ CHECK_EQ(login_tty(slave), 0);
+ } else {
+ *amaster = master;
+ close(slave);
+ }
+ return pid;
}
uptr internal_rename(const char *oldpath, const char *newpath) {
@@ -178,7 +219,7 @@ void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
uptr stacksize = pthread_get_stacksize_np(pthread_self());
// pthread_get_stacksize_np() returns an incorrect stack size for the main
// thread on Mavericks. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=261
+ // https://github.com/google/sanitizers/issues/261
if ((GetMacosVersion() >= MACOS_VERSION_MAVERICKS) && at_initialization &&
stacksize == (1 << 19)) {
struct rlimit rl;
@@ -241,6 +282,10 @@ uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) {
return 0;
}
+uptr ReadLongProcessName(/*out*/char *buf, uptr buf_len) {
+ return ReadBinaryName(buf, buf_len);
+}
+
void ReExec() {
UNIMPLEMENTED();
}
@@ -365,8 +410,67 @@ uptr GetRSS() {
return info.resident_size;
}
-void *internal_start_thread(void (*func)(void *arg), void *arg) { return 0; }
-void internal_join_thread(void *th) { }
+void *internal_start_thread(void(*func)(void *arg), void *arg) {
+ // Start the thread with signals blocked, otherwise it can steal user signals.
+ __sanitizer_sigset_t set, old;
+ internal_sigfillset(&set);
+ internal_sigprocmask(SIG_SETMASK, &set, &old);
+ pthread_t th;
+ pthread_create(&th, 0, (void*(*)(void *arg))func, arg);
+ internal_sigprocmask(SIG_SETMASK, &old, 0);
+ return th;
+}
+
+void internal_join_thread(void *th) { pthread_join((pthread_t)th, 0); }
+
+static BlockingMutex syslog_lock(LINKER_INITIALIZED);
+
+void WriteOneLineToSyslog(const char *s) {
+ syslog_lock.CheckLocked();
+ asl_log(nullptr, nullptr, ASL_LEVEL_ERR, "%s", s);
+}
+
+void LogMessageOnPrintf(const char *str) {
+ // Log all printf output to CrashLog.
+ if (common_flags()->abort_on_error)
+ CRAppendCrashLogMessage(str);
+}
+
+void LogFullErrorReport(const char *buffer) {
+ // Log with os_trace. This will make it into the crash log.
+#if SANITIZER_OS_TRACE
+ if (GetMacosVersion() >= MACOS_VERSION_YOSEMITE) {
+ // os_trace requires the message (format parameter) to be a string literal.
+ if (internal_strncmp(SanitizerToolName, "AddressSanitizer",
+ sizeof("AddressSanitizer") - 1) == 0)
+ os_trace("Address Sanitizer reported a failure.");
+ else if (internal_strncmp(SanitizerToolName, "UndefinedBehaviorSanitizer",
+ sizeof("UndefinedBehaviorSanitizer") - 1) == 0)
+ os_trace("Undefined Behavior Sanitizer reported a failure.");
+ else if (internal_strncmp(SanitizerToolName, "ThreadSanitizer",
+ sizeof("ThreadSanitizer") - 1) == 0)
+ os_trace("Thread Sanitizer reported a failure.");
+ else
+ os_trace("Sanitizer tool reported a failure.");
+
+ if (common_flags()->log_to_syslog)
+ os_trace("Consult syslog for more information.");
+ }
+#endif
+
+ // Log to syslog.
+ // The logging on OS X may call pthread_create so we need the threading
+ // environment to be fully initialized. Also, this should never be called when
+ // holding the thread registry lock since that may result in a deadlock. If
+ // the reporting thread holds the thread registry mutex, and asl_log waits
+ // for GCD to dispatch a new thread, the process will deadlock, because the
+ // pthread_create wrapper needs to acquire the lock as well.
+ BlockingMutexLock l(&syslog_lock);
+ if (common_flags()->log_to_syslog)
+ WriteToSyslog(buffer);
+
+ // The report is added to CrashLog as part of logging all of Printf output.
+}
void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
ucontext_t *ucontext = (ucontext_t*)context;
@@ -395,6 +499,173 @@ void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
# endif
}
+static const char kDyldInsertLibraries[] = "DYLD_INSERT_LIBRARIES";
+LowLevelAllocator allocator_for_env;
+
+// Change the value of the env var |name|, leaking the original value.
+// If |name_value| is NULL, the variable is deleted from the environment,
+// otherwise the corresponding "NAME=value" string is replaced with
+// |name_value|.
+void LeakyResetEnv(const char *name, const char *name_value) {
+ char **env = GetEnviron();
+ uptr name_len = internal_strlen(name);
+ while (*env != 0) {
+ uptr len = internal_strlen(*env);
+ if (len > name_len) {
+ const char *p = *env;
+ if (!internal_memcmp(p, name, name_len) && p[name_len] == '=') {
+ // Match.
+ if (name_value) {
+ // Replace the old value with the new one.
+ *env = const_cast<char*>(name_value);
+ } else {
+ // Shift the subsequent pointers back.
+ char **del = env;
+ do {
+ del[0] = del[1];
+ } while (*del++);
+ }
+ }
+ }
+ env++;
+ }
+}
+
+static bool reexec_disabled = false;
+
+void DisableReexec() {
+ reexec_disabled = true;
+}
+
+extern "C" double dyldVersionNumber;
+static const double kMinDyldVersionWithAutoInterposition = 360.0;
+
+bool DyldNeedsEnvVariable() {
+ // If running on OS X 10.11+ or iOS 9.0+, dyld will interpose even if
+ // DYLD_INSERT_LIBRARIES is not set. However, checking OS version via
+ // GetMacosVersion() doesn't work for the simulator. Let's instead check
+ // `dyldVersionNumber`, which is exported by dyld, against a known version
+ // number from the first OS release where this appeared.
+ return dyldVersionNumber < kMinDyldVersionWithAutoInterposition;
+}
+
+void MaybeReexec() {
+ if (reexec_disabled) return;
+
+ // Make sure the dynamic runtime library is preloaded so that the
+ // wrappers work. If it is not, set DYLD_INSERT_LIBRARIES and re-exec
+ // ourselves.
+ Dl_info info;
+ CHECK(dladdr((void*)((uptr)&__sanitizer_report_error_summary), &info));
+ char *dyld_insert_libraries =
+ const_cast<char*>(GetEnv(kDyldInsertLibraries));
+ uptr old_env_len = dyld_insert_libraries ?
+ internal_strlen(dyld_insert_libraries) : 0;
+ uptr fname_len = internal_strlen(info.dli_fname);
+ const char *dylib_name = StripModuleName(info.dli_fname);
+ uptr dylib_name_len = internal_strlen(dylib_name);
+
+ bool lib_is_in_env = dyld_insert_libraries &&
+ internal_strstr(dyld_insert_libraries, dylib_name);
+ if (DyldNeedsEnvVariable() && !lib_is_in_env) {
+ // DYLD_INSERT_LIBRARIES is not set or does not contain the runtime
+ // library.
+ InternalScopedString program_name(1024);
+ uint32_t buf_size = program_name.size();
+ _NSGetExecutablePath(program_name.data(), &buf_size);
+ char *new_env = const_cast<char*>(info.dli_fname);
+ if (dyld_insert_libraries) {
+ // Append the runtime dylib name to the existing value of
+ // DYLD_INSERT_LIBRARIES.
+ new_env = (char*)allocator_for_env.Allocate(old_env_len + fname_len + 2);
+ internal_strncpy(new_env, dyld_insert_libraries, old_env_len);
+ new_env[old_env_len] = ':';
+ // Copy fname_len and add a trailing zero.
+ internal_strncpy(new_env + old_env_len + 1, info.dli_fname,
+ fname_len + 1);
+ // Ok to use setenv() since the wrappers don't depend on the value of
+ // asan_inited.
+ setenv(kDyldInsertLibraries, new_env, /*overwrite*/1);
+ } else {
+ // Set DYLD_INSERT_LIBRARIES equal to the runtime dylib name.
+ setenv(kDyldInsertLibraries, info.dli_fname, /*overwrite*/0);
+ }
+ VReport(1, "exec()-ing the program with\n");
+ VReport(1, "%s=%s\n", kDyldInsertLibraries, new_env);
+ VReport(1, "to enable wrappers.\n");
+ execv(program_name.data(), *_NSGetArgv());
+
+ // We get here only if execv() failed.
+ Report("ERROR: The process is launched without DYLD_INSERT_LIBRARIES, "
+ "which is required for the sanitizer to work. We tried to set the "
+ "environment variable and re-execute itself, but execv() failed, "
+ "possibly because of sandbox restrictions. Make sure to launch the "
+ "executable with:\n%s=%s\n", kDyldInsertLibraries, new_env);
+ CHECK("execv failed" && 0);
+ }
+
+ if (!lib_is_in_env)
+ return;
+
+ // DYLD_INSERT_LIBRARIES is set and contains the runtime library. Let's remove
+ // the dylib from the environment variable, because interceptors are installed
+ // and we don't want our children to inherit the variable.
+
+ uptr env_name_len = internal_strlen(kDyldInsertLibraries);
+ // Allocate memory to hold the previous env var name, its value, the '='
+ // sign and the '\0' char.
+ char *new_env = (char*)allocator_for_env.Allocate(
+ old_env_len + 2 + env_name_len);
+ CHECK(new_env);
+ internal_memset(new_env, '\0', old_env_len + 2 + env_name_len);
+ internal_strncpy(new_env, kDyldInsertLibraries, env_name_len);
+ new_env[env_name_len] = '=';
+ char *new_env_pos = new_env + env_name_len + 1;
+
+ // Iterate over colon-separated pieces of |dyld_insert_libraries|.
+ char *piece_start = dyld_insert_libraries;
+ char *piece_end = NULL;
+ char *old_env_end = dyld_insert_libraries + old_env_len;
+ do {
+ if (piece_start[0] == ':') piece_start++;
+ piece_end = internal_strchr(piece_start, ':');
+ if (!piece_end) piece_end = dyld_insert_libraries + old_env_len;
+ if ((uptr)(piece_start - dyld_insert_libraries) > old_env_len) break;
+ uptr piece_len = piece_end - piece_start;
+
+ char *filename_start =
+ (char *)internal_memrchr(piece_start, '/', piece_len);
+ uptr filename_len = piece_len;
+ if (filename_start) {
+ filename_start += 1;
+ filename_len = piece_len - (filename_start - piece_start);
+ } else {
+ filename_start = piece_start;
+ }
+
+ // If the current piece isn't the runtime library name,
+ // append it to new_env.
+ if ((dylib_name_len != filename_len) ||
+ (internal_memcmp(filename_start, dylib_name, dylib_name_len) != 0)) {
+ if (new_env_pos != new_env + env_name_len + 1) {
+ new_env_pos[0] = ':';
+ new_env_pos++;
+ }
+ internal_strncpy(new_env_pos, piece_start, piece_len);
+ new_env_pos += piece_len;
+ }
+ // Move on to the next piece.
+ piece_start = piece_end;
+ } while (piece_start < old_env_end);
+
+ // Can't use setenv() here, because it requires the allocator to be
+ // initialized.
+ // FIXME: instead of filtering DYLD_INSERT_LIBRARIES here, do it in
+ // a separate function called after InitializeAllocator().
+ if (new_env_pos == new_env + env_name_len + 1) new_env = NULL;
+ LeakyResetEnv(kDyldInsertLibraries, new_env);
+}
+
} // namespace __sanitizer
#endif // SANITIZER_MAC
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_mac.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_mac.h
index 50dbe93226c2..6e2b84f432e5 100644
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_mac.h
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_mac.h
@@ -13,6 +13,7 @@
#ifndef SANITIZER_MAC_H
#define SANITIZER_MAC_H
+#include "sanitizer_common.h"
#include "sanitizer_platform.h"
#if SANITIZER_MAC
#include "sanitizer_posix.h"
@@ -37,5 +38,18 @@ char **GetEnviron();
} // namespace __sanitizer
+extern "C" {
+static char __crashreporter_info_buff__[kErrorMessageBufferSize] = {};
+static const char *__crashreporter_info__ __attribute__((__used__)) =
+ &__crashreporter_info_buff__[0];
+asm(".desc ___crashreporter_info__, 0x10");
+} // extern "C"
+static BlockingMutex crashreporter_info_mutex(LINKER_INITIALIZED);
+
+INLINE void CRAppendCrashLogMessage(const char *msg) {
+ BlockingMutexLock l(&crashreporter_info_mutex);
+ internal_strlcat(__crashreporter_info_buff__, msg,
+ sizeof(__crashreporter_info_buff__)); }
+
#endif // SANITIZER_MAC
#endif // SANITIZER_MAC_H
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_malloc_mac.inc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_malloc_mac.inc
new file mode 100644
index 000000000000..149857c168c6
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_malloc_mac.inc
@@ -0,0 +1,329 @@
+//===-- sanitizer_malloc_mac.inc --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains Mac-specific malloc interceptors and a custom zone
+// implementation, which together replace the system allocator.
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_platform.h"
+#if !SANITIZER_MAC
+#error "This file should only be compiled on Darwin."
+#endif
+
+#include <AvailabilityMacros.h>
+#include <CoreFoundation/CFBase.h>
+#include <dlfcn.h>
+#include <malloc/malloc.h>
+#include <sys/mman.h>
+
+#include "interception/interception.h"
+#include "sanitizer_common/sanitizer_mac.h"
+
+// Similar code is used in Google Perftools,
+// https://github.com/gperftools/gperftools.
+
+static malloc_zone_t sanitizer_zone;
+
+INTERCEPTOR(malloc_zone_t *, malloc_create_zone,
+ vm_size_t start_size, unsigned zone_flags) {
+ COMMON_MALLOC_ENTER();
+ uptr page_size = GetPageSizeCached();
+ uptr allocated_size = RoundUpTo(sizeof(sanitizer_zone), page_size);
+ COMMON_MALLOC_MEMALIGN(page_size, allocated_size);
+ malloc_zone_t *new_zone = (malloc_zone_t *)p;
+ internal_memcpy(new_zone, &sanitizer_zone, sizeof(sanitizer_zone));
+ new_zone->zone_name = NULL; // The name will be changed anyway.
+ if (GetMacosVersion() >= MACOS_VERSION_LION) {
+ // Prevent the client app from overwriting the zone contents.
+ // Library functions that need to modify the zone will set PROT_WRITE on it.
+ // This matches the behavior of malloc_create_zone() on OSX 10.7 and higher.
+ mprotect(new_zone, allocated_size, PROT_READ);
+ }
+ return new_zone;
+}
+
+INTERCEPTOR(malloc_zone_t *, malloc_default_zone, void) {
+ COMMON_MALLOC_ENTER();
+ return &sanitizer_zone;
+}
+
+INTERCEPTOR(malloc_zone_t *, malloc_default_purgeable_zone, void) {
+ // FIXME: ASan should support purgeable allocations.
+ // https://github.com/google/sanitizers/issues/139
+ COMMON_MALLOC_ENTER();
+ return &sanitizer_zone;
+}
+
+INTERCEPTOR(void, malloc_make_purgeable, void *ptr) {
+ // FIXME: ASan should support purgeable allocations. Ignoring them is fine
+ // for now.
+ COMMON_MALLOC_ENTER();
+}
+
+INTERCEPTOR(int, malloc_make_nonpurgeable, void *ptr) {
+ // FIXME: ASan should support purgeable allocations. Ignoring them is fine
+ // for now.
+ COMMON_MALLOC_ENTER();
+ // Must return 0 if the contents were not purged since the last call to
+ // malloc_make_purgeable().
+ return 0;
+}
+
+INTERCEPTOR(void, malloc_set_zone_name, malloc_zone_t *zone, const char *name) {
+ COMMON_MALLOC_ENTER();
+ // Allocate |sizeof(COMMON_MALLOC_ZONE_NAME "-") + internal_strlen(name)|
+ // bytes.
+ size_t buflen =
+ sizeof(COMMON_MALLOC_ZONE_NAME "-") + (name ? internal_strlen(name) : 0);
+ InternalScopedString new_name(buflen);
+ if (name && zone->introspect == sanitizer_zone.introspect) {
+ new_name.append(COMMON_MALLOC_ZONE_NAME "-%s", name);
+ name = new_name.data();
+ }
+
+ // Call the system malloc's implementation for both external and our zones,
+ // since that appropriately changes VM region protections on the zone.
+ REAL(malloc_set_zone_name)(zone, name);
+}
+
+INTERCEPTOR(void *, malloc, size_t size) {
+ COMMON_MALLOC_ENTER();
+ COMMON_MALLOC_MALLOC(size);
+ return p;
+}
+
+INTERCEPTOR(void, free, void *ptr) {
+ COMMON_MALLOC_ENTER();
+ if (!ptr) return;
+ COMMON_MALLOC_FREE(ptr);
+}
+
+INTERCEPTOR(void *, realloc, void *ptr, size_t size) {
+ COMMON_MALLOC_ENTER();
+ COMMON_MALLOC_REALLOC(ptr, size);
+ return p;
+}
+
+INTERCEPTOR(void *, calloc, size_t nmemb, size_t size) {
+ COMMON_MALLOC_ENTER();
+ COMMON_MALLOC_CALLOC(nmemb, size);
+ return p;
+}
+
+INTERCEPTOR(void *, valloc, size_t size) {
+ COMMON_MALLOC_ENTER();
+ COMMON_MALLOC_VALLOC(size);
+ return p;
+}
+
+INTERCEPTOR(size_t, malloc_good_size, size_t size) {
+ COMMON_MALLOC_ENTER();
+ return sanitizer_zone.introspect->good_size(&sanitizer_zone, size);
+}
+
+INTERCEPTOR(int, posix_memalign, void **memptr, size_t alignment, size_t size) {
+ COMMON_MALLOC_ENTER();
+ CHECK(memptr);
+ COMMON_MALLOC_MEMALIGN(alignment, size);
+ if (p) {
+ *memptr = p;
+ return 0;
+ }
+ return -1;
+}
+
+namespace {
+
+// TODO(glider): the __sanitizer_mz_* functions should be united with the Linux
+// wrappers, as they are basically copied from there.
+extern "C"
+SANITIZER_INTERFACE_ATTRIBUTE
+size_t __sanitizer_mz_size(malloc_zone_t* zone, const void* ptr) {
+ COMMON_MALLOC_SIZE(ptr);
+ return size;
+}
+
+extern "C"
+SANITIZER_INTERFACE_ATTRIBUTE
+void *__sanitizer_mz_malloc(malloc_zone_t *zone, uptr size) {
+ COMMON_MALLOC_ENTER();
+ COMMON_MALLOC_MALLOC(size);
+ return p;
+}
+
+extern "C"
+SANITIZER_INTERFACE_ATTRIBUTE
+void *__sanitizer_mz_calloc(malloc_zone_t *zone, size_t nmemb, size_t size) {
+ if (UNLIKELY(!COMMON_MALLOC_SANITIZER_INITIALIZED)) {
+ // Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym.
+ const size_t kCallocPoolSize = 1024;
+ static uptr calloc_memory_for_dlsym[kCallocPoolSize];
+ static size_t allocated;
+ size_t size_in_words = ((nmemb * size) + kWordSize - 1) / kWordSize;
+ void *mem = (void*)&calloc_memory_for_dlsym[allocated];
+ allocated += size_in_words;
+ CHECK(allocated < kCallocPoolSize);
+ return mem;
+ }
+ COMMON_MALLOC_CALLOC(nmemb, size);
+ return p;
+}
+
+extern "C"
+SANITIZER_INTERFACE_ATTRIBUTE
+void *__sanitizer_mz_valloc(malloc_zone_t *zone, size_t size) {
+ COMMON_MALLOC_ENTER();
+ COMMON_MALLOC_VALLOC(size);
+ return p;
+}
+
+// TODO(glider): the allocation callbacks need to be refactored.
+extern "C"
+SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_mz_free(malloc_zone_t *zone, void *ptr) {
+ if (!ptr) return;
+ COMMON_MALLOC_FREE(ptr);
+}
+
+#define GET_ZONE_FOR_PTR(ptr) \
+ malloc_zone_t *zone_ptr = malloc_zone_from_ptr(ptr); \
+ const char *zone_name = (zone_ptr == 0) ? 0 : zone_ptr->zone_name
+
+extern "C"
+SANITIZER_INTERFACE_ATTRIBUTE
+void *__sanitizer_mz_realloc(malloc_zone_t *zone, void *ptr, size_t new_size) {
+ if (!ptr) {
+ COMMON_MALLOC_MALLOC(new_size);
+ return p;
+ } else {
+ COMMON_MALLOC_SIZE(ptr);
+ if (size) {
+ COMMON_MALLOC_REALLOC(ptr, new_size);
+ return p;
+ } else {
+ // We can't recover from reallocating an unknown address, because
+ // this would require reading at most |new_size| bytes from
+ // potentially unaccessible memory.
+ GET_ZONE_FOR_PTR(ptr);
+ COMMON_MALLOC_REPORT_UNKNOWN_REALLOC(ptr, zone_ptr, zone_name);
+ return nullptr;
+ }
+ }
+}
+
+extern "C"
+SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_mz_destroy(malloc_zone_t* zone) {
+ // A no-op -- we will not be destroyed!
+ Report("__sanitizer_mz_destroy() called -- ignoring\n");
+}
+
+extern "C"
+SANITIZER_INTERFACE_ATTRIBUTE
+void *__sanitizer_mz_memalign(malloc_zone_t *zone, size_t align, size_t size) {
+ COMMON_MALLOC_ENTER();
+ COMMON_MALLOC_MEMALIGN(align, size);
+ return p;
+}
+
+// This function is currently unused, and we build with -Werror.
+#if 0
+void __sanitizer_mz_free_definite_size(
+ malloc_zone_t* zone, void *ptr, size_t size) {
+ // TODO(glider): check that |size| is valid.
+ UNIMPLEMENTED();
+}
+#endif
+
+kern_return_t mi_enumerator(task_t task, void *,
+ unsigned type_mask, vm_address_t zone_address,
+ memory_reader_t reader,
+ vm_range_recorder_t recorder) {
+ // Should enumerate all the pointers we have. Seems like a lot of work.
+ return KERN_FAILURE;
+}
+
+size_t mi_good_size(malloc_zone_t *zone, size_t size) {
+ // I think it's always safe to return size, but we maybe could do better.
+ return size;
+}
+
+boolean_t mi_check(malloc_zone_t *zone) {
+ UNIMPLEMENTED();
+}
+
+void mi_print(malloc_zone_t *zone, boolean_t verbose) {
+ UNIMPLEMENTED();
+}
+
+void mi_log(malloc_zone_t *zone, void *address) {
+ // I don't think we support anything like this
+}
+
+void mi_force_lock(malloc_zone_t *zone) {
+ COMMON_MALLOC_FORCE_LOCK();
+}
+
+void mi_force_unlock(malloc_zone_t *zone) {
+ COMMON_MALLOC_FORCE_UNLOCK();
+}
+
+void mi_statistics(malloc_zone_t *zone, malloc_statistics_t *stats) {
+ COMMON_MALLOC_FILL_STATS(zone, stats);
+}
+
+boolean_t mi_zone_locked(malloc_zone_t *zone) {
+ // UNIMPLEMENTED();
+ return false;
+}
+
+} // unnamed namespace
+
+namespace COMMON_MALLOC_NAMESPACE {
+
+void ReplaceSystemMalloc() {
+ static malloc_introspection_t sanitizer_zone_introspection;
+ // Ok to use internal_memset, these places are not performance-critical.
+ internal_memset(&sanitizer_zone_introspection, 0,
+ sizeof(sanitizer_zone_introspection));
+
+ sanitizer_zone_introspection.enumerator = &mi_enumerator;
+ sanitizer_zone_introspection.good_size = &mi_good_size;
+ sanitizer_zone_introspection.check = &mi_check;
+ sanitizer_zone_introspection.print = &mi_print;
+ sanitizer_zone_introspection.log = &mi_log;
+ sanitizer_zone_introspection.force_lock = &mi_force_lock;
+ sanitizer_zone_introspection.force_unlock = &mi_force_unlock;
+ sanitizer_zone_introspection.statistics = &mi_statistics;
+ sanitizer_zone_introspection.zone_locked = &mi_zone_locked;
+
+ internal_memset(&sanitizer_zone, 0, sizeof(malloc_zone_t));
+
+ // Use version 6 for OSX >= 10.6.
+ sanitizer_zone.version = 6;
+ sanitizer_zone.zone_name = COMMON_MALLOC_ZONE_NAME;
+ sanitizer_zone.size = &__sanitizer_mz_size;
+ sanitizer_zone.malloc = &__sanitizer_mz_malloc;
+ sanitizer_zone.calloc = &__sanitizer_mz_calloc;
+ sanitizer_zone.valloc = &__sanitizer_mz_valloc;
+ sanitizer_zone.free = &__sanitizer_mz_free;
+ sanitizer_zone.realloc = &__sanitizer_mz_realloc;
+ sanitizer_zone.destroy = &__sanitizer_mz_destroy;
+ sanitizer_zone.batch_malloc = 0;
+ sanitizer_zone.batch_free = 0;
+ sanitizer_zone.free_definite_size = 0;
+ sanitizer_zone.memalign = &__sanitizer_mz_memalign;
+ sanitizer_zone.introspect = &sanitizer_zone_introspection;
+
+ // Register the zone.
+ malloc_zone_register(&sanitizer_zone);
+}
+
+} // namespace COMMON_MALLOC_NAMESPACE
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_persistent_allocator.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_persistent_allocator.h
index 326406b12bfb..8e5ce06d4c3d 100644
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_persistent_allocator.h
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_persistent_allocator.h
@@ -10,6 +10,7 @@
// A fast memory allocator that does not support free() nor realloc().
// All allocations are forever.
//===----------------------------------------------------------------------===//
+
#ifndef SANITIZER_PERSISTENT_ALLOCATOR_H
#define SANITIZER_PERSISTENT_ALLOCATOR_H
@@ -36,7 +37,7 @@ inline void *PersistentAllocator::tryAlloc(uptr size) {
for (;;) {
uptr cmp = atomic_load(&region_pos, memory_order_acquire);
uptr end = atomic_load(&region_end, memory_order_acquire);
- if (cmp == 0 || cmp + size > end) return 0;
+ if (cmp == 0 || cmp + size > end) return nullptr;
if (atomic_compare_exchange_weak(&region_pos, &cmp, cmp + size,
memory_order_acquire))
return (void *)cmp;
@@ -68,4 +69,4 @@ inline void *PersistentAlloc(uptr sz) {
} // namespace __sanitizer
-#endif // SANITIZER_PERSISTENT_ALLOCATOR_H
+#endif // SANITIZER_PERSISTENT_ALLOCATOR_H
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_platform.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_platform.h
index b47281b589e9..841cceb510a8 100644
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_platform.h
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_platform.h
@@ -87,7 +87,7 @@
// For such platforms build this code with -DSANITIZER_CAN_USE_ALLOCATOR64=0 or
// change the definition of SANITIZER_CAN_USE_ALLOCATOR64 here.
#ifndef SANITIZER_CAN_USE_ALLOCATOR64
-# if defined(__aarch64__) || defined(__mips64)
+# if defined(__mips64) || defined(__aarch64__)
# define SANITIZER_CAN_USE_ALLOCATOR64 0
# else
# define SANITIZER_CAN_USE_ALLOCATOR64 (SANITIZER_WORDSIZE == 64)
@@ -95,12 +95,9 @@
#endif
// The range of addresses which can be returned my mmap.
-// FIXME: this value should be different on different platforms,
-// e.g. on AArch64 it is most likely (1ULL << 39). Larger values will still work
-// but will consume more memory for TwoLevelByteMap.
-#if defined(__aarch64__)
-# define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 39)
-#elif defined(__mips__)
+// FIXME: this value should be different on different platforms. Larger values
+// will still work but will consume more memory for TwoLevelByteMap.
+#if defined(__mips__)
# define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 40)
#else
# define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 47)
@@ -130,7 +127,7 @@
#define SANITIZER_USES_UID16_SYSCALLS 0
#endif
-#ifdef __mips__
+#if defined(__mips__)
# define SANITIZER_POINTER_FORMAT_LENGTH FIRST_32_SECOND_64(8, 10)
#else
# define SANITIZER_POINTER_FORMAT_LENGTH FIRST_32_SECOND_64(8, 12)
@@ -142,4 +139,15 @@
# define HAVE_TIRPC_RPC_XDR_H 0
#endif
+/// \macro MSC_PREREQ
+/// \brief Is the compiler MSVC of at least the specified version?
+/// The common \param version values to check for are:
+/// * 1800: Microsoft Visual Studio 2013 / 12.0
+/// * 1900: Microsoft Visual Studio 2015 / 14.0
+#ifdef _MSC_VER
+# define MSC_PREREQ(version) (_MSC_VER >= (version))
+#else
+# define MSC_PREREQ(version) 0
+#endif
+
#endif // SANITIZER_PLATFORM_H
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h
index 77cc84cd03af..430ad4839809 100644
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h
@@ -60,6 +60,7 @@
#define SANITIZER_INTERCEPT_STRPBRK 1
#define SANITIZER_INTERCEPT_TEXTDOMAIN SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_STRCASECMP SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_MEMCMP 1
#define SANITIZER_INTERCEPT_MEMCHR 1
#define SANITIZER_INTERCEPT_MEMRCHR SI_FREEBSD || SI_LINUX
@@ -132,7 +133,7 @@
#define SANITIZER_INTERCEPT_READDIR64 SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_PTRACE SI_LINUX_NOT_ANDROID && \
(defined(__i386) || defined(__x86_64) || defined(__mips64) || \
- defined(__powerpc64__))
+ defined(__powerpc64__) || defined(__aarch64__) || defined(__arm__))
#define SANITIZER_INTERCEPT_SETLOCALE SI_NOT_WINDOWS
#define SANITIZER_INTERCEPT_GETCWD SI_NOT_WINDOWS
#define SANITIZER_INTERCEPT_GET_CURRENT_DIR_NAME SI_LINUX_NOT_ANDROID
@@ -142,6 +143,8 @@
#define SANITIZER_INTERCEPT_WCSTOMBS SI_NOT_WINDOWS
#define SANITIZER_INTERCEPT_WCSNRTOMBS \
SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_WCRTOMB \
+ SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_TCGETATTR SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_REALPATH SI_NOT_WINDOWS
#define SANITIZER_INTERCEPT_CANONICALIZE_FILE_NAME SI_LINUX_NOT_ANDROID
@@ -217,7 +220,7 @@
// FIXME: getline seems to be available on OSX 10.7
#define SANITIZER_INTERCEPT_GETLINE SI_FREEBSD || SI_LINUX_NOT_ANDROID
-#define SANITIZER_INTERCEPT__EXIT SI_LINUX || SI_FREEBSD
+#define SANITIZER_INTERCEPT__EXIT SI_LINUX || SI_FREEBSD || SI_MAC
#define SANITIZER_INTERCEPT_PHTREAD_MUTEX SI_NOT_WINDOWS
#define SANITIZER_INTERCEPT_PTHREAD_SETNAME_NP \
@@ -253,5 +256,13 @@
#define SANITIZER_INTERCEPT_MLOCKX SI_NOT_WINDOWS
#define SANITIZER_INTERCEPT_FOPENCOOKIE SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_SEM SI_LINUX || SI_FREEBSD
+#define SANITIZER_INTERCEPT_PTHREAD_SETCANCEL SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_MINCORE SI_LINUX
+#define SANITIZER_INTERCEPT_PROCESS_VM_READV SI_LINUX
+#define SANITIZER_INTERCEPT_CTERMID SI_LINUX || SI_MAC || SI_FREEBSD
+#define SANITIZER_INTERCEPT_CTERMID_R SI_MAC || SI_FREEBSD
+
+#define SANITIZER_INTERCEPTOR_HOOKS SI_LINUX
#endif // #ifndef SANITIZER_PLATFORM_INTERCEPTORS_H
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cc
index aaa37ed02ebd..b642cba0fede 100644
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cc
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cc
@@ -12,8 +12,8 @@
// Sizes and layouts of platform-specific POSIX data structures.
//===----------------------------------------------------------------------===//
-
#include "sanitizer_platform.h"
+
#if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_MAC
// Tests in this file assume that off_t-dependent data structures match the
// libc ABI. For example, struct dirent here is what readdir() function (as
@@ -119,9 +119,17 @@
#if SANITIZER_LINUX || SANITIZER_FREEBSD
# include <utime.h>
# include <sys/ptrace.h>
-# if defined(__mips64)
+# if defined(__mips64) || defined(__aarch64__) || defined(__arm__)
# include <asm/ptrace.h>
+# ifdef __arm__
+typedef struct user_fpregs elf_fpregset_t;
+# define ARM_VFPREGS_SIZE_ASAN (32 * 8 /*fpregs*/ + 4 /*fpscr*/)
+# if !defined(ARM_VFPREGS_SIZE)
+# define ARM_VFPREGS_SIZE ARM_VFPREGS_SIZE_ASAN
+# endif
+# endif
# endif
+# include <semaphore.h>
#endif
#if !SANITIZER_ANDROID
@@ -195,7 +203,7 @@ namespace __sanitizer {
unsigned struct_stat_sz = sizeof(struct stat);
#if !SANITIZER_IOS && !SANITIZER_FREEBSD
unsigned struct_stat64_sz = sizeof(struct stat64);
-#endif // !SANITIZER_IOS && !SANITIZER_FREEBSD
+#endif // !SANITIZER_IOS && !SANITIZER_FREEBSD
unsigned struct_rusage_sz = sizeof(struct rusage);
unsigned struct_tm_sz = sizeof(struct tm);
unsigned struct_passwd_sz = sizeof(struct passwd);
@@ -236,27 +244,27 @@ namespace __sanitizer {
unsigned struct_new_utsname_sz = sizeof(struct new_utsname);
unsigned struct_old_utsname_sz = sizeof(struct old_utsname);
unsigned struct_oldold_utsname_sz = sizeof(struct oldold_utsname);
-#endif // SANITIZER_LINUX
+#endif // SANITIZER_LINUX
#if SANITIZER_LINUX || SANITIZER_FREEBSD
unsigned struct_rlimit_sz = sizeof(struct rlimit);
unsigned struct_timespec_sz = sizeof(struct timespec);
unsigned struct_utimbuf_sz = sizeof(struct utimbuf);
unsigned struct_itimerspec_sz = sizeof(struct itimerspec);
-#endif // SANITIZER_LINUX || SANITIZER_FREEBSD
+#endif // SANITIZER_LINUX || SANITIZER_FREEBSD
#if SANITIZER_LINUX && !SANITIZER_ANDROID
unsigned struct_ustat_sz = sizeof(struct ustat);
unsigned struct_rlimit64_sz = sizeof(struct rlimit64);
unsigned struct_statvfs64_sz = sizeof(struct statvfs64);
-#endif // SANITIZER_LINUX && !SANITIZER_ANDROID
+#endif // SANITIZER_LINUX && !SANITIZER_ANDROID
#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
unsigned struct_timex_sz = sizeof(struct timex);
unsigned struct_msqid_ds_sz = sizeof(struct msqid_ds);
unsigned struct_mq_attr_sz = sizeof(struct mq_attr);
unsigned struct_statvfs_sz = sizeof(struct statvfs);
-#endif // (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
+#endif // (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
uptr sig_ign = (uptr)SIG_IGN;
uptr sig_dfl = (uptr)SIG_DFL;
@@ -290,6 +298,12 @@ namespace __sanitizer {
return 0;
}
+#if SANITIZER_LINUX
+unsigned struct_ElfW_Phdr_sz = sizeof(ElfW(Phdr));
+#elif SANITIZER_FREEBSD
+unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
+#endif
+
#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
int glob_nomatch = GLOB_NOMATCH;
int glob_altdirfunc = GLOB_ALTDIRFUNC;
@@ -297,34 +311,63 @@ namespace __sanitizer {
#if SANITIZER_LINUX && !SANITIZER_ANDROID && \
(defined(__i386) || defined(__x86_64) || defined(__mips64) || \
- defined(__powerpc64__))
-#if defined(__mips64) || defined(__powerpc64__)
+ defined(__powerpc64__) || defined(__aarch64__) || defined(__arm__))
+#if defined(__mips64) || defined(__powerpc64__) || defined(__arm__)
unsigned struct_user_regs_struct_sz = sizeof(struct pt_regs);
unsigned struct_user_fpregs_struct_sz = sizeof(elf_fpregset_t);
+#elif defined(__aarch64__)
+ unsigned struct_user_regs_struct_sz = sizeof(struct user_pt_regs);
+ unsigned struct_user_fpregs_struct_sz = sizeof(struct user_fpsimd_state);
#else
unsigned struct_user_regs_struct_sz = sizeof(struct user_regs_struct);
unsigned struct_user_fpregs_struct_sz = sizeof(struct user_fpregs_struct);
-#endif // __mips64 || __powerpc64__
-#if defined(__x86_64) || defined(__mips64) || defined(__powerpc64__)
+#endif // __mips64 || __powerpc64__ || __aarch64__
+#if defined(__x86_64) || defined(__mips64) || defined(__powerpc64__) || \
+ defined(__aarch64__) || defined(__arm__)
unsigned struct_user_fpxregs_struct_sz = 0;
#else
unsigned struct_user_fpxregs_struct_sz = sizeof(struct user_fpxregs_struct);
-#endif // __x86_64 || __mips64 || __powerpc64__
+#endif // __x86_64 || __mips64 || __powerpc64__ || __aarch64__ || __arm__
+#ifdef __arm__
+ unsigned struct_user_vfpregs_struct_sz = ARM_VFPREGS_SIZE;
+#else
+ unsigned struct_user_vfpregs_struct_sz = 0;
+#endif
int ptrace_peektext = PTRACE_PEEKTEXT;
int ptrace_peekdata = PTRACE_PEEKDATA;
int ptrace_peekuser = PTRACE_PEEKUSER;
+#if (defined(PTRACE_GETREGS) && defined(PTRACE_SETREGS)) || \
+ (defined(PT_GETREGS) && defined(PT_SETREGS))
int ptrace_getregs = PTRACE_GETREGS;
int ptrace_setregs = PTRACE_SETREGS;
+#else
+ int ptrace_getregs = -1;
+ int ptrace_setregs = -1;
+#endif
+#if (defined(PTRACE_GETFPREGS) && defined(PTRACE_SETFPREGS)) || \
+ (defined(PT_GETFPREGS) && defined(PT_SETFPREGS))
int ptrace_getfpregs = PTRACE_GETFPREGS;
int ptrace_setfpregs = PTRACE_SETFPREGS;
-#if defined(PTRACE_GETFPXREGS) && defined(PTRACE_SETFPXREGS)
+#else
+ int ptrace_getfpregs = -1;
+ int ptrace_setfpregs = -1;
+#endif
+#if (defined(PTRACE_GETFPXREGS) && defined(PTRACE_SETFPXREGS)) || \
+ (defined(PT_GETFPXREGS) && defined(PT_SETFPXREGS))
int ptrace_getfpxregs = PTRACE_GETFPXREGS;
int ptrace_setfpxregs = PTRACE_SETFPXREGS;
#else
int ptrace_getfpxregs = -1;
int ptrace_setfpxregs = -1;
-#endif // PTRACE_GETFPXREGS/PTRACE_SETFPXREGS
+#endif // PTRACE_GETFPXREGS/PTRACE_SETFPXREGS
+#if defined(PTRACE_GETVFPREGS) && defined(PTRACE_SETVFPREGS)
+ int ptrace_getvfpregs = PTRACE_GETVFPREGS;
+ int ptrace_setvfpregs = PTRACE_SETVFPREGS;
+#else
+ int ptrace_getvfpregs = -1;
+ int ptrace_setvfpregs = -1;
+#endif
int ptrace_geteventmsg = PTRACE_GETEVENTMSG;
#if (defined(PTRACE_GETSIGINFO) && defined(PTRACE_SETSIGINFO)) || \
(defined(PT_GETSIGINFO) && defined(PT_SETSIGINFO))
@@ -333,14 +376,14 @@ namespace __sanitizer {
#else
int ptrace_getsiginfo = -1;
int ptrace_setsiginfo = -1;
-#endif // PTRACE_GETSIGINFO/PTRACE_SETSIGINFO
+#endif // PTRACE_GETSIGINFO/PTRACE_SETSIGINFO
#if defined(PTRACE_GETREGSET) && defined(PTRACE_SETREGSET)
int ptrace_getregset = PTRACE_GETREGSET;
int ptrace_setregset = PTRACE_SETREGSET;
#else
int ptrace_getregset = -1;
int ptrace_setregset = -1;
-#endif // PTRACE_GETREGSET/PTRACE_SETREGSET
+#endif // PTRACE_GETREGSET/PTRACE_SETREGSET
#endif
unsigned path_max = PATH_MAX;
@@ -378,7 +421,7 @@ namespace __sanitizer {
unsigned struct_vt_consize_sz = sizeof(struct vt_consize);
unsigned struct_vt_sizes_sz = sizeof(struct vt_sizes);
unsigned struct_vt_stat_sz = sizeof(struct vt_stat);
-#endif // SANITIZER_LINUX
+#endif // SANITIZER_LINUX
#if SANITIZER_LINUX || SANITIZER_FREEBSD
#if SOUND_VERSION >= 0x040000
@@ -398,7 +441,7 @@ namespace __sanitizer {
unsigned struct_seq_event_rec_sz = sizeof(struct seq_event_rec);
unsigned struct_synth_info_sz = sizeof(struct synth_info);
unsigned struct_vt_mode_sz = sizeof(struct vt_mode);
-#endif // SANITIZER_LINUX || SANITIZER_FREEBSD
+#endif // SANITIZER_LINUX || SANITIZER_FREEBSD
#if SANITIZER_LINUX && !SANITIZER_ANDROID
unsigned struct_ax25_parms_struct_sz = sizeof(struct ax25_parms_struct);
@@ -423,12 +466,12 @@ namespace __sanitizer {
unsigned struct_sockaddr_ax25_sz = sizeof(struct sockaddr_ax25);
unsigned struct_unimapdesc_sz = sizeof(struct unimapdesc);
unsigned struct_unimapinit_sz = sizeof(struct unimapinit);
-#endif // SANITIZER_LINUX && !SANITIZER_ANDROID
+#endif // SANITIZER_LINUX && !SANITIZER_ANDROID
#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
unsigned struct_audio_buf_info_sz = sizeof(struct audio_buf_info);
unsigned struct_ppp_stats_sz = sizeof(struct ppp_stats);
-#endif // (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
+#endif // (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
#if !SANITIZER_ANDROID && !SANITIZER_MAC
unsigned struct_sioc_sg_req_sz = sizeof(struct sioc_sg_req);
@@ -643,7 +686,7 @@ namespace __sanitizer {
unsigned IOCTL_SOUND_PCM_READ_RATE = SOUND_PCM_READ_RATE;
unsigned IOCTL_SOUND_PCM_WRITE_CHANNELS = SOUND_PCM_WRITE_CHANNELS;
unsigned IOCTL_SOUND_PCM_WRITE_FILTER = SOUND_PCM_WRITE_FILTER;
-#endif // SOUND_VERSION
+#endif // SOUND_VERSION
unsigned IOCTL_TCFLSH = TCFLSH;
unsigned IOCTL_TCGETA = TCGETA;
unsigned IOCTL_TCGETS = TCGETS;
@@ -766,7 +809,7 @@ namespace __sanitizer {
unsigned IOCTL_VT_RELDISP = VT_RELDISP;
unsigned IOCTL_VT_SETMODE = VT_SETMODE;
unsigned IOCTL_VT_WAITACTIVE = VT_WAITACTIVE;
-#endif // SANITIZER_LINUX || SANITIZER_FREEBSD
+#endif // SANITIZER_LINUX || SANITIZER_FREEBSD
#if SANITIZER_LINUX && !SANITIZER_ANDROID
unsigned IOCTL_CYGETDEFTHRESH = CYGETDEFTHRESH;
@@ -857,7 +900,7 @@ namespace __sanitizer {
unsigned IOCTL_TIOCSERGETMULTI = TIOCSERGETMULTI;
unsigned IOCTL_TIOCSERSETMULTI = TIOCSERSETMULTI;
unsigned IOCTL_TIOCSSERIAL = TIOCSSERIAL;
-#endif // SANITIZER_LINUX && !SANITIZER_ANDROID
+#endif // SANITIZER_LINUX && !SANITIZER_ANDROID
#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
unsigned IOCTL_GIO_SCRNMAP = GIO_SCRNMAP;
@@ -875,7 +918,7 @@ namespace __sanitizer {
unsigned IOCTL_PIO_SCRNMAP = PIO_SCRNMAP;
unsigned IOCTL_SNDCTL_DSP_GETISPACE = SNDCTL_DSP_GETISPACE;
unsigned IOCTL_SNDCTL_DSP_GETOSPACE = SNDCTL_DSP_GETOSPACE;
-#endif // (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
+#endif // (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
const int errno_EINVAL = EINVAL;
// EOWNERDEAD is not present in some older platforms.
@@ -887,7 +930,7 @@ namespace __sanitizer {
const int si_SEGV_MAPERR = SEGV_MAPERR;
const int si_SEGV_ACCERR = SEGV_ACCERR;
-} // namespace __sanitizer
+} // namespace __sanitizer
COMPILER_CHECK(sizeof(__sanitizer_pthread_attr_t) >= sizeof(pthread_attr_t));
@@ -917,7 +960,7 @@ COMPILER_CHECK(IOC_SIZE(0x12345678) == _IOC_SIZE(0x12345678));
COMPILER_CHECK(IOC_DIR(0x12345678) == _IOC_DIR(0x12345678));
COMPILER_CHECK(IOC_NR(0x12345678) == _IOC_NR(0x12345678));
COMPILER_CHECK(IOC_TYPE(0x12345678) == _IOC_TYPE(0x12345678));
-#endif // SANITIZER_LINUX
+#endif // SANITIZER_LINUX
#if SANITIZER_LINUX || SANITIZER_FREEBSD
// There are more undocumented fields in dl_phdr_info that we are not interested
@@ -927,7 +970,7 @@ CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_addr);
CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_name);
CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phdr);
CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phnum);
-#endif // SANITIZER_LINUX || SANITIZER_FREEBSD
+#endif // SANITIZER_LINUX || SANITIZER_FREEBSD
#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
CHECK_TYPE_SIZE(glob_t);
@@ -1124,14 +1167,14 @@ CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_netmask);
# if SANITIZER_FREEBSD
CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_dstaddr);
# else
-COMPILER_CHECK(sizeof(((__sanitizer_ifaddrs *)NULL)->ifa_dstaddr) ==
- sizeof(((ifaddrs *)NULL)->ifa_ifu));
+COMPILER_CHECK(sizeof(((__sanitizer_ifaddrs *)nullptr)->ifa_dstaddr) ==
+ sizeof(((ifaddrs *)nullptr)->ifa_ifu));
COMPILER_CHECK(offsetof(__sanitizer_ifaddrs, ifa_dstaddr) ==
offsetof(ifaddrs, ifa_ifu));
-# endif // SANITIZER_FREEBSD
+# endif // SANITIZER_FREEBSD
#else
CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_dstaddr);
-#endif // SANITIZER_LINUX
+#endif // SANITIZER_LINUX
CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_data);
#endif
@@ -1221,4 +1264,12 @@ CHECK_SIZE_AND_OFFSET(cookie_io_functions_t, seek);
CHECK_SIZE_AND_OFFSET(cookie_io_functions_t, close);
#endif
-#endif // SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_MAC
+#if SANITIZER_LINUX || SANITIZER_FREEBSD
+CHECK_TYPE_SIZE(sem_t);
+#endif
+
+#if SANITIZER_LINUX && defined(__arm__)
+COMPILER_CHECK(ARM_VFPREGS_SIZE == ARM_VFPREGS_SIZE_ASAN);
+#endif
+
+#endif // SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_MAC
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h
index ea95fb6624da..d7ef8495d16a 100644
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h
@@ -154,6 +154,18 @@ namespace __sanitizer {
};
const unsigned old_sigset_t_sz = sizeof(unsigned long);
+
+ struct __sanitizer_sem_t {
+#if SANITIZER_ANDROID && defined(_LP64)
+ int data[4];
+#elif SANITIZER_ANDROID && !defined(_LP64)
+ int data;
+#elif SANITIZER_LINUX
+ uptr data[4];
+#elif SANITIZER_FREEBSD
+ u32 data[4];
+#endif
+ };
#endif // SANITIZER_LINUX || SANITIZER_FREEBSD
#if SANITIZER_ANDROID
@@ -613,6 +625,8 @@ namespace __sanitizer {
const void *dlpi_phdr;
short dlpi_phnum;
};
+
+ extern unsigned struct_ElfW_Phdr_sz;
#endif
struct __sanitizer_addrinfo {
@@ -726,10 +740,11 @@ namespace __sanitizer {
#if SANITIZER_LINUX && !SANITIZER_ANDROID && \
(defined(__i386) || defined(__x86_64) || defined(__mips64) || \
- defined(__powerpc64__))
+ defined(__powerpc64__) || defined(__aarch64__) || defined(__arm__))
extern unsigned struct_user_regs_struct_sz;
extern unsigned struct_user_fpregs_struct_sz;
extern unsigned struct_user_fpxregs_struct_sz;
+ extern unsigned struct_user_vfpregs_struct_sz;
extern int ptrace_peektext;
extern int ptrace_peekdata;
@@ -740,6 +755,8 @@ namespace __sanitizer {
extern int ptrace_setfpregs;
extern int ptrace_getfpxregs;
extern int ptrace_setfpxregs;
+ extern int ptrace_getvfpregs;
+ extern int ptrace_setvfpregs;
extern int ptrace_getsiginfo;
extern int ptrace_setsiginfo;
extern int ptrace_getregset;
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_posix.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_posix.cc
index abf6738a8daa..5ae68663df0e 100644
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_posix.cc
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_posix.cc
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "sanitizer_platform.h"
+
#if SANITIZER_POSIX
#include "sanitizer_common.h"
@@ -57,8 +58,8 @@ static uptr GetKernelAreaSize() {
// mapped to top gigabyte (e.g. stack).
MemoryMappingLayout proc_maps(/*cache_enabled*/true);
uptr end, prot;
- while (proc_maps.Next(/*start*/0, &end,
- /*offset*/0, /*filename*/0,
+ while (proc_maps.Next(/*start*/nullptr, &end,
+ /*offset*/nullptr, /*filename*/nullptr,
/*filename_size*/0, &prot)) {
if ((end >= 3 * gbyte)
&& (prot & MemoryMappingLayout::kProtectionWrite) != 0)
@@ -111,27 +112,14 @@ uptr GetMaxVirtualAddress() {
#endif // SANITIZER_WORDSIZE
}
-void *MmapOrDie(uptr size, const char *mem_type) {
+void *MmapOrDie(uptr size, const char *mem_type, bool raw_report) {
size = RoundUpTo(size, GetPageSizeCached());
- uptr res = internal_mmap(0, size,
- PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANON, -1, 0);
+ uptr res = internal_mmap(nullptr, size,
+ PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANON, -1, 0);
int reserrno;
- if (internal_iserror(res, &reserrno)) {
- static int recursion_count;
- if (recursion_count) {
- // The Report() and CHECK calls below may call mmap recursively and fail.
- // If we went into recursion, just die.
- RawWrite("ERROR: Failed to mmap\n");
- Die();
- }
- recursion_count++;
- Report("ERROR: %s failed to "
- "allocate 0x%zx (%zd) bytes of %s (errno: %d)\n",
- SanitizerToolName, size, size, mem_type, reserrno);
- DumpProcessMap();
- CHECK("unable to mmap" && 0);
- }
+ if (internal_iserror(res, &reserrno))
+ ReportMmapFailureAndDie(size, mem_type, "allocate", reserrno, raw_report);
IncreaseTotalMmap(size);
return (void *)res;
}
@@ -149,18 +137,14 @@ void UnmapOrDie(void *addr, uptr size) {
void *MmapNoReserveOrDie(uptr size, const char *mem_type) {
uptr PageSize = GetPageSizeCached();
- uptr p = internal_mmap(0,
- RoundUpTo(size, PageSize),
- PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
- -1, 0);
+ uptr p = internal_mmap(nullptr,
+ RoundUpTo(size, PageSize),
+ PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
+ -1, 0);
int reserrno;
- if (internal_iserror(p, &reserrno)) {
- Report("ERROR: %s failed to "
- "allocate noreserve 0x%zx (%zd) bytes for '%s' (errno: %d)\n",
- SanitizerToolName, size, size, mem_type, reserrno);
- CHECK("unable to mmap" && 0);
- }
+ if (internal_iserror(p, &reserrno))
+ ReportMmapFailureAndDie(size, mem_type, "allocate noreserve", reserrno);
IncreaseTotalMmap(size);
return (void *)p;
}
@@ -174,10 +158,10 @@ void *MmapFixedOrDie(uptr fixed_addr, uptr size) {
-1, 0);
int reserrno;
if (internal_iserror(p, &reserrno)) {
- Report("ERROR: %s failed to "
- "allocate 0x%zx (%zd) bytes at address %zx (errno: %d)\n",
- SanitizerToolName, size, size, fixed_addr, reserrno);
- CHECK("unable to mmap" && 0);
+ char mem_type[30];
+ internal_snprintf(mem_type, sizeof(mem_type), "memory at address 0x%zx",
+ fixed_addr);
+ ReportMmapFailureAndDie(size, mem_type, "allocate", reserrno);
}
IncreaseTotalMmap(size);
return (void *)p;
@@ -236,8 +220,8 @@ void *MapFileToMemory(const char *file_name, uptr *buff_size) {
CHECK_NE(fsize, (uptr)-1);
CHECK_GT(fsize, 0);
*buff_size = RoundUpTo(fsize, GetPageSizeCached());
- uptr map = internal_mmap(0, *buff_size, PROT_READ, MAP_PRIVATE, fd, 0);
- return internal_iserror(map) ? 0 : (void *)map;
+ uptr map = internal_mmap(nullptr, *buff_size, PROT_READ, MAP_PRIVATE, fd, 0);
+ return internal_iserror(map) ? nullptr : (void *)map;
}
void *MapWritableFileToMemory(void *addr, uptr size, fd_t fd, OFF_T offset) {
@@ -248,7 +232,7 @@ void *MapWritableFileToMemory(void *addr, uptr size, fd_t fd, OFF_T offset) {
if (internal_iserror(p, &mmap_errno)) {
Printf("could not map writable file (%d, %lld, %zu): %zd, errno: %d\n",
fd, (long long)offset, size, p, mmap_errno);
- return 0;
+ return nullptr;
}
return (void *)p;
}
@@ -268,8 +252,8 @@ bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) {
MemoryMappingLayout proc_maps(/*cache_enabled*/true);
uptr start, end;
while (proc_maps.Next(&start, &end,
- /*offset*/0, /*filename*/0, /*filename_size*/0,
- /*protection*/0)) {
+ /*offset*/nullptr, /*filename*/nullptr,
+ /*filename_size*/0, /*protection*/nullptr)) {
if (start == end) continue; // Empty range.
CHECK_NE(0, end);
if (!IntervalsAreSeparate(start, end - 1, range_start, range_end))
@@ -284,8 +268,8 @@ void DumpProcessMap() {
const sptr kBufSize = 4095;
char *filename = (char*)MmapOrDie(kBufSize, __func__);
Report("Process memory map follows:\n");
- while (proc_maps.Next(&start, &end, /* file_offset */0,
- filename, kBufSize, /* protection */0)) {
+ while (proc_maps.Next(&start, &end, /* file_offset */nullptr,
+ filename, kBufSize, /* protection */nullptr)) {
Printf("\t%p-%p\t%s\n", (void*)start, (void*)end, filename);
}
Report("End of process memory map.\n");
@@ -296,30 +280,6 @@ const char *GetPwd() {
return GetEnv("PWD");
}
-char *FindPathToBinary(const char *name) {
- const char *path = GetEnv("PATH");
- if (!path)
- return 0;
- uptr name_len = internal_strlen(name);
- InternalScopedBuffer<char> buffer(kMaxPathLength);
- const char *beg = path;
- while (true) {
- const char *end = internal_strchrnul(beg, ':');
- uptr prefix_len = end - beg;
- if (prefix_len + name_len + 2 <= kMaxPathLength) {
- internal_memcpy(buffer.data(), beg, prefix_len);
- buffer[prefix_len] = '/';
- internal_memcpy(&buffer[prefix_len + 1], name, name_len);
- buffer[prefix_len + 1 + name_len] = '\0';
- if (FileExists(buffer.data()))
- return internal_strdup(buffer.data());
- }
- if (*end == '\0') break;
- beg = end + 1;
- }
- return 0;
-}
-
bool IsPathSeparator(const char c) {
return c == '/';
}
@@ -361,6 +321,6 @@ SignalContext SignalContext::Create(void *siginfo, void *context) {
return SignalContext(context, addr, pc, sp, bp);
}
-} // namespace __sanitizer
+} // namespace __sanitizer
-#endif // SANITIZER_POSIX
+#endif // SANITIZER_POSIX
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_posix.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_posix.h
index 5a9e97d5b5a9..c0426a0b23fa 100644
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_posix.h
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_posix.h
@@ -54,6 +54,7 @@ uptr internal_ptrace(int request, int pid, void *addr, void *data);
uptr internal_waitpid(int pid, int *status, int options);
int internal_fork();
+int internal_forkpty(int *amaster);
// These functions call appropriate pthread_ functions directly, bypassing
// the interceptor. They are weak and may not be present in some tools.
@@ -74,6 +75,8 @@ int real_pthread_join(void *th, void **ret);
} \
} // namespace __sanitizer
+int my_pthread_attr_getstack(void *attr, void **addr, uptr *size);
+
int internal_sigaction(int signum, const void *act, void *oldact);
} // namespace __sanitizer
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cc
index 3f0a4f453cb4..c158eedae0e3 100644
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cc
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cc
@@ -15,6 +15,7 @@
#include "sanitizer_platform.h"
#if SANITIZER_POSIX
+
#include "sanitizer_common.h"
#include "sanitizer_flags.h"
#include "sanitizer_platform_limits_posix.h"
@@ -30,9 +31,9 @@
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/resource.h>
+#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
-#include <sys/stat.h>
#include <unistd.h>
#if SANITIZER_FREEBSD
@@ -141,7 +142,7 @@ static const uptr kAltStackSize = SIGSTKSZ * 4; // SIGSTKSZ is not enough.
void SetAlternateSignalStack() {
stack_t altstack, oldstack;
- CHECK_EQ(0, sigaltstack(0, &oldstack));
+ CHECK_EQ(0, sigaltstack(nullptr, &oldstack));
// If the alternate stack is already in place, do nothing.
// Android always sets an alternate stack, but it's too small for us.
if (!SANITIZER_ANDROID && !(oldstack.ss_flags & SS_DISABLE)) return;
@@ -152,12 +153,12 @@ void SetAlternateSignalStack() {
altstack.ss_sp = (char*) base;
altstack.ss_flags = 0;
altstack.ss_size = kAltStackSize;
- CHECK_EQ(0, sigaltstack(&altstack, 0));
+ CHECK_EQ(0, sigaltstack(&altstack, nullptr));
}
void UnsetAlternateSignalStack() {
stack_t altstack, oldstack;
- altstack.ss_sp = 0;
+ altstack.ss_sp = nullptr;
altstack.ss_flags = SS_DISABLE;
altstack.ss_size = kAltStackSize; // Some sane value required on Darwin.
CHECK_EQ(0, sigaltstack(&altstack, &oldstack));
@@ -176,7 +177,7 @@ static void MaybeInstallSigaction(int signum,
// Clients are responsible for handling this correctly.
sigact.sa_flags = SA_SIGINFO | SA_NODEFER;
if (common_flags()->use_sigaltstack) sigact.sa_flags |= SA_ONSTACK;
- CHECK_EQ(0, internal_sigaction(signum, &sigact, 0));
+ CHECK_EQ(0, internal_sigaction(signum, &sigact, nullptr));
VReport(1, "Installed the sigaction for signal %d\n", signum);
}
@@ -188,6 +189,8 @@ void InstallDeadlySignalHandlers(SignalHandlerType handler) {
MaybeInstallSigaction(SIGSEGV, handler);
MaybeInstallSigaction(SIGBUS, handler);
MaybeInstallSigaction(SIGABRT, handler);
+ MaybeInstallSigaction(SIGFPE, handler);
+ MaybeInstallSigaction(SIGILL, handler);
}
#endif // SANITIZER_GO
@@ -226,7 +229,7 @@ void PrepareForSandboxing(__sanitizer_sandbox_arguments *args) {
#endif
}
-#if SANITIZER_ANDROID
+#if SANITIZER_ANDROID || SANITIZER_GO
int GetNamedMappingFd(const char *name, uptr size) {
return -1;
}
@@ -275,6 +278,48 @@ void *MmapNoAccess(uptr fixed_addr, uptr size, const char *name) {
0);
}
-} // namespace __sanitizer
+// This function is defined elsewhere if we intercepted pthread_attr_getstack.
+extern "C" {
+SANITIZER_WEAK_ATTRIBUTE int
+real_pthread_attr_getstack(void *attr, void **addr, size_t *size);
+} // extern "C"
+
+int my_pthread_attr_getstack(void *attr, void **addr, uptr *size) {
+#if !SANITIZER_GO && !SANITIZER_MAC
+ if (&real_pthread_attr_getstack)
+ return real_pthread_attr_getstack((pthread_attr_t *)attr, addr,
+ (size_t *)size);
+#endif
+ return pthread_attr_getstack((pthread_attr_t *)attr, addr, (size_t *)size);
+}
+
+#if !SANITIZER_GO
+void AdjustStackSize(void *attr_) {
+ pthread_attr_t *attr = (pthread_attr_t *)attr_;
+ uptr stackaddr = 0;
+ uptr stacksize = 0;
+ my_pthread_attr_getstack(attr, (void**)&stackaddr, &stacksize);
+ // GLibC will return (0 - stacksize) as the stack address in the case when
+ // stacksize is set, but stackaddr is not.
+ bool stack_set = (stackaddr != 0) && (stackaddr + stacksize != 0);
+ // We place a lot of tool data into TLS, account for that.
+ const uptr minstacksize = GetTlsSize() + 128*1024;
+ if (stacksize < minstacksize) {
+ if (!stack_set) {
+ if (stacksize != 0) {
+ VPrintf(1, "Sanitizer: increasing stacksize %zu->%zu\n", stacksize,
+ minstacksize);
+ pthread_attr_setstacksize(attr, minstacksize);
+ }
+ } else {
+ Printf("Sanitizer: pre-allocated stack size is insufficient: "
+ "%zu < %zu\n", stacksize, minstacksize);
+ Printf("Sanitizer: pthread_create is likely to fail.\n");
+ }
+ }
+}
+#endif // !SANITIZER_GO
+
+} // namespace __sanitizer
-#endif // SANITIZER_POSIX
+#endif // SANITIZER_POSIX
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_printf.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_printf.cc
index e4f67f5e0db5..434ebb93dffa 100644
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_printf.cc
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_printf.cc
@@ -14,7 +14,6 @@
// inside it.
//===----------------------------------------------------------------------===//
-
#include "sanitizer_common.h"
#include "sanitizer_flags.h"
#include "sanitizer_libc.h"
@@ -98,7 +97,7 @@ static int AppendSignedDecimal(char **buff, const char *buff_end, s64 num,
static int AppendString(char **buff, const char *buff_end, int precision,
const char *s) {
- if (s == 0)
+ if (!s)
s = "<null>";
int result = 0;
for (; *s; s++) {
@@ -260,7 +259,7 @@ static void SharedPrintfCode(bool append_pid, const char *format,
}
if (append_pid) {
int pid = internal_getpid();
- const char *exe_name = GetBinaryBasename();
+ const char *exe_name = GetProcessName();
if (common_flags()->log_exe_name && exe_name) {
needed_length += internal_snprintf(buffer, buffer_size,
"==%s", exe_name);
@@ -279,8 +278,12 @@ static void SharedPrintfCode(bool append_pid, const char *format,
# undef CHECK_NEEDED_LENGTH
}
RawWrite(buffer);
- AndroidLogWrite(buffer);
+
+ // Remove color sequences from the message.
+ RemoveANSIEscapeSequencesFromString(buffer);
CallPrintfAndReportCallback(buffer);
+ LogMessageOnPrintf(buffer);
+
// If we had mapped any memory, clean up.
if (buffer != local_buffer)
UnmapOrDie((void *)buffer, buffer_size);
@@ -328,4 +331,4 @@ void InternalScopedString::append(const char *format, ...) {
CHECK_LT(length_, size());
}
-} // namespace __sanitizer
+} // namespace __sanitizer
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_common.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_common.cc
index 2c6ce8e2b211..d43432cae909 100644
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_common.cc
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_common.cc
@@ -11,7 +11,9 @@
//===----------------------------------------------------------------------===//
#include "sanitizer_platform.h"
+
#if SANITIZER_FREEBSD || SANITIZER_LINUX
+
#include "sanitizer_common.h"
#include "sanitizer_placement_new.h"
#include "sanitizer_procmaps.h"
@@ -151,10 +153,11 @@ uptr MemoryMappingLayout::DumpListOfModules(LoadedModule *modules,
}
void GetMemoryProfile(fill_profile_f cb, uptr *stats, uptr stats_size) {
- char *smaps = 0;
+ char *smaps = nullptr;
uptr smaps_cap = 0;
- uptr smaps_len = ReadFileToBuffer("/proc/self/smaps",
- &smaps, &smaps_cap, 64<<20);
+ uptr smaps_len = 0;
+ if (!ReadFileToBuffer("/proc/self/smaps", &smaps, &smaps_cap, &smaps_len))
+ return;
uptr start = 0;
bool file = false;
const char *pos = smaps;
@@ -173,6 +176,6 @@ void GetMemoryProfile(fill_profile_f cb, uptr *stats, uptr stats_size) {
UnmapOrDie(smaps, smaps_cap);
}
-} // namespace __sanitizer
+} // namespace __sanitizer
-#endif // SANITIZER_FREEBSD || SANITIZER_LINUX
+#endif // SANITIZER_FREEBSD || SANITIZER_LINUX
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_linux.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_linux.cc
index 79ca4dfd8fca..b6fb7034ded4 100644
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_linux.cc
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_linux.cc
@@ -18,8 +18,8 @@
namespace __sanitizer {
void ReadProcMaps(ProcSelfMapsBuff *proc_maps) {
- proc_maps->len = ReadFileToBuffer("/proc/self/maps", &proc_maps->data,
- &proc_maps->mmaped_size, 1 << 26);
+ CHECK(ReadFileToBuffer("/proc/self/maps", &proc_maps->data,
+ &proc_maps->mmaped_size, &proc_maps->len));
}
static bool IsOneOf(char c, char c1, char c2) {
@@ -67,7 +67,7 @@ bool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset,
while (IsDecimal(*current_))
current_++;
// Qemu may lack the trailing space.
- // http://code.google.com/p/address-sanitizer/issues/detail?id=160
+ // https://github.com/google/sanitizers/issues/160
// CHECK_EQ(*current_++, ' ');
// Skip spaces.
while (current_ < next_line && *current_ == ' ')
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_mac.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_mac.cc
index 29d699609a6e..d10881e8a7f8 100644
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_mac.cc
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_mac.cc
@@ -65,7 +65,7 @@ void MemoryMappingLayout::LoadFromCache() {
}
// Next and NextSegmentLoad were inspired by base/sysinfo.cc in
-// Google Perftools, http://code.google.com/p/google-perftools.
+// Google Perftools, https://github.com/gperftools/gperftools.
// NextSegmentLoad scans the current image for the next segment load command
// and returns the start and end addresses and file offset of the corresponding
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_quarantine.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_quarantine.h
index 404d3753f7e9..9e0bf2d18fec 100644
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_quarantine.h
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_quarantine.h
@@ -153,7 +153,7 @@ class QuarantineCache {
QuarantineBatch *DequeueBatch() {
if (list_.empty())
- return 0;
+ return nullptr;
QuarantineBatch *b = list_.front();
list_.pop_front();
SizeSub(b->size);
@@ -180,6 +180,6 @@ class QuarantineCache {
return b;
}
};
-} // namespace __sanitizer
+} // namespace __sanitizer
-#endif // #ifndef SANITIZER_QUARANTINE_H
+#endif // SANITIZER_QUARANTINE_H
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_stackdepot.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_stackdepot.cc
index 59b53f4dcd84..985193d1ed5e 100644
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_stackdepot.cc
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_stackdepot.cc
@@ -152,7 +152,7 @@ StackDepotReverseMap::StackDepotReverseMap()
StackTrace StackDepotReverseMap::Get(u32 id) {
if (!map_.size())
return StackTrace();
- IdDescPair pair = {id, 0};
+ IdDescPair pair = {id, nullptr};
uptr idx = InternalBinarySearch(map_, 0, map_.size(), pair,
IdDescPair::IdComparator);
if (idx > map_.size())
@@ -160,4 +160,4 @@ StackTrace StackDepotReverseMap::Get(u32 id) {
return map_[idx].desc->load();
}
-} // namespace __sanitizer
+} // namespace __sanitizer
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_stackdepot.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_stackdepot.h
index 5e3a8b783ac7..cb7345002a40 100644
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_stackdepot.h
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_stackdepot.h
@@ -10,6 +10,7 @@
// This file is shared between AddressSanitizer and ThreadSanitizer
// run-time libraries.
//===----------------------------------------------------------------------===//
+
#ifndef SANITIZER_STACKDEPOT_H
#define SANITIZER_STACKDEPOT_H
@@ -23,7 +24,7 @@ namespace __sanitizer {
struct StackDepotNode;
struct StackDepotHandle {
StackDepotNode *node_;
- StackDepotHandle() : node_(0) {}
+ StackDepotHandle() : node_(nullptr) {}
explicit StackDepotHandle(StackDepotNode *node) : node_(node) {}
bool valid() { return node_; }
u32 id();
@@ -66,6 +67,6 @@ class StackDepotReverseMap {
void operator=(const StackDepotReverseMap&);
};
-} // namespace __sanitizer
+} // namespace __sanitizer
-#endif // SANITIZER_STACKDEPOT_H
+#endif // SANITIZER_STACKDEPOT_H
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_stackdepotbase.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_stackdepotbase.h
index 5de2e711fe45..4ec77b467b1f 100644
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_stackdepotbase.h
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_stackdepotbase.h
@@ -10,6 +10,7 @@
// Implementation of a mapping from arbitrary values to unique 32-bit
// identifiers.
//===----------------------------------------------------------------------===//
+
#ifndef SANITIZER_STACKDEPOTBASE_H
#define SANITIZER_STACKDEPOTBASE_H
@@ -26,7 +27,7 @@ class StackDepotBase {
typedef typename Node::args_type args_type;
typedef typename Node::handle_type handle_type;
// Maps stack trace to an unique id.
- handle_type Put(args_type args, bool *inserted = 0);
+ handle_type Put(args_type args, bool *inserted = nullptr);
// Retrieves a stored stack trace by the id.
args_type Get(u32 id);
@@ -66,7 +67,7 @@ Node *StackDepotBase<Node, kReservedBits, kTabSizeLog>::find(Node *s,
return s;
}
}
- return 0;
+ return nullptr;
}
template <class Node, int kReservedBits, int kTabSizeLog>
@@ -172,5 +173,6 @@ void StackDepotBase<Node, kReservedBits, kTabSizeLog>::UnlockAll() {
}
}
-} // namespace __sanitizer
-#endif // SANITIZER_STACKDEPOTBASE_H
+} // namespace __sanitizer
+
+#endif // SANITIZER_STACKDEPOTBASE_H
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.cc
index 84ff9d9d9e3b..7862575b37bb 100644
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.cc
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.cc
@@ -83,7 +83,18 @@ void BufferedStackTrace::FastUnwindStack(uptr pc, uptr bp, uptr stack_top,
while (IsValidFrame((uptr)frame, stack_top, bottom) &&
IsAligned((uptr)frame, sizeof(*frame)) &&
size < max_depth) {
+#ifdef __powerpc__
+ // PowerPC ABIs specify that the return address is saved at offset
+ // 16 of the *caller's* stack frame. Thus we must dereference the
+ // back chain to find the caller frame before extracting it.
+ uhwptr *caller_frame = (uhwptr*)frame[0];
+ if (!IsValidFrame((uptr)caller_frame, stack_top, bottom) ||
+ !IsAligned((uptr)caller_frame, sizeof(uhwptr)))
+ break;
+ uhwptr pc1 = caller_frame[2];
+#else
uhwptr pc1 = frame[1];
+#endif
if (pc1 != pc) {
trace_buffer[size++] = (uptr) pc1;
}
@@ -107,7 +118,7 @@ void BufferedStackTrace::PopStackFrames(uptr count) {
uptr BufferedStackTrace::LocatePcInTrace(uptr pc) {
// Use threshold to find PC in stack trace, as PC we want to unwind from may
// slightly differ from return address in the actual unwinded stack trace.
- const int kPcThreshold = 304;
+ const int kPcThreshold = 320;
for (uptr i = 0; i < size; ++i) {
if (MatchPc(pc, trace[i], kPcThreshold))
return i;
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.h
index 6c3a1511f337..969cedb165c8 100644
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.h
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.h
@@ -19,9 +19,7 @@ namespace __sanitizer {
static const u32 kStackTraceMax = 256;
-#if SANITIZER_LINUX && (defined(__aarch64__) || defined(__powerpc__) || \
- defined(__powerpc64__) || defined(__sparc__) || \
- defined(__mips__))
+#if SANITIZER_LINUX && (defined(__sparc__) || defined(__mips__))
# define SANITIZER_CAN_FAST_UNWIND 0
#elif SANITIZER_WINDOWS
# define SANITIZER_CAN_FAST_UNWIND 0
@@ -31,7 +29,7 @@ static const u32 kStackTraceMax = 256;
// Fast unwind is the only option on Mac for now; we will need to
// revisit this macro when slow unwind works on Mac, see
-// https://code.google.com/p/address-sanitizer/issues/detail?id=137
+// https://github.com/google/sanitizers/issues/137
#if SANITIZER_MAC
# define SANITIZER_CAN_SLOW_UNWIND 0
#else
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_printer.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_printer.cc
index 3574fa3782c6..669b0ba28265 100644
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_printer.cc
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_printer.cc
@@ -10,13 +10,14 @@
// This file is shared between sanitizers' run-time libraries.
//
//===----------------------------------------------------------------------===//
+
#include "sanitizer_stacktrace_printer.h"
namespace __sanitizer {
static const char *StripFunctionName(const char *function, const char *prefix) {
- if (function == 0) return 0;
- if (prefix == 0) return function;
+ if (!function) return nullptr;
+ if (!prefix) return function;
uptr prefix_len = internal_strlen(prefix);
if (0 == internal_strncmp(function, prefix, prefix_len))
return function + prefix_len;
@@ -140,4 +141,4 @@ void RenderModuleLocation(InternalScopedString *buffer, const char *module,
offset);
}
-} // namespace __sanitizer
+} // namespace __sanitizer
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
index 47b27e7e5c75..2376ee56e1d7 100644
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
@@ -12,9 +12,10 @@
//
//===----------------------------------------------------------------------===//
-
#include "sanitizer_platform.h"
-#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__mips__))
+
+#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__mips__) || \
+ defined(__aarch64__) || defined(__powerpc64__))
#include "sanitizer_stoptheworld.h"
@@ -27,9 +28,15 @@
#include <sys/prctl.h> // for PR_* definitions
#include <sys/ptrace.h> // for PTRACE_* definitions
#include <sys/types.h> // for pid_t
+#include <sys/uio.h> // for iovec
+#include <elf.h> // for NT_PRSTATUS
#if SANITIZER_ANDROID && defined(__arm__)
# include <linux/user.h> // for pt_regs
#else
+# ifdef __aarch64__
+// GLIBC 2.20+ sys/user does not include asm/ptrace.h
+# include <asm/ptrace.h>
+# endif
# include <sys/user.h> // for user_regs_struct
#endif
#include <sys/wait.h> // for signal-related stuff
@@ -112,7 +119,7 @@ bool ThreadSuspender::SuspendThread(SuspendedThreadID tid) {
if (suspended_threads_list_.Contains(tid))
return false;
int pterrno;
- if (internal_iserror(internal_ptrace(PTRACE_ATTACH, tid, NULL, NULL),
+ if (internal_iserror(internal_ptrace(PTRACE_ATTACH, tid, nullptr, nullptr),
&pterrno)) {
// Either the thread is dead, or something prevented us from attaching.
// Log this event and move on.
@@ -139,11 +146,12 @@ bool ThreadSuspender::SuspendThread(SuspendedThreadID tid) {
// doesn't hurt to report it.
VReport(1, "Waiting on thread %d failed, detaching (errno %d).\n",
tid, wperrno);
- internal_ptrace(PTRACE_DETACH, tid, NULL, NULL);
+ internal_ptrace(PTRACE_DETACH, tid, nullptr, nullptr);
return false;
}
if (WIFSTOPPED(status) && WSTOPSIG(status) != SIGSTOP) {
- internal_ptrace(PTRACE_CONT, tid, 0, (void*)(uptr)WSTOPSIG(status));
+ internal_ptrace(PTRACE_CONT, tid, nullptr,
+ (void*)(uptr)WSTOPSIG(status));
continue;
}
break;
@@ -157,7 +165,7 @@ void ThreadSuspender::ResumeAllThreads() {
for (uptr i = 0; i < suspended_threads_list_.thread_count(); i++) {
pid_t tid = suspended_threads_list_.GetThreadID(i);
int pterrno;
- if (!internal_iserror(internal_ptrace(PTRACE_DETACH, tid, NULL, NULL),
+ if (!internal_iserror(internal_ptrace(PTRACE_DETACH, tid, nullptr, nullptr),
&pterrno)) {
VReport(2, "Detached from thread %d.\n", tid);
} else {
@@ -172,7 +180,7 @@ void ThreadSuspender::ResumeAllThreads() {
void ThreadSuspender::KillAllThreads() {
for (uptr i = 0; i < suspended_threads_list_.thread_count(); i++)
internal_ptrace(PTRACE_KILL, suspended_threads_list_.GetThreadID(i),
- NULL, NULL);
+ nullptr, nullptr);
}
bool ThreadSuspender::SuspendAllThreads() {
@@ -198,13 +206,25 @@ bool ThreadSuspender::SuspendAllThreads() {
}
// Pointer to the ThreadSuspender instance for use in signal handler.
-static ThreadSuspender *thread_suspender_instance = NULL;
+static ThreadSuspender *thread_suspender_instance = nullptr;
// Synchronous signals that should not be blocked.
static const int kSyncSignals[] = { SIGABRT, SIGILL, SIGFPE, SIGSEGV, SIGBUS,
SIGXCPU, SIGXFSZ };
-static DieCallbackType old_die_callback;
+static void TracerThreadDieCallback() {
+ // Generally a call to Die() in the tracer thread should be fatal to the
+ // parent process as well, because they share the address space.
+ // This really only works correctly if all the threads are suspended at this
+ // point. So we correctly handle calls to Die() from within the callback, but
+ // not those that happen before or after the callback. Hopefully there aren't
+ // a lot of opportunities for that to happen...
+ ThreadSuspender *inst = thread_suspender_instance;
+ if (inst && stoptheworld_tracer_pid == internal_getpid()) {
+ inst->KillAllThreads();
+ thread_suspender_instance = nullptr;
+ }
+}
// Signal handler to wake up suspended threads when the tracer thread dies.
static void TracerThreadSignalHandler(int signum, void *siginfo, void *uctx) {
@@ -212,37 +232,18 @@ static void TracerThreadSignalHandler(int signum, void *siginfo, void *uctx) {
VPrintf(1, "Tracer caught signal %d: addr=0x%zx pc=0x%zx sp=0x%zx\n",
signum, ctx.addr, ctx.pc, ctx.sp);
ThreadSuspender *inst = thread_suspender_instance;
- if (inst != NULL) {
+ if (inst) {
if (signum == SIGABRT)
inst->KillAllThreads();
else
inst->ResumeAllThreads();
- SetDieCallback(old_die_callback);
- old_die_callback = NULL;
- thread_suspender_instance = NULL;
+ RAW_CHECK(RemoveDieCallback(TracerThreadDieCallback));
+ thread_suspender_instance = nullptr;
atomic_store(&inst->arg->done, 1, memory_order_relaxed);
}
internal__exit((signum == SIGABRT) ? 1 : 2);
}
-static void TracerThreadDieCallback() {
- // Generally a call to Die() in the tracer thread should be fatal to the
- // parent process as well, because they share the address space.
- // This really only works correctly if all the threads are suspended at this
- // point. So we correctly handle calls to Die() from within the callback, but
- // not those that happen before or after the callback. Hopefully there aren't
- // a lot of opportunities for that to happen...
- ThreadSuspender *inst = thread_suspender_instance;
- if (inst != NULL && stoptheworld_tracer_pid == internal_getpid()) {
- inst->KillAllThreads();
- thread_suspender_instance = NULL;
- }
- if (old_die_callback)
- old_die_callback();
- SetDieCallback(old_die_callback);
- old_die_callback = NULL;
-}
-
// Size of alternative stack for signal handlers in the tracer thread.
static const int kHandlerStackSize = 4096;
@@ -260,8 +261,7 @@ static int TracerThread(void* argument) {
tracer_thread_argument->mutex.Lock();
tracer_thread_argument->mutex.Unlock();
- old_die_callback = GetDieCallback();
- SetDieCallback(TracerThreadDieCallback);
+ RAW_CHECK(AddDieCallback(TracerThreadDieCallback));
ThreadSuspender thread_suspender(internal_getppid(), tracer_thread_argument);
// Global pointer for the signal handler.
@@ -273,7 +273,7 @@ static int TracerThread(void* argument) {
internal_memset(&handler_stack, 0, sizeof(handler_stack));
handler_stack.ss_sp = handler_stack_memory.data();
handler_stack.ss_size = kHandlerStackSize;
- internal_sigaltstack(&handler_stack, NULL);
+ internal_sigaltstack(&handler_stack, nullptr);
// Install our handler for synchronous signals. Other signals should be
// blocked by the mask we inherited from the parent thread.
@@ -295,8 +295,8 @@ static int TracerThread(void* argument) {
thread_suspender.ResumeAllThreads();
exit_code = 0;
}
- SetDieCallback(old_die_callback);
- thread_suspender_instance = NULL;
+ RAW_CHECK(RemoveDieCallback(TracerThreadDieCallback));
+ thread_suspender_instance = nullptr;
atomic_store(&tracer_thread_argument->done, 1, memory_order_relaxed);
return exit_code;
}
@@ -404,8 +404,8 @@ void StopTheWorld(StopTheWorldCallback callback, void *argument) {
uptr tracer_pid = internal_clone(
TracerThread, tracer_stack.Bottom(),
CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_UNTRACED,
- &tracer_thread_argument, 0 /* parent_tidptr */, 0 /* newtls */, 0
- /* child_tidptr */);
+ &tracer_thread_argument, nullptr /* parent_tidptr */,
+ nullptr /* newtls */, nullptr /* child_tidptr */);
internal_sigprocmask(SIG_SETMASK, &old_sigset, 0);
int local_errno = 0;
if (internal_iserror(tracer_pid, &local_errno)) {
@@ -432,7 +432,7 @@ void StopTheWorld(StopTheWorldCallback callback, void *argument) {
// Now the tracer thread is about to exit and does not touch errno,
// wait for it.
for (;;) {
- uptr waitpid_status = internal_waitpid(tracer_pid, NULL, __WALL);
+ uptr waitpid_status = internal_waitpid(tracer_pid, nullptr, __WALL);
if (!internal_iserror(waitpid_status, &local_errno))
break;
if (local_errno == EINTR)
@@ -469,6 +469,11 @@ typedef pt_regs regs_struct;
typedef struct user regs_struct;
#define REG_SP regs[EF_REG29]
+#elif defined(__aarch64__)
+typedef struct user_pt_regs regs_struct;
+#define REG_SP sp
+#define ARCH_IOVEC_FOR_GETREGSET
+
#else
#error "Unsupported architecture"
#endif // SANITIZER_ANDROID && defined(__arm__)
@@ -479,8 +484,18 @@ int SuspendedThreadsList::GetRegistersAndSP(uptr index,
pid_t tid = GetThreadID(index);
regs_struct regs;
int pterrno;
- if (internal_iserror(internal_ptrace(PTRACE_GETREGS, tid, NULL, &regs),
- &pterrno)) {
+#ifdef ARCH_IOVEC_FOR_GETREGSET
+ struct iovec regset_io;
+ regset_io.iov_base = &regs;
+ regset_io.iov_len = sizeof(regs_struct);
+ bool isErr = internal_iserror(internal_ptrace(PTRACE_GETREGSET, tid,
+ (void*)NT_PRSTATUS, (void*)&regset_io),
+ &pterrno);
+#else
+ bool isErr = internal_iserror(internal_ptrace(PTRACE_GETREGS, tid, nullptr,
+ &regs), &pterrno);
+#endif
+ if (isErr) {
VReport(1, "Could not get registers from thread %d (errno %d).\n", tid,
pterrno);
return -1;
@@ -494,6 +509,7 @@ int SuspendedThreadsList::GetRegistersAndSP(uptr index,
uptr SuspendedThreadsList::RegisterCount() {
return sizeof(regs_struct) / sizeof(uptr);
}
-} // namespace __sanitizer
+} // namespace __sanitizer
-#endif // SANITIZER_LINUX && (defined(__x86_64__) || defined(__mips__))
+#endif // SANITIZER_LINUX && (defined(__x86_64__) || defined(__mips__)
+ // || defined(__aarch64__) || defined(__powerpc64__)
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_suppressions.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_suppressions.cc
index 08cb497269bf..f0f2c9c725a1 100644
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_suppressions.cc
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_suppressions.cc
@@ -60,15 +60,13 @@ void SuppressionContext::ParseFromFile(const char *filename) {
}
// Read the file.
- char *file_contents;
- uptr buffer_size;
- const uptr max_len = 1 << 26;
- uptr contents_size =
- ReadFileToBuffer(filename, &file_contents, &buffer_size, max_len);
VPrintf(1, "%s: reading suppressions file at %s\n",
SanitizerToolName, filename);
-
- if (contents_size == 0) {
+ char *file_contents;
+ uptr buffer_size;
+ uptr contents_size;
+ if (!ReadFileToBuffer(filename, &file_contents, &buffer_size,
+ &contents_size)) {
Printf("%s: failed to read suppressions file '%s'\n", SanitizerToolName,
filename);
Die();
@@ -114,7 +112,8 @@ void SuppressionContext::Parse(const char *str) {
end = line + internal_strlen(line);
if (line != end && line[0] != '#') {
const char *end2 = end;
- while (line != end2 && (end2[-1] == ' ' || end2[-1] == '\t'))
+ while (line != end2 &&
+ (end2[-1] == ' ' || end2[-1] == '\t' || end2[-1] == '\r'))
end2--;
int type;
for (type = 0; type < suppression_types_num_; type++) {
@@ -133,8 +132,6 @@ void SuppressionContext::Parse(const char *str) {
s.templ = (char*)InternalAlloc(end2 - line + 1);
internal_memcpy(s.templ, line, end2 - line);
s.templ[end2 - line] = 0;
- s.hit_count = 0;
- s.weight = 0;
suppressions_.push_back(s);
has_suppression_type_[type] = true;
}
@@ -164,7 +161,7 @@ const Suppression *SuppressionContext::SuppressionAt(uptr i) const {
void SuppressionContext::GetMatched(
InternalMmapVector<Suppression *> *matched) {
for (uptr i = 0; i < suppressions_.size(); i++)
- if (suppressions_[i].hit_count)
+ if (atomic_load_relaxed(&suppressions_[i].hit_count))
matched->push_back(&suppressions_[i]);
}
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_suppressions.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_suppressions.h
index 02dbf6f9690b..0ca875a2dde6 100644
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_suppressions.h
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_suppressions.h
@@ -14,14 +14,16 @@
#define SANITIZER_SUPPRESSIONS_H
#include "sanitizer_common.h"
+#include "sanitizer_atomic.h"
#include "sanitizer_internal_defs.h"
namespace __sanitizer {
struct Suppression {
+ Suppression() { internal_memset(this, 0, sizeof(*this)); }
const char *type;
char *templ;
- unsigned hit_count;
+ atomic_uint32_t hit_count;
uptr weight;
};
@@ -41,7 +43,7 @@ class SuppressionContext {
void GetMatched(InternalMmapVector<Suppression *> *matched);
private:
- static const int kMaxSuppressionTypes = 16;
+ static const int kMaxSuppressionTypes = 32;
const char **const suppression_types_;
const int suppression_types_num_;
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_internal.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_internal.h
index 66ae809ed53e..12c70b602e24 100644
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_internal.h
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_internal.h
@@ -74,24 +74,31 @@ class SymbolizerProcess {
explicit SymbolizerProcess(const char *path, bool use_forkpty = false);
const char *SendCommand(const char *command);
- private:
- bool Restart();
- const char *SendCommandImpl(const char *command);
- bool ReadFromSymbolizer(char *buffer, uptr max_length);
- bool WriteToSymbolizer(const char *buffer, uptr length);
- bool StartSymbolizerSubprocess();
-
+ protected:
virtual bool ReachedEndOfOutput(const char *buffer, uptr length) const {
UNIMPLEMENTED();
}
- virtual void ExecuteWithDefaultArgs(const char *path_to_binary) const {
+ /// The maximum number of arguments required to invoke a tool process.
+ enum { kArgVMax = 6 };
+
+ /// Fill in an argv array to invoke the child process.
+ virtual void GetArgV(const char *path_to_binary,
+ const char *(&argv)[kArgVMax]) const {
UNIMPLEMENTED();
}
+ virtual bool ReadFromSymbolizer(char *buffer, uptr max_length);
+
+ private:
+ bool Restart();
+ const char *SendCommandImpl(const char *command);
+ bool WriteToSymbolizer(const char *buffer, uptr length);
+ bool StartSymbolizerSubprocess();
+
const char *path_;
- int input_fd_;
- int output_fd_;
+ fd_t input_fd_;
+ fd_t output_fd_;
static const uptr kBufferSize = 16 * 1024;
char buffer_[kBufferSize];
@@ -104,6 +111,41 @@ class SymbolizerProcess {
bool use_forkpty_;
};
+class LLVMSymbolizerProcess;
+
+// This tool invokes llvm-symbolizer in a subprocess. It should be as portable
+// as the llvm-symbolizer tool is.
+class LLVMSymbolizer : public SymbolizerTool {
+ public:
+ explicit LLVMSymbolizer(const char *path, LowLevelAllocator *allocator);
+
+ bool SymbolizePC(uptr addr, SymbolizedStack *stack) override;
+
+ bool SymbolizeData(uptr addr, DataInfo *info) override;
+
+ private:
+ const char *SendCommand(bool is_data, const char *module_name,
+ uptr module_offset);
+
+ LLVMSymbolizerProcess *symbolizer_process_;
+ static const uptr kBufferSize = 16 * 1024;
+ char buffer_[kBufferSize];
+};
+
+// Parses one or more two-line strings in the following format:
+// <function_name>
+// <file_name>:<line_number>[:<column_number>]
+// Used by LLVMSymbolizer, Addr2LinePool and InternalSymbolizer, since all of
+// them use the same output format. Returns true if any useful debug
+// information was found.
+void ParseSymbolizePCOutput(const char *str, SymbolizedStack *res);
+
+// Parses a two-line string in the following format:
+// <symbol_name>
+// <start_address> <size>
+// Used by LLVMSymbolizer and InternalSymbolizer.
+void ParseSymbolizeDataOutput(const char *str, DataInfo *info);
+
} // namespace __sanitizer
#endif // SANITIZER_SYMBOLIZER_INTERNAL_H
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.h
index 00b465a72774..ddfd475592cb 100644
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.h
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.h
@@ -16,6 +16,7 @@
#include "sanitizer_platform.h"
#include "sanitizer_common.h"
+#include "sanitizer_allocator_internal.h"
#include "sanitizer_symbolizer_internal.h"
#ifndef SANITIZER_LIBBACKTRACE
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc
index 160f55d422ca..8c3ad81f952a 100644
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc
@@ -184,4 +184,245 @@ Symbolizer *Symbolizer::GetOrInit() {
return symbolizer_;
}
+// For now we assume the following protocol:
+// For each request of the form
+// <module_name> <module_offset>
+// passed to STDIN, external symbolizer prints to STDOUT response:
+// <function_name>
+// <file_name>:<line_number>:<column_number>
+// <function_name>
+// <file_name>:<line_number>:<column_number>
+// ...
+// <empty line>
+class LLVMSymbolizerProcess : public SymbolizerProcess {
+ public:
+ explicit LLVMSymbolizerProcess(const char *path) : SymbolizerProcess(path) {}
+
+ private:
+ bool ReachedEndOfOutput(const char *buffer, uptr length) const override {
+ // Empty line marks the end of llvm-symbolizer output.
+ return length >= 2 && buffer[length - 1] == '\n' &&
+ buffer[length - 2] == '\n';
+ }
+
+ void GetArgV(const char *path_to_binary,
+ const char *(&argv)[kArgVMax]) const override {
+#if defined(__x86_64h__)
+ const char* const kSymbolizerArch = "--default-arch=x86_64h";
+#elif defined(__x86_64__)
+ const char* const kSymbolizerArch = "--default-arch=x86_64";
+#elif defined(__i386__)
+ const char* const kSymbolizerArch = "--default-arch=i386";
+#elif defined(__powerpc64__) && defined(__BIG_ENDIAN__)
+ const char* const kSymbolizerArch = "--default-arch=powerpc64";
+#elif defined(__powerpc64__) && defined(__LITTLE_ENDIAN__)
+ const char* const kSymbolizerArch = "--default-arch=powerpc64le";
+#else
+ const char* const kSymbolizerArch = "--default-arch=unknown";
+#endif
+
+ const char *const inline_flag = common_flags()->symbolize_inline_frames
+ ? "--inlining=true"
+ : "--inlining=false";
+ int i = 0;
+ argv[i++] = path_to_binary;
+ argv[i++] = inline_flag;
+ argv[i++] = kSymbolizerArch;
+ argv[i++] = nullptr;
+ }
+};
+
+LLVMSymbolizer::LLVMSymbolizer(const char *path, LowLevelAllocator *allocator)
+ : symbolizer_process_(new(*allocator) LLVMSymbolizerProcess(path)) {}
+
+// Parse a <file>:<line>[:<column>] buffer. The file path may contain colons on
+// Windows, so extract tokens from the right hand side first. The column info is
+// also optional.
+static const char *ParseFileLineInfo(AddressInfo *info, const char *str) {
+ char *file_line_info = 0;
+ str = ExtractToken(str, "\n", &file_line_info);
+ CHECK(file_line_info);
+ // Parse the last :<int>, which must be there.
+ char *last_colon = internal_strrchr(file_line_info, ':');
+ CHECK(last_colon);
+ int line_or_column = internal_atoll(last_colon + 1);
+ // Truncate the string at the last colon and find the next-to-last colon.
+ *last_colon = '\0';
+ last_colon = internal_strrchr(file_line_info, ':');
+ if (last_colon && IsDigit(last_colon[1])) {
+ // If the second-to-last colon is followed by a digit, it must be the line
+ // number, and the previous parsed number was a column.
+ info->line = internal_atoll(last_colon + 1);
+ info->column = line_or_column;
+ *last_colon = '\0';
+ } else {
+ // Otherwise, we have line info but no column info.
+ info->line = line_or_column;
+ info->column = 0;
+ }
+ ExtractToken(file_line_info, "", &info->file);
+ InternalFree(file_line_info);
+ return str;
+}
+
+// Parses one or more two-line strings in the following format:
+// <function_name>
+// <file_name>:<line_number>[:<column_number>]
+// Used by LLVMSymbolizer, Addr2LinePool and InternalSymbolizer, since all of
+// them use the same output format.
+void ParseSymbolizePCOutput(const char *str, SymbolizedStack *res) {
+ bool top_frame = true;
+ SymbolizedStack *last = res;
+ while (true) {
+ char *function_name = 0;
+ str = ExtractToken(str, "\n", &function_name);
+ CHECK(function_name);
+ if (function_name[0] == '\0') {
+ // There are no more frames.
+ InternalFree(function_name);
+ break;
+ }
+ SymbolizedStack *cur;
+ if (top_frame) {
+ cur = res;
+ top_frame = false;
+ } else {
+ cur = SymbolizedStack::New(res->info.address);
+ cur->info.FillModuleInfo(res->info.module, res->info.module_offset);
+ last->next = cur;
+ last = cur;
+ }
+
+ AddressInfo *info = &cur->info;
+ info->function = function_name;
+ str = ParseFileLineInfo(info, str);
+
+ // Functions and filenames can be "??", in which case we write 0
+ // to address info to mark that names are unknown.
+ if (0 == internal_strcmp(info->function, "??")) {
+ InternalFree(info->function);
+ info->function = 0;
+ }
+ if (0 == internal_strcmp(info->file, "??")) {
+ InternalFree(info->file);
+ info->file = 0;
+ }
+ }
+}
+
+// Parses a two-line string in the following format:
+// <symbol_name>
+// <start_address> <size>
+// Used by LLVMSymbolizer and InternalSymbolizer.
+void ParseSymbolizeDataOutput(const char *str, DataInfo *info) {
+ str = ExtractToken(str, "\n", &info->name);
+ str = ExtractUptr(str, " ", &info->start);
+ str = ExtractUptr(str, "\n", &info->size);
+}
+
+bool LLVMSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) {
+ if (const char *buf = SendCommand(/*is_data*/ false, stack->info.module,
+ stack->info.module_offset)) {
+ ParseSymbolizePCOutput(buf, stack);
+ return true;
+ }
+ return false;
+}
+
+bool LLVMSymbolizer::SymbolizeData(uptr addr, DataInfo *info) {
+ if (const char *buf =
+ SendCommand(/*is_data*/ true, info->module, info->module_offset)) {
+ ParseSymbolizeDataOutput(buf, info);
+ info->start += (addr - info->module_offset); // Add the base address.
+ return true;
+ }
+ return false;
+}
+
+const char *LLVMSymbolizer::SendCommand(bool is_data, const char *module_name,
+ uptr module_offset) {
+ CHECK(module_name);
+ internal_snprintf(buffer_, kBufferSize, "%s\"%s\" 0x%zx\n",
+ is_data ? "DATA " : "", module_name, module_offset);
+ return symbolizer_process_->SendCommand(buffer_);
+}
+
+SymbolizerProcess::SymbolizerProcess(const char *path, bool use_forkpty)
+ : path_(path),
+ input_fd_(kInvalidFd),
+ output_fd_(kInvalidFd),
+ times_restarted_(0),
+ failed_to_start_(false),
+ reported_invalid_path_(false),
+ use_forkpty_(use_forkpty) {
+ CHECK(path_);
+ CHECK_NE(path_[0], '\0');
+}
+
+const char *SymbolizerProcess::SendCommand(const char *command) {
+ for (; times_restarted_ < kMaxTimesRestarted; times_restarted_++) {
+ // Start or restart symbolizer if we failed to send command to it.
+ if (const char *res = SendCommandImpl(command))
+ return res;
+ Restart();
+ }
+ if (!failed_to_start_) {
+ Report("WARNING: Failed to use and restart external symbolizer!\n");
+ failed_to_start_ = true;
+ }
+ return 0;
+}
+
+const char *SymbolizerProcess::SendCommandImpl(const char *command) {
+ if (input_fd_ == kInvalidFd || output_fd_ == kInvalidFd)
+ return 0;
+ if (!WriteToSymbolizer(command, internal_strlen(command)))
+ return 0;
+ if (!ReadFromSymbolizer(buffer_, kBufferSize))
+ return 0;
+ return buffer_;
+}
+
+bool SymbolizerProcess::Restart() {
+ if (input_fd_ != kInvalidFd)
+ CloseFile(input_fd_);
+ if (output_fd_ != kInvalidFd)
+ CloseFile(output_fd_);
+ return StartSymbolizerSubprocess();
+}
+
+bool SymbolizerProcess::ReadFromSymbolizer(char *buffer, uptr max_length) {
+ if (max_length == 0)
+ return true;
+ uptr read_len = 0;
+ while (true) {
+ uptr just_read = 0;
+ bool success = ReadFromFile(input_fd_, buffer + read_len,
+ max_length - read_len - 1, &just_read);
+ // We can't read 0 bytes, as we don't expect external symbolizer to close
+ // its stdout.
+ if (!success || just_read == 0) {
+ Report("WARNING: Can't read from symbolizer at fd %d\n", input_fd_);
+ return false;
+ }
+ read_len += just_read;
+ if (ReachedEndOfOutput(buffer, read_len))
+ break;
+ }
+ buffer[read_len] = '\0';
+ return true;
+}
+
+bool SymbolizerProcess::WriteToSymbolizer(const char *buffer, uptr length) {
+ if (length == 0)
+ return true;
+ uptr write_len = 0;
+ bool success = WriteToFile(output_fd_, buffer, length, &write_len);
+ if (!success || write_len != length) {
+ Report("WARNING: Can't write to symbolizer at fd %d\n", output_fd_);
+ return false;
+ }
+ return true;
+}
+
} // namespace __sanitizer
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.cc
index 9a64192b0353..64048fa7e58e 100644
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.cc
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.cc
@@ -33,39 +33,50 @@ bool DlAddrSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) {
int result = dladdr((const void *)addr, &info);
if (!result) return false;
const char *demangled = DemangleCXXABI(info.dli_sname);
- stack->info.function = internal_strdup(demangled);
+ stack->info.function = demangled ? internal_strdup(demangled) : nullptr;
return true;
}
-bool DlAddrSymbolizer::SymbolizeData(uptr addr, DataInfo *info) {
- return false;
+bool DlAddrSymbolizer::SymbolizeData(uptr addr, DataInfo *datainfo) {
+ Dl_info info;
+ int result = dladdr((const void *)addr, &info);
+ if (!result) return false;
+ const char *demangled = DemangleCXXABI(info.dli_sname);
+ datainfo->name = internal_strdup(demangled);
+ datainfo->start = (uptr)info.dli_saddr;
+ return true;
}
class AtosSymbolizerProcess : public SymbolizerProcess {
public:
explicit AtosSymbolizerProcess(const char *path, pid_t parent_pid)
- : SymbolizerProcess(path, /*use_forkpty*/ true),
- parent_pid_(parent_pid) {}
+ : SymbolizerProcess(path, /*use_forkpty*/ true) {
+ // Put the string command line argument in the object so that it outlives
+ // the call to GetArgV.
+ internal_snprintf(pid_str_, sizeof(pid_str_), "%d", parent_pid);
+ }
private:
bool ReachedEndOfOutput(const char *buffer, uptr length) const override {
return (length >= 1 && buffer[length - 1] == '\n');
}
- void ExecuteWithDefaultArgs(const char *path_to_binary) const override {
- char pid_str[16];
- internal_snprintf(pid_str, sizeof(pid_str), "%d", parent_pid_);
+ void GetArgV(const char *path_to_binary,
+ const char *(&argv)[kArgVMax]) const override {
+ int i = 0;
+ argv[i++] = path_to_binary;
+ argv[i++] = "-p";
+ argv[i++] = &pid_str_[0];
if (GetMacosVersion() == MACOS_VERSION_MAVERICKS) {
// On Mavericks atos prints a deprecation warning which we suppress by
// passing -d. The warning isn't present on other OSX versions, even the
// newer ones.
- execl(path_to_binary, path_to_binary, "-p", pid_str, "-d", (char *)0);
- } else {
- execl(path_to_binary, path_to_binary, "-p", pid_str, (char *)0);
+ argv[i++] = "-d";
}
+ argv[i++] = nullptr;
}
- pid_t parent_pid_;
+ char pid_str_[16];
};
static const char *kAtosErrorMessages[] = {
@@ -85,7 +96,9 @@ static bool IsAtosErrorMessage(const char *str) {
return false;
}
-static bool ParseCommandOutput(const char *str, SymbolizedStack *res) {
+static bool ParseCommandOutput(const char *str, uptr addr, char **out_name,
+ char **out_module, char **out_file, uptr *line,
+ uptr *start_address) {
// Trim ending newlines.
char *trim;
ExtractTokenUpToDelimiter(str, "\n", &trim);
@@ -93,7 +106,9 @@ static bool ParseCommandOutput(const char *str, SymbolizedStack *res) {
// The line from `atos` is in one of these formats:
// myfunction (in library.dylib) (sourcefile.c:17)
// myfunction (in library.dylib) + 0x1fe
+ // myfunction (in library.dylib) + 15
// 0xdeadbeef (in library.dylib) + 0x1fe
+ // 0xdeadbeef (in library.dylib) + 15
// 0xdeadbeef (in library.dylib)
// 0xdeadbeef
@@ -104,21 +119,33 @@ static bool ParseCommandOutput(const char *str, SymbolizedStack *res) {
}
const char *rest = trim;
- char *function_name;
- rest = ExtractTokenUpToDelimiter(rest, " (in ", &function_name);
- if (internal_strncmp(function_name, "0x", 2) != 0)
- res->info.function = function_name;
+ char *symbol_name;
+ rest = ExtractTokenUpToDelimiter(rest, " (in ", &symbol_name);
+ if (rest[0] == '\0') {
+ InternalFree(symbol_name);
+ InternalFree(trim);
+ return false;
+ }
+
+ if (internal_strncmp(symbol_name, "0x", 2) != 0)
+ *out_name = symbol_name;
else
- InternalFree(function_name);
- rest = ExtractTokenUpToDelimiter(rest, ") ", &res->info.module);
+ InternalFree(symbol_name);
+ rest = ExtractTokenUpToDelimiter(rest, ") ", out_module);
if (rest[0] == '(') {
- rest++;
- rest = ExtractTokenUpToDelimiter(rest, ":", &res->info.file);
- char *extracted_line_number;
- rest = ExtractTokenUpToDelimiter(rest, ")", &extracted_line_number);
- res->info.line = internal_atoll(extracted_line_number);
- InternalFree(extracted_line_number);
+ if (out_file) {
+ rest++;
+ rest = ExtractTokenUpToDelimiter(rest, ":", out_file);
+ char *extracted_line_number;
+ rest = ExtractTokenUpToDelimiter(rest, ")", &extracted_line_number);
+ if (line) *line = (uptr)internal_atoll(extracted_line_number);
+ InternalFree(extracted_line_number);
+ }
+ } else if (rest[0] == '+') {
+ rest += 2;
+ uptr offset = internal_atoll(rest);
+ if (start_address) *start_address = addr - offset;
}
InternalFree(trim);
@@ -134,14 +161,29 @@ bool AtosSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) {
internal_snprintf(command, sizeof(command), "0x%zx\n", addr);
const char *buf = process_->SendCommand(command);
if (!buf) return false;
- if (!ParseCommandOutput(buf, stack)) {
+ uptr line;
+ if (!ParseCommandOutput(buf, addr, &stack->info.function, &stack->info.module,
+ &stack->info.file, &line, nullptr)) {
process_ = nullptr;
return false;
}
+ stack->info.line = (int)line;
return true;
}
-bool AtosSymbolizer::SymbolizeData(uptr addr, DataInfo *info) { return false; }
+bool AtosSymbolizer::SymbolizeData(uptr addr, DataInfo *info) {
+ if (!process_) return false;
+ char command[32];
+ internal_snprintf(command, sizeof(command), "0x%zx\n", addr);
+ const char *buf = process_->SendCommand(command);
+ if (!buf) return false;
+ if (!ParseCommandOutput(buf, addr, &info->name, &info->module, nullptr,
+ nullptr, &info->start)) {
+ process_ = nullptr;
+ return false;
+ }
+ return true;
+}
} // namespace __sanitizer
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc
index cb8455a21ae2..fc8a7d91ac73 100644
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc
@@ -20,13 +20,21 @@
#include "sanitizer_internal_defs.h"
#include "sanitizer_linux.h"
#include "sanitizer_placement_new.h"
+#include "sanitizer_posix.h"
#include "sanitizer_procmaps.h"
#include "sanitizer_symbolizer_internal.h"
#include "sanitizer_symbolizer_libbacktrace.h"
#include "sanitizer_symbolizer_mac.h"
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/wait.h>
#include <unistd.h>
+#if SANITIZER_MAC
+#include <util.h> // for forkpty()
+#endif // SANITIZER_MAC
+
// C++ demangling function, as required by Itanium C++ ABI. This is weak,
// because we do not require a C++ ABI library to be linked to a program
// using sanitizers; if it's not present, we'll just use the mangled name.
@@ -53,149 +61,130 @@ const char *DemangleCXXABI(const char *name) {
return name;
}
-// Parses one or more two-line strings in the following format:
-// <function_name>
-// <file_name>:<line_number>[:<column_number>]
-// Used by LLVMSymbolizer, Addr2LinePool and InternalSymbolizer, since all of
-// them use the same output format.
-static void ParseSymbolizePCOutput(const char *str, SymbolizedStack *res) {
- bool top_frame = true;
- SymbolizedStack *last = res;
- while (true) {
- char *function_name = 0;
- str = ExtractToken(str, "\n", &function_name);
- CHECK(function_name);
- if (function_name[0] == '\0') {
- // There are no more frames.
- InternalFree(function_name);
- break;
- }
- SymbolizedStack *cur;
- if (top_frame) {
- cur = res;
- top_frame = false;
- } else {
- cur = SymbolizedStack::New(res->info.address);
- cur->info.FillModuleInfo(res->info.module, res->info.module_offset);
- last->next = cur;
- last = cur;
- }
-
- AddressInfo *info = &cur->info;
- info->function = function_name;
- // Parse <file>:<line>:<column> buffer.
- char *file_line_info = 0;
- str = ExtractToken(str, "\n", &file_line_info);
- CHECK(file_line_info);
- const char *line_info = ExtractToken(file_line_info, ":", &info->file);
- line_info = ExtractInt(line_info, ":", &info->line);
- line_info = ExtractInt(line_info, "", &info->column);
- InternalFree(file_line_info);
-
- // Functions and filenames can be "??", in which case we write 0
- // to address info to mark that names are unknown.
- if (0 == internal_strcmp(info->function, "??")) {
- InternalFree(info->function);
- info->function = 0;
- }
- if (0 == internal_strcmp(info->file, "??")) {
- InternalFree(info->file);
- info->file = 0;
+bool SymbolizerProcess::StartSymbolizerSubprocess() {
+ if (!FileExists(path_)) {
+ if (!reported_invalid_path_) {
+ Report("WARNING: invalid path to external symbolizer!\n");
+ reported_invalid_path_ = true;
}
- }
-}
-
-// Parses a two-line string in the following format:
-// <symbol_name>
-// <start_address> <size>
-// Used by LLVMSymbolizer and InternalSymbolizer.
-static void ParseSymbolizeDataOutput(const char *str, DataInfo *info) {
- str = ExtractToken(str, "\n", &info->name);
- str = ExtractUptr(str, " ", &info->start);
- str = ExtractUptr(str, "\n", &info->size);
-}
-
-// For now we assume the following protocol:
-// For each request of the form
-// <module_name> <module_offset>
-// passed to STDIN, external symbolizer prints to STDOUT response:
-// <function_name>
-// <file_name>:<line_number>:<column_number>
-// <function_name>
-// <file_name>:<line_number>:<column_number>
-// ...
-// <empty line>
-class LLVMSymbolizerProcess : public SymbolizerProcess {
- public:
- explicit LLVMSymbolizerProcess(const char *path) : SymbolizerProcess(path) {}
-
- private:
- bool ReachedEndOfOutput(const char *buffer, uptr length) const override {
- // Empty line marks the end of llvm-symbolizer output.
- return length >= 2 && buffer[length - 1] == '\n' &&
- buffer[length - 2] == '\n';
+ return false;
}
- void ExecuteWithDefaultArgs(const char *path_to_binary) const override {
-#if defined(__x86_64h__)
- const char* const kSymbolizerArch = "--default-arch=x86_64h";
-#elif defined(__x86_64__)
- const char* const kSymbolizerArch = "--default-arch=x86_64";
-#elif defined(__i386__)
- const char* const kSymbolizerArch = "--default-arch=i386";
-#elif defined(__powerpc64__) && defined(__BIG_ENDIAN__)
- const char* const kSymbolizerArch = "--default-arch=powerpc64";
-#elif defined(__powerpc64__) && defined(__LITTLE_ENDIAN__)
- const char* const kSymbolizerArch = "--default-arch=powerpc64le";
-#else
- const char* const kSymbolizerArch = "--default-arch=unknown";
-#endif
-
- const char *const inline_flag = common_flags()->symbolize_inline_frames
- ? "--inlining=true"
- : "--inlining=false";
- execl(path_to_binary, path_to_binary, inline_flag, kSymbolizerArch,
- (char *)0);
- }
-};
+ int pid;
+ if (use_forkpty_) {
+#if SANITIZER_MAC
+ fd_t fd = kInvalidFd;
+ // Use forkpty to disable buffering in the new terminal.
+ pid = internal_forkpty(&fd);
+ if (pid == -1) {
+ // forkpty() failed.
+ Report("WARNING: failed to fork external symbolizer (errno: %d)\n",
+ errno);
+ return false;
+ } else if (pid == 0) {
+ // Child subprocess.
+ const char *argv[kArgVMax];
+ GetArgV(path_, argv);
+ execv(path_, const_cast<char **>(&argv[0]));
+ internal__exit(1);
+ }
-class LLVMSymbolizer : public SymbolizerTool {
- public:
- explicit LLVMSymbolizer(const char *path, LowLevelAllocator *allocator)
- : symbolizer_process_(new(*allocator) LLVMSymbolizerProcess(path)) {}
+ // Continue execution in parent process.
+ input_fd_ = output_fd_ = fd;
- bool SymbolizePC(uptr addr, SymbolizedStack *stack) override {
- if (const char *buf = SendCommand(/*is_data*/ false, stack->info.module,
- stack->info.module_offset)) {
- ParseSymbolizePCOutput(buf, stack);
- return true;
+ // Disable echo in the new terminal, disable CR.
+ struct termios termflags;
+ tcgetattr(fd, &termflags);
+ termflags.c_oflag &= ~ONLCR;
+ termflags.c_lflag &= ~ECHO;
+ tcsetattr(fd, TCSANOW, &termflags);
+#else // SANITIZER_MAC
+ UNIMPLEMENTED();
+#endif // SANITIZER_MAC
+ } else {
+ int *infd = NULL;
+ int *outfd = NULL;
+ // The client program may close its stdin and/or stdout and/or stderr
+ // thus allowing socketpair to reuse file descriptors 0, 1 or 2.
+ // In this case the communication between the forked processes may be
+ // broken if either the parent or the child tries to close or duplicate
+ // these descriptors. The loop below produces two pairs of file
+ // descriptors, each greater than 2 (stderr).
+ int sock_pair[5][2];
+ for (int i = 0; i < 5; i++) {
+ if (pipe(sock_pair[i]) == -1) {
+ for (int j = 0; j < i; j++) {
+ internal_close(sock_pair[j][0]);
+ internal_close(sock_pair[j][1]);
+ }
+ Report("WARNING: Can't create a socket pair to start "
+ "external symbolizer (errno: %d)\n", errno);
+ return false;
+ } else if (sock_pair[i][0] > 2 && sock_pair[i][1] > 2) {
+ if (infd == NULL) {
+ infd = sock_pair[i];
+ } else {
+ outfd = sock_pair[i];
+ for (int j = 0; j < i; j++) {
+ if (sock_pair[j] == infd) continue;
+ internal_close(sock_pair[j][0]);
+ internal_close(sock_pair[j][1]);
+ }
+ break;
+ }
+ }
}
- return false;
- }
-
- bool SymbolizeData(uptr addr, DataInfo *info) override {
- if (const char *buf =
- SendCommand(/*is_data*/ true, info->module, info->module_offset)) {
- ParseSymbolizeDataOutput(buf, info);
- info->start += (addr - info->module_offset); // Add the base address.
- return true;
+ CHECK(infd);
+ CHECK(outfd);
+
+ // Real fork() may call user callbacks registered with pthread_atfork().
+ pid = internal_fork();
+ if (pid == -1) {
+ // Fork() failed.
+ internal_close(infd[0]);
+ internal_close(infd[1]);
+ internal_close(outfd[0]);
+ internal_close(outfd[1]);
+ Report("WARNING: failed to fork external symbolizer "
+ " (errno: %d)\n", errno);
+ return false;
+ } else if (pid == 0) {
+ // Child subprocess.
+ internal_close(STDOUT_FILENO);
+ internal_close(STDIN_FILENO);
+ internal_dup2(outfd[0], STDIN_FILENO);
+ internal_dup2(infd[1], STDOUT_FILENO);
+ internal_close(outfd[0]);
+ internal_close(outfd[1]);
+ internal_close(infd[0]);
+ internal_close(infd[1]);
+ for (int fd = sysconf(_SC_OPEN_MAX); fd > 2; fd--)
+ internal_close(fd);
+ const char *argv[kArgVMax];
+ GetArgV(path_, argv);
+ execv(path_, const_cast<char **>(&argv[0]));
+ internal__exit(1);
}
- return false;
+
+ // Continue execution in parent process.
+ internal_close(outfd[0]);
+ internal_close(infd[1]);
+ input_fd_ = infd[0];
+ output_fd_ = outfd[1];
}
- private:
- const char *SendCommand(bool is_data, const char *module_name,
- uptr module_offset) {
- CHECK(module_name);
- internal_snprintf(buffer_, kBufferSize, "%s\"%s\" 0x%zx\n",
- is_data ? "DATA " : "", module_name, module_offset);
- return symbolizer_process_->SendCommand(buffer_);
+ // Check that symbolizer subprocess started successfully.
+ int pid_status;
+ SleepForMillis(kSymbolizerStartupTimeMillis);
+ int exited_pid = waitpid(pid, &pid_status, WNOHANG);
+ if (exited_pid != 0) {
+ // Either waitpid failed, or child has already exited.
+ Report("WARNING: external symbolizer didn't start up correctly!\n");
+ return false;
}
- LLVMSymbolizerProcess *symbolizer_process_;
- static const uptr kBufferSize = 16 * 1024;
- char buffer_[kBufferSize];
-};
+ return true;
+}
class Addr2LineProcess : public SymbolizerProcess {
public:
@@ -205,25 +194,54 @@ class Addr2LineProcess : public SymbolizerProcess {
const char *module_name() const { return module_name_; }
private:
- bool ReachedEndOfOutput(const char *buffer, uptr length) const override {
- // Output should consist of two lines.
- int num_lines = 0;
- for (uptr i = 0; i < length; ++i) {
- if (buffer[i] == '\n')
- num_lines++;
- if (num_lines >= 2)
- return true;
- }
- return false;
+ void GetArgV(const char *path_to_binary,
+ const char *(&argv)[kArgVMax]) const override {
+ int i = 0;
+ argv[i++] = path_to_binary;
+ argv[i++] = "-iCfe";
+ argv[i++] = module_name_;
+ argv[i++] = nullptr;
}
- void ExecuteWithDefaultArgs(const char *path_to_binary) const override {
- execl(path_to_binary, path_to_binary, "-Cfe", module_name_, (char *)0);
+ bool ReachedEndOfOutput(const char *buffer, uptr length) const override;
+
+ bool ReadFromSymbolizer(char *buffer, uptr max_length) override {
+ if (!SymbolizerProcess::ReadFromSymbolizer(buffer, max_length))
+ return false;
+ // We should cut out output_terminator_ at the end of given buffer,
+ // appended by addr2line to mark the end of its meaningful output.
+ // We cannot scan buffer from it's beginning, because it is legal for it
+ // to start with output_terminator_ in case given offset is invalid. So,
+ // scanning from second character.
+ char *garbage = internal_strstr(buffer + 1, output_terminator_);
+ // This should never be NULL since buffer must end up with
+ // output_terminator_.
+ CHECK(garbage);
+ // Trim the buffer.
+ garbage[0] = '\0';
+ return true;
}
const char *module_name_; // Owned, leaked.
+ static const char output_terminator_[];
};
+const char Addr2LineProcess::output_terminator_[] = "??\n??:0\n";
+
+bool Addr2LineProcess::ReachedEndOfOutput(const char *buffer,
+ uptr length) const {
+ const size_t kTerminatorLen = sizeof(output_terminator_) - 1;
+ // Skip, if we read just kTerminatorLen bytes, because Addr2Line output
+ // should consist at least of two pairs of lines:
+ // 1. First one, corresponding to given offset to be symbolized
+ // (may be equal to output_terminator_, if offset is not valid).
+ // 2. Second one for output_terminator_, itself to mark the end of output.
+ if (length <= kTerminatorLen) return false;
+ // Addr2Line output should end up with output_terminator_.
+ return !internal_memcmp(buffer + length - kTerminatorLen,
+ output_terminator_, kTerminatorLen);
+}
+
class Addr2LinePool : public SymbolizerTool {
public:
explicit Addr2LinePool(const char *addr2line_path,
@@ -260,15 +278,18 @@ class Addr2LinePool : public SymbolizerTool {
addr2line_pool_.push_back(addr2line);
}
CHECK_EQ(0, internal_strcmp(module_name, addr2line->module_name()));
- char buffer_[kBufferSize];
- internal_snprintf(buffer_, kBufferSize, "0x%zx\n", module_offset);
- return addr2line->SendCommand(buffer_);
+ char buffer[kBufferSize];
+ internal_snprintf(buffer, kBufferSize, "0x%zx\n0x%zx\n",
+ module_offset, dummy_address_);
+ return addr2line->SendCommand(buffer);
}
- static const uptr kBufferSize = 32;
+ static const uptr kBufferSize = 64;
const char *addr2line_path_;
LowLevelAllocator *allocator_;
InternalMmapVector<Addr2LineProcess*> addr2line_pool_;
+ static const uptr dummy_address_ =
+ FIRST_32_SECOND_64(UINT32_MAX, UINT64_MAX);
};
#if SANITIZER_SUPPORTS_WEAK_HOOKS
@@ -425,8 +446,6 @@ static void ChooseSymbolizerTools(IntrusiveList<SymbolizerTool> *list,
if (SymbolizerTool *tool = ChooseExternalSymbolizer(allocator)) {
list->push_back(tool);
- } else {
- VReport(2, "No internal or external symbolizer found.\n");
}
#if SANITIZER_MAC
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_process_libcdep.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_process_libcdep.cc
deleted file mode 100644
index f1c01a332499..000000000000
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_process_libcdep.cc
+++ /dev/null
@@ -1,229 +0,0 @@
-//===-- sanitizer_symbolizer_process_libcdep.cc ---------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// Implementation of SymbolizerProcess used by external symbolizers.
-//
-//===----------------------------------------------------------------------===//
-
-#include "sanitizer_platform.h"
-#if SANITIZER_POSIX
-#include "sanitizer_posix.h"
-#include "sanitizer_symbolizer_internal.h"
-
-#include <errno.h>
-#include <stdlib.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-#if SANITIZER_MAC
-#include <util.h> // for forkpty()
-#endif // SANITIZER_MAC
-
-namespace __sanitizer {
-
-SymbolizerProcess::SymbolizerProcess(const char *path, bool use_forkpty)
- : path_(path),
- input_fd_(kInvalidFd),
- output_fd_(kInvalidFd),
- times_restarted_(0),
- failed_to_start_(false),
- reported_invalid_path_(false),
- use_forkpty_(use_forkpty) {
- CHECK(path_);
- CHECK_NE(path_[0], '\0');
-}
-
-const char *SymbolizerProcess::SendCommand(const char *command) {
- for (; times_restarted_ < kMaxTimesRestarted; times_restarted_++) {
- // Start or restart symbolizer if we failed to send command to it.
- if (const char *res = SendCommandImpl(command))
- return res;
- Restart();
- }
- if (!failed_to_start_) {
- Report("WARNING: Failed to use and restart external symbolizer!\n");
- failed_to_start_ = true;
- }
- return 0;
-}
-
-bool SymbolizerProcess::Restart() {
- if (input_fd_ != kInvalidFd)
- internal_close(input_fd_);
- if (output_fd_ != kInvalidFd)
- internal_close(output_fd_);
- return StartSymbolizerSubprocess();
-}
-
-const char *SymbolizerProcess::SendCommandImpl(const char *command) {
- if (input_fd_ == kInvalidFd || output_fd_ == kInvalidFd)
- return 0;
- if (!WriteToSymbolizer(command, internal_strlen(command)))
- return 0;
- if (!ReadFromSymbolizer(buffer_, kBufferSize))
- return 0;
- return buffer_;
-}
-
-bool SymbolizerProcess::ReadFromSymbolizer(char *buffer, uptr max_length) {
- if (max_length == 0)
- return true;
- uptr read_len = 0;
- while (true) {
- uptr just_read = internal_read(input_fd_, buffer + read_len,
- max_length - read_len - 1);
- // We can't read 0 bytes, as we don't expect external symbolizer to close
- // its stdout.
- if (just_read == 0 || just_read == (uptr)-1) {
- Report("WARNING: Can't read from symbolizer at fd %d\n", input_fd_);
- return false;
- }
- read_len += just_read;
- if (ReachedEndOfOutput(buffer, read_len))
- break;
- }
- buffer[read_len] = '\0';
- return true;
-}
-
-bool SymbolizerProcess::WriteToSymbolizer(const char *buffer, uptr length) {
- if (length == 0)
- return true;
- uptr write_len = internal_write(output_fd_, buffer, length);
- if (write_len == 0 || write_len == (uptr)-1) {
- Report("WARNING: Can't write to symbolizer at fd %d\n", output_fd_);
- return false;
- }
- return true;
-}
-
-bool SymbolizerProcess::StartSymbolizerSubprocess() {
- if (!FileExists(path_)) {
- if (!reported_invalid_path_) {
- Report("WARNING: invalid path to external symbolizer!\n");
- reported_invalid_path_ = true;
- }
- return false;
- }
-
- int pid;
- if (use_forkpty_) {
-#if SANITIZER_MAC
- fd_t fd = kInvalidFd;
- // Use forkpty to disable buffering in the new terminal.
- pid = forkpty(&fd, 0, 0, 0);
- if (pid == -1) {
- // forkpty() failed.
- Report("WARNING: failed to fork external symbolizer (errno: %d)\n",
- errno);
- return false;
- } else if (pid == 0) {
- // Child subprocess.
- ExecuteWithDefaultArgs(path_);
- internal__exit(1);
- }
-
- // Continue execution in parent process.
- input_fd_ = output_fd_ = fd;
-
- // Disable echo in the new terminal, disable CR.
- struct termios termflags;
- tcgetattr(fd, &termflags);
- termflags.c_oflag &= ~ONLCR;
- termflags.c_lflag &= ~ECHO;
- tcsetattr(fd, TCSANOW, &termflags);
-#else // SANITIZER_MAC
- UNIMPLEMENTED();
-#endif // SANITIZER_MAC
- } else {
- int *infd = NULL;
- int *outfd = NULL;
- // The client program may close its stdin and/or stdout and/or stderr
- // thus allowing socketpair to reuse file descriptors 0, 1 or 2.
- // In this case the communication between the forked processes may be
- // broken if either the parent or the child tries to close or duplicate
- // these descriptors. The loop below produces two pairs of file
- // descriptors, each greater than 2 (stderr).
- int sock_pair[5][2];
- for (int i = 0; i < 5; i++) {
- if (pipe(sock_pair[i]) == -1) {
- for (int j = 0; j < i; j++) {
- internal_close(sock_pair[j][0]);
- internal_close(sock_pair[j][1]);
- }
- Report("WARNING: Can't create a socket pair to start "
- "external symbolizer (errno: %d)\n", errno);
- return false;
- } else if (sock_pair[i][0] > 2 && sock_pair[i][1] > 2) {
- if (infd == NULL) {
- infd = sock_pair[i];
- } else {
- outfd = sock_pair[i];
- for (int j = 0; j < i; j++) {
- if (sock_pair[j] == infd) continue;
- internal_close(sock_pair[j][0]);
- internal_close(sock_pair[j][1]);
- }
- break;
- }
- }
- }
- CHECK(infd);
- CHECK(outfd);
-
- // Real fork() may call user callbacks registered with pthread_atfork().
- pid = internal_fork();
- if (pid == -1) {
- // Fork() failed.
- internal_close(infd[0]);
- internal_close(infd[1]);
- internal_close(outfd[0]);
- internal_close(outfd[1]);
- Report("WARNING: failed to fork external symbolizer "
- " (errno: %d)\n", errno);
- return false;
- } else if (pid == 0) {
- // Child subprocess.
- internal_close(STDOUT_FILENO);
- internal_close(STDIN_FILENO);
- internal_dup2(outfd[0], STDIN_FILENO);
- internal_dup2(infd[1], STDOUT_FILENO);
- internal_close(outfd[0]);
- internal_close(outfd[1]);
- internal_close(infd[0]);
- internal_close(infd[1]);
- for (int fd = sysconf(_SC_OPEN_MAX); fd > 2; fd--)
- internal_close(fd);
- ExecuteWithDefaultArgs(path_);
- internal__exit(1);
- }
-
- // Continue execution in parent process.
- internal_close(outfd[0]);
- internal_close(infd[1]);
- input_fd_ = infd[0];
- output_fd_ = outfd[1];
- }
-
- // Check that symbolizer subprocess started successfully.
- int pid_status;
- SleepForMillis(kSymbolizerStartupTimeMillis);
- int exited_pid = waitpid(pid, &pid_status, WNOHANG);
- if (exited_pid != 0) {
- // Either waitpid failed, or child has already exited.
- Report("WARNING: external symbolizer didn't start up correctly!\n");
- return false;
- }
-
- return true;
-}
-
-} // namespace __sanitizer
-
-#endif // SANITIZER_POSIX
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_win.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_win.cc
index 31f374687e96..b1dceebf45ce 100644
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_win.cc
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_win.cc
@@ -14,17 +14,26 @@
#include "sanitizer_platform.h"
#if SANITIZER_WINDOWS
+#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <dbghelp.h>
#pragma comment(lib, "dbghelp.lib")
-#include "sanitizer_symbolizer_win.h"
#include "sanitizer_symbolizer_internal.h"
namespace __sanitizer {
namespace {
+class WinSymbolizerTool : public SymbolizerTool {
+ public:
+ bool SymbolizePC(uptr addr, SymbolizedStack *stack) override;
+ bool SymbolizeData(uptr addr, DataInfo *info) override {
+ return false;
+ }
+ const char *Demangle(const char *name) override;
+};
+
bool is_dbghelp_initialized = false;
bool TrySymInitialize() {
@@ -115,7 +124,9 @@ bool WinSymbolizerTool::SymbolizePC(uptr addr, SymbolizedStack *frame) {
frame->info.file = internal_strdup(line_info.FileName);
frame->info.line = line_info.LineNumber;
}
- return true;
+ // Only consider this a successful symbolization attempt if we got file info.
+ // Otherwise, try llvm-symbolizer.
+ return got_fileline;
}
const char *WinSymbolizerTool::Demangle(const char *name) {
@@ -137,10 +148,134 @@ void Symbolizer::PlatformPrepareForSandboxing() {
// Do nothing.
}
+namespace {
+struct ScopedHandle {
+ ScopedHandle() : h_(nullptr) {}
+ explicit ScopedHandle(HANDLE h) : h_(h) {}
+ ~ScopedHandle() {
+ if (h_)
+ ::CloseHandle(h_);
+ }
+ HANDLE get() { return h_; }
+ HANDLE *receive() { return &h_; }
+ HANDLE release() {
+ HANDLE h = h_;
+ h_ = nullptr;
+ return h;
+ }
+ HANDLE h_;
+};
+} // namespace
+
+bool SymbolizerProcess::StartSymbolizerSubprocess() {
+ // Create inherited pipes for stdin and stdout.
+ ScopedHandle stdin_read, stdin_write;
+ ScopedHandle stdout_read, stdout_write;
+ SECURITY_ATTRIBUTES attrs;
+ attrs.nLength = sizeof(SECURITY_ATTRIBUTES);
+ attrs.bInheritHandle = TRUE;
+ attrs.lpSecurityDescriptor = nullptr;
+ if (!::CreatePipe(stdin_read.receive(), stdin_write.receive(), &attrs, 0) ||
+ !::CreatePipe(stdout_read.receive(), stdout_write.receive(), &attrs, 0)) {
+ VReport(2, "WARNING: %s CreatePipe failed (error code: %d)\n",
+ SanitizerToolName, path_, GetLastError());
+ return false;
+ }
+
+ // Don't inherit the writing end of stdin or the reading end of stdout.
+ if (!SetHandleInformation(stdin_write.get(), HANDLE_FLAG_INHERIT, 0) ||
+ !SetHandleInformation(stdout_read.get(), HANDLE_FLAG_INHERIT, 0)) {
+ VReport(2, "WARNING: %s SetHandleInformation failed (error code: %d)\n",
+ SanitizerToolName, path_, GetLastError());
+ return false;
+ }
+
+ // Compute the command line. Wrap double quotes around everything.
+ const char *argv[kArgVMax];
+ GetArgV(path_, argv);
+ InternalScopedString command_line(kMaxPathLength * 3);
+ for (int i = 0; argv[i]; i++) {
+ const char *arg = argv[i];
+ int arglen = internal_strlen(arg);
+ // Check that tool command lines are simple and that complete escaping is
+ // unnecessary.
+ CHECK(!internal_strchr(arg, '"') && "quotes in args unsupported");
+ CHECK(!internal_strstr(arg, "\\\\") &&
+ "double backslashes in args unsupported");
+ CHECK(arglen > 0 && arg[arglen - 1] != '\\' &&
+ "args ending in backslash and empty args unsupported");
+ command_line.append("\"%s\" ", arg);
+ }
+ VReport(3, "Launching symbolizer command: %s\n", command_line.data());
+
+ // Launch llvm-symbolizer with stdin and stdout redirected.
+ STARTUPINFOA si;
+ memset(&si, 0, sizeof(si));
+ si.cb = sizeof(si);
+ si.dwFlags |= STARTF_USESTDHANDLES;
+ si.hStdInput = stdin_read.get();
+ si.hStdOutput = stdout_write.get();
+ PROCESS_INFORMATION pi;
+ memset(&pi, 0, sizeof(pi));
+ if (!CreateProcessA(path_, // Executable
+ command_line.data(), // Command line
+ nullptr, // Process handle not inheritable
+ nullptr, // Thread handle not inheritable
+ TRUE, // Set handle inheritance to TRUE
+ 0, // Creation flags
+ nullptr, // Use parent's environment block
+ nullptr, // Use parent's starting directory
+ &si, &pi)) {
+ VReport(2, "WARNING: %s failed to create process for %s (error code: %d)\n",
+ SanitizerToolName, path_, GetLastError());
+ return false;
+ }
+
+ // Process creation succeeded, so transfer handle ownership into the fields.
+ input_fd_ = stdout_read.release();
+ output_fd_ = stdin_write.release();
+
+ // The llvm-symbolizer process is responsible for quitting itself when the
+ // stdin pipe is closed, so we don't need these handles. Close them to prevent
+ // leaks. If we ever want to try to kill the symbolizer process from the
+ // parent, we'll want to hang on to these handles.
+ CloseHandle(pi.hProcess);
+ CloseHandle(pi.hThread);
+ return true;
+}
+
+static void ChooseSymbolizerTools(IntrusiveList<SymbolizerTool> *list,
+ LowLevelAllocator *allocator) {
+ if (!common_flags()->symbolize) {
+ VReport(2, "Symbolizer is disabled.\n");
+ return;
+ }
+
+ // Add llvm-symbolizer in case the binary has dwarf.
+ const char *user_path = common_flags()->external_symbolizer_path;
+ const char *path =
+ user_path ? user_path : FindPathToBinary("llvm-symbolizer.exe");
+ if (path) {
+ VReport(2, "Using llvm-symbolizer at %spath: %s\n",
+ user_path ? "user-specified " : "", path);
+ list->push_back(new(*allocator) LLVMSymbolizer(path, allocator));
+ } else {
+ if (user_path && user_path[0] == '\0') {
+ VReport(2, "External symbolizer is explicitly disabled.\n");
+ } else {
+ VReport(2, "External symbolizer is not present.\n");
+ }
+ }
+
+ // Add the dbghelp based symbolizer.
+ list->push_back(new(*allocator) WinSymbolizerTool());
+}
+
Symbolizer *Symbolizer::PlatformInit() {
IntrusiveList<SymbolizerTool> list;
list.clear();
- list.push_back(new(symbolizer_allocator_) WinSymbolizerTool());
+ ChooseSymbolizerTools(&list, &symbolizer_allocator_);
+
return new(symbolizer_allocator_) Symbolizer(list);
}
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_win.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_win.h
deleted file mode 100644
index 72ac5e5ee104..000000000000
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_win.h
+++ /dev/null
@@ -1,31 +0,0 @@
-//===-- sanitizer_symbolizer_win.h ------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// Header file for the Windows symbolizer tool.
-//
-//===----------------------------------------------------------------------===//
-#ifndef SANITIZER_SYMBOLIZER_WIN_H
-#define SANITIZER_SYMBOLIZER_WIN_H
-
-#include "sanitizer_symbolizer_internal.h"
-
-namespace __sanitizer {
-
-class WinSymbolizerTool : public SymbolizerTool {
- public:
- bool SymbolizePC(uptr addr, SymbolizedStack *stack) override;
- bool SymbolizeData(uptr addr, DataInfo *info) override {
- return false;
- }
- const char *Demangle(const char *name) override;
-};
-
-} // namespace __sanitizer
-
-#endif // SANITIZER_SYMBOLIZER_WIN_H
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_syscall_linux_aarch64.inc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_syscall_linux_aarch64.inc
new file mode 100644
index 000000000000..7ab1d7641449
--- /dev/null
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_syscall_linux_aarch64.inc
@@ -0,0 +1,138 @@
+//===-- sanitizer_syscall_linux_aarch64.inc --------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Implementations of internal_syscall and internal_iserror for Linux/aarch64.
+//
+//===----------------------------------------------------------------------===//
+
+#define SYSCALL(name) __NR_ ## name
+
+static uptr __internal_syscall(u64 nr) {
+ register u64 x8 asm("x8") = nr;
+ register u64 x0 asm("x0");
+ asm volatile("svc 0"
+ : "=r"(x0)
+ : "r"(x8)
+ : "memory", "cc");
+ return x0;
+}
+#define __internal_syscall0(n) \
+ (__internal_syscall)(n)
+
+static uptr __internal_syscall(u64 nr, u64 arg1) {
+ register u64 x8 asm("x8") = nr;
+ register u64 x0 asm("x0") = arg1;
+ asm volatile("svc 0"
+ : "=r"(x0)
+ : "r"(x8), "0"(x0)
+ : "memory", "cc");
+ return x0;
+}
+#define __internal_syscall1(n, a1) \
+ (__internal_syscall)(n, (u64)(a1))
+
+static uptr __internal_syscall(u64 nr, u64 arg1, long arg2) {
+ register u64 x8 asm("x8") = nr;
+ register u64 x0 asm("x0") = arg1;
+ register u64 x1 asm("x1") = arg2;
+ asm volatile("svc 0"
+ : "=r"(x0)
+ : "r"(x8), "0"(x0), "r"(x1)
+ : "memory", "cc");
+ return x0;
+}
+#define __internal_syscall2(n, a1, a2) \
+ (__internal_syscall)(n, (u64)(a1), (long)(a2))
+
+static uptr __internal_syscall(u64 nr, u64 arg1, long arg2, long arg3) {
+ register u64 x8 asm("x8") = nr;
+ register u64 x0 asm("x0") = arg1;
+ register u64 x1 asm("x1") = arg2;
+ register u64 x2 asm("x2") = arg3;
+ asm volatile("svc 0"
+ : "=r"(x0)
+ : "r"(x8), "0"(x0), "r"(x1), "r"(x2)
+ : "memory", "cc");
+ return x0;
+}
+#define __internal_syscall3(n, a1, a2, a3) \
+ (__internal_syscall)(n, (u64)(a1), (long)(a2), (long)(a3))
+
+static uptr __internal_syscall(u64 nr, u64 arg1, long arg2, long arg3,
+ u64 arg4) {
+ register u64 x8 asm("x8") = nr;
+ register u64 x0 asm("x0") = arg1;
+ register u64 x1 asm("x1") = arg2;
+ register u64 x2 asm("x2") = arg3;
+ register u64 x3 asm("x3") = arg4;
+ asm volatile("svc 0"
+ : "=r"(x0)
+ : "r"(x8), "0"(x0), "r"(x1), "r"(x2), "r"(x3)
+ : "memory", "cc");
+ return x0;
+}
+#define __internal_syscall4(n, a1, a2, a3, a4) \
+ (__internal_syscall)(n, (u64)(a1), (long)(a2), (long)(a3), (long)(a4))
+
+static uptr __internal_syscall(u64 nr, u64 arg1, long arg2, long arg3,
+ u64 arg4, long arg5) {
+ register u64 x8 asm("x8") = nr;
+ register u64 x0 asm("x0") = arg1;
+ register u64 x1 asm("x1") = arg2;
+ register u64 x2 asm("x2") = arg3;
+ register u64 x3 asm("x3") = arg4;
+ register u64 x4 asm("x4") = arg5;
+ asm volatile("svc 0"
+ : "=r"(x0)
+ : "r"(x8), "0"(x0), "r"(x1), "r"(x2), "r"(x3), "r"(x4)
+ : "memory", "cc");
+ return x0;
+}
+#define __internal_syscall5(n, a1, a2, a3, a4, a5) \
+ (__internal_syscall)(n, (u64)(a1), (long)(a2), (long)(a3), (long)(a4), \
+ (u64)(a5))
+
+static uptr __internal_syscall(u64 nr, u64 arg1, long arg2, long arg3,
+ u64 arg4, long arg5, long arg6) {
+ register u64 x8 asm("x8") = nr;
+ register u64 x0 asm("x0") = arg1;
+ register u64 x1 asm("x1") = arg2;
+ register u64 x2 asm("x2") = arg3;
+ register u64 x3 asm("x3") = arg4;
+ register u64 x4 asm("x4") = arg5;
+ register u64 x5 asm("x5") = arg6;
+ asm volatile("svc 0"
+ : "=r"(x0)
+ : "r"(x8), "0"(x0), "r"(x1), "r"(x2), "r"(x3), "r"(x4), "r"(x5)
+ : "memory", "cc");
+ return x0;
+}
+#define __internal_syscall6(n, a1, a2, a3, a4, a5, a6) \
+ (__internal_syscall)(n, (u64)(a1), (long)(a2), (long)(a3), (long)(a4), \
+ (u64)(a5), (long)(a6))
+
+#define __SYSCALL_NARGS_X(a1, a2, a3, a4, a5, a6, a7, a8, n, ...) n
+#define __SYSCALL_NARGS(...) \
+ __SYSCALL_NARGS_X(__VA_ARGS__, 7, 6, 5, 4, 3, 2, 1, 0, )
+#define __SYSCALL_CONCAT_X(a, b) a##b
+#define __SYSCALL_CONCAT(a, b) __SYSCALL_CONCAT_X(a, b)
+#define __SYSCALL_DISP(b, ...) \
+ __SYSCALL_CONCAT(b, __SYSCALL_NARGS(__VA_ARGS__))(__VA_ARGS__)
+
+#define internal_syscall(...) __SYSCALL_DISP(__internal_syscall, __VA_ARGS__)
+
+// Helper function used to avoid cobbler errno.
+bool internal_iserror(uptr retval, int *rverrno) {
+ if (retval >= (uptr)-4095) {
+ if (rverrno)
+ *rverrno = -retval;
+ return true;
+ }
+ return false;
+}
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_thread_registry.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_thread_registry.h
index 5d9c3b9694e8..a27bbb376e85 100644
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_thread_registry.h
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_thread_registry.h
@@ -79,7 +79,8 @@ class ThreadRegistry {
ThreadRegistry(ThreadContextFactory factory, u32 max_threads,
u32 thread_quarantine_size, u32 max_reuse = 0);
- void GetNumberOfThreads(uptr *total = 0, uptr *running = 0, uptr *alive = 0);
+ void GetNumberOfThreads(uptr *total = nullptr, uptr *running = nullptr,
+ uptr *alive = nullptr);
uptr GetMaxAliveThreads();
void Lock() { mtx_.Lock(); }
@@ -142,7 +143,6 @@ class ThreadRegistry {
typedef GenericScopedLock<ThreadRegistry> ThreadRegistryLock;
-} // namespace __sanitizer
-
-#endif // SANITIZER_THREAD_REGISTRY_H
+} // namespace __sanitizer
+#endif // SANITIZER_THREAD_REGISTRY_H
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_tls_get_addr.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_tls_get_addr.cc
index ea037159d00b..213aced89da7 100644
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_tls_get_addr.cc
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_tls_get_addr.cc
@@ -78,6 +78,15 @@ void DTLS_Destroy() {
DTLS_Deallocate(dtls.dtv, s);
}
+#if defined(__powerpc64__)
+// This is glibc's TLS_DTV_OFFSET:
+// "Dynamic thread vector pointers point 0x8000 past the start of each
+// TLS block."
+static const uptr kDtvOffset = 0x8000;
+#else
+static const uptr kDtvOffset = 0;
+#endif
+
DTLS::DTV *DTLS_on_tls_get_addr(void *arg_void, void *res,
uptr static_tls_begin, uptr static_tls_end) {
if (!common_flags()->intercept_tls_get_addr) return 0;
@@ -87,7 +96,7 @@ DTLS::DTV *DTLS_on_tls_get_addr(void *arg_void, void *res,
DTLS_Resize(dso_id + 1);
if (dtls.dtv[dso_id].beg) return 0;
uptr tls_size = 0;
- uptr tls_beg = reinterpret_cast<uptr>(res) - arg->offset;
+ uptr tls_beg = reinterpret_cast<uptr>(res) - arg->offset - kDtvOffset;
VPrintf(2, "__tls_get_addr: %p {%p,%p} => %p; tls_beg: %p; sp: %p "
"num_live_dtls %zd\n",
arg, arg->dso_id, arg->offset, res, tls_beg, &tls_beg,
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_win.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_win.cc
index d5bbe4565068..861261d8402c 100644
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_win.cc
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_win.cc
@@ -51,7 +51,7 @@ uptr GetMaxVirtualAddress() {
}
bool FileExists(const char *filename) {
- UNIMPLEMENTED();
+ return ::GetFileAttributesA(filename) != INVALID_FILE_ATTRIBUTES;
}
uptr internal_getpid() {
@@ -83,14 +83,11 @@ void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
}
#endif // #if !SANITIZER_GO
-void *MmapOrDie(uptr size, const char *mem_type) {
+void *MmapOrDie(uptr size, const char *mem_type, bool raw_report) {
void *rv = VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
- if (rv == 0) {
- Report("ERROR: %s failed to "
- "allocate 0x%zx (%zd) bytes of %s (error code: %d)\n",
- SanitizerToolName, size, size, mem_type, GetLastError());
- CHECK("unable to mmap" && 0);
- }
+ if (rv == 0)
+ ReportMmapFailureAndDie(size, mem_type, "allocate",
+ GetLastError(), raw_report);
return rv;
}
@@ -224,12 +221,14 @@ struct ModuleInfo {
uptr end_address;
};
+#ifndef SANITIZER_GO
int CompareModulesBase(const void *pl, const void *pr) {
const ModuleInfo *l = (ModuleInfo *)pl, *r = (ModuleInfo *)pr;
if (l->base_address < r->base_address)
return -1;
return l->base_address > r->base_address;
}
+#endif
} // namespace
#ifndef SANITIZER_GO
@@ -292,11 +291,6 @@ void SetAddressSpaceUnlimited() {
UNIMPLEMENTED();
}
-char *FindPathToBinary(const char *name) {
- // Nothing here for now.
- return 0;
-}
-
bool IsPathSeparator(const char c) {
return c == '\\' || c == '/';
}
@@ -323,6 +317,59 @@ void Abort() {
internal__exit(3);
}
+// Read the file to extract the ImageBase field from the PE header. If ASLR is
+// disabled and this virtual address is available, the loader will typically
+// load the image at this address. Therefore, we call it the preferred base. Any
+// addresses in the DWARF typically assume that the object has been loaded at
+// this address.
+static uptr GetPreferredBase(const char *modname) {
+ fd_t fd = OpenFile(modname, RdOnly, nullptr);
+ if (fd == kInvalidFd)
+ return 0;
+ FileCloser closer(fd);
+
+ // Read just the DOS header.
+ IMAGE_DOS_HEADER dos_header;
+ uptr bytes_read;
+ if (!ReadFromFile(fd, &dos_header, sizeof(dos_header), &bytes_read) ||
+ bytes_read != sizeof(dos_header))
+ return 0;
+
+ // The file should start with the right signature.
+ if (dos_header.e_magic != IMAGE_DOS_SIGNATURE)
+ return 0;
+
+ // The layout at e_lfanew is:
+ // "PE\0\0"
+ // IMAGE_FILE_HEADER
+ // IMAGE_OPTIONAL_HEADER
+ // Seek to e_lfanew and read all that data.
+ char buf[4 + sizeof(IMAGE_FILE_HEADER) + sizeof(IMAGE_OPTIONAL_HEADER)];
+ if (::SetFilePointer(fd, dos_header.e_lfanew, nullptr, FILE_BEGIN) ==
+ INVALID_SET_FILE_POINTER)
+ return 0;
+ if (!ReadFromFile(fd, &buf[0], sizeof(buf), &bytes_read) ||
+ bytes_read != sizeof(buf))
+ return 0;
+
+ // Check for "PE\0\0" before the PE header.
+ char *pe_sig = &buf[0];
+ if (internal_memcmp(pe_sig, "PE\0\0", 4) != 0)
+ return 0;
+
+ // Skip over IMAGE_FILE_HEADER. We could do more validation here if we wanted.
+ IMAGE_OPTIONAL_HEADER *pe_header =
+ (IMAGE_OPTIONAL_HEADER *)(pe_sig + 4 + sizeof(IMAGE_FILE_HEADER));
+
+ // Check for more magic in the PE header.
+ if (pe_header->Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC)
+ return 0;
+
+ // Finally, return the ImageBase.
+ return (uptr)pe_header->ImageBase;
+}
+
+#ifndef SANITIZER_GO
uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
string_predicate_t filter) {
HANDLE cur_process = GetCurrentProcess();
@@ -355,19 +402,33 @@ uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
if (!GetModuleInformation(cur_process, handle, &mi, sizeof(mi)))
continue;
- char module_name[MAX_PATH];
- bool got_module_name =
- GetModuleFileNameA(handle, module_name, sizeof(module_name));
- if (!got_module_name)
- module_name[0] = '\0';
+ // Get the UTF-16 path and convert to UTF-8.
+ wchar_t modname_utf16[kMaxPathLength];
+ int modname_utf16_len =
+ GetModuleFileNameW(handle, modname_utf16, kMaxPathLength);
+ if (modname_utf16_len == 0)
+ modname_utf16[0] = '\0';
+ char module_name[kMaxPathLength];
+ int module_name_len =
+ ::WideCharToMultiByte(CP_UTF8, 0, modname_utf16, modname_utf16_len + 1,
+ &module_name[0], kMaxPathLength, NULL, NULL);
+ module_name[module_name_len] = '\0';
if (filter && !filter(module_name))
continue;
uptr base_address = (uptr)mi.lpBaseOfDll;
uptr end_address = (uptr)mi.lpBaseOfDll + mi.SizeOfImage;
+
+ // Adjust the base address of the module so that we get a VA instead of an
+ // RVA when computing the module offset. This helps llvm-symbolizer find the
+ // right DWARF CU. In the common case that the image is loaded at it's
+ // preferred address, we will now print normal virtual addresses.
+ uptr preferred_base = GetPreferredBase(&module_name[0]);
+ uptr adjusted_base = base_address - preferred_base;
+
LoadedModule *cur_module = &modules[count];
- cur_module->set(module_name, base_address);
+ cur_module->set(module_name, adjusted_base);
// We add the whole module as one single address range.
cur_module->addAddressRange(base_address, end_address, /*executable*/ true);
count++;
@@ -377,7 +438,6 @@ uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
return count;
};
-#ifndef SANITIZER_GO
// We can't use atexit() directly at __asan_init time as the CRT is not fully
// initialized at this point. Place the functions into a vector and use
// atexit() as soon as it is ready for use (i.e. after .CRT$XIC initializers).
@@ -397,15 +457,22 @@ static int RunAtexit() {
}
#pragma section(".CRT$XID", long, read) // NOLINT
-static __declspec(allocate(".CRT$XID")) int (*__run_atexit)() = RunAtexit;
+__declspec(allocate(".CRT$XID")) int (*__run_atexit)() = RunAtexit;
#endif
// ------------------ sanitizer_libc.h
fd_t OpenFile(const char *filename, FileAccessMode mode, error_t *last_error) {
- if (mode != WrOnly)
+ fd_t res;
+ if (mode == RdOnly) {
+ res = CreateFile(filename, GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
+ } else if (mode == WrOnly) {
+ res = CreateFile(filename, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL, nullptr);
+ } else {
UNIMPLEMENTED();
- fd_t res = CreateFile(filename, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS,
- FILE_ATTRIBUTE_NORMAL, nullptr);
+ }
CHECK(res != kStdoutFd || kStdoutFd == kInvalidFd);
CHECK(res != kStderrFd || kStderrFd == kInvalidFd);
if (res == kInvalidFd && last_error)
@@ -419,7 +486,18 @@ void CloseFile(fd_t fd) {
bool ReadFromFile(fd_t fd, void *buff, uptr buff_size, uptr *bytes_read,
error_t *error_p) {
- UNIMPLEMENTED();
+ CHECK(fd != kInvalidFd);
+
+ // bytes_read can't be passed directly to ReadFile:
+ // uptr is unsigned long long on 64-bit Windows.
+ unsigned long num_read_long;
+
+ bool success = ::ReadFile(fd, buff, buff_size, &num_read_long, nullptr);
+ if (!success && error_p)
+ *error_p = GetLastError();
+ if (bytes_read)
+ *bytes_read = num_read_long;
+ return success;
}
bool SupportsColoredOutput(fd_t fd) {
@@ -431,21 +509,32 @@ bool WriteToFile(fd_t fd, const void *buff, uptr buff_size, uptr *bytes_written,
error_t *error_p) {
CHECK(fd != kInvalidFd);
- if (fd == kStdoutFd) {
- fd = GetStdHandle(STD_OUTPUT_HANDLE);
- if (fd == 0) fd = kInvalidFd;
- } else if (fd == kStderrFd) {
- fd = GetStdHandle(STD_ERROR_HANDLE);
- if (fd == 0) fd = kInvalidFd;
+ // Handle null optional parameters.
+ error_t dummy_error;
+ error_p = error_p ? error_p : &dummy_error;
+ uptr dummy_bytes_written;
+ bytes_written = bytes_written ? bytes_written : &dummy_bytes_written;
+
+ // Initialize output parameters in case we fail.
+ *error_p = 0;
+ *bytes_written = 0;
+
+ // Map the conventional Unix fds 1 and 2 to Windows handles. They might be
+ // closed, in which case this will fail.
+ if (fd == kStdoutFd || fd == kStderrFd) {
+ fd = GetStdHandle(fd == kStdoutFd ? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE);
+ if (fd == 0) {
+ *error_p = ERROR_INVALID_HANDLE;
+ return false;
+ }
}
- DWORD internal_bytes_written;
- if (fd == kInvalidFd ||
- WriteFile(fd, buff, buff_size, &internal_bytes_written, 0)) {
- if (error_p) *error_p = GetLastError();
+ DWORD bytes_written_32;
+ if (!WriteFile(fd, buff, buff_size, &bytes_written_32, 0)) {
+ *error_p = GetLastError();
return false;
} else {
- if (bytes_written) *bytes_written = internal_bytes_written;
+ *bytes_written = bytes_written_32;
return true;
}
}
@@ -665,6 +754,22 @@ uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) {
return 0;
}
+uptr ReadLongProcessName(/*out*/char *buf, uptr buf_len) {
+ return ReadBinaryName(buf, buf_len);
+}
+
+void CheckVMASize() {
+ // Do nothing.
+}
+
+void DisableReexec() {
+ // No need to re-exec on Windows.
+}
+
+void MaybeReexec() {
+ // No need to re-exec on Windows.
+}
+
} // namespace __sanitizer
#endif // _WIN32
diff --git a/contrib/compiler-rt/lib/sanitizer_common/scripts/check_lint.sh b/contrib/compiler-rt/lib/sanitizer_common/scripts/check_lint.sh
deleted file mode 100755
index 9108a81e26c8..000000000000
--- a/contrib/compiler-rt/lib/sanitizer_common/scripts/check_lint.sh
+++ /dev/null
@@ -1,136 +0,0 @@
-#!/bin/sh
-
-SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
-
-# Guess path to LLVM_CHECKOUT if not provided
-if [ "${LLVM_CHECKOUT}" = "" ]; then
- LLVM_CHECKOUT="${SCRIPT_DIR}/../../../../../"
-fi
-
-# python tools setup
-CPPLINT=${SCRIPT_DIR}/cpplint.py
-LITLINT=${SCRIPT_DIR}/litlint.py
-if [ "${PYTHON_EXECUTABLE}" != "" ]; then
- CPPLINT="${PYTHON_EXECUTABLE} ${CPPLINT}"
- LITLINT="${PYTHON_EXECUTABLE} ${LITLINT}"
-fi
-
-# Filters
-# TODO: remove some of these filters
-COMMON_LINT_FILTER=-build/include,-build/header_guard,-legal/copyright,-whitespace/comments,-readability/casting,\
--build/namespaces
-ASAN_RTL_LINT_FILTER=${COMMON_LINT_FILTER},-runtime/int
-ASAN_TEST_LINT_FILTER=${COMMON_LINT_FILTER},-runtime/sizeof,-runtime/int,-runtime/printf,-runtime/threadsafe_fn
-ASAN_LIT_TEST_LINT_FILTER=${ASAN_TEST_LINT_FILTER},-whitespace/line_length
-TSAN_RTL_LINT_FILTER=${COMMON_LINT_FILTER}
-TSAN_TEST_LINT_FILTER=${TSAN_RTL_LINT_FILTER},-runtime/threadsafe_fn,-runtime/int
-TSAN_LIT_TEST_LINT_FILTER=${TSAN_TEST_LINT_FILTER},-whitespace/line_length
-MSAN_RTL_LINT_FILTER=${COMMON_LINT_FILTER}
-LSAN_RTL_LINT_FILTER=${COMMON_LINT_FILTER}
-LSAN_LIT_TEST_LINT_FILTER=${LSAN_RTL_LINT_FILTER},-whitespace/line_length
-DFSAN_RTL_LINT_FILTER=${COMMON_LINT_FILTER},-runtime/int,-runtime/printf,-runtime/references,-readability/function
-COMMON_RTL_INC_LINT_FILTER=${COMMON_LINT_FILTER},-runtime/int,-runtime/sizeof,-runtime/printf,-readability/fn_size
-SANITIZER_INCLUDES_LINT_FILTER=${COMMON_LINT_FILTER},-runtime/int
-
-MKTEMP_DIR=$(mktemp -qd /tmp/check_lint.XXXXXXXXXX)
-MKTEMP="mktemp -q ${MKTEMP_DIR}/tmp.XXXXXXXXXX"
-cleanup() {
- rm -rf $MKTEMP_DIR
-}
-trap cleanup EXIT
-
-cd ${LLVM_CHECKOUT}
-
-EXITSTATUS=0
-ERROR_LOG=$(${MKTEMP})
-
-run_lint() {
- FILTER=$1
- shift
- TASK_LOG=$(${MKTEMP})
- ${CPPLINT} --filter=${FILTER} "$@" 2>$TASK_LOG
- if [ "$?" != "0" ]; then
- cat $TASK_LOG | grep -v "Done processing" | grep -v "Total errors found" \
- | grep -v "Skipping input" >> $ERROR_LOG
- fi
- if [ "${SILENT}" != "1" ]; then
- cat $TASK_LOG
- fi
- ${LITLINT} "$@" 2>>$ERROR_LOG
-}
-
-if [ "${COMPILER_RT}" = "" ]; then
- COMPILER_RT=projects/compiler-rt
-fi
-LIT_TESTS=${COMPILER_RT}/test
-# Headers
-SANITIZER_INCLUDES=${COMPILER_RT}/include/sanitizer
-run_lint ${SANITIZER_INCLUDES_LINT_FILTER} ${SANITIZER_INCLUDES}/*.h &
-
-# Sanitizer_common
-COMMON_RTL=${COMPILER_RT}/lib/sanitizer_common
-run_lint ${COMMON_RTL_INC_LINT_FILTER} ${COMMON_RTL}/*.cc \
- ${COMMON_RTL}/*.h \
- ${COMMON_RTL}/tests/*.cc &
-
-# Interception
-INTERCEPTION=${COMPILER_RT}/lib/interception
-run_lint ${ASAN_RTL_LINT_FILTER} ${INTERCEPTION}/*.cc \
- ${INTERCEPTION}/*.h &
-
-# ASan
-ASAN_RTL=${COMPILER_RT}/lib/asan
-run_lint ${ASAN_RTL_LINT_FILTER} ${ASAN_RTL}/*.cc \
- ${ASAN_RTL}/*.h &
-run_lint ${ASAN_TEST_LINT_FILTER} ${ASAN_RTL}/tests/*.cc \
- ${ASAN_RTL}/tests/*.h &
-run_lint ${ASAN_LIT_TEST_LINT_FILTER} ${LIT_TESTS}/asan/*/*.cc &
-
-# TSan
-TSAN_RTL=${COMPILER_RT}/lib/tsan
-run_lint ${TSAN_RTL_LINT_FILTER} ${TSAN_RTL}/rtl/*.cc \
- ${TSAN_RTL}/rtl/*.h &
-run_lint ${TSAN_TEST_LINT_FILTER} ${TSAN_RTL}/tests/rtl/*.cc \
- ${TSAN_RTL}/tests/rtl/*.h \
- ${TSAN_RTL}/tests/unit/*.cc &
-run_lint ${TSAN_LIT_TEST_LINT_FILTER} ${LIT_TESTS}/tsan/*.cc &
-
-# MSan
-MSAN_RTL=${COMPILER_RT}/lib/msan
-run_lint ${MSAN_RTL_LINT_FILTER} ${MSAN_RTL}/*.cc \
- ${MSAN_RTL}/*.h &
-
-# LSan
-LSAN_RTL=${COMPILER_RT}/lib/lsan
-run_lint ${LSAN_RTL_LINT_FILTER} ${LSAN_RTL}/*.cc \
- ${LSAN_RTL}/*.h &
-run_lint ${LSAN_LIT_TEST_LINT_FILTER} ${LIT_TESTS}/lsan/*/*.cc &
-
-# DFSan
-DFSAN_RTL=${COMPILER_RT}/lib/dfsan
-run_lint ${DFSAN_RTL_LINT_FILTER} ${DFSAN_RTL}/*.cc \
- ${DFSAN_RTL}/*.h &
-${DFSAN_RTL}/scripts/check_custom_wrappers.sh >> $ERROR_LOG
-
-# Misc files
-FILES=${COMMON_RTL}/*.inc
-TMPFILES=""
-for FILE in $FILES; do
- TMPFILE="$(${MKTEMP}).$(basename ${FILE}).cc"
- cp -f $FILE $TMPFILE
- run_lint ${COMMON_RTL_INC_LINT_FILTER} $TMPFILE &
- TMPFILES="$TMPFILES $TMPFILE"
-done
-
-wait
-
-for temp in $TMPFILES; do
- rm -f $temp
-done
-
-if [ -s $ERROR_LOG ]; then
- cat $ERROR_LOG
- exit 1
-fi
-
-exit 0
diff --git a/contrib/compiler-rt/lib/sanitizer_common/scripts/cpplint.py b/contrib/compiler-rt/lib/sanitizer_common/scripts/cpplint.py
deleted file mode 100755
index d45c47f7ed0c..000000000000
--- a/contrib/compiler-rt/lib/sanitizer_common/scripts/cpplint.py
+++ /dev/null
@@ -1,4024 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright (c) 2009 Google Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-# Here are some issues that I've had people identify in my code during reviews,
-# that I think are possible to flag automatically in a lint tool. If these were
-# caught by lint, it would save time both for myself and that of my reviewers.
-# Most likely, some of these are beyond the scope of the current lint framework,
-# but I think it is valuable to retain these wish-list items even if they cannot
-# be immediately implemented.
-#
-# Suggestions
-# -----------
-# - Check for no 'explicit' for multi-arg ctor
-# - Check for boolean assign RHS in parens
-# - Check for ctor initializer-list colon position and spacing
-# - Check that if there's a ctor, there should be a dtor
-# - Check accessors that return non-pointer member variables are
-# declared const
-# - Check accessors that return non-const pointer member vars are
-# *not* declared const
-# - Check for using public includes for testing
-# - Check for spaces between brackets in one-line inline method
-# - Check for no assert()
-# - Check for spaces surrounding operators
-# - Check for 0 in pointer context (should be NULL)
-# - Check for 0 in char context (should be '\0')
-# - Check for camel-case method name conventions for methods
-# that are not simple inline getters and setters
-# - Do not indent namespace contents
-# - Avoid inlining non-trivial constructors in header files
-# - Check for old-school (void) cast for call-sites of functions
-# ignored return value
-# - Check gUnit usage of anonymous namespace
-# - Check for class declaration order (typedefs, consts, enums,
-# ctor(s?), dtor, friend declarations, methods, member vars)
-#
-
-"""Does google-lint on c++ files.
-
-The goal of this script is to identify places in the code that *may*
-be in non-compliance with google style. It does not attempt to fix
-up these problems -- the point is to educate. It does also not
-attempt to find all problems, or to ensure that everything it does
-find is legitimately a problem.
-
-In particular, we can get very confused by /* and // inside strings!
-We do a small hack, which is to ignore //'s with "'s after them on the
-same line, but it is far from perfect (in either direction).
-"""
-
-import codecs
-import copy
-import getopt
-import math # for log
-import os
-import re
-import sre_compile
-import string
-import sys
-import unicodedata
-
-
-_USAGE = """
-Syntax: cpplint.py [--verbose=#] [--output=vs7] [--filter=-x,+y,...]
- [--counting=total|toplevel|detailed]
- <file> [file] ...
-
- The style guidelines this tries to follow are those in
- http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml
-
- Every problem is given a confidence score from 1-5, with 5 meaning we are
- certain of the problem, and 1 meaning it could be a legitimate construct.
- This will miss some errors, and is not a substitute for a code review.
-
- To suppress false-positive errors of a certain category, add a
- 'NOLINT(category)' comment to the line. NOLINT or NOLINT(*)
- suppresses errors of all categories on that line.
-
- The files passed in will be linted; at least one file must be provided.
- Linted extensions are .cc, .cpp, and .h. Other file types will be ignored.
-
- Flags:
-
- output=vs7
- By default, the output is formatted to ease emacs parsing. Visual Studio
- compatible output (vs7) may also be used. Other formats are unsupported.
-
- verbose=#
- Specify a number 0-5 to restrict errors to certain verbosity levels.
-
- filter=-x,+y,...
- Specify a comma-separated list of category-filters to apply: only
- error messages whose category names pass the filters will be printed.
- (Category names are printed with the message and look like
- "[whitespace/indent]".) Filters are evaluated left to right.
- "-FOO" and "FOO" means "do not print categories that start with FOO".
- "+FOO" means "do print categories that start with FOO".
-
- Examples: --filter=-whitespace,+whitespace/braces
- --filter=whitespace,runtime/printf,+runtime/printf_format
- --filter=-,+build/include_what_you_use
-
- To see a list of all the categories used in cpplint, pass no arg:
- --filter=
-
- counting=total|toplevel|detailed
- The total number of errors found is always printed. If
- 'toplevel' is provided, then the count of errors in each of
- the top-level categories like 'build' and 'whitespace' will
- also be printed. If 'detailed' is provided, then a count
- is provided for each category like 'build/class'.
-
- root=subdir
- The root directory used for deriving header guard CPP variable.
- By default, the header guard CPP variable is calculated as the relative
- path to the directory that contains .git, .hg, or .svn. When this flag
- is specified, the relative path is calculated from the specified
- directory. If the specified directory does not exist, this flag is
- ignored.
-
- Examples:
- Assuing that src/.git exists, the header guard CPP variables for
- src/chrome/browser/ui/browser.h are:
-
- No flag => CHROME_BROWSER_UI_BROWSER_H_
- --root=chrome => BROWSER_UI_BROWSER_H_
- --root=chrome/browser => UI_BROWSER_H_
-"""
-
-# We categorize each error message we print. Here are the categories.
-# We want an explicit list so we can list them all in cpplint --filter=.
-# If you add a new error message with a new category, add it to the list
-# here! cpplint_unittest.py should tell you if you forget to do this.
-# \ used for clearer layout -- pylint: disable-msg=C6013
-_ERROR_CATEGORIES = [
- 'build/class',
- 'build/deprecated',
- 'build/endif_comment',
- 'build/explicit_make_pair',
- 'build/forward_decl',
- 'build/header_guard',
- 'build/include',
- 'build/include_alpha',
- 'build/include_order',
- 'build/include_what_you_use',
- 'build/namespaces',
- 'build/printf_format',
- 'build/storage_class',
- 'legal/copyright',
- 'readability/alt_tokens',
- 'readability/braces',
- 'readability/casting',
- 'readability/check',
- 'readability/constructors',
- 'readability/fn_size',
- 'readability/function',
- 'readability/multiline_comment',
- 'readability/multiline_string',
- 'readability/namespace',
- 'readability/nolint',
- 'readability/streams',
- 'readability/todo',
- 'readability/utf8',
- 'runtime/arrays',
- 'runtime/casting',
- 'runtime/explicit',
- 'runtime/int',
- 'runtime/init',
- 'runtime/invalid_increment',
- 'runtime/member_string_references',
- 'runtime/memset',
- 'runtime/operator',
- 'runtime/printf',
- 'runtime/printf_format',
- 'runtime/references',
- 'runtime/rtti',
- 'runtime/sizeof',
- 'runtime/string',
- 'runtime/threadsafe_fn',
- 'whitespace/blank_line',
- 'whitespace/braces',
- 'whitespace/comma',
- 'whitespace/comments',
- 'whitespace/empty_loop_body',
- 'whitespace/end_of_line',
- 'whitespace/ending_newline',
- 'whitespace/forcolon',
- 'whitespace/indent',
- 'whitespace/labels',
- 'whitespace/line_length',
- 'whitespace/newline',
- 'whitespace/operators',
- 'whitespace/parens',
- 'whitespace/semicolon',
- 'whitespace/tab',
- 'whitespace/todo'
- ]
-
-# The default state of the category filter. This is overrided by the --filter=
-# flag. By default all errors are on, so only add here categories that should be
-# off by default (i.e., categories that must be enabled by the --filter= flags).
-# All entries here should start with a '-' or '+', as in the --filter= flag.
-_DEFAULT_FILTERS = ['-build/include_alpha']
-
-# We used to check for high-bit characters, but after much discussion we
-# decided those were OK, as long as they were in UTF-8 and didn't represent
-# hard-coded international strings, which belong in a separate i18n file.
-
-# Headers that we consider STL headers.
-_STL_HEADERS = frozenset([
- 'algobase.h', 'algorithm', 'alloc.h', 'bitset', 'deque', 'exception',
- 'function.h', 'functional', 'hash_map', 'hash_map.h', 'hash_set',
- 'hash_set.h', 'iterator', 'list', 'list.h', 'map', 'memory', 'new',
- 'pair.h', 'pthread_alloc', 'queue', 'set', 'set.h', 'sstream', 'stack',
- 'stl_alloc.h', 'stl_relops.h', 'type_traits.h',
- 'utility', 'vector', 'vector.h',
- ])
-
-
-# Non-STL C++ system headers.
-_CPP_HEADERS = frozenset([
- 'algo.h', 'builtinbuf.h', 'bvector.h', 'cassert', 'cctype',
- 'cerrno', 'cfloat', 'ciso646', 'climits', 'clocale', 'cmath',
- 'complex', 'complex.h', 'csetjmp', 'csignal', 'cstdarg', 'cstddef',
- 'cstdio', 'cstdlib', 'cstring', 'ctime', 'cwchar', 'cwctype',
- 'defalloc.h', 'deque.h', 'editbuf.h', 'exception', 'fstream',
- 'fstream.h', 'hashtable.h', 'heap.h', 'indstream.h', 'iomanip',
- 'iomanip.h', 'ios', 'iosfwd', 'iostream', 'iostream.h', 'istream',
- 'istream.h', 'iterator.h', 'limits', 'map.h', 'multimap.h', 'multiset.h',
- 'numeric', 'ostream', 'ostream.h', 'parsestream.h', 'pfstream.h',
- 'PlotFile.h', 'procbuf.h', 'pthread_alloc.h', 'rope', 'rope.h',
- 'ropeimpl.h', 'SFile.h', 'slist', 'slist.h', 'stack.h', 'stdexcept',
- 'stdiostream.h', 'streambuf', 'streambuf.h', 'stream.h', 'strfile.h',
- 'string', 'strstream', 'strstream.h', 'tempbuf.h', 'tree.h', 'typeinfo',
- 'valarray',
- ])
-
-
-# Assertion macros. These are defined in base/logging.h and
-# testing/base/gunit.h. Note that the _M versions need to come first
-# for substring matching to work.
-_CHECK_MACROS = [
- 'DCHECK', 'CHECK',
- 'EXPECT_TRUE_M', 'EXPECT_TRUE',
- 'ASSERT_TRUE_M', 'ASSERT_TRUE',
- 'EXPECT_FALSE_M', 'EXPECT_FALSE',
- 'ASSERT_FALSE_M', 'ASSERT_FALSE',
- ]
-
-# Replacement macros for CHECK/DCHECK/EXPECT_TRUE/EXPECT_FALSE
-_CHECK_REPLACEMENT = dict([(m, {}) for m in _CHECK_MACROS])
-
-for op, replacement in [('==', 'EQ'), ('!=', 'NE'),
- ('>=', 'GE'), ('>', 'GT'),
- ('<=', 'LE'), ('<', 'LT')]:
- _CHECK_REPLACEMENT['DCHECK'][op] = 'DCHECK_%s' % replacement
- _CHECK_REPLACEMENT['CHECK'][op] = 'CHECK_%s' % replacement
- _CHECK_REPLACEMENT['EXPECT_TRUE'][op] = 'EXPECT_%s' % replacement
- _CHECK_REPLACEMENT['ASSERT_TRUE'][op] = 'ASSERT_%s' % replacement
- _CHECK_REPLACEMENT['EXPECT_TRUE_M'][op] = 'EXPECT_%s_M' % replacement
- _CHECK_REPLACEMENT['ASSERT_TRUE_M'][op] = 'ASSERT_%s_M' % replacement
-
-for op, inv_replacement in [('==', 'NE'), ('!=', 'EQ'),
- ('>=', 'LT'), ('>', 'LE'),
- ('<=', 'GT'), ('<', 'GE')]:
- _CHECK_REPLACEMENT['EXPECT_FALSE'][op] = 'EXPECT_%s' % inv_replacement
- _CHECK_REPLACEMENT['ASSERT_FALSE'][op] = 'ASSERT_%s' % inv_replacement
- _CHECK_REPLACEMENT['EXPECT_FALSE_M'][op] = 'EXPECT_%s_M' % inv_replacement
- _CHECK_REPLACEMENT['ASSERT_FALSE_M'][op] = 'ASSERT_%s_M' % inv_replacement
-
-# Alternative tokens and their replacements. For full list, see section 2.5
-# Alternative tokens [lex.digraph] in the C++ standard.
-#
-# Digraphs (such as '%:') are not included here since it's a mess to
-# match those on a word boundary.
-_ALT_TOKEN_REPLACEMENT = {
- 'and': '&&',
- 'bitor': '|',
- 'or': '||',
- 'xor': '^',
- 'compl': '~',
- 'bitand': '&',
- 'and_eq': '&=',
- 'or_eq': '|=',
- 'xor_eq': '^=',
- 'not': '!',
- 'not_eq': '!='
- }
-
-# Compile regular expression that matches all the above keywords. The "[ =()]"
-# bit is meant to avoid matching these keywords outside of boolean expressions.
-#
-# False positives include C-style multi-line comments (http://go/nsiut )
-# and multi-line strings (http://go/beujw ), but those have always been
-# troublesome for cpplint.
-_ALT_TOKEN_REPLACEMENT_PATTERN = re.compile(
- r'[ =()](' + ('|'.join(_ALT_TOKEN_REPLACEMENT.keys())) + r')(?=[ (]|$)')
-
-
-# These constants define types of headers for use with
-# _IncludeState.CheckNextIncludeOrder().
-_C_SYS_HEADER = 1
-_CPP_SYS_HEADER = 2
-_LIKELY_MY_HEADER = 3
-_POSSIBLE_MY_HEADER = 4
-_OTHER_HEADER = 5
-
-# These constants define the current inline assembly state
-_NO_ASM = 0 # Outside of inline assembly block
-_INSIDE_ASM = 1 # Inside inline assembly block
-_END_ASM = 2 # Last line of inline assembly block
-_BLOCK_ASM = 3 # The whole block is an inline assembly block
-
-# Match start of assembly blocks
-_MATCH_ASM = re.compile(r'^\s*(?:asm|_asm|__asm|__asm__)'
- r'(?:\s+(volatile|__volatile__))?'
- r'\s*[{(]')
-
-
-_regexp_compile_cache = {}
-
-# Finds occurrences of NOLINT or NOLINT(...).
-_RE_SUPPRESSION = re.compile(r'\bNOLINT\b(\([^)]*\))?')
-
-# {str, set(int)}: a map from error categories to sets of linenumbers
-# on which those errors are expected and should be suppressed.
-_error_suppressions = {}
-
-# The root directory used for deriving header guard CPP variable.
-# This is set by --root flag.
-_root = None
-
-def ParseNolintSuppressions(filename, raw_line, linenum, error):
- """Updates the global list of error-suppressions.
-
- Parses any NOLINT comments on the current line, updating the global
- error_suppressions store. Reports an error if the NOLINT comment
- was malformed.
-
- Args:
- filename: str, the name of the input file.
- raw_line: str, the line of input text, with comments.
- linenum: int, the number of the current line.
- error: function, an error handler.
- """
- # FIXME(adonovan): "NOLINT(" is misparsed as NOLINT(*).
- matched = _RE_SUPPRESSION.search(raw_line)
- if matched:
- category = matched.group(1)
- if category in (None, '(*)'): # => "suppress all"
- _error_suppressions.setdefault(None, set()).add(linenum)
- else:
- if category.startswith('(') and category.endswith(')'):
- category = category[1:-1]
- if category in _ERROR_CATEGORIES:
- _error_suppressions.setdefault(category, set()).add(linenum)
- else:
- error(filename, linenum, 'readability/nolint', 5,
- 'Unknown NOLINT error category: %s' % category)
-
-
-def ResetNolintSuppressions():
- "Resets the set of NOLINT suppressions to empty."
- _error_suppressions.clear()
-
-
-def IsErrorSuppressedByNolint(category, linenum):
- """Returns true if the specified error category is suppressed on this line.
-
- Consults the global error_suppressions map populated by
- ParseNolintSuppressions/ResetNolintSuppressions.
-
- Args:
- category: str, the category of the error.
- linenum: int, the current line number.
- Returns:
- bool, True iff the error should be suppressed due to a NOLINT comment.
- """
- return (linenum in _error_suppressions.get(category, set()) or
- linenum in _error_suppressions.get(None, set()))
-
-def Match(pattern, s):
- """Matches the string with the pattern, caching the compiled regexp."""
- # The regexp compilation caching is inlined in both Match and Search for
- # performance reasons; factoring it out into a separate function turns out
- # to be noticeably expensive.
- if not pattern in _regexp_compile_cache:
- _regexp_compile_cache[pattern] = sre_compile.compile(pattern)
- return _regexp_compile_cache[pattern].match(s)
-
-
-def Search(pattern, s):
- """Searches the string for the pattern, caching the compiled regexp."""
- if not pattern in _regexp_compile_cache:
- _regexp_compile_cache[pattern] = sre_compile.compile(pattern)
- return _regexp_compile_cache[pattern].search(s)
-
-
-class _IncludeState(dict):
- """Tracks line numbers for includes, and the order in which includes appear.
-
- As a dict, an _IncludeState object serves as a mapping between include
- filename and line number on which that file was included.
-
- Call CheckNextIncludeOrder() once for each header in the file, passing
- in the type constants defined above. Calls in an illegal order will
- raise an _IncludeError with an appropriate error message.
-
- """
- # self._section will move monotonically through this set. If it ever
- # needs to move backwards, CheckNextIncludeOrder will raise an error.
- _INITIAL_SECTION = 0
- _MY_H_SECTION = 1
- _C_SECTION = 2
- _CPP_SECTION = 3
- _OTHER_H_SECTION = 4
-
- _TYPE_NAMES = {
- _C_SYS_HEADER: 'C system header',
- _CPP_SYS_HEADER: 'C++ system header',
- _LIKELY_MY_HEADER: 'header this file implements',
- _POSSIBLE_MY_HEADER: 'header this file may implement',
- _OTHER_HEADER: 'other header',
- }
- _SECTION_NAMES = {
- _INITIAL_SECTION: "... nothing. (This can't be an error.)",
- _MY_H_SECTION: 'a header this file implements',
- _C_SECTION: 'C system header',
- _CPP_SECTION: 'C++ system header',
- _OTHER_H_SECTION: 'other header',
- }
-
- def __init__(self):
- dict.__init__(self)
- # The name of the current section.
- self._section = self._INITIAL_SECTION
- # The path of last found header.
- self._last_header = ''
-
- def CanonicalizeAlphabeticalOrder(self, header_path):
- """Returns a path canonicalized for alphabetical comparison.
-
- - replaces "-" with "_" so they both cmp the same.
- - removes '-inl' since we don't require them to be after the main header.
- - lowercase everything, just in case.
-
- Args:
- header_path: Path to be canonicalized.
-
- Returns:
- Canonicalized path.
- """
- return header_path.replace('-inl.h', '.h').replace('-', '_').lower()
-
- def IsInAlphabeticalOrder(self, header_path):
- """Check if a header is in alphabetical order with the previous header.
-
- Args:
- header_path: Header to be checked.
-
- Returns:
- Returns true if the header is in alphabetical order.
- """
- canonical_header = self.CanonicalizeAlphabeticalOrder(header_path)
- if self._last_header > canonical_header:
- return False
- self._last_header = canonical_header
- return True
-
- def CheckNextIncludeOrder(self, header_type):
- """Returns a non-empty error message if the next header is out of order.
-
- This function also updates the internal state to be ready to check
- the next include.
-
- Args:
- header_type: One of the _XXX_HEADER constants defined above.
-
- Returns:
- The empty string if the header is in the right order, or an
- error message describing what's wrong.
-
- """
- error_message = ('Found %s after %s' %
- (self._TYPE_NAMES[header_type],
- self._SECTION_NAMES[self._section]))
-
- last_section = self._section
-
- if header_type == _C_SYS_HEADER:
- if self._section <= self._C_SECTION:
- self._section = self._C_SECTION
- else:
- self._last_header = ''
- return error_message
- elif header_type == _CPP_SYS_HEADER:
- if self._section <= self._CPP_SECTION:
- self._section = self._CPP_SECTION
- else:
- self._last_header = ''
- return error_message
- elif header_type == _LIKELY_MY_HEADER:
- if self._section <= self._MY_H_SECTION:
- self._section = self._MY_H_SECTION
- else:
- self._section = self._OTHER_H_SECTION
- elif header_type == _POSSIBLE_MY_HEADER:
- if self._section <= self._MY_H_SECTION:
- self._section = self._MY_H_SECTION
- else:
- # This will always be the fallback because we're not sure
- # enough that the header is associated with this file.
- self._section = self._OTHER_H_SECTION
- else:
- assert header_type == _OTHER_HEADER
- self._section = self._OTHER_H_SECTION
-
- if last_section != self._section:
- self._last_header = ''
-
- return ''
-
-
-class _CppLintState(object):
- """Maintains module-wide state.."""
-
- def __init__(self):
- self.verbose_level = 1 # global setting.
- self.error_count = 0 # global count of reported errors
- # filters to apply when emitting error messages
- self.filters = _DEFAULT_FILTERS[:]
- self.counting = 'total' # In what way are we counting errors?
- self.errors_by_category = {} # string to int dict storing error counts
-
- # output format:
- # "emacs" - format that emacs can parse (default)
- # "vs7" - format that Microsoft Visual Studio 7 can parse
- self.output_format = 'emacs'
-
- def SetOutputFormat(self, output_format):
- """Sets the output format for errors."""
- self.output_format = output_format
-
- def SetVerboseLevel(self, level):
- """Sets the module's verbosity, and returns the previous setting."""
- last_verbose_level = self.verbose_level
- self.verbose_level = level
- return last_verbose_level
-
- def SetCountingStyle(self, counting_style):
- """Sets the module's counting options."""
- self.counting = counting_style
-
- def SetFilters(self, filters):
- """Sets the error-message filters.
-
- These filters are applied when deciding whether to emit a given
- error message.
-
- Args:
- filters: A string of comma-separated filters (eg "+whitespace/indent").
- Each filter should start with + or -; else we die.
-
- Raises:
- ValueError: The comma-separated filters did not all start with '+' or '-'.
- E.g. "-,+whitespace,-whitespace/indent,whitespace/badfilter"
- """
- # Default filters always have less priority than the flag ones.
- self.filters = _DEFAULT_FILTERS[:]
- for filt in filters.split(','):
- clean_filt = filt.strip()
- if clean_filt:
- self.filters.append(clean_filt)
- for filt in self.filters:
- if not (filt.startswith('+') or filt.startswith('-')):
- raise ValueError('Every filter in --filters must start with + or -'
- ' (%s does not)' % filt)
-
- def ResetErrorCounts(self):
- """Sets the module's error statistic back to zero."""
- self.error_count = 0
- self.errors_by_category = {}
-
- def IncrementErrorCount(self, category):
- """Bumps the module's error statistic."""
- self.error_count += 1
- if self.counting in ('toplevel', 'detailed'):
- if self.counting != 'detailed':
- category = category.split('/')[0]
- if category not in self.errors_by_category:
- self.errors_by_category[category] = 0
- self.errors_by_category[category] += 1
-
- def PrintErrorCounts(self):
- """Print a summary of errors by category, and the total."""
- for category, count in self.errors_by_category.iteritems():
- sys.stderr.write('Category \'%s\' errors found: %d\n' %
- (category, count))
- sys.stderr.write('Total errors found: %d\n' % self.error_count)
-
-_cpplint_state = _CppLintState()
-
-
-def _OutputFormat():
- """Gets the module's output format."""
- return _cpplint_state.output_format
-
-
-def _SetOutputFormat(output_format):
- """Sets the module's output format."""
- _cpplint_state.SetOutputFormat(output_format)
-
-
-def _VerboseLevel():
- """Returns the module's verbosity setting."""
- return _cpplint_state.verbose_level
-
-
-def _SetVerboseLevel(level):
- """Sets the module's verbosity, and returns the previous setting."""
- return _cpplint_state.SetVerboseLevel(level)
-
-
-def _SetCountingStyle(level):
- """Sets the module's counting options."""
- _cpplint_state.SetCountingStyle(level)
-
-
-def _Filters():
- """Returns the module's list of output filters, as a list."""
- return _cpplint_state.filters
-
-
-def _SetFilters(filters):
- """Sets the module's error-message filters.
-
- These filters are applied when deciding whether to emit a given
- error message.
-
- Args:
- filters: A string of comma-separated filters (eg "whitespace/indent").
- Each filter should start with + or -; else we die.
- """
- _cpplint_state.SetFilters(filters)
-
-
-class _FunctionState(object):
- """Tracks current function name and the number of lines in its body."""
-
- _NORMAL_TRIGGER = 250 # for --v=0, 500 for --v=1, etc.
- _TEST_TRIGGER = 400 # about 50% more than _NORMAL_TRIGGER.
-
- def __init__(self):
- self.in_a_function = False
- self.lines_in_function = 0
- self.current_function = ''
-
- def Begin(self, function_name):
- """Start analyzing function body.
-
- Args:
- function_name: The name of the function being tracked.
- """
- self.in_a_function = True
- self.lines_in_function = 0
- self.current_function = function_name
-
- def Count(self):
- """Count line in current function body."""
- if self.in_a_function:
- self.lines_in_function += 1
-
- def Check(self, error, filename, linenum):
- """Report if too many lines in function body.
-
- Args:
- error: The function to call with any errors found.
- filename: The name of the current file.
- linenum: The number of the line to check.
- """
- if Match(r'T(EST|est)', self.current_function):
- base_trigger = self._TEST_TRIGGER
- else:
- base_trigger = self._NORMAL_TRIGGER
- trigger = base_trigger * 2**_VerboseLevel()
-
- if self.lines_in_function > trigger:
- error_level = int(math.log(self.lines_in_function / base_trigger, 2))
- # 50 => 0, 100 => 1, 200 => 2, 400 => 3, 800 => 4, 1600 => 5, ...
- if error_level > 5:
- error_level = 5
- error(filename, linenum, 'readability/fn_size', error_level,
- 'Small and focused functions are preferred:'
- ' %s has %d non-comment lines'
- ' (error triggered by exceeding %d lines).' % (
- self.current_function, self.lines_in_function, trigger))
-
- def End(self):
- """Stop analyzing function body."""
- self.in_a_function = False
-
-
-class _IncludeError(Exception):
- """Indicates a problem with the include order in a file."""
- pass
-
-
-class FileInfo:
- """Provides utility functions for filenames.
-
- FileInfo provides easy access to the components of a file's path
- relative to the project root.
- """
-
- def __init__(self, filename):
- self._filename = filename
-
- def FullName(self):
- """Make Windows paths like Unix."""
- return os.path.abspath(self._filename).replace('\\', '/')
-
- def RepositoryName(self):
- """FullName after removing the local path to the repository.
-
- If we have a real absolute path name here we can try to do something smart:
- detecting the root of the checkout and truncating /path/to/checkout from
- the name so that we get header guards that don't include things like
- "C:\Documents and Settings\..." or "/home/username/..." in them and thus
- people on different computers who have checked the source out to different
- locations won't see bogus errors.
- """
- fullname = self.FullName()
-
- if os.path.exists(fullname):
- project_dir = os.path.dirname(fullname)
-
- if os.path.exists(os.path.join(project_dir, ".svn")):
- # If there's a .svn file in the current directory, we recursively look
- # up the directory tree for the top of the SVN checkout
- root_dir = project_dir
- one_up_dir = os.path.dirname(root_dir)
- while os.path.exists(os.path.join(one_up_dir, ".svn")):
- root_dir = os.path.dirname(root_dir)
- one_up_dir = os.path.dirname(one_up_dir)
-
- prefix = os.path.commonprefix([root_dir, project_dir])
- return fullname[len(prefix) + 1:]
-
- # Not SVN <= 1.6? Try to find a git, hg, or svn top level directory by
- # searching up from the current path.
- root_dir = os.path.dirname(fullname)
- while (root_dir != os.path.dirname(root_dir) and
- not os.path.exists(os.path.join(root_dir, ".git")) and
- not os.path.exists(os.path.join(root_dir, ".hg")) and
- not os.path.exists(os.path.join(root_dir, ".svn"))):
- root_dir = os.path.dirname(root_dir)
-
- if (os.path.exists(os.path.join(root_dir, ".git")) or
- os.path.exists(os.path.join(root_dir, ".hg")) or
- os.path.exists(os.path.join(root_dir, ".svn"))):
- prefix = os.path.commonprefix([root_dir, project_dir])
- return fullname[len(prefix) + 1:]
-
- # Don't know what to do; header guard warnings may be wrong...
- return fullname
-
- def Split(self):
- """Splits the file into the directory, basename, and extension.
-
- For 'chrome/browser/browser.cc', Split() would
- return ('chrome/browser', 'browser', '.cc')
-
- Returns:
- A tuple of (directory, basename, extension).
- """
-
- googlename = self.RepositoryName()
- project, rest = os.path.split(googlename)
- return (project,) + os.path.splitext(rest)
-
- def BaseName(self):
- """File base name - text after the final slash, before the final period."""
- return self.Split()[1]
-
- def Extension(self):
- """File extension - text following the final period."""
- return self.Split()[2]
-
- def NoExtension(self):
- """File has no source file extension."""
- return '/'.join(self.Split()[0:2])
-
- def IsSource(self):
- """File has a source file extension."""
- return self.Extension()[1:] in ('c', 'cc', 'cpp', 'cxx')
-
-
-def _ShouldPrintError(category, confidence, linenum):
- """If confidence >= verbose, category passes filter and is not suppressed."""
-
- # There are three ways we might decide not to print an error message:
- # a "NOLINT(category)" comment appears in the source,
- # the verbosity level isn't high enough, or the filters filter it out.
- if IsErrorSuppressedByNolint(category, linenum):
- return False
- if confidence < _cpplint_state.verbose_level:
- return False
-
- is_filtered = False
- for one_filter in _Filters():
- if one_filter.startswith('-'):
- if category.startswith(one_filter[1:]):
- is_filtered = True
- elif one_filter.startswith('+'):
- if category.startswith(one_filter[1:]):
- is_filtered = False
- else:
- assert False # should have been checked for in SetFilter.
- if is_filtered:
- return False
-
- return True
-
-
-def Error(filename, linenum, category, confidence, message):
- """Logs the fact we've found a lint error.
-
- We log where the error was found, and also our confidence in the error,
- that is, how certain we are this is a legitimate style regression, and
- not a misidentification or a use that's sometimes justified.
-
- False positives can be suppressed by the use of
- "cpplint(category)" comments on the offending line. These are
- parsed into _error_suppressions.
-
- Args:
- filename: The name of the file containing the error.
- linenum: The number of the line containing the error.
- category: A string used to describe the "category" this bug
- falls under: "whitespace", say, or "runtime". Categories
- may have a hierarchy separated by slashes: "whitespace/indent".
- confidence: A number from 1-5 representing a confidence score for
- the error, with 5 meaning that we are certain of the problem,
- and 1 meaning that it could be a legitimate construct.
- message: The error message.
- """
- if _ShouldPrintError(category, confidence, linenum):
- _cpplint_state.IncrementErrorCount(category)
- if _cpplint_state.output_format == 'vs7':
- sys.stderr.write('%s(%s): %s [%s] [%d]\n' % (
- filename, linenum, message, category, confidence))
- elif _cpplint_state.output_format == 'eclipse':
- sys.stderr.write('%s:%s: warning: %s [%s] [%d]\n' % (
- filename, linenum, message, category, confidence))
- else:
- sys.stderr.write('%s:%s: %s [%s] [%d]\n' % (
- filename, linenum, message, category, confidence))
-
-
-# Matches standard C++ escape esequences per 2.13.2.3 of the C++ standard.
-_RE_PATTERN_CLEANSE_LINE_ESCAPES = re.compile(
- r'\\([abfnrtv?"\\\']|\d+|x[0-9a-fA-F]+)')
-# Matches strings. Escape codes should already be removed by ESCAPES.
-_RE_PATTERN_CLEANSE_LINE_DOUBLE_QUOTES = re.compile(r'"[^"]*"')
-# Matches characters. Escape codes should already be removed by ESCAPES.
-_RE_PATTERN_CLEANSE_LINE_SINGLE_QUOTES = re.compile(r"'.'")
-# Matches multi-line C++ comments.
-# This RE is a little bit more complicated than one might expect, because we
-# have to take care of space removals tools so we can handle comments inside
-# statements better.
-# The current rule is: We only clear spaces from both sides when we're at the
-# end of the line. Otherwise, we try to remove spaces from the right side,
-# if this doesn't work we try on left side but only if there's a non-character
-# on the right.
-_RE_PATTERN_CLEANSE_LINE_C_COMMENTS = re.compile(
- r"""(\s*/\*.*\*/\s*$|
- /\*.*\*/\s+|
- \s+/\*.*\*/(?=\W)|
- /\*.*\*/)""", re.VERBOSE)
-
-
-def IsCppString(line):
- """Does line terminate so, that the next symbol is in string constant.
-
- This function does not consider single-line nor multi-line comments.
-
- Args:
- line: is a partial line of code starting from the 0..n.
-
- Returns:
- True, if next character appended to 'line' is inside a
- string constant.
- """
-
- line = line.replace(r'\\', 'XX') # after this, \\" does not match to \"
- return ((line.count('"') - line.count(r'\"') - line.count("'\"'")) & 1) == 1
-
-
-def FindNextMultiLineCommentStart(lines, lineix):
- """Find the beginning marker for a multiline comment."""
- while lineix < len(lines):
- if lines[lineix].strip().startswith('/*'):
- # Only return this marker if the comment goes beyond this line
- if lines[lineix].strip().find('*/', 2) < 0:
- return lineix
- lineix += 1
- return len(lines)
-
-
-def FindNextMultiLineCommentEnd(lines, lineix):
- """We are inside a comment, find the end marker."""
- while lineix < len(lines):
- if lines[lineix].strip().endswith('*/'):
- return lineix
- lineix += 1
- return len(lines)
-
-
-def RemoveMultiLineCommentsFromRange(lines, begin, end):
- """Clears a range of lines for multi-line comments."""
- # Having // dummy comments makes the lines non-empty, so we will not get
- # unnecessary blank line warnings later in the code.
- for i in range(begin, end):
- lines[i] = '// dummy'
-
-
-def RemoveMultiLineComments(filename, lines, error):
- """Removes multiline (c-style) comments from lines."""
- lineix = 0
- while lineix < len(lines):
- lineix_begin = FindNextMultiLineCommentStart(lines, lineix)
- if lineix_begin >= len(lines):
- return
- lineix_end = FindNextMultiLineCommentEnd(lines, lineix_begin)
- if lineix_end >= len(lines):
- error(filename, lineix_begin + 1, 'readability/multiline_comment', 5,
- 'Could not find end of multi-line comment')
- return
- RemoveMultiLineCommentsFromRange(lines, lineix_begin, lineix_end + 1)
- lineix = lineix_end + 1
-
-
-def CleanseComments(line):
- """Removes //-comments and single-line C-style /* */ comments.
-
- Args:
- line: A line of C++ source.
-
- Returns:
- The line with single-line comments removed.
- """
- commentpos = line.find('//')
- if commentpos != -1 and not IsCppString(line[:commentpos]):
- line = line[:commentpos].rstrip()
- # get rid of /* ... */
- return _RE_PATTERN_CLEANSE_LINE_C_COMMENTS.sub('', line)
-
-
-class CleansedLines(object):
- """Holds 3 copies of all lines with different preprocessing applied to them.
-
- 1) elided member contains lines without strings and comments,
- 2) lines member contains lines without comments, and
- 3) raw_lines member contains all the lines without processing.
- All these three members are of <type 'list'>, and of the same length.
- """
-
- def __init__(self, lines):
- self.elided = []
- self.lines = []
- self.raw_lines = lines
- self.num_lines = len(lines)
- for linenum in range(len(lines)):
- self.lines.append(CleanseComments(lines[linenum]))
- elided = self._CollapseStrings(lines[linenum])
- self.elided.append(CleanseComments(elided))
-
- def NumLines(self):
- """Returns the number of lines represented."""
- return self.num_lines
-
- @staticmethod
- def _CollapseStrings(elided):
- """Collapses strings and chars on a line to simple "" or '' blocks.
-
- We nix strings first so we're not fooled by text like '"http://"'
-
- Args:
- elided: The line being processed.
-
- Returns:
- The line with collapsed strings.
- """
- if not _RE_PATTERN_INCLUDE.match(elided):
- # Remove escaped characters first to make quote/single quote collapsing
- # basic. Things that look like escaped characters shouldn't occur
- # outside of strings and chars.
- elided = _RE_PATTERN_CLEANSE_LINE_ESCAPES.sub('', elided)
- elided = _RE_PATTERN_CLEANSE_LINE_SINGLE_QUOTES.sub("''", elided)
- elided = _RE_PATTERN_CLEANSE_LINE_DOUBLE_QUOTES.sub('""', elided)
- return elided
-
-
-def FindEndOfExpressionInLine(line, startpos, depth, startchar, endchar):
- """Find the position just after the matching endchar.
-
- Args:
- line: a CleansedLines line.
- startpos: start searching at this position.
- depth: nesting level at startpos.
- startchar: expression opening character.
- endchar: expression closing character.
-
- Returns:
- Index just after endchar.
- """
- for i in xrange(startpos, len(line)):
- if line[i] == startchar:
- depth += 1
- elif line[i] == endchar:
- depth -= 1
- if depth == 0:
- return i + 1
- return -1
-
-
-def CloseExpression(clean_lines, linenum, pos):
- """If input points to ( or { or [, finds the position that closes it.
-
- If lines[linenum][pos] points to a '(' or '{' or '[', finds the
- linenum/pos that correspond to the closing of the expression.
-
- Args:
- clean_lines: A CleansedLines instance containing the file.
- linenum: The number of the line to check.
- pos: A position on the line.
-
- Returns:
- A tuple (line, linenum, pos) pointer *past* the closing brace, or
- (line, len(lines), -1) if we never find a close. Note we ignore
- strings and comments when matching; and the line we return is the
- 'cleansed' line at linenum.
- """
-
- line = clean_lines.elided[linenum]
- startchar = line[pos]
- if startchar not in '({[':
- return (line, clean_lines.NumLines(), -1)
- if startchar == '(': endchar = ')'
- if startchar == '[': endchar = ']'
- if startchar == '{': endchar = '}'
-
- # Check first line
- end_pos = FindEndOfExpressionInLine(line, pos, 0, startchar, endchar)
- if end_pos > -1:
- return (line, linenum, end_pos)
- tail = line[pos:]
- num_open = tail.count(startchar) - tail.count(endchar)
- while linenum < clean_lines.NumLines() - 1:
- linenum += 1
- line = clean_lines.elided[linenum]
- delta = line.count(startchar) - line.count(endchar)
- if num_open + delta <= 0:
- return (line, linenum,
- FindEndOfExpressionInLine(line, 0, num_open, startchar, endchar))
- num_open += delta
-
- # Did not find endchar before end of file, give up
- return (line, clean_lines.NumLines(), -1)
-
-def CheckForCopyright(filename, lines, error):
- """Logs an error if no Copyright message appears at the top of the file."""
-
- # We'll say it should occur by line 10. Don't forget there's a
- # dummy line at the front.
- for line in xrange(1, min(len(lines), 11)):
- if re.search(r'Copyright', lines[line], re.I): break
- else: # means no copyright line was found
- error(filename, 0, 'legal/copyright', 5,
- 'No copyright message found. '
- 'You should have a line: "Copyright [year] <Copyright Owner>"')
-
-
-def GetHeaderGuardCPPVariable(filename):
- """Returns the CPP variable that should be used as a header guard.
-
- Args:
- filename: The name of a C++ header file.
-
- Returns:
- The CPP variable that should be used as a header guard in the
- named file.
-
- """
-
- # Restores original filename in case that cpplint is invoked from Emacs's
- # flymake.
- filename = re.sub(r'_flymake\.h$', '.h', filename)
- filename = re.sub(r'/\.flymake/([^/]*)$', r'/\1', filename)
-
- fileinfo = FileInfo(filename)
- file_path_from_root = fileinfo.RepositoryName()
- if _root:
- file_path_from_root = re.sub('^' + _root + os.sep, '', file_path_from_root)
- return re.sub(r'[-./\s]', '_', file_path_from_root).upper() + '_'
-
-
-def CheckForHeaderGuard(filename, lines, error):
- """Checks that the file contains a header guard.
-
- Logs an error if no #ifndef header guard is present. For other
- headers, checks that the full pathname is used.
-
- Args:
- filename: The name of the C++ header file.
- lines: An array of strings, each representing a line of the file.
- error: The function to call with any errors found.
- """
-
- cppvar = GetHeaderGuardCPPVariable(filename)
-
- ifndef = None
- ifndef_linenum = 0
- define = None
- endif = None
- endif_linenum = 0
- for linenum, line in enumerate(lines):
- linesplit = line.split()
- if len(linesplit) >= 2:
- # find the first occurrence of #ifndef and #define, save arg
- if not ifndef and linesplit[0] == '#ifndef':
- # set ifndef to the header guard presented on the #ifndef line.
- ifndef = linesplit[1]
- ifndef_linenum = linenum
- if not define and linesplit[0] == '#define':
- define = linesplit[1]
- # find the last occurrence of #endif, save entire line
- if line.startswith('#endif'):
- endif = line
- endif_linenum = linenum
-
- if not ifndef:
- error(filename, 0, 'build/header_guard', 5,
- 'No #ifndef header guard found, suggested CPP variable is: %s' %
- cppvar)
- return
-
- if not define:
- error(filename, 0, 'build/header_guard', 5,
- 'No #define header guard found, suggested CPP variable is: %s' %
- cppvar)
- return
-
- # The guard should be PATH_FILE_H_, but we also allow PATH_FILE_H__
- # for backward compatibility.
- if ifndef != cppvar:
- error_level = 0
- if ifndef != cppvar + '_':
- error_level = 5
-
- ParseNolintSuppressions(filename, lines[ifndef_linenum], ifndef_linenum,
- error)
- error(filename, ifndef_linenum, 'build/header_guard', error_level,
- '#ifndef header guard has wrong style, please use: %s' % cppvar)
-
- if define != ifndef:
- error(filename, 0, 'build/header_guard', 5,
- '#ifndef and #define don\'t match, suggested CPP variable is: %s' %
- cppvar)
- return
-
- if endif != ('#endif // %s' % cppvar):
- error_level = 0
- if endif != ('#endif // %s' % (cppvar + '_')):
- error_level = 5
-
- ParseNolintSuppressions(filename, lines[endif_linenum], endif_linenum,
- error)
- error(filename, endif_linenum, 'build/header_guard', error_level,
- '#endif line should be "#endif // %s"' % cppvar)
-
-
-def CheckForUnicodeReplacementCharacters(filename, lines, error):
- """Logs an error for each line containing Unicode replacement characters.
-
- These indicate that either the file contained invalid UTF-8 (likely)
- or Unicode replacement characters (which it shouldn't). Note that
- it's possible for this to throw off line numbering if the invalid
- UTF-8 occurred adjacent to a newline.
-
- Args:
- filename: The name of the current file.
- lines: An array of strings, each representing a line of the file.
- error: The function to call with any errors found.
- """
- for linenum, line in enumerate(lines):
- if u'\ufffd' in line:
- error(filename, linenum, 'readability/utf8', 5,
- 'Line contains invalid UTF-8 (or Unicode replacement character).')
-
-
-def CheckForNewlineAtEOF(filename, lines, error):
- """Logs an error if there is no newline char at the end of the file.
-
- Args:
- filename: The name of the current file.
- lines: An array of strings, each representing a line of the file.
- error: The function to call with any errors found.
- """
-
- # The array lines() was created by adding two newlines to the
- # original file (go figure), then splitting on \n.
- # To verify that the file ends in \n, we just have to make sure the
- # last-but-two element of lines() exists and is empty.
- if len(lines) < 3 or lines[-2]:
- error(filename, len(lines) - 2, 'whitespace/ending_newline', 5,
- 'Could not find a newline character at the end of the file.')
-
-
-def CheckForMultilineCommentsAndStrings(filename, clean_lines, linenum, error):
- """Logs an error if we see /* ... */ or "..." that extend past one line.
-
- /* ... */ comments are legit inside macros, for one line.
- Otherwise, we prefer // comments, so it's ok to warn about the
- other. Likewise, it's ok for strings to extend across multiple
- lines, as long as a line continuation character (backslash)
- terminates each line. Although not currently prohibited by the C++
- style guide, it's ugly and unnecessary. We don't do well with either
- in this lint program, so we warn about both.
-
- Args:
- filename: The name of the current file.
- clean_lines: A CleansedLines instance containing the file.
- linenum: The number of the line to check.
- error: The function to call with any errors found.
- """
- line = clean_lines.elided[linenum]
-
- # Remove all \\ (escaped backslashes) from the line. They are OK, and the
- # second (escaped) slash may trigger later \" detection erroneously.
- line = line.replace('\\\\', '')
-
- if line.count('/*') > line.count('*/'):
- error(filename, linenum, 'readability/multiline_comment', 5,
- 'Complex multi-line /*...*/-style comment found. '
- 'Lint may give bogus warnings. '
- 'Consider replacing these with //-style comments, '
- 'with #if 0...#endif, '
- 'or with more clearly structured multi-line comments.')
-
- if (line.count('"') - line.count('\\"')) % 2:
- error(filename, linenum, 'readability/multiline_string', 5,
- 'Multi-line string ("...") found. This lint script doesn\'t '
- 'do well with such strings, and may give bogus warnings. They\'re '
- 'ugly and unnecessary, and you should use concatenation instead".')
-
-
-threading_list = (
- ('asctime(', 'asctime_r('),
- ('ctime(', 'ctime_r('),
- ('getgrgid(', 'getgrgid_r('),
- ('getgrnam(', 'getgrnam_r('),
- ('getlogin(', 'getlogin_r('),
- ('getpwnam(', 'getpwnam_r('),
- ('getpwuid(', 'getpwuid_r('),
- ('gmtime(', 'gmtime_r('),
- ('localtime(', 'localtime_r('),
- ('rand(', 'rand_r('),
- ('readdir(', 'readdir_r('),
- ('strtok(', 'strtok_r('),
- ('ttyname(', 'ttyname_r('),
- )
-
-
-def CheckPosixThreading(filename, clean_lines, linenum, error):
- """Checks for calls to thread-unsafe functions.
-
- Much code has been originally written without consideration of
- multi-threading. Also, engineers are relying on their old experience;
- they have learned posix before threading extensions were added. These
- tests guide the engineers to use thread-safe functions (when using
- posix directly).
-
- Args:
- filename: The name of the current file.
- clean_lines: A CleansedLines instance containing the file.
- linenum: The number of the line to check.
- error: The function to call with any errors found.
- """
- line = clean_lines.elided[linenum]
- for single_thread_function, multithread_safe_function in threading_list:
- ix = line.find(single_thread_function)
- # Comparisons made explicit for clarity -- pylint: disable-msg=C6403
- if ix >= 0 and (ix == 0 or (not line[ix - 1].isalnum() and
- line[ix - 1] not in ('_', '.', '>'))):
- error(filename, linenum, 'runtime/threadsafe_fn', 2,
- 'Consider using ' + multithread_safe_function +
- '...) instead of ' + single_thread_function +
- '...) for improved thread safety.')
-
-
-# Matches invalid increment: *count++, which moves pointer instead of
-# incrementing a value.
-_RE_PATTERN_INVALID_INCREMENT = re.compile(
- r'^\s*\*\w+(\+\+|--);')
-
-
-def CheckInvalidIncrement(filename, clean_lines, linenum, error):
- """Checks for invalid increment *count++.
-
- For example following function:
- void increment_counter(int* count) {
- *count++;
- }
- is invalid, because it effectively does count++, moving pointer, and should
- be replaced with ++*count, (*count)++ or *count += 1.
-
- Args:
- filename: The name of the current file.
- clean_lines: A CleansedLines instance containing the file.
- linenum: The number of the line to check.
- error: The function to call with any errors found.
- """
- line = clean_lines.elided[linenum]
- if _RE_PATTERN_INVALID_INCREMENT.match(line):
- error(filename, linenum, 'runtime/invalid_increment', 5,
- 'Changing pointer instead of value (or unused value of operator*).')
-
-
-class _BlockInfo(object):
- """Stores information about a generic block of code."""
-
- def __init__(self, seen_open_brace):
- self.seen_open_brace = seen_open_brace
- self.open_parentheses = 0
- self.inline_asm = _NO_ASM
-
- def CheckBegin(self, filename, clean_lines, linenum, error):
- """Run checks that applies to text up to the opening brace.
-
- This is mostly for checking the text after the class identifier
- and the "{", usually where the base class is specified. For other
- blocks, there isn't much to check, so we always pass.
-
- Args:
- filename: The name of the current file.
- clean_lines: A CleansedLines instance containing the file.
- linenum: The number of the line to check.
- error: The function to call with any errors found.
- """
- pass
-
- def CheckEnd(self, filename, clean_lines, linenum, error):
- """Run checks that applies to text after the closing brace.
-
- This is mostly used for checking end of namespace comments.
-
- Args:
- filename: The name of the current file.
- clean_lines: A CleansedLines instance containing the file.
- linenum: The number of the line to check.
- error: The function to call with any errors found.
- """
- pass
-
-
-class _ClassInfo(_BlockInfo):
- """Stores information about a class."""
-
- def __init__(self, name, class_or_struct, clean_lines, linenum):
- _BlockInfo.__init__(self, False)
- self.name = name
- self.starting_linenum = linenum
- self.is_derived = False
- if class_or_struct == 'struct':
- self.access = 'public'
- else:
- self.access = 'private'
-
- # Try to find the end of the class. This will be confused by things like:
- # class A {
- # } *x = { ...
- #
- # But it's still good enough for CheckSectionSpacing.
- self.last_line = 0
- depth = 0
- for i in range(linenum, clean_lines.NumLines()):
- line = clean_lines.elided[i]
- depth += line.count('{') - line.count('}')
- if not depth:
- self.last_line = i
- break
-
- def CheckBegin(self, filename, clean_lines, linenum, error):
- # Look for a bare ':'
- if Search('(^|[^:]):($|[^:])', clean_lines.elided[linenum]):
- self.is_derived = True
-
-
-class _NamespaceInfo(_BlockInfo):
- """Stores information about a namespace."""
-
- def __init__(self, name, linenum):
- _BlockInfo.__init__(self, False)
- self.name = name or ''
- self.starting_linenum = linenum
-
- def CheckEnd(self, filename, clean_lines, linenum, error):
- """Check end of namespace comments."""
- line = clean_lines.raw_lines[linenum]
-
- # Check how many lines is enclosed in this namespace. Don't issue
- # warning for missing namespace comments if there aren't enough
- # lines. However, do apply checks if there is already an end of
- # namespace comment and it's incorrect.
- #
- # TODO(unknown): We always want to check end of namespace comments
- # if a namespace is large, but sometimes we also want to apply the
- # check if a short namespace contained nontrivial things (something
- # other than forward declarations). There is currently no logic on
- # deciding what these nontrivial things are, so this check is
- # triggered by namespace size only, which works most of the time.
- if (linenum - self.starting_linenum < 10
- and not Match(r'};*\s*(//|/\*).*\bnamespace\b', line)):
- return
-
- # Look for matching comment at end of namespace.
- #
- # Note that we accept C style "/* */" comments for terminating
- # namespaces, so that code that terminate namespaces inside
- # preprocessor macros can be cpplint clean. Example: http://go/nxpiz
- #
- # We also accept stuff like "// end of namespace <name>." with the
- # period at the end.
- #
- # Besides these, we don't accept anything else, otherwise we might
- # get false negatives when existing comment is a substring of the
- # expected namespace. Example: http://go/ldkdc, http://cl/23548205
- if self.name:
- # Named namespace
- if not Match((r'};*\s*(//|/\*).*\bnamespace\s+' + re.escape(self.name) +
- r'[\*/\.\\\s]*$'),
- line):
- error(filename, linenum, 'readability/namespace', 5,
- 'Namespace should be terminated with "// namespace %s"' %
- self.name)
- else:
- # Anonymous namespace
- if not Match(r'};*\s*(//|/\*).*\bnamespace[\*/\.\\\s]*$', line):
- error(filename, linenum, 'readability/namespace', 5,
- 'Namespace should be terminated with "// namespace"')
-
-
-class _PreprocessorInfo(object):
- """Stores checkpoints of nesting stacks when #if/#else is seen."""
-
- def __init__(self, stack_before_if):
- # The entire nesting stack before #if
- self.stack_before_if = stack_before_if
-
- # The entire nesting stack up to #else
- self.stack_before_else = []
-
- # Whether we have already seen #else or #elif
- self.seen_else = False
-
-
-class _NestingState(object):
- """Holds states related to parsing braces."""
-
- def __init__(self):
- # Stack for tracking all braces. An object is pushed whenever we
- # see a "{", and popped when we see a "}". Only 3 types of
- # objects are possible:
- # - _ClassInfo: a class or struct.
- # - _NamespaceInfo: a namespace.
- # - _BlockInfo: some other type of block.
- self.stack = []
-
- # Stack of _PreprocessorInfo objects.
- self.pp_stack = []
-
- def SeenOpenBrace(self):
- """Check if we have seen the opening brace for the innermost block.
-
- Returns:
- True if we have seen the opening brace, False if the innermost
- block is still expecting an opening brace.
- """
- return (not self.stack) or self.stack[-1].seen_open_brace
-
- def InNamespaceBody(self):
- """Check if we are currently one level inside a namespace body.
-
- Returns:
- True if top of the stack is a namespace block, False otherwise.
- """
- return self.stack and isinstance(self.stack[-1], _NamespaceInfo)
-
- def UpdatePreprocessor(self, line):
- """Update preprocessor stack.
-
- We need to handle preprocessors due to classes like this:
- #ifdef SWIG
- struct ResultDetailsPageElementExtensionPoint {
- #else
- struct ResultDetailsPageElementExtensionPoint : public Extension {
- #endif
- (see http://go/qwddn for original example)
-
- We make the following assumptions (good enough for most files):
- - Preprocessor condition evaluates to true from #if up to first
- #else/#elif/#endif.
-
- - Preprocessor condition evaluates to false from #else/#elif up
- to #endif. We still perform lint checks on these lines, but
- these do not affect nesting stack.
-
- Args:
- line: current line to check.
- """
- if Match(r'^\s*#\s*(if|ifdef|ifndef)\b', line):
- # Beginning of #if block, save the nesting stack here. The saved
- # stack will allow us to restore the parsing state in the #else case.
- self.pp_stack.append(_PreprocessorInfo(copy.deepcopy(self.stack)))
- elif Match(r'^\s*#\s*(else|elif)\b', line):
- # Beginning of #else block
- if self.pp_stack:
- if not self.pp_stack[-1].seen_else:
- # This is the first #else or #elif block. Remember the
- # whole nesting stack up to this point. This is what we
- # keep after the #endif.
- self.pp_stack[-1].seen_else = True
- self.pp_stack[-1].stack_before_else = copy.deepcopy(self.stack)
-
- # Restore the stack to how it was before the #if
- self.stack = copy.deepcopy(self.pp_stack[-1].stack_before_if)
- else:
- # TODO(unknown): unexpected #else, issue warning?
- pass
- elif Match(r'^\s*#\s*endif\b', line):
- # End of #if or #else blocks.
- if self.pp_stack:
- # If we saw an #else, we will need to restore the nesting
- # stack to its former state before the #else, otherwise we
- # will just continue from where we left off.
- if self.pp_stack[-1].seen_else:
- # Here we can just use a shallow copy since we are the last
- # reference to it.
- self.stack = self.pp_stack[-1].stack_before_else
- # Drop the corresponding #if
- self.pp_stack.pop()
- else:
- # TODO(unknown): unexpected #endif, issue warning?
- pass
-
- def Update(self, filename, clean_lines, linenum, error):
- """Update nesting state with current line.
-
- Args:
- filename: The name of the current file.
- clean_lines: A CleansedLines instance containing the file.
- linenum: The number of the line to check.
- error: The function to call with any errors found.
- """
- line = clean_lines.elided[linenum]
-
- # Update pp_stack first
- self.UpdatePreprocessor(line)
-
- # Count parentheses. This is to avoid adding struct arguments to
- # the nesting stack.
- if self.stack:
- inner_block = self.stack[-1]
- depth_change = line.count('(') - line.count(')')
- inner_block.open_parentheses += depth_change
-
- # Also check if we are starting or ending an inline assembly block.
- if inner_block.inline_asm in (_NO_ASM, _END_ASM):
- if (depth_change != 0 and
- inner_block.open_parentheses == 1 and
- _MATCH_ASM.match(line)):
- # Enter assembly block
- inner_block.inline_asm = _INSIDE_ASM
- else:
- # Not entering assembly block. If previous line was _END_ASM,
- # we will now shift to _NO_ASM state.
- inner_block.inline_asm = _NO_ASM
- elif (inner_block.inline_asm == _INSIDE_ASM and
- inner_block.open_parentheses == 0):
- # Exit assembly block
- inner_block.inline_asm = _END_ASM
-
- # Consume namespace declaration at the beginning of the line. Do
- # this in a loop so that we catch same line declarations like this:
- # namespace proto2 { namespace bridge { class MessageSet; } }
- while True:
- # Match start of namespace. The "\b\s*" below catches namespace
- # declarations even if it weren't followed by a whitespace, this
- # is so that we don't confuse our namespace checker. The
- # missing spaces will be flagged by CheckSpacing.
- namespace_decl_match = Match(r'^\s*namespace\b\s*([:\w]+)?(.*)$', line)
- if not namespace_decl_match:
- break
-
- new_namespace = _NamespaceInfo(namespace_decl_match.group(1), linenum)
- self.stack.append(new_namespace)
-
- line = namespace_decl_match.group(2)
- if line.find('{') != -1:
- new_namespace.seen_open_brace = True
- line = line[line.find('{') + 1:]
-
- # Look for a class declaration in whatever is left of the line
- # after parsing namespaces. The regexp accounts for decorated classes
- # such as in:
- # class LOCKABLE API Object {
- # };
- #
- # Templates with class arguments may confuse the parser, for example:
- # template <class T
- # class Comparator = less<T>,
- # class Vector = vector<T> >
- # class HeapQueue {
- #
- # Because this parser has no nesting state about templates, by the
- # time it saw "class Comparator", it may think that it's a new class.
- # Nested templates have a similar problem:
- # template <
- # typename ExportedType,
- # typename TupleType,
- # template <typename, typename> class ImplTemplate>
- #
- # To avoid these cases, we ignore classes that are followed by '=' or '>'
- class_decl_match = Match(
- r'\s*(template\s*<[\w\s<>,:]*>\s*)?'
- '(class|struct)\s+([A-Z_]+\s+)*(\w+(?:::\w+)*)'
- '(([^=>]|<[^<>]*>)*)$', line)
- if (class_decl_match and
- (not self.stack or self.stack[-1].open_parentheses == 0)):
- self.stack.append(_ClassInfo(
- class_decl_match.group(4), class_decl_match.group(2),
- clean_lines, linenum))
- line = class_decl_match.group(5)
-
- # If we have not yet seen the opening brace for the innermost block,
- # run checks here.
- if not self.SeenOpenBrace():
- self.stack[-1].CheckBegin(filename, clean_lines, linenum, error)
-
- # Update access control if we are inside a class/struct
- if self.stack and isinstance(self.stack[-1], _ClassInfo):
- access_match = Match(r'\s*(public|private|protected)\s*:', line)
- if access_match:
- self.stack[-1].access = access_match.group(1)
-
- # Consume braces or semicolons from what's left of the line
- while True:
- # Match first brace, semicolon, or closed parenthesis.
- matched = Match(r'^[^{;)}]*([{;)}])(.*)$', line)
- if not matched:
- break
-
- token = matched.group(1)
- if token == '{':
- # If namespace or class hasn't seen a opening brace yet, mark
- # namespace/class head as complete. Push a new block onto the
- # stack otherwise.
- if not self.SeenOpenBrace():
- self.stack[-1].seen_open_brace = True
- else:
- self.stack.append(_BlockInfo(True))
- if _MATCH_ASM.match(line):
- self.stack[-1].inline_asm = _BLOCK_ASM
- elif token == ';' or token == ')':
- # If we haven't seen an opening brace yet, but we already saw
- # a semicolon, this is probably a forward declaration. Pop
- # the stack for these.
- #
- # Similarly, if we haven't seen an opening brace yet, but we
- # already saw a closing parenthesis, then these are probably
- # function arguments with extra "class" or "struct" keywords.
- # Also pop these stack for these.
- if not self.SeenOpenBrace():
- self.stack.pop()
- else: # token == '}'
- # Perform end of block checks and pop the stack.
- if self.stack:
- self.stack[-1].CheckEnd(filename, clean_lines, linenum, error)
- self.stack.pop()
- line = matched.group(2)
-
- def InnermostClass(self):
- """Get class info on the top of the stack.
-
- Returns:
- A _ClassInfo object if we are inside a class, or None otherwise.
- """
- for i in range(len(self.stack), 0, -1):
- classinfo = self.stack[i - 1]
- if isinstance(classinfo, _ClassInfo):
- return classinfo
- return None
-
- def CheckClassFinished(self, filename, error):
- """Checks that all classes have been completely parsed.
-
- Call this when all lines in a file have been processed.
- Args:
- filename: The name of the current file.
- error: The function to call with any errors found.
- """
- # Note: This test can result in false positives if #ifdef constructs
- # get in the way of brace matching. See the testBuildClass test in
- # cpplint_unittest.py for an example of this.
- for obj in self.stack:
- if isinstance(obj, _ClassInfo):
- error(filename, obj.starting_linenum, 'build/class', 5,
- 'Failed to find complete declaration of class %s' %
- obj.name)
-
-
-def CheckForNonStandardConstructs(filename, clean_lines, linenum,
- nesting_state, error):
- """Logs an error if we see certain non-ANSI constructs ignored by gcc-2.
-
- Complain about several constructs which gcc-2 accepts, but which are
- not standard C++. Warning about these in lint is one way to ease the
- transition to new compilers.
- - put storage class first (e.g. "static const" instead of "const static").
- - "%lld" instead of %qd" in printf-type functions.
- - "%1$d" is non-standard in printf-type functions.
- - "\%" is an undefined character escape sequence.
- - text after #endif is not allowed.
- - invalid inner-style forward declaration.
- - >? and <? operators, and their >?= and <?= cousins.
-
- Additionally, check for constructor/destructor style violations and reference
- members, as it is very convenient to do so while checking for
- gcc-2 compliance.
-
- Args:
- filename: The name of the current file.
- clean_lines: A CleansedLines instance containing the file.
- linenum: The number of the line to check.
- nesting_state: A _NestingState instance which maintains information about
- the current stack of nested blocks being parsed.
- error: A callable to which errors are reported, which takes 4 arguments:
- filename, line number, error level, and message
- """
-
- # Remove comments from the line, but leave in strings for now.
- line = clean_lines.lines[linenum]
-
- if Search(r'printf\s*\(.*".*%[-+ ]?\d*q', line):
- error(filename, linenum, 'runtime/printf_format', 3,
- '%q in format strings is deprecated. Use %ll instead.')
-
- if Search(r'printf\s*\(.*".*%\d+\$', line):
- error(filename, linenum, 'runtime/printf_format', 2,
- '%N$ formats are unconventional. Try rewriting to avoid them.')
-
- # Remove escaped backslashes before looking for undefined escapes.
- line = line.replace('\\\\', '')
-
- if Search(r'("|\').*\\(%|\[|\(|{)', line):
- error(filename, linenum, 'build/printf_format', 3,
- '%, [, (, and { are undefined character escapes. Unescape them.')
-
- # For the rest, work with both comments and strings removed.
- line = clean_lines.elided[linenum]
-
- if Search(r'\b(const|volatile|void|char|short|int|long'
- r'|float|double|signed|unsigned'
- r'|schar|u?int8|u?int16|u?int32|u?int64)'
- r'\s+(register|static|extern|typedef)\b',
- line):
- error(filename, linenum, 'build/storage_class', 5,
- 'Storage class (static, extern, typedef, etc) should be first.')
-
- if Match(r'\s*#\s*endif\s*[^/\s]+', line):
- error(filename, linenum, 'build/endif_comment', 5,
- 'Uncommented text after #endif is non-standard. Use a comment.')
-
- if Match(r'\s*class\s+(\w+\s*::\s*)+\w+\s*;', line):
- error(filename, linenum, 'build/forward_decl', 5,
- 'Inner-style forward declarations are invalid. Remove this line.')
-
- if Search(r'(\w+|[+-]?\d+(\.\d*)?)\s*(<|>)\?=?\s*(\w+|[+-]?\d+)(\.\d*)?',
- line):
- error(filename, linenum, 'build/deprecated', 3,
- '>? and <? (max and min) operators are non-standard and deprecated.')
-
- if Search(r'^\s*const\s*string\s*&\s*\w+\s*;', line):
- # TODO(unknown): Could it be expanded safely to arbitrary references,
- # without triggering too many false positives? The first
- # attempt triggered 5 warnings for mostly benign code in the regtest, hence
- # the restriction.
- # Here's the original regexp, for the reference:
- # type_name = r'\w+((\s*::\s*\w+)|(\s*<\s*\w+?\s*>))?'
- # r'\s*const\s*' + type_name + '\s*&\s*\w+\s*;'
- error(filename, linenum, 'runtime/member_string_references', 2,
- 'const string& members are dangerous. It is much better to use '
- 'alternatives, such as pointers or simple constants.')
-
- # Everything else in this function operates on class declarations.
- # Return early if the top of the nesting stack is not a class, or if
- # the class head is not completed yet.
- classinfo = nesting_state.InnermostClass()
- if not classinfo or not classinfo.seen_open_brace:
- return
-
- # The class may have been declared with namespace or classname qualifiers.
- # The constructor and destructor will not have those qualifiers.
- base_classname = classinfo.name.split('::')[-1]
-
- # Look for single-argument constructors that aren't marked explicit.
- # Technically a valid construct, but against style.
- args = Match(r'\s+(?:inline\s+)?%s\s*\(([^,()]+)\)'
- % re.escape(base_classname),
- line)
- if (args and
- args.group(1) != 'void' and
- not Match(r'(const\s+)?%s\s*(?:<\w+>\s*)?&' % re.escape(base_classname),
- args.group(1).strip())):
- error(filename, linenum, 'runtime/explicit', 5,
- 'Single-argument constructors should be marked explicit.')
-
-
-def CheckSpacingForFunctionCall(filename, line, linenum, error):
- """Checks for the correctness of various spacing around function calls.
-
- Args:
- filename: The name of the current file.
- line: The text of the line to check.
- linenum: The number of the line to check.
- error: The function to call with any errors found.
- """
-
- # Since function calls often occur inside if/for/while/switch
- # expressions - which have their own, more liberal conventions - we
- # first see if we should be looking inside such an expression for a
- # function call, to which we can apply more strict standards.
- fncall = line # if there's no control flow construct, look at whole line
- for pattern in (r'\bif\s*\((.*)\)\s*{',
- r'\bfor\s*\((.*)\)\s*{',
- r'\bwhile\s*\((.*)\)\s*[{;]',
- r'\bswitch\s*\((.*)\)\s*{'):
- match = Search(pattern, line)
- if match:
- fncall = match.group(1) # look inside the parens for function calls
- break
-
- # Except in if/for/while/switch, there should never be space
- # immediately inside parens (eg "f( 3, 4 )"). We make an exception
- # for nested parens ( (a+b) + c ). Likewise, there should never be
- # a space before a ( when it's a function argument. I assume it's a
- # function argument when the char before the whitespace is legal in
- # a function name (alnum + _) and we're not starting a macro. Also ignore
- # pointers and references to arrays and functions coz they're too tricky:
- # we use a very simple way to recognize these:
- # " (something)(maybe-something)" or
- # " (something)(maybe-something," or
- # " (something)[something]"
- # Note that we assume the contents of [] to be short enough that
- # they'll never need to wrap.
- if ( # Ignore control structures.
- not Search(r'\b(if|for|while|switch|return|delete)\b', fncall) and
- # Ignore pointers/references to functions.
- not Search(r' \([^)]+\)\([^)]*(\)|,$)', fncall) and
- # Ignore pointers/references to arrays.
- not Search(r' \([^)]+\)\[[^\]]+\]', fncall)):
- if Search(r'\w\s*\(\s(?!\s*\\$)', fncall): # a ( used for a fn call
- error(filename, linenum, 'whitespace/parens', 4,
- 'Extra space after ( in function call')
- elif Search(r'\(\s+(?!(\s*\\)|\()', fncall):
- error(filename, linenum, 'whitespace/parens', 2,
- 'Extra space after (')
- if (Search(r'\w\s+\(', fncall) and
- not Search(r'#\s*define|typedef', fncall) and
- not Search(r'\w\s+\((\w+::)?\*\w+\)\(', fncall)):
- error(filename, linenum, 'whitespace/parens', 4,
- 'Extra space before ( in function call')
- # If the ) is followed only by a newline or a { + newline, assume it's
- # part of a control statement (if/while/etc), and don't complain
- if Search(r'[^)]\s+\)\s*[^{\s]', fncall):
- # If the closing parenthesis is preceded by only whitespaces,
- # try to give a more descriptive error message.
- if Search(r'^\s+\)', fncall):
- error(filename, linenum, 'whitespace/parens', 2,
- 'Closing ) should be moved to the previous line')
- else:
- error(filename, linenum, 'whitespace/parens', 2,
- 'Extra space before )')
-
-
-def IsBlankLine(line):
- """Returns true if the given line is blank.
-
- We consider a line to be blank if the line is empty or consists of
- only white spaces.
-
- Args:
- line: A line of a string.
-
- Returns:
- True, if the given line is blank.
- """
- return not line or line.isspace()
-
-
-def CheckForFunctionLengths(filename, clean_lines, linenum,
- function_state, error):
- """Reports for long function bodies.
-
- For an overview why this is done, see:
- http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Write_Short_Functions
-
- Uses a simplistic algorithm assuming other style guidelines
- (especially spacing) are followed.
- Only checks unindented functions, so class members are unchecked.
- Trivial bodies are unchecked, so constructors with huge initializer lists
- may be missed.
- Blank/comment lines are not counted so as to avoid encouraging the removal
- of vertical space and comments just to get through a lint check.
- NOLINT *on the last line of a function* disables this check.
-
- Args:
- filename: The name of the current file.
- clean_lines: A CleansedLines instance containing the file.
- linenum: The number of the line to check.
- function_state: Current function name and lines in body so far.
- error: The function to call with any errors found.
- """
- lines = clean_lines.lines
- line = lines[linenum]
- raw = clean_lines.raw_lines
- raw_line = raw[linenum]
- joined_line = ''
-
- starting_func = False
- regexp = r'(\w(\w|::|\*|\&|\s)*)\(' # decls * & space::name( ...
- match_result = Match(regexp, line)
- if match_result:
- # If the name is all caps and underscores, figure it's a macro and
- # ignore it, unless it's TEST or TEST_F.
- function_name = match_result.group(1).split()[-1]
- if function_name == 'TEST' or function_name == 'TEST_F' or (
- not Match(r'[A-Z_]+$', function_name)):
- starting_func = True
-
- if starting_func:
- body_found = False
- for start_linenum in xrange(linenum, clean_lines.NumLines()):
- start_line = lines[start_linenum]
- joined_line += ' ' + start_line.lstrip()
- if Search(r'(;|})', start_line): # Declarations and trivial functions
- body_found = True
- break # ... ignore
- elif Search(r'{', start_line):
- body_found = True
- function = Search(r'((\w|:)*)\(', line).group(1)
- if Match(r'TEST', function): # Handle TEST... macros
- parameter_regexp = Search(r'(\(.*\))', joined_line)
- if parameter_regexp: # Ignore bad syntax
- function += parameter_regexp.group(1)
- else:
- function += '()'
- function_state.Begin(function)
- break
- if not body_found:
- # No body for the function (or evidence of a non-function) was found.
- error(filename, linenum, 'readability/fn_size', 5,
- 'Lint failed to find start of function body.')
- elif Match(r'^\}\s*$', line): # function end
- function_state.Check(error, filename, linenum)
- function_state.End()
- elif not Match(r'^\s*$', line):
- function_state.Count() # Count non-blank/non-comment lines.
-
-
-_RE_PATTERN_TODO = re.compile(r'^//(\s*)TODO(\(.+?\))?:?(\s|$)?')
-
-
-def CheckComment(comment, filename, linenum, error):
- """Checks for common mistakes in TODO comments.
-
- Args:
- comment: The text of the comment from the line in question.
- filename: The name of the current file.
- linenum: The number of the line to check.
- error: The function to call with any errors found.
- """
- match = _RE_PATTERN_TODO.match(comment)
- if match:
- # One whitespace is correct; zero whitespace is handled elsewhere.
- leading_whitespace = match.group(1)
- if len(leading_whitespace) > 1:
- error(filename, linenum, 'whitespace/todo', 2,
- 'Too many spaces before TODO')
-
- username = match.group(2)
- if not username:
- error(filename, linenum, 'readability/todo', 2,
- 'Missing username in TODO; it should look like '
- '"// TODO(my_username): Stuff."')
-
- middle_whitespace = match.group(3)
- # Comparisons made explicit for correctness -- pylint: disable-msg=C6403
- if middle_whitespace != ' ' and middle_whitespace != '':
- error(filename, linenum, 'whitespace/todo', 2,
- 'TODO(my_username) should be followed by a space')
-
-def CheckAccess(filename, clean_lines, linenum, nesting_state, error):
- """Checks for improper use of DISALLOW* macros.
-
- Args:
- filename: The name of the current file.
- clean_lines: A CleansedLines instance containing the file.
- linenum: The number of the line to check.
- nesting_state: A _NestingState instance which maintains information about
- the current stack of nested blocks being parsed.
- error: The function to call with any errors found.
- """
- line = clean_lines.elided[linenum] # get rid of comments and strings
-
- matched = Match((r'\s*(DISALLOW_COPY_AND_ASSIGN|'
- r'DISALLOW_EVIL_CONSTRUCTORS|'
- r'DISALLOW_IMPLICIT_CONSTRUCTORS)'), line)
- if not matched:
- return
- if nesting_state.stack and isinstance(nesting_state.stack[-1], _ClassInfo):
- if nesting_state.stack[-1].access != 'private':
- error(filename, linenum, 'readability/constructors', 3,
- '%s must be in the private: section' % matched.group(1))
-
- else:
- # Found DISALLOW* macro outside a class declaration, or perhaps it
- # was used inside a function when it should have been part of the
- # class declaration. We could issue a warning here, but it
- # probably resulted in a compiler error already.
- pass
-
-
-def FindNextMatchingAngleBracket(clean_lines, linenum, init_suffix):
- """Find the corresponding > to close a template.
-
- Args:
- clean_lines: A CleansedLines instance containing the file.
- linenum: Current line number.
- init_suffix: Remainder of the current line after the initial <.
-
- Returns:
- True if a matching bracket exists.
- """
- line = init_suffix
- nesting_stack = ['<']
- while True:
- # Find the next operator that can tell us whether < is used as an
- # opening bracket or as a less-than operator. We only want to
- # warn on the latter case.
- #
- # We could also check all other operators and terminate the search
- # early, e.g. if we got something like this "a<b+c", the "<" is
- # most likely a less-than operator, but then we will get false
- # positives for default arguments (e.g. http://go/prccd) and
- # other template expressions (e.g. http://go/oxcjq).
- match = Search(r'^[^<>(),;\[\]]*([<>(),;\[\]])(.*)$', line)
- if match:
- # Found an operator, update nesting stack
- operator = match.group(1)
- line = match.group(2)
-
- if nesting_stack[-1] == '<':
- # Expecting closing angle bracket
- if operator in ('<', '(', '['):
- nesting_stack.append(operator)
- elif operator == '>':
- nesting_stack.pop()
- if not nesting_stack:
- # Found matching angle bracket
- return True
- elif operator == ',':
- # Got a comma after a bracket, this is most likely a template
- # argument. We have not seen a closing angle bracket yet, but
- # it's probably a few lines later if we look for it, so just
- # return early here.
- return True
- else:
- # Got some other operator.
- return False
-
- else:
- # Expecting closing parenthesis or closing bracket
- if operator in ('<', '(', '['):
- nesting_stack.append(operator)
- elif operator in (')', ']'):
- # We don't bother checking for matching () or []. If we got
- # something like (] or [), it would have been a syntax error.
- nesting_stack.pop()
-
- else:
- # Scan the next line
- linenum += 1
- if linenum >= len(clean_lines.elided):
- break
- line = clean_lines.elided[linenum]
-
- # Exhausted all remaining lines and still no matching angle bracket.
- # Most likely the input was incomplete, otherwise we should have
- # seen a semicolon and returned early.
- return True
-
-
-def FindPreviousMatchingAngleBracket(clean_lines, linenum, init_prefix):
- """Find the corresponding < that started a template.
-
- Args:
- clean_lines: A CleansedLines instance containing the file.
- linenum: Current line number.
- init_prefix: Part of the current line before the initial >.
-
- Returns:
- True if a matching bracket exists.
- """
- line = init_prefix
- nesting_stack = ['>']
- while True:
- # Find the previous operator
- match = Search(r'^(.*)([<>(),;\[\]])[^<>(),;\[\]]*$', line)
- if match:
- # Found an operator, update nesting stack
- operator = match.group(2)
- line = match.group(1)
-
- if nesting_stack[-1] == '>':
- # Expecting opening angle bracket
- if operator in ('>', ')', ']'):
- nesting_stack.append(operator)
- elif operator == '<':
- nesting_stack.pop()
- if not nesting_stack:
- # Found matching angle bracket
- return True
- elif operator == ',':
- # Got a comma before a bracket, this is most likely a
- # template argument. The opening angle bracket is probably
- # there if we look for it, so just return early here.
- return True
- else:
- # Got some other operator.
- return False
-
- else:
- # Expecting opening parenthesis or opening bracket
- if operator in ('>', ')', ']'):
- nesting_stack.append(operator)
- elif operator in ('(', '['):
- nesting_stack.pop()
-
- else:
- # Scan the previous line
- linenum -= 1
- if linenum < 0:
- break
- line = clean_lines.elided[linenum]
-
- # Exhausted all earlier lines and still no matching angle bracket.
- return False
-
-
-def CheckSpacing(filename, clean_lines, linenum, nesting_state, error):
- """Checks for the correctness of various spacing issues in the code.
-
- Things we check for: spaces around operators, spaces after
- if/for/while/switch, no spaces around parens in function calls, two
- spaces between code and comment, don't start a block with a blank
- line, don't end a function with a blank line, don't add a blank line
- after public/protected/private, don't have too many blank lines in a row.
-
- Args:
- filename: The name of the current file.
- clean_lines: A CleansedLines instance containing the file.
- linenum: The number of the line to check.
- nesting_state: A _NestingState instance which maintains information about
- the current stack of nested blocks being parsed.
- error: The function to call with any errors found.
- """
-
- raw = clean_lines.raw_lines
- line = raw[linenum]
-
- # Before nixing comments, check if the line is blank for no good
- # reason. This includes the first line after a block is opened, and
- # blank lines at the end of a function (ie, right before a line like '}'
- #
- # Skip all the blank line checks if we are immediately inside a
- # namespace body. In other words, don't issue blank line warnings
- # for this block:
- # namespace {
- #
- # }
- #
- # A warning about missing end of namespace comments will be issued instead.
- if IsBlankLine(line) and not nesting_state.InNamespaceBody():
- elided = clean_lines.elided
- prev_line = elided[linenum - 1]
- prevbrace = prev_line.rfind('{')
- # TODO(unknown): Don't complain if line before blank line, and line after,
- # both start with alnums and are indented the same amount.
- # This ignores whitespace at the start of a namespace block
- # because those are not usually indented.
- if prevbrace != -1 and prev_line[prevbrace:].find('}') == -1:
- # OK, we have a blank line at the start of a code block. Before we
- # complain, we check if it is an exception to the rule: The previous
- # non-empty line has the parameters of a function header that are indented
- # 4 spaces (because they did not fit in a 80 column line when placed on
- # the same line as the function name). We also check for the case where
- # the previous line is indented 6 spaces, which may happen when the
- # initializers of a constructor do not fit into a 80 column line.
- exception = False
- if Match(r' {6}\w', prev_line): # Initializer list?
- # We are looking for the opening column of initializer list, which
- # should be indented 4 spaces to cause 6 space indentation afterwards.
- search_position = linenum-2
- while (search_position >= 0
- and Match(r' {6}\w', elided[search_position])):
- search_position -= 1
- exception = (search_position >= 0
- and elided[search_position][:5] == ' :')
- else:
- # Search for the function arguments or an initializer list. We use a
- # simple heuristic here: If the line is indented 4 spaces; and we have a
- # closing paren, without the opening paren, followed by an opening brace
- # or colon (for initializer lists) we assume that it is the last line of
- # a function header. If we have a colon indented 4 spaces, it is an
- # initializer list.
- exception = (Match(r' {4}\w[^\(]*\)\s*(const\s*)?(\{\s*$|:)',
- prev_line)
- or Match(r' {4}:', prev_line))
-
- if not exception:
- error(filename, linenum, 'whitespace/blank_line', 2,
- 'Blank line at the start of a code block. Is this needed?')
- # Ignore blank lines at the end of a block in a long if-else
- # chain, like this:
- # if (condition1) {
- # // Something followed by a blank line
- #
- # } else if (condition2) {
- # // Something else
- # }
- if linenum + 1 < clean_lines.NumLines():
- next_line = raw[linenum + 1]
- if (next_line
- and Match(r'\s*}', next_line)
- and next_line.find('} else ') == -1):
- error(filename, linenum, 'whitespace/blank_line', 3,
- 'Blank line at the end of a code block. Is this needed?')
-
- matched = Match(r'\s*(public|protected|private):', prev_line)
- if matched:
- error(filename, linenum, 'whitespace/blank_line', 3,
- 'Do not leave a blank line after "%s:"' % matched.group(1))
-
- # Next, we complain if there's a comment too near the text
- commentpos = line.find('//')
- if commentpos != -1:
- # Check if the // may be in quotes. If so, ignore it
- # Comparisons made explicit for clarity -- pylint: disable-msg=C6403
- if (line.count('"', 0, commentpos) -
- line.count('\\"', 0, commentpos)) % 2 == 0: # not in quotes
- # Allow one space for new scopes, two spaces otherwise:
- if (not Match(r'^\s*{ //', line) and
- ((commentpos >= 1 and
- line[commentpos-1] not in string.whitespace) or
- (commentpos >= 2 and
- line[commentpos-2] not in string.whitespace))):
- error(filename, linenum, 'whitespace/comments', 2,
- 'At least two spaces is best between code and comments')
- # There should always be a space between the // and the comment
- commentend = commentpos + 2
- if commentend < len(line) and not line[commentend] == ' ':
- # but some lines are exceptions -- e.g. if they're big
- # comment delimiters like:
- # //----------------------------------------------------------
- # or are an empty C++ style Doxygen comment, like:
- # ///
- # or they begin with multiple slashes followed by a space:
- # //////// Header comment
- match = (Search(r'[=/-]{4,}\s*$', line[commentend:]) or
- Search(r'^/$', line[commentend:]) or
- Search(r'^/+ ', line[commentend:]))
- if not match:
- error(filename, linenum, 'whitespace/comments', 4,
- 'Should have a space between // and comment')
- CheckComment(line[commentpos:], filename, linenum, error)
-
- line = clean_lines.elided[linenum] # get rid of comments and strings
-
- # Don't try to do spacing checks for operator methods
- line = re.sub(r'operator(==|!=|<|<<|<=|>=|>>|>)\(', 'operator\(', line)
-
- # We allow no-spaces around = within an if: "if ( (a=Foo()) == 0 )".
- # Otherwise not. Note we only check for non-spaces on *both* sides;
- # sometimes people put non-spaces on one side when aligning ='s among
- # many lines (not that this is behavior that I approve of...)
- if Search(r'[\w.]=[\w.]', line) and not Search(r'\b(if|while) ', line):
- error(filename, linenum, 'whitespace/operators', 4,
- 'Missing spaces around =')
-
- # It's ok not to have spaces around binary operators like + - * /, but if
- # there's too little whitespace, we get concerned. It's hard to tell,
- # though, so we punt on this one for now. TODO.
-
- # You should always have whitespace around binary operators.
- #
- # Check <= and >= first to avoid false positives with < and >, then
- # check non-include lines for spacing around < and >.
- match = Search(r'[^<>=!\s](==|!=|<=|>=)[^<>=!\s]', line)
- if match:
- error(filename, linenum, 'whitespace/operators', 3,
- 'Missing spaces around %s' % match.group(1))
- # We allow no-spaces around << when used like this: 10<<20, but
- # not otherwise (particularly, not when used as streams)
- match = Search(r'(\S)(?:L|UL|ULL|l|ul|ull)?<<(\S)', line)
- if match and not (match.group(1).isdigit() and match.group(2).isdigit()):
- error(filename, linenum, 'whitespace/operators', 3,
- 'Missing spaces around <<')
- elif not Match(r'#.*include', line):
- # Avoid false positives on ->
- reduced_line = line.replace('->', '')
-
- # Look for < that is not surrounded by spaces. This is only
- # triggered if both sides are missing spaces, even though
- # technically should should flag if at least one side is missing a
- # space. This is done to avoid some false positives with shifts.
- match = Search(r'[^\s<]<([^\s=<].*)', reduced_line)
- if (match and
- not FindNextMatchingAngleBracket(clean_lines, linenum, match.group(1))):
- error(filename, linenum, 'whitespace/operators', 3,
- 'Missing spaces around <')
-
- # Look for > that is not surrounded by spaces. Similar to the
- # above, we only trigger if both sides are missing spaces to avoid
- # false positives with shifts.
- match = Search(r'^(.*[^\s>])>[^\s=>]', reduced_line)
- if (match and
- not FindPreviousMatchingAngleBracket(clean_lines, linenum,
- match.group(1))):
- error(filename, linenum, 'whitespace/operators', 3,
- 'Missing spaces around >')
-
- # We allow no-spaces around >> for almost anything. This is because
- # C++11 allows ">>" to close nested templates, which accounts for
- # most cases when ">>" is not followed by a space.
- #
- # We still warn on ">>" followed by alpha character, because that is
- # likely due to ">>" being used for right shifts, e.g.:
- # value >> alpha
- #
- # When ">>" is used to close templates, the alphanumeric letter that
- # follows would be part of an identifier, and there should still be
- # a space separating the template type and the identifier.
- # type<type<type>> alpha
- match = Search(r'>>[a-zA-Z_]', line)
- if match:
- error(filename, linenum, 'whitespace/operators', 3,
- 'Missing spaces around >>')
-
- # There shouldn't be space around unary operators
- match = Search(r'(!\s|~\s|[\s]--[\s;]|[\s]\+\+[\s;])', line)
- if match:
- error(filename, linenum, 'whitespace/operators', 4,
- 'Extra space for operator %s' % match.group(1))
-
- # A pet peeve of mine: no spaces after an if, while, switch, or for
- match = Search(r' (if\(|for\(|while\(|switch\()', line)
- if match:
- error(filename, linenum, 'whitespace/parens', 5,
- 'Missing space before ( in %s' % match.group(1))
-
- # For if/for/while/switch, the left and right parens should be
- # consistent about how many spaces are inside the parens, and
- # there should either be zero or one spaces inside the parens.
- # We don't want: "if ( foo)" or "if ( foo )".
- # Exception: "for ( ; foo; bar)" and "for (foo; bar; )" are allowed.
- match = Search(r'\b(if|for|while|switch)\s*'
- r'\(([ ]*)(.).*[^ ]+([ ]*)\)\s*{\s*$',
- line)
- if match:
- if len(match.group(2)) != len(match.group(4)):
- if not (match.group(3) == ';' and
- len(match.group(2)) == 1 + len(match.group(4)) or
- not match.group(2) and Search(r'\bfor\s*\(.*; \)', line)):
- error(filename, linenum, 'whitespace/parens', 5,
- 'Mismatching spaces inside () in %s' % match.group(1))
- if not len(match.group(2)) in [0, 1]:
- error(filename, linenum, 'whitespace/parens', 5,
- 'Should have zero or one spaces inside ( and ) in %s' %
- match.group(1))
-
- # You should always have a space after a comma (either as fn arg or operator)
- if Search(r',[^\s]', line):
- error(filename, linenum, 'whitespace/comma', 3,
- 'Missing space after ,')
-
- # You should always have a space after a semicolon
- # except for few corner cases
- # TODO(unknown): clarify if 'if (1) { return 1;}' is requires one more
- # space after ;
- if Search(r';[^\s};\\)/]', line):
- error(filename, linenum, 'whitespace/semicolon', 3,
- 'Missing space after ;')
-
- # Next we will look for issues with function calls.
- CheckSpacingForFunctionCall(filename, line, linenum, error)
-
- # Except after an opening paren, or after another opening brace (in case of
- # an initializer list, for instance), you should have spaces before your
- # braces. And since you should never have braces at the beginning of a line,
- # this is an easy test.
- if Search(r'[^ ({]{', line):
- error(filename, linenum, 'whitespace/braces', 5,
- 'Missing space before {')
-
- # Make sure '} else {' has spaces.
- if Search(r'}else', line):
- error(filename, linenum, 'whitespace/braces', 5,
- 'Missing space before else')
-
- # You shouldn't have spaces before your brackets, except maybe after
- # 'delete []' or 'new char * []'.
- if Search(r'\w\s+\[', line) and not Search(r'delete\s+\[', line):
- error(filename, linenum, 'whitespace/braces', 5,
- 'Extra space before [')
-
- # You shouldn't have a space before a semicolon at the end of the line.
- # There's a special case for "for" since the style guide allows space before
- # the semicolon there.
- if Search(r':\s*;\s*$', line):
- error(filename, linenum, 'whitespace/semicolon', 5,
- 'Semicolon defining empty statement. Use {} instead.')
- elif Search(r'^\s*;\s*$', line):
- error(filename, linenum, 'whitespace/semicolon', 5,
- 'Line contains only semicolon. If this should be an empty statement, '
- 'use {} instead.')
- elif (Search(r'\s+;\s*$', line) and
- not Search(r'\bfor\b', line)):
- error(filename, linenum, 'whitespace/semicolon', 5,
- 'Extra space before last semicolon. If this should be an empty '
- 'statement, use {} instead.')
-
- # In range-based for, we wanted spaces before and after the colon, but
- # not around "::" tokens that might appear.
- if (Search('for *\(.*[^:]:[^: ]', line) or
- Search('for *\(.*[^: ]:[^:]', line)):
- error(filename, linenum, 'whitespace/forcolon', 2,
- 'Missing space around colon in range-based for loop')
-
-
-def CheckSectionSpacing(filename, clean_lines, class_info, linenum, error):
- """Checks for additional blank line issues related to sections.
-
- Currently the only thing checked here is blank line before protected/private.
-
- Args:
- filename: The name of the current file.
- clean_lines: A CleansedLines instance containing the file.
- class_info: A _ClassInfo objects.
- linenum: The number of the line to check.
- error: The function to call with any errors found.
- """
- # Skip checks if the class is small, where small means 25 lines or less.
- # 25 lines seems like a good cutoff since that's the usual height of
- # terminals, and any class that can't fit in one screen can't really
- # be considered "small".
- #
- # Also skip checks if we are on the first line. This accounts for
- # classes that look like
- # class Foo { public: ... };
- #
- # If we didn't find the end of the class, last_line would be zero,
- # and the check will be skipped by the first condition.
- if (class_info.last_line - class_info.starting_linenum <= 24 or
- linenum <= class_info.starting_linenum):
- return
-
- matched = Match(r'\s*(public|protected|private):', clean_lines.lines[linenum])
- if matched:
- # Issue warning if the line before public/protected/private was
- # not a blank line, but don't do this if the previous line contains
- # "class" or "struct". This can happen two ways:
- # - We are at the beginning of the class.
- # - We are forward-declaring an inner class that is semantically
- # private, but needed to be public for implementation reasons.
- # Also ignores cases where the previous line ends with a backslash as can be
- # common when defining classes in C macros.
- prev_line = clean_lines.lines[linenum - 1]
- if (not IsBlankLine(prev_line) and
- not Search(r'\b(class|struct)\b', prev_line) and
- not Search(r'\\$', prev_line)):
- # Try a bit harder to find the beginning of the class. This is to
- # account for multi-line base-specifier lists, e.g.:
- # class Derived
- # : public Base {
- end_class_head = class_info.starting_linenum
- for i in range(class_info.starting_linenum, linenum):
- if Search(r'\{\s*$', clean_lines.lines[i]):
- end_class_head = i
- break
- if end_class_head < linenum - 1:
- error(filename, linenum, 'whitespace/blank_line', 3,
- '"%s:" should be preceded by a blank line' % matched.group(1))
-
-
-def GetPreviousNonBlankLine(clean_lines, linenum):
- """Return the most recent non-blank line and its line number.
-
- Args:
- clean_lines: A CleansedLines instance containing the file contents.
- linenum: The number of the line to check.
-
- Returns:
- A tuple with two elements. The first element is the contents of the last
- non-blank line before the current line, or the empty string if this is the
- first non-blank line. The second is the line number of that line, or -1
- if this is the first non-blank line.
- """
-
- prevlinenum = linenum - 1
- while prevlinenum >= 0:
- prevline = clean_lines.elided[prevlinenum]
- if not IsBlankLine(prevline): # if not a blank line...
- return (prevline, prevlinenum)
- prevlinenum -= 1
- return ('', -1)
-
-
-def CheckBraces(filename, clean_lines, linenum, error):
- """Looks for misplaced braces (e.g. at the end of line).
-
- Args:
- filename: The name of the current file.
- clean_lines: A CleansedLines instance containing the file.
- linenum: The number of the line to check.
- error: The function to call with any errors found.
- """
-
- line = clean_lines.elided[linenum] # get rid of comments and strings
-
- if Match(r'\s*{\s*$', line):
- # We allow an open brace to start a line in the case where someone
- # is using braces in a block to explicitly create a new scope,
- # which is commonly used to control the lifetime of
- # stack-allocated variables. We don't detect this perfectly: we
- # just don't complain if the last non-whitespace character on the
- # previous non-blank line is ';', ':', '{', or '}', or if the previous
- # line starts a preprocessor block.
- prevline = GetPreviousNonBlankLine(clean_lines, linenum)[0]
- if (not Search(r'[;:}{]\s*$', prevline) and
- not Match(r'\s*#', prevline)):
- error(filename, linenum, 'whitespace/braces', 4,
- '{ should almost always be at the end of the previous line')
-
- # An else clause should be on the same line as the preceding closing brace.
- if Match(r'\s*else\s*', line):
- prevline = GetPreviousNonBlankLine(clean_lines, linenum)[0]
- if Match(r'\s*}\s*$', prevline):
- error(filename, linenum, 'whitespace/newline', 4,
- 'An else should appear on the same line as the preceding }')
-
- # If braces come on one side of an else, they should be on both.
- # However, we have to worry about "else if" that spans multiple lines!
- if Search(r'}\s*else[^{]*$', line) or Match(r'[^}]*else\s*{', line):
- if Search(r'}\s*else if([^{]*)$', line): # could be multi-line if
- # find the ( after the if
- pos = line.find('else if')
- pos = line.find('(', pos)
- if pos > 0:
- (endline, _, endpos) = CloseExpression(clean_lines, linenum, pos)
- if endline[endpos:].find('{') == -1: # must be brace after if
- error(filename, linenum, 'readability/braces', 5,
- 'If an else has a brace on one side, it should have it on both')
- else: # common case: else not followed by a multi-line if
- error(filename, linenum, 'readability/braces', 5,
- 'If an else has a brace on one side, it should have it on both')
-
- # Likewise, an else should never have the else clause on the same line
- if Search(r'\belse [^\s{]', line) and not Search(r'\belse if\b', line):
- error(filename, linenum, 'whitespace/newline', 4,
- 'Else clause should never be on same line as else (use 2 lines)')
-
- # In the same way, a do/while should never be on one line
- if Match(r'\s*do [^\s{]', line):
- error(filename, linenum, 'whitespace/newline', 4,
- 'do/while clauses should not be on a single line')
-
- # Braces shouldn't be followed by a ; unless they're defining a struct
- # or initializing an array.
- # We can't tell in general, but we can for some common cases.
- prevlinenum = linenum
- while True:
- (prevline, prevlinenum) = GetPreviousNonBlankLine(clean_lines, prevlinenum)
- if Match(r'\s+{.*}\s*;', line) and not prevline.count(';'):
- line = prevline + line
- else:
- break
- if (Search(r'{.*}\s*;', line) and
- line.count('{') == line.count('}') and
- not Search(r'struct|class|enum|\s*=\s*{', line)):
- error(filename, linenum, 'readability/braces', 4,
- "You don't need a ; after a }")
-
-
-def CheckEmptyLoopBody(filename, clean_lines, linenum, error):
- """Loop for empty loop body with only a single semicolon.
-
- Args:
- filename: The name of the current file.
- clean_lines: A CleansedLines instance containing the file.
- linenum: The number of the line to check.
- error: The function to call with any errors found.
- """
-
- # Search for loop keywords at the beginning of the line. Because only
- # whitespaces are allowed before the keywords, this will also ignore most
- # do-while-loops, since those lines should start with closing brace.
- line = clean_lines.elided[linenum]
- if Match(r'\s*(for|while)\s*\(', line):
- # Find the end of the conditional expression
- (end_line, end_linenum, end_pos) = CloseExpression(
- clean_lines, linenum, line.find('('))
-
- # Output warning if what follows the condition expression is a semicolon.
- # No warning for all other cases, including whitespace or newline, since we
- # have a separate check for semicolons preceded by whitespace.
- if end_pos >= 0 and Match(r';', end_line[end_pos:]):
- error(filename, end_linenum, 'whitespace/empty_loop_body', 5,
- 'Empty loop bodies should use {} or continue')
-
-
-def ReplaceableCheck(operator, macro, line):
- """Determine whether a basic CHECK can be replaced with a more specific one.
-
- For example suggest using CHECK_EQ instead of CHECK(a == b) and
- similarly for CHECK_GE, CHECK_GT, CHECK_LE, CHECK_LT, CHECK_NE.
-
- Args:
- operator: The C++ operator used in the CHECK.
- macro: The CHECK or EXPECT macro being called.
- line: The current source line.
-
- Returns:
- True if the CHECK can be replaced with a more specific one.
- """
-
- # This matches decimal and hex integers, strings, and chars (in that order).
- match_constant = r'([-+]?(\d+|0[xX][0-9a-fA-F]+)[lLuU]{0,3}|".*"|\'.*\')'
-
- # Expression to match two sides of the operator with something that
- # looks like a literal, since CHECK(x == iterator) won't compile.
- # This means we can't catch all the cases where a more specific
- # CHECK is possible, but it's less annoying than dealing with
- # extraneous warnings.
- match_this = (r'\s*' + macro + r'\((\s*' +
- match_constant + r'\s*' + operator + r'[^<>].*|'
- r'.*[^<>]' + operator + r'\s*' + match_constant +
- r'\s*\))')
-
- # Don't complain about CHECK(x == NULL) or similar because
- # CHECK_EQ(x, NULL) won't compile (requires a cast).
- # Also, don't complain about more complex boolean expressions
- # involving && or || such as CHECK(a == b || c == d).
- return Match(match_this, line) and not Search(r'NULL|&&|\|\|', line)
-
-
-def CheckCheck(filename, clean_lines, linenum, error):
- """Checks the use of CHECK and EXPECT macros.
-
- Args:
- filename: The name of the current file.
- clean_lines: A CleansedLines instance containing the file.
- linenum: The number of the line to check.
- error: The function to call with any errors found.
- """
-
- # Decide the set of replacement macros that should be suggested
- raw_lines = clean_lines.raw_lines
- current_macro = ''
- for macro in _CHECK_MACROS:
- if raw_lines[linenum].find(macro) >= 0:
- current_macro = macro
- break
- if not current_macro:
- # Don't waste time here if line doesn't contain 'CHECK' or 'EXPECT'
- return
-
- line = clean_lines.elided[linenum] # get rid of comments and strings
-
- # Encourage replacing plain CHECKs with CHECK_EQ/CHECK_NE/etc.
- for operator in ['==', '!=', '>=', '>', '<=', '<']:
- if ReplaceableCheck(operator, current_macro, line):
- error(filename, linenum, 'readability/check', 2,
- 'Consider using %s instead of %s(a %s b)' % (
- _CHECK_REPLACEMENT[current_macro][operator],
- current_macro, operator))
- break
-
-
-def CheckAltTokens(filename, clean_lines, linenum, error):
- """Check alternative keywords being used in boolean expressions.
-
- Args:
- filename: The name of the current file.
- clean_lines: A CleansedLines instance containing the file.
- linenum: The number of the line to check.
- error: The function to call with any errors found.
- """
- line = clean_lines.elided[linenum]
-
- # Avoid preprocessor lines
- if Match(r'^\s*#', line):
- return
-
- # Last ditch effort to avoid multi-line comments. This will not help
- # if the comment started before the current line or ended after the
- # current line, but it catches most of the false positives. At least,
- # it provides a way to workaround this warning for people who use
- # multi-line comments in preprocessor macros.
- #
- # TODO(unknown): remove this once cpplint has better support for
- # multi-line comments.
- if line.find('/*') >= 0 or line.find('*/') >= 0:
- return
-
- for match in _ALT_TOKEN_REPLACEMENT_PATTERN.finditer(line):
- error(filename, linenum, 'readability/alt_tokens', 2,
- 'Use operator %s instead of %s' % (
- _ALT_TOKEN_REPLACEMENT[match.group(1)], match.group(1)))
-
-
-def GetLineWidth(line):
- """Determines the width of the line in column positions.
-
- Args:
- line: A string, which may be a Unicode string.
-
- Returns:
- The width of the line in column positions, accounting for Unicode
- combining characters and wide characters.
- """
- if isinstance(line, unicode):
- width = 0
- for uc in unicodedata.normalize('NFC', line):
- if unicodedata.east_asian_width(uc) in ('W', 'F'):
- width += 2
- elif not unicodedata.combining(uc):
- width += 1
- return width
- else:
- return len(line)
-
-
-def CheckStyle(filename, clean_lines, linenum, file_extension, nesting_state,
- error):
- """Checks rules from the 'C++ style rules' section of cppguide.html.
-
- Most of these rules are hard to test (naming, comment style), but we
- do what we can. In particular we check for 2-space indents, line lengths,
- tab usage, spaces inside code, etc.
-
- Args:
- filename: The name of the current file.
- clean_lines: A CleansedLines instance containing the file.
- linenum: The number of the line to check.
- file_extension: The extension (without the dot) of the filename.
- nesting_state: A _NestingState instance which maintains information about
- the current stack of nested blocks being parsed.
- error: The function to call with any errors found.
- """
-
- raw_lines = clean_lines.raw_lines
- line = raw_lines[linenum]
-
- if line.find('\t') != -1:
- error(filename, linenum, 'whitespace/tab', 1,
- 'Tab found; better to use spaces')
-
- # One or three blank spaces at the beginning of the line is weird; it's
- # hard to reconcile that with 2-space indents.
- # NOTE: here are the conditions rob pike used for his tests. Mine aren't
- # as sophisticated, but it may be worth becoming so: RLENGTH==initial_spaces
- # if(RLENGTH > 20) complain = 0;
- # if(match($0, " +(error|private|public|protected):")) complain = 0;
- # if(match(prev, "&& *$")) complain = 0;
- # if(match(prev, "\\|\\| *$")) complain = 0;
- # if(match(prev, "[\",=><] *$")) complain = 0;
- # if(match($0, " <<")) complain = 0;
- # if(match(prev, " +for \\(")) complain = 0;
- # if(prevodd && match(prevprev, " +for \\(")) complain = 0;
- initial_spaces = 0
- cleansed_line = clean_lines.elided[linenum]
- while initial_spaces < len(line) and line[initial_spaces] == ' ':
- initial_spaces += 1
- if line and line[-1].isspace():
- error(filename, linenum, 'whitespace/end_of_line', 4,
- 'Line ends in whitespace. Consider deleting these extra spaces.')
- # There are certain situations we allow one space, notably for labels
- elif ((initial_spaces == 1 or initial_spaces == 3) and
- not Match(r'\s*\w+\s*:\s*$', cleansed_line)):
- error(filename, linenum, 'whitespace/indent', 3,
- 'Weird number of spaces at line-start. '
- 'Are you using a 2-space indent?')
- # Labels should always be indented at least one space.
- elif not initial_spaces and line[:2] != '//' and Search(r'[^:]:\s*$',
- line):
- error(filename, linenum, 'whitespace/labels', 4,
- 'Labels should always be indented at least one space. '
- 'If this is a member-initializer list in a constructor or '
- 'the base class list in a class definition, the colon should '
- 'be on the following line.')
-
-
- # Check if the line is a header guard.
- is_header_guard = False
- if file_extension == 'h':
- cppvar = GetHeaderGuardCPPVariable(filename)
- if (line.startswith('#ifndef %s' % cppvar) or
- line.startswith('#define %s' % cppvar) or
- line.startswith('#endif // %s' % cppvar)):
- is_header_guard = True
- # #include lines and header guards can be long, since there's no clean way to
- # split them.
- #
- # URLs can be long too. It's possible to split these, but it makes them
- # harder to cut&paste.
- #
- # The "$Id:...$" comment may also get very long without it being the
- # developers fault.
- if (not line.startswith('#include') and not is_header_guard and
- not Match(r'^\s*//.*http(s?)://\S*$', line) and
- not Match(r'^// \$Id:.*#[0-9]+ \$$', line)):
- line_width = GetLineWidth(line)
- if line_width > 100:
- error(filename, linenum, 'whitespace/line_length', 4,
- 'Lines should very rarely be longer than 100 characters')
- elif line_width > 80:
- error(filename, linenum, 'whitespace/line_length', 2,
- 'Lines should be <= 80 characters long')
-
- if (cleansed_line.count(';') > 1 and
- # for loops are allowed two ;'s (and may run over two lines).
- cleansed_line.find('for') == -1 and
- (GetPreviousNonBlankLine(clean_lines, linenum)[0].find('for') == -1 or
- GetPreviousNonBlankLine(clean_lines, linenum)[0].find(';') != -1) and
- # It's ok to have many commands in a switch case that fits in 1 line
- not ((cleansed_line.find('case ') != -1 or
- cleansed_line.find('default:') != -1) and
- cleansed_line.find('break;') != -1)):
- error(filename, linenum, 'whitespace/newline', 0,
- 'More than one command on the same line')
-
- # Some more style checks
- CheckBraces(filename, clean_lines, linenum, error)
- CheckEmptyLoopBody(filename, clean_lines, linenum, error)
- CheckAccess(filename, clean_lines, linenum, nesting_state, error)
- CheckSpacing(filename, clean_lines, linenum, nesting_state, error)
- CheckCheck(filename, clean_lines, linenum, error)
- CheckAltTokens(filename, clean_lines, linenum, error)
- classinfo = nesting_state.InnermostClass()
- if classinfo:
- CheckSectionSpacing(filename, clean_lines, classinfo, linenum, error)
-
-
-_RE_PATTERN_INCLUDE_NEW_STYLE = re.compile(r'#include +"[^/]+\.h"')
-_RE_PATTERN_INCLUDE = re.compile(r'^\s*#\s*include\s*([<"])([^>"]*)[>"].*$')
-# Matches the first component of a filename delimited by -s and _s. That is:
-# _RE_FIRST_COMPONENT.match('foo').group(0) == 'foo'
-# _RE_FIRST_COMPONENT.match('foo.cc').group(0) == 'foo'
-# _RE_FIRST_COMPONENT.match('foo-bar_baz.cc').group(0) == 'foo'
-# _RE_FIRST_COMPONENT.match('foo_bar-baz.cc').group(0) == 'foo'
-_RE_FIRST_COMPONENT = re.compile(r'^[^-_.]+')
-
-
-def _DropCommonSuffixes(filename):
- """Drops common suffixes like _test.cc or -inl.h from filename.
-
- For example:
- >>> _DropCommonSuffixes('foo/foo-inl.h')
- 'foo/foo'
- >>> _DropCommonSuffixes('foo/bar/foo.cc')
- 'foo/bar/foo'
- >>> _DropCommonSuffixes('foo/foo_internal.h')
- 'foo/foo'
- >>> _DropCommonSuffixes('foo/foo_unusualinternal.h')
- 'foo/foo_unusualinternal'
-
- Args:
- filename: The input filename.
-
- Returns:
- The filename with the common suffix removed.
- """
- for suffix in ('test.cc', 'regtest.cc', 'unittest.cc',
- 'inl.h', 'impl.h', 'internal.h'):
- if (filename.endswith(suffix) and len(filename) > len(suffix) and
- filename[-len(suffix) - 1] in ('-', '_')):
- return filename[:-len(suffix) - 1]
- return os.path.splitext(filename)[0]
-
-
-def _IsTestFilename(filename):
- """Determines if the given filename has a suffix that identifies it as a test.
-
- Args:
- filename: The input filename.
-
- Returns:
- True if 'filename' looks like a test, False otherwise.
- """
- if (filename.endswith('_test.cc') or
- filename.endswith('_unittest.cc') or
- filename.endswith('_regtest.cc')):
- return True
- else:
- return False
-
-
-def _ClassifyInclude(fileinfo, include, is_system):
- """Figures out what kind of header 'include' is.
-
- Args:
- fileinfo: The current file cpplint is running over. A FileInfo instance.
- include: The path to a #included file.
- is_system: True if the #include used <> rather than "".
-
- Returns:
- One of the _XXX_HEADER constants.
-
- For example:
- >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'stdio.h', True)
- _C_SYS_HEADER
- >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'string', True)
- _CPP_SYS_HEADER
- >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'foo/foo.h', False)
- _LIKELY_MY_HEADER
- >>> _ClassifyInclude(FileInfo('foo/foo_unknown_extension.cc'),
- ... 'bar/foo_other_ext.h', False)
- _POSSIBLE_MY_HEADER
- >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'foo/bar.h', False)
- _OTHER_HEADER
- """
- # This is a list of all standard c++ header files, except
- # those already checked for above.
- is_stl_h = include in _STL_HEADERS
- is_cpp_h = is_stl_h or include in _CPP_HEADERS
-
- if is_system:
- if is_cpp_h:
- return _CPP_SYS_HEADER
- else:
- return _C_SYS_HEADER
-
- # If the target file and the include we're checking share a
- # basename when we drop common extensions, and the include
- # lives in . , then it's likely to be owned by the target file.
- target_dir, target_base = (
- os.path.split(_DropCommonSuffixes(fileinfo.RepositoryName())))
- include_dir, include_base = os.path.split(_DropCommonSuffixes(include))
- if target_base == include_base and (
- include_dir == target_dir or
- include_dir == os.path.normpath(target_dir + '/../public')):
- return _LIKELY_MY_HEADER
-
- # If the target and include share some initial basename
- # component, it's possible the target is implementing the
- # include, so it's allowed to be first, but we'll never
- # complain if it's not there.
- target_first_component = _RE_FIRST_COMPONENT.match(target_base)
- include_first_component = _RE_FIRST_COMPONENT.match(include_base)
- if (target_first_component and include_first_component and
- target_first_component.group(0) ==
- include_first_component.group(0)):
- return _POSSIBLE_MY_HEADER
-
- return _OTHER_HEADER
-
-
-
-def CheckIncludeLine(filename, clean_lines, linenum, include_state, error):
- """Check rules that are applicable to #include lines.
-
- Strings on #include lines are NOT removed from elided line, to make
- certain tasks easier. However, to prevent false positives, checks
- applicable to #include lines in CheckLanguage must be put here.
-
- Args:
- filename: The name of the current file.
- clean_lines: A CleansedLines instance containing the file.
- linenum: The number of the line to check.
- include_state: An _IncludeState instance in which the headers are inserted.
- error: The function to call with any errors found.
- """
- fileinfo = FileInfo(filename)
-
- line = clean_lines.lines[linenum]
-
- # "include" should use the new style "foo/bar.h" instead of just "bar.h"
- if _RE_PATTERN_INCLUDE_NEW_STYLE.search(line):
- error(filename, linenum, 'build/include', 4,
- 'Include the directory when naming .h files')
-
- # we shouldn't include a file more than once. actually, there are a
- # handful of instances where doing so is okay, but in general it's
- # not.
- match = _RE_PATTERN_INCLUDE.search(line)
- if match:
- include = match.group(2)
- is_system = (match.group(1) == '<')
- if include in include_state:
- error(filename, linenum, 'build/include', 4,
- '"%s" already included at %s:%s' %
- (include, filename, include_state[include]))
- else:
- include_state[include] = linenum
-
- # We want to ensure that headers appear in the right order:
- # 1) for foo.cc, foo.h (preferred location)
- # 2) c system files
- # 3) cpp system files
- # 4) for foo.cc, foo.h (deprecated location)
- # 5) other google headers
- #
- # We classify each include statement as one of those 5 types
- # using a number of techniques. The include_state object keeps
- # track of the highest type seen, and complains if we see a
- # lower type after that.
- error_message = include_state.CheckNextIncludeOrder(
- _ClassifyInclude(fileinfo, include, is_system))
- if error_message:
- error(filename, linenum, 'build/include_order', 4,
- '%s. Should be: %s.h, c system, c++ system, other.' %
- (error_message, fileinfo.BaseName()))
- if not include_state.IsInAlphabeticalOrder(include):
- error(filename, linenum, 'build/include_alpha', 4,
- 'Include "%s" not in alphabetical order' % include)
-
- # Look for any of the stream classes that are part of standard C++.
- match = _RE_PATTERN_INCLUDE.match(line)
- if match:
- include = match.group(2)
- if Match(r'(f|ind|io|i|o|parse|pf|stdio|str|)?stream$', include):
- # Many unit tests use cout, so we exempt them.
- if not _IsTestFilename(filename):
- error(filename, linenum, 'readability/streams', 3,
- 'Streams are highly discouraged.')
-
-
-def _GetTextInside(text, start_pattern):
- """Retrieves all the text between matching open and close parentheses.
-
- Given a string of lines and a regular expression string, retrieve all the text
- following the expression and between opening punctuation symbols like
- (, [, or {, and the matching close-punctuation symbol. This properly nested
- occurrences of the punctuations, so for the text like
- printf(a(), b(c()));
- a call to _GetTextInside(text, r'printf\(') will return 'a(), b(c())'.
- start_pattern must match string having an open punctuation symbol at the end.
-
- Args:
- text: The lines to extract text. Its comments and strings must be elided.
- It can be single line and can span multiple lines.
- start_pattern: The regexp string indicating where to start extracting
- the text.
- Returns:
- The extracted text.
- None if either the opening string or ending punctuation could not be found.
- """
- # TODO(sugawarayu): Audit cpplint.py to see what places could be profitably
- # rewritten to use _GetTextInside (and use inferior regexp matching today).
-
- # Give opening punctuations to get the matching close-punctuations.
- matching_punctuation = {'(': ')', '{': '}', '[': ']'}
- closing_punctuation = set(matching_punctuation.itervalues())
-
- # Find the position to start extracting text.
- match = re.search(start_pattern, text, re.M)
- if not match: # start_pattern not found in text.
- return None
- start_position = match.end(0)
-
- assert start_position > 0, (
- 'start_pattern must ends with an opening punctuation.')
- assert text[start_position - 1] in matching_punctuation, (
- 'start_pattern must ends with an opening punctuation.')
- # Stack of closing punctuations we expect to have in text after position.
- punctuation_stack = [matching_punctuation[text[start_position - 1]]]
- position = start_position
- while punctuation_stack and position < len(text):
- if text[position] == punctuation_stack[-1]:
- punctuation_stack.pop()
- elif text[position] in closing_punctuation:
- # A closing punctuation without matching opening punctuations.
- return None
- elif text[position] in matching_punctuation:
- punctuation_stack.append(matching_punctuation[text[position]])
- position += 1
- if punctuation_stack:
- # Opening punctuations left without matching close-punctuations.
- return None
- # punctuations match.
- return text[start_position:position - 1]
-
-
-def CheckLanguage(filename, clean_lines, linenum, file_extension, include_state,
- error):
- """Checks rules from the 'C++ language rules' section of cppguide.html.
-
- Some of these rules are hard to test (function overloading, using
- uint32 inappropriately), but we do the best we can.
-
- Args:
- filename: The name of the current file.
- clean_lines: A CleansedLines instance containing the file.
- linenum: The number of the line to check.
- file_extension: The extension (without the dot) of the filename.
- include_state: An _IncludeState instance in which the headers are inserted.
- error: The function to call with any errors found.
- """
- # If the line is empty or consists of entirely a comment, no need to
- # check it.
- line = clean_lines.elided[linenum]
- if not line:
- return
-
- match = _RE_PATTERN_INCLUDE.search(line)
- if match:
- CheckIncludeLine(filename, clean_lines, linenum, include_state, error)
- return
-
- # Create an extended_line, which is the concatenation of the current and
- # next lines, for more effective checking of code that may span more than one
- # line.
- if linenum + 1 < clean_lines.NumLines():
- extended_line = line + clean_lines.elided[linenum + 1]
- else:
- extended_line = line
-
- # Make Windows paths like Unix.
- fullname = os.path.abspath(filename).replace('\\', '/')
-
- # TODO(unknown): figure out if they're using default arguments in fn proto.
-
- # Check for non-const references in functions. This is tricky because &
- # is also used to take the address of something. We allow <> for templates,
- # (ignoring whatever is between the braces) and : for classes.
- # These are complicated re's. They try to capture the following:
- # paren (for fn-prototype start), typename, &, varname. For the const
- # version, we're willing for const to be before typename or after
- # Don't check the implementation on same line.
- fnline = line.split('{', 1)[0]
- if (len(re.findall(r'\([^()]*\b(?:[\w:]|<[^()]*>)+(\s?&|&\s?)\w+', fnline)) >
- len(re.findall(r'\([^()]*\bconst\s+(?:typename\s+)?(?:struct\s+)?'
- r'(?:[\w:]|<[^()]*>)+(\s?&|&\s?)\w+', fnline)) +
- len(re.findall(r'\([^()]*\b(?:[\w:]|<[^()]*>)+\s+const(\s?&|&\s?)[\w]+',
- fnline))):
-
- # We allow non-const references in a few standard places, like functions
- # called "swap()" or iostream operators like "<<" or ">>". We also filter
- # out for loops, which lint otherwise mistakenly thinks are functions.
- if not Search(
- r'(for|swap|Swap|operator[<>][<>])\s*\(\s*'
- r'(?:(?:typename\s*)?[\w:]|<.*>)+\s*&',
- fnline):
- error(filename, linenum, 'runtime/references', 2,
- 'Is this a non-const reference? '
- 'If so, make const or use a pointer.')
-
- # Check to see if they're using an conversion function cast.
- # I just try to capture the most common basic types, though there are more.
- # Parameterless conversion functions, such as bool(), are allowed as they are
- # probably a member operator declaration or default constructor.
- match = Search(
- r'(\bnew\s+)?\b' # Grab 'new' operator, if it's there
- r'(int|float|double|bool|char|int32|uint32|int64|uint64)\([^)]', line)
- if match:
- # gMock methods are defined using some variant of MOCK_METHODx(name, type)
- # where type may be float(), int(string), etc. Without context they are
- # virtually indistinguishable from int(x) casts. Likewise, gMock's
- # MockCallback takes a template parameter of the form return_type(arg_type),
- # which looks much like the cast we're trying to detect.
- if (match.group(1) is None and # If new operator, then this isn't a cast
- not (Match(r'^\s*MOCK_(CONST_)?METHOD\d+(_T)?\(', line) or
- Match(r'^\s*MockCallback<.*>', line))):
- # Try a bit harder to catch gmock lines: the only place where
- # something looks like an old-style cast is where we declare the
- # return type of the mocked method, and the only time when we
- # are missing context is if MOCK_METHOD was split across
- # multiple lines (for example http://go/hrfhr ), so we only need
- # to check the previous line for MOCK_METHOD.
- if (linenum == 0 or
- not Match(r'^\s*MOCK_(CONST_)?METHOD\d+(_T)?\(\S+,\s*$',
- clean_lines.elided[linenum - 1])):
- error(filename, linenum, 'readability/casting', 4,
- 'Using deprecated casting style. '
- 'Use static_cast<%s>(...) instead' %
- match.group(2))
-
- CheckCStyleCast(filename, linenum, line, clean_lines.raw_lines[linenum],
- 'static_cast',
- r'\((int|float|double|bool|char|u?int(16|32|64))\)', error)
-
- # This doesn't catch all cases. Consider (const char * const)"hello".
- #
- # (char *) "foo" should always be a const_cast (reinterpret_cast won't
- # compile).
- if CheckCStyleCast(filename, linenum, line, clean_lines.raw_lines[linenum],
- 'const_cast', r'\((char\s?\*+\s?)\)\s*"', error):
- pass
- else:
- # Check pointer casts for other than string constants
- CheckCStyleCast(filename, linenum, line, clean_lines.raw_lines[linenum],
- 'reinterpret_cast', r'\((\w+\s?\*+\s?)\)', error)
-
- # In addition, we look for people taking the address of a cast. This
- # is dangerous -- casts can assign to temporaries, so the pointer doesn't
- # point where you think.
- if Search(
- r'(&\([^)]+\)[\w(])|(&(static|dynamic|reinterpret)_cast\b)', line):
- error(filename, linenum, 'runtime/casting', 4,
- ('Are you taking an address of a cast? '
- 'This is dangerous: could be a temp var. '
- 'Take the address before doing the cast, rather than after'))
-
- # Check for people declaring static/global STL strings at the top level.
- # This is dangerous because the C++ language does not guarantee that
- # globals with constructors are initialized before the first access.
- match = Match(
- r'((?:|static +)(?:|const +))string +([a-zA-Z0-9_:]+)\b(.*)',
- line)
- # Make sure it's not a function.
- # Function template specialization looks like: "string foo<Type>(...".
- # Class template definitions look like: "string Foo<Type>::Method(...".
- if match and not Match(r'\s*(<.*>)?(::[a-zA-Z0-9_]+)?\s*\(([^"]|$)',
- match.group(3)):
- error(filename, linenum, 'runtime/string', 4,
- 'For a static/global string constant, use a C style string instead: '
- '"%schar %s[]".' %
- (match.group(1), match.group(2)))
-
- # Check that we're not using RTTI outside of testing code.
- if Search(r'\bdynamic_cast<', line) and not _IsTestFilename(filename):
- error(filename, linenum, 'runtime/rtti', 5,
- 'Do not use dynamic_cast<>. If you need to cast within a class '
- "hierarchy, use static_cast<> to upcast. Google doesn't support "
- 'RTTI.')
-
- if Search(r'\b([A-Za-z0-9_]*_)\(\1\)', line):
- error(filename, linenum, 'runtime/init', 4,
- 'You seem to be initializing a member variable with itself.')
-
- if file_extension == 'h':
- # TODO(unknown): check that 1-arg constructors are explicit.
- # How to tell it's a constructor?
- # (handled in CheckForNonStandardConstructs for now)
- # TODO(unknown): check that classes have DISALLOW_EVIL_CONSTRUCTORS
- # (level 1 error)
- pass
-
- # Check if people are using the verboten C basic types. The only exception
- # we regularly allow is "unsigned short port" for port.
- if Search(r'\bshort port\b', line):
- if not Search(r'\bunsigned short port\b', line):
- error(filename, linenum, 'runtime/int', 4,
- 'Use "unsigned short" for ports, not "short"')
- else:
- match = Search(r'\b(short|long(?! +double)|long long)\b', line)
- if match:
- error(filename, linenum, 'runtime/int', 4,
- 'Use int16/int64/etc, rather than the C type %s' % match.group(1))
-
- # When snprintf is used, the second argument shouldn't be a literal.
- match = Search(r'snprintf\s*\(([^,]*),\s*([0-9]*)\s*,', line)
- if match and match.group(2) != '0':
- # If 2nd arg is zero, snprintf is used to calculate size.
- error(filename, linenum, 'runtime/printf', 3,
- 'If you can, use sizeof(%s) instead of %s as the 2nd arg '
- 'to snprintf.' % (match.group(1), match.group(2)))
-
- # Check if some verboten C functions are being used.
- if Search(r'\bsprintf\b', line):
- error(filename, linenum, 'runtime/printf', 5,
- 'Never use sprintf. Use snprintf instead.')
- match = Search(r'\b(strcpy|strcat)\b', line)
- if match:
- error(filename, linenum, 'runtime/printf', 4,
- 'Almost always, snprintf is better than %s' % match.group(1))
-
- if Search(r'\bsscanf\b', line):
- error(filename, linenum, 'runtime/printf', 1,
- 'sscanf can be ok, but is slow and can overflow buffers.')
-
- # Check if some verboten operator overloading is going on
- # TODO(unknown): catch out-of-line unary operator&:
- # class X {};
- # int operator&(const X& x) { return 42; } // unary operator&
- # The trick is it's hard to tell apart from binary operator&:
- # class Y { int operator&(const Y& x) { return 23; } }; // binary operator&
- if Search(r'\boperator\s*&\s*\(\s*\)', line):
- error(filename, linenum, 'runtime/operator', 4,
- 'Unary operator& is dangerous. Do not use it.')
-
- # Check for suspicious usage of "if" like
- # } if (a == b) {
- if Search(r'\}\s*if\s*\(', line):
- error(filename, linenum, 'readability/braces', 4,
- 'Did you mean "else if"? If not, start a new line for "if".')
-
- # Check for potential format string bugs like printf(foo).
- # We constrain the pattern not to pick things like DocidForPrintf(foo).
- # Not perfect but it can catch printf(foo.c_str()) and printf(foo->c_str())
- # TODO(sugawarayu): Catch the following case. Need to change the calling
- # convention of the whole function to process multiple line to handle it.
- # printf(
- # boy_this_is_a_really_long_variable_that_cannot_fit_on_the_prev_line);
- printf_args = _GetTextInside(line, r'(?i)\b(string)?printf\s*\(')
- if printf_args:
- match = Match(r'([\w.\->()]+)$', printf_args)
- if match and match.group(1) != '__VA_ARGS__':
- function_name = re.search(r'\b((?:string)?printf)\s*\(',
- line, re.I).group(1)
- error(filename, linenum, 'runtime/printf', 4,
- 'Potential format string bug. Do %s("%%s", %s) instead.'
- % (function_name, match.group(1)))
-
- # Check for potential memset bugs like memset(buf, sizeof(buf), 0).
- match = Search(r'memset\s*\(([^,]*),\s*([^,]*),\s*0\s*\)', line)
- if match and not Match(r"^''|-?[0-9]+|0x[0-9A-Fa-f]$", match.group(2)):
- error(filename, linenum, 'runtime/memset', 4,
- 'Did you mean "memset(%s, 0, %s)"?'
- % (match.group(1), match.group(2)))
-
- if Search(r'\busing namespace\b', line):
- error(filename, linenum, 'build/namespaces', 5,
- 'Do not use namespace using-directives. '
- 'Use using-declarations instead.')
-
- # Detect variable-length arrays.
- match = Match(r'\s*(.+::)?(\w+) [a-z]\w*\[(.+)];', line)
- if (match and match.group(2) != 'return' and match.group(2) != 'delete' and
- match.group(3).find(']') == -1):
- # Split the size using space and arithmetic operators as delimiters.
- # If any of the resulting tokens are not compile time constants then
- # report the error.
- tokens = re.split(r'\s|\+|\-|\*|\/|<<|>>]', match.group(3))
- is_const = True
- skip_next = False
- for tok in tokens:
- if skip_next:
- skip_next = False
- continue
-
- if Search(r'sizeof\(.+\)', tok): continue
- if Search(r'arraysize\(\w+\)', tok): continue
-
- tok = tok.lstrip('(')
- tok = tok.rstrip(')')
- if not tok: continue
- if Match(r'\d+', tok): continue
- if Match(r'0[xX][0-9a-fA-F]+', tok): continue
- if Match(r'k[A-Z0-9]\w*', tok): continue
- if Match(r'(.+::)?k[A-Z0-9]\w*', tok): continue
- if Match(r'(.+::)?[A-Z][A-Z0-9_]*', tok): continue
- # A catch all for tricky sizeof cases, including 'sizeof expression',
- # 'sizeof(*type)', 'sizeof(const type)', 'sizeof(struct StructName)'
- # requires skipping the next token because we split on ' ' and '*'.
- if tok.startswith('sizeof'):
- skip_next = True
- continue
- is_const = False
- break
- if not is_const:
- error(filename, linenum, 'runtime/arrays', 1,
- 'Do not use variable-length arrays. Use an appropriately named '
- "('k' followed by CamelCase) compile-time constant for the size.")
-
- # If DISALLOW_EVIL_CONSTRUCTORS, DISALLOW_COPY_AND_ASSIGN, or
- # DISALLOW_IMPLICIT_CONSTRUCTORS is present, then it should be the last thing
- # in the class declaration.
- match = Match(
- (r'\s*'
- r'(DISALLOW_(EVIL_CONSTRUCTORS|COPY_AND_ASSIGN|IMPLICIT_CONSTRUCTORS))'
- r'\(.*\);$'),
- line)
- if match and linenum + 1 < clean_lines.NumLines():
- next_line = clean_lines.elided[linenum + 1]
- # We allow some, but not all, declarations of variables to be present
- # in the statement that defines the class. The [\w\*,\s]* fragment of
- # the regular expression below allows users to declare instances of
- # the class or pointers to instances, but not less common types such
- # as function pointers or arrays. It's a tradeoff between allowing
- # reasonable code and avoiding trying to parse more C++ using regexps.
- if not Search(r'^\s*}[\w\*,\s]*;', next_line):
- error(filename, linenum, 'readability/constructors', 3,
- match.group(1) + ' should be the last thing in the class')
-
- # Check for use of unnamed namespaces in header files. Registration
- # macros are typically OK, so we allow use of "namespace {" on lines
- # that end with backslashes.
- if (file_extension == 'h'
- and Search(r'\bnamespace\s*{', line)
- and line[-1] != '\\'):
- error(filename, linenum, 'build/namespaces', 4,
- 'Do not use unnamed namespaces in header files. See '
- 'http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Namespaces'
- ' for more information.')
-
-
-def CheckCStyleCast(filename, linenum, line, raw_line, cast_type, pattern,
- error):
- """Checks for a C-style cast by looking for the pattern.
-
- This also handles sizeof(type) warnings, due to similarity of content.
-
- Args:
- filename: The name of the current file.
- linenum: The number of the line to check.
- line: The line of code to check.
- raw_line: The raw line of code to check, with comments.
- cast_type: The string for the C++ cast to recommend. This is either
- reinterpret_cast, static_cast, or const_cast, depending.
- pattern: The regular expression used to find C-style casts.
- error: The function to call with any errors found.
-
- Returns:
- True if an error was emitted.
- False otherwise.
- """
- match = Search(pattern, line)
- if not match:
- return False
-
- # e.g., sizeof(int)
- sizeof_match = Match(r'.*sizeof\s*$', line[0:match.start(1) - 1])
- if sizeof_match:
- error(filename, linenum, 'runtime/sizeof', 1,
- 'Using sizeof(type). Use sizeof(varname) instead if possible')
- return True
-
- # operator++(int) and operator--(int)
- if (line[0:match.start(1) - 1].endswith(' operator++') or
- line[0:match.start(1) - 1].endswith(' operator--')):
- return False
-
- remainder = line[match.end(0):]
-
- # The close paren is for function pointers as arguments to a function.
- # eg, void foo(void (*bar)(int));
- # The semicolon check is a more basic function check; also possibly a
- # function pointer typedef.
- # eg, void foo(int); or void foo(int) const;
- # The equals check is for function pointer assignment.
- # eg, void *(*foo)(int) = ...
- # The > is for MockCallback<...> ...
- #
- # Right now, this will only catch cases where there's a single argument, and
- # it's unnamed. It should probably be expanded to check for multiple
- # arguments with some unnamed.
- function_match = Match(r'\s*(\)|=|(const)?\s*(;|\{|throw\(\)|>))', remainder)
- if function_match:
- if (not function_match.group(3) or
- function_match.group(3) == ';' or
- ('MockCallback<' not in raw_line and
- '/*' not in raw_line)):
- error(filename, linenum, 'readability/function', 3,
- 'All parameters should be named in a function')
- return True
-
- # At this point, all that should be left is actual casts.
- error(filename, linenum, 'readability/casting', 4,
- 'Using C-style cast. Use %s<%s>(...) instead' %
- (cast_type, match.group(1)))
-
- return True
-
-
-_HEADERS_CONTAINING_TEMPLATES = (
- ('<deque>', ('deque',)),
- ('<functional>', ('unary_function', 'binary_function',
- 'plus', 'minus', 'multiplies', 'divides', 'modulus',
- 'negate',
- 'equal_to', 'not_equal_to', 'greater', 'less',
- 'greater_equal', 'less_equal',
- 'logical_and', 'logical_or', 'logical_not',
- 'unary_negate', 'not1', 'binary_negate', 'not2',
- 'bind1st', 'bind2nd',
- 'pointer_to_unary_function',
- 'pointer_to_binary_function',
- 'ptr_fun',
- 'mem_fun_t', 'mem_fun', 'mem_fun1_t', 'mem_fun1_ref_t',
- 'mem_fun_ref_t',
- 'const_mem_fun_t', 'const_mem_fun1_t',
- 'const_mem_fun_ref_t', 'const_mem_fun1_ref_t',
- 'mem_fun_ref',
- )),
- ('<limits>', ('numeric_limits',)),
- ('<list>', ('list',)),
- ('<map>', ('map', 'multimap',)),
- ('<memory>', ('allocator',)),
- ('<queue>', ('queue', 'priority_queue',)),
- ('<set>', ('set', 'multiset',)),
- ('<stack>', ('stack',)),
- ('<string>', ('char_traits', 'basic_string',)),
- ('<utility>', ('pair',)),
- ('<vector>', ('vector',)),
-
- # gcc extensions.
- # Note: std::hash is their hash, ::hash is our hash
- ('<hash_map>', ('hash_map', 'hash_multimap',)),
- ('<hash_set>', ('hash_set', 'hash_multiset',)),
- ('<slist>', ('slist',)),
- )
-
-_RE_PATTERN_STRING = re.compile(r'\bstring\b')
-
-_re_pattern_algorithm_header = []
-for _template in ('copy', 'max', 'min', 'min_element', 'sort', 'swap',
- 'transform'):
- # Match max<type>(..., ...), max(..., ...), but not foo->max, foo.max or
- # type::max().
- _re_pattern_algorithm_header.append(
- (re.compile(r'[^>.]\b' + _template + r'(<.*?>)?\([^\)]'),
- _template,
- '<algorithm>'))
-
-_re_pattern_templates = []
-for _header, _templates in _HEADERS_CONTAINING_TEMPLATES:
- for _template in _templates:
- _re_pattern_templates.append(
- (re.compile(r'(\<|\b)' + _template + r'\s*\<'),
- _template + '<>',
- _header))
-
-
-def FilesBelongToSameModule(filename_cc, filename_h):
- """Check if these two filenames belong to the same module.
-
- The concept of a 'module' here is a as follows:
- foo.h, foo-inl.h, foo.cc, foo_test.cc and foo_unittest.cc belong to the
- same 'module' if they are in the same directory.
- some/path/public/xyzzy and some/path/internal/xyzzy are also considered
- to belong to the same module here.
-
- If the filename_cc contains a longer path than the filename_h, for example,
- '/absolute/path/to/base/sysinfo.cc', and this file would include
- 'base/sysinfo.h', this function also produces the prefix needed to open the
- header. This is used by the caller of this function to more robustly open the
- header file. We don't have access to the real include paths in this context,
- so we need this guesswork here.
-
- Known bugs: tools/base/bar.cc and base/bar.h belong to the same module
- according to this implementation. Because of this, this function gives
- some false positives. This should be sufficiently rare in practice.
-
- Args:
- filename_cc: is the path for the .cc file
- filename_h: is the path for the header path
-
- Returns:
- Tuple with a bool and a string:
- bool: True if filename_cc and filename_h belong to the same module.
- string: the additional prefix needed to open the header file.
- """
-
- if not filename_cc.endswith('.cc'):
- return (False, '')
- filename_cc = filename_cc[:-len('.cc')]
- if filename_cc.endswith('_unittest'):
- filename_cc = filename_cc[:-len('_unittest')]
- elif filename_cc.endswith('_test'):
- filename_cc = filename_cc[:-len('_test')]
- filename_cc = filename_cc.replace('/public/', '/')
- filename_cc = filename_cc.replace('/internal/', '/')
-
- if not filename_h.endswith('.h'):
- return (False, '')
- filename_h = filename_h[:-len('.h')]
- if filename_h.endswith('-inl'):
- filename_h = filename_h[:-len('-inl')]
- filename_h = filename_h.replace('/public/', '/')
- filename_h = filename_h.replace('/internal/', '/')
-
- files_belong_to_same_module = filename_cc.endswith(filename_h)
- common_path = ''
- if files_belong_to_same_module:
- common_path = filename_cc[:-len(filename_h)]
- return files_belong_to_same_module, common_path
-
-
-def UpdateIncludeState(filename, include_state, io=codecs):
- """Fill up the include_state with new includes found from the file.
-
- Args:
- filename: the name of the header to read.
- include_state: an _IncludeState instance in which the headers are inserted.
- io: The io factory to use to read the file. Provided for testability.
-
- Returns:
- True if a header was successfully added. False otherwise.
- """
- headerfile = None
- try:
- headerfile = io.open(filename, 'r', 'utf8', 'replace')
- except IOError:
- return False
- linenum = 0
- for line in headerfile:
- linenum += 1
- clean_line = CleanseComments(line)
- match = _RE_PATTERN_INCLUDE.search(clean_line)
- if match:
- include = match.group(2)
- # The value formatting is cute, but not really used right now.
- # What matters here is that the key is in include_state.
- include_state.setdefault(include, '%s:%d' % (filename, linenum))
- return True
-
-
-def CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error,
- io=codecs):
- """Reports for missing stl includes.
-
- This function will output warnings to make sure you are including the headers
- necessary for the stl containers and functions that you use. We only give one
- reason to include a header. For example, if you use both equal_to<> and
- less<> in a .h file, only one (the latter in the file) of these will be
- reported as a reason to include the <functional>.
-
- Args:
- filename: The name of the current file.
- clean_lines: A CleansedLines instance containing the file.
- include_state: An _IncludeState instance.
- error: The function to call with any errors found.
- io: The IO factory to use to read the header file. Provided for unittest
- injection.
- """
- required = {} # A map of header name to linenumber and the template entity.
- # Example of required: { '<functional>': (1219, 'less<>') }
-
- for linenum in xrange(clean_lines.NumLines()):
- line = clean_lines.elided[linenum]
- if not line or line[0] == '#':
- continue
-
- # String is special -- it is a non-templatized type in STL.
- matched = _RE_PATTERN_STRING.search(line)
- if matched:
- # Don't warn about strings in non-STL namespaces:
- # (We check only the first match per line; good enough.)
- prefix = line[:matched.start()]
- if prefix.endswith('std::') or not prefix.endswith('::'):
- required['<string>'] = (linenum, 'string')
-
- for pattern, template, header in _re_pattern_algorithm_header:
- if pattern.search(line):
- required[header] = (linenum, template)
-
- # The following function is just a speed up, no semantics are changed.
- if not '<' in line: # Reduces the cpu time usage by skipping lines.
- continue
-
- for pattern, template, header in _re_pattern_templates:
- if pattern.search(line):
- required[header] = (linenum, template)
-
- # The policy is that if you #include something in foo.h you don't need to
- # include it again in foo.cc. Here, we will look at possible includes.
- # Let's copy the include_state so it is only messed up within this function.
- include_state = include_state.copy()
-
- # Did we find the header for this file (if any) and successfully load it?
- header_found = False
-
- # Use the absolute path so that matching works properly.
- abs_filename = FileInfo(filename).FullName()
-
- # For Emacs's flymake.
- # If cpplint is invoked from Emacs's flymake, a temporary file is generated
- # by flymake and that file name might end with '_flymake.cc'. In that case,
- # restore original file name here so that the corresponding header file can be
- # found.
- # e.g. If the file name is 'foo_flymake.cc', we should search for 'foo.h'
- # instead of 'foo_flymake.h'
- abs_filename = re.sub(r'_flymake\.cc$', '.cc', abs_filename)
-
- # include_state is modified during iteration, so we iterate over a copy of
- # the keys.
- header_keys = include_state.keys()
- for header in header_keys:
- (same_module, common_path) = FilesBelongToSameModule(abs_filename, header)
- fullpath = common_path + header
- if same_module and UpdateIncludeState(fullpath, include_state, io):
- header_found = True
-
- # If we can't find the header file for a .cc, assume it's because we don't
- # know where to look. In that case we'll give up as we're not sure they
- # didn't include it in the .h file.
- # TODO(unknown): Do a better job of finding .h files so we are confident that
- # not having the .h file means there isn't one.
- if filename.endswith('.cc') and not header_found:
- return
-
- # All the lines have been processed, report the errors found.
- for required_header_unstripped in required:
- template = required[required_header_unstripped][1]
- if required_header_unstripped.strip('<>"') not in include_state:
- error(filename, required[required_header_unstripped][0],
- 'build/include_what_you_use', 4,
- 'Add #include ' + required_header_unstripped + ' for ' + template)
-
-
-_RE_PATTERN_EXPLICIT_MAKEPAIR = re.compile(r'\bmake_pair\s*<')
-
-
-def CheckMakePairUsesDeduction(filename, clean_lines, linenum, error):
- """Check that make_pair's template arguments are deduced.
-
- G++ 4.6 in C++0x mode fails badly if make_pair's template arguments are
- specified explicitly, and such use isn't intended in any case.
-
- Args:
- filename: The name of the current file.
- clean_lines: A CleansedLines instance containing the file.
- linenum: The number of the line to check.
- error: The function to call with any errors found.
- """
- raw = clean_lines.raw_lines
- line = raw[linenum]
- match = _RE_PATTERN_EXPLICIT_MAKEPAIR.search(line)
- if match:
- error(filename, linenum, 'build/explicit_make_pair',
- 4, # 4 = high confidence
- 'For C++11-compatibility, omit template arguments from make_pair'
- ' OR use pair directly OR if appropriate, construct a pair directly')
-
-
-def ProcessLine(filename, file_extension, clean_lines, line,
- include_state, function_state, nesting_state, error,
- extra_check_functions=[]):
- """Processes a single line in the file.
-
- Args:
- filename: Filename of the file that is being processed.
- file_extension: The extension (dot not included) of the file.
- clean_lines: An array of strings, each representing a line of the file,
- with comments stripped.
- line: Number of line being processed.
- include_state: An _IncludeState instance in which the headers are inserted.
- function_state: A _FunctionState instance which counts function lines, etc.
- nesting_state: A _NestingState instance which maintains information about
- the current stack of nested blocks being parsed.
- error: A callable to which errors are reported, which takes 4 arguments:
- filename, line number, error level, and message
- extra_check_functions: An array of additional check functions that will be
- run on each source line. Each function takes 4
- arguments: filename, clean_lines, line, error
- """
- raw_lines = clean_lines.raw_lines
- ParseNolintSuppressions(filename, raw_lines[line], line, error)
- nesting_state.Update(filename, clean_lines, line, error)
- if nesting_state.stack and nesting_state.stack[-1].inline_asm != _NO_ASM:
- return
- CheckForFunctionLengths(filename, clean_lines, line, function_state, error)
- CheckForMultilineCommentsAndStrings(filename, clean_lines, line, error)
- CheckStyle(filename, clean_lines, line, file_extension, nesting_state, error)
- CheckLanguage(filename, clean_lines, line, file_extension, include_state,
- error)
- CheckForNonStandardConstructs(filename, clean_lines, line,
- nesting_state, error)
- CheckPosixThreading(filename, clean_lines, line, error)
- CheckInvalidIncrement(filename, clean_lines, line, error)
- CheckMakePairUsesDeduction(filename, clean_lines, line, error)
- for check_fn in extra_check_functions:
- check_fn(filename, clean_lines, line, error)
-
-def ProcessFileData(filename, file_extension, lines, error,
- extra_check_functions=[]):
- """Performs lint checks and reports any errors to the given error function.
-
- Args:
- filename: Filename of the file that is being processed.
- file_extension: The extension (dot not included) of the file.
- lines: An array of strings, each representing a line of the file, with the
- last element being empty if the file is terminated with a newline.
- error: A callable to which errors are reported, which takes 4 arguments:
- filename, line number, error level, and message
- extra_check_functions: An array of additional check functions that will be
- run on each source line. Each function takes 4
- arguments: filename, clean_lines, line, error
- """
- lines = (['// marker so line numbers and indices both start at 1'] + lines +
- ['// marker so line numbers end in a known way'])
-
- include_state = _IncludeState()
- function_state = _FunctionState()
- nesting_state = _NestingState()
-
- ResetNolintSuppressions()
-
- CheckForCopyright(filename, lines, error)
-
- if file_extension == 'h':
- CheckForHeaderGuard(filename, lines, error)
-
- RemoveMultiLineComments(filename, lines, error)
- clean_lines = CleansedLines(lines)
- for line in xrange(clean_lines.NumLines()):
- ProcessLine(filename, file_extension, clean_lines, line,
- include_state, function_state, nesting_state, error,
- extra_check_functions)
- nesting_state.CheckClassFinished(filename, error)
-
- CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error)
-
- # We check here rather than inside ProcessLine so that we see raw
- # lines rather than "cleaned" lines.
- CheckForUnicodeReplacementCharacters(filename, lines, error)
-
- CheckForNewlineAtEOF(filename, lines, error)
-
-def ProcessFile(filename, vlevel, extra_check_functions=[]):
- """Does google-lint on a single file.
-
- Args:
- filename: The name of the file to parse.
-
- vlevel: The level of errors to report. Every error of confidence
- >= verbose_level will be reported. 0 is a good default.
-
- extra_check_functions: An array of additional check functions that will be
- run on each source line. Each function takes 4
- arguments: filename, clean_lines, line, error
- """
-
- _SetVerboseLevel(vlevel)
-
- try:
- # Support the UNIX convention of using "-" for stdin. Note that
- # we are not opening the file with universal newline support
- # (which codecs doesn't support anyway), so the resulting lines do
- # contain trailing '\r' characters if we are reading a file that
- # has CRLF endings.
- # If after the split a trailing '\r' is present, it is removed
- # below. If it is not expected to be present (i.e. os.linesep !=
- # '\r\n' as in Windows), a warning is issued below if this file
- # is processed.
-
- if filename == '-':
- lines = codecs.StreamReaderWriter(sys.stdin,
- codecs.getreader('utf8'),
- codecs.getwriter('utf8'),
- 'replace').read().split('\n')
- else:
- lines = codecs.open(filename, 'r', 'utf8', 'replace').read().split('\n')
-
- carriage_return_found = False
- # Remove trailing '\r'.
- for linenum in range(len(lines)):
- if lines[linenum].endswith('\r'):
- lines[linenum] = lines[linenum].rstrip('\r')
- carriage_return_found = True
-
- except IOError:
- sys.stderr.write(
- "Skipping input '%s': Can't open for reading\n" % filename)
- return
-
- # Note, if no dot is found, this will give the entire filename as the ext.
- file_extension = filename[filename.rfind('.') + 1:]
-
- # When reading from stdin, the extension is unknown, so no cpplint tests
- # should rely on the extension.
- if (filename != '-' and file_extension != 'cc' and file_extension != 'h'
- and file_extension != 'cpp'):
- sys.stderr.write('Ignoring %s; not a .cc or .h file\n' % filename)
- else:
- ProcessFileData(filename, file_extension, lines, Error,
- extra_check_functions)
- if carriage_return_found and os.linesep != '\r\n':
- # Use 0 for linenum since outputting only one error for potentially
- # several lines.
- Error(filename, 0, 'whitespace/newline', 1,
- 'One or more unexpected \\r (^M) found;'
- 'better to use only a \\n')
-
- sys.stderr.write('Done processing %s\n' % filename)
-
-
-def PrintUsage(message):
- """Prints a brief usage string and exits, optionally with an error message.
-
- Args:
- message: The optional error message.
- """
- sys.stderr.write(_USAGE)
- if message:
- sys.exit('\nFATAL ERROR: ' + message)
- else:
- sys.exit(1)
-
-
-def PrintCategories():
- """Prints a list of all the error-categories used by error messages.
-
- These are the categories used to filter messages via --filter.
- """
- sys.stderr.write(''.join(' %s\n' % cat for cat in _ERROR_CATEGORIES))
- sys.exit(0)
-
-
-def ParseArguments(args):
- """Parses the command line arguments.
-
- This may set the output format and verbosity level as side-effects.
-
- Args:
- args: The command line arguments:
-
- Returns:
- The list of filenames to lint.
- """
- try:
- (opts, filenames) = getopt.getopt(args, '', ['help', 'output=', 'verbose=',
- 'counting=',
- 'filter=',
- 'root='])
- except getopt.GetoptError:
- PrintUsage('Invalid arguments.')
-
- verbosity = _VerboseLevel()
- output_format = _OutputFormat()
- filters = ''
- counting_style = ''
-
- for (opt, val) in opts:
- if opt == '--help':
- PrintUsage(None)
- elif opt == '--output':
- if not val in ('emacs', 'vs7', 'eclipse'):
- PrintUsage('The only allowed output formats are emacs, vs7 and eclipse.')
- output_format = val
- elif opt == '--verbose':
- verbosity = int(val)
- elif opt == '--filter':
- filters = val
- if not filters:
- PrintCategories()
- elif opt == '--counting':
- if val not in ('total', 'toplevel', 'detailed'):
- PrintUsage('Valid counting options are total, toplevel, and detailed')
- counting_style = val
- elif opt == '--root':
- global _root
- _root = val
-
- if not filenames:
- PrintUsage('No files were specified.')
-
- _SetOutputFormat(output_format)
- _SetVerboseLevel(verbosity)
- _SetFilters(filters)
- _SetCountingStyle(counting_style)
-
- return filenames
-
-
-def main():
- filenames = ParseArguments(sys.argv[1:])
-
- # Change stderr to write with replacement characters so we don't die
- # if we try to print something containing non-ASCII characters.
- sys.stderr = codecs.StreamReaderWriter(sys.stderr,
- codecs.getreader('utf8'),
- codecs.getwriter('utf8'),
- 'replace')
-
- _cpplint_state.ResetErrorCounts()
- for filename in filenames:
- ProcessFile(filename, _cpplint_state.verbose_level)
- _cpplint_state.PrintErrorCounts()
-
- sys.exit(_cpplint_state.error_count > 0)
-
-
-if __name__ == '__main__':
- main()
diff --git a/contrib/compiler-rt/lib/sanitizer_common/scripts/gen_dynamic_list.py b/contrib/compiler-rt/lib/sanitizer_common/scripts/gen_dynamic_list.py
deleted file mode 100755
index f055bb44ba21..000000000000
--- a/contrib/compiler-rt/lib/sanitizer_common/scripts/gen_dynamic_list.py
+++ /dev/null
@@ -1,110 +0,0 @@
-#!/usr/bin/env python
-#===- lib/sanitizer_common/scripts/gen_dynamic_list.py ---------------------===#
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-#===------------------------------------------------------------------------===#
-#
-# Generates the list of functions that should be exported from sanitizer
-# runtimes. The output format is recognized by --dynamic-list linker option.
-# Usage:
-# gen_dynamic_list.py libclang_rt.*san*.a [ files ... ]
-#
-#===------------------------------------------------------------------------===#
-import argparse
-import os
-import re
-import subprocess
-import sys
-
-new_delete = set([
- '_Znam', '_ZnamRKSt9nothrow_t', # operator new[](unsigned long)
- '_Znwm', '_ZnwmRKSt9nothrow_t', # operator new(unsigned long)
- '_Znaj', '_ZnajRKSt9nothrow_t', # operator new[](unsigned int)
- '_Znwj', '_ZnwjRKSt9nothrow_t', # operator new(unsigned int)
- '_ZdaPv', '_ZdaPvRKSt9nothrow_t', # operator delete[](void *)
- '_ZdlPv', '_ZdlPvRKSt9nothrow_t', # operator delete(void *)
- '_ZdaPvm', # operator delete[](void*, unsigned long)
- '_ZdlPvm', # operator delete(void*, unsigned long)
- '_ZdaPvj', # operator delete[](void*, unsigned int)
- '_ZdlPvj', # operator delete(void*, unsigned int)
- ])
-
-versioned_functions = set(['memcpy', 'pthread_attr_getaffinity_np',
- 'pthread_cond_broadcast',
- 'pthread_cond_destroy', 'pthread_cond_init',
- 'pthread_cond_signal', 'pthread_cond_timedwait',
- 'pthread_cond_wait', 'realpath',
- 'sched_getaffinity'])
-
-def get_global_functions(library):
- functions = []
- nm_proc = subprocess.Popen(['nm', library], stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
- nm_out = nm_proc.communicate()[0].decode().split('\n')
- if nm_proc.returncode != 0:
- raise subprocess.CalledProcessError(nm_proc.returncode, 'nm')
- func_symbols = ['T', 'W']
- # On PowerPC, nm prints function descriptors from .data section.
- if os.uname()[4] in ["powerpc", "ppc64"]:
- func_symbols += ['D']
- for line in nm_out:
- cols = line.split(' ')
- if len(cols) == 3 and cols[1] in func_symbols :
- functions.append(cols[2])
- return functions
-
-def main(argv):
- parser = argparse.ArgumentParser()
- parser.add_argument('--version-list', action='store_true')
- parser.add_argument('--extra', default=[], action='append')
- parser.add_argument('libraries', default=[], nargs='+')
- args = parser.parse_args()
-
- result = []
-
- all_functions = []
- for library in args.libraries:
- all_functions.extend(get_global_functions(library))
- function_set = set(all_functions)
- for func in all_functions:
- # Export new/delete operators.
- if func in new_delete:
- result.append(func)
- continue
- # Export interceptors.
- match = re.match('__interceptor_(.*)', func)
- if match:
- result.append(func)
- # We have to avoid exporting the interceptors for versioned library
- # functions due to gold internal error.
- orig_name = match.group(1)
- if orig_name in function_set and (args.version_list or orig_name not in versioned_functions):
- result.append(orig_name)
- continue
- # Export sanitizer interface functions.
- if re.match('__sanitizer_(.*)', func):
- result.append(func)
-
- # Additional exported functions from files.
- for fname in args.extra:
- f = open(fname, 'r')
- for line in f:
- result.append(line.rstrip())
- # Print the resulting list in the format recognized by ld.
- print('{')
- if args.version_list:
- print('global:')
- result.sort()
- for f in result:
- print(' ' + f.encode('utf-8') + ';')
- if args.version_list:
- print('local:')
- print(' *;')
- print('};')
-
-if __name__ == '__main__':
- main(sys.argv)
diff --git a/contrib/compiler-rt/lib/sanitizer_common/scripts/litlint.py b/contrib/compiler-rt/lib/sanitizer_common/scripts/litlint.py
deleted file mode 100755
index 81b89c214438..000000000000
--- a/contrib/compiler-rt/lib/sanitizer_common/scripts/litlint.py
+++ /dev/null
@@ -1,72 +0,0 @@
-#!/usr/bin/env python
-#
-# litlint
-#
-# Ensure RUN commands in lit tests are free of common errors.
-#
-# If any errors are detected, litlint returns a nonzero exit code.
-#
-
-import optparse
-import re
-import sys
-
-# Compile regex once for all files
-runRegex = re.compile(r'(?<!-o)(?<!%run) %t\s')
-
-def LintLine(s):
- """ Validate a line
-
- Args:
- s: str, the line to validate
-
- Returns:
- Returns an error message and a 1-based column number if an error was
- detected, otherwise (None, None).
- """
-
- # Check that RUN command can be executed with an emulator
- m = runRegex.search(s)
- if m:
- start, end = m.span()
- return ('missing %run before %t', start + 2)
-
- # No errors
- return (None, None)
-
-
-def LintFile(p):
- """ Check that each RUN command can be executed with an emulator
-
- Args:
- p: str, valid path to a file
-
- Returns:
- The number of errors detected.
- """
- errs = 0
- with open(p, 'r') as f:
- for i, s in enumerate(f.readlines(), start=1):
- msg, col = LintLine(s)
- if msg != None:
- errs += 1
- errorMsg = 'litlint: {}:{}:{}: error: {}.\n{}{}\n'
- arrow = (col-1) * ' ' + '^'
- sys.stderr.write(errorMsg.format(p, i, col, msg, s, arrow))
- return errs
-
-
-if __name__ == "__main__":
- # Parse args
- parser = optparse.OptionParser()
- parser.add_option('--filter') # ignored
- (options, filenames) = parser.parse_args()
-
- # Lint each file
- errs = 0
- for p in filenames:
- errs += LintFile(p)
-
- # If errors, return nonzero
- if errs > 0:
- sys.exit(1)
diff --git a/contrib/compiler-rt/lib/sanitizer_common/scripts/litlint_test.py b/contrib/compiler-rt/lib/sanitizer_common/scripts/litlint_test.py
deleted file mode 100755
index 3ce482d70444..000000000000
--- a/contrib/compiler-rt/lib/sanitizer_common/scripts/litlint_test.py
+++ /dev/null
@@ -1,23 +0,0 @@
-#!/usr/bin/python
-
-# Tests for litlint.py
-#
-# Usage: python litlint_test.py
-#
-# Returns nonzero if any test fails
-
-import litlint
-import unittest
-
-class TestLintLine(unittest.TestCase):
- def test_missing_run(self):
- f = litlint.LintLine
- self.assertEqual(f(' %t '), ('missing %run before %t', 2))
- self.assertEqual(f(' %t\n'), ('missing %run before %t', 2))
- self.assertEqual(f(' %t.so '), (None, None))
- self.assertEqual(f(' %t.o '), (None, None))
- self.assertEqual(f('%run %t '), (None, None))
- self.assertEqual(f('-o %t '), (None, None))
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/contrib/compiler-rt/lib/sanitizer_common/scripts/sancov.py b/contrib/compiler-rt/lib/sanitizer_common/scripts/sancov.py
deleted file mode 100755
index a5ae9574a26a..000000000000
--- a/contrib/compiler-rt/lib/sanitizer_common/scripts/sancov.py
+++ /dev/null
@@ -1,241 +0,0 @@
-#!/usr/bin/env python
-# Merge or print the coverage data collected by asan's coverage.
-# Input files are sequences of 4-byte integers.
-# We need to merge these integers into a set and then
-# either print them (as hex) or dump them into another file.
-import array
-import bisect
-import glob
-import os.path
-import struct
-import subprocess
-import sys
-
-prog_name = ""
-
-def Usage():
- print >> sys.stderr, "Usage: \n" + \
- " " + prog_name + " merge FILE [FILE...] > OUTPUT\n" \
- " " + prog_name + " print FILE [FILE...]\n" \
- " " + prog_name + " unpack FILE [FILE...]\n" \
- " " + prog_name + " rawunpack FILE [FILE ...]\n" \
- " " + prog_name + " missing BINARY < LIST_OF_PCS\n"
- exit(1)
-
-def CheckBits(bits):
- if bits != 32 and bits != 64:
- raise Exception("Wrong bitness: %d" % bits)
-
-def TypeCodeForBits(bits):
- CheckBits(bits)
- return 'L' if bits == 64 else 'I'
-
-kMagic32SecondHalf = 0xFFFFFF32;
-kMagic64SecondHalf = 0xFFFFFF64;
-kMagicFirstHalf = 0xC0BFFFFF;
-
-def MagicForBits(bits):
- CheckBits(bits)
- if sys.byteorder == 'little':
- return [kMagic64SecondHalf if bits == 64 else kMagic32SecondHalf, kMagicFirstHalf]
- else:
- return [kMagicFirstHalf, kMagic64SecondHalf if bits == 64 else kMagic32SecondHalf]
-
-def ReadMagicAndReturnBitness(f, path):
- magic_bytes = f.read(8)
- magic_words = struct.unpack('II', magic_bytes);
- bits = 0
- idx = 1 if sys.byteorder == 'little' else 0
- if magic_words[idx] == kMagicFirstHalf:
- if magic_words[1-idx] == kMagic64SecondHalf:
- bits = 64
- elif magic_words[1-idx] == kMagic32SecondHalf:
- bits = 32
- if bits == 0:
- raise Exception('Bad magic word in %s' % path)
- return bits
-
-def ReadOneFile(path):
- with open(path, mode="rb") as f:
- f.seek(0, 2)
- size = f.tell()
- f.seek(0, 0)
- if size < 8:
- raise Exception('File %s is short (< 8 bytes)' % path)
- bits = ReadMagicAndReturnBitness(f, path)
- size -= 8
- s = array.array(TypeCodeForBits(bits), f.read(size))
- print >>sys.stderr, "%s: read %d %d-bit PCs from %s" % (prog_name, size * 8 / bits, bits, path)
- return s
-
-def Merge(files):
- s = set()
- for f in files:
- s = s.union(set(ReadOneFile(f)))
- print >> sys.stderr, "%s: %d files merged; %d PCs total" % \
- (prog_name, len(files), len(s))
- return sorted(s)
-
-def PrintFiles(files):
- if len(files) > 1:
- s = Merge(files)
- else: # If there is just on file, print the PCs in order.
- s = ReadOneFile(files[0])
- print >> sys.stderr, "%s: 1 file merged; %d PCs total" % \
- (prog_name, len(s))
- for i in s:
- print "0x%x" % i
-
-def MergeAndPrint(files):
- if sys.stdout.isatty():
- Usage()
- s = Merge(files)
- bits = 32
- if max(s) > 0xFFFFFFFF:
- bits = 64
- array.array('I', MagicForBits(bits)).tofile(sys.stdout)
- a = array.array(TypeCodeForBits(bits), s)
- a.tofile(sys.stdout)
-
-
-def UnpackOneFile(path):
- with open(path, mode="rb") as f:
- print >> sys.stderr, "%s: unpacking %s" % (prog_name, path)
- while True:
- header = f.read(12)
- if not header: return
- if len(header) < 12:
- break
- pid, module_length, blob_size = struct.unpack('iII', header)
- module = f.read(module_length)
- blob = f.read(blob_size)
- assert(len(module) == module_length)
- assert(len(blob) == blob_size)
- extracted_file = "%s.%d.sancov" % (module, pid)
- print >> sys.stderr, "%s: extracting %s" % \
- (prog_name, extracted_file)
- # The packed file may contain multiple blobs for the same pid/module
- # pair. Append to the end of the file instead of overwriting.
- with open(extracted_file, 'ab') as f2:
- f2.write(blob)
- # fail
- raise Exception('Error reading file %s' % path)
-
-
-def Unpack(files):
- for f in files:
- UnpackOneFile(f)
-
-def UnpackOneRawFile(path, map_path):
- mem_map = []
- with open(map_path, mode="rt") as f_map:
- print >> sys.stderr, "%s: reading map %s" % (prog_name, map_path)
- bits = int(f_map.readline())
- if bits != 32 and bits != 64:
- raise Exception('Wrong bits size in the map')
- for line in f_map:
- parts = line.rstrip().split()
- mem_map.append((int(parts[0], 16),
- int(parts[1], 16),
- int(parts[2], 16),
- ' '.join(parts[3:])))
- mem_map.sort(key=lambda m : m[0])
- mem_map_keys = [m[0] for m in mem_map]
-
- with open(path, mode="rb") as f:
- print >> sys.stderr, "%s: unpacking %s" % (prog_name, path)
-
- f.seek(0, 2)
- size = f.tell()
- f.seek(0, 0)
- pcs = array.array(TypeCodeForBits(bits), f.read(size))
- mem_map_pcs = [[] for i in range(0, len(mem_map))]
-
- for pc in pcs:
- if pc == 0: continue
- map_idx = bisect.bisect(mem_map_keys, pc) - 1
- (start, end, base, module_path) = mem_map[map_idx]
- assert pc >= start
- if pc >= end:
- print >> sys.stderr, "warning: %s: pc %x outside of any known mapping" % (prog_name, pc)
- continue
- mem_map_pcs[map_idx].append(pc - base)
-
- for ((start, end, base, module_path), pc_list) in zip(mem_map, mem_map_pcs):
- if len(pc_list) == 0: continue
- assert path.endswith('.sancov.raw')
- dst_path = module_path + '.' + os.path.basename(path)[:-4]
- print >> sys.stderr, "%s: writing %d PCs to %s" % (prog_name, len(pc_list), dst_path)
- arr = array.array(TypeCodeForBits(bits))
- arr.fromlist(sorted(pc_list))
- with open(dst_path, 'ab') as f2:
- array.array('I', MagicForBits(bits)).tofile(f2)
- arr.tofile(f2)
-
-def RawUnpack(files):
- for f in files:
- if not f.endswith('.sancov.raw'):
- raise Exception('Unexpected raw file name %s' % f)
- f_map = f[:-3] + 'map'
- UnpackOneRawFile(f, f_map)
-
-def GetInstrumentedPCs(binary):
- # This looks scary, but all it does is extract all offsets where we call:
- # - __sanitizer_cov() or __sanitizer_cov_with_check(),
- # - with call or callq,
- # - directly or via PLT.
- cmd = "objdump -d %s | " \
- "grep '^\s\+[0-9a-f]\+:.*\scall\(q\|\)\s\+[0-9a-f]\+ <__sanitizer_cov\(_with_check\|\)\(@plt\|\)>' | " \
- "grep '^\s\+[0-9a-f]\+' -o" % binary
- proc = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
- shell=True)
- proc.stdin.close()
- # The PCs we get from objdump are off by 4 bytes, as they point to the
- # beginning of the callq instruction. Empirically this is true on x86 and
- # x86_64.
- return set(int(line.strip(), 16) + 4 for line in proc.stdout)
-
-def PrintMissing(binary):
- if not os.path.isfile(binary):
- raise Exception('File not found: %s' % binary)
- instrumented = GetInstrumentedPCs(binary)
- print >> sys.stderr, "%s: found %d instrumented PCs in %s" % (prog_name,
- len(instrumented),
- binary)
- covered = set(int(line, 16) for line in sys.stdin)
- print >> sys.stderr, "%s: read %d PCs from stdin" % (prog_name, len(covered))
- missing = instrumented - covered
- print >> sys.stderr, "%s: %d PCs missing from coverage" % (prog_name, len(missing))
- if (len(missing) > len(instrumented) - len(covered)):
- print >> sys.stderr, \
- "%s: WARNING: stdin contains PCs not found in binary" % prog_name
- for pc in sorted(missing):
- print "0x%x" % pc
-
-if __name__ == '__main__':
- prog_name = sys.argv[0]
- if len(sys.argv) <= 2:
- Usage();
-
- if sys.argv[1] == "missing":
- if len(sys.argv) != 3:
- Usage()
- PrintMissing(sys.argv[2])
- exit(0)
-
- file_list = []
- for f in sys.argv[2:]:
- file_list += glob.glob(f)
- if not file_list:
- Usage()
-
- if sys.argv[1] == "print":
- PrintFiles(file_list)
- elif sys.argv[1] == "merge":
- MergeAndPrint(file_list)
- elif sys.argv[1] == "unpack":
- Unpack(file_list)
- elif sys.argv[1] == "rawunpack":
- RawUnpack(file_list)
- else:
- Usage()
diff --git a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_allocator_test.cc b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_allocator_test.cc
deleted file mode 100644
index be8fc91aa861..000000000000
--- a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_allocator_test.cc
+++ /dev/null
@@ -1,860 +0,0 @@
-//===-- sanitizer_allocator_test.cc ---------------------------------------===//
-//
-// 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 ThreadSanitizer/AddressSanitizer runtime.
-// Tests for sanitizer_allocator.h.
-//
-//===----------------------------------------------------------------------===//
-#include "sanitizer_common/sanitizer_allocator.h"
-#include "sanitizer_common/sanitizer_allocator_internal.h"
-#include "sanitizer_common/sanitizer_common.h"
-
-#include "sanitizer_test_utils.h"
-#include "sanitizer_pthread_wrappers.h"
-
-#include "gtest/gtest.h"
-
-#include <stdlib.h>
-#include <algorithm>
-#include <vector>
-#include <set>
-
-// Too slow for debug build
-#if !SANITIZER_DEBUG
-
-#if SANITIZER_CAN_USE_ALLOCATOR64
-static const uptr kAllocatorSpace = 0x700000000000ULL;
-static const uptr kAllocatorSize = 0x010000000000ULL; // 1T.
-static const u64 kAddressSpaceSize = 1ULL << 47;
-
-typedef SizeClassAllocator64<
- kAllocatorSpace, kAllocatorSize, 16, DefaultSizeClassMap> Allocator64;
-
-typedef SizeClassAllocator64<
- kAllocatorSpace, kAllocatorSize, 16, CompactSizeClassMap> Allocator64Compact;
-#elif defined(__mips64)
-static const u64 kAddressSpaceSize = 1ULL << 40;
-#else
-static const u64 kAddressSpaceSize = 1ULL << 32;
-#endif
-
-static const uptr kRegionSizeLog = FIRST_32_SECOND_64(20, 24);
-static const uptr kFlatByteMapSize = kAddressSpaceSize >> kRegionSizeLog;
-
-typedef SizeClassAllocator32<
- 0, kAddressSpaceSize,
- /*kMetadataSize*/16,
- CompactSizeClassMap,
- kRegionSizeLog,
- FlatByteMap<kFlatByteMapSize> >
- Allocator32Compact;
-
-template <class SizeClassMap>
-void TestSizeClassMap() {
- typedef SizeClassMap SCMap;
- // SCMap::Print();
- SCMap::Validate();
-}
-
-TEST(SanitizerCommon, DefaultSizeClassMap) {
- TestSizeClassMap<DefaultSizeClassMap>();
-}
-
-TEST(SanitizerCommon, CompactSizeClassMap) {
- TestSizeClassMap<CompactSizeClassMap>();
-}
-
-TEST(SanitizerCommon, InternalSizeClassMap) {
- TestSizeClassMap<InternalSizeClassMap>();
-}
-
-template <class Allocator>
-void TestSizeClassAllocator() {
- Allocator *a = new Allocator;
- a->Init();
- SizeClassAllocatorLocalCache<Allocator> cache;
- memset(&cache, 0, sizeof(cache));
- cache.Init(0);
-
- static const uptr sizes[] = {1, 16, 30, 40, 100, 1000, 10000,
- 50000, 60000, 100000, 120000, 300000, 500000, 1000000, 2000000};
-
- std::vector<void *> allocated;
-
- uptr last_total_allocated = 0;
- for (int i = 0; i < 3; i++) {
- // Allocate a bunch of chunks.
- for (uptr s = 0; s < ARRAY_SIZE(sizes); s++) {
- uptr size = sizes[s];
- if (!a->CanAllocate(size, 1)) continue;
- // printf("s = %ld\n", size);
- uptr n_iter = std::max((uptr)6, 8000000 / size);
- // fprintf(stderr, "size: %ld iter: %ld\n", size, n_iter);
- for (uptr i = 0; i < n_iter; i++) {
- uptr class_id0 = Allocator::SizeClassMapT::ClassID(size);
- char *x = (char*)cache.Allocate(a, class_id0);
- x[0] = 0;
- x[size - 1] = 0;
- x[size / 2] = 0;
- allocated.push_back(x);
- CHECK_EQ(x, a->GetBlockBegin(x));
- CHECK_EQ(x, a->GetBlockBegin(x + size - 1));
- CHECK(a->PointerIsMine(x));
- CHECK(a->PointerIsMine(x + size - 1));
- CHECK(a->PointerIsMine(x + size / 2));
- CHECK_GE(a->GetActuallyAllocatedSize(x), size);
- uptr class_id = a->GetSizeClass(x);
- CHECK_EQ(class_id, Allocator::SizeClassMapT::ClassID(size));
- uptr *metadata = reinterpret_cast<uptr*>(a->GetMetaData(x));
- metadata[0] = reinterpret_cast<uptr>(x) + 1;
- metadata[1] = 0xABCD;
- }
- }
- // Deallocate all.
- for (uptr i = 0; i < allocated.size(); i++) {
- void *x = allocated[i];
- uptr *metadata = reinterpret_cast<uptr*>(a->GetMetaData(x));
- CHECK_EQ(metadata[0], reinterpret_cast<uptr>(x) + 1);
- CHECK_EQ(metadata[1], 0xABCD);
- cache.Deallocate(a, a->GetSizeClass(x), x);
- }
- allocated.clear();
- uptr total_allocated = a->TotalMemoryUsed();
- if (last_total_allocated == 0)
- last_total_allocated = total_allocated;
- CHECK_EQ(last_total_allocated, total_allocated);
- }
-
- // Check that GetBlockBegin never crashes.
- for (uptr x = 0, step = kAddressSpaceSize / 100000;
- x < kAddressSpaceSize - step; x += step)
- if (a->PointerIsMine(reinterpret_cast<void *>(x)))
- Ident(a->GetBlockBegin(reinterpret_cast<void *>(x)));
-
- a->TestOnlyUnmap();
- delete a;
-}
-
-#if SANITIZER_CAN_USE_ALLOCATOR64
-TEST(SanitizerCommon, SizeClassAllocator64) {
- TestSizeClassAllocator<Allocator64>();
-}
-
-TEST(SanitizerCommon, SizeClassAllocator64Compact) {
- TestSizeClassAllocator<Allocator64Compact>();
-}
-#endif
-
-TEST(SanitizerCommon, SizeClassAllocator32Compact) {
- TestSizeClassAllocator<Allocator32Compact>();
-}
-
-template <class Allocator>
-void SizeClassAllocatorMetadataStress() {
- Allocator *a = new Allocator;
- a->Init();
- SizeClassAllocatorLocalCache<Allocator> cache;
- memset(&cache, 0, sizeof(cache));
- cache.Init(0);
-
- const uptr kNumAllocs = 1 << 13;
- void *allocated[kNumAllocs];
- void *meta[kNumAllocs];
- for (uptr i = 0; i < kNumAllocs; i++) {
- void *x = cache.Allocate(a, 1 + i % 50);
- allocated[i] = x;
- meta[i] = a->GetMetaData(x);
- }
- // Get Metadata kNumAllocs^2 times.
- for (uptr i = 0; i < kNumAllocs * kNumAllocs; i++) {
- uptr idx = i % kNumAllocs;
- void *m = a->GetMetaData(allocated[idx]);
- EXPECT_EQ(m, meta[idx]);
- }
- for (uptr i = 0; i < kNumAllocs; i++) {
- cache.Deallocate(a, 1 + i % 50, allocated[i]);
- }
-
- a->TestOnlyUnmap();
- delete a;
-}
-
-#if SANITIZER_CAN_USE_ALLOCATOR64
-TEST(SanitizerCommon, SizeClassAllocator64MetadataStress) {
- SizeClassAllocatorMetadataStress<Allocator64>();
-}
-
-TEST(SanitizerCommon, SizeClassAllocator64CompactMetadataStress) {
- SizeClassAllocatorMetadataStress<Allocator64Compact>();
-}
-#endif // SANITIZER_CAN_USE_ALLOCATOR64
-TEST(SanitizerCommon, SizeClassAllocator32CompactMetadataStress) {
- SizeClassAllocatorMetadataStress<Allocator32Compact>();
-}
-
-template <class Allocator>
-void SizeClassAllocatorGetBlockBeginStress() {
- Allocator *a = new Allocator;
- a->Init();
- SizeClassAllocatorLocalCache<Allocator> cache;
- memset(&cache, 0, sizeof(cache));
- cache.Init(0);
-
- uptr max_size_class = Allocator::kNumClasses - 1;
- uptr size = Allocator::SizeClassMapT::Size(max_size_class);
- u64 G8 = 1ULL << 33;
- // Make sure we correctly compute GetBlockBegin() w/o overflow.
- for (size_t i = 0; i <= G8 / size; i++) {
- void *x = cache.Allocate(a, max_size_class);
- void *beg = a->GetBlockBegin(x);
- // if ((i & (i - 1)) == 0)
- // fprintf(stderr, "[%zd] %p %p\n", i, x, beg);
- EXPECT_EQ(x, beg);
- }
-
- a->TestOnlyUnmap();
- delete a;
-}
-
-#if SANITIZER_CAN_USE_ALLOCATOR64
-TEST(SanitizerCommon, SizeClassAllocator64GetBlockBegin) {
- SizeClassAllocatorGetBlockBeginStress<Allocator64>();
-}
-TEST(SanitizerCommon, SizeClassAllocator64CompactGetBlockBegin) {
- SizeClassAllocatorGetBlockBeginStress<Allocator64Compact>();
-}
-TEST(SanitizerCommon, SizeClassAllocator32CompactGetBlockBegin) {
- SizeClassAllocatorGetBlockBeginStress<Allocator32Compact>();
-}
-#endif // SANITIZER_CAN_USE_ALLOCATOR64
-
-struct TestMapUnmapCallback {
- static int map_count, unmap_count;
- void OnMap(uptr p, uptr size) const { map_count++; }
- void OnUnmap(uptr p, uptr size) const { unmap_count++; }
-};
-int TestMapUnmapCallback::map_count;
-int TestMapUnmapCallback::unmap_count;
-
-#if SANITIZER_CAN_USE_ALLOCATOR64
-TEST(SanitizerCommon, SizeClassAllocator64MapUnmapCallback) {
- TestMapUnmapCallback::map_count = 0;
- TestMapUnmapCallback::unmap_count = 0;
- typedef SizeClassAllocator64<
- kAllocatorSpace, kAllocatorSize, 16, DefaultSizeClassMap,
- TestMapUnmapCallback> Allocator64WithCallBack;
- Allocator64WithCallBack *a = new Allocator64WithCallBack;
- a->Init();
- EXPECT_EQ(TestMapUnmapCallback::map_count, 1); // Allocator state.
- SizeClassAllocatorLocalCache<Allocator64WithCallBack> cache;
- memset(&cache, 0, sizeof(cache));
- cache.Init(0);
- AllocatorStats stats;
- stats.Init();
- a->AllocateBatch(&stats, &cache, 32);
- EXPECT_EQ(TestMapUnmapCallback::map_count, 3); // State + alloc + metadata.
- a->TestOnlyUnmap();
- EXPECT_EQ(TestMapUnmapCallback::unmap_count, 1); // The whole thing.
- delete a;
-}
-#endif
-
-TEST(SanitizerCommon, SizeClassAllocator32MapUnmapCallback) {
- TestMapUnmapCallback::map_count = 0;
- TestMapUnmapCallback::unmap_count = 0;
- typedef SizeClassAllocator32<
- 0, kAddressSpaceSize,
- /*kMetadataSize*/16,
- CompactSizeClassMap,
- kRegionSizeLog,
- FlatByteMap<kFlatByteMapSize>,
- TestMapUnmapCallback>
- Allocator32WithCallBack;
- Allocator32WithCallBack *a = new Allocator32WithCallBack;
- a->Init();
- EXPECT_EQ(TestMapUnmapCallback::map_count, 0);
- SizeClassAllocatorLocalCache<Allocator32WithCallBack> cache;
- memset(&cache, 0, sizeof(cache));
- cache.Init(0);
- AllocatorStats stats;
- stats.Init();
- a->AllocateBatch(&stats, &cache, 32);
- EXPECT_EQ(TestMapUnmapCallback::map_count, 1);
- a->TestOnlyUnmap();
- EXPECT_EQ(TestMapUnmapCallback::unmap_count, 1);
- delete a;
- // fprintf(stderr, "Map: %d Unmap: %d\n",
- // TestMapUnmapCallback::map_count,
- // TestMapUnmapCallback::unmap_count);
-}
-
-TEST(SanitizerCommon, LargeMmapAllocatorMapUnmapCallback) {
- TestMapUnmapCallback::map_count = 0;
- TestMapUnmapCallback::unmap_count = 0;
- LargeMmapAllocator<TestMapUnmapCallback> a;
- a.Init(/* may_return_null */ false);
- AllocatorStats stats;
- stats.Init();
- void *x = a.Allocate(&stats, 1 << 20, 1);
- EXPECT_EQ(TestMapUnmapCallback::map_count, 1);
- a.Deallocate(&stats, x);
- EXPECT_EQ(TestMapUnmapCallback::unmap_count, 1);
-}
-
-template<class Allocator>
-void FailInAssertionOnOOM() {
- Allocator a;
- a.Init();
- SizeClassAllocatorLocalCache<Allocator> cache;
- memset(&cache, 0, sizeof(cache));
- cache.Init(0);
- AllocatorStats stats;
- stats.Init();
- for (int i = 0; i < 1000000; i++) {
- a.AllocateBatch(&stats, &cache, 52);
- }
-
- a.TestOnlyUnmap();
-}
-
-#if SANITIZER_CAN_USE_ALLOCATOR64
-TEST(SanitizerCommon, SizeClassAllocator64Overflow) {
- EXPECT_DEATH(FailInAssertionOnOOM<Allocator64>(), "Out of memory");
-}
-#endif
-
-#if !defined(_WIN32) // FIXME: This currently fails on Windows.
-TEST(SanitizerCommon, LargeMmapAllocator) {
- LargeMmapAllocator<> a;
- a.Init(/* may_return_null */ false);
- AllocatorStats stats;
- stats.Init();
-
- static const int kNumAllocs = 1000;
- char *allocated[kNumAllocs];
- static const uptr size = 4000;
- // Allocate some.
- for (int i = 0; i < kNumAllocs; i++) {
- allocated[i] = (char *)a.Allocate(&stats, size, 1);
- CHECK(a.PointerIsMine(allocated[i]));
- }
- // Deallocate all.
- CHECK_GT(a.TotalMemoryUsed(), size * kNumAllocs);
- for (int i = 0; i < kNumAllocs; i++) {
- char *p = allocated[i];
- CHECK(a.PointerIsMine(p));
- a.Deallocate(&stats, p);
- }
- // Check that non left.
- CHECK_EQ(a.TotalMemoryUsed(), 0);
-
- // Allocate some more, also add metadata.
- for (int i = 0; i < kNumAllocs; i++) {
- char *x = (char *)a.Allocate(&stats, size, 1);
- CHECK_GE(a.GetActuallyAllocatedSize(x), size);
- uptr *meta = reinterpret_cast<uptr*>(a.GetMetaData(x));
- *meta = i;
- allocated[i] = x;
- }
- for (int i = 0; i < kNumAllocs * kNumAllocs; i++) {
- char *p = allocated[i % kNumAllocs];
- CHECK(a.PointerIsMine(p));
- CHECK(a.PointerIsMine(p + 2000));
- }
- CHECK_GT(a.TotalMemoryUsed(), size * kNumAllocs);
- // Deallocate all in reverse order.
- for (int i = 0; i < kNumAllocs; i++) {
- int idx = kNumAllocs - i - 1;
- char *p = allocated[idx];
- uptr *meta = reinterpret_cast<uptr*>(a.GetMetaData(p));
- CHECK_EQ(*meta, idx);
- CHECK(a.PointerIsMine(p));
- a.Deallocate(&stats, p);
- }
- CHECK_EQ(a.TotalMemoryUsed(), 0);
-
- // Test alignments.
- uptr max_alignment = SANITIZER_WORDSIZE == 64 ? (1 << 28) : (1 << 24);
- for (uptr alignment = 8; alignment <= max_alignment; alignment *= 2) {
- const uptr kNumAlignedAllocs = 100;
- for (uptr i = 0; i < kNumAlignedAllocs; i++) {
- uptr size = ((i % 10) + 1) * 4096;
- char *p = allocated[i] = (char *)a.Allocate(&stats, size, alignment);
- CHECK_EQ(p, a.GetBlockBegin(p));
- CHECK_EQ(p, a.GetBlockBegin(p + size - 1));
- CHECK_EQ(p, a.GetBlockBegin(p + size / 2));
- CHECK_EQ(0, (uptr)allocated[i] % alignment);
- p[0] = p[size - 1] = 0;
- }
- for (uptr i = 0; i < kNumAlignedAllocs; i++) {
- a.Deallocate(&stats, allocated[i]);
- }
- }
-
- // Regression test for boundary condition in GetBlockBegin().
- uptr page_size = GetPageSizeCached();
- char *p = (char *)a.Allocate(&stats, page_size, 1);
- CHECK_EQ(p, a.GetBlockBegin(p));
- CHECK_EQ(p, (char *)a.GetBlockBegin(p + page_size - 1));
- CHECK_NE(p, (char *)a.GetBlockBegin(p + page_size));
- a.Deallocate(&stats, p);
-}
-#endif
-
-template
-<class PrimaryAllocator, class SecondaryAllocator, class AllocatorCache>
-void TestCombinedAllocator() {
- typedef
- CombinedAllocator<PrimaryAllocator, AllocatorCache, SecondaryAllocator>
- Allocator;
- Allocator *a = new Allocator;
- a->Init(/* may_return_null */ true);
-
- AllocatorCache cache;
- memset(&cache, 0, sizeof(cache));
- a->InitCache(&cache);
-
- EXPECT_EQ(a->Allocate(&cache, -1, 1), (void*)0);
- EXPECT_EQ(a->Allocate(&cache, -1, 1024), (void*)0);
- EXPECT_EQ(a->Allocate(&cache, (uptr)-1 - 1024, 1), (void*)0);
- EXPECT_EQ(a->Allocate(&cache, (uptr)-1 - 1024, 1024), (void*)0);
- EXPECT_EQ(a->Allocate(&cache, (uptr)-1 - 1023, 1024), (void*)0);
-
- // Set to false
- a->SetMayReturnNull(false);
- EXPECT_DEATH(a->Allocate(&cache, -1, 1),
- "allocator is terminating the process");
-
- const uptr kNumAllocs = 100000;
- const uptr kNumIter = 10;
- for (uptr iter = 0; iter < kNumIter; iter++) {
- std::vector<void*> allocated;
- for (uptr i = 0; i < kNumAllocs; i++) {
- uptr size = (i % (1 << 14)) + 1;
- if ((i % 1024) == 0)
- size = 1 << (10 + (i % 14));
- void *x = a->Allocate(&cache, size, 1);
- uptr *meta = reinterpret_cast<uptr*>(a->GetMetaData(x));
- CHECK_EQ(*meta, 0);
- *meta = size;
- allocated.push_back(x);
- }
-
- random_shuffle(allocated.begin(), allocated.end());
-
- for (uptr i = 0; i < kNumAllocs; i++) {
- void *x = allocated[i];
- uptr *meta = reinterpret_cast<uptr*>(a->GetMetaData(x));
- CHECK_NE(*meta, 0);
- CHECK(a->PointerIsMine(x));
- *meta = 0;
- a->Deallocate(&cache, x);
- }
- allocated.clear();
- a->SwallowCache(&cache);
- }
- a->DestroyCache(&cache);
- a->TestOnlyUnmap();
-}
-
-#if SANITIZER_CAN_USE_ALLOCATOR64
-TEST(SanitizerCommon, CombinedAllocator64) {
- TestCombinedAllocator<Allocator64,
- LargeMmapAllocator<>,
- SizeClassAllocatorLocalCache<Allocator64> > ();
-}
-
-TEST(SanitizerCommon, CombinedAllocator64Compact) {
- TestCombinedAllocator<Allocator64Compact,
- LargeMmapAllocator<>,
- SizeClassAllocatorLocalCache<Allocator64Compact> > ();
-}
-#endif
-
-#if !defined(_WIN32) // FIXME: This currently fails on Windows.
-TEST(SanitizerCommon, CombinedAllocator32Compact) {
- TestCombinedAllocator<Allocator32Compact,
- LargeMmapAllocator<>,
- SizeClassAllocatorLocalCache<Allocator32Compact> > ();
-}
-#endif
-
-template <class AllocatorCache>
-void TestSizeClassAllocatorLocalCache() {
- AllocatorCache cache;
- typedef typename AllocatorCache::Allocator Allocator;
- Allocator *a = new Allocator();
-
- a->Init();
- memset(&cache, 0, sizeof(cache));
- cache.Init(0);
-
- const uptr kNumAllocs = 10000;
- const int kNumIter = 100;
- uptr saved_total = 0;
- for (int class_id = 1; class_id <= 5; class_id++) {
- for (int it = 0; it < kNumIter; it++) {
- void *allocated[kNumAllocs];
- for (uptr i = 0; i < kNumAllocs; i++) {
- allocated[i] = cache.Allocate(a, class_id);
- }
- for (uptr i = 0; i < kNumAllocs; i++) {
- cache.Deallocate(a, class_id, allocated[i]);
- }
- cache.Drain(a);
- uptr total_allocated = a->TotalMemoryUsed();
- if (it)
- CHECK_EQ(saved_total, total_allocated);
- saved_total = total_allocated;
- }
- }
-
- a->TestOnlyUnmap();
- delete a;
-}
-
-#if SANITIZER_CAN_USE_ALLOCATOR64
-TEST(SanitizerCommon, SizeClassAllocator64LocalCache) {
- TestSizeClassAllocatorLocalCache<
- SizeClassAllocatorLocalCache<Allocator64> >();
-}
-
-TEST(SanitizerCommon, SizeClassAllocator64CompactLocalCache) {
- TestSizeClassAllocatorLocalCache<
- SizeClassAllocatorLocalCache<Allocator64Compact> >();
-}
-#endif
-
-TEST(SanitizerCommon, SizeClassAllocator32CompactLocalCache) {
- TestSizeClassAllocatorLocalCache<
- SizeClassAllocatorLocalCache<Allocator32Compact> >();
-}
-
-#if SANITIZER_CAN_USE_ALLOCATOR64
-typedef SizeClassAllocatorLocalCache<Allocator64> AllocatorCache;
-static AllocatorCache static_allocator_cache;
-
-void *AllocatorLeakTestWorker(void *arg) {
- typedef AllocatorCache::Allocator Allocator;
- Allocator *a = (Allocator*)(arg);
- static_allocator_cache.Allocate(a, 10);
- static_allocator_cache.Drain(a);
- return 0;
-}
-
-TEST(SanitizerCommon, AllocatorLeakTest) {
- typedef AllocatorCache::Allocator Allocator;
- Allocator a;
- a.Init();
- uptr total_used_memory = 0;
- for (int i = 0; i < 100; i++) {
- pthread_t t;
- PTHREAD_CREATE(&t, 0, AllocatorLeakTestWorker, &a);
- PTHREAD_JOIN(t, 0);
- if (i == 0)
- total_used_memory = a.TotalMemoryUsed();
- EXPECT_EQ(a.TotalMemoryUsed(), total_used_memory);
- }
-
- a.TestOnlyUnmap();
-}
-
-// Struct which is allocated to pass info to new threads. The new thread frees
-// it.
-struct NewThreadParams {
- AllocatorCache *thread_cache;
- AllocatorCache::Allocator *allocator;
- uptr class_id;
-};
-
-// Called in a new thread. Just frees its argument.
-static void *DeallocNewThreadWorker(void *arg) {
- NewThreadParams *params = reinterpret_cast<NewThreadParams*>(arg);
- params->thread_cache->Deallocate(params->allocator, params->class_id, params);
- return NULL;
-}
-
-// The allocator cache is supposed to be POD and zero initialized. We should be
-// able to call Deallocate on a zeroed cache, and it will self-initialize.
-TEST(Allocator, AllocatorCacheDeallocNewThread) {
- AllocatorCache::Allocator allocator;
- allocator.Init();
- AllocatorCache main_cache;
- AllocatorCache child_cache;
- memset(&main_cache, 0, sizeof(main_cache));
- memset(&child_cache, 0, sizeof(child_cache));
-
- uptr class_id = DefaultSizeClassMap::ClassID(sizeof(NewThreadParams));
- NewThreadParams *params = reinterpret_cast<NewThreadParams*>(
- main_cache.Allocate(&allocator, class_id));
- params->thread_cache = &child_cache;
- params->allocator = &allocator;
- params->class_id = class_id;
- pthread_t t;
- PTHREAD_CREATE(&t, 0, DeallocNewThreadWorker, params);
- PTHREAD_JOIN(t, 0);
-}
-#endif
-
-TEST(Allocator, Basic) {
- char *p = (char*)InternalAlloc(10);
- EXPECT_NE(p, (char*)0);
- char *p2 = (char*)InternalAlloc(20);
- EXPECT_NE(p2, (char*)0);
- EXPECT_NE(p2, p);
- InternalFree(p);
- InternalFree(p2);
-}
-
-TEST(Allocator, Stress) {
- const int kCount = 1000;
- char *ptrs[kCount];
- unsigned rnd = 42;
- for (int i = 0; i < kCount; i++) {
- uptr sz = my_rand_r(&rnd) % 1000;
- char *p = (char*)InternalAlloc(sz);
- EXPECT_NE(p, (char*)0);
- ptrs[i] = p;
- }
- for (int i = 0; i < kCount; i++) {
- InternalFree(ptrs[i]);
- }
-}
-
-TEST(Allocator, LargeAlloc) {
- void *p = InternalAlloc(10 << 20);
- InternalFree(p);
-}
-
-TEST(Allocator, ScopedBuffer) {
- const int kSize = 512;
- {
- InternalScopedBuffer<int> int_buf(kSize);
- EXPECT_EQ(sizeof(int) * kSize, int_buf.size()); // NOLINT
- }
- InternalScopedBuffer<char> char_buf(kSize);
- EXPECT_EQ(sizeof(char) * kSize, char_buf.size()); // NOLINT
- internal_memset(char_buf.data(), 'c', kSize);
- for (int i = 0; i < kSize; i++) {
- EXPECT_EQ('c', char_buf[i]);
- }
-}
-
-void IterationTestCallback(uptr chunk, void *arg) {
- reinterpret_cast<std::set<uptr> *>(arg)->insert(chunk);
-}
-
-template <class Allocator>
-void TestSizeClassAllocatorIteration() {
- Allocator *a = new Allocator;
- a->Init();
- SizeClassAllocatorLocalCache<Allocator> cache;
- memset(&cache, 0, sizeof(cache));
- cache.Init(0);
-
- static const uptr sizes[] = {1, 16, 30, 40, 100, 1000, 10000,
- 50000, 60000, 100000, 120000, 300000, 500000, 1000000, 2000000};
-
- std::vector<void *> allocated;
-
- // Allocate a bunch of chunks.
- for (uptr s = 0; s < ARRAY_SIZE(sizes); s++) {
- uptr size = sizes[s];
- if (!a->CanAllocate(size, 1)) continue;
- // printf("s = %ld\n", size);
- uptr n_iter = std::max((uptr)6, 80000 / size);
- // fprintf(stderr, "size: %ld iter: %ld\n", size, n_iter);
- for (uptr j = 0; j < n_iter; j++) {
- uptr class_id0 = Allocator::SizeClassMapT::ClassID(size);
- void *x = cache.Allocate(a, class_id0);
- allocated.push_back(x);
- }
- }
-
- std::set<uptr> reported_chunks;
- a->ForceLock();
- a->ForEachChunk(IterationTestCallback, &reported_chunks);
- a->ForceUnlock();
-
- for (uptr i = 0; i < allocated.size(); i++) {
- // Don't use EXPECT_NE. Reporting the first mismatch is enough.
- ASSERT_NE(reported_chunks.find(reinterpret_cast<uptr>(allocated[i])),
- reported_chunks.end());
- }
-
- a->TestOnlyUnmap();
- delete a;
-}
-
-#if SANITIZER_CAN_USE_ALLOCATOR64
-TEST(SanitizerCommon, SizeClassAllocator64Iteration) {
- TestSizeClassAllocatorIteration<Allocator64>();
-}
-#endif
-
-TEST(SanitizerCommon, SizeClassAllocator32Iteration) {
- TestSizeClassAllocatorIteration<Allocator32Compact>();
-}
-
-TEST(SanitizerCommon, LargeMmapAllocatorIteration) {
- LargeMmapAllocator<> a;
- a.Init(/* may_return_null */ false);
- AllocatorStats stats;
- stats.Init();
-
- static const uptr kNumAllocs = 1000;
- char *allocated[kNumAllocs];
- static const uptr size = 40;
- // Allocate some.
- for (uptr i = 0; i < kNumAllocs; i++)
- allocated[i] = (char *)a.Allocate(&stats, size, 1);
-
- std::set<uptr> reported_chunks;
- a.ForceLock();
- a.ForEachChunk(IterationTestCallback, &reported_chunks);
- a.ForceUnlock();
-
- for (uptr i = 0; i < kNumAllocs; i++) {
- // Don't use EXPECT_NE. Reporting the first mismatch is enough.
- ASSERT_NE(reported_chunks.find(reinterpret_cast<uptr>(allocated[i])),
- reported_chunks.end());
- }
- for (uptr i = 0; i < kNumAllocs; i++)
- a.Deallocate(&stats, allocated[i]);
-}
-
-TEST(SanitizerCommon, LargeMmapAllocatorBlockBegin) {
- LargeMmapAllocator<> a;
- a.Init(/* may_return_null */ false);
- AllocatorStats stats;
- stats.Init();
-
- static const uptr kNumAllocs = 1024;
- static const uptr kNumExpectedFalseLookups = 10000000;
- char *allocated[kNumAllocs];
- static const uptr size = 4096;
- // Allocate some.
- for (uptr i = 0; i < kNumAllocs; i++) {
- allocated[i] = (char *)a.Allocate(&stats, size, 1);
- }
-
- a.ForceLock();
- for (uptr i = 0; i < kNumAllocs * kNumAllocs; i++) {
- // if ((i & (i - 1)) == 0) fprintf(stderr, "[%zd]\n", i);
- char *p1 = allocated[i % kNumAllocs];
- EXPECT_EQ(p1, a.GetBlockBeginFastLocked(p1));
- EXPECT_EQ(p1, a.GetBlockBeginFastLocked(p1 + size / 2));
- EXPECT_EQ(p1, a.GetBlockBeginFastLocked(p1 + size - 1));
- EXPECT_EQ(p1, a.GetBlockBeginFastLocked(p1 - 100));
- }
-
- for (uptr i = 0; i < kNumExpectedFalseLookups; i++) {
- void *p = reinterpret_cast<void *>(i % 1024);
- EXPECT_EQ((void *)0, a.GetBlockBeginFastLocked(p));
- p = reinterpret_cast<void *>(~0L - (i % 1024));
- EXPECT_EQ((void *)0, a.GetBlockBeginFastLocked(p));
- }
- a.ForceUnlock();
-
- for (uptr i = 0; i < kNumAllocs; i++)
- a.Deallocate(&stats, allocated[i]);
-}
-
-
-#if SANITIZER_CAN_USE_ALLOCATOR64
-// Regression test for out-of-memory condition in PopulateFreeList().
-TEST(SanitizerCommon, SizeClassAllocator64PopulateFreeListOOM) {
- // In a world where regions are small and chunks are huge...
- typedef SizeClassMap<63, 128, 16> SpecialSizeClassMap;
- typedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize, 0,
- SpecialSizeClassMap> SpecialAllocator64;
- const uptr kRegionSize =
- kAllocatorSize / SpecialSizeClassMap::kNumClassesRounded;
- SpecialAllocator64 *a = new SpecialAllocator64;
- a->Init();
- SizeClassAllocatorLocalCache<SpecialAllocator64> cache;
- memset(&cache, 0, sizeof(cache));
- cache.Init(0);
-
- // ...one man is on a mission to overflow a region with a series of
- // successive allocations.
- const uptr kClassID = 107;
- const uptr kAllocationSize = DefaultSizeClassMap::Size(kClassID);
- ASSERT_LT(2 * kAllocationSize, kRegionSize);
- ASSERT_GT(3 * kAllocationSize, kRegionSize);
- cache.Allocate(a, kClassID);
- EXPECT_DEATH(cache.Allocate(a, kClassID) && cache.Allocate(a, kClassID),
- "The process has exhausted");
- a->TestOnlyUnmap();
- delete a;
-}
-#endif
-
-TEST(SanitizerCommon, TwoLevelByteMap) {
- const u64 kSize1 = 1 << 6, kSize2 = 1 << 12;
- const u64 n = kSize1 * kSize2;
- TwoLevelByteMap<kSize1, kSize2> m;
- m.TestOnlyInit();
- for (u64 i = 0; i < n; i += 7) {
- m.set(i, (i % 100) + 1);
- }
- for (u64 j = 0; j < n; j++) {
- if (j % 7)
- EXPECT_EQ(m[j], 0);
- else
- EXPECT_EQ(m[j], (j % 100) + 1);
- }
-
- m.TestOnlyUnmap();
-}
-
-
-typedef TwoLevelByteMap<1 << 12, 1 << 13, TestMapUnmapCallback> TestByteMap;
-
-struct TestByteMapParam {
- TestByteMap *m;
- size_t shard;
- size_t num_shards;
-};
-
-void *TwoLevelByteMapUserThread(void *param) {
- TestByteMapParam *p = (TestByteMapParam*)param;
- for (size_t i = p->shard; i < p->m->size(); i += p->num_shards) {
- size_t val = (i % 100) + 1;
- p->m->set(i, val);
- EXPECT_EQ((*p->m)[i], val);
- }
- return 0;
-}
-
-TEST(SanitizerCommon, ThreadedTwoLevelByteMap) {
- TestByteMap m;
- m.TestOnlyInit();
- TestMapUnmapCallback::map_count = 0;
- TestMapUnmapCallback::unmap_count = 0;
- static const int kNumThreads = 4;
- pthread_t t[kNumThreads];
- TestByteMapParam p[kNumThreads];
- for (int i = 0; i < kNumThreads; i++) {
- p[i].m = &m;
- p[i].shard = i;
- p[i].num_shards = kNumThreads;
- PTHREAD_CREATE(&t[i], 0, TwoLevelByteMapUserThread, &p[i]);
- }
- for (int i = 0; i < kNumThreads; i++) {
- PTHREAD_JOIN(t[i], 0);
- }
- EXPECT_EQ((uptr)TestMapUnmapCallback::map_count, m.size1());
- EXPECT_EQ((uptr)TestMapUnmapCallback::unmap_count, 0UL);
- m.TestOnlyUnmap();
- EXPECT_EQ((uptr)TestMapUnmapCallback::map_count, m.size1());
- EXPECT_EQ((uptr)TestMapUnmapCallback::unmap_count, m.size1());
-}
-
-#endif // #if !SANITIZER_DEBUG
diff --git a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_allocator_testlib.cc b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_allocator_testlib.cc
deleted file mode 100644
index 0cc3b9ba6944..000000000000
--- a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_allocator_testlib.cc
+++ /dev/null
@@ -1,162 +0,0 @@
-//===-- sanitizer_allocator_testlib.cc ------------------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-// Malloc replacement library based on CombinedAllocator.
-// The primary purpose of this file is an end-to-end integration test
-// for CombinedAllocator.
-//===----------------------------------------------------------------------===//
-/* Usage:
-clang++ -fno-exceptions -g -fPIC -I. -I../include -Isanitizer \
- sanitizer_common/tests/sanitizer_allocator_testlib.cc \
- sanitizer_common/sanitizer_*.cc -shared -lpthread -o testmalloc.so
-LD_PRELOAD=`pwd`/testmalloc.so /your/app
-*/
-#include "sanitizer_common/sanitizer_allocator.h"
-#include "sanitizer_common/sanitizer_common.h"
-#include <stddef.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <pthread.h>
-
-#ifndef SANITIZER_MALLOC_HOOK
-# define SANITIZER_MALLOC_HOOK(p, s)
-#endif
-
-#ifndef SANITIZER_FREE_HOOK
-# define SANITIZER_FREE_HOOK(p)
-#endif
-
-namespace {
-static const uptr kAllocatorSpace = 0x600000000000ULL;
-static const uptr kAllocatorSize = 0x10000000000ULL; // 1T.
-
-typedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize, 0,
- CompactSizeClassMap> PrimaryAllocator;
-typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache;
-typedef LargeMmapAllocator<> SecondaryAllocator;
-typedef CombinedAllocator<PrimaryAllocator, AllocatorCache,
- SecondaryAllocator> Allocator;
-
-static Allocator allocator;
-static bool global_inited;
-static THREADLOCAL AllocatorCache cache;
-static THREADLOCAL bool thread_inited;
-static pthread_key_t pkey;
-
-static void thread_dtor(void *v) {
- if ((uptr)v != 3) {
- pthread_setspecific(pkey, (void*)((uptr)v + 1));
- return;
- }
- allocator.SwallowCache(&cache);
-}
-
-static void NOINLINE thread_init() {
- if (!global_inited) {
- global_inited = true;
- allocator.Init();
- pthread_key_create(&pkey, thread_dtor);
- }
- thread_inited = true;
- pthread_setspecific(pkey, (void*)1);
- cache.Init();
-}
-} // namespace
-
-extern "C" {
-void *malloc(size_t size) {
- if (UNLIKELY(!thread_inited))
- thread_init();
- void *p = allocator.Allocate(&cache, size, 8);
- SANITIZER_MALLOC_HOOK(p, size);
- return p;
-}
-
-void free(void *p) {
- if (UNLIKELY(!thread_inited))
- thread_init();
- SANITIZER_FREE_HOOK(p);
- allocator.Deallocate(&cache, p);
-}
-
-void *calloc(size_t nmemb, size_t size) {
- if (UNLIKELY(!thread_inited))
- thread_init();
- size *= nmemb;
- void *p = allocator.Allocate(&cache, size, 8, false);
- memset(p, 0, size);
- SANITIZER_MALLOC_HOOK(p, size);
- return p;
-}
-
-void *realloc(void *p, size_t size) {
- if (UNLIKELY(!thread_inited))
- thread_init();
- if (p) {
- SANITIZER_FREE_HOOK(p);
- }
- p = allocator.Reallocate(&cache, p, size, 8);
- if (p) {
- SANITIZER_MALLOC_HOOK(p, size);
- }
- return p;
-}
-
-void *memalign(size_t alignment, size_t size) {
- if (UNLIKELY(!thread_inited))
- thread_init();
- void *p = allocator.Allocate(&cache, size, alignment);
- SANITIZER_MALLOC_HOOK(p, size);
- return p;
-}
-
-int posix_memalign(void **memptr, size_t alignment, size_t size) {
- if (UNLIKELY(!thread_inited))
- thread_init();
- *memptr = allocator.Allocate(&cache, size, alignment);
- SANITIZER_MALLOC_HOOK(*memptr, size);
- return 0;
-}
-
-void *valloc(size_t size) {
- if (UNLIKELY(!thread_inited))
- thread_init();
- if (size == 0)
- size = GetPageSizeCached();
- void *p = allocator.Allocate(&cache, size, GetPageSizeCached());
- SANITIZER_MALLOC_HOOK(p, size);
- return p;
-}
-
-void cfree(void *p) ALIAS("free");
-void *pvalloc(size_t size) ALIAS("valloc");
-void *__libc_memalign(size_t alignment, size_t size) ALIAS("memalign");
-
-void malloc_usable_size() {
-}
-
-void mallinfo() {
-}
-
-void mallopt() {
-}
-} // extern "C"
-
-namespace std {
- struct nothrow_t;
-}
-
-void *operator new(size_t size) ALIAS("malloc");
-void *operator new[](size_t size) ALIAS("malloc");
-void *operator new(size_t size, std::nothrow_t const&) ALIAS("malloc");
-void *operator new[](size_t size, std::nothrow_t const&) ALIAS("malloc");
-void operator delete(void *ptr) throw() ALIAS("free");
-void operator delete[](void *ptr) throw() ALIAS("free");
-void operator delete(void *ptr, std::nothrow_t const&) ALIAS("free");
-void operator delete[](void *ptr, std::nothrow_t const&) ALIAS("free");
diff --git a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_atomic_test.cc b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_atomic_test.cc
deleted file mode 100644
index 56bcd35c826c..000000000000
--- a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_atomic_test.cc
+++ /dev/null
@@ -1,128 +0,0 @@
-//===-- sanitizer_atomic_test.cc ------------------------------------------===//
-//
-// 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 ThreadSanitizer/AddressSanitizer runtime.
-//
-//===----------------------------------------------------------------------===//
-#include "sanitizer_common/sanitizer_atomic.h"
-#include "gtest/gtest.h"
-
-namespace __sanitizer {
-
-template<typename T>
-struct ValAndMagic {
- typename T::Type magic0;
- T a;
- typename T::Type magic1;
-
- static ValAndMagic<T> *sink;
-};
-
-template<typename T>
-ValAndMagic<T> *ValAndMagic<T>::sink;
-
-template<typename T, memory_order load_mo, memory_order store_mo>
-void CheckStoreLoad() {
- typedef typename T::Type Type;
- ValAndMagic<T> val;
- // Prevent the compiler from scalarizing the struct.
- ValAndMagic<T>::sink = &val;
- // Ensure that surrounding memory is not overwritten.
- val.magic0 = val.magic1 = (Type)-3;
- for (u64 i = 0; i < 100; i++) {
- // Generate a value that occupies all bytes of the variable.
- u64 v = i;
- v |= v << 8;
- v |= v << 16;
- v |= v << 32;
- val.a.val_dont_use = (Type)v;
- EXPECT_EQ(atomic_load(&val.a, load_mo), (Type)v);
- val.a.val_dont_use = (Type)-1;
- atomic_store(&val.a, (Type)v, store_mo);
- EXPECT_EQ(val.a.val_dont_use, (Type)v);
- }
- EXPECT_EQ(val.magic0, (Type)-3);
- EXPECT_EQ(val.magic1, (Type)-3);
-}
-
-TEST(SanitizerCommon, AtomicStoreLoad) {
- CheckStoreLoad<atomic_uint8_t, memory_order_relaxed, memory_order_relaxed>();
- CheckStoreLoad<atomic_uint8_t, memory_order_consume, memory_order_relaxed>();
- CheckStoreLoad<atomic_uint8_t, memory_order_acquire, memory_order_relaxed>();
- CheckStoreLoad<atomic_uint8_t, memory_order_relaxed, memory_order_release>();
- CheckStoreLoad<atomic_uint8_t, memory_order_seq_cst, memory_order_seq_cst>();
-
- CheckStoreLoad<atomic_uint16_t, memory_order_relaxed, memory_order_relaxed>();
- CheckStoreLoad<atomic_uint16_t, memory_order_consume, memory_order_relaxed>();
- CheckStoreLoad<atomic_uint16_t, memory_order_acquire, memory_order_relaxed>();
- CheckStoreLoad<atomic_uint16_t, memory_order_relaxed, memory_order_release>();
- CheckStoreLoad<atomic_uint16_t, memory_order_seq_cst, memory_order_seq_cst>();
-
- CheckStoreLoad<atomic_uint32_t, memory_order_relaxed, memory_order_relaxed>();
- CheckStoreLoad<atomic_uint32_t, memory_order_consume, memory_order_relaxed>();
- CheckStoreLoad<atomic_uint32_t, memory_order_acquire, memory_order_relaxed>();
- CheckStoreLoad<atomic_uint32_t, memory_order_relaxed, memory_order_release>();
- CheckStoreLoad<atomic_uint32_t, memory_order_seq_cst, memory_order_seq_cst>();
-
- CheckStoreLoad<atomic_uint64_t, memory_order_relaxed, memory_order_relaxed>();
- CheckStoreLoad<atomic_uint64_t, memory_order_consume, memory_order_relaxed>();
- CheckStoreLoad<atomic_uint64_t, memory_order_acquire, memory_order_relaxed>();
- CheckStoreLoad<atomic_uint64_t, memory_order_relaxed, memory_order_release>();
- CheckStoreLoad<atomic_uint64_t, memory_order_seq_cst, memory_order_seq_cst>();
-
- CheckStoreLoad<atomic_uintptr_t, memory_order_relaxed, memory_order_relaxed>
- ();
- CheckStoreLoad<atomic_uintptr_t, memory_order_consume, memory_order_relaxed>
- ();
- CheckStoreLoad<atomic_uintptr_t, memory_order_acquire, memory_order_relaxed>
- ();
- CheckStoreLoad<atomic_uintptr_t, memory_order_relaxed, memory_order_release>
- ();
- CheckStoreLoad<atomic_uintptr_t, memory_order_seq_cst, memory_order_seq_cst>
- ();
-}
-
-// Clang crashes while compiling this test for Android:
-// http://llvm.org/bugs/show_bug.cgi?id=15587
-#if !SANITIZER_ANDROID
-template<typename T>
-void CheckAtomicCompareExchange() {
- typedef typename T::Type Type;
- {
- Type old_val = 42;
- Type new_val = 24;
- Type var = old_val;
- EXPECT_TRUE(atomic_compare_exchange_strong((T*)&var, &old_val, new_val,
- memory_order_relaxed));
- EXPECT_FALSE(atomic_compare_exchange_strong((T*)&var, &old_val, new_val,
- memory_order_relaxed));
- EXPECT_EQ(new_val, old_val);
- }
- {
- Type old_val = 42;
- Type new_val = 24;
- Type var = old_val;
- EXPECT_TRUE(atomic_compare_exchange_weak((T*)&var, &old_val, new_val,
- memory_order_relaxed));
- EXPECT_FALSE(atomic_compare_exchange_weak((T*)&var, &old_val, new_val,
- memory_order_relaxed));
- EXPECT_EQ(new_val, old_val);
- }
-}
-
-TEST(SanitizerCommon, AtomicCompareExchangeTest) {
- CheckAtomicCompareExchange<atomic_uint8_t>();
- CheckAtomicCompareExchange<atomic_uint16_t>();
- CheckAtomicCompareExchange<atomic_uint32_t>();
- CheckAtomicCompareExchange<atomic_uint64_t>();
- CheckAtomicCompareExchange<atomic_uintptr_t>();
-}
-#endif //!SANITIZER_ANDROID
-
-} // namespace __sanitizer
diff --git a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_bitvector_test.cc b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_bitvector_test.cc
deleted file mode 100644
index 706b4c58968e..000000000000
--- a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_bitvector_test.cc
+++ /dev/null
@@ -1,176 +0,0 @@
-//===-- sanitizer_bitvector_test.cc ---------------------------------------===//
-//
-// 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 Sanitizer runtime.
-// Tests for sanitizer_bitvector.h.
-//
-//===----------------------------------------------------------------------===//
-#include "sanitizer_common/sanitizer_bitvector.h"
-
-#include "sanitizer_test_utils.h"
-
-#include "gtest/gtest.h"
-
-#include <algorithm>
-#include <vector>
-#include <set>
-
-using namespace __sanitizer;
-using namespace std;
-
-
-// Check the 'bv' == 's' and that the indexes go in increasing order.
-// Also check the BV::Iterator
-template <class BV>
-static void CheckBV(const BV &bv, const set<uptr> &s) {
- BV t;
- t.copyFrom(bv);
- set<uptr> t_s(s);
- uptr last_idx = bv.size();
- uptr count = 0;
- for (typename BV::Iterator it(bv); it.hasNext();) {
- uptr idx = it.next();
- count++;
- if (last_idx != bv.size())
- EXPECT_LT(last_idx, idx);
- last_idx = idx;
- EXPECT_TRUE(s.count(idx));
- }
- EXPECT_EQ(count, s.size());
-
- last_idx = bv.size();
- while (!t.empty()) {
- uptr idx = t.getAndClearFirstOne();
- if (last_idx != bv.size())
- EXPECT_LT(last_idx, idx);
- last_idx = idx;
- EXPECT_TRUE(t_s.erase(idx));
- }
- EXPECT_TRUE(t_s.empty());
-}
-
-template <class BV>
-void Print(const BV &bv) {
- BV t;
- t.copyFrom(bv);
- while (!t.empty()) {
- uptr idx = t.getAndClearFirstOne();
- fprintf(stderr, "%zd ", idx);
- }
- fprintf(stderr, "\n");
-}
-
-void Print(const set<uptr> &s) {
- for (set<uptr>::iterator it = s.begin(); it != s.end(); ++it) {
- fprintf(stderr, "%zd ", *it);
- }
- fprintf(stderr, "\n");
-}
-
-template <class BV>
-void TestBitVector(uptr expected_size) {
- BV bv, bv1, t_bv;
- EXPECT_EQ(expected_size, BV::kSize);
- bv.clear();
- EXPECT_TRUE(bv.empty());
- bv.setBit(5);
- EXPECT_FALSE(bv.empty());
- EXPECT_FALSE(bv.getBit(4));
- EXPECT_FALSE(bv.getBit(6));
- EXPECT_TRUE(bv.getBit(5));
- bv.clearBit(5);
- EXPECT_FALSE(bv.getBit(5));
-
- // test random bits
- bv.clear();
- set<uptr> s;
- for (uptr it = 0; it < 1000; it++) {
- uptr bit = ((uptr)my_rand() % bv.size());
- EXPECT_EQ(bv.getBit(bit), s.count(bit) == 1);
- switch (my_rand() % 2) {
- case 0:
- EXPECT_EQ(bv.setBit(bit), s.insert(bit).second);
- break;
- case 1:
- size_t old_size = s.size();
- s.erase(bit);
- EXPECT_EQ(bv.clearBit(bit), old_size > s.size());
- break;
- }
- EXPECT_EQ(bv.getBit(bit), s.count(bit) == 1);
- }
-
- vector<uptr>bits(bv.size());
- // Test setUnion, setIntersection, setDifference,
- // intersectsWith, and getAndClearFirstOne.
- for (uptr it = 0; it < 30; it++) {
- // iota
- for (size_t j = 0; j < bits.size(); j++) bits[j] = j;
- random_shuffle(bits.begin(), bits.end());
- set<uptr> s, s1, t_s;
- bv.clear();
- bv1.clear();
- uptr n_bits = ((uptr)my_rand() % bv.size()) + 1;
- uptr n_bits1 = (uptr)my_rand() % (bv.size() / 2);
- EXPECT_TRUE(n_bits > 0 && n_bits <= bv.size());
- EXPECT_TRUE(n_bits1 < bv.size() / 2);
- for (uptr i = 0; i < n_bits; i++) {
- bv.setBit(bits[i]);
- s.insert(bits[i]);
- }
- CheckBV(bv, s);
- for (uptr i = 0; i < n_bits1; i++) {
- bv1.setBit(bits[bv.size() / 2 + i]);
- s1.insert(bits[bv.size() / 2 + i]);
- }
- CheckBV(bv1, s1);
-
- vector<uptr> vec;
- set_intersection(s.begin(), s.end(), s1.begin(), s1.end(),
- back_insert_iterator<vector<uptr> >(vec));
- EXPECT_EQ(bv.intersectsWith(bv1), !vec.empty());
-
- // setUnion
- t_s = s;
- t_bv.copyFrom(bv);
- t_s.insert(s1.begin(), s1.end());
- EXPECT_EQ(t_bv.setUnion(bv1), s.size() != t_s.size());
- CheckBV(t_bv, t_s);
-
- // setIntersection
- t_s = set<uptr>(vec.begin(), vec.end());
- t_bv.copyFrom(bv);
- EXPECT_EQ(t_bv.setIntersection(bv1), s.size() != t_s.size());
- CheckBV(t_bv, t_s);
-
- // setDifference
- vec.clear();
- set_difference(s.begin(), s.end(), s1.begin(), s1.end(),
- back_insert_iterator<vector<uptr> >(vec));
- t_s = set<uptr>(vec.begin(), vec.end());
- t_bv.copyFrom(bv);
- EXPECT_EQ(t_bv.setDifference(bv1), s.size() != t_s.size());
- CheckBV(t_bv, t_s);
- }
-}
-
-TEST(SanitizerCommon, BasicBitVector) {
- TestBitVector<BasicBitVector<u8> >(8);
- TestBitVector<BasicBitVector<u16> >(16);
- TestBitVector<BasicBitVector<> >(SANITIZER_WORDSIZE);
-}
-
-TEST(SanitizerCommon, TwoLevelBitVector) {
- uptr ws = SANITIZER_WORDSIZE;
- TestBitVector<TwoLevelBitVector<1, BasicBitVector<u8> > >(8 * 8);
- TestBitVector<TwoLevelBitVector<> >(ws * ws);
- TestBitVector<TwoLevelBitVector<2> >(ws * ws * 2);
- TestBitVector<TwoLevelBitVector<3> >(ws * ws * 3);
- TestBitVector<TwoLevelBitVector<3, BasicBitVector<u16> > >(16 * 16 * 3);
-}
diff --git a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_bvgraph_test.cc b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_bvgraph_test.cc
deleted file mode 100644
index 3b39f8dd734a..000000000000
--- a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_bvgraph_test.cc
+++ /dev/null
@@ -1,339 +0,0 @@
-//===-- sanitizer_bvgraph_test.cc -----------------------------------------===//
-//
-// 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 Sanitizer runtime.
-// Tests for sanitizer_bvgraph.h.
-//
-//===----------------------------------------------------------------------===//
-#include "sanitizer_common/sanitizer_bvgraph.h"
-
-#include "sanitizer_test_utils.h"
-
-#include "gtest/gtest.h"
-
-#include <algorithm>
-#include <vector>
-#include <set>
-
-using namespace __sanitizer;
-using namespace std;
-
-typedef BasicBitVector<u8> BV1;
-typedef BasicBitVector<> BV2;
-typedef TwoLevelBitVector<> BV3;
-typedef TwoLevelBitVector<3, BasicBitVector<u8> > BV4;
-
-template<class G>
-void PrintGraph(const G &g) {
- for (uptr i = 0; i < g.size(); i++) {
- for (uptr j = 0; j < g.size(); j++) {
- fprintf(stderr, "%d", g.hasEdge(i, j));
- }
- fprintf(stderr, "\n");
- }
-}
-
-
-class SimpleGraph {
- public:
- void clear() { s_.clear(); }
- bool addEdge(uptr from, uptr to) {
- return s_.insert(idx(from, to)).second;
- }
- bool removeEdge(uptr from, uptr to) {
- return s_.erase(idx(from, to));
- }
- template <class G>
- void checkSameAs(G *g) {
- for (set<uptr>::iterator it = s_.begin(); it != s_.end(); ++it) {
- uptr from = *it >> 16;
- uptr to = *it & ((1 << 16) - 1);
- EXPECT_TRUE(g->removeEdge(from, to));
- }
- EXPECT_TRUE(g->empty());
- }
- private:
- uptr idx(uptr from, uptr to) {
- CHECK_LE(from|to, 1 << 16);
- return (from << 16) + to;
- }
- set<uptr> s_;
-};
-
-template <class BV>
-void BasicTest() {
- BVGraph<BV> g;
- g.clear();
- BV target;
- SimpleGraph s_g;
- set<uptr> s;
- set<uptr> s_target;
- int num_reachable = 0;
- for (int it = 0; it < 1000; it++) {
- target.clear();
- s_target.clear();
- for (int t = 0; t < 4; t++) {
- uptr idx = (uptr)my_rand() % g.size();
- EXPECT_EQ(target.setBit(idx), s_target.insert(idx).second);
- }
- uptr from = my_rand() % g.size();
- uptr to = my_rand() % g.size();
- EXPECT_EQ(g.addEdge(from, to), s_g.addEdge(from, to));
- EXPECT_TRUE(g.hasEdge(from, to));
- for (int i = 0; i < 10; i++) {
- from = my_rand() % g.size();
- bool is_reachable = g.isReachable(from, target);
- if (is_reachable) {
- uptr path[BV::kSize];
- uptr len;
- for (len = 1; len < BV::kSize; len++) {
- if (g.findPath(from, target, path, len) == len)
- break;
- }
- EXPECT_LT(len, BV::kSize);
- EXPECT_TRUE(target.getBit(path[len - 1]));
- // fprintf(stderr, "reachable: %zd; path %zd {%zd %zd %zd}\n",
- // from, len, path[0], path[1], path[2]);
- num_reachable++;
- }
- }
- }
- EXPECT_GT(num_reachable, 0);
-}
-
-TEST(BVGraph, BasicTest) {
- BasicTest<BV1>();
- BasicTest<BV2>();
- BasicTest<BV3>();
- BasicTest<BV4>();
-}
-
-template <class BV>
-void RemoveEdges() {
- SimpleGraph s_g;
- BVGraph<BV> g;
- g.clear();
- BV bv;
- set<uptr> s;
- for (int it = 0; it < 100; it++) {
- s.clear();
- bv.clear();
- s_g.clear();
- g.clear();
- for (uptr j = 0; j < g.size() * 2; j++) {
- uptr from = my_rand() % g.size();
- uptr to = my_rand() % g.size();
- EXPECT_EQ(g.addEdge(from, to), s_g.addEdge(from, to));
- }
- for (uptr j = 0; j < 5; j++) {
- uptr idx = my_rand() % g.size();
- s.insert(idx);
- bv.setBit(idx);
- }
-
- if (it % 2) {
- g.removeEdgesFrom(bv);
- for (set<uptr>::iterator from = s.begin(); from != s.end(); ++from) {
- for (uptr to = 0; to < g.size(); to++)
- s_g.removeEdge(*from, to);
- }
- } else {
- g.removeEdgesTo(bv);
- for (set<uptr>::iterator to = s.begin(); to != s.end(); ++to) {
- for (uptr from = 0; from < g.size(); from++)
- s_g.removeEdge(from, *to);
- }
- }
- s_g.checkSameAs(&g);
- }
-}
-
-TEST(BVGraph, RemoveEdges) {
- RemoveEdges<BV1>();
- RemoveEdges<BV2>();
- RemoveEdges<BV3>();
- RemoveEdges<BV4>();
-}
-
-template <class BV>
-void Test_isReachable() {
- uptr path[5];
- BVGraph<BV> g;
- g.clear();
- BV target;
- target.clear();
- uptr t0 = 0;
- uptr t1 = g.size() - 1;
- target.setBit(t0);
- target.setBit(t1);
-
- uptr f0 = 1;
- uptr f1 = 2;
- uptr f2 = g.size() / 2;
- uptr f3 = g.size() - 2;
-
- EXPECT_FALSE(g.isReachable(f0, target));
- EXPECT_FALSE(g.isReachable(f1, target));
- EXPECT_FALSE(g.isReachable(f2, target));
- EXPECT_FALSE(g.isReachable(f3, target));
-
- g.addEdge(f0, f1);
- g.addEdge(f1, f2);
- g.addEdge(f2, f3);
- EXPECT_FALSE(g.isReachable(f0, target));
- EXPECT_FALSE(g.isReachable(f1, target));
- EXPECT_FALSE(g.isReachable(f2, target));
- EXPECT_FALSE(g.isReachable(f3, target));
-
- g.addEdge(f1, t0);
- EXPECT_TRUE(g.isReachable(f0, target));
- EXPECT_TRUE(g.isReachable(f1, target));
- EXPECT_FALSE(g.isReachable(f2, target));
- EXPECT_FALSE(g.isReachable(f3, target));
- EXPECT_EQ(g.findPath(f0, target, path, ARRAY_SIZE(path)), 3U);
- EXPECT_EQ(path[0], f0);
- EXPECT_EQ(path[1], f1);
- EXPECT_EQ(path[2], t0);
- EXPECT_EQ(g.findPath(f1, target, path, ARRAY_SIZE(path)), 2U);
- EXPECT_EQ(path[0], f1);
- EXPECT_EQ(path[1], t0);
-
- g.addEdge(f3, t1);
- EXPECT_TRUE(g.isReachable(f0, target));
- EXPECT_TRUE(g.isReachable(f1, target));
- EXPECT_TRUE(g.isReachable(f2, target));
- EXPECT_TRUE(g.isReachable(f3, target));
-}
-
-TEST(BVGraph, isReachable) {
- Test_isReachable<BV1>();
- Test_isReachable<BV2>();
- Test_isReachable<BV3>();
- Test_isReachable<BV4>();
-}
-
-template <class BV>
-void LongCycle() {
- BVGraph<BV> g;
- g.clear();
- vector<uptr> path_vec(g.size());
- uptr *path = path_vec.data();
- uptr start = 5;
- for (uptr i = start; i < g.size() - 1; i++) {
- g.addEdge(i, i + 1);
- for (uptr j = 0; j < start; j++)
- g.addEdge(i, j);
- }
- // Bad graph that looks like this:
- // 00000000000000
- // 00000000000000
- // 00000000000000
- // 00000000000000
- // 00000000000000
- // 11111010000000
- // 11111001000000
- // 11111000100000
- // 11111000010000
- // 11111000001000
- // 11111000000100
- // 11111000000010
- // 11111000000001
- // if (g.size() <= 64) PrintGraph(g);
- BV target;
- for (uptr i = start + 1; i < g.size(); i += 11) {
- // if ((i & (i - 1)) == 0) fprintf(stderr, "Path: : %zd\n", i);
- target.clear();
- target.setBit(i);
- EXPECT_TRUE(g.isReachable(start, target));
- EXPECT_EQ(g.findPath(start, target, path, g.size()), i - start + 1);
- }
-}
-
-TEST(BVGraph, LongCycle) {
- LongCycle<BV1>();
- LongCycle<BV2>();
- LongCycle<BV3>();
- LongCycle<BV4>();
-}
-
-template <class BV>
-void ShortestPath() {
- uptr path[8];
- BVGraph<BV> g;
- g.clear();
- BV t7;
- t7.clear();
- t7.setBit(7);
- // 1=>2=>3=>4=>5=>6=>7
- // 1=>7
- g.addEdge(1, 2);
- g.addEdge(2, 3);
- g.addEdge(3, 4);
- g.addEdge(4, 5);
- g.addEdge(5, 6);
- g.addEdge(6, 7);
- g.addEdge(1, 7);
- EXPECT_TRUE(g.isReachable(1, t7));
- // No path of length 1.
- EXPECT_EQ(0U, g.findPath(1, t7, path, 1));
- // Trying to find a path of len 2..6 gives path of len 2.
- EXPECT_EQ(2U, g.findPath(1, t7, path, 2));
- EXPECT_EQ(2U, g.findPath(1, t7, path, 3));
- EXPECT_EQ(2U, g.findPath(1, t7, path, 4));
- EXPECT_EQ(2U, g.findPath(1, t7, path, 5));
- EXPECT_EQ(2U, g.findPath(1, t7, path, 6));
- // Trying to find a path of len 7 gives path of len 7, because this is DFS.
- EXPECT_EQ(7U, g.findPath(1, t7, path, 7));
- // But findShortestPath will find the shortest path.
- EXPECT_EQ(2U, g.findShortestPath(1, t7, path, 2));
- EXPECT_EQ(2U, g.findShortestPath(1, t7, path, 7));
-}
-
-TEST(BVGraph, ShortestPath) {
- ShortestPath<BV1>();
- ShortestPath<BV2>();
- ShortestPath<BV3>();
- ShortestPath<BV4>();
-}
-
-template <class BV>
-void RunAddEdgesTest() {
- BVGraph<BV> g;
- BV from;
- const int kMaxEdges = 10;
- uptr added_edges[kMaxEdges];
- g.clear();
- from.clear();
- EXPECT_EQ(0U, g.addEdges(from, 0, added_edges, kMaxEdges));
- EXPECT_EQ(0U, g.addEdges(from, 1, added_edges, kMaxEdges));
- from.setBit(0);
- EXPECT_EQ(1U, g.addEdges(from, 1, added_edges, kMaxEdges));
- EXPECT_EQ(0U, added_edges[0]);
- EXPECT_EQ(0U, g.addEdges(from, 1, added_edges, kMaxEdges));
-
- from.clear();
- from.setBit(1);
- EXPECT_EQ(1U, g.addEdges(from, 4, added_edges, kMaxEdges));
- EXPECT_TRUE(g.hasEdge(1, 4));
- EXPECT_FALSE(g.hasEdge(1, 5));
- EXPECT_EQ(1U, added_edges[0]);
- from.setBit(2);
- from.setBit(3);
- EXPECT_EQ(2U, g.addEdges(from, 4, added_edges, kMaxEdges));
- EXPECT_TRUE(g.hasEdge(2, 4));
- EXPECT_FALSE(g.hasEdge(2, 5));
- EXPECT_TRUE(g.hasEdge(3, 4));
- EXPECT_FALSE(g.hasEdge(3, 5));
- EXPECT_EQ(2U, added_edges[0]);
- EXPECT_EQ(3U, added_edges[1]);
-}
-
-TEST(BVGraph, AddEdgesTest) {
- RunAddEdgesTest<BV2>();
-}
diff --git a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_common_test.cc b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_common_test.cc
deleted file mode 100644
index e08a38c82450..000000000000
--- a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_common_test.cc
+++ /dev/null
@@ -1,229 +0,0 @@
-//===-- sanitizer_common_test.cc ------------------------------------------===//
-//
-// 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 ThreadSanitizer/AddressSanitizer runtime.
-//
-//===----------------------------------------------------------------------===//
-#include "sanitizer_common/sanitizer_allocator_internal.h"
-#include "sanitizer_common/sanitizer_common.h"
-#include "sanitizer_common/sanitizer_flags.h"
-#include "sanitizer_common/sanitizer_libc.h"
-#include "sanitizer_common/sanitizer_platform.h"
-
-#include "sanitizer_pthread_wrappers.h"
-
-#include "gtest/gtest.h"
-
-namespace __sanitizer {
-
-static bool IsSorted(const uptr *array, uptr n) {
- for (uptr i = 1; i < n; i++) {
- if (array[i] < array[i - 1]) return false;
- }
- return true;
-}
-
-TEST(SanitizerCommon, SortTest) {
- uptr array[100];
- uptr n = 100;
- // Already sorted.
- for (uptr i = 0; i < n; i++) {
- array[i] = i;
- }
- SortArray(array, n);
- EXPECT_TRUE(IsSorted(array, n));
- // Reverse order.
- for (uptr i = 0; i < n; i++) {
- array[i] = n - 1 - i;
- }
- SortArray(array, n);
- EXPECT_TRUE(IsSorted(array, n));
- // Mixed order.
- for (uptr i = 0; i < n; i++) {
- array[i] = (i % 2 == 0) ? i : n - 1 - i;
- }
- SortArray(array, n);
- EXPECT_TRUE(IsSorted(array, n));
- // All equal.
- for (uptr i = 0; i < n; i++) {
- array[i] = 42;
- }
- SortArray(array, n);
- EXPECT_TRUE(IsSorted(array, n));
- // All but one sorted.
- for (uptr i = 0; i < n - 1; i++) {
- array[i] = i;
- }
- array[n - 1] = 42;
- SortArray(array, n);
- EXPECT_TRUE(IsSorted(array, n));
- // Minimal case - sort three elements.
- array[0] = 1;
- array[1] = 0;
- SortArray(array, 2);
- EXPECT_TRUE(IsSorted(array, 2));
-}
-
-TEST(SanitizerCommon, MmapAlignedOrDie) {
- uptr PageSize = GetPageSizeCached();
- for (uptr size = 1; size <= 32; size *= 2) {
- for (uptr alignment = 1; alignment <= 32; alignment *= 2) {
- for (int iter = 0; iter < 100; iter++) {
- uptr res = (uptr)MmapAlignedOrDie(
- size * PageSize, alignment * PageSize, "MmapAlignedOrDieTest");
- EXPECT_EQ(0U, res % (alignment * PageSize));
- internal_memset((void*)res, 1, size * PageSize);
- UnmapOrDie((void*)res, size * PageSize);
- }
- }
- }
-}
-
-#if SANITIZER_LINUX
-TEST(SanitizerCommon, SanitizerSetThreadName) {
- const char *names[] = {
- "0123456789012",
- "01234567890123",
- "012345678901234", // Larger names will be truncated on linux.
- };
-
- for (size_t i = 0; i < ARRAY_SIZE(names); i++) {
- EXPECT_TRUE(SanitizerSetThreadName(names[i]));
- char buff[100];
- EXPECT_TRUE(SanitizerGetThreadName(buff, sizeof(buff) - 1));
- EXPECT_EQ(0, internal_strcmp(buff, names[i]));
- }
-}
-#endif
-
-TEST(SanitizerCommon, InternalMmapVector) {
- InternalMmapVector<uptr> vector(1);
- for (uptr i = 0; i < 100; i++) {
- EXPECT_EQ(i, vector.size());
- vector.push_back(i);
- }
- for (uptr i = 0; i < 100; i++) {
- EXPECT_EQ(i, vector[i]);
- }
- for (int i = 99; i >= 0; i--) {
- EXPECT_EQ((uptr)i, vector.back());
- vector.pop_back();
- EXPECT_EQ((uptr)i, vector.size());
- }
- InternalMmapVector<uptr> empty_vector(0);
- CHECK_GT(empty_vector.capacity(), 0U);
- CHECK_EQ(0U, empty_vector.size());
-}
-
-void TestThreadInfo(bool main) {
- uptr stk_addr = 0;
- uptr stk_size = 0;
- uptr tls_addr = 0;
- uptr tls_size = 0;
- GetThreadStackAndTls(main, &stk_addr, &stk_size, &tls_addr, &tls_size);
-
- int stack_var;
- EXPECT_NE(stk_addr, (uptr)0);
- EXPECT_NE(stk_size, (uptr)0);
- EXPECT_GT((uptr)&stack_var, stk_addr);
- EXPECT_LT((uptr)&stack_var, stk_addr + stk_size);
-
-#if SANITIZER_LINUX && defined(__x86_64__)
- static __thread int thread_var;
- EXPECT_NE(tls_addr, (uptr)0);
- EXPECT_NE(tls_size, (uptr)0);
- EXPECT_GT((uptr)&thread_var, tls_addr);
- EXPECT_LT((uptr)&thread_var, tls_addr + tls_size);
-
- // Ensure that tls and stack do not intersect.
- uptr tls_end = tls_addr + tls_size;
- EXPECT_TRUE(tls_addr < stk_addr || tls_addr >= stk_addr + stk_size);
- EXPECT_TRUE(tls_end < stk_addr || tls_end >= stk_addr + stk_size);
- EXPECT_TRUE((tls_addr < stk_addr) == (tls_end < stk_addr));
-#endif
-}
-
-static void *WorkerThread(void *arg) {
- TestThreadInfo(false);
- return 0;
-}
-
-TEST(SanitizerCommon, ThreadStackTlsMain) {
- InitTlsSize();
- TestThreadInfo(true);
-}
-
-TEST(SanitizerCommon, ThreadStackTlsWorker) {
- InitTlsSize();
- pthread_t t;
- PTHREAD_CREATE(&t, 0, WorkerThread, 0);
- PTHREAD_JOIN(t, 0);
-}
-
-bool UptrLess(uptr a, uptr b) {
- return a < b;
-}
-
-TEST(SanitizerCommon, InternalBinarySearch) {
- static const uptr kSize = 5;
- uptr arr[kSize];
- for (uptr i = 0; i < kSize; i++) arr[i] = i * i;
-
- for (uptr i = 0; i < kSize; i++)
- ASSERT_EQ(InternalBinarySearch(arr, 0, kSize, i * i, UptrLess), i);
-
- ASSERT_EQ(InternalBinarySearch(arr, 0, kSize, 7, UptrLess), kSize + 1);
-}
-
-#if SANITIZER_LINUX && !SANITIZER_ANDROID
-TEST(SanitizerCommon, FindPathToBinary) {
- char *true_path = FindPathToBinary("true");
- EXPECT_NE((char*)0, internal_strstr(true_path, "/bin/true"));
- InternalFree(true_path);
- EXPECT_EQ(0, FindPathToBinary("unexisting_binary.ergjeorj"));
-}
-#endif
-
-TEST(SanitizerCommon, StripPathPrefix) {
- EXPECT_EQ(0, StripPathPrefix(0, "prefix"));
- EXPECT_STREQ("foo", StripPathPrefix("foo", 0));
- EXPECT_STREQ("dir/file.cc",
- StripPathPrefix("/usr/lib/dir/file.cc", "/usr/lib/"));
- EXPECT_STREQ("/file.cc", StripPathPrefix("/usr/myroot/file.cc", "/myroot"));
- EXPECT_STREQ("file.h", StripPathPrefix("/usr/lib/./file.h", "/usr/lib/"));
-}
-
-TEST(SanitizerCommon, InternalScopedString) {
- InternalScopedString str(10);
- EXPECT_EQ(0U, str.length());
- EXPECT_STREQ("", str.data());
-
- str.append("foo");
- EXPECT_EQ(3U, str.length());
- EXPECT_STREQ("foo", str.data());
-
- int x = 1234;
- str.append("%d", x);
- EXPECT_EQ(7U, str.length());
- EXPECT_STREQ("foo1234", str.data());
-
- str.append("%d", x);
- EXPECT_EQ(9U, str.length());
- EXPECT_STREQ("foo123412", str.data());
-
- str.clear();
- EXPECT_EQ(0U, str.length());
- EXPECT_STREQ("", str.data());
-
- str.append("0123456789");
- EXPECT_EQ(9U, str.length());
- EXPECT_STREQ("012345678", str.data());
-}
-
-} // namespace __sanitizer
diff --git a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_deadlock_detector_test.cc b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_deadlock_detector_test.cc
deleted file mode 100644
index 7835eef76d06..000000000000
--- a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_deadlock_detector_test.cc
+++ /dev/null
@@ -1,496 +0,0 @@
-//===-- sanitizer_deadlock_detector_test.cc -------------------------------===//
-//
-// 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 Sanitizer runtime.
-// Tests for sanitizer_deadlock_detector.h
-//
-//===----------------------------------------------------------------------===//
-#include "sanitizer_common/sanitizer_deadlock_detector.h"
-
-#include "sanitizer_test_utils.h"
-
-#include "gtest/gtest.h"
-
-#include <algorithm>
-#include <vector>
-#include <set>
-
-using namespace __sanitizer;
-using namespace std;
-
-typedef BasicBitVector<u8> BV1;
-typedef BasicBitVector<> BV2;
-typedef TwoLevelBitVector<> BV3;
-typedef TwoLevelBitVector<3, BasicBitVector<u8> > BV4;
-
-// Poor man's unique_ptr.
-template<class BV>
-struct ScopedDD {
- ScopedDD() {
- dp = new DeadlockDetector<BV>;
- dp->clear();
- dtls.clear();
- }
- ~ScopedDD() { delete dp; }
- DeadlockDetector<BV> *dp;
- DeadlockDetectorTLS<BV> dtls;
-};
-
-template <class BV>
-void RunBasicTest() {
- uptr path[10];
- ScopedDD<BV> sdd;
- DeadlockDetector<BV> &d = *sdd.dp;
- DeadlockDetectorTLS<BV> &dtls = sdd.dtls;
- set<uptr> s;
- for (size_t i = 0; i < d.size() * 3; i++) {
- uptr node = d.newNode(0);
- EXPECT_TRUE(s.insert(node).second);
- }
-
- d.clear();
- s.clear();
- // Add size() nodes.
- for (size_t i = 0; i < d.size(); i++) {
- uptr node = d.newNode(0);
- EXPECT_TRUE(s.insert(node).second);
- }
- // Remove all nodes.
- for (set<uptr>::iterator it = s.begin(); it != s.end(); ++it)
- d.removeNode(*it);
- // The nodes should be reused.
- for (size_t i = 0; i < d.size(); i++) {
- uptr node = d.newNode(0);
- EXPECT_FALSE(s.insert(node).second);
- }
-
- // Cycle: n1->n2->n1
- {
- d.clear();
- dtls.clear();
- uptr n1 = d.newNode(1);
- uptr n2 = d.newNode(2);
- EXPECT_FALSE(d.onLock(&dtls, n1));
- EXPECT_FALSE(d.onLock(&dtls, n2));
- d.onUnlock(&dtls, n2);
- d.onUnlock(&dtls, n1);
-
- EXPECT_FALSE(d.onLock(&dtls, n2));
- EXPECT_EQ(0U, d.findPathToLock(&dtls, n1, path, 1));
- EXPECT_EQ(2U, d.findPathToLock(&dtls, n1, path, 10));
- EXPECT_EQ(2U, d.findPathToLock(&dtls, n1, path, 2));
- EXPECT_TRUE(d.onLock(&dtls, n1));
- EXPECT_EQ(path[0], n1);
- EXPECT_EQ(path[1], n2);
- EXPECT_EQ(d.getData(n1), 1U);
- EXPECT_EQ(d.getData(n2), 2U);
- d.onUnlock(&dtls, n1);
- d.onUnlock(&dtls, n2);
- }
-
- // Cycle: n1->n2->n3->n1
- {
- d.clear();
- dtls.clear();
- uptr n1 = d.newNode(1);
- uptr n2 = d.newNode(2);
- uptr n3 = d.newNode(3);
-
- EXPECT_FALSE(d.onLock(&dtls, n1));
- EXPECT_FALSE(d.onLock(&dtls, n2));
- d.onUnlock(&dtls, n2);
- d.onUnlock(&dtls, n1);
-
- EXPECT_FALSE(d.onLock(&dtls, n2));
- EXPECT_FALSE(d.onLock(&dtls, n3));
- d.onUnlock(&dtls, n3);
- d.onUnlock(&dtls, n2);
-
- EXPECT_FALSE(d.onLock(&dtls, n3));
- EXPECT_EQ(0U, d.findPathToLock(&dtls, n1, path, 2));
- EXPECT_EQ(3U, d.findPathToLock(&dtls, n1, path, 10));
- EXPECT_TRUE(d.onLock(&dtls, n1));
- EXPECT_EQ(path[0], n1);
- EXPECT_EQ(path[1], n2);
- EXPECT_EQ(path[2], n3);
- EXPECT_EQ(d.getData(n1), 1U);
- EXPECT_EQ(d.getData(n2), 2U);
- EXPECT_EQ(d.getData(n3), 3U);
- d.onUnlock(&dtls, n1);
- d.onUnlock(&dtls, n3);
- }
-}
-
-TEST(DeadlockDetector, BasicTest) {
- RunBasicTest<BV1>();
- RunBasicTest<BV2>();
- RunBasicTest<BV3>();
- RunBasicTest<BV4>();
-}
-
-template <class BV>
-void RunRemoveNodeTest() {
- ScopedDD<BV> sdd;
- DeadlockDetector<BV> &d = *sdd.dp;
- DeadlockDetectorTLS<BV> &dtls = sdd.dtls;
-
- uptr l0 = d.newNode(0);
- uptr l1 = d.newNode(1);
- uptr l2 = d.newNode(2);
- uptr l3 = d.newNode(3);
- uptr l4 = d.newNode(4);
- uptr l5 = d.newNode(5);
-
- // l0=>l1=>l2
- d.onLock(&dtls, l0);
- d.onLock(&dtls, l1);
- d.onLock(&dtls, l2);
- d.onUnlock(&dtls, l1);
- d.onUnlock(&dtls, l0);
- d.onUnlock(&dtls, l2);
- // l3=>l4=>l5
- d.onLock(&dtls, l3);
- d.onLock(&dtls, l4);
- d.onLock(&dtls, l5);
- d.onUnlock(&dtls, l4);
- d.onUnlock(&dtls, l3);
- d.onUnlock(&dtls, l5);
-
- set<uptr> locks;
- locks.insert(l0);
- locks.insert(l1);
- locks.insert(l2);
- locks.insert(l3);
- locks.insert(l4);
- locks.insert(l5);
- for (uptr i = 6; i < d.size(); i++) {
- uptr lt = d.newNode(i);
- locks.insert(lt);
- d.onLock(&dtls, lt);
- d.onUnlock(&dtls, lt);
- d.removeNode(lt);
- }
- EXPECT_EQ(locks.size(), d.size());
- // l2=>l0
- EXPECT_FALSE(d.onLock(&dtls, l2));
- EXPECT_TRUE(d.onLock(&dtls, l0));
- d.onUnlock(&dtls, l2);
- d.onUnlock(&dtls, l0);
- // l4=>l3
- EXPECT_FALSE(d.onLock(&dtls, l4));
- EXPECT_TRUE(d.onLock(&dtls, l3));
- d.onUnlock(&dtls, l4);
- d.onUnlock(&dtls, l3);
-
- EXPECT_EQ(d.size(), d.testOnlyGetEpoch());
-
- d.removeNode(l2);
- d.removeNode(l3);
- locks.clear();
- // make sure no edges from or to l0,l1,l4,l5 left.
- for (uptr i = 4; i < d.size(); i++) {
- uptr lt = d.newNode(i);
- locks.insert(lt);
- uptr a, b;
- // l0 => lt?
- a = l0; b = lt;
- EXPECT_FALSE(d.onLock(&dtls, a));
- EXPECT_FALSE(d.onLock(&dtls, b));
- d.onUnlock(&dtls, a);
- d.onUnlock(&dtls, b);
- // l1 => lt?
- a = l1; b = lt;
- EXPECT_FALSE(d.onLock(&dtls, a));
- EXPECT_FALSE(d.onLock(&dtls, b));
- d.onUnlock(&dtls, a);
- d.onUnlock(&dtls, b);
- // lt => l4?
- a = lt; b = l4;
- EXPECT_FALSE(d.onLock(&dtls, a));
- EXPECT_FALSE(d.onLock(&dtls, b));
- d.onUnlock(&dtls, a);
- d.onUnlock(&dtls, b);
- // lt => l5?
- a = lt; b = l5;
- EXPECT_FALSE(d.onLock(&dtls, a));
- EXPECT_FALSE(d.onLock(&dtls, b));
- d.onUnlock(&dtls, a);
- d.onUnlock(&dtls, b);
-
- d.removeNode(lt);
- }
- // Still the same epoch.
- EXPECT_EQ(d.size(), d.testOnlyGetEpoch());
- EXPECT_EQ(locks.size(), d.size() - 4);
- // l2 and l3 should have ben reused.
- EXPECT_EQ(locks.count(l2), 1U);
- EXPECT_EQ(locks.count(l3), 1U);
-}
-
-TEST(DeadlockDetector, RemoveNodeTest) {
- RunRemoveNodeTest<BV1>();
- RunRemoveNodeTest<BV2>();
- RunRemoveNodeTest<BV3>();
- RunRemoveNodeTest<BV4>();
-}
-
-template <class BV>
-void RunMultipleEpochsTest() {
- ScopedDD<BV> sdd;
- DeadlockDetector<BV> &d = *sdd.dp;
- DeadlockDetectorTLS<BV> &dtls = sdd.dtls;
-
- set<uptr> locks;
- for (uptr i = 0; i < d.size(); i++) {
- EXPECT_TRUE(locks.insert(d.newNode(i)).second);
- }
- EXPECT_EQ(d.testOnlyGetEpoch(), d.size());
- for (uptr i = 0; i < d.size(); i++) {
- EXPECT_TRUE(locks.insert(d.newNode(i)).second);
- EXPECT_EQ(d.testOnlyGetEpoch(), d.size() * 2);
- }
- locks.clear();
-
- uptr l0 = d.newNode(0);
- uptr l1 = d.newNode(0);
- d.onLock(&dtls, l0);
- d.onLock(&dtls, l1);
- d.onUnlock(&dtls, l0);
- EXPECT_EQ(d.testOnlyGetEpoch(), 3 * d.size());
- for (uptr i = 0; i < d.size(); i++) {
- EXPECT_TRUE(locks.insert(d.newNode(i)).second);
- }
- EXPECT_EQ(d.testOnlyGetEpoch(), 4 * d.size());
-
-#if !SANITIZER_DEBUG
- // EXPECT_DEATH clones a thread with 4K stack,
- // which is overflown by tsan memory accesses functions in debug mode.
-
- // Can not handle the locks from the previous epoch.
- // The caller should update the lock id.
- EXPECT_DEATH(d.onLock(&dtls, l0), "CHECK failed.*current_epoch_");
-#endif
-}
-
-TEST(DeadlockDetector, MultipleEpochsTest) {
- RunMultipleEpochsTest<BV1>();
- RunMultipleEpochsTest<BV2>();
- RunMultipleEpochsTest<BV3>();
- RunMultipleEpochsTest<BV4>();
-}
-
-template <class BV>
-void RunCorrectEpochFlush() {
- ScopedDD<BV> sdd;
- DeadlockDetector<BV> &d = *sdd.dp;
- DeadlockDetectorTLS<BV> &dtls = sdd.dtls;
- vector<uptr> locks1;
- for (uptr i = 0; i < d.size(); i++)
- locks1.push_back(d.newNode(i));
- EXPECT_EQ(d.testOnlyGetEpoch(), d.size());
- d.onLock(&dtls, locks1[3]);
- d.onLock(&dtls, locks1[4]);
- d.onLock(&dtls, locks1[5]);
-
- // We have a new epoch, old locks in dtls will have to be forgotten.
- uptr l0 = d.newNode(0);
- EXPECT_EQ(d.testOnlyGetEpoch(), d.size() * 2);
- uptr l1 = d.newNode(0);
- EXPECT_EQ(d.testOnlyGetEpoch(), d.size() * 2);
- d.onLock(&dtls, l0);
- d.onLock(&dtls, l1);
- EXPECT_TRUE(d.testOnlyHasEdgeRaw(0, 1));
- EXPECT_FALSE(d.testOnlyHasEdgeRaw(1, 0));
- EXPECT_FALSE(d.testOnlyHasEdgeRaw(3, 0));
- EXPECT_FALSE(d.testOnlyHasEdgeRaw(4, 0));
- EXPECT_FALSE(d.testOnlyHasEdgeRaw(5, 0));
-}
-
-TEST(DeadlockDetector, CorrectEpochFlush) {
- RunCorrectEpochFlush<BV1>();
- RunCorrectEpochFlush<BV2>();
-}
-
-template <class BV>
-void RunTryLockTest() {
- ScopedDD<BV> sdd;
- DeadlockDetector<BV> &d = *sdd.dp;
- DeadlockDetectorTLS<BV> &dtls = sdd.dtls;
-
- uptr l0 = d.newNode(0);
- uptr l1 = d.newNode(0);
- uptr l2 = d.newNode(0);
- EXPECT_FALSE(d.onLock(&dtls, l0));
- EXPECT_FALSE(d.onTryLock(&dtls, l1));
- EXPECT_FALSE(d.onLock(&dtls, l2));
- EXPECT_TRUE(d.isHeld(&dtls, l0));
- EXPECT_TRUE(d.isHeld(&dtls, l1));
- EXPECT_TRUE(d.isHeld(&dtls, l2));
- EXPECT_FALSE(d.testOnlyHasEdge(l0, l1));
- EXPECT_TRUE(d.testOnlyHasEdge(l1, l2));
- d.onUnlock(&dtls, l0);
- d.onUnlock(&dtls, l1);
- d.onUnlock(&dtls, l2);
-}
-
-TEST(DeadlockDetector, TryLockTest) {
- RunTryLockTest<BV1>();
- RunTryLockTest<BV2>();
-}
-
-template <class BV>
-void RunOnFirstLockTest() {
- ScopedDD<BV> sdd;
- DeadlockDetector<BV> &d = *sdd.dp;
- DeadlockDetectorTLS<BV> &dtls = sdd.dtls;
-
- uptr l0 = d.newNode(0);
- uptr l1 = d.newNode(0);
- EXPECT_FALSE(d.onFirstLock(&dtls, l0)); // dtls has old epoch.
- d.onLock(&dtls, l0);
- d.onUnlock(&dtls, l0);
-
- EXPECT_TRUE(d.onFirstLock(&dtls, l0)); // Ok, same ecpoch, first lock.
- EXPECT_FALSE(d.onFirstLock(&dtls, l1)); // Second lock.
- d.onLock(&dtls, l1);
- d.onUnlock(&dtls, l1);
- d.onUnlock(&dtls, l0);
-
- EXPECT_TRUE(d.onFirstLock(&dtls, l0)); // Ok
- d.onUnlock(&dtls, l0);
-
- vector<uptr> locks1;
- for (uptr i = 0; i < d.size(); i++)
- locks1.push_back(d.newNode(i));
-
- EXPECT_TRUE(d.onFirstLock(&dtls, l0)); // Epoch has changed, but not in dtls.
-
- uptr l3 = d.newNode(0);
- d.onLock(&dtls, l3);
- d.onUnlock(&dtls, l3);
-
- EXPECT_FALSE(d.onFirstLock(&dtls, l0)); // Epoch has changed in dtls.
-}
-
-TEST(DeadlockDetector, onFirstLockTest) {
- RunOnFirstLockTest<BV2>();
-}
-
-template <class BV>
-void RunRecusriveLockTest() {
- ScopedDD<BV> sdd;
- DeadlockDetector<BV> &d = *sdd.dp;
- DeadlockDetectorTLS<BV> &dtls = sdd.dtls;
-
- uptr l0 = d.newNode(0);
- uptr l1 = d.newNode(0);
- uptr l2 = d.newNode(0);
- uptr l3 = d.newNode(0);
-
- EXPECT_FALSE(d.onLock(&dtls, l0));
- EXPECT_FALSE(d.onLock(&dtls, l1));
- EXPECT_FALSE(d.onLock(&dtls, l0)); // Recurisve.
- EXPECT_FALSE(d.onLock(&dtls, l2));
- d.onUnlock(&dtls, l0);
- EXPECT_FALSE(d.onLock(&dtls, l3));
- d.onUnlock(&dtls, l0);
- d.onUnlock(&dtls, l1);
- d.onUnlock(&dtls, l2);
- d.onUnlock(&dtls, l3);
- EXPECT_TRUE(d.testOnlyHasEdge(l0, l1));
- EXPECT_TRUE(d.testOnlyHasEdge(l0, l2));
- EXPECT_TRUE(d.testOnlyHasEdge(l0, l3));
-}
-
-TEST(DeadlockDetector, RecusriveLockTest) {
- RunRecusriveLockTest<BV2>();
-}
-
-template <class BV>
-void RunLockContextTest() {
- ScopedDD<BV> sdd;
- DeadlockDetector<BV> &d = *sdd.dp;
- DeadlockDetectorTLS<BV> &dtls = sdd.dtls;
-
- uptr l0 = d.newNode(0);
- uptr l1 = d.newNode(0);
- uptr l2 = d.newNode(0);
- uptr l3 = d.newNode(0);
- uptr l4 = d.newNode(0);
- EXPECT_FALSE(d.onLock(&dtls, l0, 10));
- EXPECT_FALSE(d.onLock(&dtls, l1, 11));
- EXPECT_FALSE(d.onLock(&dtls, l2, 12));
- EXPECT_FALSE(d.onLock(&dtls, l3, 13));
- EXPECT_EQ(10U, d.findLockContext(&dtls, l0));
- EXPECT_EQ(11U, d.findLockContext(&dtls, l1));
- EXPECT_EQ(12U, d.findLockContext(&dtls, l2));
- EXPECT_EQ(13U, d.findLockContext(&dtls, l3));
- d.onUnlock(&dtls, l0);
- EXPECT_EQ(0U, d.findLockContext(&dtls, l0));
- EXPECT_EQ(11U, d.findLockContext(&dtls, l1));
- EXPECT_EQ(12U, d.findLockContext(&dtls, l2));
- EXPECT_EQ(13U, d.findLockContext(&dtls, l3));
- d.onUnlock(&dtls, l2);
- EXPECT_EQ(0U, d.findLockContext(&dtls, l0));
- EXPECT_EQ(11U, d.findLockContext(&dtls, l1));
- EXPECT_EQ(0U, d.findLockContext(&dtls, l2));
- EXPECT_EQ(13U, d.findLockContext(&dtls, l3));
-
- EXPECT_FALSE(d.onLock(&dtls, l4, 14));
- EXPECT_EQ(14U, d.findLockContext(&dtls, l4));
-}
-
-TEST(DeadlockDetector, LockContextTest) {
- RunLockContextTest<BV2>();
-}
-
-template <class BV>
-void RunRemoveEdgesTest() {
- ScopedDD<BV> sdd;
- DeadlockDetector<BV> &d = *sdd.dp;
- DeadlockDetectorTLS<BV> &dtls = sdd.dtls;
- vector<uptr> node(BV::kSize);
- u32 stk_from = 0, stk_to = 0;
- int unique_tid = 0;
- for (size_t i = 0; i < BV::kSize; i++)
- node[i] = d.newNode(0);
-
- for (size_t i = 0; i < BV::kSize; i++)
- EXPECT_FALSE(d.onLock(&dtls, node[i], i + 1));
- for (size_t i = 0; i < BV::kSize; i++) {
- for (uptr j = i + 1; j < BV::kSize; j++) {
- EXPECT_TRUE(
- d.findEdge(node[i], node[j], &stk_from, &stk_to, &unique_tid));
- EXPECT_EQ(stk_from, i + 1);
- EXPECT_EQ(stk_to, j + 1);
- }
- }
- EXPECT_EQ(d.testOnlyGetEpoch(), d.size());
- // Remove and re-create half of the nodes.
- for (uptr i = 1; i < BV::kSize; i += 2)
- d.removeNode(node[i]);
- for (uptr i = 1; i < BV::kSize; i += 2)
- node[i] = d.newNode(0);
- EXPECT_EQ(d.testOnlyGetEpoch(), d.size());
- // The edges from or to the removed nodes should be gone.
- for (size_t i = 0; i < BV::kSize; i++) {
- for (uptr j = i + 1; j < BV::kSize; j++) {
- if ((i % 2) || (j % 2))
- EXPECT_FALSE(
- d.findEdge(node[i], node[j], &stk_from, &stk_to, &unique_tid));
- else
- EXPECT_TRUE(
- d.findEdge(node[i], node[j], &stk_from, &stk_to, &unique_tid));
- }
- }
-}
-
-TEST(DeadlockDetector, RemoveEdgesTest) {
- RunRemoveEdgesTest<BV1>();
-}
diff --git a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_flags_test.cc b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_flags_test.cc
deleted file mode 100644
index 3e5d8381ed3a..000000000000
--- a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_flags_test.cc
+++ /dev/null
@@ -1,142 +0,0 @@
-//===-- sanitizer_flags_test.cc -------------------------------------------===//
-//
-// 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 ThreadSanitizer/AddressSanitizer runtime.
-//
-//===----------------------------------------------------------------------===//
-#include "sanitizer_common/sanitizer_common.h"
-#include "sanitizer_common/sanitizer_flags.h"
-#include "sanitizer_common/sanitizer_flag_parser.h"
-#include "sanitizer_common/sanitizer_libc.h"
-#include "sanitizer_common/sanitizer_allocator_internal.h"
-#include "gtest/gtest.h"
-
-#include <string.h>
-
-namespace __sanitizer {
-
-static const char kFlagName[] = "flag_name";
-static const char kFlagDesc[] = "flag description";
-
-template <typename T>
-static void TestFlag(T start_value, const char *env, T final_value) {
- T flag = start_value;
-
- FlagParser parser;
- RegisterFlag(&parser, kFlagName, kFlagDesc, &flag);
-
- parser.ParseString(env);
-
- EXPECT_EQ(final_value, flag);
-}
-
-template <>
-void TestFlag(const char *start_value, const char *env,
- const char *final_value) {
- const char *flag = start_value;
-
- FlagParser parser;
- RegisterFlag(&parser, kFlagName, kFlagDesc, &flag);
-
- parser.ParseString(env);
-
- EXPECT_EQ(0, internal_strcmp(final_value, flag));
-}
-
-TEST(SanitizerCommon, BooleanFlags) {
- TestFlag(false, "flag_name=1", true);
- TestFlag(false, "flag_name=yes", true);
- TestFlag(false, "flag_name=true", true);
- TestFlag(true, "flag_name=0", false);
- TestFlag(true, "flag_name=no", false);
- TestFlag(true, "flag_name=false", false);
-}
-
-TEST(SanitizerCommon, IntFlags) {
- TestFlag(-11, 0, -11);
- TestFlag(-11, "flag_name=0", 0);
- TestFlag(-11, "flag_name=42", 42);
- TestFlag(-11, "flag_name=-42", -42);
-
- // Unrecognized flags are ignored.
- TestFlag(-11, "--flag_name=42", -11);
- TestFlag(-11, "zzzzzzz=42", -11);
-
- EXPECT_DEATH(TestFlag(-11, "flag_name", 0), "expected '='");
- EXPECT_DEATH(TestFlag(-11, "flag_name=42U", 0),
- "Invalid value for int option");
-}
-
-TEST(SanitizerCommon, StrFlags) {
- TestFlag("zzz", 0, "zzz");
- TestFlag("zzz", "flag_name=", "");
- TestFlag("zzz", "flag_name=abc", "abc");
- TestFlag("", "flag_name=abc", "abc");
- TestFlag("", "flag_name='abc zxc'", "abc zxc");
- // TestStrFlag("", "flag_name=\"abc qwe\" asd", "abc qwe");
-}
-
-static void TestTwoFlags(const char *env, bool expected_flag1,
- const char *expected_flag2,
- const char *name1 = "flag1",
- const char *name2 = "flag2") {
- bool flag1 = !expected_flag1;
- const char *flag2 = "";
-
- FlagParser parser;
- RegisterFlag(&parser, name1, kFlagDesc, &flag1);
- RegisterFlag(&parser, name2, kFlagDesc, &flag2);
-
- parser.ParseString(env);
-
- EXPECT_EQ(expected_flag1, flag1);
- EXPECT_EQ(0, internal_strcmp(flag2, expected_flag2));
-}
-
-TEST(SanitizerCommon, MultipleFlags) {
- TestTwoFlags("flag1=1 flag2='zzz'", true, "zzz");
- TestTwoFlags("flag2='qxx' flag1=0", false, "qxx");
- TestTwoFlags("flag1=false:flag2='zzz'", false, "zzz");
- TestTwoFlags("flag2=qxx:flag1=yes", true, "qxx");
- TestTwoFlags("flag2=qxx\nflag1=yes", true, "qxx");
- TestTwoFlags("flag2=qxx\r\nflag1=yes", true, "qxx");
- TestTwoFlags("flag2=qxx\tflag1=yes", true, "qxx");
-}
-
-TEST(SanitizerCommon, CommonSuffixFlags) {
- TestTwoFlags("flag=1 other_flag='zzz'", true, "zzz", "flag", "other_flag");
- TestTwoFlags("other_flag='zzz' flag=1", true, "zzz", "flag", "other_flag");
- TestTwoFlags("other_flag=' flag=0 ' flag=1", true, " flag=0 ", "flag",
- "other_flag");
- TestTwoFlags("flag=1 other_flag=' flag=0 '", true, " flag=0 ", "flag",
- "other_flag");
-}
-
-TEST(SanitizerCommon, CommonFlags) {
- CommonFlags cf;
- FlagParser parser;
- RegisterCommonFlags(&parser, &cf);
-
- cf.SetDefaults();
- EXPECT_TRUE(cf.symbolize);
- EXPECT_STREQ(".", cf.coverage_dir);
-
- cf.symbolize = false;
- cf.coverage = true;
- cf.coverage_direct = true;
- cf.log_path = "path/one";
-
- parser.ParseString("symbolize=1:coverage_direct=false log_path='path/two'");
- EXPECT_TRUE(cf.symbolize);
- EXPECT_TRUE(cf.coverage);
- EXPECT_FALSE(cf.coverage_direct);
- EXPECT_STREQ("path/two", cf.log_path);
-}
-
-} // namespace __sanitizer
diff --git a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_format_interceptor_test.cc b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_format_interceptor_test.cc
deleted file mode 100644
index 13918aff1009..000000000000
--- a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_format_interceptor_test.cc
+++ /dev/null
@@ -1,259 +0,0 @@
-//===-- sanitizer_format_interceptor_test.cc ------------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// Tests for *scanf interceptors implementation in sanitizer_common.
-//
-//===----------------------------------------------------------------------===//
-#include <algorithm>
-#include <vector>
-
-#include "interception/interception.h"
-#include "sanitizer_test_utils.h"
-#include "sanitizer_common/sanitizer_libc.h"
-#include "sanitizer_common/sanitizer_common.h"
-#include "gtest/gtest.h"
-
-using namespace __sanitizer;
-
-#define COMMON_INTERCEPTOR_READ_WRITE_RANGE(ctx, ptr, size) \
- do { \
- ((std::vector<unsigned> *)ctx)->push_back(size); \
- ptr = ptr; \
- } while (0)
-
-#define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) \
- COMMON_INTERCEPTOR_READ_WRITE_RANGE(ctx, ptr, size)
-
-#define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \
- COMMON_INTERCEPTOR_READ_WRITE_RANGE(ctx, ptr, size)
-
-#define SANITIZER_INTERCEPT_PRINTF 1
-#include "sanitizer_common/sanitizer_common_interceptors_format.inc"
-
-static const unsigned I = sizeof(int);
-static const unsigned L = sizeof(long);
-static const unsigned LL = sizeof(long long);
-static const unsigned S = sizeof(short);
-static const unsigned C = sizeof(char);
-static const unsigned LC = sizeof(wchar_t);
-static const unsigned D = sizeof(double);
-static const unsigned LD = sizeof(long double);
-static const unsigned F = sizeof(float);
-static const unsigned P = sizeof(char *);
-
-static void verifyFormatResults(const char *format, unsigned n,
- const std::vector<unsigned> &computed_sizes,
- va_list expected_sizes) {
- // "+ 1" because of format string
- ASSERT_EQ(n + 1,
- computed_sizes.size()) << "Unexpected number of format arguments: '"
- << format << "'";
- for (unsigned i = 0; i < n; ++i)
- EXPECT_EQ(va_arg(expected_sizes, unsigned), computed_sizes[i + 1])
- << "Unexpect write size for argument " << i << ", format string '"
- << format << "'";
-}
-
-static const char test_buf[] = "Test string.";
-static const size_t test_buf_size = sizeof(test_buf);
-
-static const unsigned SCANF_ARGS_MAX = 16;
-
-static void testScanf3(void *ctx, int result, bool allowGnuMalloc,
- const char *format, ...) {
- va_list ap;
- va_start(ap, format);
- scanf_common(ctx, result, allowGnuMalloc, format, ap);
- va_end(ap);
-}
-
-static void testScanf2(const char *format, int scanf_result,
- bool allowGnuMalloc, unsigned n,
- va_list expected_sizes) {
- std::vector<unsigned> scanf_sizes;
- // 16 args should be enough.
- testScanf3((void *)&scanf_sizes, scanf_result, allowGnuMalloc, format,
- test_buf, test_buf, test_buf, test_buf, test_buf, test_buf,
- test_buf, test_buf, test_buf, test_buf, test_buf, test_buf,
- test_buf, test_buf, test_buf, test_buf);
- verifyFormatResults(format, n, scanf_sizes, expected_sizes);
-}
-
-static void testScanf(const char *format, unsigned n, ...) {
- va_list ap;
- va_start(ap, n);
- testScanf2(format, SCANF_ARGS_MAX, /* allowGnuMalloc */ true, n, ap);
- va_end(ap);
-}
-
-static void testScanfPartial(const char *format, int scanf_result, unsigned n,
- ...) {
- va_list ap;
- va_start(ap, n);
- testScanf2(format, scanf_result, /* allowGnuMalloc */ true, n, ap);
- va_end(ap);
-}
-
-static void testScanfNoGnuMalloc(const char *format, unsigned n, ...) {
- va_list ap;
- va_start(ap, n);
- testScanf2(format, SCANF_ARGS_MAX, /* allowGnuMalloc */ false, n, ap);
- va_end(ap);
-}
-
-TEST(SanitizerCommonInterceptors, Scanf) {
- testScanf("%d", 1, I);
- testScanf("%d%d%d", 3, I, I, I);
- testScanf("ab%u%dc", 2, I, I);
- testScanf("%ld", 1, L);
- testScanf("%llu", 1, LL);
- testScanf("%qd", 1, LL);
- testScanf("a %hd%hhx", 2, S, C);
- testScanf("%c", 1, C);
- testScanf("%lc", 1, LC);
-
- testScanf("%%", 0);
- testScanf("a%%", 0);
- testScanf("a%%b", 0);
- testScanf("a%%%%b", 0);
- testScanf("a%%b%%", 0);
- testScanf("a%%%%%%b", 0);
- testScanf("a%%%%%b", 0);
- testScanf("a%%%%%f", 1, F);
- testScanf("a%%%lxb", 1, L);
- testScanf("a%lf%%%lxb", 2, D, L);
- testScanf("%nf", 1, I);
-
- testScanf("%10s", 1, 11);
- testScanf("%10c", 1, 10);
- testScanf("%10ls", 1, 11 * LC);
- testScanf("%10lc", 1, 10 * LC);
- testScanf("%%10s", 0);
- testScanf("%*10s", 0);
- testScanf("%*d", 0);
-
- testScanf("%4d%8f%c", 3, I, F, C);
- testScanf("%s%d", 2, test_buf_size, I);
- testScanf("%[abc]", 1, test_buf_size);
- testScanf("%4[bcdef]", 1, 5);
- testScanf("%[]]", 1, test_buf_size);
- testScanf("%8[^]%d0-9-]%c", 2, 9, C);
-
- testScanf("%*[^:]%n:%d:%1[ ]%n", 4, I, I, 2, I);
-
- testScanf("%*d%u", 1, I);
-
- testScanf("%c%d", 2, C, I);
- testScanf("%A%lf", 2, F, D);
-
- testScanf("%ms %Lf", 2, P, LD);
- testScanf("s%Las", 1, LD);
- testScanf("%ar", 1, F);
-
- // In the cases with std::min below the format spec can be interpreted as
- // either floating-something, or (GNU extension) callee-allocated string.
- // Our conservative implementation reports one of the two possibilities with
- // the least store range.
- testScanf("%a[", 0);
- testScanf("%a[]", 0);
- testScanf("%a[]]", 1, std::min(F, P));
- testScanf("%a[abc]", 1, std::min(F, P));
- testScanf("%a[^abc]", 1, std::min(F, P));
- testScanf("%a[ab%c] %d", 0);
- testScanf("%a[^ab%c] %d", 0);
- testScanf("%as", 1, std::min(F, P));
- testScanf("%aS", 1, std::min(F, P));
- testScanf("%a13S", 1, std::min(F, P));
- testScanf("%alS", 1, std::min(F, P));
-
- testScanfNoGnuMalloc("s%Las", 1, LD);
- testScanfNoGnuMalloc("%ar", 1, F);
- testScanfNoGnuMalloc("%a[", 1, F);
- testScanfNoGnuMalloc("%a[]", 1, F);
- testScanfNoGnuMalloc("%a[]]", 1, F);
- testScanfNoGnuMalloc("%a[abc]", 1, F);
- testScanfNoGnuMalloc("%a[^abc]", 1, F);
- testScanfNoGnuMalloc("%a[ab%c] %d", 3, F, C, I);
- testScanfNoGnuMalloc("%a[^ab%c] %d", 3, F, C, I);
- testScanfNoGnuMalloc("%as", 1, F);
- testScanfNoGnuMalloc("%aS", 1, F);
- testScanfNoGnuMalloc("%a13S", 1, F);
- testScanfNoGnuMalloc("%alS", 1, F);
-
- testScanf("%5$d", 0);
- testScanf("%md", 0);
- testScanf("%m10s", 0);
-
- testScanfPartial("%d%d%d%d //1\n", 1, 1, I);
- testScanfPartial("%d%d%d%d //2\n", 2, 2, I, I);
- testScanfPartial("%d%d%d%d //3\n", 3, 3, I, I, I);
- testScanfPartial("%d%d%d%d //4\n", 4, 4, I, I, I, I);
-
- testScanfPartial("%d%n%n%d //1\n", 1, 3, I, I, I);
- testScanfPartial("%d%n%n%d //2\n", 2, 4, I, I, I, I);
-
- testScanfPartial("%d%n%n%d %s %s", 3, 5, I, I, I, I, test_buf_size);
- testScanfPartial("%d%n%n%d %s %s", 4, 6, I, I, I, I, test_buf_size,
- test_buf_size);
-}
-
-static void testPrintf3(void *ctx, const char *format, ...) {
- va_list ap;
- va_start(ap, format);
- printf_common(ctx, format, ap);
- va_end(ap);
-}
-
-static void testPrintf2(const char *format, unsigned n,
- va_list expected_sizes) {
- std::vector<unsigned> printf_sizes;
- // 16 args should be enough.
- testPrintf3((void *)&printf_sizes, format,
- test_buf, test_buf, test_buf, test_buf, test_buf, test_buf,
- test_buf, test_buf, test_buf, test_buf, test_buf, test_buf,
- test_buf, test_buf, test_buf, test_buf);
- verifyFormatResults(format, n, printf_sizes, expected_sizes);
-}
-
-static void testPrintf(const char *format, unsigned n, ...) {
- va_list ap;
- va_start(ap, n);
- testPrintf2(format, n, ap);
- va_end(ap);
-}
-
-TEST(SanitizerCommonInterceptors, Printf) {
- // Only test functionality which differs from scanf
-
- // Indexed arguments
- testPrintf("%5$d", 0);
- testPrintf("%.*5$d", 0);
-
- // errno
- testPrintf("%0-m", 0);
-
- // Dynamic width
- testPrintf("%*n", 1, I);
- testPrintf("%*.10n", 1, I);
-
- // Precision
- testPrintf("%10.10n", 1, I);
- testPrintf("%.3s", 1, 3);
- testPrintf("%.20s", 1, test_buf_size);
-
- // Dynamic precision
- testPrintf("%.*n", 1, I);
- testPrintf("%10.*n", 1, I);
-
- // Dynamic precision for strings is not implemented yet.
- testPrintf("%.*s", 1, 0);
-
- // Checks for wide-character strings are not implemented yet.
- testPrintf("%ls", 1, 0);
-}
diff --git a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_ioctl_test.cc b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_ioctl_test.cc
deleted file mode 100644
index 22fa5228dfbd..000000000000
--- a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_ioctl_test.cc
+++ /dev/null
@@ -1,103 +0,0 @@
-//===-- sanitizer_ioctl_test.cc -------------------------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// Tests for ioctl interceptor implementation in sanitizer_common.
-//
-//===----------------------------------------------------------------------===//
-
-#include "sanitizer_common/sanitizer_platform.h"
-#if SANITIZER_LINUX
-
-#include <linux/input.h>
-#include <vector>
-
-#include "interception/interception.h"
-#include "sanitizer_test_utils.h"
-#include "sanitizer_common/sanitizer_platform_limits_posix.h"
-#include "sanitizer_common/sanitizer_common.h"
-#include "gtest/gtest.h"
-
-
-using namespace __sanitizer;
-
-#define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, sz) \
- do { \
- (void) ctx; \
- (void) ptr; \
- (void) sz; \
- } while (0)
-#define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, sz) \
- do { \
- (void) ctx; \
- (void) ptr; \
- (void) sz; \
- } while (0)
-
-#include "sanitizer_common/sanitizer_common_interceptors_ioctl.inc"
-
-static struct IoctlInit {
- IoctlInit() {
- ioctl_init();
- // Avoid unused function warnings.
- (void)&ioctl_common_pre;
- (void)&ioctl_common_post;
- (void)&ioctl_decode;
- }
-} ioctl_static_initializer;
-
-TEST(SanitizerIoctl, Fixup) {
- EXPECT_EQ((unsigned)FIONBIO, ioctl_request_fixup(FIONBIO));
-
- EXPECT_EQ(EVIOCGBIT(0, 0), ioctl_request_fixup(EVIOCGBIT(0, 16)));
- EXPECT_EQ(EVIOCGBIT(0, 0), ioctl_request_fixup(EVIOCGBIT(1, 16)));
- EXPECT_EQ(EVIOCGBIT(0, 0), ioctl_request_fixup(EVIOCGBIT(1, 17)));
- EXPECT_EQ(EVIOCGBIT(0, 0), ioctl_request_fixup(EVIOCGBIT(31, 16)));
- EXPECT_NE(EVIOCGBIT(0, 0), ioctl_request_fixup(EVIOCGBIT(32, 16)));
-
- EXPECT_EQ(EVIOCGABS(0), ioctl_request_fixup(EVIOCGABS(0)));
- EXPECT_EQ(EVIOCGABS(0), ioctl_request_fixup(EVIOCGABS(5)));
- EXPECT_EQ(EVIOCGABS(0), ioctl_request_fixup(EVIOCGABS(63)));
- EXPECT_NE(EVIOCGABS(0), ioctl_request_fixup(EVIOCGABS(64)));
-
- EXPECT_EQ(EVIOCSABS(0), ioctl_request_fixup(EVIOCSABS(0)));
- EXPECT_EQ(EVIOCSABS(0), ioctl_request_fixup(EVIOCSABS(5)));
- EXPECT_EQ(EVIOCSABS(0), ioctl_request_fixup(EVIOCSABS(63)));
- EXPECT_NE(EVIOCSABS(0), ioctl_request_fixup(EVIOCSABS(64)));
-
- const ioctl_desc *desc = ioctl_lookup(EVIOCGKEY(16));
- EXPECT_NE((void *)0, desc);
- EXPECT_EQ(EVIOCGKEY(0), desc->req);
-}
-
-// Test decoding KVM ioctl numbers.
-TEST(SanitizerIoctl, KVM_GET_MP_STATE) {
- ioctl_desc desc;
- bool res = ioctl_decode(0x8004ae98U, &desc);
- EXPECT_TRUE(res);
- EXPECT_EQ(ioctl_desc::WRITE, desc.type);
- EXPECT_EQ(4U, desc.size);
-}
-
-TEST(SanitizerIoctl, KVM_GET_LAPIC) {
- ioctl_desc desc;
- bool res = ioctl_decode(0x8400ae8eU, &desc);
- EXPECT_TRUE(res);
- EXPECT_EQ(ioctl_desc::WRITE, desc.type);
- EXPECT_EQ(1024U, desc.size);
-}
-
-TEST(SanitizerIoctl, KVM_GET_MSR_INDEX_LIST) {
- ioctl_desc desc;
- bool res = ioctl_decode(0xc004ae02U, &desc);
- EXPECT_TRUE(res);
- EXPECT_EQ(ioctl_desc::READWRITE, desc.type);
- EXPECT_EQ(4U, desc.size);
-}
-
-#endif // SANITIZER_LINUX
diff --git a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_libc_test.cc b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_libc_test.cc
deleted file mode 100644
index 3252db77653d..000000000000
--- a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_libc_test.cc
+++ /dev/null
@@ -1,159 +0,0 @@
-//===-- sanitizer_libc_test.cc --------------------------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-// Tests for sanitizer_libc.h.
-//===----------------------------------------------------------------------===//
-
-#include "sanitizer_common/sanitizer_common.h"
-#include "sanitizer_common/sanitizer_libc.h"
-#include "sanitizer_common/sanitizer_platform.h"
-#include "gtest/gtest.h"
-
-#if SANITIZER_LINUX || SANITIZER_MAC
-# define SANITIZER_TEST_HAS_STAT_H 1
-# include <sys/stat.h>
-# include "sanitizer_common/sanitizer_posix.h"
-#else
-# define SANITIZER_TEST_HAS_STAT_H 0
-#endif
-
-// A regression test for internal_memmove() implementation.
-TEST(SanitizerCommon, InternalMemmoveRegression) {
- char src[] = "Hello World";
- char *dest = src + 6;
- __sanitizer::internal_memmove(dest, src, 5);
- EXPECT_EQ(dest[0], src[0]);
- EXPECT_EQ(dest[4], src[4]);
-}
-
-TEST(SanitizerCommon, mem_is_zero) {
- size_t size = 128;
- char *x = new char[size];
- memset(x, 0, size);
- for (size_t pos = 0; pos < size; pos++) {
- x[pos] = 1;
- for (size_t beg = 0; beg < size; beg++) {
- for (size_t end = beg; end < size; end++) {
- // fprintf(stderr, "pos %zd beg %zd end %zd \n", pos, beg, end);
- if (beg <= pos && pos < end)
- EXPECT_FALSE(__sanitizer::mem_is_zero(x + beg, end - beg));
- else
- EXPECT_TRUE(__sanitizer::mem_is_zero(x + beg, end - beg));
- }
- }
- x[pos] = 0;
- }
- delete [] x;
-}
-
-struct stat_and_more {
- struct stat st;
- unsigned char z;
-};
-
-static void temp_file_name(char *buf, size_t bufsize, const char *prefix) {
- const char *tmpdir = "/tmp";
-#if SANITIZER_ANDROID
- // I don't know a way to query temp directory location on Android without
- // going through Java interfaces. The code below is not ideal, but should
- // work. May require "adb root", but it is needed for almost any use of ASan
- // on Android already.
- tmpdir = GetEnv("EXTERNAL_STORAGE");
-#endif
- u32 uid = GetUid();
- internal_snprintf(buf, bufsize, "%s/%s%d", tmpdir, prefix, uid);
-}
-
-// FIXME: File manipulations are not yet supported on Windows
-#if !defined(_WIN32)
-TEST(SanitizerCommon, FileOps) {
- const char *str1 = "qwerty";
- uptr len1 = internal_strlen(str1);
- const char *str2 = "zxcv";
- uptr len2 = internal_strlen(str2);
-
- char tmpfile[128];
- temp_file_name(tmpfile, sizeof(tmpfile), "sanitizer_common.fileops.tmp.");
- fd_t fd = OpenFile(tmpfile, WrOnly);
- ASSERT_NE(fd, kInvalidFd);
- EXPECT_EQ(len1, internal_write(fd, str1, len1));
- EXPECT_EQ(len2, internal_write(fd, str2, len2));
- CloseFile(fd);
-
- fd = OpenFile(tmpfile, RdOnly);
- ASSERT_NE(fd, kInvalidFd);
- uptr fsize = internal_filesize(fd);
- EXPECT_EQ(len1 + len2, fsize);
-
-#if SANITIZER_TEST_HAS_STAT_H
- struct stat st1, st2, st3;
- EXPECT_EQ(0u, internal_stat(tmpfile, &st1));
- EXPECT_EQ(0u, internal_lstat(tmpfile, &st2));
- EXPECT_EQ(0u, internal_fstat(fd, &st3));
- EXPECT_EQ(fsize, (uptr)st3.st_size);
-
- // Verify that internal_fstat does not write beyond the end of the supplied
- // buffer.
- struct stat_and_more sam;
- memset(&sam, 0xAB, sizeof(sam));
- EXPECT_EQ(0u, internal_fstat(fd, &sam.st));
- EXPECT_EQ(0xAB, sam.z);
- EXPECT_NE(0xAB, sam.st.st_size);
- EXPECT_NE(0, sam.st.st_size);
-#endif
-
- char buf[64] = {};
- EXPECT_EQ(len1, internal_read(fd, buf, len1));
- EXPECT_EQ(0, internal_memcmp(buf, str1, len1));
- EXPECT_EQ((char)0, buf[len1 + 1]);
- internal_memset(buf, 0, len1);
- EXPECT_EQ(len2, internal_read(fd, buf, len2));
- EXPECT_EQ(0, internal_memcmp(buf, str2, len2));
- CloseFile(fd);
- internal_unlink(tmpfile);
-}
-#endif
-
-TEST(SanitizerCommon, InternalStrFunctions) {
- const char *haystack = "haystack";
- EXPECT_EQ(haystack + 2, internal_strchr(haystack, 'y'));
- EXPECT_EQ(haystack + 2, internal_strchrnul(haystack, 'y'));
- EXPECT_EQ(0, internal_strchr(haystack, 'z'));
- EXPECT_EQ(haystack + 8, internal_strchrnul(haystack, 'z'));
-}
-
-// FIXME: File manipulations are not yet supported on Windows
-#if !defined(_WIN32) && !SANITIZER_MAC
-TEST(SanitizerCommon, InternalMmapWithOffset) {
- char tmpfile[128];
- temp_file_name(tmpfile, sizeof(tmpfile),
- "sanitizer_common.internalmmapwithoffset.tmp.");
- fd_t fd = OpenFile(tmpfile, RdWr);
- ASSERT_NE(fd, kInvalidFd);
-
- uptr page_size = GetPageSizeCached();
- uptr res = internal_ftruncate(fd, page_size * 2);
- ASSERT_FALSE(internal_iserror(res));
-
- res = internal_lseek(fd, page_size, SEEK_SET);
- ASSERT_FALSE(internal_iserror(res));
-
- res = internal_write(fd, "AB", 2);
- ASSERT_FALSE(internal_iserror(res));
-
- char *p = (char *)MapWritableFileToMemory(nullptr, page_size, fd, page_size);
- ASSERT_NE(nullptr, p);
-
- ASSERT_EQ('A', p[0]);
- ASSERT_EQ('B', p[1]);
-
- CloseFile(fd);
- UnmapOrDie(p, page_size);
- internal_unlink(tmpfile);
-}
-#endif
diff --git a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_linux_test.cc b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_linux_test.cc
deleted file mode 100644
index 11342b775cc7..000000000000
--- a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_linux_test.cc
+++ /dev/null
@@ -1,268 +0,0 @@
-//===-- sanitizer_linux_test.cc -------------------------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// Tests for sanitizer_linux.h
-//
-//===----------------------------------------------------------------------===//
-
-#include "sanitizer_common/sanitizer_platform.h"
-#if SANITIZER_LINUX
-
-#include "sanitizer_common/sanitizer_linux.h"
-
-#include "sanitizer_common/sanitizer_common.h"
-#include "gtest/gtest.h"
-
-#include <pthread.h>
-#include <sched.h>
-#include <stdlib.h>
-
-#include <algorithm>
-#include <vector>
-
-namespace __sanitizer {
-
-struct TidReporterArgument {
- TidReporterArgument() {
- pthread_mutex_init(&terminate_thread_mutex, NULL);
- pthread_mutex_init(&tid_reported_mutex, NULL);
- pthread_cond_init(&terminate_thread_cond, NULL);
- pthread_cond_init(&tid_reported_cond, NULL);
- terminate_thread = false;
- }
-
- ~TidReporterArgument() {
- pthread_mutex_destroy(&terminate_thread_mutex);
- pthread_mutex_destroy(&tid_reported_mutex);
- pthread_cond_destroy(&terminate_thread_cond);
- pthread_cond_destroy(&tid_reported_cond);
- }
-
- pid_t reported_tid;
- // For signaling to spawned threads that they should terminate.
- pthread_cond_t terminate_thread_cond;
- pthread_mutex_t terminate_thread_mutex;
- bool terminate_thread;
- // For signaling to main thread that a child thread has reported its tid.
- pthread_cond_t tid_reported_cond;
- pthread_mutex_t tid_reported_mutex;
-
- private:
- // Disallow evil constructors
- TidReporterArgument(const TidReporterArgument &);
- void operator=(const TidReporterArgument &);
-};
-
-class ThreadListerTest : public ::testing::Test {
- protected:
- virtual void SetUp() {
- pthread_t pthread_id;
- pid_t tid;
- for (uptr i = 0; i < kThreadCount; i++) {
- SpawnTidReporter(&pthread_id, &tid);
- pthread_ids_.push_back(pthread_id);
- tids_.push_back(tid);
- }
- }
-
- virtual void TearDown() {
- pthread_mutex_lock(&thread_arg.terminate_thread_mutex);
- thread_arg.terminate_thread = true;
- pthread_cond_broadcast(&thread_arg.terminate_thread_cond);
- pthread_mutex_unlock(&thread_arg.terminate_thread_mutex);
- for (uptr i = 0; i < pthread_ids_.size(); i++)
- pthread_join(pthread_ids_[i], NULL);
- }
-
- void SpawnTidReporter(pthread_t *pthread_id, pid_t *tid);
-
- static const uptr kThreadCount = 20;
-
- std::vector<pthread_t> pthread_ids_;
- std::vector<pid_t> tids_;
-
- TidReporterArgument thread_arg;
-};
-
-// Writes its TID once to reported_tid and waits until signaled to terminate.
-void *TidReporterThread(void *argument) {
- TidReporterArgument *arg = reinterpret_cast<TidReporterArgument *>(argument);
- pthread_mutex_lock(&arg->tid_reported_mutex);
- arg->reported_tid = GetTid();
- pthread_cond_broadcast(&arg->tid_reported_cond);
- pthread_mutex_unlock(&arg->tid_reported_mutex);
-
- pthread_mutex_lock(&arg->terminate_thread_mutex);
- while (!arg->terminate_thread)
- pthread_cond_wait(&arg->terminate_thread_cond,
- &arg->terminate_thread_mutex);
- pthread_mutex_unlock(&arg->terminate_thread_mutex);
- return NULL;
-}
-
-void ThreadListerTest::SpawnTidReporter(pthread_t *pthread_id,
- pid_t *tid) {
- pthread_mutex_lock(&thread_arg.tid_reported_mutex);
- thread_arg.reported_tid = -1;
- ASSERT_EQ(0, pthread_create(pthread_id, NULL,
- TidReporterThread,
- &thread_arg));
- while (thread_arg.reported_tid == -1)
- pthread_cond_wait(&thread_arg.tid_reported_cond,
- &thread_arg.tid_reported_mutex);
- pthread_mutex_unlock(&thread_arg.tid_reported_mutex);
- *tid = thread_arg.reported_tid;
-}
-
-static std::vector<pid_t> ReadTidsToVector(ThreadLister *thread_lister) {
- std::vector<pid_t> listed_tids;
- pid_t tid;
- while ((tid = thread_lister->GetNextTID()) >= 0)
- listed_tids.push_back(tid);
- EXPECT_FALSE(thread_lister->error());
- return listed_tids;
-}
-
-static bool Includes(std::vector<pid_t> first, std::vector<pid_t> second) {
- std::sort(first.begin(), first.end());
- std::sort(second.begin(), second.end());
- return std::includes(first.begin(), first.end(),
- second.begin(), second.end());
-}
-
-static bool HasElement(std::vector<pid_t> vector, pid_t element) {
- return std::find(vector.begin(), vector.end(), element) != vector.end();
-}
-
-// ThreadLister's output should include the current thread's TID and the TID of
-// every thread we spawned.
-TEST_F(ThreadListerTest, ThreadListerSeesAllSpawnedThreads) {
- pid_t self_tid = GetTid();
- ThreadLister thread_lister(getpid());
- std::vector<pid_t> listed_tids = ReadTidsToVector(&thread_lister);
- ASSERT_TRUE(HasElement(listed_tids, self_tid));
- ASSERT_TRUE(Includes(listed_tids, tids_));
-}
-
-// Calling Reset() should not cause ThreadLister to forget any threads it's
-// supposed to know about.
-TEST_F(ThreadListerTest, ResetDoesNotForgetThreads) {
- ThreadLister thread_lister(getpid());
-
- // Run the loop body twice, because Reset() might behave differently if called
- // on a freshly created object.
- for (uptr i = 0; i < 2; i++) {
- thread_lister.Reset();
- std::vector<pid_t> listed_tids = ReadTidsToVector(&thread_lister);
- ASSERT_TRUE(Includes(listed_tids, tids_));
- }
-}
-
-// If new threads have spawned during ThreadLister object's lifetime, calling
-// Reset() should cause ThreadLister to recognize their existence.
-TEST_F(ThreadListerTest, ResetMakesNewThreadsKnown) {
- ThreadLister thread_lister(getpid());
- std::vector<pid_t> threads_before_extra = ReadTidsToVector(&thread_lister);
-
- pthread_t extra_pthread_id;
- pid_t extra_tid;
- SpawnTidReporter(&extra_pthread_id, &extra_tid);
- // Register the new thread so it gets terminated in TearDown().
- pthread_ids_.push_back(extra_pthread_id);
-
- // It would be very bizarre if the new TID had been listed before we even
- // spawned that thread, but it would also cause a false success in this test,
- // so better check for that.
- ASSERT_FALSE(HasElement(threads_before_extra, extra_tid));
-
- thread_lister.Reset();
-
- std::vector<pid_t> threads_after_extra = ReadTidsToVector(&thread_lister);
- ASSERT_TRUE(HasElement(threads_after_extra, extra_tid));
-}
-
-TEST(SanitizerCommon, SetEnvTest) {
- const char kEnvName[] = "ENV_FOO";
- SetEnv(kEnvName, "value");
- EXPECT_STREQ("value", getenv(kEnvName));
- unsetenv(kEnvName);
- EXPECT_EQ(0, getenv(kEnvName));
-}
-
-#if defined(__x86_64__) || defined(__i386__)
-void *thread_self_offset_test_func(void *arg) {
- bool result =
- *(uptr *)((char *)ThreadSelf() + ThreadSelfOffset()) == ThreadSelf();
- return (void *)result;
-}
-
-TEST(SanitizerLinux, ThreadSelfOffset) {
- EXPECT_TRUE((bool)thread_self_offset_test_func(0));
- pthread_t tid;
- void *result;
- ASSERT_EQ(0, pthread_create(&tid, 0, thread_self_offset_test_func, 0));
- ASSERT_EQ(0, pthread_join(tid, &result));
- EXPECT_TRUE((bool)result);
-}
-
-// libpthread puts the thread descriptor at the end of stack space.
-void *thread_descriptor_size_test_func(void *arg) {
- uptr descr_addr = ThreadSelf();
- pthread_attr_t attr;
- pthread_getattr_np(pthread_self(), &attr);
- void *stackaddr;
- size_t stacksize;
- pthread_attr_getstack(&attr, &stackaddr, &stacksize);
- return (void *)((uptr)stackaddr + stacksize - descr_addr);
-}
-
-TEST(SanitizerLinux, ThreadDescriptorSize) {
- pthread_t tid;
- void *result;
- ASSERT_EQ(0, pthread_create(&tid, 0, thread_descriptor_size_test_func, 0));
- ASSERT_EQ(0, pthread_join(tid, &result));
- EXPECT_EQ((uptr)result, ThreadDescriptorSize());
-}
-#endif
-
-TEST(SanitizerCommon, LibraryNameIs) {
- EXPECT_FALSE(LibraryNameIs("", ""));
-
- char full_name[256];
- const char *paths[] = { "", "/", "/path/to/" };
- const char *suffixes[] = { "", "-linux", ".1.2", "-linux.1.2" };
- const char *base_names[] = { "lib", "lib.0", "lib-i386" };
- const char *wrong_names[] = { "", "lib.9", "lib-x86_64" };
- for (uptr i = 0; i < ARRAY_SIZE(paths); i++)
- for (uptr j = 0; j < ARRAY_SIZE(suffixes); j++) {
- for (uptr k = 0; k < ARRAY_SIZE(base_names); k++) {
- internal_snprintf(full_name, ARRAY_SIZE(full_name), "%s%s%s.so",
- paths[i], base_names[k], suffixes[j]);
- EXPECT_TRUE(LibraryNameIs(full_name, base_names[k]))
- << "Full name " << full_name
- << " doesn't match base name " << base_names[k];
- for (uptr m = 0; m < ARRAY_SIZE(wrong_names); m++)
- EXPECT_FALSE(LibraryNameIs(full_name, wrong_names[m]))
- << "Full name " << full_name
- << " matches base name " << wrong_names[m];
- }
- }
-}
-
-#if defined(__mips64)
-// Effectively, this is a test for ThreadDescriptorSize() which is used to
-// compute ThreadSelf().
-TEST(SanitizerLinux, ThreadSelfTest) {
- ASSERT_EQ(pthread_self(), ThreadSelf());
-}
-#endif
-
-} // namespace __sanitizer
-
-#endif // SANITIZER_LINUX
diff --git a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_list_test.cc b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_list_test.cc
deleted file mode 100644
index fbe53c0375c0..000000000000
--- a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_list_test.cc
+++ /dev/null
@@ -1,173 +0,0 @@
-//===-- sanitizer_list_test.cc --------------------------------------------===//
-//
-// 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 ThreadSanitizer/AddressSanitizer runtime.
-//
-//===----------------------------------------------------------------------===//
-#include "sanitizer_common/sanitizer_list.h"
-#include "gtest/gtest.h"
-
-namespace __sanitizer {
-
-struct ListItem {
- ListItem *next;
-};
-
-typedef IntrusiveList<ListItem> List;
-
-static List static_list;
-
-static void SetList(List *l, ListItem *x = 0,
- ListItem *y = 0, ListItem *z = 0) {
- l->clear();
- if (x) l->push_back(x);
- if (y) l->push_back(y);
- if (z) l->push_back(z);
-}
-
-static void CheckList(List *l, ListItem *i1, ListItem *i2 = 0, ListItem *i3 = 0,
- ListItem *i4 = 0, ListItem *i5 = 0, ListItem *i6 = 0) {
- if (i1) {
- CHECK_EQ(l->front(), i1);
- l->pop_front();
- }
- if (i2) {
- CHECK_EQ(l->front(), i2);
- l->pop_front();
- }
- if (i3) {
- CHECK_EQ(l->front(), i3);
- l->pop_front();
- }
- if (i4) {
- CHECK_EQ(l->front(), i4);
- l->pop_front();
- }
- if (i5) {
- CHECK_EQ(l->front(), i5);
- l->pop_front();
- }
- if (i6) {
- CHECK_EQ(l->front(), i6);
- l->pop_front();
- }
- CHECK(l->empty());
-}
-
-TEST(SanitizerCommon, IntrusiveList) {
- ListItem items[6];
- CHECK_EQ(static_list.size(), 0);
-
- List l;
- l.clear();
-
- ListItem *x = &items[0];
- ListItem *y = &items[1];
- ListItem *z = &items[2];
- ListItem *a = &items[3];
- ListItem *b = &items[4];
- ListItem *c = &items[5];
-
- CHECK_EQ(l.size(), 0);
- l.push_back(x);
- CHECK_EQ(l.size(), 1);
- CHECK_EQ(l.back(), x);
- CHECK_EQ(l.front(), x);
- l.pop_front();
- CHECK(l.empty());
- l.CheckConsistency();
-
- l.push_front(x);
- CHECK_EQ(l.size(), 1);
- CHECK_EQ(l.back(), x);
- CHECK_EQ(l.front(), x);
- l.pop_front();
- CHECK(l.empty());
- l.CheckConsistency();
-
- l.push_front(x);
- l.push_front(y);
- l.push_front(z);
- CHECK_EQ(l.size(), 3);
- CHECK_EQ(l.front(), z);
- CHECK_EQ(l.back(), x);
- l.CheckConsistency();
-
- l.pop_front();
- CHECK_EQ(l.size(), 2);
- CHECK_EQ(l.front(), y);
- CHECK_EQ(l.back(), x);
- l.pop_front();
- l.pop_front();
- CHECK(l.empty());
- l.CheckConsistency();
-
- l.push_back(x);
- l.push_back(y);
- l.push_back(z);
- CHECK_EQ(l.size(), 3);
- CHECK_EQ(l.front(), x);
- CHECK_EQ(l.back(), z);
- l.CheckConsistency();
-
- l.pop_front();
- CHECK_EQ(l.size(), 2);
- CHECK_EQ(l.front(), y);
- CHECK_EQ(l.back(), z);
- l.pop_front();
- l.pop_front();
- CHECK(l.empty());
- l.CheckConsistency();
-
- List l1, l2;
- l1.clear();
- l2.clear();
-
- l1.append_front(&l2);
- CHECK(l1.empty());
- CHECK(l2.empty());
-
- l1.append_back(&l2);
- CHECK(l1.empty());
- CHECK(l2.empty());
-
- SetList(&l1, x);
- CheckList(&l1, x);
-
- SetList(&l1, x, y, z);
- SetList(&l2, a, b, c);
- l1.append_back(&l2);
- CheckList(&l1, x, y, z, a, b, c);
- CHECK(l2.empty());
-
- SetList(&l1, x, y);
- SetList(&l2);
- l1.append_front(&l2);
- CheckList(&l1, x, y);
- CHECK(l2.empty());
-}
-
-TEST(SanitizerCommon, IntrusiveListAppendEmpty) {
- ListItem i;
- List l;
- l.clear();
- l.push_back(&i);
- List l2;
- l2.clear();
- l.append_back(&l2);
- CHECK_EQ(l.back(), &i);
- CHECK_EQ(l.front(), &i);
- CHECK_EQ(l.size(), 1);
- l.append_front(&l2);
- CHECK_EQ(l.back(), &i);
- CHECK_EQ(l.front(), &i);
- CHECK_EQ(l.size(), 1);
-}
-
-} // namespace __sanitizer
diff --git a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_mutex_test.cc b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_mutex_test.cc
deleted file mode 100644
index d14e7c2fba21..000000000000
--- a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_mutex_test.cc
+++ /dev/null
@@ -1,137 +0,0 @@
-//===-- sanitizer_mutex_test.cc -------------------------------------------===//
-//
-// 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 ThreadSanitizer/AddressSanitizer runtime.
-//
-//===----------------------------------------------------------------------===//
-#include "sanitizer_common/sanitizer_mutex.h"
-#include "sanitizer_common/sanitizer_common.h"
-
-#include "sanitizer_pthread_wrappers.h"
-
-#include "gtest/gtest.h"
-
-#include <string.h>
-
-namespace __sanitizer {
-
-template<typename MutexType>
-class TestData {
- public:
- explicit TestData(MutexType *mtx)
- : mtx_(mtx) {
- for (int i = 0; i < kSize; i++)
- data_[i] = 0;
- }
-
- void Write() {
- Lock l(mtx_);
- T v0 = data_[0];
- for (int i = 0; i < kSize; i++) {
- CHECK_EQ(data_[i], v0);
- data_[i]++;
- }
- }
-
- void TryWrite() {
- if (!mtx_->TryLock())
- return;
- T v0 = data_[0];
- for (int i = 0; i < kSize; i++) {
- CHECK_EQ(data_[i], v0);
- data_[i]++;
- }
- mtx_->Unlock();
- }
-
- void Backoff() {
- volatile T data[kSize] = {};
- for (int i = 0; i < kSize; i++) {
- data[i]++;
- CHECK_EQ(data[i], 1);
- }
- }
-
- private:
- typedef GenericScopedLock<MutexType> Lock;
- static const int kSize = 64;
- typedef u64 T;
- MutexType *mtx_;
- char pad_[kCacheLineSize];
- T data_[kSize];
-};
-
-const int kThreads = 8;
-#if SANITIZER_DEBUG
-const int kIters = 16*1024;
-#else
-const int kIters = 64*1024;
-#endif
-
-template<typename MutexType>
-static void *lock_thread(void *param) {
- TestData<MutexType> *data = (TestData<MutexType>*)param;
- for (int i = 0; i < kIters; i++) {
- data->Write();
- data->Backoff();
- }
- return 0;
-}
-
-template<typename MutexType>
-static void *try_thread(void *param) {
- TestData<MutexType> *data = (TestData<MutexType>*)param;
- for (int i = 0; i < kIters; i++) {
- data->TryWrite();
- data->Backoff();
- }
- return 0;
-}
-
-template<typename MutexType>
-static void check_locked(MutexType *mtx) {
- GenericScopedLock<MutexType> l(mtx);
- mtx->CheckLocked();
-}
-
-TEST(SanitizerCommon, SpinMutex) {
- SpinMutex mtx;
- mtx.Init();
- TestData<SpinMutex> data(&mtx);
- pthread_t threads[kThreads];
- for (int i = 0; i < kThreads; i++)
- PTHREAD_CREATE(&threads[i], 0, lock_thread<SpinMutex>, &data);
- for (int i = 0; i < kThreads; i++)
- PTHREAD_JOIN(threads[i], 0);
-}
-
-TEST(SanitizerCommon, SpinMutexTry) {
- SpinMutex mtx;
- mtx.Init();
- TestData<SpinMutex> data(&mtx);
- pthread_t threads[kThreads];
- for (int i = 0; i < kThreads; i++)
- PTHREAD_CREATE(&threads[i], 0, try_thread<SpinMutex>, &data);
- for (int i = 0; i < kThreads; i++)
- PTHREAD_JOIN(threads[i], 0);
-}
-
-TEST(SanitizerCommon, BlockingMutex) {
- u64 mtxmem[1024] = {};
- BlockingMutex *mtx = new(mtxmem) BlockingMutex(LINKER_INITIALIZED);
- TestData<BlockingMutex> data(mtx);
- pthread_t threads[kThreads];
- for (int i = 0; i < kThreads; i++)
- PTHREAD_CREATE(&threads[i], 0, lock_thread<BlockingMutex>, &data);
- for (int i = 0; i < kThreads; i++)
- PTHREAD_JOIN(threads[i], 0);
- check_locked(mtx);
-}
-
-} // namespace __sanitizer
diff --git a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_nolibc_test.cc b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_nolibc_test.cc
deleted file mode 100644
index d0d5a5e13898..000000000000
--- a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_nolibc_test.cc
+++ /dev/null
@@ -1,31 +0,0 @@
-//===-- sanitizer_nolibc_test.cc ------------------------------------------===//
-//
-// 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 ThreadSanitizer/AddressSanitizer runtime.
-// Tests for libc independence of sanitizer_common.
-//
-//===----------------------------------------------------------------------===//
-
-#include "sanitizer_common/sanitizer_platform.h"
-
-#include "gtest/gtest.h"
-
-#include <stdlib.h>
-
-extern const char *argv0;
-
-#if SANITIZER_LINUX && defined(__x86_64__)
-TEST(SanitizerCommon, NolibcMain) {
- std::string NolibcTestPath = argv0;
- NolibcTestPath += "-Nolibc";
- int status = system(NolibcTestPath.c_str());
- EXPECT_EQ(true, WIFEXITED(status));
- EXPECT_EQ(0, WEXITSTATUS(status));
-}
-#endif
diff --git a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_nolibc_test_main.cc b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_nolibc_test_main.cc
deleted file mode 100644
index 72df621d07ff..000000000000
--- a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_nolibc_test_main.cc
+++ /dev/null
@@ -1,19 +0,0 @@
-//===-- sanitizer_nolibc_test_main.cc -------------------------------------===//
-//
-// 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 ThreadSanitizer/AddressSanitizer runtime.
-// Tests for libc independence of sanitizer_common.
-//
-//===----------------------------------------------------------------------===//
-
-#include "sanitizer_common/sanitizer_libc.h"
-
-extern "C" void _start() {
- internal__exit(0);
-}
diff --git a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_posix_test.cc b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_posix_test.cc
deleted file mode 100644
index 03ca449d3622..000000000000
--- a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_posix_test.cc
+++ /dev/null
@@ -1,80 +0,0 @@
-//===-- sanitizer_posix_test.cc -------------------------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// Tests for POSIX-specific code.
-//
-//===----------------------------------------------------------------------===//
-
-#include "sanitizer_common/sanitizer_platform.h"
-#if SANITIZER_POSIX
-
-#include "sanitizer_common/sanitizer_common.h"
-#include "gtest/gtest.h"
-
-#include <pthread.h>
-#include <sys/mman.h>
-
-namespace __sanitizer {
-
-static pthread_key_t key;
-static bool destructor_executed;
-
-extern "C"
-void destructor(void *arg) {
- uptr iter = reinterpret_cast<uptr>(arg);
- if (iter > 1) {
- ASSERT_EQ(0, pthread_setspecific(key, reinterpret_cast<void *>(iter - 1)));
- return;
- }
- destructor_executed = true;
-}
-
-extern "C"
-void *thread_func(void *arg) {
- return reinterpret_cast<void*>(pthread_setspecific(key, arg));
-}
-
-static void SpawnThread(uptr iteration) {
- destructor_executed = false;
- pthread_t tid;
- ASSERT_EQ(0, pthread_create(&tid, 0, &thread_func,
- reinterpret_cast<void *>(iteration)));
- void *retval;
- ASSERT_EQ(0, pthread_join(tid, &retval));
- ASSERT_EQ(0, retval);
-}
-
-TEST(SanitizerCommon, PthreadDestructorIterations) {
- ASSERT_EQ(0, pthread_key_create(&key, &destructor));
- SpawnThread(GetPthreadDestructorIterations());
- EXPECT_TRUE(destructor_executed);
- SpawnThread(GetPthreadDestructorIterations() + 1);
- EXPECT_FALSE(destructor_executed);
-}
-
-TEST(SanitizerCommon, IsAccessibleMemoryRange) {
- const int page_size = GetPageSize();
- uptr mem = (uptr)mmap(0, 3 * page_size, PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANON, -1, 0);
- // Protect the middle page.
- mprotect((void *)(mem + page_size), page_size, PROT_NONE);
- EXPECT_TRUE(IsAccessibleMemoryRange(mem, page_size - 1));
- EXPECT_TRUE(IsAccessibleMemoryRange(mem, page_size));
- EXPECT_FALSE(IsAccessibleMemoryRange(mem, page_size + 1));
- EXPECT_TRUE(IsAccessibleMemoryRange(mem + page_size - 1, 1));
- EXPECT_FALSE(IsAccessibleMemoryRange(mem + page_size - 1, 2));
- EXPECT_FALSE(IsAccessibleMemoryRange(mem + 2 * page_size - 1, 1));
- EXPECT_TRUE(IsAccessibleMemoryRange(mem + 2 * page_size, page_size));
- EXPECT_FALSE(IsAccessibleMemoryRange(mem, 3 * page_size));
- EXPECT_FALSE(IsAccessibleMemoryRange(0x0, 2));
-}
-
-} // namespace __sanitizer
-
-#endif // SANITIZER_POSIX
diff --git a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_printf_test.cc b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_printf_test.cc
deleted file mode 100644
index 5e39e0a591d6..000000000000
--- a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_printf_test.cc
+++ /dev/null
@@ -1,153 +0,0 @@
-//===-- sanitizer_printf_test.cc ------------------------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// Tests for sanitizer_printf.cc
-//
-//===----------------------------------------------------------------------===//
-#include "sanitizer_common/sanitizer_common.h"
-#include "sanitizer_common/sanitizer_libc.h"
-#include "gtest/gtest.h"
-
-#include <string.h>
-#include <limits.h>
-
-namespace __sanitizer {
-
-TEST(Printf, Basic) {
- char buf[1024];
- uptr len = internal_snprintf(buf, sizeof(buf),
- "a%db%zdc%ue%zuf%xh%zxq%pe%sr",
- (int)-1, (long)-2, // NOLINT
- (unsigned)-4, (unsigned long)5, // NOLINT
- (unsigned)10, (unsigned long)11, // NOLINT
- (void*)0x123, "_string_");
- EXPECT_EQ(len, strlen(buf));
-
- std::string expectedString = "a-1b-2c4294967292e5fahbq0x";
- expectedString += std::string(SANITIZER_POINTER_FORMAT_LENGTH - 3, '0');
- expectedString += "123e_string_r";
- EXPECT_STREQ(expectedString.c_str(), buf);
-}
-
-TEST(Printf, OverflowStr) {
- char buf[] = "123456789";
- uptr len = internal_snprintf(buf, 4, "%s", "abcdef"); // NOLINT
- EXPECT_EQ(len, (uptr)6);
- EXPECT_STREQ("abc", buf);
- EXPECT_EQ(buf[3], 0);
- EXPECT_EQ(buf[4], '5');
- EXPECT_EQ(buf[5], '6');
- EXPECT_EQ(buf[6], '7');
- EXPECT_EQ(buf[7], '8');
- EXPECT_EQ(buf[8], '9');
- EXPECT_EQ(buf[9], 0);
-}
-
-TEST(Printf, OverflowInt) {
- char buf[] = "123456789";
- internal_snprintf(buf, 4, "%d", -123456789); // NOLINT
- EXPECT_STREQ("-12", buf);
- EXPECT_EQ(buf[3], 0);
- EXPECT_EQ(buf[4], '5');
- EXPECT_EQ(buf[5], '6');
- EXPECT_EQ(buf[6], '7');
- EXPECT_EQ(buf[7], '8');
- EXPECT_EQ(buf[8], '9');
- EXPECT_EQ(buf[9], 0);
-}
-
-TEST(Printf, OverflowUint) {
- char buf[] = "123456789";
- uptr val;
- if (sizeof(val) == 4) {
- val = (uptr)0x12345678;
- } else {
- val = (uptr)0x123456789ULL;
- }
- internal_snprintf(buf, 4, "a%zx", val); // NOLINT
- EXPECT_STREQ("a12", buf);
- EXPECT_EQ(buf[3], 0);
- EXPECT_EQ(buf[4], '5');
- EXPECT_EQ(buf[5], '6');
- EXPECT_EQ(buf[6], '7');
- EXPECT_EQ(buf[7], '8');
- EXPECT_EQ(buf[8], '9');
- EXPECT_EQ(buf[9], 0);
-}
-
-TEST(Printf, OverflowPtr) {
- char buf[] = "123456789";
- void *p;
- if (sizeof(p) == 4) {
- p = (void*)0x1234567;
- } else {
- p = (void*)0x123456789ULL;
- }
- internal_snprintf(buf, 4, "%p", p); // NOLINT
- EXPECT_STREQ("0x0", buf);
- EXPECT_EQ(buf[3], 0);
- EXPECT_EQ(buf[4], '5');
- EXPECT_EQ(buf[5], '6');
- EXPECT_EQ(buf[6], '7');
- EXPECT_EQ(buf[7], '8');
- EXPECT_EQ(buf[8], '9');
- EXPECT_EQ(buf[9], 0);
-}
-
-#if defined(_WIN32)
-// Oh well, MSVS headers don't define snprintf.
-# define snprintf _snprintf
-#endif
-
-template<typename T>
-static void TestAgainstLibc(const char *fmt, T arg1, T arg2) {
- char buf[1024];
- uptr len = internal_snprintf(buf, sizeof(buf), fmt, arg1, arg2);
- char buf2[1024];
- snprintf(buf2, sizeof(buf2), fmt, arg1, arg2);
- EXPECT_EQ(len, strlen(buf));
- EXPECT_STREQ(buf2, buf);
-}
-
-TEST(Printf, MinMax) {
- TestAgainstLibc<int>("%d-%d", INT_MIN, INT_MAX); // NOLINT
- TestAgainstLibc<unsigned>("%u-%u", 0, UINT_MAX); // NOLINT
- TestAgainstLibc<unsigned>("%x-%x", 0, UINT_MAX); // NOLINT
-#if !defined(_WIN32)
- // %z* format doesn't seem to be supported by MSVS.
- TestAgainstLibc<long>("%zd-%zd", LONG_MIN, LONG_MAX); // NOLINT
- TestAgainstLibc<unsigned long>("%zu-%zu", 0, ULONG_MAX); // NOLINT
- TestAgainstLibc<unsigned long>("%zx-%zx", 0, ULONG_MAX); // NOLINT
-#endif
-}
-
-TEST(Printf, Padding) {
- TestAgainstLibc<int>("%3d - %3d", 1, 0);
- TestAgainstLibc<int>("%3d - %3d", -1, 123);
- TestAgainstLibc<int>("%3d - %3d", -1, -123);
- TestAgainstLibc<int>("%3d - %3d", 12, 1234);
- TestAgainstLibc<int>("%3d - %3d", -12, -1234);
- TestAgainstLibc<int>("%03d - %03d", 1, 0);
- TestAgainstLibc<int>("%03d - %03d", -1, 123);
- TestAgainstLibc<int>("%03d - %03d", -1, -123);
- TestAgainstLibc<int>("%03d - %03d", 12, 1234);
- TestAgainstLibc<int>("%03d - %03d", -12, -1234);
-}
-
-TEST(Printf, Precision) {
- char buf[1024];
- uptr len = internal_snprintf(buf, sizeof(buf), "%.*s", 3, "12345");
- EXPECT_EQ(3U, len);
- EXPECT_STREQ("123", buf);
- len = internal_snprintf(buf, sizeof(buf), "%.*s", 6, "12345");
- EXPECT_EQ(5U, len);
- EXPECT_STREQ("12345", buf);
-}
-
-} // namespace __sanitizer
diff --git a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_procmaps_test.cc b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_procmaps_test.cc
deleted file mode 100644
index 12bc9e18193a..000000000000
--- a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_procmaps_test.cc
+++ /dev/null
@@ -1,56 +0,0 @@
-//===-- sanitizer_procmaps_test.cc ----------------------------------------===//
-//
-// 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 ThreadSanitizer/AddressSanitizer runtime.
-//
-//===----------------------------------------------------------------------===//
-#if !defined(_WIN32) // There are no /proc/maps on Windows.
-
-#include "sanitizer_common/sanitizer_procmaps.h"
-#include "gtest/gtest.h"
-
-#include <stdlib.h>
-
-static void noop() {}
-extern const char *argv0;
-
-namespace __sanitizer {
-
-#if SANITIZER_LINUX && !SANITIZER_ANDROID
-TEST(MemoryMappingLayout, CodeRange) {
- uptr start, end;
- bool res = GetCodeRangeForFile("[vdso]", &start, &end);
- EXPECT_EQ(res, true);
- EXPECT_GT(start, 0U);
- EXPECT_LT(start, end);
-}
-#endif
-
-TEST(MemoryMappingLayout, DumpListOfModules) {
- const char *last_slash = strrchr(argv0, '/');
- const char *binary_name = last_slash ? last_slash + 1 : argv0;
- MemoryMappingLayout memory_mapping(false);
- const uptr kMaxModules = 100;
- LoadedModule modules[kMaxModules];
- uptr n_modules = memory_mapping.DumpListOfModules(modules, kMaxModules, 0);
- EXPECT_GT(n_modules, 0U);
- bool found = false;
- for (uptr i = 0; i < n_modules; ++i) {
- if (modules[i].containsAddress((uptr)&noop)) {
- // Verify that the module name is sane.
- if (strstr(modules[i].full_name(), binary_name) != 0)
- found = true;
- }
- modules[i].clear();
- }
- EXPECT_TRUE(found);
-}
-
-} // namespace __sanitizer
-#endif // !defined(_WIN32)
diff --git a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_pthread_wrappers.h b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_pthread_wrappers.h
deleted file mode 100644
index 47b0f97de840..000000000000
--- a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_pthread_wrappers.h
+++ /dev/null
@@ -1,66 +0,0 @@
-//===-- sanitizer_pthread_wrappers.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 *Sanitizer runtime.
-// It provides handy wrappers for thread manipulation, that:
-// a) assert on any failure rather than returning an error code
-// b) defines pthread-like interface on platforms where where <pthread.h>
-// is not supplied by default.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef SANITIZER_PTHREAD_WRAPPERS_H
-#define SANITIZER_PTHREAD_WRAPPERS_H
-
-#include "sanitizer_test_utils.h"
-
-#if !defined(_WIN32)
-# include <pthread.h>
-// Simply forward the arguments and check that the pthread functions succeed.
-# define PTHREAD_CREATE(a, b, c, d) ASSERT_EQ(0, pthread_create(a, b, c, d))
-# define PTHREAD_JOIN(a, b) ASSERT_EQ(0, pthread_join(a, b))
-#else
-typedef HANDLE pthread_t;
-
-struct PthreadHelperCreateThreadInfo {
- void *(*start_routine)(void *);
- void *arg;
-};
-
-inline DWORD WINAPI PthreadHelperThreadProc(void *arg) {
- PthreadHelperCreateThreadInfo *start_data =
- reinterpret_cast<PthreadHelperCreateThreadInfo*>(arg);
- void *ret = (start_data->start_routine)(start_data->arg);
- delete start_data;
- return (DWORD)ret;
-}
-
-inline void PTHREAD_CREATE(pthread_t *thread, void *attr,
- void *(*start_routine)(void *), void *arg) {
- ASSERT_EQ(0, attr) << "Thread attributes are not supported yet.";
- PthreadHelperCreateThreadInfo *data = new PthreadHelperCreateThreadInfo;
- data->start_routine = start_routine;
- data->arg = arg;
- *thread = CreateThread(0, 0, PthreadHelperThreadProc, data, 0, 0);
- ASSERT_NE(nullptr, *thread) << "Failed to create a thread.";
-}
-
-inline void PTHREAD_JOIN(pthread_t thread, void **value_ptr) {
- ASSERT_EQ(0, value_ptr) << "Nonzero value_ptr is not supported yet.";
- ASSERT_EQ(WAIT_OBJECT_0, WaitForSingleObject(thread, INFINITE));
- ASSERT_NE(0, CloseHandle(thread));
-}
-
-inline void pthread_exit(void *retval) {
- ASSERT_EQ(0, retval) << "Nonzero retval is not supported yet.";
- ExitThread((DWORD)retval);
-}
-#endif // _WIN32
-
-#endif // SANITIZER_PTHREAD_WRAPPERS_H
diff --git a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_stackdepot_test.cc b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_stackdepot_test.cc
deleted file mode 100644
index 513432fac214..000000000000
--- a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_stackdepot_test.cc
+++ /dev/null
@@ -1,93 +0,0 @@
-//===-- sanitizer_stackdepot_test.cc --------------------------------------===//
-//
-// 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 ThreadSanitizer/AddressSanitizer runtime.
-//
-//===----------------------------------------------------------------------===//
-#include "sanitizer_common/sanitizer_stackdepot.h"
-#include "sanitizer_common/sanitizer_internal_defs.h"
-#include "sanitizer_common/sanitizer_libc.h"
-#include "gtest/gtest.h"
-
-namespace __sanitizer {
-
-TEST(SanitizerCommon, StackDepotBasic) {
- uptr array[] = {1, 2, 3, 4, 5};
- StackTrace s1(array, ARRAY_SIZE(array));
- u32 i1 = StackDepotPut(s1);
- StackTrace stack = StackDepotGet(i1);
- EXPECT_NE(stack.trace, (uptr*)0);
- EXPECT_EQ(ARRAY_SIZE(array), stack.size);
- EXPECT_EQ(0, internal_memcmp(stack.trace, array, sizeof(array)));
-}
-
-TEST(SanitizerCommon, StackDepotAbsent) {
- StackTrace stack = StackDepotGet((1 << 30) - 1);
- EXPECT_EQ((uptr*)0, stack.trace);
-}
-
-TEST(SanitizerCommon, StackDepotEmptyStack) {
- u32 i1 = StackDepotPut(StackTrace());
- StackTrace stack = StackDepotGet(i1);
- EXPECT_EQ((uptr*)0, stack.trace);
-}
-
-TEST(SanitizerCommon, StackDepotZeroId) {
- StackTrace stack = StackDepotGet(0);
- EXPECT_EQ((uptr*)0, stack.trace);
-}
-
-TEST(SanitizerCommon, StackDepotSame) {
- uptr array[] = {1, 2, 3, 4, 6};
- StackTrace s1(array, ARRAY_SIZE(array));
- u32 i1 = StackDepotPut(s1);
- u32 i2 = StackDepotPut(s1);
- EXPECT_EQ(i1, i2);
- StackTrace stack = StackDepotGet(i1);
- EXPECT_NE(stack.trace, (uptr*)0);
- EXPECT_EQ(ARRAY_SIZE(array), stack.size);
- EXPECT_EQ(0, internal_memcmp(stack.trace, array, sizeof(array)));
-}
-
-TEST(SanitizerCommon, StackDepotSeveral) {
- uptr array1[] = {1, 2, 3, 4, 7};
- StackTrace s1(array1, ARRAY_SIZE(array1));
- u32 i1 = StackDepotPut(s1);
- uptr array2[] = {1, 2, 3, 4, 8, 9};
- StackTrace s2(array2, ARRAY_SIZE(array2));
- u32 i2 = StackDepotPut(s2);
- EXPECT_NE(i1, i2);
-}
-
-TEST(SanitizerCommon, StackDepotReverseMap) {
- uptr array1[] = {1, 2, 3, 4, 5};
- uptr array2[] = {7, 1, 3, 0};
- uptr array3[] = {10, 2, 5, 3};
- uptr array4[] = {1, 3, 2, 5};
- u32 ids[4] = {0};
- StackTrace s1(array1, ARRAY_SIZE(array1));
- StackTrace s2(array2, ARRAY_SIZE(array2));
- StackTrace s3(array3, ARRAY_SIZE(array3));
- StackTrace s4(array4, ARRAY_SIZE(array4));
- ids[0] = StackDepotPut(s1);
- ids[1] = StackDepotPut(s2);
- ids[2] = StackDepotPut(s3);
- ids[3] = StackDepotPut(s4);
-
- StackDepotReverseMap map;
-
- for (uptr i = 0; i < 4; i++) {
- StackTrace stack = StackDepotGet(ids[i]);
- StackTrace from_map = map.Get(ids[i]);
- EXPECT_EQ(stack.size, from_map.size);
- EXPECT_EQ(stack.trace, from_map.trace);
- }
-}
-
-} // namespace __sanitizer
diff --git a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_stacktrace_printer_test.cc b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_stacktrace_printer_test.cc
deleted file mode 100644
index 05796fcbff77..000000000000
--- a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_stacktrace_printer_test.cc
+++ /dev/null
@@ -1,152 +0,0 @@
-//===-- sanitizer_common_printer_test.cc ----------------------------------===//
-//
-// 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 sanitizer_common test suite.
-//
-//===----------------------------------------------------------------------===//
-#include "sanitizer_common/sanitizer_stacktrace_printer.h"
-
-#include "gtest/gtest.h"
-
-namespace __sanitizer {
-
-TEST(SanitizerStacktracePrinter, RenderSourceLocation) {
- InternalScopedString str(128);
- RenderSourceLocation(&str, "/dir/file.cc", 10, 5, false, "");
- EXPECT_STREQ("/dir/file.cc:10:5", str.data());
-
- str.clear();
- RenderSourceLocation(&str, "/dir/file.cc", 11, 0, false, "");
- EXPECT_STREQ("/dir/file.cc:11", str.data());
-
- str.clear();
- RenderSourceLocation(&str, "/dir/file.cc", 0, 0, false, "");
- EXPECT_STREQ("/dir/file.cc", str.data());
-
- str.clear();
- RenderSourceLocation(&str, "/dir/file.cc", 10, 5, false, "/dir/");
- EXPECT_STREQ("file.cc:10:5", str.data());
-
- str.clear();
- RenderSourceLocation(&str, "/dir/file.cc", 10, 5, true, "");
- EXPECT_STREQ("/dir/file.cc(10,5)", str.data());
-
- str.clear();
- RenderSourceLocation(&str, "/dir/file.cc", 11, 0, true, "");
- EXPECT_STREQ("/dir/file.cc(11)", str.data());
-
- str.clear();
- RenderSourceLocation(&str, "/dir/file.cc", 0, 0, true, "");
- EXPECT_STREQ("/dir/file.cc", str.data());
-
- str.clear();
- RenderSourceLocation(&str, "/dir/file.cc", 10, 5, true, "/dir/");
- EXPECT_STREQ("file.cc(10,5)", str.data());
-}
-
-TEST(SanitizerStacktracePrinter, RenderModuleLocation) {
- InternalScopedString str(128);
- RenderModuleLocation(&str, "/dir/exe", 0x123, "");
- EXPECT_STREQ("(/dir/exe+0x123)", str.data());
-
- // Check that we strip file prefix if necessary.
- str.clear();
- RenderModuleLocation(&str, "/dir/exe", 0x123, "/dir/");
- EXPECT_STREQ("(exe+0x123)", str.data());
-}
-
-TEST(SanitizerStacktracePrinter, RenderFrame) {
- int frame_no = 42;
- AddressInfo info;
- info.address = 0x400000;
- info.module = internal_strdup("/path/to/my/module");
- info.module_offset = 0x200;
- info.function = internal_strdup("function_foo");
- info.function_offset = 0x100;
- info.file = internal_strdup("/path/to/my/source");
- info.line = 10;
- info.column = 5;
- InternalScopedString str(256);
-
- // Dump all the AddressInfo fields.
- RenderFrame(&str, "%% Frame:%n PC:%p Module:%m ModuleOffset:%o "
- "Function:%f FunctionOffset:%q Source:%s Line:%l "
- "Column:%c",
- frame_no, info, false, "/path/to/", "function_");
- EXPECT_STREQ("% Frame:42 PC:0x400000 Module:my/module ModuleOffset:0x200 "
- "Function:foo FunctionOffset:0x100 Source:my/source Line:10 "
- "Column:5",
- str.data());
- info.Clear();
- str.clear();
-
- // Test special format specifiers.
- info.address = 0x400000;
- RenderFrame(&str, "%M", frame_no, info, false);
- EXPECT_NE(nullptr, internal_strstr(str.data(), "400000"));
- str.clear();
-
- RenderFrame(&str, "%L", frame_no, info, false);
- EXPECT_STREQ("(<unknown module>)", str.data());
- str.clear();
-
- info.module = internal_strdup("/path/to/module");
- info.module_offset = 0x200;
- RenderFrame(&str, "%M", frame_no, info, false);
- EXPECT_NE(nullptr, internal_strstr(str.data(), "(module+0x"));
- EXPECT_NE(nullptr, internal_strstr(str.data(), "200"));
- str.clear();
-
- RenderFrame(&str, "%L", frame_no, info, false);
- EXPECT_STREQ("(/path/to/module+0x200)", str.data());
- str.clear();
-
- info.function = internal_strdup("my_function");
- RenderFrame(&str, "%F", frame_no, info, false);
- EXPECT_STREQ("in my_function", str.data());
- str.clear();
-
- info.function_offset = 0x100;
- RenderFrame(&str, "%F %S", frame_no, info, false);
- EXPECT_STREQ("in my_function+0x100 <null>", str.data());
- str.clear();
-
- info.file = internal_strdup("my_file");
- RenderFrame(&str, "%F %S", frame_no, info, false);
- EXPECT_STREQ("in my_function my_file", str.data());
- str.clear();
-
- info.line = 10;
- RenderFrame(&str, "%F %S", frame_no, info, false);
- EXPECT_STREQ("in my_function my_file:10", str.data());
- str.clear();
-
- info.column = 5;
- RenderFrame(&str, "%S %L", frame_no, info, false);
- EXPECT_STREQ("my_file:10:5 my_file:10:5", str.data());
- str.clear();
-
- RenderFrame(&str, "%S %L", frame_no, info, true);
- EXPECT_STREQ("my_file(10,5) my_file(10,5)", str.data());
- str.clear();
-
- info.column = 0;
- RenderFrame(&str, "%F %S", frame_no, info, true);
- EXPECT_STREQ("in my_function my_file(10)", str.data());
- str.clear();
-
- info.line = 0;
- RenderFrame(&str, "%F %S", frame_no, info, true);
- EXPECT_STREQ("in my_function my_file", str.data());
- str.clear();
-
- info.Clear();
-}
-
-} // namespace __sanitizer
diff --git a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc
deleted file mode 100644
index 654ea1db82fb..000000000000
--- a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc
+++ /dev/null
@@ -1,154 +0,0 @@
-//===-- sanitizer_stacktrace_test.cc --------------------------------------===//
-//
-// 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 ThreadSanitizer/AddressSanitizer runtime.
-//
-//===----------------------------------------------------------------------===//
-
-#include "sanitizer_common/sanitizer_common.h"
-#include "sanitizer_common/sanitizer_stacktrace.h"
-#include "gtest/gtest.h"
-
-namespace __sanitizer {
-
-class FastUnwindTest : public ::testing::Test {
- protected:
- virtual void SetUp();
- virtual void TearDown();
- bool TryFastUnwind(uptr max_depth) {
- if (!StackTrace::WillUseFastUnwind(true))
- return false;
- trace.Unwind(max_depth, start_pc, (uptr)&fake_stack[0], 0, fake_top,
- fake_bottom, true);
- return true;
- }
-
- void *mapping;
- uhwptr *fake_stack;
- const uptr fake_stack_size = 10;
- uhwptr start_pc;
- uhwptr fake_top;
- uhwptr fake_bottom;
- BufferedStackTrace trace;
-};
-
-static uptr PC(uptr idx) {
- return (1<<20) + idx;
-}
-
-void FastUnwindTest::SetUp() {
- size_t ps = GetPageSize();
- mapping = MmapOrDie(2 * ps, "FastUnwindTest");
- MprotectNoAccess((uptr)mapping, ps);
-
- // Unwinder may peek 1 word down from the starting FP.
- fake_stack = (uhwptr *)((uptr)mapping + ps + sizeof(uhwptr));
-
- // Fill an array of pointers with fake fp+retaddr pairs. Frame pointers have
- // even indices.
- for (uptr i = 0; i + 1 < fake_stack_size; i += 2) {
- fake_stack[i] = (uptr)&fake_stack[i+2]; // fp
- fake_stack[i+1] = PC(i + 1); // retaddr
- }
- // Mark the last fp point back up to terminate the stack trace.
- fake_stack[RoundDownTo(fake_stack_size - 1, 2)] = (uhwptr)&fake_stack[0];
-
- // Top is two slots past the end because FastUnwindStack subtracts two.
- fake_top = (uhwptr)&fake_stack[fake_stack_size + 2];
- // Bottom is one slot before the start because FastUnwindStack uses >.
- fake_bottom = (uhwptr)mapping;
- start_pc = PC(0);
-}
-
-void FastUnwindTest::TearDown() {
- size_t ps = GetPageSize();
- UnmapOrDie(mapping, 2 * ps);
-}
-
-TEST_F(FastUnwindTest, Basic) {
- if (!TryFastUnwind(kStackTraceMax))
- return;
- // Should get all on-stack retaddrs and start_pc.
- EXPECT_EQ(6U, trace.size);
- EXPECT_EQ(start_pc, trace.trace[0]);
- for (uptr i = 1; i <= 5; i++) {
- EXPECT_EQ(PC(i*2 - 1), trace.trace[i]);
- }
-}
-
-// From: http://code.google.com/p/address-sanitizer/issues/detail?id=162
-TEST_F(FastUnwindTest, FramePointerLoop) {
- // Make one fp point to itself.
- fake_stack[4] = (uhwptr)&fake_stack[4];
- if (!TryFastUnwind(kStackTraceMax))
- return;
- // Should get all on-stack retaddrs up to the 4th slot and start_pc.
- EXPECT_EQ(4U, trace.size);
- EXPECT_EQ(start_pc, trace.trace[0]);
- for (uptr i = 1; i <= 3; i++) {
- EXPECT_EQ(PC(i*2 - 1), trace.trace[i]);
- }
-}
-
-TEST_F(FastUnwindTest, MisalignedFramePointer) {
- // Make one fp misaligned.
- fake_stack[4] += 3;
- if (!TryFastUnwind(kStackTraceMax))
- return;
- // Should get all on-stack retaddrs up to the 4th slot and start_pc.
- EXPECT_EQ(4U, trace.size);
- EXPECT_EQ(start_pc, trace.trace[0]);
- for (uptr i = 1; i < 4U; i++) {
- EXPECT_EQ(PC(i*2 - 1), trace.trace[i]);
- }
-}
-
-TEST_F(FastUnwindTest, OneFrameStackTrace) {
- if (!TryFastUnwind(1))
- return;
- EXPECT_EQ(1U, trace.size);
- EXPECT_EQ(start_pc, trace.trace[0]);
- EXPECT_EQ((uhwptr)&fake_stack[0], trace.top_frame_bp);
-}
-
-TEST_F(FastUnwindTest, ZeroFramesStackTrace) {
- if (!TryFastUnwind(0))
- return;
- EXPECT_EQ(0U, trace.size);
- EXPECT_EQ(0U, trace.top_frame_bp);
-}
-
-TEST_F(FastUnwindTest, FPBelowPrevFP) {
- // The next FP points to unreadable memory inside the stack limits, but below
- // current FP.
- fake_stack[0] = (uhwptr)&fake_stack[-50];
- fake_stack[1] = PC(1);
- if (!TryFastUnwind(3))
- return;
- EXPECT_EQ(2U, trace.size);
- EXPECT_EQ(PC(0), trace.trace[0]);
- EXPECT_EQ(PC(1), trace.trace[1]);
-}
-
-TEST(SlowUnwindTest, ShortStackTrace) {
- if (StackTrace::WillUseFastUnwind(false))
- return;
- BufferedStackTrace stack;
- uptr pc = StackTrace::GetCurrentPc();
- uptr bp = GET_CURRENT_FRAME();
- stack.Unwind(0, pc, bp, 0, 0, 0, false);
- EXPECT_EQ(0U, stack.size);
- EXPECT_EQ(0U, stack.top_frame_bp);
- stack.Unwind(1, pc, bp, 0, 0, 0, false);
- EXPECT_EQ(1U, stack.size);
- EXPECT_EQ(pc, stack.trace[0]);
- EXPECT_EQ(bp, stack.top_frame_bp);
-}
-
-} // namespace __sanitizer
diff --git a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_stoptheworld_test.cc b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_stoptheworld_test.cc
deleted file mode 100644
index 802af392c609..000000000000
--- a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_stoptheworld_test.cc
+++ /dev/null
@@ -1,204 +0,0 @@
-//===-- sanitizer_stoptheworld_test.cc ------------------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// Tests for sanitizer_stoptheworld.h
-//
-//===----------------------------------------------------------------------===//
-
-#include "sanitizer_common/sanitizer_platform.h"
-#if SANITIZER_LINUX && defined(__x86_64__)
-
-#include "sanitizer_common/sanitizer_stoptheworld.h"
-#include "gtest/gtest.h"
-
-#include "sanitizer_common/sanitizer_libc.h"
-#include "sanitizer_common/sanitizer_common.h"
-
-#include <pthread.h>
-#include <sched.h>
-
-namespace __sanitizer {
-
-static pthread_mutex_t incrementer_thread_exit_mutex;
-
-struct CallbackArgument {
- volatile int counter;
- volatile bool threads_stopped;
- volatile bool callback_executed;
- CallbackArgument()
- : counter(0),
- threads_stopped(false),
- callback_executed(false) {}
-};
-
-void *IncrementerThread(void *argument) {
- CallbackArgument *callback_argument = (CallbackArgument *)argument;
- while (true) {
- __sync_fetch_and_add(&callback_argument->counter, 1);
- if (pthread_mutex_trylock(&incrementer_thread_exit_mutex) == 0) {
- pthread_mutex_unlock(&incrementer_thread_exit_mutex);
- return NULL;
- } else {
- sched_yield();
- }
- }
-}
-
-// This callback checks that IncrementerThread is suspended at the time of its
-// execution.
-void Callback(const SuspendedThreadsList &suspended_threads_list,
- void *argument) {
- CallbackArgument *callback_argument = (CallbackArgument *)argument;
- callback_argument->callback_executed = true;
- int counter_at_init = __sync_fetch_and_add(&callback_argument->counter, 0);
- for (uptr i = 0; i < 1000; i++) {
- sched_yield();
- if (__sync_fetch_and_add(&callback_argument->counter, 0) !=
- counter_at_init) {
- callback_argument->threads_stopped = false;
- return;
- }
- }
- callback_argument->threads_stopped = true;
-}
-
-TEST(StopTheWorld, SuspendThreadsSimple) {
- pthread_mutex_init(&incrementer_thread_exit_mutex, NULL);
- CallbackArgument argument;
- pthread_t thread_id;
- int pthread_create_result;
- pthread_mutex_lock(&incrementer_thread_exit_mutex);
- pthread_create_result = pthread_create(&thread_id, NULL, IncrementerThread,
- &argument);
- ASSERT_EQ(0, pthread_create_result);
- StopTheWorld(&Callback, &argument);
- pthread_mutex_unlock(&incrementer_thread_exit_mutex);
- EXPECT_TRUE(argument.callback_executed);
- EXPECT_TRUE(argument.threads_stopped);
- // argument is on stack, so we have to wait for the incrementer thread to
- // terminate before we can return from this function.
- ASSERT_EQ(0, pthread_join(thread_id, NULL));
- pthread_mutex_destroy(&incrementer_thread_exit_mutex);
-}
-
-// A more comprehensive test where we spawn a bunch of threads while executing
-// StopTheWorld in parallel.
-static const uptr kThreadCount = 50;
-static const uptr kStopWorldAfter = 10; // let this many threads spawn first
-
-static pthread_mutex_t advanced_incrementer_thread_exit_mutex;
-
-struct AdvancedCallbackArgument {
- volatile uptr thread_index;
- volatile int counters[kThreadCount];
- pthread_t thread_ids[kThreadCount];
- volatile bool threads_stopped;
- volatile bool callback_executed;
- volatile bool fatal_error;
- AdvancedCallbackArgument()
- : thread_index(0),
- threads_stopped(false),
- callback_executed(false),
- fatal_error(false) {}
-};
-
-void *AdvancedIncrementerThread(void *argument) {
- AdvancedCallbackArgument *callback_argument =
- (AdvancedCallbackArgument *)argument;
- uptr this_thread_index = __sync_fetch_and_add(
- &callback_argument->thread_index, 1);
- // Spawn the next thread.
- int pthread_create_result;
- if (this_thread_index + 1 < kThreadCount) {
- pthread_create_result =
- pthread_create(&callback_argument->thread_ids[this_thread_index + 1],
- NULL, AdvancedIncrementerThread, argument);
- // Cannot use ASSERT_EQ in non-void-returning functions. If there's a
- // problem, defer failing to the main thread.
- if (pthread_create_result != 0) {
- callback_argument->fatal_error = true;
- __sync_fetch_and_add(&callback_argument->thread_index,
- kThreadCount - callback_argument->thread_index);
- }
- }
- // Do the actual work.
- while (true) {
- __sync_fetch_and_add(&callback_argument->counters[this_thread_index], 1);
- if (pthread_mutex_trylock(&advanced_incrementer_thread_exit_mutex) == 0) {
- pthread_mutex_unlock(&advanced_incrementer_thread_exit_mutex);
- return NULL;
- } else {
- sched_yield();
- }
- }
-}
-
-void AdvancedCallback(const SuspendedThreadsList &suspended_threads_list,
- void *argument) {
- AdvancedCallbackArgument *callback_argument =
- (AdvancedCallbackArgument *)argument;
- callback_argument->callback_executed = true;
-
- int counters_at_init[kThreadCount];
- for (uptr j = 0; j < kThreadCount; j++)
- counters_at_init[j] = __sync_fetch_and_add(&callback_argument->counters[j],
- 0);
- for (uptr i = 0; i < 10; i++) {
- sched_yield();
- for (uptr j = 0; j < kThreadCount; j++)
- if (__sync_fetch_and_add(&callback_argument->counters[j], 0) !=
- counters_at_init[j]) {
- callback_argument->threads_stopped = false;
- return;
- }
- }
- callback_argument->threads_stopped = true;
-}
-
-TEST(StopTheWorld, SuspendThreadsAdvanced) {
- pthread_mutex_init(&advanced_incrementer_thread_exit_mutex, NULL);
- AdvancedCallbackArgument argument;
-
- pthread_mutex_lock(&advanced_incrementer_thread_exit_mutex);
- int pthread_create_result;
- pthread_create_result = pthread_create(&argument.thread_ids[0], NULL,
- AdvancedIncrementerThread,
- &argument);
- ASSERT_EQ(0, pthread_create_result);
- // Wait for several threads to spawn before proceeding.
- while (__sync_fetch_and_add(&argument.thread_index, 0) < kStopWorldAfter)
- sched_yield();
- StopTheWorld(&AdvancedCallback, &argument);
- EXPECT_TRUE(argument.callback_executed);
- EXPECT_TRUE(argument.threads_stopped);
-
- // Wait for all threads to spawn before we start terminating them.
- while (__sync_fetch_and_add(&argument.thread_index, 0) < kThreadCount)
- sched_yield();
- ASSERT_FALSE(argument.fatal_error); // a pthread_create has failed
- // Signal the threads to terminate.
- pthread_mutex_unlock(&advanced_incrementer_thread_exit_mutex);
- for (uptr i = 0; i < kThreadCount; i++)
- ASSERT_EQ(0, pthread_join(argument.thread_ids[i], NULL));
- pthread_mutex_destroy(&advanced_incrementer_thread_exit_mutex);
-}
-
-static void SegvCallback(const SuspendedThreadsList &suspended_threads_list,
- void *argument) {
- *(volatile int*)0x1234 = 0;
-}
-
-TEST(StopTheWorld, SegvInCallback) {
- // Test that tracer thread catches SIGSEGV.
- StopTheWorld(&SegvCallback, NULL);
-}
-
-} // namespace __sanitizer
-
-#endif // SANITIZER_LINUX && defined(__x86_64__)
diff --git a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_stoptheworld_testlib.cc b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_stoptheworld_testlib.cc
deleted file mode 100644
index d8be2afb19e9..000000000000
--- a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_stoptheworld_testlib.cc
+++ /dev/null
@@ -1,53 +0,0 @@
-//===-- sanitizer_stoptheworld_testlib.cc ---------------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-// Dynamic library to test StopTheWorld functionality.
-// When loaded with LD_PRELOAD, it will periodically suspend all threads.
-//===----------------------------------------------------------------------===//
-/* Usage:
-clang++ -fno-exceptions -g -fPIC -I. \
- sanitizer_common/tests/sanitizer_stoptheworld_testlib.cc \
- sanitizer_common/sanitizer_*.cc -shared -lpthread -o teststoptheworld.so
-LD_PRELOAD=`pwd`/teststoptheworld.so /your/app
-*/
-
-#include "sanitizer_common/sanitizer_platform.h"
-#if SANITIZER_LINUX
-
-#include <dlfcn.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <pthread.h>
-#include <unistd.h>
-
-#include "sanitizer_common/sanitizer_stoptheworld.h"
-
-namespace {
-const uptr kSuspendDuration = 3;
-const uptr kRunDuration = 3;
-
-void Callback(const SuspendedThreadsList &suspended_threads_list,
- void *argument) {
- sleep(kSuspendDuration);
-}
-
-void *SuspenderThread(void *argument) {
- while (true) {
- sleep(kRunDuration);
- StopTheWorld(Callback, NULL);
- }
- return NULL;
-}
-
-__attribute__((constructor)) void StopTheWorldTestLibConstructor(void) {
- pthread_t thread_id;
- pthread_create(&thread_id, NULL, SuspenderThread, NULL);
-}
-} // namespace
-
-#endif // SANITIZER_LINUX
diff --git a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_suppressions_test.cc b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_suppressions_test.cc
deleted file mode 100644
index e8c30d07e78c..000000000000
--- a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_suppressions_test.cc
+++ /dev/null
@@ -1,134 +0,0 @@
-//===-- sanitizer_suppressions_test.cc ------------------------------------===//
-//
-// 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 ThreadSanitizer/AddressSanitizer runtime.
-//
-//===----------------------------------------------------------------------===//
-#include "sanitizer_common/sanitizer_suppressions.h"
-#include "gtest/gtest.h"
-
-#include <string.h>
-
-namespace __sanitizer {
-
-static bool MyMatch(const char *templ, const char *func) {
- char tmp[1024];
- strcpy(tmp, templ); // NOLINT
- return TemplateMatch(tmp, func);
-}
-
-TEST(Suppressions, Match) {
- EXPECT_TRUE(MyMatch("foobar$", "foobar"));
-
- EXPECT_TRUE(MyMatch("foobar", "foobar"));
- EXPECT_TRUE(MyMatch("*foobar*", "foobar"));
- EXPECT_TRUE(MyMatch("foobar", "prefix_foobar_postfix"));
- EXPECT_TRUE(MyMatch("*foobar*", "prefix_foobar_postfix"));
- EXPECT_TRUE(MyMatch("foo*bar", "foo_middle_bar"));
- EXPECT_TRUE(MyMatch("foo*bar", "foobar"));
- EXPECT_TRUE(MyMatch("foo*bar*baz", "foo_middle_bar_another_baz"));
- EXPECT_TRUE(MyMatch("foo*bar*baz", "foo_middle_barbaz"));
- EXPECT_TRUE(MyMatch("^foobar", "foobar"));
- EXPECT_TRUE(MyMatch("^foobar", "foobar_postfix"));
- EXPECT_TRUE(MyMatch("^*foobar", "foobar"));
- EXPECT_TRUE(MyMatch("^*foobar", "prefix_foobar"));
- EXPECT_TRUE(MyMatch("foobar$", "foobar"));
- EXPECT_TRUE(MyMatch("foobar$", "prefix_foobar"));
- EXPECT_TRUE(MyMatch("*foobar*$", "foobar"));
- EXPECT_TRUE(MyMatch("*foobar*$", "foobar_postfix"));
- EXPECT_TRUE(MyMatch("^foobar$", "foobar"));
-
- EXPECT_FALSE(MyMatch("foo", "baz"));
- EXPECT_FALSE(MyMatch("foobarbaz", "foobar"));
- EXPECT_FALSE(MyMatch("foobarbaz", "barbaz"));
- EXPECT_FALSE(MyMatch("foo*bar", "foobaz"));
- EXPECT_FALSE(MyMatch("foo*bar", "foo_baz"));
- EXPECT_FALSE(MyMatch("^foobar", "prefix_foobar"));
- EXPECT_FALSE(MyMatch("foobar$", "foobar_postfix"));
- EXPECT_FALSE(MyMatch("^foobar$", "prefix_foobar"));
- EXPECT_FALSE(MyMatch("^foobar$", "foobar_postfix"));
- EXPECT_FALSE(MyMatch("foo^bar", "foobar"));
- EXPECT_FALSE(MyMatch("foo$bar", "foobar"));
- EXPECT_FALSE(MyMatch("foo$^bar", "foobar"));
-}
-
-static const char *kTestSuppressionTypes[] = {"race", "thread", "mutex",
- "signal"};
-
-class SuppressionContextTest : public ::testing::Test {
- public:
- SuppressionContextTest()
- : ctx_(kTestSuppressionTypes, ARRAY_SIZE(kTestSuppressionTypes)) {}
-
- protected:
- SuppressionContext ctx_;
-
- void CheckSuppressions(unsigned count, std::vector<const char *> types,
- std::vector<const char *> templs) const {
- EXPECT_EQ(count, ctx_.SuppressionCount());
- for (unsigned i = 0; i < count; i++) {
- const Suppression *s = ctx_.SuppressionAt(i);
- EXPECT_STREQ(types[i], s->type);
- EXPECT_STREQ(templs[i], s->templ);
- }
- }
-};
-
-TEST_F(SuppressionContextTest, Parse) {
- ctx_.Parse("race:foo\n"
- " race:bar\n" // NOLINT
- "race:baz \n" // NOLINT
- "# a comment\n"
- "race:quz\n"); // NOLINT
- CheckSuppressions(4, {"race", "race", "race", "race"},
- {"foo", "bar", "baz", "quz"});
-}
-
-TEST_F(SuppressionContextTest, Parse2) {
- ctx_.Parse(
- " # first line comment\n" // NOLINT
- " race:bar \n" // NOLINT
- "race:baz* *baz\n"
- "# a comment\n"
- "# last line comment\n"
- ); // NOLINT
- CheckSuppressions(2, {"race", "race"}, {"bar", "baz* *baz"});
-}
-
-TEST_F(SuppressionContextTest, Parse3) {
- ctx_.Parse(
- "# last suppression w/o line-feed\n"
- "race:foo\n"
- "race:bar"
- ); // NOLINT
- CheckSuppressions(2, {"race", "race"}, {"foo", "bar"});
-}
-
-TEST_F(SuppressionContextTest, ParseType) {
- ctx_.Parse(
- "race:foo\n"
- "thread:bar\n"
- "mutex:baz\n"
- "signal:quz\n"
- ); // NOLINT
- CheckSuppressions(4, {"race", "thread", "mutex", "signal"},
- {"foo", "bar", "baz", "quz"});
-}
-
-TEST_F(SuppressionContextTest, HasSuppressionType) {
- ctx_.Parse(
- "race:foo\n"
- "thread:bar\n");
- EXPECT_TRUE(ctx_.HasSuppressionType("race"));
- EXPECT_TRUE(ctx_.HasSuppressionType("thread"));
- EXPECT_FALSE(ctx_.HasSuppressionType("mutex"));
- EXPECT_FALSE(ctx_.HasSuppressionType("signal"));
-}
-
-} // namespace __sanitizer
diff --git a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_symbolizer_test.cc b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_symbolizer_test.cc
deleted file mode 100644
index 429ac591e502..000000000000
--- a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_symbolizer_test.cc
+++ /dev/null
@@ -1,58 +0,0 @@
-//===-- sanitizer_symbolizer_test.cc --------------------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// Tests for sanitizer_symbolizer.h and sanitizer_symbolizer_internal.h
-//
-//===----------------------------------------------------------------------===//
-
-#include "sanitizer_common/sanitizer_allocator_internal.h"
-#include "sanitizer_common/sanitizer_symbolizer_internal.h"
-#include "gtest/gtest.h"
-
-namespace __sanitizer {
-
-TEST(Symbolizer, ExtractToken) {
- char *token;
- const char *rest;
-
- rest = ExtractToken("a;b;c", ";", &token);
- EXPECT_STREQ("a", token);
- EXPECT_STREQ("b;c", rest);
- InternalFree(token);
-
- rest = ExtractToken("aaa-bbb.ccc", ";.-*", &token);
- EXPECT_STREQ("aaa", token);
- EXPECT_STREQ("bbb.ccc", rest);
- InternalFree(token);
-}
-
-TEST(Symbolizer, ExtractInt) {
- int token;
- const char *rest = ExtractInt("123,456;789", ";,", &token);
- EXPECT_EQ(123, token);
- EXPECT_STREQ("456;789", rest);
-}
-
-TEST(Symbolizer, ExtractUptr) {
- uptr token;
- const char *rest = ExtractUptr("123,456;789", ";,", &token);
- EXPECT_EQ(123U, token);
- EXPECT_STREQ("456;789", rest);
-}
-
-TEST(Symbolizer, ExtractTokenUpToDelimiter) {
- char *token;
- const char *rest =
- ExtractTokenUpToDelimiter("aaa-+-bbb-+-ccc", "-+-", &token);
- EXPECT_STREQ("aaa", token);
- EXPECT_STREQ("bbb-+-ccc", rest);
- InternalFree(token);
-}
-
-} // namespace __sanitizer
diff --git a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_test_config.h b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_test_config.h
deleted file mode 100644
index bdf614606d6a..000000000000
--- a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_test_config.h
+++ /dev/null
@@ -1,30 +0,0 @@
-//===-- sanitizer_test_config.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 *Sanitizer runtime.
-//
-//===----------------------------------------------------------------------===//
-#if !defined(INCLUDED_FROM_SANITIZER_TEST_UTILS_H)
-# error "This file should be included into sanitizer_test_utils.h only"
-#endif
-
-#ifndef SANITIZER_TEST_CONFIG_H
-#define SANITIZER_TEST_CONFIG_H
-
-#include <vector>
-#include <string>
-#include <map>
-
-#if SANITIZER_USE_DEJAGNU_GTEST
-# include "dejagnu-gtest.h"
-#else
-# include "gtest/gtest.h"
-#endif
-
-#endif // SANITIZER_TEST_CONFIG_H
diff --git a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_test_main.cc b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_test_main.cc
deleted file mode 100644
index b7fd3dafab26..000000000000
--- a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_test_main.cc
+++ /dev/null
@@ -1,22 +0,0 @@
-//===-- sanitizer_test_main.cc --------------------------------------------===//
-//
-// 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 ThreadSanitizer/AddressSanitizer runtime.
-//
-//===----------------------------------------------------------------------===//
-#include "gtest/gtest.h"
-
-const char *argv0;
-
-int main(int argc, char **argv) {
- argv0 = argv[0];
- testing::GTEST_FLAG(death_test_style) = "threadsafe";
- testing::InitGoogleTest(&argc, argv);
- return RUN_ALL_TESTS();
-}
diff --git a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_test_utils.h b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_test_utils.h
deleted file mode 100644
index 9c162a66f547..000000000000
--- a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_test_utils.h
+++ /dev/null
@@ -1,127 +0,0 @@
-//===-- sanitizer_test_utils.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 *Sanitizer runtime.
-// Common unit tests utilities.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef SANITIZER_TEST_UTILS_H
-#define SANITIZER_TEST_UTILS_H
-
-#if defined(_WIN32)
-// <windows.h> should always be the first include on Windows.
-# include <windows.h>
-// MSVS headers define max/min as macros, so std::max/min gets crazy.
-# undef max
-# undef min
-#endif
-
-#if !defined(SANITIZER_EXTERNAL_TEST_CONFIG)
-# define INCLUDED_FROM_SANITIZER_TEST_UTILS_H
-# include "sanitizer_test_config.h"
-# undef INCLUDED_FROM_SANITIZER_TEST_UTILS_H
-#endif
-
-#include <stdint.h>
-
-#if defined(_MSC_VER)
-# define NOINLINE __declspec(noinline)
-#else // defined(_MSC_VER)
-# define NOINLINE __attribute__((noinline))
-#endif // defined(_MSC_VER)
-
-#if !defined(_MSC_VER) || defined(__clang__)
-# define UNUSED __attribute__((unused))
-# define USED __attribute__((used))
-#else
-# define UNUSED
-# define USED
-#endif
-
-#if !defined(__has_feature)
-#define __has_feature(x) 0
-#endif
-
-#ifndef ATTRIBUTE_NO_SANITIZE_ADDRESS
-# if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
-# define ATTRIBUTE_NO_SANITIZE_ADDRESS \
- __attribute__((no_sanitize_address))
-# else
-# define ATTRIBUTE_NO_SANITIZE_ADDRESS
-# endif
-#endif // ATTRIBUTE_NO_SANITIZE_ADDRESS
-
-#if __LP64__ || defined(_WIN64)
-# define SANITIZER_WORDSIZE 64
-#else
-# define SANITIZER_WORDSIZE 32
-#endif
-
-// Make the compiler thinks that something is going on there.
-inline void break_optimization(void *arg) {
-#if !defined(_WIN32) || defined(__clang__)
- __asm__ __volatile__("" : : "r" (arg) : "memory");
-#endif
-}
-
-// This function returns its parameter but in such a way that compiler
-// can not prove it.
-template<class T>
-NOINLINE
-static T Ident(T t) {
- T ret = t;
- break_optimization(&ret);
- return ret;
-}
-
-// Simple stand-alone pseudorandom number generator.
-// Current algorithm is ANSI C linear congruential PRNG.
-static inline uint32_t my_rand_r(uint32_t* state) {
- return (*state = *state * 1103515245 + 12345) >> 16;
-}
-
-static uint32_t global_seed = 0;
-
-static inline uint32_t my_rand() {
- return my_rand_r(&global_seed);
-}
-
-// Set availability of platform-specific functions.
-
-#if !defined(__APPLE__) && !defined(__ANDROID__) && !defined(_WIN32)
-# define SANITIZER_TEST_HAS_POSIX_MEMALIGN 1
-#else
-# define SANITIZER_TEST_HAS_POSIX_MEMALIGN 0
-#endif
-
-#if !defined(__APPLE__) && !defined(__FreeBSD__) && \
- !defined(__ANDROID__) && !defined(_WIN32)
-# define SANITIZER_TEST_HAS_MEMALIGN 1
-# define SANITIZER_TEST_HAS_PVALLOC 1
-# define SANITIZER_TEST_HAS_MALLOC_USABLE_SIZE 1
-#else
-# define SANITIZER_TEST_HAS_MEMALIGN 0
-# define SANITIZER_TEST_HAS_PVALLOC 0
-# define SANITIZER_TEST_HAS_MALLOC_USABLE_SIZE 0
-#endif
-
-#if !defined(__APPLE__)
-# define SANITIZER_TEST_HAS_STRNLEN 1
-#else
-# define SANITIZER_TEST_HAS_STRNLEN 0
-#endif
-
-#if defined(__FreeBSD__)
-# define SANITIZER_TEST_HAS_PRINTF_L 1
-#else
-# define SANITIZER_TEST_HAS_PRINTF_L 0
-#endif
-
-#endif // SANITIZER_TEST_UTILS_H
diff --git a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_thread_registry_test.cc b/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_thread_registry_test.cc
deleted file mode 100644
index 58c627a704ff..000000000000
--- a/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_thread_registry_test.cc
+++ /dev/null
@@ -1,232 +0,0 @@
-//===-- sanitizer_thread_registry_test.cc ---------------------------------===//
-//
-// 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 shared sanitizer runtime.
-//
-//===----------------------------------------------------------------------===//
-#include "sanitizer_common/sanitizer_thread_registry.h"
-
-#include "sanitizer_pthread_wrappers.h"
-
-#include "gtest/gtest.h"
-
-#include <vector>
-
-namespace __sanitizer {
-
-static BlockingMutex tctx_allocator_lock(LINKER_INITIALIZED);
-static LowLevelAllocator tctx_allocator;
-
-template<typename TCTX>
-static ThreadContextBase *GetThreadContext(u32 tid) {
- BlockingMutexLock l(&tctx_allocator_lock);
- return new(tctx_allocator) TCTX(tid);
-}
-
-static const u32 kMaxRegistryThreads = 1000;
-static const u32 kRegistryQuarantine = 2;
-
-static void CheckThreadQuantity(ThreadRegistry *registry, uptr exp_total,
- uptr exp_running, uptr exp_alive) {
- uptr total, running, alive;
- registry->GetNumberOfThreads(&total, &running, &alive);
- EXPECT_EQ(exp_total, total);
- EXPECT_EQ(exp_running, running);
- EXPECT_EQ(exp_alive, alive);
-}
-
-static bool is_detached(u32 tid) {
- return (tid % 2 == 0);
-}
-
-static uptr get_uid(u32 tid) {
- return tid * 2;
-}
-
-static bool HasName(ThreadContextBase *tctx, void *arg) {
- char *name = (char*)arg;
- return (0 == internal_strcmp(tctx->name, name));
-}
-
-static bool HasUid(ThreadContextBase *tctx, void *arg) {
- uptr uid = (uptr)arg;
- return (tctx->user_id == uid);
-}
-
-static void MarkUidAsPresent(ThreadContextBase *tctx, void *arg) {
- bool *arr = (bool*)arg;
- arr[tctx->tid] = true;
-}
-
-static void TestRegistry(ThreadRegistry *registry, bool has_quarantine) {
- // Create and start a main thread.
- EXPECT_EQ(0U, registry->CreateThread(get_uid(0), true, -1, 0));
- registry->StartThread(0, 0, 0);
- // Create a bunch of threads.
- for (u32 i = 1; i <= 10; i++) {
- EXPECT_EQ(i, registry->CreateThread(get_uid(i), is_detached(i), 0, 0));
- }
- CheckThreadQuantity(registry, 11, 1, 11);
- // Start some of them.
- for (u32 i = 1; i <= 5; i++) {
- registry->StartThread(i, 0, 0);
- }
- CheckThreadQuantity(registry, 11, 6, 11);
- // Finish, create and start more threads.
- for (u32 i = 1; i <= 5; i++) {
- registry->FinishThread(i);
- if (!is_detached(i))
- registry->JoinThread(i, 0);
- }
- for (u32 i = 6; i <= 10; i++) {
- registry->StartThread(i, 0, 0);
- }
- std::vector<u32> new_tids;
- for (u32 i = 11; i <= 15; i++) {
- new_tids.push_back(
- registry->CreateThread(get_uid(i), is_detached(i), 0, 0));
- }
- ASSERT_LE(kRegistryQuarantine, 5U);
- u32 exp_total = 16 - (has_quarantine ? 5 - kRegistryQuarantine : 0);
- CheckThreadQuantity(registry, exp_total, 6, 11);
- // Test SetThreadName and FindThread.
- registry->SetThreadName(6, "six");
- registry->SetThreadName(7, "seven");
- EXPECT_EQ(7U, registry->FindThread(HasName, (void*)"seven"));
- EXPECT_EQ(ThreadRegistry::kUnknownTid,
- registry->FindThread(HasName, (void*)"none"));
- EXPECT_EQ(0U, registry->FindThread(HasUid, (void*)get_uid(0)));
- EXPECT_EQ(10U, registry->FindThread(HasUid, (void*)get_uid(10)));
- EXPECT_EQ(ThreadRegistry::kUnknownTid,
- registry->FindThread(HasUid, (void*)0x1234));
- // Detach and finish and join remaining threads.
- for (u32 i = 6; i <= 10; i++) {
- registry->DetachThread(i, 0);
- registry->FinishThread(i);
- }
- for (u32 i = 0; i < new_tids.size(); i++) {
- u32 tid = new_tids[i];
- registry->StartThread(tid, 0, 0);
- registry->DetachThread(tid, 0);
- registry->FinishThread(tid);
- }
- CheckThreadQuantity(registry, exp_total, 1, 1);
- // Test methods that require the caller to hold a ThreadRegistryLock.
- bool has_tid[16];
- internal_memset(&has_tid[0], 0, sizeof(has_tid));
- {
- ThreadRegistryLock l(registry);
- registry->RunCallbackForEachThreadLocked(MarkUidAsPresent, &has_tid[0]);
- }
- for (u32 i = 0; i < exp_total; i++) {
- EXPECT_TRUE(has_tid[i]);
- }
- {
- ThreadRegistryLock l(registry);
- registry->CheckLocked();
- ThreadContextBase *main_thread = registry->GetThreadLocked(0);
- EXPECT_EQ(main_thread, registry->FindThreadContextLocked(
- HasUid, (void*)get_uid(0)));
- }
- EXPECT_EQ(11U, registry->GetMaxAliveThreads());
-}
-
-TEST(SanitizerCommon, ThreadRegistryTest) {
- ThreadRegistry quarantine_registry(GetThreadContext<ThreadContextBase>,
- kMaxRegistryThreads,
- kRegistryQuarantine);
- TestRegistry(&quarantine_registry, true);
-
- ThreadRegistry no_quarantine_registry(GetThreadContext<ThreadContextBase>,
- kMaxRegistryThreads,
- kMaxRegistryThreads);
- TestRegistry(&no_quarantine_registry, false);
-}
-
-static const int kThreadsPerShard = 20;
-static const int kNumShards = 25;
-
-static int num_created[kNumShards + 1];
-static int num_started[kNumShards + 1];
-static int num_joined[kNumShards + 1];
-
-namespace {
-
-struct RunThreadArgs {
- ThreadRegistry *registry;
- uptr shard; // started from 1.
-};
-
-class TestThreadContext : public ThreadContextBase {
- public:
- explicit TestThreadContext(int tid) : ThreadContextBase(tid) {}
- void OnJoined(void *arg) {
- uptr shard = (uptr)arg;
- num_joined[shard]++;
- }
- void OnStarted(void *arg) {
- uptr shard = (uptr)arg;
- num_started[shard]++;
- }
- void OnCreated(void *arg) {
- uptr shard = (uptr)arg;
- num_created[shard]++;
- }
-};
-
-} // namespace
-
-void *RunThread(void *arg) {
- RunThreadArgs *args = static_cast<RunThreadArgs*>(arg);
- std::vector<int> tids;
- for (int i = 0; i < kThreadsPerShard; i++)
- tids.push_back(
- args->registry->CreateThread(0, false, 0, (void*)args->shard));
- for (int i = 0; i < kThreadsPerShard; i++)
- args->registry->StartThread(tids[i], 0, (void*)args->shard);
- for (int i = 0; i < kThreadsPerShard; i++)
- args->registry->FinishThread(tids[i]);
- for (int i = 0; i < kThreadsPerShard; i++)
- args->registry->JoinThread(tids[i], (void*)args->shard);
- return 0;
-}
-
-static void ThreadedTestRegistry(ThreadRegistry *registry) {
- // Create and start a main thread.
- EXPECT_EQ(0U, registry->CreateThread(0, true, -1, 0));
- registry->StartThread(0, 0, 0);
- pthread_t threads[kNumShards];
- RunThreadArgs args[kNumShards];
- for (int i = 0; i < kNumShards; i++) {
- args[i].registry = registry;
- args[i].shard = i + 1;
- PTHREAD_CREATE(&threads[i], 0, RunThread, &args[i]);
- }
- for (int i = 0; i < kNumShards; i++) {
- PTHREAD_JOIN(threads[i], 0);
- }
- // Check that each thread created/started/joined correct amount
- // of "threads" in thread_registry.
- EXPECT_EQ(1, num_created[0]);
- EXPECT_EQ(1, num_started[0]);
- EXPECT_EQ(0, num_joined[0]);
- for (int i = 1; i <= kNumShards; i++) {
- EXPECT_EQ(kThreadsPerShard, num_created[i]);
- EXPECT_EQ(kThreadsPerShard, num_started[i]);
- EXPECT_EQ(kThreadsPerShard, num_joined[i]);
- }
-}
-
-TEST(SanitizerCommon, ThreadRegistryThreadedTest) {
- ThreadRegistry registry(GetThreadContext<TestThreadContext>,
- kThreadsPerShard * kNumShards + 1, 10);
- ThreadedTestRegistry(&registry);
-}
-
-} // namespace __sanitizer
diff --git a/contrib/compiler-rt/lib/sanitizer_common/tests/standalone_malloc_test.cc b/contrib/compiler-rt/lib/sanitizer_common/tests/standalone_malloc_test.cc
deleted file mode 100644
index 9e6f7c93b04b..000000000000
--- a/contrib/compiler-rt/lib/sanitizer_common/tests/standalone_malloc_test.cc
+++ /dev/null
@@ -1,87 +0,0 @@
-#include <stdio.h>
-#include <vector>
-#include <pthread.h>
-#include <malloc.h>
-#include <algorithm>
-
-using namespace std;
-
-const size_t kNumThreds = 16;
-const size_t kNumIters = 1 << 23;
-
-inline void break_optimization(void *arg) {
- __asm__ __volatile__("" : : "r" (arg) : "memory");
-}
-
-__attribute__((noinline))
-static void *MallocThread(void *t) {
- size_t total_malloced = 0, total_freed = 0;
- size_t max_in_use = 0;
- size_t tid = reinterpret_cast<size_t>(t);
- vector<pair<char *, size_t> > allocated;
- allocated.reserve(kNumIters);
- for (size_t i = 1; i < kNumIters; i++) {
- if ((i % (kNumIters / 4)) == 0 && tid == 0)
- fprintf(stderr, " T[%ld] iter %ld\n", tid, i);
- bool allocate = (i % 5) <= 2; // 60% malloc, 40% free
- if (i > kNumIters / 4)
- allocate = i % 2; // then switch to 50% malloc, 50% free
- if (allocate) {
- size_t size = 1 + (i % 200);
- if ((i % 10001) == 0)
- size *= 4096;
- total_malloced += size;
- char *x = new char[size];
- x[0] = x[size - 1] = x[size / 2] = 0;
- allocated.push_back(make_pair(x, size));
- max_in_use = max(max_in_use, total_malloced - total_freed);
- } else {
- if (allocated.empty()) continue;
- size_t slot = i % allocated.size();
- char *p = allocated[slot].first;
- p[0] = 0; // emulate last user touch of the block
- size_t size = allocated[slot].second;
- total_freed += size;
- swap(allocated[slot], allocated.back());
- allocated.pop_back();
- delete [] p;
- }
- }
- if (tid == 0)
- fprintf(stderr, " T[%ld] total_malloced: %ldM in use %ldM max %ldM\n",
- tid, total_malloced >> 20, (total_malloced - total_freed) >> 20,
- max_in_use >> 20);
- for (size_t i = 0; i < allocated.size(); i++)
- delete [] allocated[i].first;
- return 0;
-}
-
-template <int depth>
-struct DeepStack {
- __attribute__((noinline))
- static void *run(void *t) {
- break_optimization(0);
- DeepStack<depth - 1>::run(t);
- break_optimization(0);
- return 0;
- }
-};
-
-template<>
-struct DeepStack<0> {
- static void *run(void *t) {
- MallocThread(t);
- return 0;
- }
-};
-
-// Build with -Dstandalone_malloc_test=main to make it a separate program.
-int standalone_malloc_test() {
- pthread_t t[kNumThreds];
- for (size_t i = 0; i < kNumThreds; i++)
- pthread_create(&t[i], 0, DeepStack<200>::run, reinterpret_cast<void *>(i));
- for (size_t i = 0; i < kNumThreds; i++)
- pthread_join(t[i], 0);
- malloc_stats();
- return 0;
-}
diff --git a/contrib/compiler-rt/lib/tsan/analyze_libtsan.sh b/contrib/compiler-rt/lib/tsan/analyze_libtsan.sh
deleted file mode 100755
index 705e4c5460f2..000000000000
--- a/contrib/compiler-rt/lib/tsan/analyze_libtsan.sh
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/bin/bash
-
-set -e
-set -u
-
-get_asm() {
- grep __tsan_$1.: -A 10000 libtsan.objdump | \
- awk "/[^:]$/ {print;} />:/ {c++; if (c == 2) {exit}}"
-}
-
-list="write1 \
- write2 \
- write4 \
- write8 \
- read1 \
- read2 \
- read4 \
- read8 \
- func_entry \
- func_exit"
-
-BIN=`dirname $0`/tsan_test
-objdump -d $BIN > libtsan.objdump
-nm -S $BIN | grep "__tsan_" > libtsan.nm
-
-for f in $list; do
- file=asm_$f.s
- get_asm $f > $file
- tot=$(wc -l < $file)
- size=$(grep __tsan_$f$ libtsan.nm | awk --non-decimal-data '{print ("0x"$2)+0}')
- rsp=$(grep '(%rsp)' $file | wc -l)
- push=$(grep 'push' $file | wc -l)
- pop=$(grep 'pop' $file | wc -l)
- call=$(grep 'call' $file | wc -l)
- load=$(egrep 'mov .*\,.*\(.*\)|cmp .*\,.*\(.*\)' $file | wc -l)
- store=$(egrep 'mov .*\(.*\),' $file | wc -l)
- mov=$(grep 'mov' $file | wc -l)
- lea=$(grep 'lea' $file | wc -l)
- sh=$(grep 'shr\|shl' $file | wc -l)
- cmp=$(grep 'cmp\|test' $file | wc -l)
- printf "%10s tot %3d; size %4d; rsp %d; push %d; pop %d; call %d; load %2d; store %2d; sh %3d; mov %3d; lea %3d; cmp %3d\n" \
- $f $tot $size $rsp $push $pop $call $load $store $sh $mov $lea $cmp;
-done
diff --git a/contrib/compiler-rt/lib/tsan/check_analyze.sh b/contrib/compiler-rt/lib/tsan/check_analyze.sh
deleted file mode 100755
index 4b33393ef648..000000000000
--- a/contrib/compiler-rt/lib/tsan/check_analyze.sh
+++ /dev/null
@@ -1,44 +0,0 @@
-#!/bin/bash
-set -u
-
-RES=$(./analyze_libtsan.sh)
-PrintRes() {
- printf "%s\n" "$RES"
-}
-
-PrintRes
-
-check() {
- res=$(PrintRes | egrep "$1 .* $2 $3; ")
- if [ "$res" == "" ]; then
- echo FAILED $1 must contain $2 $3
- exit 1
- fi
-}
-
-for f in write1; do
- check $f rsp 1
- check $f push 2
- check $f pop 2
-done
-
-for f in write2 write4 write8; do
- check $f rsp 1
- check $f push 3
- check $f pop 3
-done
-
-for f in read1 read2 read4 read8; do
- check $f rsp 1
- check $f push 5
- check $f pop 5
-done
-
-for f in func_entry func_exit; do
- check $f rsp 0
- check $f push 0
- check $f pop 0
- check $f call 1 # TraceSwitch()
-done
-
-echo LGTM
diff --git a/contrib/compiler-rt/lib/tsan/check_cmake.sh b/contrib/compiler-rt/lib/tsan/check_cmake.sh
deleted file mode 100755
index 7668c5b49e1a..000000000000
--- a/contrib/compiler-rt/lib/tsan/check_cmake.sh
+++ /dev/null
@@ -1,18 +0,0 @@
-#!/bin/bash
-set -u
-set -e
-
-ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
-if [ -d "$ROOT/llvm-build" ]; then
- cd $ROOT/llvm-build
-else
- mkdir -p $ROOT/llvm-build
- cd $ROOT/llvm-build
- CC=clang CXX=clang++ cmake -G Ninja -DLLVM_ENABLE_WERROR=ON -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_ASSERTIONS=ON $ROOT/../../../..
-fi
-ninja
-ninja check-sanitizer
-ninja check-tsan
-ninja check-asan
-ninja check-msan
-ninja check-lsan
diff --git a/contrib/compiler-rt/lib/tsan/check_memcpy.sh b/contrib/compiler-rt/lib/tsan/check_memcpy.sh
deleted file mode 100755
index 101df1166b7c..000000000000
--- a/contrib/compiler-rt/lib/tsan/check_memcpy.sh
+++ /dev/null
@@ -1,31 +0,0 @@
-#!/bin/bash
-
-# Ensure that tsan runtime does not contain compiler-emitted memcpy and memset calls.
-
-set -eu
-
-ROOTDIR=$(dirname $0)
-TEST_DIR=$ROOTDIR/../../test/tsan
-
-: ${CXX:=clang++}
-CFLAGS="-fsanitize=thread -fPIE -O1 -g"
-LDFLAGS="-pie -lpthread -ldl -lrt -lm -Wl,--whole-archive $ROOTDIR/rtl/libtsan.a -Wl,--no-whole-archive"
-
-SRC=$TEST_DIR/simple_race.cc
-OBJ=$SRC.o
-EXE=$SRC.exe
-$CXX $SRC $CFLAGS -c -o $OBJ
-$CXX $OBJ $LDFLAGS -o $EXE
-
-NCALL=$(objdump -d $EXE | egrep "callq .*<__interceptor_mem(cpy|set)>" | wc -l)
-if [ "$NCALL" != "0" ]; then
- echo FAIL: found $NCALL memcpy/memset calls
- exit 1
-fi
-
-# tail calls
-NCALL=$(objdump -d $EXE | egrep "jmpq .*<__interceptor_mem(cpy|set)>" | wc -l)
-if [ "$NCALL" != "0" ]; then
- echo FAIL: found $NCALL memcpy/memset calls
- exit 1
-fi
diff --git a/contrib/compiler-rt/lib/tsan/go/build.bat b/contrib/compiler-rt/lib/tsan/go/build.bat
deleted file mode 100644
index 7d393dc0e025..000000000000
--- a/contrib/compiler-rt/lib/tsan/go/build.bat
+++ /dev/null
@@ -1,4 +0,0 @@
-type tsan_go.cc ..\rtl\tsan_interface_atomic.cc ..\rtl\tsan_clock.cc ..\rtl\tsan_flags.cc ..\rtl\tsan_md5.cc ..\rtl\tsan_mutex.cc ..\rtl\tsan_report.cc ..\rtl\tsan_rtl.cc ..\rtl\tsan_rtl_mutex.cc ..\rtl\tsan_rtl_report.cc ..\rtl\tsan_rtl_thread.cc ..\rtl\tsan_stat.cc ..\rtl\tsan_suppressions.cc ..\rtl\tsan_sync.cc ..\rtl\tsan_stack_trace.cc ..\..\sanitizer_common\sanitizer_allocator.cc ..\..\sanitizer_common\sanitizer_common.cc ..\..\sanitizer_common\sanitizer_flags.cc ..\..\sanitizer_common\sanitizer_stacktrace.cc ..\..\sanitizer_common\sanitizer_libc.cc ..\..\sanitizer_common\sanitizer_printf.cc ..\..\sanitizer_common\sanitizer_suppressions.cc ..\..\sanitizer_common\sanitizer_thread_registry.cc ..\rtl\tsan_platform_windows.cc ..\..\sanitizer_common\sanitizer_win.cc ..\..\sanitizer_common\sanitizer_deadlock_detector1.cc ..\..\sanitizer_common\sanitizer_stackdepot.cc ..\..\sanitizer_common\sanitizer_persistent_allocator.cc ..\..\sanitizer_common\sanitizer_flag_parser.cc ..\..\sanitizer_common\sanitizer_symbolizer.cc > gotsan.cc
-
-gcc -c -o race_windows_amd64.syso gotsan.cc -I..\rtl -I..\.. -I..\..\sanitizer_common -I..\..\..\include -m64 -Wall -fno-exceptions -fno-rtti -DSANITIZER_GO -Wno-error=attributes -Wno-attributes -Wno-format -Wno-maybe-uninitialized -DSANITIZER_DEBUG=0 -O3 -fomit-frame-pointer -std=c++11
-
diff --git a/contrib/compiler-rt/lib/tsan/go/buildgo.sh b/contrib/compiler-rt/lib/tsan/go/buildgo.sh
deleted file mode 100755
index 7193b57684f2..000000000000
--- a/contrib/compiler-rt/lib/tsan/go/buildgo.sh
+++ /dev/null
@@ -1,130 +0,0 @@
-#!/bin/sh
-
-set -e
-
-SRCS="
- tsan_go.cc
- ../rtl/tsan_clock.cc
- ../rtl/tsan_flags.cc
- ../rtl/tsan_interface_atomic.cc
- ../rtl/tsan_md5.cc
- ../rtl/tsan_mutex.cc
- ../rtl/tsan_report.cc
- ../rtl/tsan_rtl.cc
- ../rtl/tsan_rtl_mutex.cc
- ../rtl/tsan_rtl_report.cc
- ../rtl/tsan_rtl_thread.cc
- ../rtl/tsan_stack_trace.cc
- ../rtl/tsan_stat.cc
- ../rtl/tsan_suppressions.cc
- ../rtl/tsan_sync.cc
- ../../sanitizer_common/sanitizer_allocator.cc
- ../../sanitizer_common/sanitizer_common.cc
- ../../sanitizer_common/sanitizer_deadlock_detector2.cc
- ../../sanitizer_common/sanitizer_flag_parser.cc
- ../../sanitizer_common/sanitizer_flags.cc
- ../../sanitizer_common/sanitizer_libc.cc
- ../../sanitizer_common/sanitizer_persistent_allocator.cc
- ../../sanitizer_common/sanitizer_printf.cc
- ../../sanitizer_common/sanitizer_suppressions.cc
- ../../sanitizer_common/sanitizer_thread_registry.cc
- ../../sanitizer_common/sanitizer_stackdepot.cc
- ../../sanitizer_common/sanitizer_stacktrace.cc
- ../../sanitizer_common/sanitizer_symbolizer.cc
-"
-
-if [ "`uname -a | grep Linux`" != "" ]; then
- SUFFIX="linux_amd64"
- OSCFLAGS="-fPIC -ffreestanding -Wno-maybe-uninitialized -Wno-unused-const-variable -Werror -Wno-unknown-warning-option"
- OSLDFLAGS="-lpthread -lrt -fPIC -fpie"
- SRCS="
- $SRCS
- ../rtl/tsan_platform_linux.cc
- ../../sanitizer_common/sanitizer_posix.cc
- ../../sanitizer_common/sanitizer_posix_libcdep.cc
- ../../sanitizer_common/sanitizer_procmaps_common.cc
- ../../sanitizer_common/sanitizer_procmaps_linux.cc
- ../../sanitizer_common/sanitizer_linux.cc
- ../../sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
- "
-elif [ "`uname -a | grep FreeBSD`" != "" ]; then
- SUFFIX="freebsd_amd64"
- OSCFLAGS="-fno-strict-aliasing -fPIC -Werror"
- OSLDFLAGS="-lpthread -fPIC -fpie"
- SRCS="
- $SRCS
- ../rtl/tsan_platform_linux.cc
- ../../sanitizer_common/sanitizer_posix.cc
- ../../sanitizer_common/sanitizer_posix_libcdep.cc
- ../../sanitizer_common/sanitizer_procmaps_common.cc
- ../../sanitizer_common/sanitizer_procmaps_freebsd.cc
- ../../sanitizer_common/sanitizer_linux.cc
- ../../sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
- "
-elif [ "`uname -a | grep Darwin`" != "" ]; then
- SUFFIX="darwin_amd64"
- OSCFLAGS="-fPIC -Wno-unused-const-variable -Wno-unknown-warning-option"
- OSLDFLAGS="-lpthread -fPIC -fpie"
- SRCS="
- $SRCS
- ../rtl/tsan_platform_mac.cc
- ../../sanitizer_common/sanitizer_mac.cc
- ../../sanitizer_common/sanitizer_posix.cc
- ../../sanitizer_common/sanitizer_posix_libcdep.cc
- ../../sanitizer_common/sanitizer_procmaps_mac.cc
- "
-elif [ "`uname -a | grep MINGW`" != "" ]; then
- SUFFIX="windows_amd64"
- OSCFLAGS="-Wno-error=attributes -Wno-attributes -Wno-unused-const-variable -Wno-unknown-warning-option"
- OSLDFLAGS=""
- SRCS="
- $SRCS
- ../rtl/tsan_platform_windows.cc
- ../../sanitizer_common/sanitizer_win.cc
- "
-else
- echo Unknown platform
- exit 1
-fi
-
-CC=${CC:-gcc}
-IN_TMPDIR=${IN_TMPDIR:-0}
-SILENT=${SILENT:-0}
-
-if [ $IN_TMPDIR != "0" ]; then
- DIR=$(mktemp -qd /tmp/gotsan.XXXXXXXXXX)
- cleanup() {
- rm -rf $DIR
- }
- trap cleanup EXIT
-else
- DIR=.
-fi
-
-SRCS="$SRCS $ADD_SRCS"
-
-rm -f $DIR/gotsan.cc
-for F in $SRCS; do
- cat $F >> $DIR/gotsan.cc
-done
-
-FLAGS=" -I../rtl -I../.. -I../../sanitizer_common -I../../../include -std=c++11 -m64 -Wall -fno-exceptions -fno-rtti -DSANITIZER_GO -DSANITIZER_DEADLOCK_DETECTOR_VERSION=2 $OSCFLAGS"
-if [ "$DEBUG" = "" ]; then
- FLAGS="$FLAGS -DSANITIZER_DEBUG=0 -O3 -msse3 -fomit-frame-pointer"
-else
- FLAGS="$FLAGS -DSANITIZER_DEBUG=1 -g"
-fi
-
-if [ "$SILENT" != "1" ]; then
- echo $CC gotsan.cc -c -o $DIR/race_$SUFFIX.syso $FLAGS $CFLAGS
-fi
-$CC $DIR/gotsan.cc -c -o $DIR/race_$SUFFIX.syso $FLAGS $CFLAGS
-
-$CC test.c $DIR/race_$SUFFIX.syso -m64 -o $DIR/test $OSLDFLAGS
-
-export GORACE="exitcode=0 atexit_sleep_ms=0"
-if [ "$SILENT" != "1" ]; then
- $DIR/test
-else
- $DIR/test 2>/dev/null
-fi
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_clock.cc b/contrib/compiler-rt/lib/tsan/rtl/tsan_clock.cc
index 59e3de435f1b..1e2050d1f203 100644
--- a/contrib/compiler-rt/lib/tsan/rtl/tsan_clock.cc
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_clock.cc
@@ -90,8 +90,6 @@
namespace __tsan {
-const unsigned kInvalidTid = (unsigned)-1;
-
ThreadClock::ThreadClock(unsigned tid, unsigned reused)
: tid_(tid)
, reused_(reused + 1) { // 0 has special meaning
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_defs.h b/contrib/compiler-rt/lib/tsan/rtl/tsan_defs.h
index d869d95e0878..9c7b329dcf00 100644
--- a/contrib/compiler-rt/lib/tsan/rtl/tsan_defs.h
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_defs.h
@@ -38,13 +38,10 @@ namespace __tsan {
const bool kGoMode = true;
const bool kCppMode = false;
const char *const kTsanOptionsEnv = "GORACE";
-// Go linker does not support weak symbols.
-#define CPP_WEAK
#else
const bool kGoMode = false;
const bool kCppMode = true;
const char *const kTsanOptionsEnv = "TSAN_OPTIONS";
-#define CPP_WEAK WEAK
#endif
const int kTidBits = 13;
@@ -83,6 +80,8 @@ const bool kCollectHistory = false;
const bool kCollectHistory = true;
#endif
+const unsigned kInvalidTid = (unsigned)-1;
+
// The following "build consistency" machinery ensures that all source files
// are built in the same configuration. Inconsistent builds lead to
// hard to debug crashes.
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_dense_alloc.h b/contrib/compiler-rt/lib/tsan/rtl/tsan_dense_alloc.h
index a1cf84b8f166..e9815c90a953 100644
--- a/contrib/compiler-rt/lib/tsan/rtl/tsan_dense_alloc.h
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_dense_alloc.h
@@ -108,7 +108,7 @@ class DenseSlabAlloc {
// Reserve 0 as invalid index.
IndexT start = fillpos_ == 0 ? 1 : 0;
for (IndexT i = start; i < kL2Size; i++) {
- new(batch + i) T();
+ new(batch + i) T;
*(IndexT*)(batch + i) = i + 1 + fillpos_ * kL2Size;
}
*(IndexT*)(batch + kL2Size - 1) = 0;
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_flags.cc b/contrib/compiler-rt/lib/tsan/rtl/tsan_flags.cc
index 5de227a42dee..761523171c77 100644
--- a/contrib/compiler-rt/lib/tsan/rtl/tsan_flags.cc
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_flags.cc
@@ -29,8 +29,8 @@ Flags *flags() {
#ifdef TSAN_EXTERNAL_HOOKS
extern "C" const char* __tsan_default_options();
#else
-extern "C" SANITIZER_INTERFACE_ATTRIBUTE
-const char *WEAK __tsan_default_options() {
+SANITIZER_WEAK_DEFAULT_IMPL
+const char *__tsan_default_options() {
return "";
}
#endif
@@ -61,11 +61,16 @@ void InitializeFlags(Flags *f, const char *env) {
CommonFlags cf;
cf.CopyFrom(*common_flags());
cf.allow_addr2line = true;
-#ifndef SANITIZER_GO
- cf.detect_deadlocks = true;
-#endif
+ if (kGoMode) {
+ // Does not work as expected for Go: runtime handles SIGABRT and crashes.
+ cf.abort_on_error = false;
+ // Go does not have mutexes.
+ } else {
+ cf.detect_deadlocks = true;
+ }
cf.print_suppressions = false;
cf.stack_trace_format = " #%n %f %S %M";
+ cf.exitcode = 66;
OverrideCommonFlags(cf);
}
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_flags.inc b/contrib/compiler-rt/lib/tsan/rtl/tsan_flags.inc
index e4994685fa0d..ab9ca9924936 100644
--- a/contrib/compiler-rt/lib/tsan/rtl/tsan_flags.inc
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_flags.inc
@@ -45,7 +45,6 @@ TSAN_FLAG(
"If set, all atomics are effectively sequentially consistent (seq_cst), "
"regardless of what user actually specified.")
TSAN_FLAG(bool, print_benign, false, "Print matched \"benign\" races at exit.")
-TSAN_FLAG(int, exitcode, 66, "Override exit status if something was reported.")
TSAN_FLAG(bool, halt_on_error, false, "Exit after first reported error.")
TSAN_FLAG(int, atexit_sleep_ms, 1000,
"Sleep in main thread before exiting for that many ms "
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc b/contrib/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc
index b1a7ae6de328..7c835c6dc7df 100644
--- a/contrib/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc
@@ -28,16 +28,42 @@
#include "tsan_mman.h"
#include "tsan_fd.h"
+#if SANITIZER_POSIX
+#include "sanitizer_common/sanitizer_posix.h"
+#endif
+
using namespace __tsan; // NOLINT
-#if SANITIZER_FREEBSD
+#if SANITIZER_FREEBSD || SANITIZER_MAC
#define __errno_location __error
-#define __libc_realloc __realloc
-#define __libc_calloc __calloc
#define stdout __stdoutp
#define stderr __stderrp
#endif
+#if SANITIZER_FREEBSD
+#define __libc_realloc __realloc
+#define __libc_calloc __calloc
+#elif SANITIZER_MAC
+#define __libc_malloc REAL(malloc)
+#define __libc_realloc REAL(realloc)
+#define __libc_calloc REAL(calloc)
+#define __libc_free REAL(free)
+#elif SANITIZER_ANDROID
+#define __errno_location __errno
+#define __libc_malloc REAL(malloc)
+#define __libc_realloc REAL(realloc)
+#define __libc_calloc REAL(calloc)
+#define __libc_free REAL(free)
+#define mallopt(a, b)
+#endif
+
+#if SANITIZER_LINUX || SANITIZER_FREEBSD
+#define PTHREAD_CREATE_DETACHED 1
+#elif SANITIZER_MAC
+#define PTHREAD_CREATE_DETACHED 2
+#endif
+
+
#ifdef __mips__
const int kSigCount = 129;
#else
@@ -60,6 +86,14 @@ struct ucontext_t {
};
#endif
+#if defined(__x86_64__) || defined(__mips__) \
+ || (defined(__powerpc64__) && defined(__BIG_ENDIAN__))
+#define PTHREAD_ABI_BASE "GLIBC_2.3.2"
+#elif defined(__aarch64__) || (defined(__powerpc64__) \
+ && defined(__LITTLE_ENDIAN__))
+#define PTHREAD_ABI_BASE "GLIBC_2.17"
+#endif
+
extern "C" int pthread_attr_init(void *attr);
extern "C" int pthread_attr_destroy(void *attr);
DECLARE_REAL(int, pthread_attr_getdetachstate, void *, void *)
@@ -67,20 +101,23 @@ extern "C" int pthread_attr_setstacksize(void *attr, uptr stacksize);
extern "C" int pthread_key_create(unsigned *key, void (*destructor)(void* v));
extern "C" int pthread_setspecific(unsigned key, const void *v);
DECLARE_REAL(int, pthread_mutexattr_gettype, void *, void *)
-extern "C" int pthread_yield();
extern "C" int pthread_sigmask(int how, const __sanitizer_sigset_t *set,
__sanitizer_sigset_t *oldset);
// REAL(sigfillset) defined in common interceptors.
DECLARE_REAL(int, sigfillset, __sanitizer_sigset_t *set)
DECLARE_REAL(int, fflush, __sanitizer_FILE *fp)
+DECLARE_REAL_AND_INTERCEPTOR(void *, malloc, uptr size)
+DECLARE_REAL_AND_INTERCEPTOR(void, free, void *ptr)
extern "C" void *pthread_self();
extern "C" void _exit(int status);
extern "C" int *__errno_location();
extern "C" int fileno_unlocked(void *stream);
+#if !SANITIZER_ANDROID
extern "C" void *__libc_calloc(uptr size, uptr n);
extern "C" void *__libc_realloc(void *ptr, uptr size);
+#endif
extern "C" int dirfd(void *dirp);
-#if !SANITIZER_FREEBSD
+#if !SANITIZER_FREEBSD && !SANITIZER_ANDROID
extern "C" int mallopt(int param, int value);
#endif
extern __sanitizer_FILE *stdout, *stderr;
@@ -89,14 +126,16 @@ const int PTHREAD_MUTEX_RECURSIVE_NP = 1;
const int EINVAL = 22;
const int EBUSY = 16;
const int EOWNERDEAD = 130;
+#if !SANITIZER_MAC
const int EPOLL_CTL_ADD = 1;
+#endif
const int SIGILL = 4;
const int SIGABRT = 6;
const int SIGFPE = 8;
const int SIGSEGV = 11;
const int SIGPIPE = 13;
const int SIGTERM = 15;
-#ifdef __mips__
+#if defined(__mips__) || SANITIZER_MAC
const int SIGBUS = 10;
const int SIGSYS = 12;
#else
@@ -104,7 +143,9 @@ const int SIGBUS = 7;
const int SIGSYS = 31;
#endif
void *const MAP_FAILED = (void*)-1;
+#if !SANITIZER_MAC
const int PTHREAD_BARRIER_SERIAL_THREAD = -1;
+#endif
const int MAP_FIXED = 0x10;
typedef long long_t; // NOLINT
@@ -119,6 +160,17 @@ typedef long long_t; // NOLINT
typedef void (*sighandler_t)(int sig);
typedef void (*sigactionhandler_t)(int sig, my_siginfo_t *siginfo, void *uctx);
+#if SANITIZER_ANDROID
+struct sigaction_t {
+ u32 sa_flags;
+ union {
+ sighandler_t sa_handler;
+ sigactionhandler_t sa_sgiaction;
+ };
+ __sanitizer_sigset_t sa_mask;
+ void (*sa_restorer)();
+};
+#else
struct sigaction_t {
#ifdef __mips__
u32 sa_flags;
@@ -130,6 +182,9 @@ struct sigaction_t {
#if SANITIZER_FREEBSD
int sa_flags;
__sanitizer_sigset_t sa_mask;
+#elif SANITIZER_MAC
+ __sanitizer_sigset_t sa_mask;
+ int sa_flags;
#else
__sanitizer_sigset_t sa_mask;
#ifndef __mips__
@@ -138,11 +193,12 @@ struct sigaction_t {
void (*sa_restorer)();
#endif
};
+#endif
const sighandler_t SIG_DFL = (sighandler_t)0;
const sighandler_t SIG_IGN = (sighandler_t)1;
const sighandler_t SIG_ERR = (sighandler_t)-1;
-#if SANITIZER_FREEBSD
+#if SANITIZER_FREEBSD || SANITIZER_MAC
const int SA_SIGINFO = 0x40;
const int SIG_SETMASK = 3;
#elif defined(__mips__)
@@ -171,6 +227,9 @@ struct ThreadSignalContext {
atomic_uintptr_t in_blocking_func;
atomic_uintptr_t have_pending_signals;
SignalDesc pending_signals[kSigCount];
+ // emptyset and oldset are too big for stack.
+ __sanitizer_sigset_t emptyset;
+ __sanitizer_sigset_t oldset;
};
// The object is 64-byte aligned, because we want hot data to be located in
@@ -203,7 +262,9 @@ static ThreadSignalContext *SigCtx(ThreadState *thr) {
return ctx;
}
+#if !SANITIZER_MAC
static unsigned g_thread_finalize_key;
+#endif
ScopedInterceptor::ScopedInterceptor(ThreadState *thr, const char *fname,
uptr pc)
@@ -234,17 +295,20 @@ ScopedInterceptor::~ScopedInterceptor() {
}
}
-#define SCOPED_TSAN_INTERCEPTOR(func, ...) \
- SCOPED_INTERCEPTOR_RAW(func, __VA_ARGS__); \
- if (REAL(func) == 0) { \
- Report("FATAL: ThreadSanitizer: failed to intercept %s\n", #func); \
- Die(); \
- } \
- if (thr->ignore_interceptors || thr->in_ignored_lib) \
- return REAL(func)(__VA_ARGS__); \
-/**/
+void ScopedInterceptor::UserCallbackStart() {
+ if (in_ignored_lib_) {
+ thr_->in_ignored_lib = false;
+ ThreadIgnoreEnd(thr_, pc_);
+ }
+}
+
+void ScopedInterceptor::UserCallbackEnd() {
+ if (in_ignored_lib_) {
+ thr_->in_ignored_lib = true;
+ ThreadIgnoreBegin(thr_, pc_);
+ }
+}
-#define TSAN_INTERCEPTOR(ret, func, ...) INTERCEPTOR(ret, func, __VA_ARGS__)
#define TSAN_INTERCEPT(func) INTERCEPT_FUNCTION(func)
#if SANITIZER_FREEBSD
# define TSAN_INTERCEPT_VER(func, ver) INTERCEPT_FUNCTION(func)
@@ -329,6 +393,7 @@ static void at_exit_wrapper(void *arg) {
static int setup_at_exit_wrapper(ThreadState *thr, uptr pc, void(*f)(),
void *arg, void *dso);
+#if !SANITIZER_ANDROID
TSAN_INTERCEPTOR(int, atexit, void (*f)()) {
if (cur_thread()->in_symbolizer)
return 0;
@@ -337,6 +402,7 @@ TSAN_INTERCEPTOR(int, atexit, void (*f)()) {
SCOPED_INTERCEPTOR_RAW(atexit, f);
return setup_at_exit_wrapper(thr, pc, (void(*)())f, 0, 0);
}
+#endif
TSAN_INTERCEPTOR(int, __cxa_atexit, void (*f)(void *a), void *arg, void *dso) {
if (cur_thread()->in_symbolizer)
@@ -359,6 +425,7 @@ static int setup_at_exit_wrapper(ThreadState *thr, uptr pc, void(*f)(),
return res;
}
+#if !SANITIZER_MAC
static void on_exit_wrapper(int status, void *arg) {
ThreadState *thr = cur_thread();
uptr pc = 0;
@@ -383,6 +450,7 @@ TSAN_INTERCEPTOR(int, on_exit, void(*f)(int, void*), void *arg) {
ThreadIgnoreEnd(thr, pc);
return res;
}
+#endif
// Cleanup old bufs.
static void JmpBufGarbageCollect(ThreadState *thr, uptr sp) {
@@ -390,7 +458,7 @@ static void JmpBufGarbageCollect(ThreadState *thr, uptr sp) {
JmpBuf *buf = &thr->jmp_bufs[i];
if (buf->sp <= sp) {
uptr sz = thr->jmp_bufs.Size();
- thr->jmp_bufs[i] = thr->jmp_bufs[sz - 1];
+ internal_memcpy(buf, &thr->jmp_bufs[sz - 1], sizeof(*buf));
thr->jmp_bufs.PopBack();
i--;
}
@@ -417,11 +485,17 @@ static void SetJmp(ThreadState *thr, uptr sp, uptr mangled_sp) {
}
static void LongJmp(ThreadState *thr, uptr *env) {
-#if SANITIZER_FREEBSD
+#ifdef __powerpc__
+ uptr mangled_sp = env[0];
+#elif SANITIZER_FREEBSD || SANITIZER_MAC
uptr mangled_sp = env[2];
-#else
+#elif defined(SANITIZER_LINUX)
+# ifdef __aarch64__
+ uptr mangled_sp = env[13];
+# else
uptr mangled_sp = env[6];
-#endif // SANITIZER_FREEBSD
+# endif
+#endif
// Find the saved buf by mangled_sp.
for (uptr i = 0; i < thr->jmp_bufs.Size(); i++) {
JmpBuf *buf = &thr->jmp_bufs[i];
@@ -451,6 +525,11 @@ extern "C" void __tsan_setjmp(uptr sp, uptr mangled_sp) {
SetJmp(cur_thread(), sp, mangled_sp);
}
+#if SANITIZER_MAC
+TSAN_INTERCEPTOR(int, setjmp, void *env);
+TSAN_INTERCEPTOR(int, _setjmp, void *env);
+TSAN_INTERCEPTOR(int, sigsetjmp, void *env);
+#else // SANITIZER_MAC
// Not called. Merely to satisfy TSAN_INTERCEPT().
extern "C" SANITIZER_INTERFACE_ATTRIBUTE
int __interceptor_setjmp(void *env);
@@ -489,6 +568,7 @@ DEFINE_REAL(int, setjmp, void *env)
DEFINE_REAL(int, _setjmp, void *env)
DEFINE_REAL(int, sigsetjmp, void *env)
DEFINE_REAL(int, __sigsetjmp, void *env)
+#endif // SANITIZER_MAC
TSAN_INTERCEPTOR(void, longjmp, uptr *env, int val) {
{
@@ -506,6 +586,7 @@ TSAN_INTERCEPTOR(void, siglongjmp, uptr *env, int val) {
REAL(siglongjmp)(env, val);
}
+#if !SANITIZER_MAC
TSAN_INTERCEPTOR(void*, malloc, uptr size) {
if (cur_thread()->in_symbolizer)
return __libc_malloc(size);
@@ -572,6 +653,7 @@ TSAN_INTERCEPTOR(uptr, malloc_usable_size, void *p) {
SCOPED_INTERCEPTOR_RAW(malloc_usable_size, p);
return user_alloc_usable_size(p);
}
+#endif
TSAN_INTERCEPTOR(uptr, strlen, const char *s) {
SCOPED_TSAN_INTERCEPTOR(strlen, s);
@@ -596,27 +678,18 @@ TSAN_INTERCEPTOR(void*, memcpy, void *dst, const void *src, uptr size) {
MemoryAccessRange(thr, pc, (uptr)dst, size, true);
MemoryAccessRange(thr, pc, (uptr)src, size, false);
}
- return internal_memcpy(dst, src, size);
-}
-
-TSAN_INTERCEPTOR(int, memcmp, const void *s1, const void *s2, uptr n) {
- SCOPED_TSAN_INTERCEPTOR(memcmp, s1, s2, n);
- int res = 0;
- uptr len = 0;
- for (; len < n; len++) {
- if ((res = ((const unsigned char *)s1)[len] -
- ((const unsigned char *)s2)[len]))
- break;
- }
- MemoryAccessRange(thr, pc, (uptr)s1, len < n ? len + 1 : n, false);
- MemoryAccessRange(thr, pc, (uptr)s2, len < n ? len + 1 : n, false);
- return res;
+ // On OS X, calling internal_memcpy here will cause memory corruptions,
+ // because memcpy and memmove are actually aliases of the same implementation.
+ // We need to use internal_memmove here.
+ return internal_memmove(dst, src, size);
}
TSAN_INTERCEPTOR(void*, memmove, void *dst, void *src, uptr n) {
- SCOPED_TSAN_INTERCEPTOR(memmove, dst, src, n);
- MemoryAccessRange(thr, pc, (uptr)dst, n, true);
- MemoryAccessRange(thr, pc, (uptr)src, n, false);
+ if (!COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) {
+ SCOPED_TSAN_INTERCEPTOR(memmove, dst, src, n);
+ MemoryAccessRange(thr, pc, (uptr)dst, n, true);
+ MemoryAccessRange(thr, pc, (uptr)src, n, false);
+ }
return REAL(memmove)(dst, src, n);
}
@@ -629,6 +702,7 @@ TSAN_INTERCEPTOR(char*, strchr, char *s, int c) {
return res;
}
+#if !SANITIZER_MAC
TSAN_INTERCEPTOR(char*, strchrnul, char *s, int c) {
SCOPED_TSAN_INTERCEPTOR(strchrnul, s, c);
char *res = REAL(strchrnul)(s, c);
@@ -636,6 +710,7 @@ TSAN_INTERCEPTOR(char*, strchrnul, char *s, int c) {
READ_STRING(thr, pc, s, len);
return res;
}
+#endif
TSAN_INTERCEPTOR(char*, strrchr, char *s, int c) {
SCOPED_TSAN_INTERCEPTOR(strrchr, s, c);
@@ -679,8 +754,8 @@ static bool fix_mmap_addr(void **addr, long_t sz, int flags) {
return true;
}
-TSAN_INTERCEPTOR(void*, mmap, void *addr, long_t sz, int prot,
- int flags, int fd, unsigned off) {
+TSAN_INTERCEPTOR(void *, mmap, void *addr, SIZE_T sz, int prot, int flags,
+ int fd, OFF_T off) {
SCOPED_TSAN_INTERCEPTOR(mmap, addr, sz, prot, flags, fd, off);
if (!fix_mmap_addr(&addr, sz, flags))
return MAP_FAILED;
@@ -693,9 +768,9 @@ TSAN_INTERCEPTOR(void*, mmap, void *addr, long_t sz, int prot,
return res;
}
-#if !SANITIZER_FREEBSD
-TSAN_INTERCEPTOR(void*, mmap64, void *addr, long_t sz, int prot,
- int flags, int fd, u64 off) {
+#if SANITIZER_LINUX
+TSAN_INTERCEPTOR(void *, mmap64, void *addr, SIZE_T sz, int prot, int flags,
+ int fd, OFF64_T off) {
SCOPED_TSAN_INTERCEPTOR(mmap64, addr, sz, prot, flags, fd, off);
if (!fix_mmap_addr(&addr, sz, flags))
return MAP_FAILED;
@@ -723,7 +798,7 @@ TSAN_INTERCEPTOR(int, munmap, void *addr, long_t sz) {
return res;
}
-#if !SANITIZER_FREEBSD
+#if SANITIZER_LINUX
TSAN_INTERCEPTOR(void*, memalign, uptr align, uptr sz) {
SCOPED_INTERCEPTOR_RAW(memalign, align, sz);
return user_alloc(thr, pc, sz, align);
@@ -733,6 +808,7 @@ TSAN_INTERCEPTOR(void*, memalign, uptr align, uptr sz) {
#define TSAN_MAYBE_INTERCEPT_MEMALIGN
#endif
+#if !SANITIZER_MAC
TSAN_INTERCEPTOR(void*, aligned_alloc, uptr align, uptr sz) {
SCOPED_INTERCEPTOR_RAW(memalign, align, sz);
return user_alloc(thr, pc, sz, align);
@@ -742,8 +818,9 @@ TSAN_INTERCEPTOR(void*, valloc, uptr sz) {
SCOPED_INTERCEPTOR_RAW(valloc, sz);
return user_alloc(thr, pc, sz, GetPageSizeCached());
}
+#endif
-#if !SANITIZER_FREEBSD
+#if SANITIZER_LINUX
TSAN_INTERCEPTOR(void*, pvalloc, uptr sz) {
SCOPED_INTERCEPTOR_RAW(pvalloc, sz);
sz = RoundUp(sz, GetPageSizeCached());
@@ -754,14 +831,33 @@ TSAN_INTERCEPTOR(void*, pvalloc, uptr sz) {
#define TSAN_MAYBE_INTERCEPT_PVALLOC
#endif
+#if !SANITIZER_MAC
TSAN_INTERCEPTOR(int, posix_memalign, void **memptr, uptr align, uptr sz) {
SCOPED_INTERCEPTOR_RAW(posix_memalign, memptr, align, sz);
*memptr = user_alloc(thr, pc, sz, align);
return 0;
}
+#endif
+
+// __cxa_guard_acquire and friends need to be intercepted in a special way -
+// regular interceptors will break statically-linked libstdc++. Linux
+// interceptors are especially defined as weak functions (so that they don't
+// cause link errors when user defines them as well). So they silently
+// auto-disable themselves when such symbol is already present in the binary. If
+// we link libstdc++ statically, it will bring own __cxa_guard_acquire which
+// will silently replace our interceptor. That's why on Linux we simply export
+// these interceptors with INTERFACE_ATTRIBUTE.
+// On OS X, we don't support statically linking, so we just use a regular
+// interceptor.
+#if SANITIZER_MAC
+#define STDCXX_INTERCEPTOR TSAN_INTERCEPTOR
+#else
+#define STDCXX_INTERCEPTOR(rettype, name, ...) \
+ extern "C" rettype INTERFACE_ATTRIBUTE name(__VA_ARGS__)
+#endif
// Used in thread-safe function static initialization.
-extern "C" int INTERFACE_ATTRIBUTE __cxa_guard_acquire(atomic_uint32_t *g) {
+STDCXX_INTERCEPTOR(int, __cxa_guard_acquire, atomic_uint32_t *g) {
SCOPED_INTERCEPTOR_RAW(__cxa_guard_acquire, g);
for (;;) {
u32 cmp = atomic_load(g, memory_order_acquire);
@@ -777,17 +873,31 @@ extern "C" int INTERFACE_ATTRIBUTE __cxa_guard_acquire(atomic_uint32_t *g) {
}
}
-extern "C" void INTERFACE_ATTRIBUTE __cxa_guard_release(atomic_uint32_t *g) {
+STDCXX_INTERCEPTOR(void, __cxa_guard_release, atomic_uint32_t *g) {
SCOPED_INTERCEPTOR_RAW(__cxa_guard_release, g);
Release(thr, pc, (uptr)g);
atomic_store(g, 1, memory_order_release);
}
-extern "C" void INTERFACE_ATTRIBUTE __cxa_guard_abort(atomic_uint32_t *g) {
+STDCXX_INTERCEPTOR(void, __cxa_guard_abort, atomic_uint32_t *g) {
SCOPED_INTERCEPTOR_RAW(__cxa_guard_abort, g);
atomic_store(g, 0, memory_order_relaxed);
}
+namespace __tsan {
+void DestroyThreadState() {
+ ThreadState *thr = cur_thread();
+ ThreadFinish(thr);
+ ThreadSignalContext *sctx = thr->signal_ctx;
+ if (sctx) {
+ thr->signal_ctx = 0;
+ UnmapOrDie(sctx, sizeof(*sctx));
+ }
+ cur_thread_finalize();
+}
+} // namespace __tsan
+
+#if !SANITIZER_MAC
static void thread_finalize(void *v) {
uptr iter = (uptr)v;
if (iter > 1) {
@@ -797,16 +907,9 @@ static void thread_finalize(void *v) {
}
return;
}
- {
- ThreadState *thr = cur_thread();
- ThreadFinish(thr);
- ThreadSignalContext *sctx = thr->signal_ctx;
- if (sctx) {
- thr->signal_ctx = 0;
- UnmapOrDie(sctx, sizeof(*sctx));
- }
- }
+ DestroyThreadState();
}
+#endif
struct ThreadParam {
@@ -824,6 +927,7 @@ extern "C" void *__tsan_thread_start_func(void *arg) {
ThreadState *thr = cur_thread();
// Thread-local state is not initialized yet.
ScopedIgnoreInterceptors ignore;
+#if !SANITIZER_MAC
ThreadIgnoreBegin(thr, 0);
if (pthread_setspecific(g_thread_finalize_key,
(void *)GetPthreadDestructorIterations())) {
@@ -831,8 +935,9 @@ extern "C" void *__tsan_thread_start_func(void *arg) {
Die();
}
ThreadIgnoreEnd(thr, 0);
+#endif
while ((tid = atomic_load(&p->tid, memory_order_acquire)) == 0)
- pthread_yield();
+ internal_sched_yield();
ThreadStart(thr, tid, GetTid());
atomic_store(&p->tid, 0, memory_order_release);
}
@@ -880,7 +985,8 @@ TSAN_INTERCEPTOR(int, pthread_create,
ThreadIgnoreEnd(thr, pc);
}
if (res == 0) {
- int tid = ThreadCreate(thr, pc, *(uptr*)th, detached);
+ int tid = ThreadCreate(thr, pc, *(uptr*)th,
+ detached == PTHREAD_CREATE_DETACHED);
CHECK_NE(tid, 0);
// Synchronization on p.tid serves two purposes:
// 1. ThreadCreate must finish before the new thread starts.
@@ -891,7 +997,7 @@ TSAN_INTERCEPTOR(int, pthread_create,
// before the new thread got a chance to acquire from it in ThreadStart.
atomic_store(&p.tid, tid, memory_order_release);
while (atomic_load(&p.tid, memory_order_acquire) != 0)
- pthread_yield();
+ internal_sched_yield();
}
if (attr == &myattr)
pthread_attr_destroy(&myattr);
@@ -1094,6 +1200,7 @@ TSAN_INTERCEPTOR(int, pthread_mutex_trylock, void *m) {
return res;
}
+#if !SANITIZER_MAC
TSAN_INTERCEPTOR(int, pthread_mutex_timedlock, void *m, void *abstime) {
SCOPED_TSAN_INTERCEPTOR(pthread_mutex_timedlock, m, abstime);
int res = REAL(pthread_mutex_timedlock)(m, abstime);
@@ -1102,7 +1209,9 @@ TSAN_INTERCEPTOR(int, pthread_mutex_timedlock, void *m, void *abstime) {
}
return res;
}
+#endif
+#if !SANITIZER_MAC
TSAN_INTERCEPTOR(int, pthread_spin_init, void *m, int pshared) {
SCOPED_TSAN_INTERCEPTOR(pthread_spin_init, m, pshared);
int res = REAL(pthread_spin_init)(m, pshared);
@@ -1145,6 +1254,7 @@ TSAN_INTERCEPTOR(int, pthread_spin_unlock, void *m) {
int res = REAL(pthread_spin_unlock)(m);
return res;
}
+#endif
TSAN_INTERCEPTOR(int, pthread_rwlock_init, void *m, void *a) {
SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_init, m, a);
@@ -1182,6 +1292,7 @@ TSAN_INTERCEPTOR(int, pthread_rwlock_tryrdlock, void *m) {
return res;
}
+#if !SANITIZER_MAC
TSAN_INTERCEPTOR(int, pthread_rwlock_timedrdlock, void *m, void *abstime) {
SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_timedrdlock, m, abstime);
int res = REAL(pthread_rwlock_timedrdlock)(m, abstime);
@@ -1190,6 +1301,7 @@ TSAN_INTERCEPTOR(int, pthread_rwlock_timedrdlock, void *m, void *abstime) {
}
return res;
}
+#endif
TSAN_INTERCEPTOR(int, pthread_rwlock_wrlock, void *m) {
SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_wrlock, m);
@@ -1209,6 +1321,7 @@ TSAN_INTERCEPTOR(int, pthread_rwlock_trywrlock, void *m) {
return res;
}
+#if !SANITIZER_MAC
TSAN_INTERCEPTOR(int, pthread_rwlock_timedwrlock, void *m, void *abstime) {
SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_timedwrlock, m, abstime);
int res = REAL(pthread_rwlock_timedwrlock)(m, abstime);
@@ -1217,6 +1330,7 @@ TSAN_INTERCEPTOR(int, pthread_rwlock_timedwrlock, void *m, void *abstime) {
}
return res;
}
+#endif
TSAN_INTERCEPTOR(int, pthread_rwlock_unlock, void *m) {
SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_unlock, m);
@@ -1225,6 +1339,7 @@ TSAN_INTERCEPTOR(int, pthread_rwlock_unlock, void *m) {
return res;
}
+#if !SANITIZER_MAC
TSAN_INTERCEPTOR(int, pthread_barrier_init, void *b, void *a, unsigned count) {
SCOPED_TSAN_INTERCEPTOR(pthread_barrier_init, b, a, count);
MemoryWrite(thr, pc, (uptr)b, kSizeLog1);
@@ -1250,12 +1365,17 @@ TSAN_INTERCEPTOR(int, pthread_barrier_wait, void *b) {
}
return res;
}
+#endif
TSAN_INTERCEPTOR(int, pthread_once, void *o, void (*f)()) {
SCOPED_INTERCEPTOR_RAW(pthread_once, o, f);
if (o == 0 || f == 0)
return EINVAL;
- atomic_uint32_t *a = static_cast<atomic_uint32_t*>(o);
+ atomic_uint32_t *a;
+ if (!SANITIZER_MAC)
+ a = static_cast<atomic_uint32_t*>(o);
+ else // On OS X, pthread_once_t has a header with a long-sized signature.
+ a = static_cast<atomic_uint32_t*>((void *)((char *)o + sizeof(long_t)));
u32 v = atomic_load(a, memory_order_acquire);
if (v == 0 && atomic_compare_exchange_strong(a, &v, 1,
memory_order_relaxed)) {
@@ -1265,7 +1385,7 @@ TSAN_INTERCEPTOR(int, pthread_once, void *o, void (*f)()) {
atomic_store(a, 2, memory_order_release);
} else {
while (v != 2) {
- pthread_yield();
+ internal_sched_yield();
v = atomic_load(a, memory_order_acquire);
}
if (!thr->in_ignored_lib)
@@ -1274,62 +1394,7 @@ TSAN_INTERCEPTOR(int, pthread_once, void *o, void (*f)()) {
return 0;
}
-TSAN_INTERCEPTOR(int, sem_init, void *s, int pshared, unsigned value) {
- SCOPED_TSAN_INTERCEPTOR(sem_init, s, pshared, value);
- int res = REAL(sem_init)(s, pshared, value);
- return res;
-}
-
-TSAN_INTERCEPTOR(int, sem_destroy, void *s) {
- SCOPED_TSAN_INTERCEPTOR(sem_destroy, s);
- int res = REAL(sem_destroy)(s);
- return res;
-}
-
-TSAN_INTERCEPTOR(int, sem_wait, void *s) {
- SCOPED_TSAN_INTERCEPTOR(sem_wait, s);
- int res = BLOCK_REAL(sem_wait)(s);
- if (res == 0) {
- Acquire(thr, pc, (uptr)s);
- }
- return res;
-}
-
-TSAN_INTERCEPTOR(int, sem_trywait, void *s) {
- SCOPED_TSAN_INTERCEPTOR(sem_trywait, s);
- int res = BLOCK_REAL(sem_trywait)(s);
- if (res == 0) {
- Acquire(thr, pc, (uptr)s);
- }
- return res;
-}
-
-TSAN_INTERCEPTOR(int, sem_timedwait, void *s, void *abstime) {
- SCOPED_TSAN_INTERCEPTOR(sem_timedwait, s, abstime);
- int res = BLOCK_REAL(sem_timedwait)(s, abstime);
- if (res == 0) {
- Acquire(thr, pc, (uptr)s);
- }
- return res;
-}
-
-TSAN_INTERCEPTOR(int, sem_post, void *s) {
- SCOPED_TSAN_INTERCEPTOR(sem_post, s);
- Release(thr, pc, (uptr)s);
- int res = REAL(sem_post)(s);
- return res;
-}
-
-TSAN_INTERCEPTOR(int, sem_getvalue, void *s, int *sval) {
- SCOPED_TSAN_INTERCEPTOR(sem_getvalue, s, sval);
- int res = REAL(sem_getvalue)(s, sval);
- if (res == 0) {
- Acquire(thr, pc, (uptr)s);
- }
- return res;
-}
-
-#if !SANITIZER_FREEBSD
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
TSAN_INTERCEPTOR(int, __xstat, int version, const char *path, void *buf) {
SCOPED_TSAN_INTERCEPTOR(__xstat, version, path, buf);
READ_STRING(thr, pc, path, 0);
@@ -1341,7 +1406,7 @@ TSAN_INTERCEPTOR(int, __xstat, int version, const char *path, void *buf) {
#endif
TSAN_INTERCEPTOR(int, stat, const char *path, void *buf) {
-#if SANITIZER_FREEBSD
+#if SANITIZER_FREEBSD || SANITIZER_MAC || SANITIZER_ANDROID
SCOPED_TSAN_INTERCEPTOR(stat, path, buf);
READ_STRING(thr, pc, path, 0);
return REAL(stat)(path, buf);
@@ -1352,7 +1417,7 @@ TSAN_INTERCEPTOR(int, stat, const char *path, void *buf) {
#endif
}
-#if !SANITIZER_FREEBSD
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
TSAN_INTERCEPTOR(int, __xstat64, int version, const char *path, void *buf) {
SCOPED_TSAN_INTERCEPTOR(__xstat64, version, path, buf);
READ_STRING(thr, pc, path, 0);
@@ -1363,7 +1428,7 @@ TSAN_INTERCEPTOR(int, __xstat64, int version, const char *path, void *buf) {
#define TSAN_MAYBE_INTERCEPT___XSTAT64
#endif
-#if !SANITIZER_FREEBSD
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
TSAN_INTERCEPTOR(int, stat64, const char *path, void *buf) {
SCOPED_TSAN_INTERCEPTOR(__xstat64, 0, path, buf);
READ_STRING(thr, pc, path, 0);
@@ -1374,7 +1439,7 @@ TSAN_INTERCEPTOR(int, stat64, const char *path, void *buf) {
#define TSAN_MAYBE_INTERCEPT_STAT64
#endif
-#if !SANITIZER_FREEBSD
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
TSAN_INTERCEPTOR(int, __lxstat, int version, const char *path, void *buf) {
SCOPED_TSAN_INTERCEPTOR(__lxstat, version, path, buf);
READ_STRING(thr, pc, path, 0);
@@ -1386,7 +1451,7 @@ TSAN_INTERCEPTOR(int, __lxstat, int version, const char *path, void *buf) {
#endif
TSAN_INTERCEPTOR(int, lstat, const char *path, void *buf) {
-#if SANITIZER_FREEBSD
+#if SANITIZER_FREEBSD || SANITIZER_MAC || SANITIZER_ANDROID
SCOPED_TSAN_INTERCEPTOR(lstat, path, buf);
READ_STRING(thr, pc, path, 0);
return REAL(lstat)(path, buf);
@@ -1397,7 +1462,7 @@ TSAN_INTERCEPTOR(int, lstat, const char *path, void *buf) {
#endif
}
-#if !SANITIZER_FREEBSD
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
TSAN_INTERCEPTOR(int, __lxstat64, int version, const char *path, void *buf) {
SCOPED_TSAN_INTERCEPTOR(__lxstat64, version, path, buf);
READ_STRING(thr, pc, path, 0);
@@ -1408,7 +1473,7 @@ TSAN_INTERCEPTOR(int, __lxstat64, int version, const char *path, void *buf) {
#define TSAN_MAYBE_INTERCEPT___LXSTAT64
#endif
-#if !SANITIZER_FREEBSD
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
TSAN_INTERCEPTOR(int, lstat64, const char *path, void *buf) {
SCOPED_TSAN_INTERCEPTOR(__lxstat64, 0, path, buf);
READ_STRING(thr, pc, path, 0);
@@ -1419,7 +1484,7 @@ TSAN_INTERCEPTOR(int, lstat64, const char *path, void *buf) {
#define TSAN_MAYBE_INTERCEPT_LSTAT64
#endif
-#if !SANITIZER_FREEBSD
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
TSAN_INTERCEPTOR(int, __fxstat, int version, int fd, void *buf) {
SCOPED_TSAN_INTERCEPTOR(__fxstat, version, fd, buf);
if (fd > 0)
@@ -1432,7 +1497,7 @@ TSAN_INTERCEPTOR(int, __fxstat, int version, int fd, void *buf) {
#endif
TSAN_INTERCEPTOR(int, fstat, int fd, void *buf) {
-#if SANITIZER_FREEBSD
+#if SANITIZER_FREEBSD || SANITIZER_MAC || SANITIZER_ANDROID
SCOPED_TSAN_INTERCEPTOR(fstat, fd, buf);
if (fd > 0)
FdAccess(thr, pc, fd);
@@ -1445,7 +1510,7 @@ TSAN_INTERCEPTOR(int, fstat, int fd, void *buf) {
#endif
}
-#if !SANITIZER_FREEBSD
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
TSAN_INTERCEPTOR(int, __fxstat64, int version, int fd, void *buf) {
SCOPED_TSAN_INTERCEPTOR(__fxstat64, version, fd, buf);
if (fd > 0)
@@ -1457,7 +1522,7 @@ TSAN_INTERCEPTOR(int, __fxstat64, int version, int fd, void *buf) {
#define TSAN_MAYBE_INTERCEPT___FXSTAT64
#endif
-#if !SANITIZER_FREEBSD
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
TSAN_INTERCEPTOR(int, fstat64, int fd, void *buf) {
SCOPED_TSAN_INTERCEPTOR(__fxstat64, 0, fd, buf);
if (fd > 0)
@@ -1478,7 +1543,7 @@ TSAN_INTERCEPTOR(int, open, const char *name, int flags, int mode) {
return fd;
}
-#if !SANITIZER_FREEBSD
+#if SANITIZER_LINUX
TSAN_INTERCEPTOR(int, open64, const char *name, int flags, int mode) {
SCOPED_TSAN_INTERCEPTOR(open64, name, flags, mode);
READ_STRING(thr, pc, name, 0);
@@ -1501,7 +1566,7 @@ TSAN_INTERCEPTOR(int, creat, const char *name, int mode) {
return fd;
}
-#if !SANITIZER_FREEBSD
+#if SANITIZER_LINUX
TSAN_INTERCEPTOR(int, creat64, const char *name, int mode) {
SCOPED_TSAN_INTERCEPTOR(creat64, name, mode);
READ_STRING(thr, pc, name, 0);
@@ -1531,6 +1596,7 @@ TSAN_INTERCEPTOR(int, dup2, int oldfd, int newfd) {
return newfd2;
}
+#if !SANITIZER_MAC
TSAN_INTERCEPTOR(int, dup3, int oldfd, int newfd, int flags) {
SCOPED_TSAN_INTERCEPTOR(dup3, oldfd, newfd, flags);
int newfd2 = REAL(dup3)(oldfd, newfd, flags);
@@ -1538,8 +1604,9 @@ TSAN_INTERCEPTOR(int, dup3, int oldfd, int newfd, int flags) {
FdDup(thr, pc, oldfd, newfd2, false);
return newfd2;
}
+#endif
-#if !SANITIZER_FREEBSD
+#if SANITIZER_LINUX
TSAN_INTERCEPTOR(int, eventfd, unsigned initval, int flags) {
SCOPED_TSAN_INTERCEPTOR(eventfd, initval, flags);
int fd = REAL(eventfd)(initval, flags);
@@ -1552,7 +1619,7 @@ TSAN_INTERCEPTOR(int, eventfd, unsigned initval, int flags) {
#define TSAN_MAYBE_INTERCEPT_EVENTFD
#endif
-#if !SANITIZER_FREEBSD
+#if SANITIZER_LINUX
TSAN_INTERCEPTOR(int, signalfd, int fd, void *mask, int flags) {
SCOPED_TSAN_INTERCEPTOR(signalfd, fd, mask, flags);
if (fd >= 0)
@@ -1567,7 +1634,7 @@ TSAN_INTERCEPTOR(int, signalfd, int fd, void *mask, int flags) {
#define TSAN_MAYBE_INTERCEPT_SIGNALFD
#endif
-#if !SANITIZER_FREEBSD
+#if SANITIZER_LINUX
TSAN_INTERCEPTOR(int, inotify_init, int fake) {
SCOPED_TSAN_INTERCEPTOR(inotify_init, fake);
int fd = REAL(inotify_init)(fake);
@@ -1580,7 +1647,7 @@ TSAN_INTERCEPTOR(int, inotify_init, int fake) {
#define TSAN_MAYBE_INTERCEPT_INOTIFY_INIT
#endif
-#if !SANITIZER_FREEBSD
+#if SANITIZER_LINUX
TSAN_INTERCEPTOR(int, inotify_init1, int flags) {
SCOPED_TSAN_INTERCEPTOR(inotify_init1, flags);
int fd = REAL(inotify_init1)(flags);
@@ -1634,7 +1701,7 @@ TSAN_INTERCEPTOR(int, listen, int fd, int backlog) {
return res;
}
-#if !SANITIZER_FREEBSD
+#if SANITIZER_LINUX
TSAN_INTERCEPTOR(int, epoll_create, int size) {
SCOPED_TSAN_INTERCEPTOR(epoll_create, size);
int fd = REAL(epoll_create)(size);
@@ -1647,7 +1714,7 @@ TSAN_INTERCEPTOR(int, epoll_create, int size) {
#define TSAN_MAYBE_INTERCEPT_EPOLL_CREATE
#endif
-#if !SANITIZER_FREEBSD
+#if SANITIZER_LINUX
TSAN_INTERCEPTOR(int, epoll_create1, int flags) {
SCOPED_TSAN_INTERCEPTOR(epoll_create1, flags);
int fd = REAL(epoll_create1)(flags);
@@ -1667,7 +1734,7 @@ TSAN_INTERCEPTOR(int, close, int fd) {
return REAL(close)(fd);
}
-#if !SANITIZER_FREEBSD
+#if SANITIZER_LINUX
TSAN_INTERCEPTOR(int, __close, int fd) {
SCOPED_TSAN_INTERCEPTOR(__close, fd);
if (fd >= 0)
@@ -1680,7 +1747,7 @@ TSAN_INTERCEPTOR(int, __close, int fd) {
#endif
// glibc guts
-#if !SANITIZER_FREEBSD
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
TSAN_INTERCEPTOR(void, __res_iclose, void *state, bool free_addr) {
SCOPED_TSAN_INTERCEPTOR(__res_iclose, state, free_addr);
int fds[64];
@@ -1704,6 +1771,7 @@ TSAN_INTERCEPTOR(int, pipe, int *pipefd) {
return res;
}
+#if !SANITIZER_MAC
TSAN_INTERCEPTOR(int, pipe2, int *pipefd, int flags) {
SCOPED_TSAN_INTERCEPTOR(pipe2, pipefd, flags);
int res = REAL(pipe2)(pipefd, flags);
@@ -1711,6 +1779,7 @@ TSAN_INTERCEPTOR(int, pipe2, int *pipefd, int flags) {
FdPipeCreate(thr, pc, pipefd[0], pipefd[1]);
return res;
}
+#endif
TSAN_INTERCEPTOR(long_t, send, int fd, void *buf, long_t len, int flags) {
SCOPED_TSAN_INTERCEPTOR(send, fd, buf, len, flags);
@@ -1761,7 +1830,7 @@ TSAN_INTERCEPTOR(void*, tmpfile, int fake) {
return res;
}
-#if !SANITIZER_FREEBSD
+#if SANITIZER_LINUX
TSAN_INTERCEPTOR(void*, tmpfile64, int fake) {
SCOPED_TSAN_INTERCEPTOR(tmpfile64, fake);
void *res = REAL(tmpfile64)(fake);
@@ -1823,12 +1892,14 @@ TSAN_INTERCEPTOR(int, rmdir, char *path) {
TSAN_INTERCEPTOR(int, closedir, void *dirp) {
SCOPED_TSAN_INTERCEPTOR(closedir, dirp);
- int fd = dirfd(dirp);
- FdClose(thr, pc, fd);
+ if (dirp) {
+ int fd = dirfd(dirp);
+ FdClose(thr, pc, fd);
+ }
return REAL(closedir)(dirp);
}
-#if !SANITIZER_FREEBSD
+#if SANITIZER_LINUX
TSAN_INTERCEPTOR(int, epoll_ctl, int epfd, int op, int fd, void *ev) {
SCOPED_TSAN_INTERCEPTOR(epoll_ctl, epfd, op, fd, ev);
if (epfd >= 0)
@@ -1845,7 +1916,7 @@ TSAN_INTERCEPTOR(int, epoll_ctl, int epfd, int op, int fd, void *ev) {
#define TSAN_MAYBE_INTERCEPT_EPOLL_CTL
#endif
-#if !SANITIZER_FREEBSD
+#if SANITIZER_LINUX
TSAN_INTERCEPTOR(int, epoll_wait, int epfd, void *ev, int cnt, int timeout) {
SCOPED_TSAN_INTERCEPTOR(epoll_wait, epfd, ev, cnt, timeout);
if (epfd >= 0)
@@ -1895,7 +1966,7 @@ static void CallUserSignalHandler(ThreadState *thr, bool sync, bool acquire,
ObtainCurrentStack(thr, StackTrace::GetNextInstructionPc(pc), &stack);
ThreadRegistryLock l(ctx->thread_registry);
ScopedReport rep(ReportTypeErrnoInSignal);
- if (!IsFiredSuppression(ctx, rep, stack)) {
+ if (!IsFiredSuppression(ctx, ReportTypeErrnoInSignal, stack)) {
rep.AddStack(stack, true);
OutputReport(thr, rep);
}
@@ -1910,10 +1981,8 @@ void ProcessPendingSignals(ThreadState *thr) {
return;
atomic_store(&sctx->have_pending_signals, 0, memory_order_relaxed);
atomic_fetch_add(&thr->in_signal_handler, 1, memory_order_relaxed);
- // These are too big for stack.
- static THREADLOCAL __sanitizer_sigset_t emptyset, oldset;
- CHECK_EQ(0, REAL(sigfillset)(&emptyset));
- CHECK_EQ(0, pthread_sigmask(SIG_SETMASK, &emptyset, &oldset));
+ CHECK_EQ(0, REAL(sigfillset)(&sctx->emptyset));
+ CHECK_EQ(0, pthread_sigmask(SIG_SETMASK, &sctx->emptyset, &sctx->oldset));
for (int sig = 0; sig < kSigCount; sig++) {
SignalDesc *signal = &sctx->pending_signals[sig];
if (signal->armed) {
@@ -1922,7 +1991,7 @@ void ProcessPendingSignals(ThreadState *thr) {
&signal->siginfo, &signal->ctx);
}
}
- CHECK_EQ(0, pthread_sigmask(SIG_SETMASK, &oldset, 0));
+ CHECK_EQ(0, pthread_sigmask(SIG_SETMASK, &sctx->oldset, 0));
atomic_fetch_add(&thr->in_signal_handler, -1, memory_order_relaxed);
}
@@ -2011,7 +2080,7 @@ TSAN_INTERCEPTOR(int, sigaction, int sig, sigaction_t *act, sigaction_t *old) {
sigactions[sig].sa_flags = *(volatile int*)&act->sa_flags;
internal_memcpy(&sigactions[sig].sa_mask, &act->sa_mask,
sizeof(sigactions[sig].sa_mask));
-#if !SANITIZER_FREEBSD
+#if !SANITIZER_FREEBSD && !SANITIZER_MAC
sigactions[sig].sa_restorer = act->sa_restorer;
#endif
sigaction_t newact;
@@ -2144,6 +2213,7 @@ TSAN_INTERCEPTOR(int, vfork, int fake) {
return WRAP(fork)(fake);
}
+#if !SANITIZER_MAC && !SANITIZER_ANDROID
typedef int (*dl_iterate_phdr_cb_t)(__sanitizer_dl_phdr_info *info, SIZE_T size,
void *data);
struct dl_iterate_phdr_data {
@@ -2187,6 +2257,7 @@ TSAN_INTERCEPTOR(int, dl_iterate_phdr, dl_iterate_phdr_cb_t cb, void *data) {
int res = REAL(dl_iterate_phdr)(dl_iterate_phdr_cb, &cbdata);
return res;
}
+#endif
static int OnExit(ThreadState *thr) {
int status = Finalize(thr);
@@ -2200,6 +2271,7 @@ struct TsanInterceptorContext {
const uptr pc;
};
+#if !SANITIZER_MAC
static void HandleRecvmsg(ThreadState *thr, uptr pc,
__sanitizer_msghdr *msg) {
int fds[64];
@@ -2207,6 +2279,7 @@ static void HandleRecvmsg(ThreadState *thr, uptr pc,
for (int i = 0; i < cnt; i++)
FdEventCreate(thr, pc, fds[i]);
}
+#endif
#include "sanitizer_common/sanitizer_platform_interceptors.h"
// Causes interceptor recursion (getaddrinfo() and fopen())
@@ -2277,6 +2350,12 @@ static void HandleRecvmsg(ThreadState *thr, uptr pc,
#define COMMON_INTERCEPTOR_LIBRARY_UNLOADED() \
libignore()->OnLibraryUnloaded()
+#define COMMON_INTERCEPTOR_ACQUIRE(ctx, u) \
+ Acquire(((TsanInterceptorContext *) ctx)->thr, pc, u)
+
+#define COMMON_INTERCEPTOR_RELEASE(ctx, u) \
+ Release(((TsanInterceptorContext *) ctx)->thr, pc, u)
+
#define COMMON_INTERCEPTOR_DIR_ACQUIRE(ctx, path) \
Acquire(((TsanInterceptorContext *) ctx)->thr, pc, Dir2addr(path))
@@ -2315,9 +2394,11 @@ static void HandleRecvmsg(ThreadState *thr, uptr pc,
MutexRepair(((TsanInterceptorContext *)ctx)->thr, \
((TsanInterceptorContext *)ctx)->pc, (uptr)m)
+#if !SANITIZER_MAC
#define COMMON_INTERCEPTOR_HANDLE_RECVMSG(ctx, msg) \
HandleRecvmsg(((TsanInterceptorContext *)ctx)->thr, \
((TsanInterceptorContext *)ctx)->pc, msg)
+#endif
#define COMMON_INTERCEPTOR_GET_TLS_RANGE(begin, end) \
if (TsanThread *t = GetCurrentThread()) { \
@@ -2349,6 +2430,7 @@ struct ScopedSyscall {
}
};
+#if !SANITIZER_MAC
static void syscall_access_range(uptr pc, uptr p, uptr s, bool write) {
TSAN_SYSCALL();
MemoryAccessRange(thr, pc, p, s, write);
@@ -2402,6 +2484,7 @@ static void syscall_post_fork(uptr pc, int pid) {
ForkParentAfter(thr, pc);
}
}
+#endif
#define COMMON_SYSCALL_PRE_READ_RANGE(p, s) \
syscall_access_range(GET_CALLER_PC(), (uptr)(p), (uptr)(s), false)
@@ -2449,28 +2532,32 @@ static void finalize(void *arg) {
// Make sure the output is not lost.
FlushStreams();
if (status)
- REAL(_exit)(status);
+ Die();
}
+#if !SANITIZER_MAC && !SANITIZER_ANDROID
static void unreachable() {
Report("FATAL: ThreadSanitizer: unreachable called\n");
Die();
}
+#endif
void InitializeInterceptors() {
+#if !SANITIZER_MAC
// We need to setup it early, because functions like dlsym() can call it.
REAL(memset) = internal_memset;
REAL(memcpy) = internal_memcpy;
- REAL(memcmp) = internal_memcmp;
+#endif
// Instruct libc malloc to consume less memory.
-#if !SANITIZER_FREEBSD
+#if SANITIZER_LINUX
mallopt(1, 0); // M_MXFAST
mallopt(-3, 32*1024); // M_MMAP_THRESHOLD
#endif
InitializeCommonInterceptors();
+#if !SANITIZER_MAC
// We can not use TSAN_INTERCEPT to get setjmp addr,
// because it does &setjmp and setjmp is not present in some versions of libc.
using __interception::GetRealFunctionAddress;
@@ -2478,6 +2565,7 @@ void InitializeInterceptors() {
GetRealFunctionAddress("_setjmp", (uptr*)&REAL(_setjmp), 0, 0);
GetRealFunctionAddress("sigsetjmp", (uptr*)&REAL(sigsetjmp), 0, 0);
GetRealFunctionAddress("__sigsetjmp", (uptr*)&REAL(__sigsetjmp), 0, 0);
+#endif
TSAN_INTERCEPT(longjmp);
TSAN_INTERCEPT(siglongjmp);
@@ -2500,7 +2588,6 @@ void InitializeInterceptors() {
TSAN_INTERCEPT(memset);
TSAN_INTERCEPT(memcpy);
TSAN_INTERCEPT(memmove);
- TSAN_INTERCEPT(memcmp);
TSAN_INTERCEPT(strchr);
TSAN_INTERCEPT(strchrnul);
TSAN_INTERCEPT(strrchr);
@@ -2512,12 +2599,12 @@ void InitializeInterceptors() {
TSAN_INTERCEPT(pthread_join);
TSAN_INTERCEPT(pthread_detach);
- TSAN_INTERCEPT_VER(pthread_cond_init, "GLIBC_2.3.2");
- TSAN_INTERCEPT_VER(pthread_cond_signal, "GLIBC_2.3.2");
- TSAN_INTERCEPT_VER(pthread_cond_broadcast, "GLIBC_2.3.2");
- TSAN_INTERCEPT_VER(pthread_cond_wait, "GLIBC_2.3.2");
- TSAN_INTERCEPT_VER(pthread_cond_timedwait, "GLIBC_2.3.2");
- TSAN_INTERCEPT_VER(pthread_cond_destroy, "GLIBC_2.3.2");
+ TSAN_INTERCEPT_VER(pthread_cond_init, PTHREAD_ABI_BASE);
+ TSAN_INTERCEPT_VER(pthread_cond_signal, PTHREAD_ABI_BASE);
+ TSAN_INTERCEPT_VER(pthread_cond_broadcast, PTHREAD_ABI_BASE);
+ TSAN_INTERCEPT_VER(pthread_cond_wait, PTHREAD_ABI_BASE);
+ TSAN_INTERCEPT_VER(pthread_cond_timedwait, PTHREAD_ABI_BASE);
+ TSAN_INTERCEPT_VER(pthread_cond_destroy, PTHREAD_ABI_BASE);
TSAN_INTERCEPT(pthread_mutex_init);
TSAN_INTERCEPT(pthread_mutex_destroy);
@@ -2546,14 +2633,6 @@ void InitializeInterceptors() {
TSAN_INTERCEPT(pthread_once);
- TSAN_INTERCEPT(sem_init);
- TSAN_INTERCEPT(sem_destroy);
- TSAN_INTERCEPT(sem_wait);
- TSAN_INTERCEPT(sem_trywait);
- TSAN_INTERCEPT(sem_timedwait);
- TSAN_INTERCEPT(sem_post);
- TSAN_INTERCEPT(sem_getvalue);
-
TSAN_INTERCEPT(stat);
TSAN_MAYBE_INTERCEPT___XSTAT;
TSAN_MAYBE_INTERCEPT_STAT64;
@@ -2621,25 +2700,68 @@ void InitializeInterceptors() {
TSAN_INTERCEPT(fork);
TSAN_INTERCEPT(vfork);
+#if !SANITIZER_ANDROID
TSAN_INTERCEPT(dl_iterate_phdr);
+#endif
TSAN_INTERCEPT(on_exit);
TSAN_INTERCEPT(__cxa_atexit);
TSAN_INTERCEPT(_exit);
+#if !SANITIZER_MAC && !SANITIZER_ANDROID
// Need to setup it, because interceptors check that the function is resolved.
// But atexit is emitted directly into the module, so can't be resolved.
REAL(atexit) = (int(*)(void(*)()))unreachable;
+#endif
+
if (REAL(__cxa_atexit)(&finalize, 0, 0)) {
Printf("ThreadSanitizer: failed to setup atexit callback\n");
Die();
}
+#if !SANITIZER_MAC
if (pthread_key_create(&g_thread_finalize_key, &thread_finalize)) {
Printf("ThreadSanitizer: failed to create thread key\n");
Die();
}
+#endif
FdInit();
}
} // namespace __tsan
+
+// Invisible barrier for tests.
+// There were several unsuccessful iterations for this functionality:
+// 1. Initially it was implemented in user code using
+// REAL(pthread_barrier_wait). But pthread_barrier_wait is not supported on
+// MacOS. Futexes are linux-specific for this matter.
+// 2. Then we switched to atomics+usleep(10). But usleep produced parasitic
+// "as-if synchronized via sleep" messages in reports which failed some
+// output tests.
+// 3. Then we switched to atomics+sched_yield. But this produced tons of tsan-
+// visible events, which lead to "failed to restore stack trace" failures.
+// Note that no_sanitize_thread attribute does not turn off atomic interception
+// so attaching it to the function defined in user code does not help.
+// That's why we now have what we have.
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_testonly_barrier_init(u64 *barrier, u32 count) {
+ if (count >= (1 << 8)) {
+ Printf("barrier_init: count is too large (%d)\n", count);
+ Die();
+ }
+ // 8 lsb is thread count, the remaining are count of entered threads.
+ *barrier = count;
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_testonly_barrier_wait(u64 *barrier) {
+ unsigned old = __atomic_fetch_add(barrier, 1 << 8, __ATOMIC_RELAXED);
+ unsigned old_epoch = (old >> 8) / (old & 0xff);
+ for (;;) {
+ unsigned cur = __atomic_load_n(barrier, __ATOMIC_RELAXED);
+ unsigned cur_epoch = (cur >> 8) / (cur & 0xff);
+ if (cur_epoch != old_epoch)
+ return;
+ internal_sched_yield();
+ }
+}
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_interceptors.h b/contrib/compiler-rt/lib/tsan/rtl/tsan_interceptors.h
index 49b79a7c5f9e..d831620cfafe 100644
--- a/contrib/compiler-rt/lib/tsan/rtl/tsan_interceptors.h
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_interceptors.h
@@ -10,6 +10,8 @@ class ScopedInterceptor {
public:
ScopedInterceptor(ThreadState *thr, const char *fname, uptr pc);
~ScopedInterceptor();
+ void UserCallbackStart();
+ void UserCallbackEnd();
private:
ThreadState *const thr_;
const uptr pc_;
@@ -26,6 +28,24 @@ class ScopedInterceptor {
(void)pc; \
/**/
+#define SCOPED_TSAN_INTERCEPTOR(func, ...) \
+ SCOPED_INTERCEPTOR_RAW(func, __VA_ARGS__); \
+ if (REAL(func) == 0) { \
+ Report("FATAL: ThreadSanitizer: failed to intercept %s\n", #func); \
+ Die(); \
+ } \
+ if (thr->ignore_interceptors || thr->in_ignored_lib) \
+ return REAL(func)(__VA_ARGS__); \
+/**/
+
+#define SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START() \
+ si.UserCallbackStart();
+
+#define SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END() \
+ si.UserCallbackEnd();
+
+#define TSAN_INTERCEPTOR(ret, func, ...) INTERCEPTOR(ret, func, __VA_ARGS__)
+
#if SANITIZER_FREEBSD
#define __libc_free __free
#define __libc_malloc __malloc
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_interceptors_mac.cc b/contrib/compiler-rt/lib/tsan/rtl/tsan_interceptors_mac.cc
new file mode 100644
index 000000000000..2bf7ad9861c4
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_interceptors_mac.cc
@@ -0,0 +1,91 @@
+//===-- tsan_interceptors_mac.cc ------------------------------------------===//
+//
+// 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 ThreadSanitizer (TSan), a race detector.
+//
+// Mac-specific interceptors.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_platform.h"
+#if SANITIZER_MAC
+
+#include "interception/interception.h"
+#include "tsan_interceptors.h"
+
+#include <libkern/OSAtomic.h>
+
+namespace __tsan {
+
+TSAN_INTERCEPTOR(void, OSSpinLockLock, volatile OSSpinLock *lock) {
+ CHECK(!cur_thread()->is_dead);
+ if (!cur_thread()->is_inited) {
+ return REAL(OSSpinLockLock)(lock);
+ }
+ SCOPED_TSAN_INTERCEPTOR(OSSpinLockLock, lock);
+ REAL(OSSpinLockLock)(lock);
+ Acquire(thr, pc, (uptr)lock);
+}
+
+TSAN_INTERCEPTOR(bool, OSSpinLockTry, volatile OSSpinLock *lock) {
+ CHECK(!cur_thread()->is_dead);
+ if (!cur_thread()->is_inited) {
+ return REAL(OSSpinLockTry)(lock);
+ }
+ SCOPED_TSAN_INTERCEPTOR(OSSpinLockTry, lock);
+ bool result = REAL(OSSpinLockTry)(lock);
+ if (result)
+ Acquire(thr, pc, (uptr)lock);
+ return result;
+}
+
+TSAN_INTERCEPTOR(void, OSSpinLockUnlock, volatile OSSpinLock *lock) {
+ CHECK(!cur_thread()->is_dead);
+ if (!cur_thread()->is_inited) {
+ return REAL(OSSpinLockUnlock)(lock);
+ }
+ SCOPED_TSAN_INTERCEPTOR(OSSpinLockUnlock, lock);
+ Release(thr, pc, (uptr)lock);
+ REAL(OSSpinLockUnlock)(lock);
+}
+
+TSAN_INTERCEPTOR(void, os_lock_lock, void *lock) {
+ CHECK(!cur_thread()->is_dead);
+ if (!cur_thread()->is_inited) {
+ return REAL(os_lock_lock)(lock);
+ }
+ SCOPED_TSAN_INTERCEPTOR(os_lock_lock, lock);
+ REAL(os_lock_lock)(lock);
+ Acquire(thr, pc, (uptr)lock);
+}
+
+TSAN_INTERCEPTOR(bool, os_lock_trylock, void *lock) {
+ CHECK(!cur_thread()->is_dead);
+ if (!cur_thread()->is_inited) {
+ return REAL(os_lock_trylock)(lock);
+ }
+ SCOPED_TSAN_INTERCEPTOR(os_lock_trylock, lock);
+ bool result = REAL(os_lock_trylock)(lock);
+ if (result)
+ Acquire(thr, pc, (uptr)lock);
+ return result;
+}
+
+TSAN_INTERCEPTOR(void, os_lock_unlock, void *lock) {
+ CHECK(!cur_thread()->is_dead);
+ if (!cur_thread()->is_inited) {
+ return REAL(os_lock_unlock)(lock);
+ }
+ SCOPED_TSAN_INTERCEPTOR(os_lock_unlock, lock);
+ Release(thr, pc, (uptr)lock);
+ REAL(os_lock_unlock)(lock);
+}
+
+} // namespace __tsan
+
+#endif // SANITIZER_MAC
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_interface_ann.cc b/contrib/compiler-rt/lib/tsan/rtl/tsan_interface_ann.cc
index fd3c846678f5..62db79661625 100644
--- a/contrib/compiler-rt/lib/tsan/rtl/tsan_interface_ann.cc
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_interface_ann.cc
@@ -63,8 +63,8 @@ static const int kMaxDescLen = 128;
struct ExpectRace {
ExpectRace *next;
ExpectRace *prev;
- int hitcount;
- int addcount;
+ atomic_uintptr_t hitcount;
+ atomic_uintptr_t addcount;
uptr addr;
uptr size;
char *file;
@@ -90,7 +90,8 @@ static void AddExpectRace(ExpectRace *list,
ExpectRace *race = list->next;
for (; race != list; race = race->next) {
if (race->addr == addr && race->size == size) {
- race->addcount++;
+ atomic_store_relaxed(&race->addcount,
+ atomic_load_relaxed(&race->addcount) + 1);
return;
}
}
@@ -100,8 +101,8 @@ static void AddExpectRace(ExpectRace *list,
race->file = f;
race->line = l;
race->desc[0] = 0;
- race->hitcount = 0;
- race->addcount = 1;
+ atomic_store_relaxed(&race->hitcount, 0);
+ atomic_store_relaxed(&race->addcount, 1);
if (desc) {
int i = 0;
for (; i < kMaxDescLen - 1 && desc[i]; i++)
@@ -130,7 +131,7 @@ static bool CheckContains(ExpectRace *list, uptr addr, uptr size) {
return false;
DPrintf("Hit expected/benign race: %s addr=%zx:%d %s:%d\n",
race->desc, race->addr, (int)race->size, race->file, race->line);
- race->hitcount++;
+ atomic_fetch_add(&race->hitcount, 1, memory_order_relaxed);
return true;
}
@@ -146,7 +147,7 @@ void InitializeDynamicAnnotations() {
}
bool IsExpectedReport(uptr addr, uptr size) {
- Lock lock(&dyn_ann_ctx->mtx);
+ ReadLock lock(&dyn_ann_ctx->mtx);
if (CheckContains(&dyn_ann_ctx->expect, addr, size))
return true;
if (CheckContains(&dyn_ann_ctx->benign, addr, size))
@@ -155,20 +156,21 @@ bool IsExpectedReport(uptr addr, uptr size) {
}
static void CollectMatchedBenignRaces(Vector<ExpectRace> *matched,
- int *unique_count, int *hit_count, int ExpectRace::*counter) {
+ int *unique_count, int *hit_count, atomic_uintptr_t ExpectRace::*counter) {
ExpectRace *list = &dyn_ann_ctx->benign;
for (ExpectRace *race = list->next; race != list; race = race->next) {
(*unique_count)++;
- if (race->*counter == 0)
+ const uptr cnt = atomic_load_relaxed(&(race->*counter));
+ if (cnt == 0)
continue;
- (*hit_count) += race->*counter;
+ *hit_count += cnt;
uptr i = 0;
for (; i < matched->Size(); i++) {
ExpectRace *race0 = &(*matched)[i];
if (race->line == race0->line
&& internal_strcmp(race->file, race0->file) == 0
&& internal_strcmp(race->desc, race0->desc) == 0) {
- race0->*counter += race->*counter;
+ atomic_fetch_add(&(race0->*counter), cnt, memory_order_relaxed);
break;
}
}
@@ -193,8 +195,8 @@ void PrintMatchedBenignRaces() {
hit_count, (int)internal_getpid());
for (uptr i = 0; i < hit_matched.Size(); i++) {
Printf("%d %s:%d %s\n",
- hit_matched[i].hitcount, hit_matched[i].file,
- hit_matched[i].line, hit_matched[i].desc);
+ atomic_load_relaxed(&hit_matched[i].hitcount),
+ hit_matched[i].file, hit_matched[i].line, hit_matched[i].desc);
}
}
if (hit_matched.Size()) {
@@ -203,8 +205,8 @@ void PrintMatchedBenignRaces() {
add_count, unique_count, (int)internal_getpid());
for (uptr i = 0; i < add_matched.Size(); i++) {
Printf("%d %s:%d %s\n",
- add_matched[i].addcount, add_matched[i].file,
- add_matched[i].line, add_matched[i].desc);
+ atomic_load_relaxed(&add_matched[i].addcount),
+ add_matched[i].file, add_matched[i].line, add_matched[i].desc);
}
}
}
@@ -303,7 +305,7 @@ void INTERFACE_ATTRIBUTE AnnotateFlushExpectedRaces(char *f, int l) {
Lock lock(&dyn_ann_ctx->mtx);
while (dyn_ann_ctx->expect.next != &dyn_ann_ctx->expect) {
ExpectRace *race = dyn_ann_ctx->expect.next;
- if (race->hitcount == 0) {
+ if (atomic_load_relaxed(&race->hitcount) == 0) {
ctx->nmissed_expected++;
ReportMissedExpectedRace(race);
}
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_libdispatch_mac.cc b/contrib/compiler-rt/lib/tsan/rtl/tsan_libdispatch_mac.cc
new file mode 100644
index 000000000000..617dc91b33d0
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_libdispatch_mac.cc
@@ -0,0 +1,284 @@
+//===-- tsan_libdispatch_mac.cc -------------------------------------------===//
+//
+// 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 ThreadSanitizer (TSan), a race detector.
+//
+// Mac-specific libdispatch (GCD) support.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_platform.h"
+#if SANITIZER_MAC
+
+#include "sanitizer_common/sanitizer_common.h"
+#include "interception/interception.h"
+#include "tsan_interceptors.h"
+#include "tsan_platform.h"
+#include "tsan_rtl.h"
+
+#include <Block.h>
+#include <dispatch/dispatch.h>
+#include <pthread.h>
+
+typedef long long_t; // NOLINT
+
+namespace __tsan {
+
+typedef struct {
+ dispatch_queue_t queue;
+ void *orig_context;
+ dispatch_function_t orig_work;
+ uptr object_to_acquire;
+ dispatch_object_t object_to_release;
+} tsan_block_context_t;
+
+// The offsets of different fields of the dispatch_queue_t structure, exported
+// by libdispatch.dylib.
+extern "C" struct dispatch_queue_offsets_s {
+ const uint16_t dqo_version;
+ const uint16_t dqo_label;
+ const uint16_t dqo_label_size;
+ const uint16_t dqo_flags;
+ const uint16_t dqo_flags_size;
+ const uint16_t dqo_serialnum;
+ const uint16_t dqo_serialnum_size;
+ const uint16_t dqo_width;
+ const uint16_t dqo_width_size;
+ const uint16_t dqo_running;
+ const uint16_t dqo_running_size;
+ const uint16_t dqo_suspend_cnt;
+ const uint16_t dqo_suspend_cnt_size;
+ const uint16_t dqo_target_queue;
+ const uint16_t dqo_target_queue_size;
+ const uint16_t dqo_priority;
+ const uint16_t dqo_priority_size;
+} dispatch_queue_offsets;
+
+static bool IsQueueSerial(dispatch_queue_t q) {
+ CHECK_EQ(dispatch_queue_offsets.dqo_width_size, 2);
+ uptr width = *(uint16_t *)(((uptr)q) + dispatch_queue_offsets.dqo_width);
+ CHECK_NE(width, 0);
+ return width == 1;
+}
+
+static tsan_block_context_t *AllocContext(ThreadState *thr, uptr pc,
+ dispatch_queue_t queue,
+ void *orig_context,
+ dispatch_function_t orig_work) {
+ tsan_block_context_t *new_context =
+ (tsan_block_context_t *)user_alloc(thr, pc, sizeof(tsan_block_context_t));
+ new_context->queue = queue;
+ new_context->orig_context = orig_context;
+ new_context->orig_work = orig_work;
+ new_context->object_to_acquire = (uptr)new_context;
+ new_context->object_to_release = nullptr;
+ return new_context;
+}
+
+static void dispatch_callback_wrap_acquire(void *param) {
+ SCOPED_INTERCEPTOR_RAW(dispatch_async_f_callback_wrap);
+ tsan_block_context_t *context = (tsan_block_context_t *)param;
+ Acquire(thr, pc, context->object_to_acquire);
+
+ // Extra retain/release is required for dispatch groups. We use the group
+ // itself to synchronize, but in a notification (dispatch_group_notify
+ // callback), it may be disposed already. To solve this, we retain the group
+ // and release it here.
+ if (context->object_to_release) dispatch_release(context->object_to_release);
+
+ // In serial queues, work items can be executed on different threads, we need
+ // to explicitly synchronize on the queue itself.
+ if (IsQueueSerial(context->queue)) Acquire(thr, pc, (uptr)context->queue);
+ SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START();
+ context->orig_work(context->orig_context);
+ SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END();
+ if (IsQueueSerial(context->queue)) Release(thr, pc, (uptr)context->queue);
+ user_free(thr, pc, context);
+}
+
+static void invoke_and_release_block(void *param) {
+ dispatch_block_t block = (dispatch_block_t)param;
+ block();
+ Block_release(block);
+}
+
+#define DISPATCH_INTERCEPT_B(name) \
+ TSAN_INTERCEPTOR(void, name, dispatch_queue_t q, dispatch_block_t block) { \
+ SCOPED_TSAN_INTERCEPTOR(name, q, block); \
+ SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START(); \
+ dispatch_block_t heap_block = Block_copy(block); \
+ SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END(); \
+ tsan_block_context_t *new_context = \
+ AllocContext(thr, pc, q, heap_block, &invoke_and_release_block); \
+ Release(thr, pc, (uptr)new_context); \
+ SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START(); \
+ REAL(name##_f)(q, new_context, dispatch_callback_wrap_acquire); \
+ SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END(); \
+ }
+
+#define DISPATCH_INTERCEPT_F(name) \
+ TSAN_INTERCEPTOR(void, name, dispatch_queue_t q, void *context, \
+ dispatch_function_t work) { \
+ SCOPED_TSAN_INTERCEPTOR(name, q, context, work); \
+ tsan_block_context_t *new_context = \
+ AllocContext(thr, pc, q, context, work); \
+ Release(thr, pc, (uptr)new_context); \
+ SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START(); \
+ REAL(name)(q, new_context, dispatch_callback_wrap_acquire); \
+ SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END(); \
+ }
+
+// We wrap dispatch_async, dispatch_sync and friends where we allocate a new
+// context, which is used to synchronize (we release the context before
+// submitting, and the callback acquires it before executing the original
+// callback).
+DISPATCH_INTERCEPT_B(dispatch_async)
+DISPATCH_INTERCEPT_B(dispatch_barrier_async)
+DISPATCH_INTERCEPT_F(dispatch_async_f)
+DISPATCH_INTERCEPT_F(dispatch_barrier_async_f)
+DISPATCH_INTERCEPT_B(dispatch_sync)
+DISPATCH_INTERCEPT_B(dispatch_barrier_sync)
+DISPATCH_INTERCEPT_F(dispatch_sync_f)
+DISPATCH_INTERCEPT_F(dispatch_barrier_sync_f)
+
+// GCD's dispatch_once implementation has a fast path that contains a racy read
+// and it's inlined into user's code. Furthermore, this fast path doesn't
+// establish a proper happens-before relations between the initialization and
+// code following the call to dispatch_once. We could deal with this in
+// instrumented code, but there's not much we can do about it in system
+// libraries. Let's disable the fast path (by never storing the value ~0 to
+// predicate), so the interceptor is always called, and let's add proper release
+// and acquire semantics. Since TSan does not see its own atomic stores, the
+// race on predicate won't be reported - the only accesses to it that TSan sees
+// are the loads on the fast path. Loads don't race. Secondly, dispatch_once is
+// both a macro and a real function, we want to intercept the function, so we
+// need to undefine the macro.
+#undef dispatch_once
+TSAN_INTERCEPTOR(void, dispatch_once, dispatch_once_t *predicate,
+ dispatch_block_t block) {
+ SCOPED_TSAN_INTERCEPTOR(dispatch_once, predicate, block);
+ atomic_uint32_t *a = reinterpret_cast<atomic_uint32_t *>(predicate);
+ u32 v = atomic_load(a, memory_order_acquire);
+ if (v == 0 &&
+ atomic_compare_exchange_strong(a, &v, 1, memory_order_relaxed)) {
+ SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START();
+ block();
+ SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END();
+ Release(thr, pc, (uptr)a);
+ atomic_store(a, 2, memory_order_release);
+ } else {
+ while (v != 2) {
+ internal_sched_yield();
+ v = atomic_load(a, memory_order_acquire);
+ }
+ Acquire(thr, pc, (uptr)a);
+ }
+}
+
+#undef dispatch_once_f
+TSAN_INTERCEPTOR(void, dispatch_once_f, dispatch_once_t *predicate,
+ void *context, dispatch_function_t function) {
+ SCOPED_TSAN_INTERCEPTOR(dispatch_once_f, predicate, context, function);
+ SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START();
+ WRAP(dispatch_once)(predicate, ^(void) {
+ function(context);
+ });
+ SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END();
+}
+
+TSAN_INTERCEPTOR(long_t, dispatch_semaphore_signal,
+ dispatch_semaphore_t dsema) {
+ SCOPED_TSAN_INTERCEPTOR(dispatch_semaphore_signal, dsema);
+ Release(thr, pc, (uptr)dsema);
+ return REAL(dispatch_semaphore_signal)(dsema);
+}
+
+TSAN_INTERCEPTOR(long_t, dispatch_semaphore_wait, dispatch_semaphore_t dsema,
+ dispatch_time_t timeout) {
+ SCOPED_TSAN_INTERCEPTOR(dispatch_semaphore_wait, dsema, timeout);
+ long_t result = REAL(dispatch_semaphore_wait)(dsema, timeout);
+ if (result == 0) Acquire(thr, pc, (uptr)dsema);
+ return result;
+}
+
+TSAN_INTERCEPTOR(long_t, dispatch_group_wait, dispatch_group_t group,
+ dispatch_time_t timeout) {
+ SCOPED_TSAN_INTERCEPTOR(dispatch_group_wait, group, timeout);
+ long_t result = REAL(dispatch_group_wait)(group, timeout);
+ if (result == 0) Acquire(thr, pc, (uptr)group);
+ return result;
+}
+
+TSAN_INTERCEPTOR(void, dispatch_group_leave, dispatch_group_t group) {
+ SCOPED_TSAN_INTERCEPTOR(dispatch_group_leave, group);
+ Release(thr, pc, (uptr)group);
+ REAL(dispatch_group_leave)(group);
+}
+
+TSAN_INTERCEPTOR(void, dispatch_group_async, dispatch_group_t group,
+ dispatch_queue_t queue, dispatch_block_t block) {
+ SCOPED_TSAN_INTERCEPTOR(dispatch_group_async, group, queue, block);
+ dispatch_retain(group);
+ dispatch_group_enter(group);
+ WRAP(dispatch_async)(queue, ^(void) {
+ block();
+ WRAP(dispatch_group_leave)(group);
+ dispatch_release(group);
+ });
+}
+
+TSAN_INTERCEPTOR(void, dispatch_group_async_f, dispatch_group_t group,
+ dispatch_queue_t queue, void *context,
+ dispatch_function_t work) {
+ SCOPED_TSAN_INTERCEPTOR(dispatch_group_async_f, group, queue, context, work);
+ dispatch_retain(group);
+ dispatch_group_enter(group);
+ WRAP(dispatch_async)(queue, ^(void) {
+ work(context);
+ WRAP(dispatch_group_leave)(group);
+ dispatch_release(group);
+ });
+}
+
+TSAN_INTERCEPTOR(void, dispatch_group_notify, dispatch_group_t group,
+ dispatch_queue_t q, dispatch_block_t block) {
+ SCOPED_TSAN_INTERCEPTOR(dispatch_group_notify, group, q, block);
+ SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START();
+ dispatch_block_t heap_block = Block_copy(block);
+ SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END();
+ tsan_block_context_t *new_context =
+ AllocContext(thr, pc, q, heap_block, &invoke_and_release_block);
+ new_context->object_to_acquire = (uptr)group;
+
+ // Will be released in dispatch_callback_wrap_acquire.
+ new_context->object_to_release = group;
+ dispatch_retain(group);
+
+ Release(thr, pc, (uptr)group);
+ REAL(dispatch_group_notify_f)(group, q, new_context,
+ dispatch_callback_wrap_acquire);
+}
+
+TSAN_INTERCEPTOR(void, dispatch_group_notify_f, dispatch_group_t group,
+ dispatch_queue_t q, void *context, dispatch_function_t work) {
+ SCOPED_TSAN_INTERCEPTOR(dispatch_group_notify_f, group, q, context, work);
+ tsan_block_context_t *new_context = AllocContext(thr, pc, q, context, work);
+ new_context->object_to_acquire = (uptr)group;
+
+ // Will be released in dispatch_callback_wrap_acquire.
+ new_context->object_to_release = group;
+ dispatch_retain(group);
+
+ Release(thr, pc, (uptr)group);
+ REAL(dispatch_group_notify_f)(group, q, new_context,
+ dispatch_callback_wrap_acquire);
+}
+
+} // namespace __tsan
+
+#endif // SANITIZER_MAC
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_malloc_mac.cc b/contrib/compiler-rt/lib/tsan/rtl/tsan_malloc_mac.cc
new file mode 100644
index 000000000000..7fd94273c314
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_malloc_mac.cc
@@ -0,0 +1,65 @@
+//===-- tsan_malloc_mac.cc ------------------------------------------------===//
+//
+// 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 ThreadSanitizer (TSan), a race detector.
+//
+// Mac-specific malloc interception.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_platform.h"
+#if SANITIZER_MAC
+
+#include "tsan_interceptors.h"
+#include "tsan_stack_trace.h"
+
+using namespace __tsan;
+#define COMMON_MALLOC_ZONE_NAME "tsan"
+#define COMMON_MALLOC_ENTER()
+#define COMMON_MALLOC_SANITIZER_INITIALIZED (cur_thread()->is_inited)
+#define COMMON_MALLOC_FORCE_LOCK()
+#define COMMON_MALLOC_FORCE_UNLOCK()
+#define COMMON_MALLOC_MEMALIGN(alignment, size) \
+ void *p = \
+ user_alloc(cur_thread(), StackTrace::GetCurrentPc(), size, alignment)
+#define COMMON_MALLOC_MALLOC(size) \
+ if (cur_thread()->in_symbolizer) \
+ return REAL(malloc)(size); \
+ SCOPED_INTERCEPTOR_RAW(malloc, size); \
+ void *p = user_alloc(thr, pc, size)
+#define COMMON_MALLOC_REALLOC(ptr, size) \
+ if (cur_thread()->in_symbolizer) \
+ return REAL(realloc)(ptr, size); \
+ SCOPED_INTERCEPTOR_RAW(realloc, ptr, size); \
+ void *p = user_realloc(thr, pc, ptr, size)
+#define COMMON_MALLOC_CALLOC(count, size) \
+ if (cur_thread()->in_symbolizer) \
+ return REAL(calloc)(count, size); \
+ SCOPED_INTERCEPTOR_RAW(calloc, size, count); \
+ void *p = user_calloc(thr, pc, size, count)
+#define COMMON_MALLOC_VALLOC(size) \
+ if (cur_thread()->in_symbolizer) \
+ return REAL(valloc)(size); \
+ SCOPED_INTERCEPTOR_RAW(valloc, size); \
+ void *p = user_alloc(thr, pc, size, GetPageSizeCached())
+#define COMMON_MALLOC_FREE(ptr) \
+ if (cur_thread()->in_symbolizer) \
+ return REAL(free)(ptr); \
+ SCOPED_INTERCEPTOR_RAW(free, ptr); \
+ user_free(thr, pc, ptr)
+#define COMMON_MALLOC_SIZE(ptr) \
+ uptr size = user_alloc_usable_size(ptr);
+#define COMMON_MALLOC_FILL_STATS(zone, stats)
+#define COMMON_MALLOC_REPORT_UNKNOWN_REALLOC(ptr, zone_ptr, zone_name) \
+ (void)zone_name; \
+ Report("mz_realloc(%p) -- attempting to realloc unallocated memory.\n", ptr);
+#define COMMON_MALLOC_NAMESPACE __tsan
+
+#include "sanitizer_common/sanitizer_malloc_mac.inc"
+
+#endif
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_mman.cc b/contrib/compiler-rt/lib/tsan/rtl/tsan_mman.cc
index 12a616ff5ae8..7247c6e00035 100644
--- a/contrib/compiler-rt/lib/tsan/rtl/tsan_mman.cc
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_mman.cc
@@ -19,12 +19,14 @@
#include "tsan_flags.h"
// May be overriden by front-end.
-extern "C" void WEAK __sanitizer_malloc_hook(void *ptr, uptr size) {
+SANITIZER_WEAK_DEFAULT_IMPL
+void __sanitizer_malloc_hook(void *ptr, uptr size) {
(void)ptr;
(void)size;
}
-extern "C" void WEAK __sanitizer_free_hook(void *ptr) {
+SANITIZER_WEAK_DEFAULT_IMPL
+void __sanitizer_free_hook(void *ptr) {
(void)ptr;
}
@@ -80,17 +82,17 @@ void AllocatorPrintStats() {
}
static void SignalUnsafeCall(ThreadState *thr, uptr pc) {
- if (atomic_load(&thr->in_signal_handler, memory_order_relaxed) == 0 ||
+ if (atomic_load_relaxed(&thr->in_signal_handler) == 0 ||
!flags()->report_signal_unsafe)
return;
VarSizeStackTrace stack;
ObtainCurrentStack(thr, pc, &stack);
+ if (IsFiredSuppression(ctx, ReportTypeSignalUnsafe, stack))
+ return;
ThreadRegistryLock l(ctx->thread_registry);
ScopedReport rep(ReportTypeSignalUnsafe);
- if (!IsFiredSuppression(ctx, rep, stack)) {
- rep.AddStack(stack, true);
- OutputReport(thr, rep);
- }
+ rep.AddStack(stack, true);
+ OutputReport(thr, rep);
}
void *user_alloc(ThreadState *thr, uptr pc, uptr sz, uptr align, bool signal) {
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_mman.h b/contrib/compiler-rt/lib/tsan/rtl/tsan_mman.h
index 5ff956d827f6..b419b58ca457 100644
--- a/contrib/compiler-rt/lib/tsan/rtl/tsan_mman.h
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_mman.h
@@ -20,6 +20,7 @@ namespace __tsan {
const uptr kDefaultAlignment = 16;
void InitializeAllocator();
+void ReplaceSystemMalloc();
void AllocatorThreadStart(ThreadState *thr);
void AllocatorThreadFinish(ThreadState *thr);
void AllocatorPrintStats();
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_mutex.cc b/contrib/compiler-rt/lib/tsan/rtl/tsan_mutex.cc
index dc5a462a8081..9dd24803b183 100644
--- a/contrib/compiler-rt/lib/tsan/rtl/tsan_mutex.cc
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_mutex.cc
@@ -41,6 +41,8 @@ static MutexType CanLockTab[MutexTypeCount][MutexTypeCount] = {
/*9 MutexTypeMBlock*/ {MutexTypeSyncVar},
/*10 MutexTypeJavaMBlock*/ {MutexTypeSyncVar},
/*11 MutexTypeDDetector*/ {},
+ /*12 MutexTypeFired*/ {MutexTypeLeaf},
+ /*13 MutexTypeRacy*/ {MutexTypeLeaf},
};
static bool CanLockAdj[MutexTypeCount][MutexTypeCount];
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_mutex.h b/contrib/compiler-rt/lib/tsan/rtl/tsan_mutex.h
index 88fad57c78a0..27f55385c959 100644
--- a/contrib/compiler-rt/lib/tsan/rtl/tsan_mutex.h
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_mutex.h
@@ -32,6 +32,8 @@ enum MutexType {
MutexTypeMBlock,
MutexTypeJavaMBlock,
MutexTypeDDetector,
+ MutexTypeFired,
+ MutexTypeRacy,
// This must be the last.
MutexTypeCount
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_new_delete.cc b/contrib/compiler-rt/lib/tsan/rtl/tsan_new_delete.cc
index 2d9d044e42fa..ebb422cf2023 100644
--- a/contrib/compiler-rt/lib/tsan/rtl/tsan_new_delete.cc
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_new_delete.cc
@@ -11,6 +11,7 @@
//
// Interceptors for operators new and delete.
//===----------------------------------------------------------------------===//
+#include "interception/interception.h"
#include "sanitizer_common/sanitizer_internal_defs.h"
#include "tsan_interceptors.h"
@@ -20,6 +21,13 @@ namespace std {
struct nothrow_t {};
} // namespace std
+DECLARE_REAL(void *, malloc, uptr size)
+DECLARE_REAL(void, free, void *ptr)
+#if SANITIZER_MAC || SANITIZER_ANDROID
+#define __libc_malloc REAL(malloc)
+#define __libc_free REAL(free)
+#endif
+
#define OPERATOR_NEW_BODY(mangled_name) \
if (cur_thread()->in_symbolizer) \
return __libc_malloc(size); \
@@ -64,14 +72,14 @@ void *operator new[](__sanitizer::uptr size, std::nothrow_t const&) {
user_free(thr, pc, ptr);
SANITIZER_INTERFACE_ATTRIBUTE
-void operator delete(void *ptr) throw();
-void operator delete(void *ptr) throw() {
+void operator delete(void *ptr) NOEXCEPT;
+void operator delete(void *ptr) NOEXCEPT {
OPERATOR_DELETE_BODY(_ZdlPv);
}
SANITIZER_INTERFACE_ATTRIBUTE
-void operator delete[](void *ptr) throw();
-void operator delete[](void *ptr) throw() {
+void operator delete[](void *ptr) NOEXCEPT;
+void operator delete[](void *ptr) NOEXCEPT {
OPERATOR_DELETE_BODY(_ZdaPv);
}
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_platform.h b/contrib/compiler-rt/lib/tsan/rtl/tsan_platform.h
index 135e16027132..c2b487155300 100644
--- a/contrib/compiler-rt/lib/tsan/rtl/tsan_platform.h
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_platform.h
@@ -41,21 +41,23 @@ C/C++ on linux/x86_64 and freebsd/x86_64
7e00 0000 0000 - 7e80 0000 0000: -
7e80 0000 0000 - 8000 0000 0000: modules and main thread stack
*/
-const uptr kMetaShadowBeg = 0x300000000000ull;
-const uptr kMetaShadowEnd = 0x400000000000ull;
-const uptr kTraceMemBeg = 0x600000000000ull;
-const uptr kTraceMemEnd = 0x620000000000ull;
-const uptr kShadowBeg = 0x020000000000ull;
-const uptr kShadowEnd = 0x100000000000ull;
-const uptr kHeapMemBeg = 0x7d0000000000ull;
-const uptr kHeapMemEnd = 0x7e0000000000ull;
-const uptr kLoAppMemBeg = 0x000000001000ull;
-const uptr kLoAppMemEnd = 0x010000000000ull;
-const uptr kHiAppMemBeg = 0x7e8000000000ull;
-const uptr kHiAppMemEnd = 0x800000000000ull;
-const uptr kAppMemMsk = 0x7c0000000000ull;
-const uptr kAppMemXor = 0x020000000000ull;
-const uptr kVdsoBeg = 0xf000000000000000ull;
+struct Mapping {
+ static const uptr kMetaShadowBeg = 0x300000000000ull;
+ static const uptr kMetaShadowEnd = 0x400000000000ull;
+ static const uptr kTraceMemBeg = 0x600000000000ull;
+ static const uptr kTraceMemEnd = 0x620000000000ull;
+ static const uptr kShadowBeg = 0x020000000000ull;
+ static const uptr kShadowEnd = 0x100000000000ull;
+ static const uptr kHeapMemBeg = 0x7d0000000000ull;
+ static const uptr kHeapMemEnd = 0x7e0000000000ull;
+ static const uptr kLoAppMemBeg = 0x000000001000ull;
+ static const uptr kLoAppMemEnd = 0x010000000000ull;
+ static const uptr kHiAppMemBeg = 0x7e8000000000ull;
+ static const uptr kHiAppMemEnd = 0x800000000000ull;
+ static const uptr kAppMemMsk = 0x7c0000000000ull;
+ static const uptr kAppMemXor = 0x020000000000ull;
+ static const uptr kVdsoBeg = 0xf000000000000000ull;
+};
#elif defined(__mips64)
/*
C/C++ on linux/mips64
@@ -71,69 +73,181 @@ fe00 0000 00 - ff00 0000 00: heap
ff00 0000 00 - ff80 0000 00: -
ff80 0000 00 - ffff ffff ff: modules and main thread stack
*/
-const uptr kMetaShadowBeg = 0x3000000000ull;
-const uptr kMetaShadowEnd = 0x4000000000ull;
-const uptr kTraceMemBeg = 0x6000000000ull;
-const uptr kTraceMemEnd = 0x6200000000ull;
-const uptr kShadowBeg = 0x1400000000ull;
-const uptr kShadowEnd = 0x2400000000ull;
-const uptr kHeapMemBeg = 0xfe00000000ull;
-const uptr kHeapMemEnd = 0xff00000000ull;
-const uptr kLoAppMemBeg = 0x0100000000ull;
-const uptr kLoAppMemEnd = 0x0200000000ull;
-const uptr kHiAppMemBeg = 0xff80000000ull;
-const uptr kHiAppMemEnd = 0xffffffffffull;
-const uptr kAppMemMsk = 0xfc00000000ull;
-const uptr kAppMemXor = 0x0400000000ull;
-const uptr kVdsoBeg = 0xfffff00000ull;
-#endif
-
-ALWAYS_INLINE
-bool IsAppMem(uptr mem) {
- return (mem >= kHeapMemBeg && mem < kHeapMemEnd) ||
- (mem >= kLoAppMemBeg && mem < kLoAppMemEnd) ||
- (mem >= kHiAppMemBeg && mem < kHiAppMemEnd);
-}
-
-ALWAYS_INLINE
-bool IsShadowMem(uptr mem) {
- return mem >= kShadowBeg && mem <= kShadowEnd;
-}
+struct Mapping {
+ static const uptr kMetaShadowBeg = 0x3000000000ull;
+ static const uptr kMetaShadowEnd = 0x4000000000ull;
+ static const uptr kTraceMemBeg = 0x6000000000ull;
+ static const uptr kTraceMemEnd = 0x6200000000ull;
+ static const uptr kShadowBeg = 0x1400000000ull;
+ static const uptr kShadowEnd = 0x2400000000ull;
+ static const uptr kHeapMemBeg = 0xfe00000000ull;
+ static const uptr kHeapMemEnd = 0xff00000000ull;
+ static const uptr kLoAppMemBeg = 0x0100000000ull;
+ static const uptr kLoAppMemEnd = 0x0200000000ull;
+ static const uptr kHiAppMemBeg = 0xff80000000ull;
+ static const uptr kHiAppMemEnd = 0xffffffffffull;
+ static const uptr kAppMemMsk = 0xfc00000000ull;
+ static const uptr kAppMemXor = 0x0400000000ull;
+ static const uptr kVdsoBeg = 0xfffff00000ull;
+};
+#elif defined(__aarch64__)
+// AArch64 supports multiple VMA which leads to multiple address transformation
+// functions. To support these multiple VMAS transformations and mappings TSAN
+// runtime for AArch64 uses an external memory read (vmaSize) to select which
+// mapping to use. Although slower, it make a same instrumented binary run on
+// multiple kernels.
-ALWAYS_INLINE
-bool IsMetaMem(uptr mem) {
- return mem >= kMetaShadowBeg && mem <= kMetaShadowEnd;
-}
+/*
+C/C++ on linux/aarch64 (39-bit VMA)
+0000 0010 00 - 0100 0000 00: main binary
+0100 0000 00 - 0800 0000 00: -
+0800 0000 00 - 2000 0000 00: shadow memory
+2000 0000 00 - 3100 0000 00: -
+3100 0000 00 - 3400 0000 00: metainfo
+3400 0000 00 - 5500 0000 00: -
+5500 0000 00 - 5600 0000 00: main binary (PIE)
+5600 0000 00 - 6000 0000 00: -
+6000 0000 00 - 6200 0000 00: traces
+6200 0000 00 - 7d00 0000 00: -
+7c00 0000 00 - 7d00 0000 00: heap
+7d00 0000 00 - 7fff ffff ff: modules and main thread stack
+*/
+struct Mapping39 {
+ static const uptr kLoAppMemBeg = 0x0000001000ull;
+ static const uptr kLoAppMemEnd = 0x0100000000ull;
+ static const uptr kShadowBeg = 0x0800000000ull;
+ static const uptr kShadowEnd = 0x2000000000ull;
+ static const uptr kMetaShadowBeg = 0x3100000000ull;
+ static const uptr kMetaShadowEnd = 0x3400000000ull;
+ static const uptr kMidAppMemBeg = 0x5500000000ull;
+ static const uptr kMidAppMemEnd = 0x5600000000ull;
+ static const uptr kMidShadowOff = 0x5000000000ull;
+ static const uptr kTraceMemBeg = 0x6000000000ull;
+ static const uptr kTraceMemEnd = 0x6200000000ull;
+ static const uptr kHeapMemBeg = 0x7c00000000ull;
+ static const uptr kHeapMemEnd = 0x7d00000000ull;
+ static const uptr kHiAppMemBeg = 0x7e00000000ull;
+ static const uptr kHiAppMemEnd = 0x7fffffffffull;
+ static const uptr kAppMemMsk = 0x7800000000ull;
+ static const uptr kAppMemXor = 0x0200000000ull;
+ static const uptr kVdsoBeg = 0x7f00000000ull;
+};
-ALWAYS_INLINE
-uptr MemToShadow(uptr x) {
- DCHECK(IsAppMem(x));
- return (((x) & ~(kAppMemMsk | (kShadowCell - 1)))
- ^ kAppMemXor) * kShadowCnt;
-}
+/*
+C/C++ on linux/aarch64 (42-bit VMA)
+00000 0010 00 - 01000 0000 00: main binary
+01000 0000 00 - 10000 0000 00: -
+10000 0000 00 - 20000 0000 00: shadow memory
+20000 0000 00 - 26000 0000 00: -
+26000 0000 00 - 28000 0000 00: metainfo
+28000 0000 00 - 2aa00 0000 00: -
+2aa00 0000 00 - 2ab00 0000 00: main binary (PIE)
+2ab00 0000 00 - 36200 0000 00: -
+36200 0000 00 - 36240 0000 00: traces
+36240 0000 00 - 3e000 0000 00: -
+3e000 0000 00 - 3f000 0000 00: heap
+3f000 0000 00 - 3ffff ffff ff: modules and main thread stack
+*/
+struct Mapping42 {
+ static const uptr kLoAppMemBeg = 0x00000001000ull;
+ static const uptr kLoAppMemEnd = 0x01000000000ull;
+ static const uptr kShadowBeg = 0x10000000000ull;
+ static const uptr kShadowEnd = 0x20000000000ull;
+ static const uptr kMetaShadowBeg = 0x26000000000ull;
+ static const uptr kMetaShadowEnd = 0x28000000000ull;
+ static const uptr kMidAppMemBeg = 0x2aa00000000ull;
+ static const uptr kMidAppMemEnd = 0x2ab00000000ull;
+ static const uptr kMidShadowOff = 0x28000000000ull;
+ static const uptr kTraceMemBeg = 0x36200000000ull;
+ static const uptr kTraceMemEnd = 0x36400000000ull;
+ static const uptr kHeapMemBeg = 0x3e000000000ull;
+ static const uptr kHeapMemEnd = 0x3f000000000ull;
+ static const uptr kHiAppMemBeg = 0x3f000000000ull;
+ static const uptr kHiAppMemEnd = 0x3ffffffffffull;
+ static const uptr kAppMemMsk = 0x3c000000000ull;
+ static const uptr kAppMemXor = 0x04000000000ull;
+ static const uptr kVdsoBeg = 0x37f00000000ull;
+};
-ALWAYS_INLINE
-u32 *MemToMeta(uptr x) {
- DCHECK(IsAppMem(x));
- return (u32*)(((((x) & ~(kAppMemMsk | (kMetaShadowCell - 1)))
- ^ kAppMemXor) / kMetaShadowCell * kMetaShadowSize) | kMetaShadowBeg);
-}
+// Indicates the runtime will define the memory regions at runtime.
+#define TSAN_RUNTIME_VMA 1
+// Indicates that mapping defines a mid range memory segment.
+#define TSAN_MID_APP_RANGE 1
+#elif defined(__powerpc64__)
+// PPC64 supports multiple VMA which leads to multiple address transformation
+// functions. To support these multiple VMAS transformations and mappings TSAN
+// runtime for PPC64 uses an external memory read (vmaSize) to select which
+// mapping to use. Although slower, it make a same instrumented binary run on
+// multiple kernels.
-ALWAYS_INLINE
-uptr ShadowToMem(uptr s) {
- CHECK(IsShadowMem(s));
- if (s >= MemToShadow(kLoAppMemBeg) && s <= MemToShadow(kLoAppMemEnd - 1))
- return (s / kShadowCnt) ^ kAppMemXor;
- else
- return ((s / kShadowCnt) ^ kAppMemXor) | kAppMemMsk;
-}
+/*
+C/C++ on linux/powerpc64 (44-bit VMA)
+0000 0000 0100 - 0001 0000 0000: main binary
+0001 0000 0000 - 0001 0000 0000: -
+0001 0000 0000 - 0b00 0000 0000: shadow
+0b00 0000 0000 - 0b00 0000 0000: -
+0b00 0000 0000 - 0d00 0000 0000: metainfo (memory blocks and sync objects)
+0d00 0000 0000 - 0d00 0000 0000: -
+0d00 0000 0000 - 0f00 0000 0000: traces
+0f00 0000 0000 - 0f00 0000 0000: -
+0f00 0000 0000 - 0f50 0000 0000: heap
+0f50 0000 0000 - 0f60 0000 0000: -
+0f60 0000 0000 - 1000 0000 0000: modules and main thread stack
+*/
+struct Mapping44 {
+ static const uptr kMetaShadowBeg = 0x0b0000000000ull;
+ static const uptr kMetaShadowEnd = 0x0d0000000000ull;
+ static const uptr kTraceMemBeg = 0x0d0000000000ull;
+ static const uptr kTraceMemEnd = 0x0f0000000000ull;
+ static const uptr kShadowBeg = 0x000100000000ull;
+ static const uptr kShadowEnd = 0x0b0000000000ull;
+ static const uptr kLoAppMemBeg = 0x000000000100ull;
+ static const uptr kLoAppMemEnd = 0x000100000000ull;
+ static const uptr kHeapMemBeg = 0x0f0000000000ull;
+ static const uptr kHeapMemEnd = 0x0f5000000000ull;
+ static const uptr kHiAppMemBeg = 0x0f6000000000ull;
+ static const uptr kHiAppMemEnd = 0x100000000000ull; // 44 bits
+ static const uptr kAppMemMsk = 0x0f0000000000ull;
+ static const uptr kAppMemXor = 0x002100000000ull;
+ static const uptr kVdsoBeg = 0x3c0000000000000ull;
+};
-static USED uptr UserRegions[] = {
- kLoAppMemBeg, kLoAppMemEnd,
- kHiAppMemBeg, kHiAppMemEnd,
- kHeapMemBeg, kHeapMemEnd,
+/*
+C/C++ on linux/powerpc64 (46-bit VMA)
+0000 0000 1000 - 0100 0000 0000: main binary
+0100 0000 0000 - 0200 0000 0000: -
+0100 0000 0000 - 1000 0000 0000: shadow
+1000 0000 0000 - 1000 0000 0000: -
+1000 0000 0000 - 2000 0000 0000: metainfo (memory blocks and sync objects)
+2000 0000 0000 - 2000 0000 0000: -
+2000 0000 0000 - 2200 0000 0000: traces
+2200 0000 0000 - 3d00 0000 0000: -
+3d00 0000 0000 - 3e00 0000 0000: heap
+3e00 0000 0000 - 3e80 0000 0000: -
+3e80 0000 0000 - 4000 0000 0000: modules and main thread stack
+*/
+struct Mapping46 {
+ static const uptr kMetaShadowBeg = 0x100000000000ull;
+ static const uptr kMetaShadowEnd = 0x200000000000ull;
+ static const uptr kTraceMemBeg = 0x200000000000ull;
+ static const uptr kTraceMemEnd = 0x220000000000ull;
+ static const uptr kShadowBeg = 0x010000000000ull;
+ static const uptr kShadowEnd = 0x100000000000ull;
+ static const uptr kHeapMemBeg = 0x3d0000000000ull;
+ static const uptr kHeapMemEnd = 0x3e0000000000ull;
+ static const uptr kLoAppMemBeg = 0x000000001000ull;
+ static const uptr kLoAppMemEnd = 0x010000000000ull;
+ static const uptr kHiAppMemBeg = 0x3e8000000000ull;
+ static const uptr kHiAppMemEnd = 0x400000000000ull; // 46 bits
+ static const uptr kAppMemMsk = 0x3c0000000000ull;
+ static const uptr kAppMemXor = 0x020000000000ull;
+ static const uptr kVdsoBeg = 0x7800000000000000ull;
};
+// Indicates the runtime will define the memory regions at runtime.
+#define TSAN_RUNTIME_VMA 1
+#endif
+
#elif defined(SANITIZER_GO) && !SANITIZER_WINDOWS
/* Go on linux, darwin and freebsd
@@ -149,138 +263,495 @@ static USED uptr UserRegions[] = {
6200 0000 0000 - 8000 0000 0000: -
*/
-const uptr kMetaShadowBeg = 0x300000000000ull;
-const uptr kMetaShadowEnd = 0x400000000000ull;
-const uptr kTraceMemBeg = 0x600000000000ull;
-const uptr kTraceMemEnd = 0x620000000000ull;
-const uptr kShadowBeg = 0x200000000000ull;
-const uptr kShadowEnd = 0x238000000000ull;
-const uptr kAppMemBeg = 0x000000001000ull;
-const uptr kAppMemEnd = 0x00e000000000ull;
+struct Mapping {
+ static const uptr kMetaShadowBeg = 0x300000000000ull;
+ static const uptr kMetaShadowEnd = 0x400000000000ull;
+ static const uptr kTraceMemBeg = 0x600000000000ull;
+ static const uptr kTraceMemEnd = 0x620000000000ull;
+ static const uptr kShadowBeg = 0x200000000000ull;
+ static const uptr kShadowEnd = 0x238000000000ull;
+ static const uptr kAppMemBeg = 0x000000001000ull;
+ static const uptr kAppMemEnd = 0x00e000000000ull;
+};
+
+#elif defined(SANITIZER_GO) && SANITIZER_WINDOWS
+
+/* Go on windows
+0000 0000 1000 - 0000 1000 0000: executable
+0000 1000 0000 - 00f8 0000 0000: -
+00c0 0000 0000 - 00e0 0000 0000: heap
+00e0 0000 0000 - 0100 0000 0000: -
+0100 0000 0000 - 0500 0000 0000: shadow
+0500 0000 0000 - 0560 0000 0000: -
+0560 0000 0000 - 0760 0000 0000: traces
+0760 0000 0000 - 07d0 0000 0000: metainfo (memory blocks and sync objects)
+07d0 0000 0000 - 8000 0000 0000: -
+*/
+
+struct Mapping {
+ static const uptr kMetaShadowBeg = 0x076000000000ull;
+ static const uptr kMetaShadowEnd = 0x07d000000000ull;
+ static const uptr kTraceMemBeg = 0x056000000000ull;
+ static const uptr kTraceMemEnd = 0x076000000000ull;
+ static const uptr kShadowBeg = 0x010000000000ull;
+ static const uptr kShadowEnd = 0x050000000000ull;
+ static const uptr kAppMemBeg = 0x000000001000ull;
+ static const uptr kAppMemEnd = 0x00e000000000ull;
+}
+
+#else
+# error "Unknown platform"
+#endif
+
+
+#ifdef TSAN_RUNTIME_VMA
+extern uptr vmaSize;
+#endif
+
+
+enum MappingType {
+ MAPPING_LO_APP_BEG,
+ MAPPING_LO_APP_END,
+ MAPPING_HI_APP_BEG,
+ MAPPING_HI_APP_END,
+#ifdef TSAN_MID_APP_RANGE
+ MAPPING_MID_APP_BEG,
+ MAPPING_MID_APP_END,
+#endif
+ MAPPING_HEAP_BEG,
+ MAPPING_HEAP_END,
+ MAPPING_APP_BEG,
+ MAPPING_APP_END,
+ MAPPING_SHADOW_BEG,
+ MAPPING_SHADOW_END,
+ MAPPING_META_SHADOW_BEG,
+ MAPPING_META_SHADOW_END,
+ MAPPING_TRACE_BEG,
+ MAPPING_TRACE_END,
+ MAPPING_VDSO_BEG,
+};
+
+template<typename Mapping, int Type>
+uptr MappingImpl(void) {
+ switch (Type) {
+#ifndef SANITIZER_GO
+ case MAPPING_LO_APP_BEG: return Mapping::kLoAppMemBeg;
+ case MAPPING_LO_APP_END: return Mapping::kLoAppMemEnd;
+# ifdef TSAN_MID_APP_RANGE
+ case MAPPING_MID_APP_BEG: return Mapping::kMidAppMemBeg;
+ case MAPPING_MID_APP_END: return Mapping::kMidAppMemEnd;
+# endif
+ case MAPPING_HI_APP_BEG: return Mapping::kHiAppMemBeg;
+ case MAPPING_HI_APP_END: return Mapping::kHiAppMemEnd;
+ case MAPPING_HEAP_BEG: return Mapping::kHeapMemBeg;
+ case MAPPING_HEAP_END: return Mapping::kHeapMemEnd;
+ case MAPPING_VDSO_BEG: return Mapping::kVdsoBeg;
+#else
+ case MAPPING_APP_BEG: return Mapping::kAppMemBeg;
+ case MAPPING_APP_END: return Mapping::kAppMemEnd;
+#endif
+ case MAPPING_SHADOW_BEG: return Mapping::kShadowBeg;
+ case MAPPING_SHADOW_END: return Mapping::kShadowEnd;
+ case MAPPING_META_SHADOW_BEG: return Mapping::kMetaShadowBeg;
+ case MAPPING_META_SHADOW_END: return Mapping::kMetaShadowEnd;
+ case MAPPING_TRACE_BEG: return Mapping::kTraceMemBeg;
+ case MAPPING_TRACE_END: return Mapping::kTraceMemEnd;
+ }
+}
+
+template<int Type>
+uptr MappingArchImpl(void) {
+#ifdef __aarch64__
+ if (vmaSize == 39)
+ return MappingImpl<Mapping39, Type>();
+ else
+ return MappingImpl<Mapping42, Type>();
+ DCHECK(0);
+#elif defined(__powerpc64__)
+ if (vmaSize == 44)
+ return MappingImpl<Mapping44, Type>();
+ else
+ return MappingImpl<Mapping46, Type>();
+ DCHECK(0);
+#else
+ return MappingImpl<Mapping, Type>();
+#endif
+}
+#ifndef SANITIZER_GO
ALWAYS_INLINE
-bool IsAppMem(uptr mem) {
- return mem >= kAppMemBeg && mem < kAppMemEnd;
+uptr LoAppMemBeg(void) {
+ return MappingArchImpl<MAPPING_LO_APP_BEG>();
+}
+ALWAYS_INLINE
+uptr LoAppMemEnd(void) {
+ return MappingArchImpl<MAPPING_LO_APP_END>();
}
+#ifdef TSAN_MID_APP_RANGE
ALWAYS_INLINE
-bool IsShadowMem(uptr mem) {
- return mem >= kShadowBeg && mem <= kShadowEnd;
+uptr MidAppMemBeg(void) {
+ return MappingArchImpl<MAPPING_MID_APP_BEG>();
+}
+ALWAYS_INLINE
+uptr MidAppMemEnd(void) {
+ return MappingArchImpl<MAPPING_MID_APP_END>();
}
+#endif
ALWAYS_INLINE
-bool IsMetaMem(uptr mem) {
- return mem >= kMetaShadowBeg && mem <= kMetaShadowEnd;
+uptr HeapMemBeg(void) {
+ return MappingArchImpl<MAPPING_HEAP_BEG>();
+}
+ALWAYS_INLINE
+uptr HeapMemEnd(void) {
+ return MappingArchImpl<MAPPING_HEAP_END>();
}
ALWAYS_INLINE
-uptr MemToShadow(uptr x) {
- DCHECK(IsAppMem(x));
- return ((x & ~(kShadowCell - 1)) * kShadowCnt) | kShadowBeg;
+uptr HiAppMemBeg(void) {
+ return MappingArchImpl<MAPPING_HI_APP_BEG>();
+}
+ALWAYS_INLINE
+uptr HiAppMemEnd(void) {
+ return MappingArchImpl<MAPPING_HI_APP_END>();
}
ALWAYS_INLINE
-u32 *MemToMeta(uptr x) {
- DCHECK(IsAppMem(x));
- return (u32*)(((x & ~(kMetaShadowCell - 1)) / \
- kMetaShadowCell * kMetaShadowSize) | kMetaShadowBeg);
+uptr VdsoBeg(void) {
+ return MappingArchImpl<MAPPING_VDSO_BEG>();
}
+#else
+
ALWAYS_INLINE
-uptr ShadowToMem(uptr s) {
- CHECK(IsShadowMem(s));
- return (s & ~kShadowBeg) / kShadowCnt;
+uptr AppMemBeg(void) {
+ return MappingArchImpl<MAPPING_APP_BEG>();
+}
+ALWAYS_INLINE
+uptr AppMemEnd(void) {
+ return MappingArchImpl<MAPPING_APP_END>();
}
-static USED uptr UserRegions[] = {
- kAppMemBeg, kAppMemEnd,
-};
+#endif
-#elif defined(SANITIZER_GO) && SANITIZER_WINDOWS
+static inline
+bool GetUserRegion(int i, uptr *start, uptr *end) {
+ switch (i) {
+ default:
+ return false;
+#ifndef SANITIZER_GO
+ case 0:
+ *start = LoAppMemBeg();
+ *end = LoAppMemEnd();
+ return true;
+ case 1:
+ *start = HiAppMemBeg();
+ *end = HiAppMemEnd();
+ return true;
+ case 2:
+ *start = HeapMemBeg();
+ *end = HeapMemEnd();
+ return true;
+# ifdef TSAN_MID_APP_RANGE
+ case 3:
+ *start = MidAppMemBeg();
+ *end = MidAppMemEnd();
+ return true;
+# endif
+#else
+ case 0:
+ *start = AppMemBeg();
+ *end = AppMemEnd();
+ return true;
+#endif
+ }
+}
-/* Go on windows
-0000 0000 1000 - 0000 1000 0000: executable
-0000 1000 0000 - 00f8 0000 0000: -
-00c0 0000 0000 - 00e0 0000 0000: heap
-00e0 0000 0000 - 0100 0000 0000: -
-0100 0000 0000 - 0500 0000 0000: shadow
-0500 0000 0000 - 0560 0000 0000: -
-0560 0000 0000 - 0760 0000 0000: traces
-0760 0000 0000 - 07d0 0000 0000: metainfo (memory blocks and sync objects)
-07d0 0000 0000 - 8000 0000 0000: -
-*/
+ALWAYS_INLINE
+uptr ShadowBeg(void) {
+ return MappingArchImpl<MAPPING_SHADOW_BEG>();
+}
+ALWAYS_INLINE
+uptr ShadowEnd(void) {
+ return MappingArchImpl<MAPPING_SHADOW_END>();
+}
+
+ALWAYS_INLINE
+uptr MetaShadowBeg(void) {
+ return MappingArchImpl<MAPPING_META_SHADOW_BEG>();
+}
+ALWAYS_INLINE
+uptr MetaShadowEnd(void) {
+ return MappingArchImpl<MAPPING_META_SHADOW_END>();
+}
+
+ALWAYS_INLINE
+uptr TraceMemBeg(void) {
+ return MappingArchImpl<MAPPING_TRACE_BEG>();
+}
+ALWAYS_INLINE
+uptr TraceMemEnd(void) {
+ return MappingArchImpl<MAPPING_TRACE_END>();
+}
-const uptr kMetaShadowBeg = 0x076000000000ull;
-const uptr kMetaShadowEnd = 0x07d000000000ull;
-const uptr kTraceMemBeg = 0x056000000000ull;
-const uptr kTraceMemEnd = 0x076000000000ull;
-const uptr kShadowBeg = 0x010000000000ull;
-const uptr kShadowEnd = 0x050000000000ull;
-const uptr kAppMemBeg = 0x000000001000ull;
-const uptr kAppMemEnd = 0x00e000000000ull;
+
+template<typename Mapping>
+bool IsAppMemImpl(uptr mem) {
+#ifndef SANITIZER_GO
+ return (mem >= Mapping::kHeapMemBeg && mem < Mapping::kHeapMemEnd) ||
+# ifdef TSAN_MID_APP_RANGE
+ (mem >= Mapping::kMidAppMemBeg && mem < Mapping::kMidAppMemEnd) ||
+# endif
+ (mem >= Mapping::kLoAppMemBeg && mem < Mapping::kLoAppMemEnd) ||
+ (mem >= Mapping::kHiAppMemBeg && mem < Mapping::kHiAppMemEnd);
+#else
+ return mem >= Mapping::kAppMemBeg && mem < Mapping::kAppMemEnd;
+#endif
+}
ALWAYS_INLINE
bool IsAppMem(uptr mem) {
- return mem >= kAppMemBeg && mem < kAppMemEnd;
+#ifdef __aarch64__
+ if (vmaSize == 39)
+ return IsAppMemImpl<Mapping39>(mem);
+ else
+ return IsAppMemImpl<Mapping42>(mem);
+ DCHECK(0);
+#elif defined(__powerpc64__)
+ if (vmaSize == 44)
+ return IsAppMemImpl<Mapping44>(mem);
+ else
+ return IsAppMemImpl<Mapping46>(mem);
+ DCHECK(0);
+#else
+ return IsAppMemImpl<Mapping>(mem);
+#endif
+}
+
+
+template<typename Mapping>
+bool IsShadowMemImpl(uptr mem) {
+ return mem >= Mapping::kShadowBeg && mem <= Mapping::kShadowEnd;
}
ALWAYS_INLINE
bool IsShadowMem(uptr mem) {
- return mem >= kShadowBeg && mem <= kShadowEnd;
+#ifdef __aarch64__
+ if (vmaSize == 39)
+ return IsShadowMemImpl<Mapping39>(mem);
+ else
+ return IsShadowMemImpl<Mapping42>(mem);
+ DCHECK(0);
+#elif defined(__powerpc64__)
+ if (vmaSize == 44)
+ return IsShadowMemImpl<Mapping44>(mem);
+ else
+ return IsShadowMemImpl<Mapping46>(mem);
+ DCHECK(0);
+#else
+ return IsShadowMemImpl<Mapping>(mem);
+#endif
+}
+
+
+template<typename Mapping>
+bool IsMetaMemImpl(uptr mem) {
+ return mem >= Mapping::kMetaShadowBeg && mem <= Mapping::kMetaShadowEnd;
}
ALWAYS_INLINE
bool IsMetaMem(uptr mem) {
- return mem >= kMetaShadowBeg && mem <= kMetaShadowEnd;
+#ifdef __aarch64__
+ if (vmaSize == 39)
+ return IsMetaMemImpl<Mapping39>(mem);
+ else
+ return IsMetaMemImpl<Mapping42>(mem);
+ DCHECK(0);
+#elif defined(__powerpc64__)
+ if (vmaSize == 44)
+ return IsMetaMemImpl<Mapping44>(mem);
+ else
+ return IsMetaMemImpl<Mapping46>(mem);
+ DCHECK(0);
+#else
+ return IsMetaMemImpl<Mapping>(mem);
+#endif
}
-ALWAYS_INLINE
-uptr MemToShadow(uptr x) {
+
+template<typename Mapping>
+uptr MemToShadowImpl(uptr x) {
DCHECK(IsAppMem(x));
- return ((x & ~(kShadowCell - 1)) * kShadowCnt) + kShadowBeg;
+#ifndef SANITIZER_GO
+ return (((x) & ~(Mapping::kAppMemMsk | (kShadowCell - 1)))
+ ^ Mapping::kAppMemXor) * kShadowCnt;
+#else
+ return ((x & ~(kShadowCell - 1)) * kShadowCnt) | Mapping::kShadowBeg;
+#endif
}
ALWAYS_INLINE
-u32 *MemToMeta(uptr x) {
+uptr MemToShadow(uptr x) {
+#ifdef __aarch64__
+ if (vmaSize == 39)
+ return MemToShadowImpl<Mapping39>(x);
+ else
+ return MemToShadowImpl<Mapping42>(x);
+ DCHECK(0);
+#elif defined(__powerpc64__)
+ if (vmaSize == 44)
+ return MemToShadowImpl<Mapping44>(x);
+ else
+ return MemToShadowImpl<Mapping46>(x);
+ DCHECK(0);
+#else
+ return MemToShadowImpl<Mapping>(x);
+#endif
+}
+
+
+template<typename Mapping>
+u32 *MemToMetaImpl(uptr x) {
DCHECK(IsAppMem(x));
+#ifndef SANITIZER_GO
+ return (u32*)(((((x) & ~(Mapping::kAppMemMsk | (kMetaShadowCell - 1)))
+ ^ Mapping::kAppMemXor) / kMetaShadowCell * kMetaShadowSize)
+ | Mapping::kMetaShadowBeg);
+#else
return (u32*)(((x & ~(kMetaShadowCell - 1)) / \
- kMetaShadowCell * kMetaShadowSize) | kMetaShadowBeg);
+ kMetaShadowCell * kMetaShadowSize) | Mapping::kMetaShadowBeg);
+#endif
}
ALWAYS_INLINE
-uptr ShadowToMem(uptr s) {
- CHECK(IsShadowMem(s));
- // FIXME(dvyukov): this is most likely wrong as the mapping is not bijection.
- return (s - kShadowBeg) / kShadowCnt;
+u32 *MemToMeta(uptr x) {
+#ifdef __aarch64__
+ if (vmaSize == 39)
+ return MemToMetaImpl<Mapping39>(x);
+ else
+ return MemToMetaImpl<Mapping42>(x);
+ DCHECK(0);
+#elif defined(__powerpc64__)
+ if (vmaSize == 44)
+ return MemToMetaImpl<Mapping44>(x);
+ else
+ return MemToMetaImpl<Mapping46>(x);
+ DCHECK(0);
+#else
+ return MemToMetaImpl<Mapping>(x);
+#endif
}
-static USED uptr UserRegions[] = {
- kAppMemBeg, kAppMemEnd,
-};
+template<typename Mapping>
+uptr ShadowToMemImpl(uptr s) {
+ DCHECK(IsShadowMem(s));
+#ifndef SANITIZER_GO
+ if (s >= MemToShadow(Mapping::kLoAppMemBeg)
+ && s <= MemToShadow(Mapping::kLoAppMemEnd - 1))
+ return (s / kShadowCnt) ^ Mapping::kAppMemXor;
+# ifdef TSAN_MID_APP_RANGE
+ if (s >= MemToShadow(Mapping::kMidAppMemBeg)
+ && s <= MemToShadow(Mapping::kMidAppMemEnd - 1))
+ return ((s / kShadowCnt) ^ Mapping::kAppMemXor) + Mapping::kMidShadowOff;
+# endif
+ else
+ return ((s / kShadowCnt) ^ Mapping::kAppMemXor) | Mapping::kAppMemMsk;
#else
-# error "Unknown platform"
+# ifndef SANITIZER_WINDOWS
+ return (s & ~Mapping::kShadowBeg) / kShadowCnt;
+# else
+ // FIXME(dvyukov): this is most likely wrong as the mapping is not bijection.
+ return (s - Mapping::kShadowBeg) / kShadowCnt;
+# endif // SANITIZER_WINDOWS
+#endif
+}
+
+ALWAYS_INLINE
+uptr ShadowToMem(uptr s) {
+#ifdef __aarch64__
+ if (vmaSize == 39)
+ return ShadowToMemImpl<Mapping39>(s);
+ else
+ return ShadowToMemImpl<Mapping42>(s);
+ DCHECK(0);
+#elif defined(__powerpc64__)
+ if (vmaSize == 44)
+ return ShadowToMemImpl<Mapping44>(s);
+ else
+ return ShadowToMemImpl<Mapping46>(s);
+ DCHECK(0);
+#else
+ return ShadowToMemImpl<Mapping>(s);
#endif
+}
+
+
// The additional page is to catch shadow stack overflow as paging fault.
// Windows wants 64K alignment for mmaps.
const uptr kTotalTraceSize = (kTraceSize * sizeof(Event) + sizeof(Trace)
+ (64 << 10) + (64 << 10) - 1) & ~((64 << 10) - 1);
-uptr ALWAYS_INLINE GetThreadTrace(int tid) {
- uptr p = kTraceMemBeg + (uptr)tid * kTotalTraceSize;
- DCHECK_LT(p, kTraceMemEnd);
+template<typename Mapping>
+uptr GetThreadTraceImpl(int tid) {
+ uptr p = Mapping::kTraceMemBeg + (uptr)tid * kTotalTraceSize;
+ DCHECK_LT(p, Mapping::kTraceMemEnd);
return p;
}
-uptr ALWAYS_INLINE GetThreadTraceHeader(int tid) {
- uptr p = kTraceMemBeg + (uptr)tid * kTotalTraceSize
+ALWAYS_INLINE
+uptr GetThreadTrace(int tid) {
+#ifdef __aarch64__
+ if (vmaSize == 39)
+ return GetThreadTraceImpl<Mapping39>(tid);
+ else
+ return GetThreadTraceImpl<Mapping42>(tid);
+ DCHECK(0);
+#elif defined(__powerpc64__)
+ if (vmaSize == 44)
+ return GetThreadTraceImpl<Mapping44>(tid);
+ else
+ return GetThreadTraceImpl<Mapping46>(tid);
+ DCHECK(0);
+#else
+ return GetThreadTraceImpl<Mapping>(tid);
+#endif
+}
+
+
+template<typename Mapping>
+uptr GetThreadTraceHeaderImpl(int tid) {
+ uptr p = Mapping::kTraceMemBeg + (uptr)tid * kTotalTraceSize
+ kTraceSize * sizeof(Event);
- DCHECK_LT(p, kTraceMemEnd);
+ DCHECK_LT(p, Mapping::kTraceMemEnd);
return p;
}
+ALWAYS_INLINE
+uptr GetThreadTraceHeader(int tid) {
+#ifdef __aarch64__
+ if (vmaSize == 39)
+ return GetThreadTraceHeaderImpl<Mapping39>(tid);
+ else
+ return GetThreadTraceHeaderImpl<Mapping42>(tid);
+ DCHECK(0);
+#elif defined(__powerpc64__)
+ if (vmaSize == 44)
+ return GetThreadTraceHeaderImpl<Mapping44>(tid);
+ else
+ return GetThreadTraceHeaderImpl<Mapping46>(tid);
+ DCHECK(0);
+#else
+ return GetThreadTraceHeaderImpl<Mapping>(tid);
+#endif
+}
+
void InitializePlatform();
+void InitializePlatformEarly();
+void CheckAndProtect();
+void InitializeShadowMemoryPlatform();
void FlushShadowMemory();
void WriteMemoryProfile(char *buf, uptr buf_size, uptr nthread, uptr nlive);
@@ -294,6 +765,8 @@ int call_pthread_cancel_with_cleanup(int(*fn)(void *c, void *m,
void *abstime), void *c, void *m, void *abstime,
void(*cleanup)(void *arg), void *arg);
+void DestroyThreadState();
+
} // namespace __tsan
#endif // TSAN_PLATFORM_H
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_platform_linux.cc b/contrib/compiler-rt/lib/tsan/rtl/tsan_platform_linux.cc
index 1309058210ce..6602561186ce 100644
--- a/contrib/compiler-rt/lib/tsan/rtl/tsan_platform_linux.cc
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_platform_linux.cc
@@ -67,6 +67,11 @@ namespace __tsan {
static uptr g_data_start;
static uptr g_data_end;
+#ifdef TSAN_RUNTIME_VMA
+// Runtime detected VMA size.
+uptr vmaSize;
+#endif
+
enum {
MemTotal = 0,
MemShadow = 1,
@@ -82,29 +87,30 @@ enum {
void FillProfileCallback(uptr p, uptr rss, bool file,
uptr *mem, uptr stats_size) {
mem[MemTotal] += rss;
- if (p >= kShadowBeg && p < kShadowEnd)
+ if (p >= ShadowBeg() && p < ShadowEnd())
mem[MemShadow] += rss;
- else if (p >= kMetaShadowBeg && p < kMetaShadowEnd)
+ else if (p >= MetaShadowBeg() && p < MetaShadowEnd())
mem[MemMeta] += rss;
#ifndef SANITIZER_GO
- else if (p >= kHeapMemBeg && p < kHeapMemEnd)
+ else if (p >= HeapMemBeg() && p < HeapMemEnd())
mem[MemHeap] += rss;
- else if (p >= kLoAppMemBeg && p < kLoAppMemEnd)
+ else if (p >= LoAppMemBeg() && p < LoAppMemEnd())
mem[file ? MemFile : MemMmap] += rss;
- else if (p >= kHiAppMemBeg && p < kHiAppMemEnd)
+ else if (p >= HiAppMemBeg() && p < HiAppMemEnd())
mem[file ? MemFile : MemMmap] += rss;
#else
- else if (p >= kAppMemBeg && p < kAppMemEnd)
+ else if (p >= AppMemBeg() && p < AppMemEnd())
mem[file ? MemFile : MemMmap] += rss;
#endif
- else if (p >= kTraceMemBeg && p < kTraceMemEnd)
+ else if (p >= TraceMemBeg() && p < TraceMemEnd())
mem[MemTrace] += rss;
else
mem[MemOther] += rss;
}
void WriteMemoryProfile(char *buf, uptr buf_size, uptr nthread, uptr nlive) {
- uptr mem[MemCount] = {};
+ uptr mem[MemCount];
+ internal_memset(mem, 0, sizeof(mem[0]) * MemCount);
__sanitizer::GetMemoryProfile(FillProfileCallback, mem, 7);
StackDepotStats *stacks = StackDepotGetStats();
internal_snprintf(buf, buf_size,
@@ -121,7 +127,7 @@ void WriteMemoryProfile(char *buf, uptr buf_size, uptr nthread, uptr nlive) {
void FlushShadowMemoryCallback(
const SuspendedThreadsList &suspended_threads_list,
void *argument) {
- FlushUnneededShadowMemory(kShadowBeg, kShadowEnd - kShadowBeg);
+ FlushUnneededShadowMemory(ShadowBeg(), ShadowEnd() - ShadowBeg());
}
#endif
@@ -132,17 +138,6 @@ void FlushShadowMemory() {
}
#ifndef SANITIZER_GO
-static void ProtectRange(uptr beg, uptr end) {
- CHECK_LE(beg, end);
- if (beg == end)
- return;
- if (beg != (uptr)MmapNoAccess(beg, end - beg)) {
- Printf("FATAL: ThreadSanitizer can not protect [%zx,%zx]\n", beg, end);
- Printf("FATAL: Make sure you are not using unlimited stack\n");
- Die();
- }
-}
-
// Mark shadow for .rodata sections with the special kShadowRodata marker.
// Accesses to .rodata can't race, so this saves time, memory and trace space.
static void MapRodata() {
@@ -200,55 +195,7 @@ static void MapRodata() {
internal_close(fd);
}
-void InitializeShadowMemory() {
- // Map memory shadow.
- uptr shadow =
- (uptr)MmapFixedNoReserve(kShadowBeg, kShadowEnd - kShadowBeg, "shadow");
- if (shadow != kShadowBeg) {
- Printf("FATAL: ThreadSanitizer can not mmap the shadow memory\n");
- Printf("FATAL: Make sure to compile with -fPIE and "
- "to link with -pie (%p, %p).\n", shadow, kShadowBeg);
- Die();
- }
- // This memory range is used for thread stacks and large user mmaps.
- // Frequently a thread uses only a small part of stack and similarly
- // a program uses a small part of large mmap. On some programs
- // we see 20% memory usage reduction without huge pages for this range.
- // FIXME: don't use constants here.
-#if defined(__x86_64__)
- const uptr kMadviseRangeBeg = 0x7f0000000000ull;
- const uptr kMadviseRangeSize = 0x010000000000ull;
-#elif defined(__mips64)
- const uptr kMadviseRangeBeg = 0xff00000000ull;
- const uptr kMadviseRangeSize = 0x0100000000ull;
-#endif
- NoHugePagesInRegion(MemToShadow(kMadviseRangeBeg),
- kMadviseRangeSize * kShadowMultiplier);
- // Meta shadow is compressing and we don't flush it,
- // so it makes sense to mark it as NOHUGEPAGE to not over-allocate memory.
- // On one program it reduces memory consumption from 5GB to 2.5GB.
- NoHugePagesInRegion(kMetaShadowBeg, kMetaShadowEnd - kMetaShadowBeg);
- if (common_flags()->use_madv_dontdump)
- DontDumpShadowMemory(kShadowBeg, kShadowEnd - kShadowBeg);
- DPrintf("memory shadow: %zx-%zx (%zuGB)\n",
- kShadowBeg, kShadowEnd,
- (kShadowEnd - kShadowBeg) >> 30);
-
- // Map meta shadow.
- uptr meta_size = kMetaShadowEnd - kMetaShadowBeg;
- uptr meta =
- (uptr)MmapFixedNoReserve(kMetaShadowBeg, meta_size, "meta shadow");
- if (meta != kMetaShadowBeg) {
- Printf("FATAL: ThreadSanitizer can not mmap the shadow memory\n");
- Printf("FATAL: Make sure to compile with -fPIE and "
- "to link with -pie (%p, %p).\n", meta, kMetaShadowBeg);
- Die();
- }
- if (common_flags()->use_madv_dontdump)
- DontDumpShadowMemory(meta, meta_size);
- DPrintf("meta shadow: %zx-%zx (%zuGB)\n",
- meta, meta + meta_size, meta_size >> 30);
-
+void InitializeShadowMemoryPlatform() {
MapRodata();
}
@@ -292,32 +239,27 @@ static void InitDataSeg() {
CHECK_LT((uptr)&g_data_start, g_data_end);
}
-static void CheckAndProtect() {
- // Ensure that the binary is indeed compiled with -pie.
- MemoryMappingLayout proc_maps(true);
- uptr p, end;
- while (proc_maps.Next(&p, &end, 0, 0, 0, 0)) {
- if (IsAppMem(p))
- continue;
- if (p >= kHeapMemEnd &&
- p < HeapEnd())
- continue;
- if (p >= kVdsoBeg) // vdso
- break;
- Printf("FATAL: ThreadSanitizer: unexpected memory mapping %p-%p\n", p, end);
+#endif // #ifndef SANITIZER_GO
+
+void InitializePlatformEarly() {
+#ifdef TSAN_RUNTIME_VMA
+ vmaSize =
+ (MostSignificantSetBitIndex(GET_CURRENT_FRAME()) + 1);
+#if defined(__aarch64__)
+ if (vmaSize != 39 && vmaSize != 42) {
+ Printf("FATAL: ThreadSanitizer: unsupported VMA range\n");
+ Printf("FATAL: Found %d - Supported 39 and 42\n", vmaSize);
Die();
}
-
- ProtectRange(kLoAppMemEnd, kShadowBeg);
- ProtectRange(kShadowEnd, kMetaShadowBeg);
- ProtectRange(kMetaShadowEnd, kTraceMemBeg);
- // Memory for traces is mapped lazily in MapThreadTrace.
- // Protect the whole range for now, so that user does not map something here.
- ProtectRange(kTraceMemBeg, kTraceMemEnd);
- ProtectRange(kTraceMemEnd, kHeapMemBeg);
- ProtectRange(HeapEnd(), kHiAppMemBeg);
+#elif defined(__powerpc64__)
+ if (vmaSize != 44 && vmaSize != 46) {
+ Printf("FATAL: ThreadSanitizer: unsupported VMA range\n");
+ Printf("FATAL: Found %d - Supported 44 and 46\n", vmaSize);
+ Die();
+ }
+#endif
+#endif
}
-#endif // #ifndef SANITIZER_GO
void InitializePlatform() {
DisableCoreDumperIfNecessary();
@@ -367,7 +309,7 @@ bool IsGlobalVar(uptr addr) {
// This is required to properly "close" the fds, because we do not see internal
// closes within glibc. The code is a pure hack.
int ExtractResolvFDs(void *state, int *fds, int nfd) {
-#if SANITIZER_LINUX
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
int cnt = 0;
__res_state *statp = (__res_state*)state;
for (int i = 0; i < MAXNS && cnt < nfd; i++) {
@@ -415,6 +357,10 @@ int call_pthread_cancel_with_cleanup(int(*fn)(void *c, void *m,
}
#endif
+#ifndef SANITIZER_GO
+void ReplaceSystemMalloc() { }
+#endif
+
} // namespace __tsan
#endif // SANITIZER_LINUX || SANITIZER_FREEBSD
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_platform_mac.cc b/contrib/compiler-rt/lib/tsan/rtl/tsan_platform_mac.cc
index b72d9b07ef35..31caf37dee5a 100644
--- a/contrib/compiler-rt/lib/tsan/rtl/tsan_platform_mac.cc
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_platform_mac.cc
@@ -15,8 +15,10 @@
#include "sanitizer_common/sanitizer_platform.h"
#if SANITIZER_MAC
+#include "sanitizer_common/sanitizer_atomic.h"
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_libc.h"
+#include "sanitizer_common/sanitizer_posix.h"
#include "sanitizer_common/sanitizer_procmaps.h"
#include "tsan_platform.h"
#include "tsan_rtl.h"
@@ -40,6 +42,62 @@
namespace __tsan {
+#ifndef SANITIZER_GO
+static void *SignalSafeGetOrAllocate(uptr *dst, uptr size) {
+ atomic_uintptr_t *a = (atomic_uintptr_t *)dst;
+ void *val = (void *)atomic_load_relaxed(a);
+ atomic_signal_fence(memory_order_acquire); // Turns the previous load into
+ // acquire wrt signals.
+ if (UNLIKELY(val == nullptr)) {
+ val = (void *)internal_mmap(nullptr, size, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANON, -1, 0);
+ CHECK(val);
+ void *cmp = nullptr;
+ if (!atomic_compare_exchange_strong(a, (uintptr_t *)&cmp, (uintptr_t)val,
+ memory_order_acq_rel)) {
+ internal_munmap(val, size);
+ val = cmp;
+ }
+ }
+ return val;
+}
+
+// On OS X, accessing TLVs via __thread or manually by using pthread_key_* is
+// problematic, because there are several places where interceptors are called
+// when TLVs are not accessible (early process startup, thread cleanup, ...).
+// The following provides a "poor man's TLV" implementation, where we use the
+// shadow memory of the pointer returned by pthread_self() to store a pointer to
+// the ThreadState object. The main thread's ThreadState pointer is stored
+// separately in a static variable, because we need to access it even before the
+// shadow memory is set up.
+static uptr main_thread_identity = 0;
+static ThreadState *main_thread_state = nullptr;
+
+ThreadState *cur_thread() {
+ ThreadState **fake_tls;
+ uptr thread_identity = (uptr)pthread_self();
+ if (thread_identity == main_thread_identity || main_thread_identity == 0) {
+ fake_tls = &main_thread_state;
+ } else {
+ fake_tls = (ThreadState **)MemToShadow(thread_identity);
+ }
+ ThreadState *thr = (ThreadState *)SignalSafeGetOrAllocate(
+ (uptr *)fake_tls, sizeof(ThreadState));
+ return thr;
+}
+
+// TODO(kuba.brecka): This is not async-signal-safe. In particular, we call
+// munmap first and then clear `fake_tls`; if we receive a signal in between,
+// handler will try to access the unmapped ThreadState.
+void cur_thread_finalize() {
+ uptr thread_identity = (uptr)pthread_self();
+ CHECK_NE(thread_identity, main_thread_identity);
+ ThreadState **fake_tls = (ThreadState **)MemToShadow(thread_identity);
+ internal_munmap(*fake_tls, sizeof(ThreadState));
+ *fake_tls = nullptr;
+}
+#endif
+
uptr GetShadowMemoryConsumption() {
return 0;
}
@@ -51,28 +109,62 @@ void WriteMemoryProfile(char *buf, uptr buf_size, uptr nthread, uptr nlive) {
}
#ifndef SANITIZER_GO
-void InitializeShadowMemory() {
- uptr shadow = (uptr)MmapFixedNoReserve(kShadowBeg,
- kShadowEnd - kShadowBeg);
- if (shadow != kShadowBeg) {
- Printf("FATAL: ThreadSanitizer can not mmap the shadow memory\n");
- Printf("FATAL: Make sure to compile with -fPIE and "
- "to link with -pie.\n");
- Die();
+void InitializeShadowMemoryPlatform() { }
+
+// On OS X, GCD worker threads are created without a call to pthread_create. We
+// need to properly register these threads with ThreadCreate and ThreadStart.
+// These threads don't have a parent thread, as they are created "spuriously".
+// We're using a libpthread API that notifies us about a newly created thread.
+// The `thread == pthread_self()` check indicates this is actually a worker
+// thread. If it's just a regular thread, this hook is called on the parent
+// thread.
+typedef void (*pthread_introspection_hook_t)(unsigned int event,
+ pthread_t thread, void *addr,
+ size_t size);
+extern "C" pthread_introspection_hook_t pthread_introspection_hook_install(
+ pthread_introspection_hook_t hook);
+static const uptr PTHREAD_INTROSPECTION_THREAD_CREATE = 1;
+static const uptr PTHREAD_INTROSPECTION_THREAD_TERMINATE = 3;
+static pthread_introspection_hook_t prev_pthread_introspection_hook;
+static void my_pthread_introspection_hook(unsigned int event, pthread_t thread,
+ void *addr, size_t size) {
+ if (event == PTHREAD_INTROSPECTION_THREAD_CREATE) {
+ if (thread == pthread_self()) {
+ // The current thread is a newly created GCD worker thread.
+ ThreadState *parent_thread_state = nullptr; // No parent.
+ int tid = ThreadCreate(parent_thread_state, 0, (uptr)thread, true);
+ CHECK_NE(tid, 0);
+ ThreadState *thr = cur_thread();
+ ThreadStart(thr, tid, GetTid());
+ }
+ } else if (event == PTHREAD_INTROSPECTION_THREAD_TERMINATE) {
+ if (thread == pthread_self()) {
+ ThreadState *thr = cur_thread();
+ if (thr->tctx) {
+ DestroyThreadState();
+ }
+ }
}
- if (common_flags()->use_madv_dontdump)
- DontDumpShadowMemory(kShadowBeg, kShadowEnd - kShadowBeg);
- DPrintf("kShadow %zx-%zx (%zuGB)\n",
- kShadowBeg, kShadowEnd,
- (kShadowEnd - kShadowBeg) >> 30);
- DPrintf("kAppMem %zx-%zx (%zuGB)\n",
- kAppMemBeg, kAppMemEnd,
- (kAppMemEnd - kAppMemBeg) >> 30);
+
+ if (prev_pthread_introspection_hook != nullptr)
+ prev_pthread_introspection_hook(event, thread, addr, size);
}
#endif
+void InitializePlatformEarly() {
+}
+
void InitializePlatform() {
DisableCoreDumperIfNecessary();
+#ifndef SANITIZER_GO
+ CheckAndProtect();
+
+ CHECK_EQ(main_thread_identity, 0);
+ main_thread_identity = (uptr)pthread_self();
+
+ prev_pthread_introspection_hook =
+ pthread_introspection_hook_install(&my_pthread_introspection_hook);
+#endif
}
#ifndef SANITIZER_GO
@@ -91,6 +183,10 @@ int call_pthread_cancel_with_cleanup(int(*fn)(void *c, void *m,
}
#endif
+bool IsGlobalVar(uptr addr) {
+ return false;
+}
+
} // namespace __tsan
#endif // SANITIZER_MAC
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_platform_posix.cc b/contrib/compiler-rt/lib/tsan/rtl/tsan_platform_posix.cc
new file mode 100644
index 000000000000..90476cbc5fd5
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_platform_posix.cc
@@ -0,0 +1,151 @@
+//===-- tsan_platform_posix.cc --------------------------------------------===//
+//
+// 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 ThreadSanitizer (TSan), a race detector.
+//
+// POSIX-specific code.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_platform.h"
+#if SANITIZER_POSIX
+
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_libc.h"
+#include "sanitizer_common/sanitizer_procmaps.h"
+#include "tsan_platform.h"
+#include "tsan_rtl.h"
+
+namespace __tsan {
+
+#ifndef SANITIZER_GO
+void InitializeShadowMemory() {
+ // Map memory shadow.
+ uptr shadow =
+ (uptr)MmapFixedNoReserve(ShadowBeg(), ShadowEnd() - ShadowBeg(),
+ "shadow");
+ if (shadow != ShadowBeg()) {
+ Printf("FATAL: ThreadSanitizer can not mmap the shadow memory\n");
+ Printf("FATAL: Make sure to compile with -fPIE and "
+ "to link with -pie (%p, %p).\n", shadow, ShadowBeg());
+ Die();
+ }
+ // This memory range is used for thread stacks and large user mmaps.
+ // Frequently a thread uses only a small part of stack and similarly
+ // a program uses a small part of large mmap. On some programs
+ // we see 20% memory usage reduction without huge pages for this range.
+ // FIXME: don't use constants here.
+#if defined(__x86_64__)
+ const uptr kMadviseRangeBeg = 0x7f0000000000ull;
+ const uptr kMadviseRangeSize = 0x010000000000ull;
+#elif defined(__mips64)
+ const uptr kMadviseRangeBeg = 0xff00000000ull;
+ const uptr kMadviseRangeSize = 0x0100000000ull;
+#elif defined(__aarch64__)
+ uptr kMadviseRangeBeg = 0;
+ uptr kMadviseRangeSize = 0;
+ if (vmaSize == 39) {
+ kMadviseRangeBeg = 0x7d00000000ull;
+ kMadviseRangeSize = 0x0300000000ull;
+ } else if (vmaSize == 42) {
+ kMadviseRangeBeg = 0x3f000000000ull;
+ kMadviseRangeSize = 0x01000000000ull;
+ } else {
+ DCHECK(0);
+ }
+#elif defined(__powerpc64__)
+ uptr kMadviseRangeBeg = 0;
+ uptr kMadviseRangeSize = 0;
+ if (vmaSize == 44) {
+ kMadviseRangeBeg = 0x0f60000000ull;
+ kMadviseRangeSize = 0x0010000000ull;
+ } else if (vmaSize == 46) {
+ kMadviseRangeBeg = 0x3f0000000000ull;
+ kMadviseRangeSize = 0x010000000000ull;
+ } else {
+ DCHECK(0);
+ }
+#endif
+ NoHugePagesInRegion(MemToShadow(kMadviseRangeBeg),
+ kMadviseRangeSize * kShadowMultiplier);
+ // Meta shadow is compressing and we don't flush it,
+ // so it makes sense to mark it as NOHUGEPAGE to not over-allocate memory.
+ // On one program it reduces memory consumption from 5GB to 2.5GB.
+ NoHugePagesInRegion(MetaShadowBeg(), MetaShadowEnd() - MetaShadowBeg());
+ if (common_flags()->use_madv_dontdump)
+ DontDumpShadowMemory(ShadowBeg(), ShadowEnd() - ShadowBeg());
+ DPrintf("memory shadow: %zx-%zx (%zuGB)\n",
+ ShadowBeg(), ShadowEnd(),
+ (ShadowEnd() - ShadowBeg()) >> 30);
+
+ // Map meta shadow.
+ uptr meta_size = MetaShadowEnd() - MetaShadowBeg();
+ uptr meta =
+ (uptr)MmapFixedNoReserve(MetaShadowBeg(), meta_size, "meta shadow");
+ if (meta != MetaShadowBeg()) {
+ Printf("FATAL: ThreadSanitizer can not mmap the shadow memory\n");
+ Printf("FATAL: Make sure to compile with -fPIE and "
+ "to link with -pie (%p, %p).\n", meta, MetaShadowBeg());
+ Die();
+ }
+ if (common_flags()->use_madv_dontdump)
+ DontDumpShadowMemory(meta, meta_size);
+ DPrintf("meta shadow: %zx-%zx (%zuGB)\n",
+ meta, meta + meta_size, meta_size >> 30);
+
+ InitializeShadowMemoryPlatform();
+}
+
+static void ProtectRange(uptr beg, uptr end) {
+ CHECK_LE(beg, end);
+ if (beg == end)
+ return;
+ if (beg != (uptr)MmapNoAccess(beg, end - beg)) {
+ Printf("FATAL: ThreadSanitizer can not protect [%zx,%zx]\n", beg, end);
+ Printf("FATAL: Make sure you are not using unlimited stack\n");
+ Die();
+ }
+}
+
+void CheckAndProtect() {
+ // Ensure that the binary is indeed compiled with -pie.
+ MemoryMappingLayout proc_maps(true);
+ uptr p, end, prot;
+ while (proc_maps.Next(&p, &end, 0, 0, 0, &prot)) {
+ if (IsAppMem(p))
+ continue;
+ if (p >= HeapMemEnd() &&
+ p < HeapEnd())
+ continue;
+ if (prot == 0) // Zero page or mprotected.
+ continue;
+ if (p >= VdsoBeg()) // vdso
+ break;
+ Printf("FATAL: ThreadSanitizer: unexpected memory mapping %p-%p\n", p, end);
+ Die();
+ }
+
+ ProtectRange(LoAppMemEnd(), ShadowBeg());
+ ProtectRange(ShadowEnd(), MetaShadowBeg());
+#ifdef TSAN_MID_APP_RANGE
+ ProtectRange(MetaShadowEnd(), MidAppMemBeg());
+ ProtectRange(MidAppMemEnd(), TraceMemBeg());
+#else
+ ProtectRange(MetaShadowEnd(), TraceMemBeg());
+#endif
+ // Memory for traces is mapped lazily in MapThreadTrace.
+ // Protect the whole range for now, so that user does not map something here.
+ ProtectRange(TraceMemBeg(), TraceMemEnd());
+ ProtectRange(TraceMemEnd(), HeapMemBeg());
+ ProtectRange(HeapEnd(), HiAppMemBeg());
+}
+#endif
+
+} // namespace __tsan
+
+#endif // SANITIZER_POSIX
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_platform_windows.cc b/contrib/compiler-rt/lib/tsan/rtl/tsan_platform_windows.cc
index cfbe77da2c07..c6d5058d96fc 100644
--- a/contrib/compiler-rt/lib/tsan/rtl/tsan_platform_windows.cc
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_platform_windows.cc
@@ -31,6 +31,9 @@ void FlushShadowMemory() {
void WriteMemoryProfile(char *buf, uptr buf_size, uptr nthread, uptr nlive) {
}
+void InitializePlatformEarly() {
+}
+
void InitializePlatform() {
}
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_ppc_regs.h b/contrib/compiler-rt/lib/tsan/rtl/tsan_ppc_regs.h
new file mode 100644
index 000000000000..5b43f3ddada3
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_ppc_regs.h
@@ -0,0 +1,96 @@
+#define r0 0
+#define r1 1
+#define r2 2
+#define r3 3
+#define r4 4
+#define r5 5
+#define r6 6
+#define r7 7
+#define r8 8
+#define r9 9
+#define r10 10
+#define r11 11
+#define r12 12
+#define r13 13
+#define r14 14
+#define r15 15
+#define r16 16
+#define r17 17
+#define r18 18
+#define r19 19
+#define r20 20
+#define r21 21
+#define r22 22
+#define r23 23
+#define r24 24
+#define r25 25
+#define r26 26
+#define r27 27
+#define r28 28
+#define r29 29
+#define r30 30
+#define r31 31
+#define f0 0
+#define f1 1
+#define f2 2
+#define f3 3
+#define f4 4
+#define f5 5
+#define f6 6
+#define f7 7
+#define f8 8
+#define f9 9
+#define f10 10
+#define f11 11
+#define f12 12
+#define f13 13
+#define f14 14
+#define f15 15
+#define f16 16
+#define f17 17
+#define f18 18
+#define f19 19
+#define f20 20
+#define f21 21
+#define f22 22
+#define f23 23
+#define f24 24
+#define f25 25
+#define f26 26
+#define f27 27
+#define f28 28
+#define f29 29
+#define f30 30
+#define f31 31
+#define v0 0
+#define v1 1
+#define v2 2
+#define v3 3
+#define v4 4
+#define v5 5
+#define v6 6
+#define v7 7
+#define v8 8
+#define v9 9
+#define v10 10
+#define v11 11
+#define v12 12
+#define v13 13
+#define v14 14
+#define v15 15
+#define v16 16
+#define v17 17
+#define v18 18
+#define v19 19
+#define v20 20
+#define v21 21
+#define v22 22
+#define v23 23
+#define v24 24
+#define v25 25
+#define v26 26
+#define v27 27
+#define v28 28
+#define v29 29
+#define v30 30
+#define v31 31
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_report.cc b/contrib/compiler-rt/lib/tsan/rtl/tsan_report.cc
index f4b06878a58e..c1d2fd07c0d9 100644
--- a/contrib/compiler-rt/lib/tsan/rtl/tsan_report.cc
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_report.cc
@@ -111,6 +111,12 @@ static const char *ReportTypeString(ReportType typ) {
return "";
}
+#if SANITIZER_MAC
+static const char *const kInterposedFunctionPrefix = "wrap_";
+#else
+static const char *const kInterposedFunctionPrefix = "__interceptor_";
+#endif
+
void PrintStack(const ReportStack *ent) {
if (ent == 0 || ent->frames == 0) {
Printf(" [failed to restore the stack]\n\n");
@@ -121,7 +127,7 @@ void PrintStack(const ReportStack *ent) {
InternalScopedString res(2 * GetPageSizeCached());
RenderFrame(&res, common_flags()->stack_trace_format, i, frame->info,
common_flags()->symbolize_vs_style,
- common_flags()->strip_path_prefix, "__interceptor_");
+ common_flags()->strip_path_prefix, kInterposedFunctionPrefix);
Printf("%s\n", res.data());
}
Printf("\n");
@@ -165,9 +171,14 @@ static void PrintLocation(const ReportLocation *loc) {
Printf("%s", d.Location());
if (loc->type == ReportLocationGlobal) {
const DataInfo &global = loc->global;
- Printf(" Location is global '%s' of size %zu at %p (%s+%p)\n\n",
- global.name, global.size, global.start,
- StripModuleName(global.module), global.module_offset);
+ if (global.size != 0)
+ Printf(" Location is global '%s' of size %zu at %p (%s+%p)\n\n",
+ global.name, global.size, global.start,
+ StripModuleName(global.module), global.module_offset);
+ else
+ Printf(" Location is global '%s' at %p (%s+%p)\n\n", global.name,
+ global.start, StripModuleName(global.module),
+ global.module_offset);
} else if (loc->type == ReportLocationHeap) {
char thrbuf[kThreadBufSize];
Printf(" Location is heap block of size %zu at %p allocated by %s:\n",
@@ -256,10 +267,15 @@ static bool FrameIsInternal(const SymbolizedStack *frame) {
if (frame == 0)
return false;
const char *file = frame->info.file;
- return file != 0 &&
- (internal_strstr(file, "tsan_interceptors.cc") ||
- internal_strstr(file, "sanitizer_common_interceptors.inc") ||
- internal_strstr(file, "tsan_interface_"));
+ const char *module = frame->info.module;
+ if (file != 0 &&
+ (internal_strstr(file, "tsan_interceptors.cc") ||
+ internal_strstr(file, "sanitizer_common_interceptors.inc") ||
+ internal_strstr(file, "tsan_interface_")))
+ return true;
+ if (module != 0 && (internal_strstr(module, "libclang_rt.tsan_")))
+ return true;
+ return false;
}
static SymbolizedStack *SkipTsanInternalFrames(SymbolizedStack *frames) {
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_rtl.cc b/contrib/compiler-rt/lib/tsan/rtl/tsan_rtl.cc
index 63c356b228a4..4df4db557a24 100644
--- a/contrib/compiler-rt/lib/tsan/rtl/tsan_rtl.cc
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_rtl.cc
@@ -44,7 +44,7 @@ extern "C" void __tsan_resume() {
namespace __tsan {
-#ifndef SANITIZER_GO
+#if !defined(SANITIZER_GO) && !SANITIZER_MAC
THREADLOCAL char cur_thread_placeholder[sizeof(ThreadState)] ALIGNED(64);
#endif
static char ctx_placeholder[sizeof(Context)] ALIGNED(64);
@@ -55,12 +55,12 @@ Context *ctx;
bool OnFinalize(bool failed);
void OnInitialize();
#else
-SANITIZER_INTERFACE_ATTRIBUTE
-bool WEAK OnFinalize(bool failed) {
+SANITIZER_WEAK_CXX_DEFAULT_IMPL
+bool OnFinalize(bool failed) {
return failed;
}
-SANITIZER_INTERFACE_ATTRIBUTE
-void WEAK OnInitialize() {}
+SANITIZER_WEAK_CXX_DEFAULT_IMPL
+void OnInitialize() {}
#endif
static char thread_registry_placeholder[sizeof(ThreadRegistry)];
@@ -99,8 +99,10 @@ Context::Context()
, nmissed_expected()
, thread_registry(new(thread_registry_placeholder) ThreadRegistry(
CreateThreadContext, kMaxTid, kThreadQuarantineSize, kMaxTidReuse))
+ , racy_mtx(MutexTypeRacy, StatMtxRacy)
, racy_stacks(MBlockRacyStacks)
, racy_addresses(MBlockRacyAddresses)
+ , fired_suppressions_mtx(MutexTypeFired, StatMtxFired)
, fired_suppressions(8) {
}
@@ -271,8 +273,8 @@ void MapShadow(uptr addr, uptr size) {
void MapThreadTrace(uptr addr, uptr size, const char *name) {
DPrintf("#0: Mapping trace at %p-%p(0x%zx)\n", addr, addr + size, size);
- CHECK_GE(addr, kTraceMemBeg);
- CHECK_LE(addr + size, kTraceMemEnd);
+ CHECK_GE(addr, TraceMemBeg());
+ CHECK_LE(addr + size, TraceMemEnd());
CHECK_EQ(addr, addr & ~((64 << 10) - 1)); // windows wants 64K alignment
uptr addr1 = (uptr)MmapFixedNoReserve(addr, size, name);
if (addr1 != addr) {
@@ -283,9 +285,8 @@ void MapThreadTrace(uptr addr, uptr size, const char *name) {
}
static void CheckShadowMapping() {
- for (uptr i = 0; i < ARRAY_SIZE(UserRegions); i += 2) {
- const uptr beg = UserRegions[i];
- const uptr end = UserRegions[i + 1];
+ uptr beg, end;
+ for (int i = 0; GetUserRegion(i, &beg, &end); i++) {
VPrintf(3, "checking shadow region %p-%p\n", beg, end);
for (uptr p0 = beg; p0 <= end; p0 += (end - beg) / 4) {
for (int x = -1; x <= 1; x++) {
@@ -318,10 +319,15 @@ void Initialize(ThreadState *thr) {
ctx = new(ctx_placeholder) Context;
const char *options = GetEnv(kTsanOptionsEnv);
- InitializeFlags(&ctx->flags, options);
CacheBinaryName();
+ InitializeFlags(&ctx->flags, options);
+ InitializePlatformEarly();
#ifndef SANITIZER_GO
+ // Re-exec ourselves if we need to set additional env or command line args.
+ MaybeReexec();
+
InitializeAllocator();
+ ReplaceSystemMalloc();
#endif
InitializeInterceptors();
CheckShadowMapping();
@@ -417,7 +423,7 @@ int Finalize(ThreadState *thr) {
StatOutput(ctx->stat);
#endif
- return failed ? flags()->exitcode : 0;
+ return failed ? common_flags()->exitcode : 0;
}
#ifndef SANITIZER_GO
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_rtl.h b/contrib/compiler-rt/lib/tsan/rtl/tsan_rtl.h
index a13e4b6379f0..04104b162f98 100644
--- a/contrib/compiler-rt/lib/tsan/rtl/tsan_rtl.h
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_rtl.h
@@ -54,7 +54,7 @@ namespace __tsan {
#ifndef SANITIZER_GO
struct MapUnmapCallback;
-#ifdef __mips64
+#if defined(__mips64) || defined(__aarch64__) || defined(__powerpc__)
static const uptr kAllocatorSpace = 0;
static const uptr kAllocatorSize = SANITIZER_MMAP_RANGE_SIZE;
static const uptr kAllocatorRegionSizeLog = 20;
@@ -66,7 +66,8 @@ typedef SizeClassAllocator32<kAllocatorSpace, kAllocatorSize, 0,
CompactSizeClassMap, kAllocatorRegionSizeLog, ByteMap,
MapUnmapCallback> PrimaryAllocator;
#else
-typedef SizeClassAllocator64<kHeapMemBeg, kHeapMemEnd - kHeapMemBeg, 0,
+typedef SizeClassAllocator64<Mapping::kHeapMemBeg,
+ Mapping::kHeapMemEnd - Mapping::kHeapMemBeg, 0,
DefaultSizeClassMap, MapUnmapCallback> PrimaryAllocator;
#endif
typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache;
@@ -410,12 +411,18 @@ struct ThreadState {
};
#ifndef SANITIZER_GO
+#if SANITIZER_MAC
+ThreadState *cur_thread();
+void cur_thread_finalize();
+#else
__attribute__((tls_model("initial-exec")))
extern THREADLOCAL char cur_thread_placeholder[];
INLINE ThreadState *cur_thread() {
return reinterpret_cast<ThreadState *>(&cur_thread_placeholder);
}
-#endif
+INLINE void cur_thread_finalize() { }
+#endif // SANITIZER_MAC
+#endif // SANITIZER_GO
class ThreadContext : public ThreadContextBase {
public:
@@ -458,7 +465,7 @@ struct RacyAddress {
struct FiredSuppression {
ReportType type;
- uptr pc;
+ uptr pc_or_addr;
Suppression *supp;
};
@@ -480,9 +487,11 @@ struct Context {
ThreadRegistry *thread_registry;
+ Mutex racy_mtx;
Vector<RacyStacks> racy_stacks;
Vector<RacyAddress> racy_addresses;
// Number of fired suppressions may be large enough.
+ Mutex fired_suppressions_mtx;
InternalMmapVector<FiredSuppression> fired_suppressions;
DDetector *dd;
@@ -587,8 +596,7 @@ void ForkChildAfter(ThreadState *thr, uptr pc);
void ReportRace(ThreadState *thr);
bool OutputReport(ThreadState *thr, const ScopedReport &srep);
-bool IsFiredSuppression(Context *ctx, const ScopedReport &srep,
- StackTrace trace);
+bool IsFiredSuppression(Context *ctx, ReportType type, StackTrace trace);
bool IsExpectedReport(uptr addr, uptr size);
void PrintMatchedBenignRaces();
@@ -708,7 +716,7 @@ void AcquireReleaseImpl(ThreadState *thr, uptr pc, SyncClock *c);
// The trick is that the call preserves all registers and the compiler
// does not treat it as a call.
// If it does not work for you, use normal call.
-#if !SANITIZER_DEBUG && defined(__x86_64__)
+#if !SANITIZER_DEBUG && defined(__x86_64__) && !SANITIZER_MAC
// The caller may not create the stack frame for itself at all,
// so we create a reserve stack frame for it (1024b must be enough).
#define HACKY_CALL(f) \
@@ -754,11 +762,7 @@ void ALWAYS_INLINE TraceAddEvent(ThreadState *thr, FastState fs,
#ifndef SANITIZER_GO
uptr ALWAYS_INLINE HeapEnd() {
-#if SANITIZER_CAN_USE_ALLOCATOR64
- return kHeapMemEnd + PrimaryAllocator::AdditionalSize();
-#else
- return kHeapMemEnd;
-#endif
+ return HeapMemEnd() + PrimaryAllocator::AdditionalSize();
}
#endif
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_rtl_aarch64.S b/contrib/compiler-rt/lib/tsan/rtl/tsan_rtl_aarch64.S
new file mode 100644
index 000000000000..9cea3cf02800
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_rtl_aarch64.S
@@ -0,0 +1,206 @@
+#include "sanitizer_common/sanitizer_asm.h"
+.section .text
+
+.hidden __tsan_setjmp
+.comm _ZN14__interception11real_setjmpE,8,8
+.type setjmp, @function
+setjmp:
+ CFI_STARTPROC
+
+ // save env parameters for function call
+ stp x29, x30, [sp, -32]!
+ CFI_DEF_CFA_OFFSET (32)
+ CFI_OFFSET (29, -32)
+ CFI_OFFSET (30, -24)
+
+ // Adjust the SP for previous frame
+ add x29, sp, 0
+ CFI_DEF_CFA_REGISTER (29)
+
+ // Save jmp_buf
+ str x19, [sp, 16]
+ CFI_OFFSET (19, -16)
+ mov x19, x0
+
+ // SP pointer mangling (see glibc setjmp)
+ adrp x2, :got:__pointer_chk_guard
+ ldr x2, [x2, #:got_lo12:__pointer_chk_guard]
+ add x0, x29, 32
+ ldr x2, [x2]
+ eor x1, x2, x0
+
+ // call tsan interceptor
+ bl __tsan_setjmp
+
+ // restore env parameter
+ mov x0, x19
+ ldr x19, [sp, 16]
+ ldp x29, x30, [sp], 32
+ CFI_RESTORE (30)
+ CFI_RESTORE (19)
+ CFI_DEF_CFA (31, 0)
+
+ // tail jump to libc setjmp
+ adrp x1, :got:_ZN14__interception11real_setjmpE
+ ldr x1, [x1, #:got_lo12:_ZN14__interception11real_setjmpE]
+ ldr x1, [x1]
+ br x1
+
+ CFI_ENDPROC
+.size setjmp, .-setjmp
+
+.comm _ZN14__interception12real__setjmpE,8,8
+.globl _setjmp
+.type _setjmp, @function
+_setjmp:
+ CFI_STARTPROC
+
+ // save env parameters for function call
+ stp x29, x30, [sp, -32]!
+ CFI_DEF_CFA_OFFSET (32)
+ CFI_OFFSET (29, -32)
+ CFI_OFFSET (30, -24)
+
+ // Adjust the SP for previous frame
+ add x29, sp, 0
+ CFI_DEF_CFA_REGISTER (29)
+
+ // Save jmp_buf
+ str x19, [sp, 16]
+ CFI_OFFSET (19, -16)
+ mov x19, x0
+
+ // SP pointer mangling (see glibc setjmp)
+ adrp x2, :got:__pointer_chk_guard
+ ldr x2, [x2, #:got_lo12:__pointer_chk_guard]
+ add x0, x29, 32
+ ldr x2, [x2]
+ eor x1, x2, x0
+
+ // call tsan interceptor
+ bl __tsan_setjmp
+
+ // Restore jmp_buf parameter
+ mov x0, x19
+ ldr x19, [sp, 16]
+ ldp x29, x30, [sp], 32
+ CFI_RESTORE (30)
+ CFI_RESTORE (19)
+ CFI_DEF_CFA (31, 0)
+
+ // tail jump to libc setjmp
+ adrp x1, :got:_ZN14__interception12real__setjmpE
+ ldr x1, [x1, #:got_lo12:_ZN14__interception12real__setjmpE]
+ ldr x1, [x1]
+ br x1
+
+ CFI_ENDPROC
+.size _setjmp, .-_setjmp
+
+.comm _ZN14__interception14real_sigsetjmpE,8,8
+.globl sigsetjmp
+.type sigsetjmp, @function
+sigsetjmp:
+ CFI_STARTPROC
+
+ // save env parameters for function call
+ stp x29, x30, [sp, -32]!
+ CFI_DEF_CFA_OFFSET (32)
+ CFI_OFFSET (29, -32)
+ CFI_OFFSET (30, -24)
+
+ // Adjust the SP for previous frame
+ add x29, sp, 0
+ CFI_DEF_CFA_REGISTER (29)
+
+ // Save jmp_buf and savesigs
+ stp x19, x20, [sp, 16]
+ CFI_OFFSET (19, -16)
+ CFI_OFFSET (20, -8)
+ mov w20, w1
+ mov x19, x0
+
+ // SP pointer mangling (see glibc setjmp)
+ adrp x2, :got:__pointer_chk_guard
+ ldr x2, [x2, #:got_lo12:__pointer_chk_guard]
+ add x0, x29, 32
+ ldr x2, [x2]
+ eor x1, x2, x0
+
+ // call tsan interceptor
+ bl __tsan_setjmp
+
+ // restore env parameter
+ mov w1, w20
+ mov x0, x19
+ ldp x19, x20, [sp, 16]
+ ldp x29, x30, [sp], 32
+ CFI_RESTORE (30)
+ CFI_RESTORE (29)
+ CFI_RESTORE (19)
+ CFI_RESTORE (20)
+ CFI_DEF_CFA (31, 0)
+
+ // tail jump to libc sigsetjmp
+ adrp x2, :got:_ZN14__interception14real_sigsetjmpE
+ ldr x2, [x2, #:got_lo12:_ZN14__interception14real_sigsetjmpE]
+ ldr x2, [x2]
+ br x2
+ CFI_ENDPROC
+.size sigsetjmp, .-sigsetjmp
+
+.comm _ZN14__interception16real___sigsetjmpE,8,8
+.globl __sigsetjmp
+.type __sigsetjmp, @function
+__sigsetjmp:
+ CFI_STARTPROC
+
+ // save env parameters for function call
+ stp x29, x30, [sp, -32]!
+ CFI_DEF_CFA_OFFSET (32)
+ CFI_OFFSET (29, -32)
+ CFI_OFFSET (30, -24)
+
+ // Adjust the SP for previous frame
+ add x29, sp, 0
+ CFI_DEF_CFA_REGISTER (29)
+
+ // Save jmp_buf and savesigs
+ stp x19, x20, [sp, 16]
+ CFI_OFFSET (19, -16)
+ CFI_OFFSET (20, -8)
+ mov w20, w1
+ mov x19, x0
+
+ // SP pointer mangling (see glibc setjmp)
+ adrp x2, :got:__pointer_chk_guard
+ ldr x2, [x2, #:got_lo12:__pointer_chk_guard]
+ add x0, x29, 32
+ ldr x2, [x2]
+ eor x1, x2, x0
+
+ // call tsan interceptor
+ bl __tsan_setjmp
+
+ mov w1, w20
+ mov x0, x19
+ ldp x19, x20, [sp, 16]
+ ldp x29, x30, [sp], 32
+ CFI_RESTORE (30)
+ CFI_RESTORE (29)
+ CFI_RESTORE (19)
+ CFI_RESTORE (20)
+ CFI_DEF_CFA (31, 0)
+
+ // tail jump to libc __sigsetjmp
+ adrp x2, :got:_ZN14__interception16real___sigsetjmpE
+ ldr x2, [x2, #:got_lo12:_ZN14__interception16real___sigsetjmpE]
+ ldr x2, [x2]
+ br x2
+ CFI_ENDPROC
+.size __sigsetjmp, .-__sigsetjmp
+
+#if defined(__linux__)
+/* We do not need executable stack. */
+.section .note.GNU-stack,"",@progbits
+#endif
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_rtl_amd64.S b/contrib/compiler-rt/lib/tsan/rtl/tsan_rtl_amd64.S
index 8db62f9013a3..caa832375e52 100644
--- a/contrib/compiler-rt/lib/tsan/rtl/tsan_rtl_amd64.S
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_rtl_amd64.S
@@ -1,9 +1,13 @@
#include "sanitizer_common/sanitizer_asm.h"
+#if !defined(__APPLE__)
.section .text
+#else
+.section __TEXT,__text
+#endif
-.hidden __tsan_trace_switch
-.globl __tsan_trace_switch_thunk
-__tsan_trace_switch_thunk:
+ASM_HIDDEN(__tsan_trace_switch)
+.globl ASM_TSAN_SYMBOL(__tsan_trace_switch_thunk)
+ASM_TSAN_SYMBOL(__tsan_trace_switch_thunk):
CFI_STARTPROC
# Save scratch registers.
push %rax
@@ -42,7 +46,7 @@ __tsan_trace_switch_thunk:
shr $4, %rsp # clear 4 lsb, align to 16
shl $4, %rsp
- call __tsan_trace_switch
+ call ASM_TSAN_SYMBOL(__tsan_trace_switch)
# Unalign stack frame back.
mov %rbx, %rsp # restore the original rsp
@@ -81,9 +85,9 @@ __tsan_trace_switch_thunk:
ret
CFI_ENDPROC
-.hidden __tsan_report_race
-.globl __tsan_report_race_thunk
-__tsan_report_race_thunk:
+ASM_HIDDEN(__tsan_report_race)
+.globl ASM_TSAN_SYMBOL(__tsan_report_race_thunk)
+ASM_TSAN_SYMBOL(__tsan_report_race_thunk):
CFI_STARTPROC
# Save scratch registers.
push %rax
@@ -122,7 +126,7 @@ __tsan_report_race_thunk:
shr $4, %rsp # clear 4 lsb, align to 16
shl $4, %rsp
- call __tsan_report_race
+ call ASM_TSAN_SYMBOL(__tsan_report_race)
# Unalign stack frame back.
mov %rbx, %rsp # restore the original rsp
@@ -161,11 +165,13 @@ __tsan_report_race_thunk:
ret
CFI_ENDPROC
-.hidden __tsan_setjmp
+ASM_HIDDEN(__tsan_setjmp)
+#if !defined(__APPLE__)
.comm _ZN14__interception11real_setjmpE,8,8
-.globl setjmp
-.type setjmp, @function
-setjmp:
+#endif
+.globl ASM_TSAN_SYMBOL_INTERCEPTOR(setjmp)
+ASM_TYPE_FUNCTION(ASM_TSAN_SYMBOL_INTERCEPTOR(setjmp))
+ASM_TSAN_SYMBOL_INTERCEPTOR(setjmp):
CFI_STARTPROC
// save env parameter
push %rdi
@@ -175,29 +181,38 @@ setjmp:
#if defined(__FreeBSD__)
lea 8(%rsp), %rdi
mov %rdi, %rsi
-#else
+#elif defined(__APPLE__)
+ lea 16(%rsp), %rdi
+ mov %rdi, %rsi
+#elif defined(__linux__)
lea 16(%rsp), %rdi
mov %rdi, %rsi
xor %fs:0x30, %rsi // magic mangling of rsp (see libc setjmp)
rol $0x11, %rsi
+#else
+# error "Unknown platform"
#endif
// call tsan interceptor
- call __tsan_setjmp
+ call ASM_TSAN_SYMBOL(__tsan_setjmp)
// restore env parameter
pop %rdi
CFI_ADJUST_CFA_OFFSET(-8)
CFI_RESTORE(%rdi)
// tail jump to libc setjmp
movl $0, %eax
+#if !defined(__APPLE__)
movq _ZN14__interception11real_setjmpE@GOTPCREL(%rip), %rdx
jmp *(%rdx)
+#else
+ jmp ASM_TSAN_SYMBOL(setjmp)
+#endif
CFI_ENDPROC
-.size setjmp, .-setjmp
+ASM_SIZE(ASM_TSAN_SYMBOL_INTERCEPTOR(setjmp))
.comm _ZN14__interception12real__setjmpE,8,8
-.globl _setjmp
-.type _setjmp, @function
-_setjmp:
+.globl ASM_TSAN_SYMBOL_INTERCEPTOR(_setjmp)
+ASM_TYPE_FUNCTION(ASM_TSAN_SYMBOL_INTERCEPTOR(_setjmp))
+ASM_TSAN_SYMBOL_INTERCEPTOR(_setjmp):
CFI_STARTPROC
// save env parameter
push %rdi
@@ -207,29 +222,38 @@ _setjmp:
#if defined(__FreeBSD__)
lea 8(%rsp), %rdi
mov %rdi, %rsi
-#else
+#elif defined(__APPLE__)
+ lea 16(%rsp), %rdi
+ mov %rdi, %rsi
+#elif defined(__linux__)
lea 16(%rsp), %rdi
mov %rdi, %rsi
xor %fs:0x30, %rsi // magic mangling of rsp (see libc setjmp)
rol $0x11, %rsi
+#else
+# error "Unknown platform"
#endif
// call tsan interceptor
- call __tsan_setjmp
+ call ASM_TSAN_SYMBOL(__tsan_setjmp)
// restore env parameter
pop %rdi
CFI_ADJUST_CFA_OFFSET(-8)
CFI_RESTORE(%rdi)
// tail jump to libc setjmp
movl $0, %eax
+#if !defined(__APPLE__)
movq _ZN14__interception12real__setjmpE@GOTPCREL(%rip), %rdx
jmp *(%rdx)
+#else
+ jmp ASM_TSAN_SYMBOL(_setjmp)
+#endif
CFI_ENDPROC
-.size _setjmp, .-_setjmp
+ASM_SIZE(ASM_TSAN_SYMBOL_INTERCEPTOR(_setjmp))
.comm _ZN14__interception14real_sigsetjmpE,8,8
-.globl sigsetjmp
-.type sigsetjmp, @function
-sigsetjmp:
+.globl ASM_TSAN_SYMBOL_INTERCEPTOR(sigsetjmp)
+ASM_TYPE_FUNCTION(ASM_TSAN_SYMBOL_INTERCEPTOR(sigsetjmp))
+ASM_TSAN_SYMBOL_INTERCEPTOR(sigsetjmp):
CFI_STARTPROC
// save env parameter
push %rdi
@@ -246,14 +270,19 @@ sigsetjmp:
#if defined(__FreeBSD__)
lea 24(%rsp), %rdi
mov %rdi, %rsi
-#else
+#elif defined(__APPLE__)
+ lea 32(%rsp), %rdi
+ mov %rdi, %rsi
+#elif defined(__linux__)
lea 32(%rsp), %rdi
mov %rdi, %rsi
xor %fs:0x30, %rsi // magic mangling of rsp (see libc setjmp)
rol $0x11, %rsi
+#else
+# error "Unknown platform"
#endif
// call tsan interceptor
- call __tsan_setjmp
+ call ASM_TSAN_SYMBOL(__tsan_setjmp)
// unalign stack frame
add $8, %rsp
CFI_ADJUST_CFA_OFFSET(-8)
@@ -267,15 +296,20 @@ sigsetjmp:
CFI_RESTORE(%rdi)
// tail jump to libc sigsetjmp
movl $0, %eax
+#if !defined(__APPLE__)
movq _ZN14__interception14real_sigsetjmpE@GOTPCREL(%rip), %rdx
jmp *(%rdx)
+#else
+ jmp ASM_TSAN_SYMBOL(sigsetjmp)
+#endif
CFI_ENDPROC
-.size sigsetjmp, .-sigsetjmp
+ASM_SIZE(ASM_TSAN_SYMBOL_INTERCEPTOR(sigsetjmp))
+#if !defined(__APPLE__)
.comm _ZN14__interception16real___sigsetjmpE,8,8
-.globl __sigsetjmp
-.type __sigsetjmp, @function
-__sigsetjmp:
+.globl ASM_TSAN_SYMBOL_INTERCEPTOR(__sigsetjmp)
+ASM_TYPE_FUNCTION(ASM_TSAN_SYMBOL_INTERCEPTOR(__sigsetjmp))
+ASM_TSAN_SYMBOL_INTERCEPTOR(__sigsetjmp):
CFI_STARTPROC
// save env parameter
push %rdi
@@ -299,7 +333,7 @@ __sigsetjmp:
rol $0x11, %rsi
#endif
// call tsan interceptor
- call __tsan_setjmp
+ call ASM_TSAN_SYMBOL(__tsan_setjmp)
// unalign stack frame
add $8, %rsp
CFI_ADJUST_CFA_OFFSET(-8)
@@ -316,7 +350,8 @@ __sigsetjmp:
movq _ZN14__interception16real___sigsetjmpE@GOTPCREL(%rip), %rdx
jmp *(%rdx)
CFI_ENDPROC
-.size __sigsetjmp, .-__sigsetjmp
+ASM_SIZE(ASM_TSAN_SYMBOL_INTERCEPTOR(__sigsetjmp))
+#endif // !defined(__APPLE__)
#if defined(__FreeBSD__) || defined(__linux__)
/* We do not need executable stack. */
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_rtl_mutex.cc b/contrib/compiler-rt/lib/tsan/rtl/tsan_rtl_mutex.cc
index 09180d88a6fb..62ab7aa6b2b4 100644
--- a/contrib/compiler-rt/lib/tsan/rtl/tsan_rtl_mutex.cc
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_rtl_mutex.cc
@@ -472,7 +472,7 @@ void ReportDeadlock(ThreadState *thr, uptr pc, DDReport *r) {
for (int i = 0; i < r->n; i++) {
for (int j = 0; j < (flags()->second_deadlock_stack ? 2 : 1); j++) {
u32 stk = r->loop[i].stk[j];
- if (stk) {
+ if (stk && stk != 0xffffffff) {
rep.AddStack(StackDepotGet(stk), true);
} else {
// Sometimes we fail to extract the stack trace (FIXME: investigate),
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_rtl_ppc64.S b/contrib/compiler-rt/lib/tsan/rtl/tsan_rtl_ppc64.S
new file mode 100644
index 000000000000..8285e21aa1ec
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_rtl_ppc64.S
@@ -0,0 +1,288 @@
+#include "tsan_ppc_regs.h"
+
+ .section .text
+ .hidden __tsan_setjmp
+ .globl _setjmp
+ .type _setjmp, @function
+ .align 4
+#if _CALL_ELF == 2
+_setjmp:
+#else
+ .section ".opd","aw"
+ .align 3
+_setjmp:
+ .quad .L._setjmp,.TOC.@tocbase,0
+ .previous
+#endif
+.L._setjmp:
+ mflr r0
+ stdu r1,-48(r1)
+ std r2,24(r1)
+ std r3,32(r1)
+ std r0,40(r1)
+ // r3 is the original stack pointer.
+ addi r3,r1,48
+ // r4 is the mangled stack pointer (see glibc)
+ ld r4,-28696(r13)
+ xor r4,r3,r4
+ // Materialize a TOC in case we were called from libc.
+ // For big-endian, we load the TOC from the OPD. For little-
+ // endian, we use the .TOC. symbol to find it.
+ nop
+ bcl 20,31,0f
+0:
+ mflr r2
+#if _CALL_ELF == 2
+ addis r2,r2,.TOC.-0b@ha
+ addi r2,r2,.TOC.-0b@l
+#else
+ addis r2,r2,_setjmp-0b@ha
+ addi r2,r2,_setjmp-0b@l
+ ld r2,8(r2)
+#endif
+ // Call the interceptor.
+ bl __tsan_setjmp
+ nop
+ // Restore regs needed for setjmp.
+ ld r3,32(r1)
+ ld r0,40(r1)
+ // Emulate the real setjmp function. We do this because we can't
+ // perform a sibcall: The real setjmp function trashes the TOC
+ // pointer, and with a sibcall we have no way to restore it.
+ // This way we can make sure our caller's stack pointer and
+ // link register are saved correctly in the jmpbuf.
+ ld r6,-28696(r13)
+ addi r5,r1,48 // original stack ptr of caller
+ xor r5,r6,r5
+ std r5,0(r3) // mangled stack ptr of caller
+ ld r5,24(r1)
+ std r5,8(r3) // caller's saved TOC pointer
+ xor r0,r6,r0
+ std r0,16(r3) // caller's mangled return address
+ mfcr r0
+ // Nonvolatiles.
+ std r14,24(r3)
+ stfd f14,176(r3)
+ stw r0,172(r3) // CR
+ std r15,32(r3)
+ stfd f15,184(r3)
+ std r16,40(r3)
+ stfd f16,192(r3)
+ std r17,48(r3)
+ stfd f17,200(r3)
+ std r18,56(r3)
+ stfd f18,208(r3)
+ std r19,64(r3)
+ stfd f19,216(r3)
+ std r20,72(r3)
+ stfd f20,224(r3)
+ std r21,80(r3)
+ stfd f21,232(r3)
+ std r22,88(r3)
+ stfd f22,240(r3)
+ std r23,96(r3)
+ stfd f23,248(r3)
+ std r24,104(r3)
+ stfd f24,256(r3)
+ std r25,112(r3)
+ stfd f25,264(r3)
+ std r26,120(r3)
+ stfd f26,272(r3)
+ std r27,128(r3)
+ stfd f27,280(r3)
+ std r28,136(r3)
+ stfd f28,288(r3)
+ std r29,144(r3)
+ stfd f29,296(r3)
+ std r30,152(r3)
+ stfd f30,304(r3)
+ std r31,160(r3)
+ stfd f31,312(r3)
+ addi r5,r3,320
+ mfspr r0,256
+ stw r0,168(r3) // VRSAVE
+ addi r6,r5,16
+ stvx v20,0,r5
+ addi r5,r5,32
+ stvx v21,0,r6
+ addi r6,r6,32
+ stvx v22,0,r5
+ addi r5,r5,32
+ stvx v23,0,r6
+ addi r6,r6,32
+ stvx v24,0,r5
+ addi r5,r5,32
+ stvx v25,0,r6
+ addi r6,r6,32
+ stvx v26,0,r5
+ addi r5,r5,32
+ stvx v27,0,r6
+ addi r6,r6,32
+ stvx v28,0,r5
+ addi r5,r5,32
+ stvx v29,0,r6
+ addi r6,r6,32
+ stvx v30,0,r5
+ stvx v31,0,r6
+ // Clear the "mask-saved" slot.
+ li r4,0
+ stw r4,512(r3)
+ // Restore TOC, LR, and stack and return to caller.
+ ld r2,24(r1)
+ ld r0,40(r1)
+ addi r1,r1,48
+ li r3,0 // This is the setjmp return path
+ mtlr r0
+ blr
+ .size _setjmp, .-.L._setjmp
+
+ .globl setjmp
+ .type setjmp, @function
+ .align 4
+setjmp:
+ b _setjmp
+ .size setjmp, .-setjmp
+
+ // sigsetjmp is like setjmp, except that the mask in r4 needs
+ // to be saved at offset 512 of the jump buffer.
+ .globl __sigsetjmp
+ .type __sigsetjmp, @function
+ .align 4
+#if _CALL_ELF == 2
+__sigsetjmp:
+#else
+ .section ".opd","aw"
+ .align 3
+__sigsetjmp:
+ .quad .L.__sigsetjmp,.TOC.@tocbase,0
+ .previous
+#endif
+.L.__sigsetjmp:
+ mflr r0
+ stdu r1,-64(r1)
+ std r2,24(r1)
+ std r3,32(r1)
+ std r4,40(r1)
+ std r0,48(r1)
+ // r3 is the original stack pointer.
+ addi r3,r1,64
+ // r4 is the mangled stack pointer (see glibc)
+ ld r4,-28696(r13)
+ xor r4,r3,r4
+ // Materialize a TOC in case we were called from libc.
+ // For big-endian, we load the TOC from the OPD. For little-
+ // endian, we use the .TOC. symbol to find it.
+ nop
+ bcl 20,31,1f
+1:
+ mflr r2
+#if _CALL_ELF == 2
+ addis r2,r2,.TOC.-1b@ha
+ addi r2,r2,.TOC.-1b@l
+#else
+ addis r2,r2,_setjmp-1b@ha
+ addi r2,r2,_setjmp-1b@l
+ ld r2,8(r2)
+#endif
+ // Call the interceptor.
+ bl __tsan_setjmp
+ nop
+ // Restore regs needed for __sigsetjmp.
+ ld r3,32(r1)
+ ld r4,40(r1)
+ ld r0,48(r1)
+ // Emulate the real sigsetjmp function. We do this because we can't
+ // perform a sibcall: The real sigsetjmp function trashes the TOC
+ // pointer, and with a sibcall we have no way to restore it.
+ // This way we can make sure our caller's stack pointer and
+ // link register are saved correctly in the jmpbuf.
+ ld r6,-28696(r13)
+ addi r5,r1,64 // original stack ptr of caller
+ xor r5,r6,r5
+ std r5,0(r3) // mangled stack ptr of caller
+ ld r5,24(r1)
+ std r5,8(r3) // caller's saved TOC pointer
+ xor r0,r6,r0
+ std r0,16(r3) // caller's mangled return address
+ mfcr r0
+ // Nonvolatiles.
+ std r14,24(r3)
+ stfd f14,176(r3)
+ stw r0,172(r3) // CR
+ std r15,32(r3)
+ stfd f15,184(r3)
+ std r16,40(r3)
+ stfd f16,192(r3)
+ std r17,48(r3)
+ stfd f17,200(r3)
+ std r18,56(r3)
+ stfd f18,208(r3)
+ std r19,64(r3)
+ stfd f19,216(r3)
+ std r20,72(r3)
+ stfd f20,224(r3)
+ std r21,80(r3)
+ stfd f21,232(r3)
+ std r22,88(r3)
+ stfd f22,240(r3)
+ std r23,96(r3)
+ stfd f23,248(r3)
+ std r24,104(r3)
+ stfd f24,256(r3)
+ std r25,112(r3)
+ stfd f25,264(r3)
+ std r26,120(r3)
+ stfd f26,272(r3)
+ std r27,128(r3)
+ stfd f27,280(r3)
+ std r28,136(r3)
+ stfd f28,288(r3)
+ std r29,144(r3)
+ stfd f29,296(r3)
+ std r30,152(r3)
+ stfd f30,304(r3)
+ std r31,160(r3)
+ stfd f31,312(r3)
+ addi r5,r3,320
+ mfspr r0,256
+ stw r0,168(r3) // VRSAVE
+ addi r6,r5,16
+ stvx v20,0,r5
+ addi r5,r5,32
+ stvx v21,0,r6
+ addi r6,r6,32
+ stvx v22,0,r5
+ addi r5,r5,32
+ stvx v23,0,r6
+ addi r6,r6,32
+ stvx v24,0,r5
+ addi r5,r5,32
+ stvx v25,0,r6
+ addi r6,r6,32
+ stvx v26,0,r5
+ addi r5,r5,32
+ stvx v27,0,r6
+ addi r6,r6,32
+ stvx v28,0,r5
+ addi r5,r5,32
+ stvx v29,0,r6
+ addi r6,r6,32
+ stvx v30,0,r5
+ stvx v31,0,r6
+ // Save into the "mask-saved" slot.
+ stw r4,512(r3)
+ // Restore TOC, LR, and stack and return to caller.
+ ld r2,24(r1)
+ ld r0,48(r1)
+ addi r1,r1,64
+ li r3,0 // This is the sigsetjmp return path
+ mtlr r0
+ blr
+ .size __sigsetjmp, .-.L.__sigsetjmp
+
+ .globl sigsetjmp
+ .type sigsetjmp, @function
+ .align 4
+sigsetjmp:
+ b __sigsetjmp
+ .size sigsetjmp, .-sigsetjmp
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cc b/contrib/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cc
index dc9438e6371b..5aff6ca56adf 100644
--- a/contrib/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cc
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cc
@@ -49,8 +49,8 @@ void TsanCheckFailed(const char *file, int line, const char *cond,
#ifdef TSAN_EXTERNAL_HOOKS
bool OnReport(const ReportDesc *rep, bool suppressed);
#else
-SANITIZER_INTERFACE_ATTRIBUTE
-bool WEAK OnReport(const ReportDesc *rep, bool suppressed) {
+SANITIZER_WEAK_CXX_DEFAULT_IMPL
+bool OnReport(const ReportDesc *rep, bool suppressed) {
(void)rep;
return suppressed;
}
@@ -186,7 +186,7 @@ void ScopedReport::AddThread(const ThreadContext *tctx, bool suppressable) {
return;
}
void *mem = internal_alloc(MBlockReportThread, sizeof(ReportThread));
- ReportThread *rt = new(mem) ReportThread();
+ ReportThread *rt = new(mem) ReportThread;
rep_->threads.PushBack(rt);
rt->id = tctx->tid;
rt->pid = tctx->os_id;
@@ -200,16 +200,16 @@ void ScopedReport::AddThread(const ThreadContext *tctx, bool suppressable) {
}
#ifndef SANITIZER_GO
+static bool FindThreadByUidLockedCallback(ThreadContextBase *tctx, void *arg) {
+ int unique_id = *(int *)arg;
+ return tctx->unique_id == (u32)unique_id;
+}
+
static ThreadContext *FindThreadByUidLocked(int unique_id) {
ctx->thread_registry->CheckLocked();
- for (unsigned i = 0; i < kMaxTid; i++) {
- ThreadContext *tctx = static_cast<ThreadContext*>(
- ctx->thread_registry->GetThreadLocked(i));
- if (tctx && tctx->unique_id == (u32)unique_id) {
- return tctx;
- }
- }
- return 0;
+ return static_cast<ThreadContext *>(
+ ctx->thread_registry->FindThreadContextLocked(
+ FindThreadByUidLockedCallback, &unique_id));
}
static ThreadContext *FindThreadByTidLocked(int tid) {
@@ -256,7 +256,7 @@ void ScopedReport::AddMutex(const SyncVar *s) {
return;
}
void *mem = internal_alloc(MBlockReportMutex, sizeof(ReportMutex));
- ReportMutex *rm = new(mem) ReportMutex();
+ ReportMutex *rm = new(mem) ReportMutex;
rep_->mutexes.PushBack(rm);
rm->id = s->uid;
rm->addr = s->addr;
@@ -289,7 +289,7 @@ void ScopedReport::AddDeadMutex(u64 id) {
return;
}
void *mem = internal_alloc(MBlockReportMutex, sizeof(ReportMutex));
- ReportMutex *rm = new(mem) ReportMutex();
+ ReportMutex *rm = new(mem) ReportMutex;
rep_->mutexes.PushBack(rm);
rm->id = id;
rm->addr = 0;
@@ -369,27 +369,20 @@ void RestoreStack(int tid, const u64 epoch, VarSizeStackTrace *stk,
// This function restores stack trace and mutex set for the thread/epoch.
// It does so by getting stack trace and mutex set at the beginning of
// trace part, and then replaying the trace till the given epoch.
- ctx->thread_registry->CheckLocked();
- ThreadContext *tctx = static_cast<ThreadContext*>(
- ctx->thread_registry->GetThreadLocked(tid));
- if (tctx == 0)
- return;
- if (tctx->status != ThreadStatusRunning
- && tctx->status != ThreadStatusFinished
- && tctx->status != ThreadStatusDead)
- return;
- Trace* trace = ThreadTrace(tctx->tid);
- Lock l(&trace->mtx);
+ Trace* trace = ThreadTrace(tid);
+ ReadLock l(&trace->mtx);
const int partidx = (epoch / kTracePartSize) % TraceParts();
TraceHeader* hdr = &trace->headers[partidx];
- if (epoch < hdr->epoch0)
+ if (epoch < hdr->epoch0 || epoch >= hdr->epoch0 + kTracePartSize)
return;
+ CHECK_EQ(RoundDown(epoch, kTracePartSize), hdr->epoch0);
const u64 epoch0 = RoundDown(epoch, TraceSize());
const u64 eend = epoch % TraceSize();
const u64 ebegin = RoundDown(eend, kTracePartSize);
DPrintf("#%d: RestoreStack epoch=%zu ebegin=%zu eend=%zu partidx=%d\n",
tid, (uptr)epoch, (uptr)ebegin, (uptr)eend, partidx);
- InternalScopedBuffer<uptr> stack(kShadowStackSize);
+ Vector<uptr> stack(MBlockReportStack);
+ stack.Resize(hdr->stack0.size + 64);
for (uptr i = 0; i < hdr->stack0.size; i++) {
stack[i] = hdr->stack0.trace[i];
DPrintf2(" #%02zu: pc=%zx\n", i, stack[i]);
@@ -406,6 +399,8 @@ void RestoreStack(int tid, const u64 epoch, VarSizeStackTrace *stk,
if (typ == EventTypeMop) {
stack[pos] = pc;
} else if (typ == EventTypeFuncEnter) {
+ if (stack.Size() < pos + 2)
+ stack.Resize(pos + 2);
stack[pos++] = pc;
} else if (typ == EventTypeFuncExit) {
if (pos > 0)
@@ -428,50 +423,58 @@ void RestoreStack(int tid, const u64 epoch, VarSizeStackTrace *stk,
if (pos == 0 && stack[0] == 0)
return;
pos++;
- stk->Init(stack.data(), pos);
+ stk->Init(&stack[0], pos);
}
static bool HandleRacyStacks(ThreadState *thr, VarSizeStackTrace traces[2],
uptr addr_min, uptr addr_max) {
bool equal_stack = false;
RacyStacks hash;
- if (flags()->suppress_equal_stacks) {
- hash.hash[0] = md5_hash(traces[0].trace, traces[0].size * sizeof(uptr));
- hash.hash[1] = md5_hash(traces[1].trace, traces[1].size * sizeof(uptr));
- for (uptr i = 0; i < ctx->racy_stacks.Size(); i++) {
- if (hash == ctx->racy_stacks[i]) {
- DPrintf("ThreadSanitizer: suppressing report as doubled (stack)\n");
- equal_stack = true;
- break;
- }
- }
- }
bool equal_address = false;
RacyAddress ra0 = {addr_min, addr_max};
- if (flags()->suppress_equal_addresses) {
- for (uptr i = 0; i < ctx->racy_addresses.Size(); i++) {
- RacyAddress ra2 = ctx->racy_addresses[i];
- uptr maxbeg = max(ra0.addr_min, ra2.addr_min);
- uptr minend = min(ra0.addr_max, ra2.addr_max);
- if (maxbeg < minend) {
- DPrintf("ThreadSanitizer: suppressing report as doubled (addr)\n");
- equal_address = true;
- break;
+ {
+ ReadLock lock(&ctx->racy_mtx);
+ if (flags()->suppress_equal_stacks) {
+ hash.hash[0] = md5_hash(traces[0].trace, traces[0].size * sizeof(uptr));
+ hash.hash[1] = md5_hash(traces[1].trace, traces[1].size * sizeof(uptr));
+ for (uptr i = 0; i < ctx->racy_stacks.Size(); i++) {
+ if (hash == ctx->racy_stacks[i]) {
+ VPrintf(2,
+ "ThreadSanitizer: suppressing report as doubled (stack)\n");
+ equal_stack = true;
+ break;
+ }
+ }
+ }
+ if (flags()->suppress_equal_addresses) {
+ for (uptr i = 0; i < ctx->racy_addresses.Size(); i++) {
+ RacyAddress ra2 = ctx->racy_addresses[i];
+ uptr maxbeg = max(ra0.addr_min, ra2.addr_min);
+ uptr minend = min(ra0.addr_max, ra2.addr_max);
+ if (maxbeg < minend) {
+ VPrintf(2, "ThreadSanitizer: suppressing report as doubled (addr)\n");
+ equal_address = true;
+ break;
+ }
}
}
}
- if (equal_stack || equal_address) {
- if (!equal_stack)
- ctx->racy_stacks.PushBack(hash);
- if (!equal_address)
- ctx->racy_addresses.PushBack(ra0);
- return true;
+ if (!equal_stack && !equal_address)
+ return false;
+ if (!equal_stack) {
+ Lock lock(&ctx->racy_mtx);
+ ctx->racy_stacks.PushBack(hash);
}
- return false;
+ if (!equal_address) {
+ Lock lock(&ctx->racy_mtx);
+ ctx->racy_addresses.PushBack(ra0);
+ }
+ return true;
}
static void AddRacyStacks(ThreadState *thr, VarSizeStackTrace traces[2],
uptr addr_min, uptr addr_max) {
+ Lock lock(&ctx->racy_mtx);
if (flags()->suppress_equal_stacks) {
RacyStacks hash;
hash.hash[0] = md5_hash(traces[0].trace, traces[0].size * sizeof(uptr));
@@ -485,26 +488,29 @@ static void AddRacyStacks(ThreadState *thr, VarSizeStackTrace traces[2],
}
bool OutputReport(ThreadState *thr, const ScopedReport &srep) {
- atomic_store(&ctx->last_symbolize_time_ns, NanoTime(), memory_order_relaxed);
+ if (!flags()->report_bugs)
+ return false;
+ atomic_store_relaxed(&ctx->last_symbolize_time_ns, NanoTime());
const ReportDesc *rep = srep.GetReport();
Suppression *supp = 0;
- uptr suppress_pc = 0;
- for (uptr i = 0; suppress_pc == 0 && i < rep->mops.Size(); i++)
- suppress_pc = IsSuppressed(rep->typ, rep->mops[i]->stack, &supp);
- for (uptr i = 0; suppress_pc == 0 && i < rep->stacks.Size(); i++)
- suppress_pc = IsSuppressed(rep->typ, rep->stacks[i], &supp);
- for (uptr i = 0; suppress_pc == 0 && i < rep->threads.Size(); i++)
- suppress_pc = IsSuppressed(rep->typ, rep->threads[i]->stack, &supp);
- for (uptr i = 0; suppress_pc == 0 && i < rep->locs.Size(); i++)
- suppress_pc = IsSuppressed(rep->typ, rep->locs[i], &supp);
- if (suppress_pc != 0) {
- FiredSuppression s = {srep.GetReport()->typ, suppress_pc, supp};
+ uptr pc_or_addr = 0;
+ for (uptr i = 0; pc_or_addr == 0 && i < rep->mops.Size(); i++)
+ pc_or_addr = IsSuppressed(rep->typ, rep->mops[i]->stack, &supp);
+ for (uptr i = 0; pc_or_addr == 0 && i < rep->stacks.Size(); i++)
+ pc_or_addr = IsSuppressed(rep->typ, rep->stacks[i], &supp);
+ for (uptr i = 0; pc_or_addr == 0 && i < rep->threads.Size(); i++)
+ pc_or_addr = IsSuppressed(rep->typ, rep->threads[i]->stack, &supp);
+ for (uptr i = 0; pc_or_addr == 0 && i < rep->locs.Size(); i++)
+ pc_or_addr = IsSuppressed(rep->typ, rep->locs[i], &supp);
+ if (pc_or_addr != 0) {
+ Lock lock(&ctx->fired_suppressions_mtx);
+ FiredSuppression s = {srep.GetReport()->typ, pc_or_addr, supp};
ctx->fired_suppressions.push_back(s);
}
{
bool old_is_freeing = thr->is_freeing;
thr->is_freeing = false;
- bool suppressed = OnReport(rep, suppress_pc != 0);
+ bool suppressed = OnReport(rep, pc_or_addr != 0);
thr->is_freeing = old_is_freeing;
if (suppressed)
return false;
@@ -512,20 +518,20 @@ bool OutputReport(ThreadState *thr, const ScopedReport &srep) {
PrintReport(rep);
ctx->nreported++;
if (flags()->halt_on_error)
- internal__exit(flags()->exitcode);
+ Die();
return true;
}
-bool IsFiredSuppression(Context *ctx, const ScopedReport &srep,
- StackTrace trace) {
+bool IsFiredSuppression(Context *ctx, ReportType type, StackTrace trace) {
+ ReadLock lock(&ctx->fired_suppressions_mtx);
for (uptr k = 0; k < ctx->fired_suppressions.size(); k++) {
- if (ctx->fired_suppressions[k].type != srep.GetReport()->typ)
+ if (ctx->fired_suppressions[k].type != type)
continue;
for (uptr j = 0; j < trace.size; j++) {
FiredSuppression *s = &ctx->fired_suppressions[k];
- if (trace.trace[j] == s->pc) {
+ if (trace.trace[j] == s->pc_or_addr) {
if (s->supp)
- s->supp->hit_count++;
+ atomic_fetch_add(&s->supp->hit_count, 1, memory_order_relaxed);
return true;
}
}
@@ -533,16 +539,15 @@ bool IsFiredSuppression(Context *ctx, const ScopedReport &srep,
return false;
}
-static bool IsFiredSuppression(Context *ctx,
- const ScopedReport &srep,
- uptr addr) {
+static bool IsFiredSuppression(Context *ctx, ReportType type, uptr addr) {
+ ReadLock lock(&ctx->fired_suppressions_mtx);
for (uptr k = 0; k < ctx->fired_suppressions.size(); k++) {
- if (ctx->fired_suppressions[k].type != srep.GetReport()->typ)
+ if (ctx->fired_suppressions[k].type != type)
continue;
FiredSuppression *s = &ctx->fired_suppressions[k];
- if (addr == s->pc) {
+ if (addr == s->pc_or_addr) {
if (s->supp)
- s->supp->hit_count++;
+ atomic_fetch_add(&s->supp->hit_count, 1, memory_order_relaxed);
return true;
}
}
@@ -595,8 +600,6 @@ void ReportRace(ThreadState *thr) {
return;
}
- ThreadRegistryLock l0(ctx->thread_registry);
-
ReportType typ = ReportTypeRace;
if (thr->is_vptr_access && freed)
typ = ReportTypeVptrUseAfterFree;
@@ -604,29 +607,35 @@ void ReportRace(ThreadState *thr) {
typ = ReportTypeVptrRace;
else if (freed)
typ = ReportTypeUseAfterFree;
- ScopedReport rep(typ);
- if (IsFiredSuppression(ctx, rep, addr))
+
+ if (IsFiredSuppression(ctx, typ, addr))
return;
+
const uptr kMop = 2;
VarSizeStackTrace traces[kMop];
const uptr toppc = TraceTopPC(thr);
ObtainCurrentStack(thr, toppc, &traces[0]);
- if (IsFiredSuppression(ctx, rep, traces[0]))
+ if (IsFiredSuppression(ctx, typ, traces[0]))
return;
- InternalScopedBuffer<MutexSet> mset2(1);
- new(mset2.data()) MutexSet();
+
+ // MutexSet is too large to live on stack.
+ Vector<u64> mset_buffer(MBlockScopedBuf);
+ mset_buffer.Resize(sizeof(MutexSet) / sizeof(u64) + 1);
+ MutexSet *mset2 = new(&mset_buffer[0]) MutexSet();
+
Shadow s2(thr->racy_state[1]);
- RestoreStack(s2.tid(), s2.epoch(), &traces[1], mset2.data());
- if (IsFiredSuppression(ctx, rep, traces[1]))
+ RestoreStack(s2.tid(), s2.epoch(), &traces[1], mset2);
+ if (IsFiredSuppression(ctx, typ, traces[1]))
return;
if (HandleRacyStacks(thr, traces, addr_min, addr_max))
return;
+ ThreadRegistryLock l0(ctx->thread_registry);
+ ScopedReport rep(typ);
for (uptr i = 0; i < kMop; i++) {
Shadow s(thr->racy_state[i]);
- rep.AddMemoryAccess(addr, s, traces[i],
- i == 0 ? &thr->mset : mset2.data());
+ rep.AddMemoryAccess(addr, s, traces[i], i == 0 ? &thr->mset : mset2);
}
for (uptr i = 0; i < kMop; i++) {
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_rtl_thread.cc b/contrib/compiler-rt/lib/tsan/rtl/tsan_rtl_thread.cc
index 66c78cfdd7c0..dcae255f7643 100644
--- a/contrib/compiler-rt/lib/tsan/rtl/tsan_rtl_thread.cc
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_rtl_thread.cc
@@ -55,6 +55,8 @@ void ThreadContext::OnCreated(void *arg) {
if (tid == 0)
return;
OnCreatedArgs *args = static_cast<OnCreatedArgs *>(arg);
+ if (!args->thr) // GCD workers don't have a parent thread.
+ return;
args->thr->fast_state.IncrementEpoch();
// Can't increment epoch w/o writing to the trace as well.
TraceAddEvent(args->thr, args->thr->fast_state, EventTypeMop, 0);
@@ -231,8 +233,10 @@ int ThreadCount(ThreadState *thr) {
int ThreadCreate(ThreadState *thr, uptr pc, uptr uid, bool detached) {
StatInc(thr, StatThreadCreate);
OnCreatedArgs args = { thr, pc };
- int tid = ctx->thread_registry->CreateThread(uid, detached, thr->tid, &args);
- DPrintf("#%d: ThreadCreate tid=%d uid=%zu\n", thr->tid, tid, uid);
+ u32 parent_tid = thr ? thr->tid : kInvalidTid; // No parent for GCD workers.
+ int tid =
+ ctx->thread_registry->CreateThread(uid, detached, parent_tid, &args);
+ DPrintf("#%d: ThreadCreate tid=%d uid=%zu\n", parent_tid, tid, uid);
StatSet(thr, StatThreadMaxAlive, ctx->thread_registry->GetMaxAliveThreads());
return tid;
}
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_stat.cc b/contrib/compiler-rt/lib/tsan/rtl/tsan_stat.cc
index 15fa43d6f8a1..a5cca9679582 100644
--- a/contrib/compiler-rt/lib/tsan/rtl/tsan_stat.cc
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_stat.cc
@@ -164,8 +164,9 @@ void StatOutput(u64 *stat) {
name[StatMtxAtExit] = " Atexit ";
name[StatMtxAnnotations] = " Annotations ";
name[StatMtxMBlock] = " MBlock ";
- name[StatMtxJavaMBlock] = " JavaMBlock ";
name[StatMtxDeadlockDetector] = " DeadlockDetector ";
+ name[StatMtxFired] = " FiredSuppressions ";
+ name[StatMtxRacy] = " RacyStacks ";
name[StatMtxFD] = " FD ";
Printf("Statistics:\n");
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_stat.h b/contrib/compiler-rt/lib/tsan/rtl/tsan_stat.h
index 0bd949ed1563..8ea32048e147 100644
--- a/contrib/compiler-rt/lib/tsan/rtl/tsan_stat.h
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_stat.h
@@ -169,8 +169,9 @@ enum StatType {
StatMtxAnnotations,
StatMtxAtExit,
StatMtxMBlock,
- StatMtxJavaMBlock,
StatMtxDeadlockDetector,
+ StatMtxFired,
+ StatMtxRacy,
StatMtxFD,
// This must be the last.
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_suppressions.cc b/contrib/compiler-rt/lib/tsan/rtl/tsan_suppressions.cc
index e382f21f0dff..8754b61c60cd 100644
--- a/contrib/compiler-rt/lib/tsan/rtl/tsan_suppressions.cc
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_suppressions.cc
@@ -34,7 +34,8 @@ static const char *const std_suppressions =
"race:std::_Sp_counted_ptr_inplace<std::thread::_Impl\n";
// Can be overriden in frontend.
-extern "C" const char *WEAK __tsan_default_suppressions() {
+SANITIZER_WEAK_DEFAULT_IMPL
+const char *__tsan_default_suppressions() {
return 0;
}
#endif
@@ -100,8 +101,8 @@ static uptr IsSuppressed(const char *stype, const AddressInfo &info,
if (suppression_ctx->Match(info.function, stype, sp) ||
suppression_ctx->Match(info.file, stype, sp) ||
suppression_ctx->Match(info.module, stype, sp)) {
- DPrintf("ThreadSanitizer: matched suppression '%s'\n", (*sp)->templ);
- (*sp)->hit_count++;
+ VPrintf(2, "ThreadSanitizer: matched suppression '%s'\n", (*sp)->templ);
+ atomic_fetch_add(&(*sp)->hit_count, 1, memory_order_relaxed);
return info.address;
}
return 0;
@@ -138,8 +139,8 @@ uptr IsSuppressed(ReportType typ, const ReportLocation *loc, Suppression **sp) {
const DataInfo &global = loc->global;
if (suppression_ctx->Match(global.name, stype, &s) ||
suppression_ctx->Match(global.module, stype, &s)) {
- DPrintf("ThreadSanitizer: matched suppression '%s'\n", s->templ);
- s->hit_count++;
+ VPrintf(2, "ThreadSanitizer: matched suppression '%s'\n", s->templ);
+ atomic_fetch_add(&s->hit_count, 1, memory_order_relaxed);
*sp = s;
return global.start;
}
@@ -154,7 +155,7 @@ void PrintMatchedSuppressions() {
return;
int hit_count = 0;
for (uptr i = 0; i < matched.size(); i++)
- hit_count += matched[i]->hit_count;
+ hit_count += atomic_load_relaxed(&matched[i]->hit_count);
Printf("ThreadSanitizer: Matched %d suppressions (pid=%d):\n", hit_count,
(int)internal_getpid());
for (uptr i = 0; i < matched.size(); i++) {
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_symbolize.cc b/contrib/compiler-rt/lib/tsan/rtl/tsan_symbolize.cc
index a6b9bca0501d..b2423951795f 100644
--- a/contrib/compiler-rt/lib/tsan/rtl/tsan_symbolize.cc
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_symbolize.cc
@@ -38,10 +38,10 @@ void ExitSymbolizer() {
// May be overriden by JIT/JAVA/etc,
// whatever produces PCs marked with kExternalPCBit.
-extern "C" bool WEAK __tsan_symbolize_external(uptr pc,
- char *func_buf, uptr func_siz,
- char *file_buf, uptr file_siz,
- int *line, int *col) {
+SANITIZER_WEAK_DEFAULT_IMPL
+bool __tsan_symbolize_external(uptr pc, char *func_buf, uptr func_siz,
+ char *file_buf, uptr file_siz, int *line,
+ int *col) {
return false;
}
@@ -71,7 +71,7 @@ ReportLocation *SymbolizeData(uptr addr) {
if (!Symbolizer::GetOrInit()->SymbolizeData(addr, &info))
return 0;
ReportLocation *ent = ReportLocation::New(ReportLocationGlobal);
- ent->global = info;
+ internal_memcpy(&ent->global, &info, sizeof(info));
return ent;
}
diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_sync.h b/contrib/compiler-rt/lib/tsan/rtl/tsan_sync.h
index 2d12cdff8b2f..f07ea3b9776b 100644
--- a/contrib/compiler-rt/lib/tsan/rtl/tsan_sync.h
+++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_sync.h
@@ -86,9 +86,9 @@ class MetaMap {
void OnThreadIdle(ThreadState *thr);
private:
- static const u32 kFlagMask = 3 << 30;
- static const u32 kFlagBlock = 1 << 30;
- static const u32 kFlagSync = 2 << 30;
+ static const u32 kFlagMask = 3u << 30;
+ static const u32 kFlagBlock = 1u << 30;
+ static const u32 kFlagSync = 2u << 30;
typedef DenseSlabAlloc<MBlock, 1<<16, 1<<12> BlockAlloc;
typedef DenseSlabAlloc<SyncVar, 1<<16, 1<<10> SyncAlloc;
BlockAlloc block_alloc_;
diff --git a/contrib/compiler-rt/lib/tsan/tests/rtl/tsan_bench.cc b/contrib/compiler-rt/lib/tsan/tests/rtl/tsan_bench.cc
deleted file mode 100644
index a3cf22f2c626..000000000000
--- a/contrib/compiler-rt/lib/tsan/tests/rtl/tsan_bench.cc
+++ /dev/null
@@ -1,105 +0,0 @@
-//===-- tsan_bench.cc -----------------------------------------------------===//
-//
-// 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 ThreadSanitizer (TSan), a race detector.
-//
-//===----------------------------------------------------------------------===//
-#include "tsan_test_util.h"
-#include "tsan_interface.h"
-#include "tsan_defs.h"
-#include "gtest/gtest.h"
-#include <stdint.h>
-
-const int kSize = 128;
-const int kRepeat = 2*1024*1024;
-
-void noinstr(void *p) {}
-
-template<typename T, void(*__tsan_mop)(void *p)>
-static void Benchmark() {
- volatile T data[kSize];
- for (int i = 0; i < kRepeat; i++) {
- for (int j = 0; j < kSize; j++) {
- __tsan_mop((void*)&data[j]);
- data[j]++;
- }
- }
-}
-
-TEST(DISABLED_BENCH, Mop1) {
- Benchmark<uint8_t, noinstr>();
-}
-
-TEST(DISABLED_BENCH, Mop1Read) {
- Benchmark<uint8_t, __tsan_read1>();
-}
-
-TEST(DISABLED_BENCH, Mop1Write) {
- Benchmark<uint8_t, __tsan_write1>();
-}
-
-TEST(DISABLED_BENCH, Mop2) {
- Benchmark<uint16_t, noinstr>();
-}
-
-TEST(DISABLED_BENCH, Mop2Read) {
- Benchmark<uint16_t, __tsan_read2>();
-}
-
-TEST(DISABLED_BENCH, Mop2Write) {
- Benchmark<uint16_t, __tsan_write2>();
-}
-
-TEST(DISABLED_BENCH, Mop4) {
- Benchmark<uint32_t, noinstr>();
-}
-
-TEST(DISABLED_BENCH, Mop4Read) {
- Benchmark<uint32_t, __tsan_read4>();
-}
-
-TEST(DISABLED_BENCH, Mop4Write) {
- Benchmark<uint32_t, __tsan_write4>();
-}
-
-TEST(DISABLED_BENCH, Mop8) {
- Benchmark<uint8_t, noinstr>();
-}
-
-TEST(DISABLED_BENCH, Mop8Read) {
- Benchmark<uint64_t, __tsan_read8>();
-}
-
-TEST(DISABLED_BENCH, Mop8Write) {
- Benchmark<uint64_t, __tsan_write8>();
-}
-
-TEST(DISABLED_BENCH, FuncCall) {
- for (int i = 0; i < kRepeat; i++) {
- for (int j = 0; j < kSize; j++)
- __tsan_func_entry((void*)(uintptr_t)j);
- for (int j = 0; j < kSize; j++)
- __tsan_func_exit();
- }
-}
-
-TEST(DISABLED_BENCH, MutexLocal) {
- Mutex m;
- ScopedThread().Create(m);
- for (int i = 0; i < 50; i++) {
- ScopedThread t;
- t.Lock(m);
- t.Unlock(m);
- }
- for (int i = 0; i < 16*1024*1024; i++) {
- m.Lock();
- m.Unlock();
- }
- ScopedThread().Destroy(m);
-}
diff --git a/contrib/compiler-rt/lib/tsan/tests/rtl/tsan_mop.cc b/contrib/compiler-rt/lib/tsan/tests/rtl/tsan_mop.cc
deleted file mode 100644
index f21742825050..000000000000
--- a/contrib/compiler-rt/lib/tsan/tests/rtl/tsan_mop.cc
+++ /dev/null
@@ -1,233 +0,0 @@
-//===-- tsan_mop.cc -------------------------------------------------------===//
-//
-// 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 ThreadSanitizer (TSan), a race detector.
-//
-//===----------------------------------------------------------------------===//
-#include "tsan_interface.h"
-#include "tsan_test_util.h"
-#include "gtest/gtest.h"
-#include <stddef.h>
-#include <stdint.h>
-
-TEST(ThreadSanitizer, SimpleWrite) {
- ScopedThread t;
- MemLoc l;
- t.Write1(l);
-}
-
-TEST(ThreadSanitizer, SimpleWriteWrite) {
- ScopedThread t1, t2;
- MemLoc l1, l2;
- t1.Write1(l1);
- t2.Write1(l2);
-}
-
-TEST(ThreadSanitizer, WriteWriteRace) {
- ScopedThread t1, t2;
- MemLoc l;
- t1.Write1(l);
- t2.Write1(l, true);
-}
-
-TEST(ThreadSanitizer, ReadWriteRace) {
- ScopedThread t1, t2;
- MemLoc l;
- t1.Read1(l);
- t2.Write1(l, true);
-}
-
-TEST(ThreadSanitizer, WriteReadRace) {
- ScopedThread t1, t2;
- MemLoc l;
- t1.Write1(l);
- t2.Read1(l, true);
-}
-
-TEST(ThreadSanitizer, ReadReadNoRace) {
- ScopedThread t1, t2;
- MemLoc l;
- t1.Read1(l);
- t2.Read1(l);
-}
-
-TEST(ThreadSanitizer, WriteThenRead) {
- MemLoc l;
- ScopedThread t1, t2;
- t1.Write1(l);
- t1.Read1(l);
- t2.Read1(l, true);
-}
-
-TEST(ThreadSanitizer, WriteThenLockedRead) {
- Mutex m(Mutex::RW);
- MainThread t0;
- t0.Create(m);
- MemLoc l;
- {
- ScopedThread t1, t2;
-
- t1.Write8(l);
-
- t1.Lock(m);
- t1.Read8(l);
- t1.Unlock(m);
-
- t2.Read8(l, true);
- }
- t0.Destroy(m);
-}
-
-TEST(ThreadSanitizer, LockedWriteThenRead) {
- Mutex m(Mutex::RW);
- MainThread t0;
- t0.Create(m);
- MemLoc l;
- {
- ScopedThread t1, t2;
-
- t1.Lock(m);
- t1.Write8(l);
- t1.Unlock(m);
-
- t1.Read8(l);
-
- t2.Read8(l, true);
- }
- t0.Destroy(m);
-}
-
-
-TEST(ThreadSanitizer, RaceWithOffset) {
- ScopedThread t1, t2;
- {
- MemLoc l;
- t1.Access(l.loc(), true, 8, false);
- t2.Access((char*)l.loc() + 4, true, 4, true);
- }
- {
- MemLoc l;
- t1.Access(l.loc(), true, 8, false);
- t2.Access((char*)l.loc() + 7, true, 1, true);
- }
- {
- MemLoc l;
- t1.Access((char*)l.loc() + 4, true, 4, false);
- t2.Access((char*)l.loc() + 4, true, 2, true);
- }
- {
- MemLoc l;
- t1.Access((char*)l.loc() + 4, true, 4, false);
- t2.Access((char*)l.loc() + 6, true, 2, true);
- }
- {
- MemLoc l;
- t1.Access((char*)l.loc() + 3, true, 2, false);
- t2.Access((char*)l.loc() + 4, true, 1, true);
- }
- {
- MemLoc l;
- t1.Access((char*)l.loc() + 1, true, 8, false);
- t2.Access((char*)l.loc() + 3, true, 1, true);
- }
-}
-
-TEST(ThreadSanitizer, RaceWithOffset2) {
- ScopedThread t1, t2;
- {
- MemLoc l;
- t1.Access((char*)l.loc(), true, 4, false);
- t2.Access((char*)l.loc() + 2, true, 1, true);
- }
- {
- MemLoc l;
- t1.Access((char*)l.loc() + 2, true, 1, false);
- t2.Access((char*)l.loc(), true, 4, true);
- }
-}
-
-TEST(ThreadSanitizer, NoRaceWithOffset) {
- ScopedThread t1, t2;
- {
- MemLoc l;
- t1.Access(l.loc(), true, 4, false);
- t2.Access((char*)l.loc() + 4, true, 4, false);
- }
- {
- MemLoc l;
- t1.Access((char*)l.loc() + 3, true, 2, false);
- t2.Access((char*)l.loc() + 1, true, 2, false);
- t2.Access((char*)l.loc() + 5, true, 2, false);
- }
-}
-
-TEST(ThreadSanitizer, RaceWithDeadThread) {
- MemLoc l;
- ScopedThread t;
- ScopedThread().Write1(l);
- t.Write1(l, true);
-}
-
-TEST(ThreadSanitizer, BenignRaceOnVptr) {
- void *vptr_storage;
- MemLoc vptr(&vptr_storage), val;
- vptr_storage = val.loc();
- ScopedThread t1, t2;
- t1.VptrUpdate(vptr, val);
- t2.Read8(vptr);
-}
-
-TEST(ThreadSanitizer, HarmfulRaceOnVptr) {
- void *vptr_storage;
- MemLoc vptr(&vptr_storage), val1, val2;
- vptr_storage = val1.loc();
- ScopedThread t1, t2;
- t1.VptrUpdate(vptr, val2);
- t2.Read8(vptr, true);
-}
-
-static void foo() {
- volatile int x = 42;
- int x2 = x;
- (void)x2;
-}
-
-static void bar() {
- volatile int x = 43;
- int x2 = x;
- (void)x2;
-}
-
-TEST(ThreadSanitizer, ReportDeadThread) {
- MemLoc l;
- ScopedThread t1;
- {
- ScopedThread t2;
- t2.Call(&foo);
- t2.Call(&bar);
- t2.Write1(l);
- }
- t1.Write1(l, true);
-}
-
-struct ClassWithStatic {
- static int Data[4];
-};
-
-int ClassWithStatic::Data[4];
-
-static void foobarbaz() {}
-
-TEST(ThreadSanitizer, ReportRace) {
- ScopedThread t1;
- MainThread().Access(&ClassWithStatic::Data, true, 4, false);
- t1.Call(&foobarbaz);
- t1.Access(&ClassWithStatic::Data, true, 2, true);
- t1.Return();
-}
diff --git a/contrib/compiler-rt/lib/tsan/tests/rtl/tsan_mutex.cc b/contrib/compiler-rt/lib/tsan/tests/rtl/tsan_mutex.cc
deleted file mode 100644
index 4d9c77961818..000000000000
--- a/contrib/compiler-rt/lib/tsan/tests/rtl/tsan_mutex.cc
+++ /dev/null
@@ -1,221 +0,0 @@
-//===-- tsan_mutex.cc -----------------------------------------------------===//
-//
-// 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 ThreadSanitizer (TSan), a race detector.
-//
-//===----------------------------------------------------------------------===//
-#include "sanitizer_common/sanitizer_atomic.h"
-#include "tsan_interface.h"
-#include "tsan_interface_ann.h"
-#include "tsan_test_util.h"
-#include "gtest/gtest.h"
-#include <stdint.h>
-
-namespace __tsan {
-
-TEST(ThreadSanitizer, BasicMutex) {
- ScopedThread t;
- Mutex m;
- t.Create(m);
-
- t.Lock(m);
- t.Unlock(m);
-
- CHECK(t.TryLock(m));
- t.Unlock(m);
-
- t.Lock(m);
- CHECK(!t.TryLock(m));
- t.Unlock(m);
-
- t.Destroy(m);
-}
-
-TEST(ThreadSanitizer, BasicSpinMutex) {
- ScopedThread t;
- Mutex m(Mutex::Spin);
- t.Create(m);
-
- t.Lock(m);
- t.Unlock(m);
-
- CHECK(t.TryLock(m));
- t.Unlock(m);
-
- t.Lock(m);
- CHECK(!t.TryLock(m));
- t.Unlock(m);
-
- t.Destroy(m);
-}
-
-TEST(ThreadSanitizer, BasicRwMutex) {
- ScopedThread t;
- Mutex m(Mutex::RW);
- t.Create(m);
-
- t.Lock(m);
- t.Unlock(m);
-
- CHECK(t.TryLock(m));
- t.Unlock(m);
-
- t.Lock(m);
- CHECK(!t.TryLock(m));
- t.Unlock(m);
-
- t.ReadLock(m);
- t.ReadUnlock(m);
-
- CHECK(t.TryReadLock(m));
- t.ReadUnlock(m);
-
- t.Lock(m);
- CHECK(!t.TryReadLock(m));
- t.Unlock(m);
-
- t.ReadLock(m);
- CHECK(!t.TryLock(m));
- t.ReadUnlock(m);
-
- t.ReadLock(m);
- CHECK(t.TryReadLock(m));
- t.ReadUnlock(m);
- t.ReadUnlock(m);
-
- t.Destroy(m);
-}
-
-TEST(ThreadSanitizer, Mutex) {
- Mutex m;
- MainThread t0;
- t0.Create(m);
-
- ScopedThread t1, t2;
- MemLoc l;
- t1.Lock(m);
- t1.Write1(l);
- t1.Unlock(m);
- t2.Lock(m);
- t2.Write1(l);
- t2.Unlock(m);
- t2.Destroy(m);
-}
-
-TEST(ThreadSanitizer, SpinMutex) {
- Mutex m(Mutex::Spin);
- MainThread t0;
- t0.Create(m);
-
- ScopedThread t1, t2;
- MemLoc l;
- t1.Lock(m);
- t1.Write1(l);
- t1.Unlock(m);
- t2.Lock(m);
- t2.Write1(l);
- t2.Unlock(m);
- t2.Destroy(m);
-}
-
-TEST(ThreadSanitizer, RwMutex) {
- Mutex m(Mutex::RW);
- MainThread t0;
- t0.Create(m);
-
- ScopedThread t1, t2, t3;
- MemLoc l;
- t1.Lock(m);
- t1.Write1(l);
- t1.Unlock(m);
- t2.Lock(m);
- t2.Write1(l);
- t2.Unlock(m);
- t1.ReadLock(m);
- t3.ReadLock(m);
- t1.Read1(l);
- t3.Read1(l);
- t1.ReadUnlock(m);
- t3.ReadUnlock(m);
- t2.Lock(m);
- t2.Write1(l);
- t2.Unlock(m);
- t2.Destroy(m);
-}
-
-TEST(ThreadSanitizer, StaticMutex) {
- // Emulates statically initialized mutex.
- Mutex m;
- m.StaticInit();
- {
- ScopedThread t1, t2;
- t1.Lock(m);
- t1.Unlock(m);
- t2.Lock(m);
- t2.Unlock(m);
- }
- MainThread().Destroy(m);
-}
-
-static void *singleton_thread(void *param) {
- atomic_uintptr_t *singleton = (atomic_uintptr_t *)param;
- for (int i = 0; i < 4*1024*1024; i++) {
- int *val = (int *)atomic_load(singleton, memory_order_acquire);
- __tsan_acquire(singleton);
- __tsan_read4(val);
- CHECK_EQ(*val, 42);
- }
- return 0;
-}
-
-TEST(DISABLED_BENCH_ThreadSanitizer, Singleton) {
- const int kClockSize = 100;
- const int kThreadCount = 8;
-
- // Puff off thread's clock.
- for (int i = 0; i < kClockSize; i++) {
- ScopedThread t1;
- (void)t1;
- }
- // Create the singleton.
- int val = 42;
- __tsan_write4(&val);
- atomic_uintptr_t singleton;
- __tsan_release(&singleton);
- atomic_store(&singleton, (uintptr_t)&val, memory_order_release);
- // Create reader threads.
- pthread_t threads[kThreadCount];
- for (int t = 0; t < kThreadCount; t++)
- pthread_create(&threads[t], 0, singleton_thread, &singleton);
- for (int t = 0; t < kThreadCount; t++)
- pthread_join(threads[t], 0);
-}
-
-TEST(DISABLED_BENCH_ThreadSanitizer, StopFlag) {
- const int kClockSize = 100;
- const int kIters = 16*1024*1024;
-
- // Puff off thread's clock.
- for (int i = 0; i < kClockSize; i++) {
- ScopedThread t1;
- (void)t1;
- }
- // Create the stop flag.
- atomic_uintptr_t flag;
- __tsan_release(&flag);
- atomic_store(&flag, 0, memory_order_release);
- // Read it a lot.
- for (int i = 0; i < kIters; i++) {
- uptr v = atomic_load(&flag, memory_order_acquire);
- __tsan_acquire(&flag);
- CHECK_EQ(v, 0);
- }
-}
-
-} // namespace __tsan
diff --git a/contrib/compiler-rt/lib/tsan/tests/rtl/tsan_posix.cc b/contrib/compiler-rt/lib/tsan/tests/rtl/tsan_posix.cc
deleted file mode 100644
index 0caedd7207e6..000000000000
--- a/contrib/compiler-rt/lib/tsan/tests/rtl/tsan_posix.cc
+++ /dev/null
@@ -1,146 +0,0 @@
-//===-- tsan_posix.cc -----------------------------------------------------===//
-//
-// 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 ThreadSanitizer (TSan), a race detector.
-//
-//===----------------------------------------------------------------------===//
-#include "tsan_interface.h"
-#include "tsan_test_util.h"
-#include "gtest/gtest.h"
-#include <pthread.h>
-
-struct thread_key {
- pthread_key_t key;
- pthread_mutex_t *mtx;
- int val;
- int *cnt;
- thread_key(pthread_key_t key, pthread_mutex_t *mtx, int val, int *cnt)
- : key(key)
- , mtx(mtx)
- , val(val)
- , cnt(cnt) {
- }
-};
-
-static void thread_secific_dtor(void *v) {
- thread_key *k = (thread_key *)v;
- EXPECT_EQ(pthread_mutex_lock(k->mtx), 0);
- (*k->cnt)++;
- __tsan_write4(&k->cnt);
- EXPECT_EQ(pthread_mutex_unlock(k->mtx), 0);
- if (k->val == 42) {
- delete k;
- } else if (k->val == 43 || k->val == 44) {
- k->val--;
- EXPECT_EQ(pthread_setspecific(k->key, k), 0);
- } else {
- ASSERT_TRUE(false);
- }
-}
-
-static void *dtors_thread(void *p) {
- thread_key *k = (thread_key *)p;
- EXPECT_EQ(pthread_setspecific(k->key, k), 0);
- return 0;
-}
-
-TEST(Posix, ThreadSpecificDtors) {
- int cnt = 0;
- pthread_key_t key;
- EXPECT_EQ(pthread_key_create(&key, thread_secific_dtor), 0);
- pthread_mutex_t mtx;
- EXPECT_EQ(pthread_mutex_init(&mtx, 0), 0);
- pthread_t th[3];
- thread_key *k[3];
- k[0] = new thread_key(key, &mtx, 42, &cnt);
- k[1] = new thread_key(key, &mtx, 43, &cnt);
- k[2] = new thread_key(key, &mtx, 44, &cnt);
- EXPECT_EQ(pthread_create(&th[0], 0, dtors_thread, k[0]), 0);
- EXPECT_EQ(pthread_create(&th[1], 0, dtors_thread, k[1]), 0);
- EXPECT_EQ(pthread_join(th[0], 0), 0);
- EXPECT_EQ(pthread_create(&th[2], 0, dtors_thread, k[2]), 0);
- EXPECT_EQ(pthread_join(th[1], 0), 0);
- EXPECT_EQ(pthread_join(th[2], 0), 0);
- EXPECT_EQ(pthread_key_delete(key), 0);
- EXPECT_EQ(6, cnt);
-}
-
-static __thread int local_var;
-
-static void *local_thread(void *p) {
- __tsan_write1(&local_var);
- __tsan_write1(&p);
- if (p == 0)
- return 0;
- const int kThreads = 4;
- pthread_t th[kThreads];
- for (int i = 0; i < kThreads; i++)
- EXPECT_EQ(pthread_create(&th[i], 0, local_thread,
- (void*)((long)p - 1)), 0); // NOLINT
- for (int i = 0; i < kThreads; i++)
- EXPECT_EQ(pthread_join(th[i], 0), 0);
- return 0;
-}
-
-TEST(Posix, ThreadLocalAccesses) {
- local_thread((void*)2);
-}
-
-struct CondContext {
- pthread_mutex_t m;
- pthread_cond_t c;
- int data;
-};
-
-static void *cond_thread(void *p) {
- CondContext &ctx = *static_cast<CondContext*>(p);
-
- EXPECT_EQ(pthread_mutex_lock(&ctx.m), 0);
- EXPECT_EQ(ctx.data, 0);
- ctx.data = 1;
- EXPECT_EQ(pthread_cond_signal(&ctx.c), 0);
- EXPECT_EQ(pthread_mutex_unlock(&ctx.m), 0);
-
- EXPECT_EQ(pthread_mutex_lock(&ctx.m), 0);
- while (ctx.data != 2)
- EXPECT_EQ(pthread_cond_wait(&ctx.c, &ctx.m), 0);
- EXPECT_EQ(pthread_mutex_unlock(&ctx.m), 0);
-
- EXPECT_EQ(pthread_mutex_lock(&ctx.m), 0);
- ctx.data = 3;
- EXPECT_EQ(pthread_cond_broadcast(&ctx.c), 0);
- EXPECT_EQ(pthread_mutex_unlock(&ctx.m), 0);
-
- return 0;
-}
-
-TEST(Posix, CondBasic) {
- CondContext ctx;
- EXPECT_EQ(pthread_mutex_init(&ctx.m, 0), 0);
- EXPECT_EQ(pthread_cond_init(&ctx.c, 0), 0);
- ctx.data = 0;
- pthread_t th;
- EXPECT_EQ(pthread_create(&th, 0, cond_thread, &ctx), 0);
-
- EXPECT_EQ(pthread_mutex_lock(&ctx.m), 0);
- while (ctx.data != 1)
- EXPECT_EQ(pthread_cond_wait(&ctx.c, &ctx.m), 0);
- ctx.data = 2;
- EXPECT_EQ(pthread_mutex_unlock(&ctx.m), 0);
- EXPECT_EQ(pthread_cond_broadcast(&ctx.c), 0);
-
- EXPECT_EQ(pthread_mutex_lock(&ctx.m), 0);
- while (ctx.data != 3)
- EXPECT_EQ(pthread_cond_wait(&ctx.c, &ctx.m), 0);
- EXPECT_EQ(pthread_mutex_unlock(&ctx.m), 0);
-
- EXPECT_EQ(pthread_join(th, 0), 0);
- EXPECT_EQ(pthread_cond_destroy(&ctx.c), 0);
- EXPECT_EQ(pthread_mutex_destroy(&ctx.m), 0);
-}
diff --git a/contrib/compiler-rt/lib/tsan/tests/rtl/tsan_string.cc b/contrib/compiler-rt/lib/tsan/tests/rtl/tsan_string.cc
deleted file mode 100644
index 75adc6c85ee9..000000000000
--- a/contrib/compiler-rt/lib/tsan/tests/rtl/tsan_string.cc
+++ /dev/null
@@ -1,82 +0,0 @@
-//===-- tsan_string.cc ----------------------------------------------------===//
-//
-// 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 ThreadSanitizer (TSan), a race detector.
-//
-//===----------------------------------------------------------------------===//
-#include "tsan_test_util.h"
-#include "gtest/gtest.h"
-#include <string.h>
-
-namespace __tsan {
-
-TEST(ThreadSanitizer, Memcpy) {
- char data0[7] = {1, 2, 3, 4, 5, 6, 7};
- char data[7] = {42, 42, 42, 42, 42, 42, 42};
- MainThread().Memcpy(data+1, data0+1, 5);
- EXPECT_EQ(data[0], 42);
- EXPECT_EQ(data[1], 2);
- EXPECT_EQ(data[2], 3);
- EXPECT_EQ(data[3], 4);
- EXPECT_EQ(data[4], 5);
- EXPECT_EQ(data[5], 6);
- EXPECT_EQ(data[6], 42);
- MainThread().Memset(data+1, 13, 5);
- EXPECT_EQ(data[0], 42);
- EXPECT_EQ(data[1], 13);
- EXPECT_EQ(data[2], 13);
- EXPECT_EQ(data[3], 13);
- EXPECT_EQ(data[4], 13);
- EXPECT_EQ(data[5], 13);
- EXPECT_EQ(data[6], 42);
-}
-
-TEST(ThreadSanitizer, MemcpyRace1) {
- char *data = new char[10];
- char *data1 = new char[10];
- char *data2 = new char[10];
- ScopedThread t1, t2;
- t1.Memcpy(data, data1, 10);
- t2.Memcpy(data, data2, 10, true);
-}
-
-TEST(ThreadSanitizer, MemcpyRace2) {
- char *data = new char[10];
- char *data1 = new char[10];
- char *data2 = new char[10];
- ScopedThread t1, t2;
- t1.Memcpy(data+5, data1, 1);
- t2.Memcpy(data+3, data2, 4, true);
-}
-
-TEST(ThreadSanitizer, MemcpyRace3) {
- char *data = new char[10];
- char *data1 = new char[10];
- char *data2 = new char[10];
- ScopedThread t1, t2;
- t1.Memcpy(data, data1, 10);
- t2.Memcpy(data1, data2, 10, true);
-}
-
-TEST(ThreadSanitizer, MemcpyStack) {
- char *data = new char[10];
- char *data1 = new char[10];
- ScopedThread t1, t2;
- t1.Memcpy(data, data1, 10);
- t2.Memcpy(data, data1, 10, true);
-}
-
-TEST(ThreadSanitizer, MemsetRace1) {
- char *data = new char[10];
- ScopedThread t1, t2;
- t1.Memset(data, 1, 10);
- t2.Memset(data, 2, 10, true);
-}
-
-} // namespace __tsan
diff --git a/contrib/compiler-rt/lib/tsan/tests/rtl/tsan_test.cc b/contrib/compiler-rt/lib/tsan/tests/rtl/tsan_test.cc
deleted file mode 100644
index b8b9555c2bff..000000000000
--- a/contrib/compiler-rt/lib/tsan/tests/rtl/tsan_test.cc
+++ /dev/null
@@ -1,53 +0,0 @@
-//===-- tsan_test.cc ------------------------------------------------------===//
-//
-// 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 ThreadSanitizer (TSan), a race detector.
-//
-//===----------------------------------------------------------------------===//
-#include "tsan_interface.h"
-#include "tsan_test_util.h"
-#include "gtest/gtest.h"
-
-static void foo() {}
-static void bar() {}
-
-TEST(ThreadSanitizer, FuncCall) {
- ScopedThread t1, t2;
- MemLoc l;
- t1.Write1(l);
- t2.Call(foo);
- t2.Call(bar);
- t2.Write1(l, true);
- t2.Return();
- t2.Return();
-}
-
-// We use this function instead of main, as ISO C++ forbids taking the address
-// of main, which we need to pass inside __tsan_func_entry.
-int run_tests(int argc, char **argv) {
- TestMutexBeforeInit(); // Mutexes must be usable before __tsan_init();
- __tsan_init();
- __tsan_func_entry(__builtin_return_address(0));
- __tsan_func_entry((void*)((intptr_t)&run_tests + 1));
-
- testing::GTEST_FLAG(death_test_style) = "threadsafe";
- testing::InitGoogleTest(&argc, argv);
- int res = RUN_ALL_TESTS();
-
- __tsan_func_exit();
- __tsan_func_exit();
- return res;
-}
-
-const char *argv0;
-
-int main(int argc, char **argv) {
- argv0 = argv[0];
- return run_tests(argc, argv);
-}
diff --git a/contrib/compiler-rt/lib/tsan/tests/rtl/tsan_test_util.h b/contrib/compiler-rt/lib/tsan/tests/rtl/tsan_test_util.h
deleted file mode 100644
index 84d277b137f0..000000000000
--- a/contrib/compiler-rt/lib/tsan/tests/rtl/tsan_test_util.h
+++ /dev/null
@@ -1,122 +0,0 @@
-//===-- tsan_test_util.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 ThreadSanitizer (TSan), a race detector.
-//
-// Test utils.
-//===----------------------------------------------------------------------===//
-#ifndef TSAN_TEST_UTIL_H
-#define TSAN_TEST_UTIL_H
-
-void TestMutexBeforeInit();
-
-// A location of memory on which a race may be detected.
-class MemLoc {
- public:
- explicit MemLoc(int offset_from_aligned = 0);
- explicit MemLoc(void *const real_addr) : loc_(real_addr) { }
- ~MemLoc();
- void *loc() const { return loc_; }
- private:
- void *const loc_;
- MemLoc(const MemLoc&);
- void operator = (const MemLoc&);
-};
-
-class Mutex {
- public:
- enum Type { Normal, Spin, RW };
-
- explicit Mutex(Type type = Normal);
- ~Mutex();
-
- void Init();
- void StaticInit(); // Emulates static initialization (tsan invisible).
- void Destroy();
- void Lock();
- bool TryLock();
- void Unlock();
- void ReadLock();
- bool TryReadLock();
- void ReadUnlock();
-
- private:
- // Placeholder for pthread_mutex_t, CRITICAL_SECTION or whatever.
- void *mtx_[128];
- bool alive_;
- const Type type_;
-
- Mutex(const Mutex&);
- void operator = (const Mutex&);
-};
-
-// A thread is started in CTOR and joined in DTOR.
-class ScopedThread {
- public:
- explicit ScopedThread(bool detached = false, bool main = false);
- ~ScopedThread();
- void Detach();
-
- void Access(void *addr, bool is_write, int size, bool expect_race);
- void Read(const MemLoc &ml, int size, bool expect_race = false) {
- Access(ml.loc(), false, size, expect_race);
- }
- void Write(const MemLoc &ml, int size, bool expect_race = false) {
- Access(ml.loc(), true, size, expect_race);
- }
- void Read1(const MemLoc &ml, bool expect_race = false) {
- Read(ml, 1, expect_race); }
- void Read2(const MemLoc &ml, bool expect_race = false) {
- Read(ml, 2, expect_race); }
- void Read4(const MemLoc &ml, bool expect_race = false) {
- Read(ml, 4, expect_race); }
- void Read8(const MemLoc &ml, bool expect_race = false) {
- Read(ml, 8, expect_race); }
- void Write1(const MemLoc &ml, bool expect_race = false) {
- Write(ml, 1, expect_race); }
- void Write2(const MemLoc &ml, bool expect_race = false) {
- Write(ml, 2, expect_race); }
- void Write4(const MemLoc &ml, bool expect_race = false) {
- Write(ml, 4, expect_race); }
- void Write8(const MemLoc &ml, bool expect_race = false) {
- Write(ml, 8, expect_race); }
-
- void VptrUpdate(const MemLoc &vptr, const MemLoc &new_val,
- bool expect_race = false);
-
- void Call(void(*pc)());
- void Return();
-
- void Create(const Mutex &m);
- void Destroy(const Mutex &m);
- void Lock(const Mutex &m);
- bool TryLock(const Mutex &m);
- void Unlock(const Mutex &m);
- void ReadLock(const Mutex &m);
- bool TryReadLock(const Mutex &m);
- void ReadUnlock(const Mutex &m);
-
- void Memcpy(void *dst, const void *src, int size, bool expect_race = false);
- void Memset(void *dst, int val, int size, bool expect_race = false);
-
- private:
- struct Impl;
- Impl *impl_;
- ScopedThread(const ScopedThread&); // Not implemented.
- void operator = (const ScopedThread&); // Not implemented.
-};
-
-class MainThread : public ScopedThread {
- public:
- MainThread()
- : ScopedThread(false, true) {
- }
-};
-
-#endif // #ifndef TSAN_TEST_UTIL_H
diff --git a/contrib/compiler-rt/lib/tsan/tests/rtl/tsan_test_util_linux.cc b/contrib/compiler-rt/lib/tsan/tests/rtl/tsan_test_util_linux.cc
deleted file mode 100644
index 9298bf051af2..000000000000
--- a/contrib/compiler-rt/lib/tsan/tests/rtl/tsan_test_util_linux.cc
+++ /dev/null
@@ -1,470 +0,0 @@
-
-//===-- tsan_test_util_linux.cc -------------------------------------------===//
-//
-// 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 ThreadSanitizer (TSan), a race detector.
-//
-// Test utils, Linux and FreeBSD implementation.
-//===----------------------------------------------------------------------===//
-
-#include "sanitizer_common/sanitizer_atomic.h"
-#include "tsan_interface.h"
-#include "tsan_test_util.h"
-#include "tsan_report.h"
-
-#include "gtest/gtest.h"
-
-#include <assert.h>
-#include <pthread.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <string.h>
-#include <unistd.h>
-#include <errno.h>
-
-using namespace __tsan; // NOLINT
-
-static __thread bool expect_report;
-static __thread bool expect_report_reported;
-static __thread ReportType expect_report_type;
-
-extern "C" void *__interceptor_memcpy(void*, const void*, uptr);
-extern "C" void *__interceptor_memset(void*, int, uptr);
-
-static void *BeforeInitThread(void *param) {
- (void)param;
- return 0;
-}
-
-static void AtExit() {
-}
-
-void TestMutexBeforeInit() {
- // Mutexes must be usable before __tsan_init();
- pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
- pthread_mutex_lock(&mtx);
- pthread_mutex_unlock(&mtx);
- pthread_mutex_destroy(&mtx);
- pthread_t thr;
- pthread_create(&thr, 0, BeforeInitThread, 0);
- pthread_join(thr, 0);
- atexit(AtExit);
-}
-
-namespace __tsan {
-bool OnReport(const ReportDesc *rep, bool suppressed) {
- if (expect_report) {
- if (rep->typ != expect_report_type) {
- printf("Expected report of type %d, got type %d\n",
- (int)expect_report_type, (int)rep->typ);
- EXPECT_FALSE("Wrong report type");
- return false;
- }
- } else {
- EXPECT_FALSE("Unexpected report");
- return false;
- }
- expect_report_reported = true;
- return true;
-}
-} // namespace __tsan
-
-static void* allocate_addr(int size, int offset_from_aligned = 0) {
- static uintptr_t foo;
- static atomic_uintptr_t uniq = {(uintptr_t)&foo}; // Some real address.
- const int kAlign = 16;
- CHECK(offset_from_aligned < kAlign);
- size = (size + 2 * kAlign) & ~(kAlign - 1);
- uintptr_t addr = atomic_fetch_add(&uniq, size, memory_order_relaxed);
- return (void*)(addr + offset_from_aligned);
-}
-
-MemLoc::MemLoc(int offset_from_aligned)
- : loc_(allocate_addr(16, offset_from_aligned)) {
-}
-
-MemLoc::~MemLoc() {
-}
-
-Mutex::Mutex(Type type)
- : alive_()
- , type_(type) {
-}
-
-Mutex::~Mutex() {
- CHECK(!alive_);
-}
-
-void Mutex::Init() {
- CHECK(!alive_);
- alive_ = true;
- if (type_ == Normal)
- CHECK_EQ(pthread_mutex_init((pthread_mutex_t*)mtx_, 0), 0);
- else if (type_ == Spin)
- CHECK_EQ(pthread_spin_init((pthread_spinlock_t*)mtx_, 0), 0);
- else if (type_ == RW)
- CHECK_EQ(pthread_rwlock_init((pthread_rwlock_t*)mtx_, 0), 0);
- else
- CHECK(0);
-}
-
-void Mutex::StaticInit() {
- CHECK(!alive_);
- CHECK(type_ == Normal);
- alive_ = true;
- pthread_mutex_t tmp = PTHREAD_MUTEX_INITIALIZER;
- memcpy(mtx_, &tmp, sizeof(tmp));
-}
-
-void Mutex::Destroy() {
- CHECK(alive_);
- alive_ = false;
- if (type_ == Normal)
- CHECK_EQ(pthread_mutex_destroy((pthread_mutex_t*)mtx_), 0);
- else if (type_ == Spin)
- CHECK_EQ(pthread_spin_destroy((pthread_spinlock_t*)mtx_), 0);
- else if (type_ == RW)
- CHECK_EQ(pthread_rwlock_destroy((pthread_rwlock_t*)mtx_), 0);
-}
-
-void Mutex::Lock() {
- CHECK(alive_);
- if (type_ == Normal)
- CHECK_EQ(pthread_mutex_lock((pthread_mutex_t*)mtx_), 0);
- else if (type_ == Spin)
- CHECK_EQ(pthread_spin_lock((pthread_spinlock_t*)mtx_), 0);
- else if (type_ == RW)
- CHECK_EQ(pthread_rwlock_wrlock((pthread_rwlock_t*)mtx_), 0);
-}
-
-bool Mutex::TryLock() {
- CHECK(alive_);
- if (type_ == Normal)
- return pthread_mutex_trylock((pthread_mutex_t*)mtx_) == 0;
- else if (type_ == Spin)
- return pthread_spin_trylock((pthread_spinlock_t*)mtx_) == 0;
- else if (type_ == RW)
- return pthread_rwlock_trywrlock((pthread_rwlock_t*)mtx_) == 0;
- return false;
-}
-
-void Mutex::Unlock() {
- CHECK(alive_);
- if (type_ == Normal)
- CHECK_EQ(pthread_mutex_unlock((pthread_mutex_t*)mtx_), 0);
- else if (type_ == Spin)
- CHECK_EQ(pthread_spin_unlock((pthread_spinlock_t*)mtx_), 0);
- else if (type_ == RW)
- CHECK_EQ(pthread_rwlock_unlock((pthread_rwlock_t*)mtx_), 0);
-}
-
-void Mutex::ReadLock() {
- CHECK(alive_);
- CHECK(type_ == RW);
- CHECK_EQ(pthread_rwlock_rdlock((pthread_rwlock_t*)mtx_), 0);
-}
-
-bool Mutex::TryReadLock() {
- CHECK(alive_);
- CHECK(type_ == RW);
- return pthread_rwlock_tryrdlock((pthread_rwlock_t*)mtx_) == 0;
-}
-
-void Mutex::ReadUnlock() {
- CHECK(alive_);
- CHECK(type_ == RW);
- CHECK_EQ(pthread_rwlock_unlock((pthread_rwlock_t*)mtx_), 0);
-}
-
-struct Event {
- enum Type {
- SHUTDOWN,
- READ,
- WRITE,
- VPTR_UPDATE,
- CALL,
- RETURN,
- MUTEX_CREATE,
- MUTEX_DESTROY,
- MUTEX_LOCK,
- MUTEX_TRYLOCK,
- MUTEX_UNLOCK,
- MUTEX_READLOCK,
- MUTEX_TRYREADLOCK,
- MUTEX_READUNLOCK,
- MEMCPY,
- MEMSET
- };
- Type type;
- void *ptr;
- uptr arg;
- uptr arg2;
- bool res;
- bool expect_report;
- ReportType report_type;
-
- Event(Type type, const void *ptr = 0, uptr arg = 0, uptr arg2 = 0)
- : type(type)
- , ptr(const_cast<void*>(ptr))
- , arg(arg)
- , arg2(arg2)
- , res()
- , expect_report()
- , report_type() {
- }
-
- void ExpectReport(ReportType type) {
- expect_report = true;
- report_type = type;
- }
-};
-
-struct ScopedThread::Impl {
- pthread_t thread;
- bool main;
- bool detached;
- atomic_uintptr_t event; // Event*
-
- static void *ScopedThreadCallback(void *arg);
- void send(Event *ev);
- void HandleEvent(Event *ev);
-};
-
-void ScopedThread::Impl::HandleEvent(Event *ev) {
- CHECK_EQ(expect_report, false);
- expect_report = ev->expect_report;
- expect_report_reported = false;
- expect_report_type = ev->report_type;
- switch (ev->type) {
- case Event::READ:
- case Event::WRITE: {
- void (*tsan_mop)(void *addr) = 0;
- if (ev->type == Event::READ) {
- switch (ev->arg /*size*/) {
- case 1: tsan_mop = __tsan_read1; break;
- case 2: tsan_mop = __tsan_read2; break;
- case 4: tsan_mop = __tsan_read4; break;
- case 8: tsan_mop = __tsan_read8; break;
- case 16: tsan_mop = __tsan_read16; break;
- }
- } else {
- switch (ev->arg /*size*/) {
- case 1: tsan_mop = __tsan_write1; break;
- case 2: tsan_mop = __tsan_write2; break;
- case 4: tsan_mop = __tsan_write4; break;
- case 8: tsan_mop = __tsan_write8; break;
- case 16: tsan_mop = __tsan_write16; break;
- }
- }
- CHECK_NE(tsan_mop, 0);
-#if defined(__FreeBSD__)
- const int ErrCode = ESOCKTNOSUPPORT;
-#else
- const int ErrCode = ECHRNG;
-#endif
- errno = ErrCode;
- tsan_mop(ev->ptr);
- CHECK_EQ(ErrCode, errno); // In no case must errno be changed.
- break;
- }
- case Event::VPTR_UPDATE:
- __tsan_vptr_update((void**)ev->ptr, (void*)ev->arg);
- break;
- case Event::CALL:
- __tsan_func_entry((void*)((uptr)ev->ptr));
- break;
- case Event::RETURN:
- __tsan_func_exit();
- break;
- case Event::MUTEX_CREATE:
- static_cast<Mutex*>(ev->ptr)->Init();
- break;
- case Event::MUTEX_DESTROY:
- static_cast<Mutex*>(ev->ptr)->Destroy();
- break;
- case Event::MUTEX_LOCK:
- static_cast<Mutex*>(ev->ptr)->Lock();
- break;
- case Event::MUTEX_TRYLOCK:
- ev->res = static_cast<Mutex*>(ev->ptr)->TryLock();
- break;
- case Event::MUTEX_UNLOCK:
- static_cast<Mutex*>(ev->ptr)->Unlock();
- break;
- case Event::MUTEX_READLOCK:
- static_cast<Mutex*>(ev->ptr)->ReadLock();
- break;
- case Event::MUTEX_TRYREADLOCK:
- ev->res = static_cast<Mutex*>(ev->ptr)->TryReadLock();
- break;
- case Event::MUTEX_READUNLOCK:
- static_cast<Mutex*>(ev->ptr)->ReadUnlock();
- break;
- case Event::MEMCPY:
- __interceptor_memcpy(ev->ptr, (void*)ev->arg, ev->arg2);
- break;
- case Event::MEMSET:
- __interceptor_memset(ev->ptr, ev->arg, ev->arg2);
- break;
- default: CHECK(0);
- }
- if (expect_report && !expect_report_reported) {
- printf("Missed expected report of type %d\n", (int)ev->report_type);
- EXPECT_FALSE("Missed expected race");
- }
- expect_report = false;
-}
-
-void *ScopedThread::Impl::ScopedThreadCallback(void *arg) {
- __tsan_func_entry(__builtin_return_address(0));
- Impl *impl = (Impl*)arg;
- for (;;) {
- Event* ev = (Event*)atomic_load(&impl->event, memory_order_acquire);
- if (ev == 0) {
- pthread_yield();
- continue;
- }
- if (ev->type == Event::SHUTDOWN) {
- atomic_store(&impl->event, 0, memory_order_release);
- break;
- }
- impl->HandleEvent(ev);
- atomic_store(&impl->event, 0, memory_order_release);
- }
- __tsan_func_exit();
- return 0;
-}
-
-void ScopedThread::Impl::send(Event *e) {
- if (main) {
- HandleEvent(e);
- } else {
- CHECK_EQ(atomic_load(&event, memory_order_relaxed), 0);
- atomic_store(&event, (uintptr_t)e, memory_order_release);
- while (atomic_load(&event, memory_order_acquire) != 0)
- pthread_yield();
- }
-}
-
-ScopedThread::ScopedThread(bool detached, bool main) {
- impl_ = new Impl;
- impl_->main = main;
- impl_->detached = detached;
- atomic_store(&impl_->event, 0, memory_order_relaxed);
- if (!main) {
- pthread_attr_t attr;
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, detached);
- pthread_attr_setstacksize(&attr, 64*1024);
- pthread_create(&impl_->thread, &attr,
- ScopedThread::Impl::ScopedThreadCallback, impl_);
- }
-}
-
-ScopedThread::~ScopedThread() {
- if (!impl_->main) {
- Event event(Event::SHUTDOWN);
- impl_->send(&event);
- if (!impl_->detached)
- pthread_join(impl_->thread, 0);
- }
- delete impl_;
-}
-
-void ScopedThread::Detach() {
- CHECK(!impl_->main);
- CHECK(!impl_->detached);
- impl_->detached = true;
- pthread_detach(impl_->thread);
-}
-
-void ScopedThread::Access(void *addr, bool is_write,
- int size, bool expect_race) {
- Event event(is_write ? Event::WRITE : Event::READ, addr, size);
- if (expect_race)
- event.ExpectReport(ReportTypeRace);
- impl_->send(&event);
-}
-
-void ScopedThread::VptrUpdate(const MemLoc &vptr,
- const MemLoc &new_val,
- bool expect_race) {
- Event event(Event::VPTR_UPDATE, vptr.loc(), (uptr)new_val.loc());
- if (expect_race)
- event.ExpectReport(ReportTypeRace);
- impl_->send(&event);
-}
-
-void ScopedThread::Call(void(*pc)()) {
- Event event(Event::CALL, (void*)((uintptr_t)pc));
- impl_->send(&event);
-}
-
-void ScopedThread::Return() {
- Event event(Event::RETURN);
- impl_->send(&event);
-}
-
-void ScopedThread::Create(const Mutex &m) {
- Event event(Event::MUTEX_CREATE, &m);
- impl_->send(&event);
-}
-
-void ScopedThread::Destroy(const Mutex &m) {
- Event event(Event::MUTEX_DESTROY, &m);
- impl_->send(&event);
-}
-
-void ScopedThread::Lock(const Mutex &m) {
- Event event(Event::MUTEX_LOCK, &m);
- impl_->send(&event);
-}
-
-bool ScopedThread::TryLock(const Mutex &m) {
- Event event(Event::MUTEX_TRYLOCK, &m);
- impl_->send(&event);
- return event.res;
-}
-
-void ScopedThread::Unlock(const Mutex &m) {
- Event event(Event::MUTEX_UNLOCK, &m);
- impl_->send(&event);
-}
-
-void ScopedThread::ReadLock(const Mutex &m) {
- Event event(Event::MUTEX_READLOCK, &m);
- impl_->send(&event);
-}
-
-bool ScopedThread::TryReadLock(const Mutex &m) {
- Event event(Event::MUTEX_TRYREADLOCK, &m);
- impl_->send(&event);
- return event.res;
-}
-
-void ScopedThread::ReadUnlock(const Mutex &m) {
- Event event(Event::MUTEX_READUNLOCK, &m);
- impl_->send(&event);
-}
-
-void ScopedThread::Memcpy(void *dst, const void *src, int size,
- bool expect_race) {
- Event event(Event::MEMCPY, dst, (uptr)src, size);
- if (expect_race)
- event.ExpectReport(ReportTypeRace);
- impl_->send(&event);
-}
-
-void ScopedThread::Memset(void *dst, int val, int size,
- bool expect_race) {
- Event event(Event::MEMSET, dst, val, size);
- if (expect_race)
- event.ExpectReport(ReportTypeRace);
- impl_->send(&event);
-}
diff --git a/contrib/compiler-rt/lib/tsan/tests/rtl/tsan_thread.cc b/contrib/compiler-rt/lib/tsan/tests/rtl/tsan_thread.cc
deleted file mode 100644
index 5646415a79b8..000000000000
--- a/contrib/compiler-rt/lib/tsan/tests/rtl/tsan_thread.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-//===-- tsan_thread.cc ----------------------------------------------------===//
-//
-// 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 ThreadSanitizer (TSan), a race detector.
-//
-//===----------------------------------------------------------------------===//
-#include "tsan_test_util.h"
-#include "gtest/gtest.h"
-
-TEST(ThreadSanitizer, ThreadSync) {
- MainThread t0;
- MemLoc l;
- t0.Write1(l);
- {
- ScopedThread t1;
- t1.Write1(l);
- }
- t0.Write1(l);
-}
-
-TEST(ThreadSanitizer, ThreadDetach1) {
- ScopedThread t1(true);
- MemLoc l;
- t1.Write1(l);
-}
-
-TEST(ThreadSanitizer, ThreadDetach2) {
- ScopedThread t1;
- MemLoc l;
- t1.Write1(l);
- t1.Detach();
-}
-
-static void *thread_alot_func(void *arg) {
- (void)arg;
- int usleep(unsigned);
- usleep(50);
- return 0;
-}
-
-TEST(DISABLED_SLOW_ThreadSanitizer, ThreadALot) {
- const int kThreads = 70000;
- const int kAlive = 1000;
- pthread_t threads[kAlive] = {};
- for (int i = 0; i < kThreads; i++) {
- if (threads[i % kAlive])
- pthread_join(threads[i % kAlive], 0);
- pthread_create(&threads[i % kAlive], 0, thread_alot_func, 0);
- }
- for (int i = 0; i < kAlive; i++) {
- pthread_join(threads[i], 0);
- }
-}
diff --git a/contrib/compiler-rt/lib/tsan/tests/unit/tsan_clock_test.cc b/contrib/compiler-rt/lib/tsan/tests/unit/tsan_clock_test.cc
deleted file mode 100644
index 92071827d3d8..000000000000
--- a/contrib/compiler-rt/lib/tsan/tests/unit/tsan_clock_test.cc
+++ /dev/null
@@ -1,432 +0,0 @@
-//===-- tsan_clock_test.cc ------------------------------------------------===//
-//
-// 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 ThreadSanitizer (TSan), a race detector.
-//
-//===----------------------------------------------------------------------===//
-#include "tsan_clock.h"
-#include "tsan_rtl.h"
-#include "gtest/gtest.h"
-#include <time.h>
-
-namespace __tsan {
-
-ClockCache cache;
-
-TEST(Clock, VectorBasic) {
- ThreadClock clk(0);
- ASSERT_EQ(clk.size(), 1U);
- clk.tick();
- ASSERT_EQ(clk.size(), 1U);
- ASSERT_EQ(clk.get(0), 1U);
- clk.set(3, clk.get(3) + 1);
- ASSERT_EQ(clk.size(), 4U);
- ASSERT_EQ(clk.get(0), 1U);
- ASSERT_EQ(clk.get(1), 0U);
- ASSERT_EQ(clk.get(2), 0U);
- ASSERT_EQ(clk.get(3), 1U);
- clk.set(3, clk.get(3) + 1);
- ASSERT_EQ(clk.get(3), 2U);
-}
-
-TEST(Clock, ChunkedBasic) {
- ThreadClock vector(0);
- SyncClock chunked;
- ASSERT_EQ(vector.size(), 1U);
- ASSERT_EQ(chunked.size(), 0U);
- vector.acquire(&cache, &chunked);
- ASSERT_EQ(vector.size(), 1U);
- ASSERT_EQ(chunked.size(), 0U);
- vector.release(&cache, &chunked);
- ASSERT_EQ(vector.size(), 1U);
- ASSERT_EQ(chunked.size(), 1U);
- vector.acq_rel(&cache, &chunked);
- ASSERT_EQ(vector.size(), 1U);
- ASSERT_EQ(chunked.size(), 1U);
- chunked.Reset(&cache);
-}
-
-TEST(Clock, AcquireRelease) {
- ThreadClock vector1(100);
- vector1.tick();
- SyncClock chunked;
- vector1.release(&cache, &chunked);
- ASSERT_EQ(chunked.size(), 101U);
- ThreadClock vector2(0);
- vector2.acquire(&cache, &chunked);
- ASSERT_EQ(vector2.size(), 101U);
- ASSERT_EQ(vector2.get(0), 0U);
- ASSERT_EQ(vector2.get(1), 0U);
- ASSERT_EQ(vector2.get(99), 0U);
- ASSERT_EQ(vector2.get(100), 1U);
- chunked.Reset(&cache);
-}
-
-TEST(Clock, RepeatedAcquire) {
- ThreadClock thr1(1);
- thr1.tick();
- ThreadClock thr2(2);
- thr2.tick();
-
- SyncClock sync;
- thr1.ReleaseStore(&cache, &sync);
-
- thr2.acquire(&cache, &sync);
- thr2.acquire(&cache, &sync);
-
- sync.Reset(&cache);
-}
-
-TEST(Clock, ManyThreads) {
- SyncClock chunked;
- for (unsigned i = 0; i < 100; i++) {
- ThreadClock vector(0);
- vector.tick();
- vector.set(i, 1);
- vector.release(&cache, &chunked);
- ASSERT_EQ(i + 1, chunked.size());
- vector.acquire(&cache, &chunked);
- ASSERT_EQ(i + 1, vector.size());
- }
-
- for (unsigned i = 0; i < 100; i++)
- ASSERT_EQ(1U, chunked.get(i));
-
- ThreadClock vector(1);
- vector.acquire(&cache, &chunked);
- ASSERT_EQ(100U, vector.size());
- for (unsigned i = 0; i < 100; i++)
- ASSERT_EQ(1U, vector.get(i));
-
- chunked.Reset(&cache);
-}
-
-TEST(Clock, DifferentSizes) {
- {
- ThreadClock vector1(10);
- vector1.tick();
- ThreadClock vector2(20);
- vector2.tick();
- {
- SyncClock chunked;
- vector1.release(&cache, &chunked);
- ASSERT_EQ(chunked.size(), 11U);
- vector2.release(&cache, &chunked);
- ASSERT_EQ(chunked.size(), 21U);
- chunked.Reset(&cache);
- }
- {
- SyncClock chunked;
- vector2.release(&cache, &chunked);
- ASSERT_EQ(chunked.size(), 21U);
- vector1.release(&cache, &chunked);
- ASSERT_EQ(chunked.size(), 21U);
- chunked.Reset(&cache);
- }
- {
- SyncClock chunked;
- vector1.release(&cache, &chunked);
- vector2.acquire(&cache, &chunked);
- ASSERT_EQ(vector2.size(), 21U);
- chunked.Reset(&cache);
- }
- {
- SyncClock chunked;
- vector2.release(&cache, &chunked);
- vector1.acquire(&cache, &chunked);
- ASSERT_EQ(vector1.size(), 21U);
- chunked.Reset(&cache);
- }
- }
-}
-
-TEST(Clock, Growth) {
- {
- ThreadClock vector(10);
- vector.tick();
- vector.set(5, 42);
- SyncClock sync;
- vector.release(&cache, &sync);
- ASSERT_EQ(sync.size(), 11U);
- ASSERT_EQ(sync.get(0), 0ULL);
- ASSERT_EQ(sync.get(1), 0ULL);
- ASSERT_EQ(sync.get(5), 42ULL);
- ASSERT_EQ(sync.get(9), 0ULL);
- ASSERT_EQ(sync.get(10), 1ULL);
- sync.Reset(&cache);
- }
- {
- ThreadClock vector1(10);
- vector1.tick();
- ThreadClock vector2(20);
- vector2.tick();
- SyncClock sync;
- vector1.release(&cache, &sync);
- vector2.release(&cache, &sync);
- ASSERT_EQ(sync.size(), 21U);
- ASSERT_EQ(sync.get(0), 0ULL);
- ASSERT_EQ(sync.get(10), 1ULL);
- ASSERT_EQ(sync.get(19), 0ULL);
- ASSERT_EQ(sync.get(20), 1ULL);
- sync.Reset(&cache);
- }
- {
- ThreadClock vector(100);
- vector.tick();
- vector.set(5, 42);
- vector.set(90, 84);
- SyncClock sync;
- vector.release(&cache, &sync);
- ASSERT_EQ(sync.size(), 101U);
- ASSERT_EQ(sync.get(0), 0ULL);
- ASSERT_EQ(sync.get(1), 0ULL);
- ASSERT_EQ(sync.get(5), 42ULL);
- ASSERT_EQ(sync.get(60), 0ULL);
- ASSERT_EQ(sync.get(70), 0ULL);
- ASSERT_EQ(sync.get(90), 84ULL);
- ASSERT_EQ(sync.get(99), 0ULL);
- ASSERT_EQ(sync.get(100), 1ULL);
- sync.Reset(&cache);
- }
- {
- ThreadClock vector1(10);
- vector1.tick();
- ThreadClock vector2(100);
- vector2.tick();
- SyncClock sync;
- vector1.release(&cache, &sync);
- vector2.release(&cache, &sync);
- ASSERT_EQ(sync.size(), 101U);
- ASSERT_EQ(sync.get(0), 0ULL);
- ASSERT_EQ(sync.get(10), 1ULL);
- ASSERT_EQ(sync.get(99), 0ULL);
- ASSERT_EQ(sync.get(100), 1ULL);
- sync.Reset(&cache);
- }
-}
-
-const uptr kThreads = 4;
-const uptr kClocks = 4;
-
-// SimpleSyncClock and SimpleThreadClock implement the same thing as
-// SyncClock and ThreadClock, but in a very simple way.
-struct SimpleSyncClock {
- u64 clock[kThreads];
- uptr size;
-
- SimpleSyncClock() {
- Reset();
- }
-
- void Reset() {
- size = 0;
- for (uptr i = 0; i < kThreads; i++)
- clock[i] = 0;
- }
-
- bool verify(const SyncClock *other) const {
- for (uptr i = 0; i < min(size, other->size()); i++) {
- if (clock[i] != other->get(i))
- return false;
- }
- for (uptr i = min(size, other->size()); i < max(size, other->size()); i++) {
- if (i < size && clock[i] != 0)
- return false;
- if (i < other->size() && other->get(i) != 0)
- return false;
- }
- return true;
- }
-};
-
-struct SimpleThreadClock {
- u64 clock[kThreads];
- uptr size;
- unsigned tid;
-
- explicit SimpleThreadClock(unsigned tid) {
- this->tid = tid;
- size = tid + 1;
- for (uptr i = 0; i < kThreads; i++)
- clock[i] = 0;
- }
-
- void tick() {
- clock[tid]++;
- }
-
- void acquire(const SimpleSyncClock *src) {
- if (size < src->size)
- size = src->size;
- for (uptr i = 0; i < kThreads; i++)
- clock[i] = max(clock[i], src->clock[i]);
- }
-
- void release(SimpleSyncClock *dst) const {
- if (dst->size < size)
- dst->size = size;
- for (uptr i = 0; i < kThreads; i++)
- dst->clock[i] = max(dst->clock[i], clock[i]);
- }
-
- void acq_rel(SimpleSyncClock *dst) {
- acquire(dst);
- release(dst);
- }
-
- void ReleaseStore(SimpleSyncClock *dst) const {
- if (dst->size < size)
- dst->size = size;
- for (uptr i = 0; i < kThreads; i++)
- dst->clock[i] = clock[i];
- }
-
- bool verify(const ThreadClock *other) const {
- for (uptr i = 0; i < min(size, other->size()); i++) {
- if (clock[i] != other->get(i))
- return false;
- }
- for (uptr i = min(size, other->size()); i < max(size, other->size()); i++) {
- if (i < size && clock[i] != 0)
- return false;
- if (i < other->size() && other->get(i) != 0)
- return false;
- }
- return true;
- }
-};
-
-static bool ClockFuzzer(bool printing) {
- // Create kThreads thread clocks.
- SimpleThreadClock *thr0[kThreads];
- ThreadClock *thr1[kThreads];
- unsigned reused[kThreads];
- for (unsigned i = 0; i < kThreads; i++) {
- reused[i] = 0;
- thr0[i] = new SimpleThreadClock(i);
- thr1[i] = new ThreadClock(i, reused[i]);
- }
-
- // Create kClocks sync clocks.
- SimpleSyncClock *sync0[kClocks];
- SyncClock *sync1[kClocks];
- for (unsigned i = 0; i < kClocks; i++) {
- sync0[i] = new SimpleSyncClock();
- sync1[i] = new SyncClock();
- }
-
- // Do N random operations (acquire, release, etc) and compare results
- // for SimpleThread/SyncClock and real Thread/SyncClock.
- for (int i = 0; i < 10000; i++) {
- unsigned tid = rand() % kThreads;
- unsigned cid = rand() % kClocks;
- thr0[tid]->tick();
- thr1[tid]->tick();
-
- switch (rand() % 6) {
- case 0:
- if (printing)
- printf("acquire thr%d <- clk%d\n", tid, cid);
- thr0[tid]->acquire(sync0[cid]);
- thr1[tid]->acquire(&cache, sync1[cid]);
- break;
- case 1:
- if (printing)
- printf("release thr%d -> clk%d\n", tid, cid);
- thr0[tid]->release(sync0[cid]);
- thr1[tid]->release(&cache, sync1[cid]);
- break;
- case 2:
- if (printing)
- printf("acq_rel thr%d <> clk%d\n", tid, cid);
- thr0[tid]->acq_rel(sync0[cid]);
- thr1[tid]->acq_rel(&cache, sync1[cid]);
- break;
- case 3:
- if (printing)
- printf("rel_str thr%d >> clk%d\n", tid, cid);
- thr0[tid]->ReleaseStore(sync0[cid]);
- thr1[tid]->ReleaseStore(&cache, sync1[cid]);
- break;
- case 4:
- if (printing)
- printf("reset clk%d\n", cid);
- sync0[cid]->Reset();
- sync1[cid]->Reset(&cache);
- break;
- case 5:
- if (printing)
- printf("reset thr%d\n", tid);
- u64 epoch = thr0[tid]->clock[tid] + 1;
- reused[tid]++;
- delete thr0[tid];
- thr0[tid] = new SimpleThreadClock(tid);
- thr0[tid]->clock[tid] = epoch;
- delete thr1[tid];
- thr1[tid] = new ThreadClock(tid, reused[tid]);
- thr1[tid]->set(epoch);
- break;
- }
-
- if (printing) {
- for (unsigned i = 0; i < kThreads; i++) {
- printf("thr%d: ", i);
- thr1[i]->DebugDump(printf);
- printf("\n");
- }
- for (unsigned i = 0; i < kClocks; i++) {
- printf("clk%d: ", i);
- sync1[i]->DebugDump(printf);
- printf("\n");
- }
-
- printf("\n");
- }
-
- if (!thr0[tid]->verify(thr1[tid]) || !sync0[cid]->verify(sync1[cid])) {
- if (!printing)
- return false;
- printf("differs with model:\n");
- for (unsigned i = 0; i < kThreads; i++) {
- printf("thr%d: clock=[", i);
- for (uptr j = 0; j < thr0[i]->size; j++)
- printf("%s%llu", j == 0 ? "" : ",", thr0[i]->clock[j]);
- printf("]\n");
- }
- for (unsigned i = 0; i < kClocks; i++) {
- printf("clk%d: clock=[", i);
- for (uptr j = 0; j < sync0[i]->size; j++)
- printf("%s%llu", j == 0 ? "" : ",", sync0[i]->clock[j]);
- printf("]\n");
- }
- return false;
- }
- }
-
- for (unsigned i = 0; i < kClocks; i++) {
- sync1[i]->Reset(&cache);
- }
- return true;
-}
-
-TEST(Clock, Fuzzer) {
- timespec ts;
- clock_gettime(CLOCK_MONOTONIC, &ts);
- int seed = ts.tv_sec + ts.tv_nsec;
- printf("seed=%d\n", seed);
- srand(seed);
- if (!ClockFuzzer(false)) {
- // Redo the test with the same seed, but logging operations.
- srand(seed);
- ClockFuzzer(true);
- ASSERT_TRUE(false);
- }
-}
-
-} // namespace __tsan
diff --git a/contrib/compiler-rt/lib/tsan/tests/unit/tsan_dense_alloc_test.cc b/contrib/compiler-rt/lib/tsan/tests/unit/tsan_dense_alloc_test.cc
deleted file mode 100644
index e848e48c6641..000000000000
--- a/contrib/compiler-rt/lib/tsan/tests/unit/tsan_dense_alloc_test.cc
+++ /dev/null
@@ -1,55 +0,0 @@
-//===-- tsan_dense_alloc_test.cc ------------------------------------------===//
-//
-// 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 ThreadSanitizer (TSan), a race detector.
-//
-//===----------------------------------------------------------------------===//
-#include "tsan_dense_alloc.h"
-#include "tsan_rtl.h"
-#include "tsan_mman.h"
-#include "gtest/gtest.h"
-
-#include <stdlib.h>
-#include <stdint.h>
-#include <map>
-
-namespace __tsan {
-
-TEST(DenseSlabAlloc, Basic) {
- typedef DenseSlabAlloc<int, 128, 128> Alloc;
- typedef Alloc::Cache Cache;
- typedef Alloc::IndexT IndexT;
- const int N = 1000;
-
- Alloc alloc;
- Cache cache;
- alloc.InitCache(&cache);
-
- IndexT blocks[N];
- for (int ntry = 0; ntry < 3; ntry++) {
- for (int i = 0; i < N; i++) {
- IndexT idx = alloc.Alloc(&cache);
- blocks[i] = idx;
- EXPECT_NE(idx, 0U);
- int *v = alloc.Map(idx);
- *v = i;
- }
-
- for (int i = 0; i < N; i++) {
- IndexT idx = blocks[i];
- int *v = alloc.Map(idx);
- EXPECT_EQ(*v, i);
- alloc.Free(&cache, idx);
- }
-
- alloc.FlushCache(&cache);
- }
-}
-
-} // namespace __tsan
diff --git a/contrib/compiler-rt/lib/tsan/tests/unit/tsan_flags_test.cc b/contrib/compiler-rt/lib/tsan/tests/unit/tsan_flags_test.cc
deleted file mode 100644
index 22610c0dc42f..000000000000
--- a/contrib/compiler-rt/lib/tsan/tests/unit/tsan_flags_test.cc
+++ /dev/null
@@ -1,180 +0,0 @@
-//===-- tsan_flags_test.cc ------------------------------------------------===//
-//
-// 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 ThreadSanitizer (TSan), a race detector.
-//
-//===----------------------------------------------------------------------===//
-#include "tsan_flags.h"
-#include "tsan_rtl.h"
-#include "gtest/gtest.h"
-#include <string>
-
-namespace __tsan {
-
-TEST(Flags, Basic) {
- // At least should not crash.
- Flags f;
- InitializeFlags(&f, 0);
- InitializeFlags(&f, "");
-}
-
-TEST(Flags, DefaultValues) {
- Flags f;
-
- f.enable_annotations = false;
- f.exitcode = -11;
- InitializeFlags(&f, "");
- EXPECT_EQ(66, f.exitcode);
- EXPECT_EQ(true, f.enable_annotations);
-}
-
-static const char *options1 =
- " enable_annotations=0"
- " suppress_equal_stacks=0"
- " suppress_equal_addresses=0"
- " report_bugs=0"
- " report_thread_leaks=0"
- " report_destroy_locked=0"
- " report_mutex_bugs=0"
- " report_signal_unsafe=0"
- " report_atomic_races=0"
- " force_seq_cst_atomics=0"
- " print_benign=0"
- " exitcode=111"
- " halt_on_error=0"
- " atexit_sleep_ms=222"
- " profile_memory=qqq"
- " flush_memory_ms=444"
- " flush_symbolizer_ms=555"
- " memory_limit_mb=666"
- " stop_on_start=0"
- " running_on_valgrind=0"
- " history_size=5"
- " io_sync=1"
- " die_after_fork=true"
- "";
-
-static const char *options2 =
- " enable_annotations=true"
- " suppress_equal_stacks=true"
- " suppress_equal_addresses=true"
- " report_bugs=true"
- " report_thread_leaks=true"
- " report_destroy_locked=true"
- " report_mutex_bugs=true"
- " report_signal_unsafe=true"
- " report_atomic_races=true"
- " force_seq_cst_atomics=true"
- " print_benign=true"
- " exitcode=222"
- " halt_on_error=true"
- " atexit_sleep_ms=123"
- " profile_memory=bbbbb"
- " flush_memory_ms=234"
- " flush_symbolizer_ms=345"
- " memory_limit_mb=456"
- " stop_on_start=true"
- " running_on_valgrind=true"
- " history_size=6"
- " io_sync=2"
- " die_after_fork=false"
- "";
-
-void VerifyOptions1(Flags *f) {
- EXPECT_EQ(f->enable_annotations, 0);
- EXPECT_EQ(f->suppress_equal_stacks, 0);
- EXPECT_EQ(f->suppress_equal_addresses, 0);
- EXPECT_EQ(f->report_bugs, 0);
- EXPECT_EQ(f->report_thread_leaks, 0);
- EXPECT_EQ(f->report_destroy_locked, 0);
- EXPECT_EQ(f->report_mutex_bugs, 0);
- EXPECT_EQ(f->report_signal_unsafe, 0);
- EXPECT_EQ(f->report_atomic_races, 0);
- EXPECT_EQ(f->force_seq_cst_atomics, 0);
- EXPECT_EQ(f->print_benign, 0);
- EXPECT_EQ(f->exitcode, 111);
- EXPECT_EQ(f->halt_on_error, 0);
- EXPECT_EQ(f->atexit_sleep_ms, 222);
- EXPECT_EQ(f->profile_memory, std::string("qqq"));
- EXPECT_EQ(f->flush_memory_ms, 444);
- EXPECT_EQ(f->flush_symbolizer_ms, 555);
- EXPECT_EQ(f->memory_limit_mb, 666);
- EXPECT_EQ(f->stop_on_start, 0);
- EXPECT_EQ(f->running_on_valgrind, 0);
- EXPECT_EQ(f->history_size, 5);
- EXPECT_EQ(f->io_sync, 1);
- EXPECT_EQ(f->die_after_fork, true);
-}
-
-void VerifyOptions2(Flags *f) {
- EXPECT_EQ(f->enable_annotations, true);
- EXPECT_EQ(f->suppress_equal_stacks, true);
- EXPECT_EQ(f->suppress_equal_addresses, true);
- EXPECT_EQ(f->report_bugs, true);
- EXPECT_EQ(f->report_thread_leaks, true);
- EXPECT_EQ(f->report_destroy_locked, true);
- EXPECT_EQ(f->report_mutex_bugs, true);
- EXPECT_EQ(f->report_signal_unsafe, true);
- EXPECT_EQ(f->report_atomic_races, true);
- EXPECT_EQ(f->force_seq_cst_atomics, true);
- EXPECT_EQ(f->print_benign, true);
- EXPECT_EQ(f->exitcode, 222);
- EXPECT_EQ(f->halt_on_error, true);
- EXPECT_EQ(f->atexit_sleep_ms, 123);
- EXPECT_EQ(f->profile_memory, std::string("bbbbb"));
- EXPECT_EQ(f->flush_memory_ms, 234);
- EXPECT_EQ(f->flush_symbolizer_ms, 345);
- EXPECT_EQ(f->memory_limit_mb, 456);
- EXPECT_EQ(f->stop_on_start, true);
- EXPECT_EQ(f->running_on_valgrind, true);
- EXPECT_EQ(f->history_size, 6);
- EXPECT_EQ(f->io_sync, 2);
- EXPECT_EQ(f->die_after_fork, false);
-}
-
-static const char *test_default_options;
-extern "C" const char *__tsan_default_options() {
- return test_default_options;
-}
-
-TEST(Flags, ParseDefaultOptions) {
- Flags f;
-
- test_default_options = options1;
- InitializeFlags(&f, "");
- VerifyOptions1(&f);
-
- test_default_options = options2;
- InitializeFlags(&f, "");
- VerifyOptions2(&f);
-}
-
-TEST(Flags, ParseEnvOptions) {
- Flags f;
-
- InitializeFlags(&f, options1);
- VerifyOptions1(&f);
-
- InitializeFlags(&f, options2);
- VerifyOptions2(&f);
-}
-
-TEST(Flags, ParsePriority) {
- Flags f;
-
- test_default_options = options2;
- InitializeFlags(&f, options1);
- VerifyOptions1(&f);
-
- test_default_options = options1;
- InitializeFlags(&f, options2);
- VerifyOptions2(&f);
-}
-
-} // namespace __tsan
diff --git a/contrib/compiler-rt/lib/tsan/tests/unit/tsan_mman_test.cc b/contrib/compiler-rt/lib/tsan/tests/unit/tsan_mman_test.cc
deleted file mode 100644
index bfaefe648705..000000000000
--- a/contrib/compiler-rt/lib/tsan/tests/unit/tsan_mman_test.cc
+++ /dev/null
@@ -1,153 +0,0 @@
-//===-- tsan_mman_test.cc -------------------------------------------------===//
-//
-// 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 ThreadSanitizer (TSan), a race detector.
-//
-//===----------------------------------------------------------------------===//
-#include <limits>
-#include <sanitizer/allocator_interface.h>
-#include "tsan_mman.h"
-#include "tsan_rtl.h"
-#include "gtest/gtest.h"
-
-namespace __tsan {
-
-TEST(Mman, Internal) {
- char *p = (char*)internal_alloc(MBlockScopedBuf, 10);
- EXPECT_NE(p, (char*)0);
- char *p2 = (char*)internal_alloc(MBlockScopedBuf, 20);
- EXPECT_NE(p2, (char*)0);
- EXPECT_NE(p2, p);
- for (int i = 0; i < 10; i++) {
- p[i] = 42;
- }
- for (int i = 0; i < 20; i++) {
- ((char*)p2)[i] = 42;
- }
- internal_free(p);
- internal_free(p2);
-}
-
-TEST(Mman, User) {
- ThreadState *thr = cur_thread();
- uptr pc = 0;
- char *p = (char*)user_alloc(thr, pc, 10);
- EXPECT_NE(p, (char*)0);
- char *p2 = (char*)user_alloc(thr, pc, 20);
- EXPECT_NE(p2, (char*)0);
- EXPECT_NE(p2, p);
- EXPECT_EQ(10U, user_alloc_usable_size(p));
- EXPECT_EQ(20U, user_alloc_usable_size(p2));
- user_free(thr, pc, p);
- user_free(thr, pc, p2);
-}
-
-TEST(Mman, UserRealloc) {
- ThreadState *thr = cur_thread();
- uptr pc = 0;
- {
- void *p = user_realloc(thr, pc, 0, 0);
- // Strictly saying this is incorrect, realloc(NULL, N) is equivalent to
- // malloc(N), thus must return non-NULL pointer.
- EXPECT_EQ(p, (void*)0);
- }
- {
- void *p = user_realloc(thr, pc, 0, 100);
- EXPECT_NE(p, (void*)0);
- memset(p, 0xde, 100);
- user_free(thr, pc, p);
- }
- {
- void *p = user_alloc(thr, pc, 100);
- EXPECT_NE(p, (void*)0);
- memset(p, 0xde, 100);
- void *p2 = user_realloc(thr, pc, p, 0);
- EXPECT_EQ(p2, (void*)0);
- }
- {
- void *p = user_realloc(thr, pc, 0, 100);
- EXPECT_NE(p, (void*)0);
- memset(p, 0xde, 100);
- void *p2 = user_realloc(thr, pc, p, 10000);
- EXPECT_NE(p2, (void*)0);
- for (int i = 0; i < 100; i++)
- EXPECT_EQ(((char*)p2)[i], (char)0xde);
- memset(p2, 0xde, 10000);
- user_free(thr, pc, p2);
- }
- {
- void *p = user_realloc(thr, pc, 0, 10000);
- EXPECT_NE(p, (void*)0);
- memset(p, 0xde, 10000);
- void *p2 = user_realloc(thr, pc, p, 10);
- EXPECT_NE(p2, (void*)0);
- for (int i = 0; i < 10; i++)
- EXPECT_EQ(((char*)p2)[i], (char)0xde);
- user_free(thr, pc, p2);
- }
-}
-
-TEST(Mman, UsableSize) {
- ThreadState *thr = cur_thread();
- uptr pc = 0;
- char *p = (char*)user_alloc(thr, pc, 10);
- char *p2 = (char*)user_alloc(thr, pc, 20);
- EXPECT_EQ(0U, user_alloc_usable_size(NULL));
- EXPECT_EQ(10U, user_alloc_usable_size(p));
- EXPECT_EQ(20U, user_alloc_usable_size(p2));
- user_free(thr, pc, p);
- user_free(thr, pc, p2);
- EXPECT_EQ(0U, user_alloc_usable_size((void*)0x4123));
-}
-
-TEST(Mman, Stats) {
- ThreadState *thr = cur_thread();
-
- uptr alloc0 = __sanitizer_get_current_allocated_bytes();
- uptr heap0 = __sanitizer_get_heap_size();
- uptr free0 = __sanitizer_get_free_bytes();
- uptr unmapped0 = __sanitizer_get_unmapped_bytes();
-
- EXPECT_EQ(10U, __sanitizer_get_estimated_allocated_size(10));
- EXPECT_EQ(20U, __sanitizer_get_estimated_allocated_size(20));
- EXPECT_EQ(100U, __sanitizer_get_estimated_allocated_size(100));
-
- char *p = (char*)user_alloc(thr, 0, 10);
- EXPECT_TRUE(__sanitizer_get_ownership(p));
- EXPECT_EQ(10U, __sanitizer_get_allocated_size(p));
-
- EXPECT_EQ(alloc0 + 16, __sanitizer_get_current_allocated_bytes());
- EXPECT_GE(__sanitizer_get_heap_size(), heap0);
- EXPECT_EQ(free0, __sanitizer_get_free_bytes());
- EXPECT_EQ(unmapped0, __sanitizer_get_unmapped_bytes());
-
- user_free(thr, 0, p);
-
- EXPECT_EQ(alloc0, __sanitizer_get_current_allocated_bytes());
- EXPECT_GE(__sanitizer_get_heap_size(), heap0);
- EXPECT_EQ(free0, __sanitizer_get_free_bytes());
- EXPECT_EQ(unmapped0, __sanitizer_get_unmapped_bytes());
-}
-
-TEST(Mman, CallocOverflow) {
-#if SANITIZER_DEBUG
- // EXPECT_DEATH clones a thread with 4K stack,
- // which is overflown by tsan memory accesses functions in debug mode.
- return;
-#endif
- size_t kArraySize = 4096;
- volatile size_t kMaxSizeT = std::numeric_limits<size_t>::max();
- volatile size_t kArraySize2 = kMaxSizeT / kArraySize + 10;
- volatile void *p = NULL;
- EXPECT_DEATH(p = calloc(kArraySize, kArraySize2),
- "allocator is terminating the process instead of returning 0");
- EXPECT_EQ(0L, p);
-}
-
-} // namespace __tsan
diff --git a/contrib/compiler-rt/lib/tsan/tests/unit/tsan_mutex_test.cc b/contrib/compiler-rt/lib/tsan/tests/unit/tsan_mutex_test.cc
deleted file mode 100644
index cce7f073b92f..000000000000
--- a/contrib/compiler-rt/lib/tsan/tests/unit/tsan_mutex_test.cc
+++ /dev/null
@@ -1,126 +0,0 @@
-//===-- tsan_mutex_test.cc ------------------------------------------------===//
-//
-// 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 ThreadSanitizer (TSan), a race detector.
-//
-//===----------------------------------------------------------------------===//
-#include "sanitizer_common/sanitizer_internal_defs.h"
-#include "sanitizer_common/sanitizer_atomic.h"
-#include "sanitizer_common/sanitizer_common.h"
-#include "sanitizer_common/sanitizer_mutex.h"
-#include "tsan_mutex.h"
-#include "gtest/gtest.h"
-
-namespace __tsan {
-
-template<typename MutexType>
-class TestData {
- public:
- explicit TestData(MutexType *mtx)
- : mtx_(mtx) {
- for (int i = 0; i < kSize; i++)
- data_[i] = 0;
- }
-
- void Write() {
- Lock l(mtx_);
- T v0 = data_[0];
- for (int i = 0; i < kSize; i++) {
- CHECK_EQ(data_[i], v0);
- data_[i]++;
- }
- }
-
- void Read() {
- ReadLock l(mtx_);
- T v0 = data_[0];
- for (int i = 0; i < kSize; i++) {
- CHECK_EQ(data_[i], v0);
- }
- }
-
- void Backoff() {
- volatile T data[kSize] = {};
- for (int i = 0; i < kSize; i++) {
- data[i]++;
- CHECK_EQ(data[i], 1);
- }
- }
-
- private:
- typedef GenericScopedLock<MutexType> Lock;
- static const int kSize = 64;
- typedef u64 T;
- MutexType *mtx_;
- char pad_[kCacheLineSize];
- T data_[kSize];
-};
-
-const int kThreads = 8;
-const int kWriteRate = 1024;
-#if SANITIZER_DEBUG
-const int kIters = 16*1024;
-#else
-const int kIters = 64*1024;
-#endif
-
-template<typename MutexType>
-static void *write_mutex_thread(void *param) {
- TestData<MutexType> *data = (TestData<MutexType>*)param;
- for (int i = 0; i < kIters; i++) {
- data->Write();
- data->Backoff();
- }
- return 0;
-}
-
-template<typename MutexType>
-static void *read_mutex_thread(void *param) {
- TestData<MutexType> *data = (TestData<MutexType>*)param;
- for (int i = 0; i < kIters; i++) {
- if ((i % kWriteRate) == 0)
- data->Write();
- else
- data->Read();
- data->Backoff();
- }
- return 0;
-}
-
-TEST(Mutex, Write) {
- Mutex mtx(MutexTypeAnnotations, StatMtxAnnotations);
- TestData<Mutex> data(&mtx);
- pthread_t threads[kThreads];
- for (int i = 0; i < kThreads; i++)
- pthread_create(&threads[i], 0, write_mutex_thread<Mutex>, &data);
- for (int i = 0; i < kThreads; i++)
- pthread_join(threads[i], 0);
-}
-
-TEST(Mutex, ReadWrite) {
- Mutex mtx(MutexTypeAnnotations, StatMtxAnnotations);
- TestData<Mutex> data(&mtx);
- pthread_t threads[kThreads];
- for (int i = 0; i < kThreads; i++)
- pthread_create(&threads[i], 0, read_mutex_thread<Mutex>, &data);
- for (int i = 0; i < kThreads; i++)
- pthread_join(threads[i], 0);
-}
-
-TEST(Mutex, SpinWrite) {
- SpinMutex mtx;
- TestData<SpinMutex> data(&mtx);
- pthread_t threads[kThreads];
- for (int i = 0; i < kThreads; i++)
- pthread_create(&threads[i], 0, write_mutex_thread<SpinMutex>, &data);
- for (int i = 0; i < kThreads; i++)
- pthread_join(threads[i], 0);
-}
-
-} // namespace __tsan
diff --git a/contrib/compiler-rt/lib/tsan/tests/unit/tsan_mutexset_test.cc b/contrib/compiler-rt/lib/tsan/tests/unit/tsan_mutexset_test.cc
deleted file mode 100644
index 335a7748cc1a..000000000000
--- a/contrib/compiler-rt/lib/tsan/tests/unit/tsan_mutexset_test.cc
+++ /dev/null
@@ -1,127 +0,0 @@
-//===-- tsan_mutexset_test.cc ---------------------------------------------===//
-//
-// 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 ThreadSanitizer (TSan), a race detector.
-//
-//===----------------------------------------------------------------------===//
-#include "tsan_mutexset.h"
-#include "gtest/gtest.h"
-
-namespace __tsan {
-
-static void Expect(const MutexSet &mset, uptr i, u64 id, bool write, u64 epoch,
- int count) {
- MutexSet::Desc d = mset.Get(i);
- EXPECT_EQ(id, d.id);
- EXPECT_EQ(write, d.write);
- EXPECT_EQ(epoch, d.epoch);
- EXPECT_EQ(count, d.count);
-}
-
-TEST(MutexSet, Basic) {
- MutexSet mset;
- EXPECT_EQ(mset.Size(), (uptr)0);
-
- mset.Add(1, true, 2);
- EXPECT_EQ(mset.Size(), (uptr)1);
- Expect(mset, 0, 1, true, 2, 1);
- mset.Del(1, true);
- EXPECT_EQ(mset.Size(), (uptr)0);
-
- mset.Add(3, true, 4);
- mset.Add(5, false, 6);
- EXPECT_EQ(mset.Size(), (uptr)2);
- Expect(mset, 0, 3, true, 4, 1);
- Expect(mset, 1, 5, false, 6, 1);
- mset.Del(3, true);
- EXPECT_EQ(mset.Size(), (uptr)1);
- mset.Del(5, false);
- EXPECT_EQ(mset.Size(), (uptr)0);
-}
-
-TEST(MutexSet, DoubleAdd) {
- MutexSet mset;
- mset.Add(1, true, 2);
- EXPECT_EQ(mset.Size(), (uptr)1);
- Expect(mset, 0, 1, true, 2, 1);
-
- mset.Add(1, true, 2);
- EXPECT_EQ(mset.Size(), (uptr)1);
- Expect(mset, 0, 1, true, 2, 2);
-
- mset.Del(1, true);
- EXPECT_EQ(mset.Size(), (uptr)1);
- Expect(mset, 0, 1, true, 2, 1);
-
- mset.Del(1, true);
- EXPECT_EQ(mset.Size(), (uptr)0);
-}
-
-TEST(MutexSet, DoubleDel) {
- MutexSet mset;
- mset.Add(1, true, 2);
- EXPECT_EQ(mset.Size(), (uptr)1);
- mset.Del(1, true);
- EXPECT_EQ(mset.Size(), (uptr)0);
- mset.Del(1, true);
- EXPECT_EQ(mset.Size(), (uptr)0);
-}
-
-TEST(MutexSet, Remove) {
- MutexSet mset;
- mset.Add(1, true, 2);
- mset.Add(1, true, 2);
- mset.Add(3, true, 4);
- mset.Add(3, true, 4);
- EXPECT_EQ(mset.Size(), (uptr)2);
-
- mset.Remove(1);
- EXPECT_EQ(mset.Size(), (uptr)1);
- Expect(mset, 0, 3, true, 4, 2);
-}
-
-TEST(MutexSet, Full) {
- MutexSet mset;
- for (uptr i = 0; i < MutexSet::kMaxSize; i++) {
- mset.Add(i, true, i + 1);
- }
- EXPECT_EQ(mset.Size(), MutexSet::kMaxSize);
- for (uptr i = 0; i < MutexSet::kMaxSize; i++) {
- Expect(mset, i, i, true, i + 1, 1);
- }
-
- for (uptr i = 0; i < MutexSet::kMaxSize; i++) {
- mset.Add(i, true, i + 1);
- }
- EXPECT_EQ(mset.Size(), MutexSet::kMaxSize);
- for (uptr i = 0; i < MutexSet::kMaxSize; i++) {
- Expect(mset, i, i, true, i + 1, 2);
- }
-}
-
-TEST(MutexSet, Overflow) {
- MutexSet mset;
- for (uptr i = 0; i < MutexSet::kMaxSize; i++) {
- mset.Add(i, true, i + 1);
- mset.Add(i, true, i + 1);
- }
- mset.Add(100, true, 200);
- EXPECT_EQ(mset.Size(), MutexSet::kMaxSize);
- for (uptr i = 0; i < MutexSet::kMaxSize; i++) {
- if (i == 0)
- Expect(mset, i, MutexSet::kMaxSize - 1,
- true, MutexSet::kMaxSize, 2);
- else if (i == MutexSet::kMaxSize - 1)
- Expect(mset, i, 100, true, 200, 1);
- else
- Expect(mset, i, i, true, i + 1, 2);
- }
-}
-
-} // namespace __tsan
diff --git a/contrib/compiler-rt/lib/tsan/tests/unit/tsan_shadow_test.cc b/contrib/compiler-rt/lib/tsan/tests/unit/tsan_shadow_test.cc
deleted file mode 100644
index 17b17977bf86..000000000000
--- a/contrib/compiler-rt/lib/tsan/tests/unit/tsan_shadow_test.cc
+++ /dev/null
@@ -1,78 +0,0 @@
-//===-- tsan_shadow_test.cc -----------------------------------------------===//
-//
-// 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 ThreadSanitizer (TSan), a race detector.
-//
-//===----------------------------------------------------------------------===//
-#include "tsan_platform.h"
-#include "tsan_rtl.h"
-#include "gtest/gtest.h"
-
-namespace __tsan {
-
-TEST(Shadow, FastState) {
- Shadow s(FastState(11, 22));
- EXPECT_EQ(s.tid(), (u64)11);
- EXPECT_EQ(s.epoch(), (u64)22);
- EXPECT_EQ(s.GetIgnoreBit(), false);
- EXPECT_EQ(s.GetFreedAndReset(), false);
- EXPECT_EQ(s.GetHistorySize(), 0);
- EXPECT_EQ(s.addr0(), (u64)0);
- EXPECT_EQ(s.size(), (u64)1);
- EXPECT_EQ(s.IsWrite(), true);
-
- s.IncrementEpoch();
- EXPECT_EQ(s.epoch(), (u64)23);
- s.IncrementEpoch();
- EXPECT_EQ(s.epoch(), (u64)24);
-
- s.SetIgnoreBit();
- EXPECT_EQ(s.GetIgnoreBit(), true);
- s.ClearIgnoreBit();
- EXPECT_EQ(s.GetIgnoreBit(), false);
-
- for (int i = 0; i < 8; i++) {
- s.SetHistorySize(i);
- EXPECT_EQ(s.GetHistorySize(), i);
- }
- s.SetHistorySize(2);
- s.ClearHistorySize();
- EXPECT_EQ(s.GetHistorySize(), 0);
-}
-
-TEST(Shadow, Mapping) {
- static int global;
- int stack;
- void *heap = malloc(0);
- free(heap);
-
- CHECK(IsAppMem((uptr)&global));
- CHECK(IsAppMem((uptr)&stack));
- CHECK(IsAppMem((uptr)heap));
-
- CHECK(IsShadowMem(MemToShadow((uptr)&global)));
- CHECK(IsShadowMem(MemToShadow((uptr)&stack)));
- CHECK(IsShadowMem(MemToShadow((uptr)heap)));
-}
-
-TEST(Shadow, Celling) {
- u64 aligned_data[4];
- char *data = (char*)aligned_data;
- CHECK_EQ((uptr)data % kShadowSize, 0);
- uptr s0 = MemToShadow((uptr)&data[0]);
- CHECK_EQ(s0 % kShadowSize, 0);
- for (unsigned i = 1; i < kShadowCell; i++)
- CHECK_EQ(s0, MemToShadow((uptr)&data[i]));
- for (unsigned i = kShadowCell; i < 2*kShadowCell; i++)
- CHECK_EQ(s0 + kShadowSize*kShadowCnt, MemToShadow((uptr)&data[i]));
- for (unsigned i = 2*kShadowCell; i < 3*kShadowCell; i++)
- CHECK_EQ(s0 + 2*kShadowSize*kShadowCnt, MemToShadow((uptr)&data[i]));
-}
-
-} // namespace __tsan
diff --git a/contrib/compiler-rt/lib/tsan/tests/unit/tsan_stack_test.cc b/contrib/compiler-rt/lib/tsan/tests/unit/tsan_stack_test.cc
deleted file mode 100644
index 92e035d8d000..000000000000
--- a/contrib/compiler-rt/lib/tsan/tests/unit/tsan_stack_test.cc
+++ /dev/null
@@ -1,95 +0,0 @@
-//===-- tsan_stack_test.cc ------------------------------------------------===//
-//
-// 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 ThreadSanitizer (TSan), a race detector.
-//
-//===----------------------------------------------------------------------===//
-#include "tsan_sync.h"
-#include "tsan_rtl.h"
-#include "gtest/gtest.h"
-#include <string.h>
-
-namespace __tsan {
-
-template <typename StackTraceTy>
-static void TestStackTrace(StackTraceTy *trace) {
- ThreadState thr(0, 0, 0, 0, 0, 0, 0, 0, 0);
- uptr stack[128];
- thr.shadow_stack = &stack[0];
- thr.shadow_stack_pos = &stack[0];
- thr.shadow_stack_end = &stack[128];
-
- ObtainCurrentStack(&thr, 0, trace);
- EXPECT_EQ(0U, trace->size);
-
- ObtainCurrentStack(&thr, 42, trace);
- EXPECT_EQ(1U, trace->size);
- EXPECT_EQ(42U, trace->trace[0]);
-
- *thr.shadow_stack_pos++ = 100;
- *thr.shadow_stack_pos++ = 101;
- ObtainCurrentStack(&thr, 0, trace);
- EXPECT_EQ(2U, trace->size);
- EXPECT_EQ(100U, trace->trace[0]);
- EXPECT_EQ(101U, trace->trace[1]);
-
- ObtainCurrentStack(&thr, 42, trace);
- EXPECT_EQ(3U, trace->size);
- EXPECT_EQ(100U, trace->trace[0]);
- EXPECT_EQ(101U, trace->trace[1]);
- EXPECT_EQ(42U, trace->trace[2]);
-}
-
-template<typename StackTraceTy>
-static void TestTrim(StackTraceTy *trace) {
- ThreadState thr(0, 0, 0, 0, 0, 0, 0, 0, 0);
- const uptr kShadowStackSize = 2 * kStackTraceMax;
- uptr stack[kShadowStackSize];
- thr.shadow_stack = &stack[0];
- thr.shadow_stack_pos = &stack[0];
- thr.shadow_stack_end = &stack[kShadowStackSize];
-
- for (uptr i = 0; i < kShadowStackSize; ++i)
- *thr.shadow_stack_pos++ = 100 + i;
-
- ObtainCurrentStack(&thr, 0, trace);
- EXPECT_EQ(kStackTraceMax, trace->size);
- for (uptr i = 0; i < kStackTraceMax; i++) {
- EXPECT_EQ(100 + kStackTraceMax + i, trace->trace[i]);
- }
-
- ObtainCurrentStack(&thr, 42, trace);
- EXPECT_EQ(kStackTraceMax, trace->size);
- for (uptr i = 0; i < kStackTraceMax - 1; i++) {
- EXPECT_EQ(101 + kStackTraceMax + i, trace->trace[i]);
- }
- EXPECT_EQ(42U, trace->trace[kStackTraceMax - 1]);
-}
-
-TEST(StackTrace, BasicVarSize) {
- VarSizeStackTrace trace;
- TestStackTrace(&trace);
-}
-
-TEST(StackTrace, BasicBuffered) {
- BufferedStackTrace trace;
- TestStackTrace(&trace);
-}
-
-TEST(StackTrace, TrimVarSize) {
- VarSizeStackTrace trace;
- TestTrim(&trace);
-}
-
-TEST(StackTrace, TrimBuffered) {
- BufferedStackTrace trace;
- TestTrim(&trace);
-}
-
-} // namespace __tsan
diff --git a/contrib/compiler-rt/lib/tsan/tests/unit/tsan_sync_test.cc b/contrib/compiler-rt/lib/tsan/tests/unit/tsan_sync_test.cc
deleted file mode 100644
index d3616a1a4b81..000000000000
--- a/contrib/compiler-rt/lib/tsan/tests/unit/tsan_sync_test.cc
+++ /dev/null
@@ -1,123 +0,0 @@
-//===-- tsan_sync_test.cc -------------------------------------------------===//
-//
-// 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 ThreadSanitizer (TSan), a race detector.
-//
-//===----------------------------------------------------------------------===//
-#include "tsan_sync.h"
-#include "tsan_rtl.h"
-#include "gtest/gtest.h"
-
-namespace __tsan {
-
-TEST(MetaMap, Basic) {
- ThreadState *thr = cur_thread();
- MetaMap *m = &ctx->metamap;
- u64 block[1] = {}; // fake malloc block
- m->AllocBlock(thr, 0, (uptr)&block[0], 1 * sizeof(u64));
- MBlock *mb = m->GetBlock((uptr)&block[0]);
- EXPECT_NE(mb, (MBlock*)0);
- EXPECT_EQ(mb->siz, 1 * sizeof(u64));
- EXPECT_EQ(mb->tid, thr->tid);
- uptr sz = m->FreeBlock(thr, 0, (uptr)&block[0]);
- EXPECT_EQ(sz, 1 * sizeof(u64));
- mb = m->GetBlock((uptr)&block[0]);
- EXPECT_EQ(mb, (MBlock*)0);
-}
-
-TEST(MetaMap, FreeRange) {
- ThreadState *thr = cur_thread();
- MetaMap *m = &ctx->metamap;
- u64 block[4] = {}; // fake malloc block
- m->AllocBlock(thr, 0, (uptr)&block[0], 1 * sizeof(u64));
- m->AllocBlock(thr, 0, (uptr)&block[1], 3 * sizeof(u64));
- MBlock *mb1 = m->GetBlock((uptr)&block[0]);
- EXPECT_EQ(mb1->siz, 1 * sizeof(u64));
- MBlock *mb2 = m->GetBlock((uptr)&block[1]);
- EXPECT_EQ(mb2->siz, 3 * sizeof(u64));
- m->FreeRange(thr, 0, (uptr)&block[0], 4 * sizeof(u64));
- mb1 = m->GetBlock((uptr)&block[0]);
- EXPECT_EQ(mb1, (MBlock*)0);
- mb2 = m->GetBlock((uptr)&block[1]);
- EXPECT_EQ(mb2, (MBlock*)0);
-}
-
-TEST(MetaMap, Sync) {
- ThreadState *thr = cur_thread();
- MetaMap *m = &ctx->metamap;
- u64 block[4] = {}; // fake malloc block
- m->AllocBlock(thr, 0, (uptr)&block[0], 4 * sizeof(u64));
- SyncVar *s1 = m->GetIfExistsAndLock((uptr)&block[0]);
- EXPECT_EQ(s1, (SyncVar*)0);
- s1 = m->GetOrCreateAndLock(thr, 0, (uptr)&block[0], true);
- EXPECT_NE(s1, (SyncVar*)0);
- EXPECT_EQ(s1->addr, (uptr)&block[0]);
- s1->mtx.Unlock();
- SyncVar *s2 = m->GetOrCreateAndLock(thr, 0, (uptr)&block[1], false);
- EXPECT_NE(s2, (SyncVar*)0);
- EXPECT_EQ(s2->addr, (uptr)&block[1]);
- s2->mtx.ReadUnlock();
- m->FreeBlock(thr, 0, (uptr)&block[0]);
- s1 = m->GetIfExistsAndLock((uptr)&block[0]);
- EXPECT_EQ(s1, (SyncVar*)0);
- s2 = m->GetIfExistsAndLock((uptr)&block[1]);
- EXPECT_EQ(s2, (SyncVar*)0);
- m->OnThreadIdle(thr);
-}
-
-TEST(MetaMap, MoveMemory) {
- ThreadState *thr = cur_thread();
- MetaMap *m = &ctx->metamap;
- u64 block1[4] = {}; // fake malloc block
- u64 block2[4] = {}; // fake malloc block
- m->AllocBlock(thr, 0, (uptr)&block1[0], 3 * sizeof(u64));
- m->AllocBlock(thr, 0, (uptr)&block1[3], 1 * sizeof(u64));
- SyncVar *s1 = m->GetOrCreateAndLock(thr, 0, (uptr)&block1[0], true);
- s1->mtx.Unlock();
- SyncVar *s2 = m->GetOrCreateAndLock(thr, 0, (uptr)&block1[1], true);
- s2->mtx.Unlock();
- m->MoveMemory((uptr)&block1[0], (uptr)&block2[0], 4 * sizeof(u64));
- MBlock *mb1 = m->GetBlock((uptr)&block1[0]);
- EXPECT_EQ(mb1, (MBlock*)0);
- MBlock *mb2 = m->GetBlock((uptr)&block1[3]);
- EXPECT_EQ(mb2, (MBlock*)0);
- mb1 = m->GetBlock((uptr)&block2[0]);
- EXPECT_NE(mb1, (MBlock*)0);
- EXPECT_EQ(mb1->siz, 3 * sizeof(u64));
- mb2 = m->GetBlock((uptr)&block2[3]);
- EXPECT_NE(mb2, (MBlock*)0);
- EXPECT_EQ(mb2->siz, 1 * sizeof(u64));
- s1 = m->GetIfExistsAndLock((uptr)&block1[0]);
- EXPECT_EQ(s1, (SyncVar*)0);
- s2 = m->GetIfExistsAndLock((uptr)&block1[1]);
- EXPECT_EQ(s2, (SyncVar*)0);
- s1 = m->GetIfExistsAndLock((uptr)&block2[0]);
- EXPECT_NE(s1, (SyncVar*)0);
- EXPECT_EQ(s1->addr, (uptr)&block2[0]);
- s1->mtx.Unlock();
- s2 = m->GetIfExistsAndLock((uptr)&block2[1]);
- EXPECT_NE(s2, (SyncVar*)0);
- EXPECT_EQ(s2->addr, (uptr)&block2[1]);
- s2->mtx.Unlock();
- m->FreeRange(thr, 0, (uptr)&block2[0], 4 * sizeof(u64));
-}
-
-TEST(MetaMap, ResetSync) {
- ThreadState *thr = cur_thread();
- MetaMap *m = &ctx->metamap;
- u64 block[1] = {}; // fake malloc block
- m->AllocBlock(thr, 0, (uptr)&block[0], 1 * sizeof(u64));
- SyncVar *s = m->GetOrCreateAndLock(thr, 0, (uptr)&block[0], true);
- s->Reset(thr);
- s->mtx.Unlock();
- uptr sz = m->FreeBlock(thr, 0, (uptr)&block[0]);
- EXPECT_EQ(sz, 1 * sizeof(u64));
-}
-
-} // namespace __tsan
diff --git a/contrib/compiler-rt/lib/tsan/tests/unit/tsan_unit_test_main.cc b/contrib/compiler-rt/lib/tsan/tests/unit/tsan_unit_test_main.cc
deleted file mode 100644
index 84d94dd03748..000000000000
--- a/contrib/compiler-rt/lib/tsan/tests/unit/tsan_unit_test_main.cc
+++ /dev/null
@@ -1,19 +0,0 @@
-//===-- tsan_unit_test_main.cc --------------------------------------------===//
-//
-// 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 ThreadSanitizer (TSan), a race detector.
-//
-//===----------------------------------------------------------------------===//
-#include "gtest/gtest.h"
-
-int main(int argc, char **argv) {
- testing::GTEST_FLAG(death_test_style) = "threadsafe";
- testing::InitGoogleTest(&argc, argv);
- return RUN_ALL_TESTS();
-}
diff --git a/contrib/compiler-rt/lib/tsan/tests/unit/tsan_vector_test.cc b/contrib/compiler-rt/lib/tsan/tests/unit/tsan_vector_test.cc
deleted file mode 100644
index c54ac1ee6de9..000000000000
--- a/contrib/compiler-rt/lib/tsan/tests/unit/tsan_vector_test.cc
+++ /dev/null
@@ -1,43 +0,0 @@
-//===-- tsan_vector_test.cc -----------------------------------------------===//
-//
-// 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 ThreadSanitizer (TSan), a race detector.
-//
-//===----------------------------------------------------------------------===//
-#include "tsan_vector.h"
-#include "tsan_rtl.h"
-#include "gtest/gtest.h"
-
-namespace __tsan {
-
-TEST(Vector, Basic) {
- Vector<int> v(MBlockScopedBuf);
- EXPECT_EQ(v.Size(), (uptr)0);
- v.PushBack(42);
- EXPECT_EQ(v.Size(), (uptr)1);
- EXPECT_EQ(v[0], 42);
- v.PushBack(43);
- EXPECT_EQ(v.Size(), (uptr)2);
- EXPECT_EQ(v[0], 42);
- EXPECT_EQ(v[1], 43);
-}
-
-TEST(Vector, Stride) {
- Vector<int> v(MBlockScopedBuf);
- for (int i = 0; i < 1000; i++) {
- v.PushBack(i);
- EXPECT_EQ(v.Size(), (uptr)(i + 1));
- EXPECT_EQ(v[i], i);
- }
- for (int i = 0; i < 1000; i++) {
- EXPECT_EQ(v[i], i);
- }
-}
-
-} // namespace __tsan
diff --git a/contrib/compiler-rt/lib/ubsan/ubsan_checks.inc b/contrib/compiler-rt/lib/ubsan/ubsan_checks.inc
new file mode 100644
index 000000000000..6e086414051e
--- /dev/null
+++ b/contrib/compiler-rt/lib/ubsan/ubsan_checks.inc
@@ -0,0 +1,45 @@
+//===-- ubsan_checks.inc ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// List of checks handled by UBSan runtime.
+//
+//===----------------------------------------------------------------------===//
+#ifndef UBSAN_CHECK
+# error "Define UBSAN_CHECK prior to including this file!"
+#endif
+
+// UBSAN_CHECK(Name, SummaryKind, FSanitizeFlagName)
+// SummaryKind and FSanitizeFlagName should be string literals.
+
+UBSAN_CHECK(GenericUB, "undefined-behavior", "undefined")
+UBSAN_CHECK(NullPointerUse, "null-pointer-use", "null")
+UBSAN_CHECK(MisalignedPointerUse, "misaligned-pointer-use", "alignment")
+UBSAN_CHECK(InsufficientObjectSize, "insufficient-object-size", "object-size")
+UBSAN_CHECK(SignedIntegerOverflow, "signed-integer-overflow",
+ "signed-integer-overflow")
+UBSAN_CHECK(UnsignedIntegerOverflow, "unsigned-integer-overflow",
+ "unsigned-integer-overflow")
+UBSAN_CHECK(IntegerDivideByZero, "integer-divide-by-zero",
+ "integer-divide-by-zero")
+UBSAN_CHECK(FloatDivideByZero, "float-divide-by-zero", "float-divide-by-zero")
+UBSAN_CHECK(InvalidShiftBase, "invalid-shift-base", "shift-base")
+UBSAN_CHECK(InvalidShiftExponent, "invalid-shift-exponent", "shift-exponent")
+UBSAN_CHECK(OutOfBoundsIndex, "out-of-bounds-index", "bounds")
+UBSAN_CHECK(UnreachableCall, "unreachable-call", "unreachable")
+UBSAN_CHECK(MissingReturn, "missing-return", "return")
+UBSAN_CHECK(NonPositiveVLAIndex, "non-positive-vla-index", "vla-bound")
+UBSAN_CHECK(FloatCastOverflow, "float-cast-overflow", "float-cast-overflow")
+UBSAN_CHECK(InvalidBoolLoad, "invalid-bool-load", "bool")
+UBSAN_CHECK(InvalidEnumLoad, "invalid-enum-load", "enum")
+UBSAN_CHECK(FunctionTypeMismatch, "function-type-mismatch", "function")
+UBSAN_CHECK(InvalidNullReturn, "invalid-null-return",
+ "returns-nonnull-attribute")
+UBSAN_CHECK(InvalidNullArgument, "invalid-null-argument", "nonnull-attribute")
+UBSAN_CHECK(DynamicTypeMismatch, "dynamic-type-mismatch", "vptr")
+UBSAN_CHECK(CFIBadType, "cfi-bad-type", "cfi")
diff --git a/contrib/compiler-rt/lib/ubsan/ubsan_diag.cc b/contrib/compiler-rt/lib/ubsan/ubsan_diag.cc
index 3d5042b51d2e..2476947dc914 100644
--- a/contrib/compiler-rt/lib/ubsan/ubsan_diag.cc
+++ b/contrib/compiler-rt/lib/ubsan/ubsan_diag.cc
@@ -43,10 +43,34 @@ static void MaybePrintStackTrace(uptr pc, uptr bp) {
stack.Print();
}
-static void MaybeReportErrorSummary(Location Loc) {
+static const char *ConvertTypeToString(ErrorType Type) {
+ switch (Type) {
+#define UBSAN_CHECK(Name, SummaryKind, FSanitizeFlagName) \
+ case ErrorType::Name: \
+ return SummaryKind;
+#include "ubsan_checks.inc"
+#undef UBSAN_CHECK
+ }
+ UNREACHABLE("unknown ErrorType!");
+}
+
+static const char *ConvertTypeToFlagName(ErrorType Type) {
+ switch (Type) {
+#define UBSAN_CHECK(Name, SummaryKind, FSanitizeFlagName) \
+ case ErrorType::Name: \
+ return FSanitizeFlagName;
+#include "ubsan_checks.inc"
+#undef UBSAN_CHECK
+ }
+ UNREACHABLE("unknown ErrorType!");
+}
+
+static void MaybeReportErrorSummary(Location Loc, ErrorType Type) {
if (!common_flags()->print_summary)
return;
- const char *ErrorType = "undefined-behavior";
+ if (!flags()->report_error_type)
+ Type = ErrorType::GenericUB;
+ const char *ErrorKind = ConvertTypeToString(Type);
if (Loc.isSourceLocation()) {
SourceLocation SLoc = Loc.getSourceLocation();
if (!SLoc.isInvalid()) {
@@ -55,16 +79,16 @@ static void MaybeReportErrorSummary(Location Loc) {
AI.line = SLoc.getLine();
AI.column = SLoc.getColumn();
AI.function = internal_strdup(""); // Avoid printing ?? as function name.
- ReportErrorSummary(ErrorType, AI);
+ ReportErrorSummary(ErrorKind, AI);
AI.Clear();
return;
}
} else if (Loc.isSymbolizedStack()) {
const AddressInfo &AI = Loc.getSymbolizedStack()->info;
- ReportErrorSummary(ErrorType, AI);
+ ReportErrorSummary(ErrorKind, AI);
return;
}
- ReportErrorSummary(ErrorType);
+ ReportErrorSummary(ErrorKind);
}
namespace {
@@ -341,24 +365,30 @@ Diag::~Diag() {
NumRanges, Args);
}
-ScopedReport::ScopedReport(ReportOptions Opts, Location SummaryLoc)
- : Opts(Opts), SummaryLoc(SummaryLoc) {
+ScopedReport::ScopedReport(ReportOptions Opts, Location SummaryLoc,
+ ErrorType Type)
+ : Opts(Opts), SummaryLoc(SummaryLoc), Type(Type) {
InitAsStandaloneIfNecessary();
CommonSanitizerReportMutex.Lock();
}
ScopedReport::~ScopedReport() {
MaybePrintStackTrace(Opts.pc, Opts.bp);
- MaybeReportErrorSummary(SummaryLoc);
+ MaybeReportErrorSummary(SummaryLoc, Type);
CommonSanitizerReportMutex.Unlock();
- if (Opts.DieAfterReport || flags()->halt_on_error)
+ if (flags()->halt_on_error)
Die();
}
ALIGNED(64) static char suppression_placeholder[sizeof(SuppressionContext)];
static SuppressionContext *suppression_ctx = nullptr;
static const char kVptrCheck[] = "vptr_check";
-static const char *kSuppressionTypes[] = { kVptrCheck };
+static const char *kSuppressionTypes[] = {
+#define UBSAN_CHECK(Name, SummaryKind, FSanitizeFlagName) FSanitizeFlagName,
+#include "ubsan_checks.inc"
+#undef UBSAN_CHECK
+ kVptrCheck,
+};
void __ubsan::InitializeSuppressions() {
CHECK_EQ(nullptr, suppression_ctx);
@@ -374,4 +404,28 @@ bool __ubsan::IsVptrCheckSuppressed(const char *TypeName) {
return suppression_ctx->Match(TypeName, kVptrCheck, &s);
}
+bool __ubsan::IsPCSuppressed(ErrorType ET, uptr PC, const char *Filename) {
+ InitAsStandaloneIfNecessary();
+ CHECK(suppression_ctx);
+ const char *SuppType = ConvertTypeToFlagName(ET);
+ // Fast path: don't symbolize PC if there is no suppressions for given UB
+ // type.
+ if (!suppression_ctx->HasSuppressionType(SuppType))
+ return false;
+ Suppression *s = nullptr;
+ // Suppress by file name known to runtime.
+ if (Filename != nullptr && suppression_ctx->Match(Filename, SuppType, &s))
+ return true;
+ // Suppress by module name.
+ if (const char *Module = Symbolizer::GetOrInit()->GetModuleNameForPc(PC)) {
+ if (suppression_ctx->Match(Module, SuppType, &s))
+ return true;
+ }
+ // Suppress by function or source file name from debug info.
+ SymbolizedStackHolder Stack(Symbolizer::GetOrInit()->SymbolizePC(PC));
+ const AddressInfo &AI = Stack.get()->info;
+ return suppression_ctx->Match(AI.function, SuppType, &s) ||
+ suppression_ctx->Match(AI.file, SuppType, &s);
+}
+
#endif // CAN_SANITIZE_UB
diff --git a/contrib/compiler-rt/lib/ubsan/ubsan_diag.h b/contrib/compiler-rt/lib/ubsan/ubsan_diag.h
index 615a646d9419..3edb67a03c1f 100644
--- a/contrib/compiler-rt/lib/ubsan/ubsan_diag.h
+++ b/contrib/compiler-rt/lib/ubsan/ubsan_diag.h
@@ -211,17 +211,25 @@ public:
};
struct ReportOptions {
- /// If DieAfterReport is specified, UBSan will terminate the program after the
- /// report is printed.
- bool DieAfterReport;
+ // If FromUnrecoverableHandler is specified, UBSan runtime handler is not
+ // expected to return.
+ bool FromUnrecoverableHandler;
/// pc/bp are used to unwind the stack trace.
uptr pc;
uptr bp;
};
-#define GET_REPORT_OPTIONS(die_after_report) \
+enum class ErrorType {
+#define UBSAN_CHECK(Name, SummaryKind, FSanitizeFlagName) Name,
+#include "ubsan_checks.inc"
+#undef UBSAN_CHECK
+};
+
+bool ignoreReport(SourceLocation SLoc, ReportOptions Opts, ErrorType ET);
+
+#define GET_REPORT_OPTIONS(unrecoverable_handler) \
GET_CALLER_PC_BP; \
- ReportOptions Opts = {die_after_report, pc, bp}
+ ReportOptions Opts = {unrecoverable_handler, pc, bp}
/// \brief Instantiate this class before printing diagnostics in the error
/// report. This class ensures that reports from different threads and from
@@ -229,14 +237,18 @@ struct ReportOptions {
class ScopedReport {
ReportOptions Opts;
Location SummaryLoc;
+ ErrorType Type;
public:
- ScopedReport(ReportOptions Opts, Location SummaryLoc);
+ ScopedReport(ReportOptions Opts, Location SummaryLoc, ErrorType Type);
~ScopedReport();
};
void InitializeSuppressions();
bool IsVptrCheckSuppressed(const char *TypeName);
+// Sometimes UBSan runtime can know filename from handlers arguments, even if
+// debug info is missing.
+bool IsPCSuppressed(ErrorType ET, uptr PC, const char *Filename);
} // namespace __ubsan
diff --git a/contrib/compiler-rt/lib/ubsan/ubsan_flags.cc b/contrib/compiler-rt/lib/ubsan/ubsan_flags.cc
index 6e5ad4c7967c..20087b968782 100644
--- a/contrib/compiler-rt/lib/ubsan/ubsan_flags.cc
+++ b/contrib/compiler-rt/lib/ubsan/ubsan_flags.cc
@@ -60,6 +60,9 @@ void InitializeFlags() {
// Override from environment variable.
parser.ParseString(GetEnv("UBSAN_OPTIONS"));
SetVerbosity(common_flags()->verbosity);
+ if (Verbosity()) ReportUnrecognizedFlags();
+
+ if (common_flags()->help) parser.PrintFlagDescriptions();
}
} // namespace __ubsan
diff --git a/contrib/compiler-rt/lib/ubsan/ubsan_flags.inc b/contrib/compiler-rt/lib/ubsan/ubsan_flags.inc
index 9ca31d13a9b6..d171a98e1730 100644
--- a/contrib/compiler-rt/lib/ubsan/ubsan_flags.inc
+++ b/contrib/compiler-rt/lib/ubsan/ubsan_flags.inc
@@ -22,4 +22,5 @@ UBSAN_FLAG(bool, halt_on_error, false,
UBSAN_FLAG(bool, print_stacktrace, false,
"Include full stacktrace into an error report")
UBSAN_FLAG(const char *, suppressions, "", "Suppressions file name.")
-
+UBSAN_FLAG(bool, report_error_type, false,
+ "Print specific error type instead of 'undefined-behavior' in summary.")
diff --git a/contrib/compiler-rt/lib/ubsan/ubsan_handlers.cc b/contrib/compiler-rt/lib/ubsan/ubsan_handlers.cc
index a65b2f5e3fc7..5d82e9afcd09 100644
--- a/contrib/compiler-rt/lib/ubsan/ubsan_handlers.cc
+++ b/contrib/compiler-rt/lib/ubsan/ubsan_handlers.cc
@@ -21,17 +21,20 @@
using namespace __sanitizer;
using namespace __ubsan;
-static bool ignoreReport(SourceLocation SLoc, ReportOptions Opts) {
- // If source location is already acquired, we don't need to print an error
- // report for the second time. However, if we're in an unrecoverable handler,
- // it's possible that location was required by concurrently running thread.
- // In this case, we should continue the execution to ensure that any of
- // threads will grab the report mutex and print the report before
- // crashing the program.
- return SLoc.isDisabled() && !Opts.DieAfterReport;
+namespace __ubsan {
+bool ignoreReport(SourceLocation SLoc, ReportOptions Opts, ErrorType ET) {
+ // We are not allowed to skip error report: if we are in unrecoverable
+ // handler, we have to terminate the program right now, and therefore
+ // have to print some diagnostic.
+ //
+ // Even if source location is disabled, it doesn't mean that we have
+ // already report an error to the user: some concurrently running
+ // thread could have acquired it, but not yet printed the report.
+ if (Opts.FromUnrecoverableHandler)
+ return false;
+ return SLoc.isDisabled() || IsPCSuppressed(ET, Opts.pc, SLoc.getFilename());
}
-namespace __ubsan {
const char *TypeCheckKinds[] = {
"load of", "store to", "reference binding to", "member access within",
"member call on", "constructor call on", "downcast of", "downcast of",
@@ -41,8 +44,18 @@ const char *TypeCheckKinds[] = {
static void handleTypeMismatchImpl(TypeMismatchData *Data, ValueHandle Pointer,
ReportOptions Opts) {
Location Loc = Data->Loc.acquire();
- // Use the SourceLocation from Data to track deduplication, even if 'invalid'
- if (ignoreReport(Loc.getSourceLocation(), Opts))
+
+ ErrorType ET;
+ if (!Pointer)
+ ET = ErrorType::NullPointerUse;
+ else if (Data->Alignment && (Pointer & (Data->Alignment - 1)))
+ ET = ErrorType::MisalignedPointerUse;
+ else
+ ET = ErrorType::InsufficientObjectSize;
+
+ // Use the SourceLocation from Data to track deduplication, even if it's
+ // invalid.
+ if (ignoreReport(Loc.getSourceLocation(), Opts, ET))
return;
SymbolizedStackHolder FallbackLoc;
@@ -51,20 +64,28 @@ static void handleTypeMismatchImpl(TypeMismatchData *Data, ValueHandle Pointer,
Loc = FallbackLoc;
}
- ScopedReport R(Opts, Loc);
+ ScopedReport R(Opts, Loc, ET);
- if (!Pointer)
+ switch (ET) {
+ case ErrorType::NullPointerUse:
Diag(Loc, DL_Error, "%0 null pointer of type %1")
- << TypeCheckKinds[Data->TypeCheckKind] << Data->Type;
- else if (Data->Alignment && (Pointer & (Data->Alignment - 1)))
+ << TypeCheckKinds[Data->TypeCheckKind] << Data->Type;
+ break;
+ case ErrorType::MisalignedPointerUse:
Diag(Loc, DL_Error, "%0 misaligned address %1 for type %3, "
"which requires %2 byte alignment")
- << TypeCheckKinds[Data->TypeCheckKind] << (void*)Pointer
- << Data->Alignment << Data->Type;
- else
+ << TypeCheckKinds[Data->TypeCheckKind] << (void *)Pointer
+ << Data->Alignment << Data->Type;
+ break;
+ case ErrorType::InsufficientObjectSize:
Diag(Loc, DL_Error, "%0 address %1 with insufficient space "
"for an object of type %2")
- << TypeCheckKinds[Data->TypeCheckKind] << (void*)Pointer << Data->Type;
+ << TypeCheckKinds[Data->TypeCheckKind] << (void *)Pointer << Data->Type;
+ break;
+ default:
+ UNREACHABLE("unexpected error type!");
+ }
+
if (Pointer)
Diag(Pointer, DL_Note, "pointer points here");
}
@@ -87,23 +108,28 @@ static void handleIntegerOverflowImpl(OverflowData *Data, ValueHandle LHS,
const char *Operator, T RHS,
ReportOptions Opts) {
SourceLocation Loc = Data->Loc.acquire();
- if (ignoreReport(Loc, Opts))
+ bool IsSigned = Data->Type.isSignedIntegerTy();
+ ErrorType ET = IsSigned ? ErrorType::SignedIntegerOverflow
+ : ErrorType::UnsignedIntegerOverflow;
+
+ if (ignoreReport(Loc, Opts, ET))
return;
- ScopedReport R(Opts, Loc);
+ ScopedReport R(Opts, Loc, ET);
Diag(Loc, DL_Error, "%0 integer overflow: "
"%1 %2 %3 cannot be represented in type %4")
- << (Data->Type.isSignedIntegerTy() ? "signed" : "unsigned")
+ << (IsSigned ? "signed" : "unsigned")
<< Value(Data->Type, LHS) << Operator << RHS << Data->Type;
}
-#define UBSAN_OVERFLOW_HANDLER(handler_name, op, abort) \
+#define UBSAN_OVERFLOW_HANDLER(handler_name, op, unrecoverable) \
void __ubsan::handler_name(OverflowData *Data, ValueHandle LHS, \
ValueHandle RHS) { \
- GET_REPORT_OPTIONS(abort); \
+ GET_REPORT_OPTIONS(unrecoverable); \
handleIntegerOverflowImpl(Data, LHS, op, Value(Data->Type, RHS), Opts); \
- if (abort) Die(); \
+ if (unrecoverable) \
+ Die(); \
}
UBSAN_OVERFLOW_HANDLER(__ubsan_handle_add_overflow, "+", false)
@@ -116,20 +142,23 @@ UBSAN_OVERFLOW_HANDLER(__ubsan_handle_mul_overflow_abort, "*", true)
static void handleNegateOverflowImpl(OverflowData *Data, ValueHandle OldVal,
ReportOptions Opts) {
SourceLocation Loc = Data->Loc.acquire();
- if (ignoreReport(Loc, Opts))
+ bool IsSigned = Data->Type.isSignedIntegerTy();
+ ErrorType ET = IsSigned ? ErrorType::SignedIntegerOverflow
+ : ErrorType::UnsignedIntegerOverflow;
+
+ if (ignoreReport(Loc, Opts, ET))
return;
- ScopedReport R(Opts, Loc);
+ ScopedReport R(Opts, Loc, ET);
- if (Data->Type.isSignedIntegerTy())
+ if (IsSigned)
Diag(Loc, DL_Error,
"negation of %0 cannot be represented in type %1; "
"cast to an unsigned type to negate this value to itself")
- << Value(Data->Type, OldVal) << Data->Type;
+ << Value(Data->Type, OldVal) << Data->Type;
else
- Diag(Loc, DL_Error,
- "negation of %0 cannot be represented in type %1")
- << Value(Data->Type, OldVal) << Data->Type;
+ Diag(Loc, DL_Error, "negation of %0 cannot be represented in type %1")
+ << Value(Data->Type, OldVal) << Data->Type;
}
void __ubsan::__ubsan_handle_negate_overflow(OverflowData *Data,
@@ -147,19 +176,31 @@ void __ubsan::__ubsan_handle_negate_overflow_abort(OverflowData *Data,
static void handleDivremOverflowImpl(OverflowData *Data, ValueHandle LHS,
ValueHandle RHS, ReportOptions Opts) {
SourceLocation Loc = Data->Loc.acquire();
- if (ignoreReport(Loc, Opts))
- return;
-
- ScopedReport R(Opts, Loc);
-
Value LHSVal(Data->Type, LHS);
Value RHSVal(Data->Type, RHS);
+
+ ErrorType ET;
if (RHSVal.isMinusOne())
- Diag(Loc, DL_Error,
- "division of %0 by -1 cannot be represented in type %1")
- << LHSVal << Data->Type;
+ ET = ErrorType::SignedIntegerOverflow;
+ else if (Data->Type.isIntegerTy())
+ ET = ErrorType::IntegerDivideByZero;
else
+ ET = ErrorType::FloatDivideByZero;
+
+ if (ignoreReport(Loc, Opts, ET))
+ return;
+
+ ScopedReport R(Opts, Loc, ET);
+
+ switch (ET) {
+ case ErrorType::SignedIntegerOverflow:
+ Diag(Loc, DL_Error, "division of %0 by -1 cannot be represented in type %1")
+ << LHSVal << Data->Type;
+ break;
+ default:
Diag(Loc, DL_Error, "division by zero");
+ break;
+ }
}
void __ubsan::__ubsan_handle_divrem_overflow(OverflowData *Data,
@@ -179,25 +220,35 @@ static void handleShiftOutOfBoundsImpl(ShiftOutOfBoundsData *Data,
ValueHandle LHS, ValueHandle RHS,
ReportOptions Opts) {
SourceLocation Loc = Data->Loc.acquire();
- if (ignoreReport(Loc, Opts))
- return;
-
- ScopedReport R(Opts, Loc);
-
Value LHSVal(Data->LHSType, LHS);
Value RHSVal(Data->RHSType, RHS);
- if (RHSVal.isNegative())
- Diag(Loc, DL_Error, "shift exponent %0 is negative") << RHSVal;
- else if (RHSVal.getPositiveIntValue() >= Data->LHSType.getIntegerBitWidth())
- Diag(Loc, DL_Error,
- "shift exponent %0 is too large for %1-bit type %2")
- << RHSVal << Data->LHSType.getIntegerBitWidth() << Data->LHSType;
- else if (LHSVal.isNegative())
- Diag(Loc, DL_Error, "left shift of negative value %0") << LHSVal;
+
+ ErrorType ET;
+ if (RHSVal.isNegative() ||
+ RHSVal.getPositiveIntValue() >= Data->LHSType.getIntegerBitWidth())
+ ET = ErrorType::InvalidShiftExponent;
else
- Diag(Loc, DL_Error,
- "left shift of %0 by %1 places cannot be represented in type %2")
- << LHSVal << RHSVal << Data->LHSType;
+ ET = ErrorType::InvalidShiftBase;
+
+ if (ignoreReport(Loc, Opts, ET))
+ return;
+
+ ScopedReport R(Opts, Loc, ET);
+
+ if (ET == ErrorType::InvalidShiftExponent) {
+ if (RHSVal.isNegative())
+ Diag(Loc, DL_Error, "shift exponent %0 is negative") << RHSVal;
+ else
+ Diag(Loc, DL_Error, "shift exponent %0 is too large for %1-bit type %2")
+ << RHSVal << Data->LHSType.getIntegerBitWidth() << Data->LHSType;
+ } else {
+ if (LHSVal.isNegative())
+ Diag(Loc, DL_Error, "left shift of negative value %0") << LHSVal;
+ else
+ Diag(Loc, DL_Error,
+ "left shift of %0 by %1 places cannot be represented in type %2")
+ << LHSVal << RHSVal << Data->LHSType;
+ }
}
void __ubsan::__ubsan_handle_shift_out_of_bounds(ShiftOutOfBoundsData *Data,
@@ -218,10 +269,12 @@ void __ubsan::__ubsan_handle_shift_out_of_bounds_abort(
static void handleOutOfBoundsImpl(OutOfBoundsData *Data, ValueHandle Index,
ReportOptions Opts) {
SourceLocation Loc = Data->Loc.acquire();
- if (ignoreReport(Loc, Opts))
+ ErrorType ET = ErrorType::OutOfBoundsIndex;
+
+ if (ignoreReport(Loc, Opts, ET))
return;
- ScopedReport R(Opts, Loc);
+ ScopedReport R(Opts, Loc, ET);
Value IndexVal(Data->IndexType, Index);
Diag(Loc, DL_Error, "index %0 out of bounds for type %1")
@@ -242,7 +295,7 @@ void __ubsan::__ubsan_handle_out_of_bounds_abort(OutOfBoundsData *Data,
static void handleBuiltinUnreachableImpl(UnreachableData *Data,
ReportOptions Opts) {
- ScopedReport R(Opts, Data->Loc);
+ ScopedReport R(Opts, Data->Loc, ErrorType::UnreachableCall);
Diag(Data->Loc, DL_Error, "execution reached a __builtin_unreachable() call");
}
@@ -253,7 +306,7 @@ void __ubsan::__ubsan_handle_builtin_unreachable(UnreachableData *Data) {
}
static void handleMissingReturnImpl(UnreachableData *Data, ReportOptions Opts) {
- ScopedReport R(Opts, Data->Loc);
+ ScopedReport R(Opts, Data->Loc, ErrorType::MissingReturn);
Diag(Data->Loc, DL_Error,
"execution reached the end of a value-returning function "
"without returning a value");
@@ -268,10 +321,12 @@ void __ubsan::__ubsan_handle_missing_return(UnreachableData *Data) {
static void handleVLABoundNotPositive(VLABoundData *Data, ValueHandle Bound,
ReportOptions Opts) {
SourceLocation Loc = Data->Loc.acquire();
- if (ignoreReport(Loc, Opts))
+ ErrorType ET = ErrorType::NonPositiveVLAIndex;
+
+ if (ignoreReport(Loc, Opts, ET))
return;
- ScopedReport R(Opts, Loc);
+ ScopedReport R(Opts, Loc, ET);
Diag(Loc, DL_Error, "variable length array bound evaluates to "
"non-positive value %0")
@@ -290,26 +345,60 @@ void __ubsan::__ubsan_handle_vla_bound_not_positive_abort(VLABoundData *Data,
Die();
}
-static void handleFloatCastOverflow(FloatCastOverflowData *Data,
- ValueHandle From, ReportOptions Opts) {
- // TODO: Add deduplication once a SourceLocation is generated for this check.
- SymbolizedStackHolder CallerLoc(getCallerLocation(Opts.pc));
- Location Loc = CallerLoc;
- ScopedReport R(Opts, Loc);
+static bool looksLikeFloatCastOverflowDataV1(void *Data) {
+ // First field is either a pointer to filename or a pointer to a
+ // TypeDescriptor.
+ u8 *FilenameOrTypeDescriptor;
+ internal_memcpy(&FilenameOrTypeDescriptor, Data,
+ sizeof(FilenameOrTypeDescriptor));
+
+ // Heuristic: For float_cast_overflow, the TypeKind will be either TK_Integer
+ // (0x0), TK_Float (0x1) or TK_Unknown (0xff). If both types are known,
+ // adding both bytes will be 0 or 1 (for BE or LE). If it were a filename,
+ // adding two printable characters will not yield such a value. Otherwise,
+ // if one of them is 0xff, this is most likely TK_Unknown type descriptor.
+ u16 MaybeFromTypeKind =
+ FilenameOrTypeDescriptor[0] + FilenameOrTypeDescriptor[1];
+ return MaybeFromTypeKind < 2 || FilenameOrTypeDescriptor[0] == 0xff ||
+ FilenameOrTypeDescriptor[1] == 0xff;
+}
+
+static void handleFloatCastOverflow(void *DataPtr, ValueHandle From,
+ ReportOptions Opts) {
+ SymbolizedStackHolder CallerLoc;
+ Location Loc;
+ const TypeDescriptor *FromType, *ToType;
+ ErrorType ET = ErrorType::FloatCastOverflow;
+
+ if (looksLikeFloatCastOverflowDataV1(DataPtr)) {
+ auto Data = reinterpret_cast<FloatCastOverflowData *>(DataPtr);
+ CallerLoc.reset(getCallerLocation(Opts.pc));
+ Loc = CallerLoc;
+ FromType = &Data->FromType;
+ ToType = &Data->ToType;
+ } else {
+ auto Data = reinterpret_cast<FloatCastOverflowDataV2 *>(DataPtr);
+ SourceLocation SLoc = Data->Loc.acquire();
+ if (ignoreReport(SLoc, Opts, ET))
+ return;
+ Loc = SLoc;
+ FromType = &Data->FromType;
+ ToType = &Data->ToType;
+ }
+
+ ScopedReport R(Opts, Loc, ET);
Diag(Loc, DL_Error,
"value %0 is outside the range of representable values of type %2")
- << Value(Data->FromType, From) << Data->FromType << Data->ToType;
+ << Value(*FromType, From) << *FromType << *ToType;
}
-void __ubsan::__ubsan_handle_float_cast_overflow(FloatCastOverflowData *Data,
- ValueHandle From) {
+void __ubsan::__ubsan_handle_float_cast_overflow(void *Data, ValueHandle From) {
GET_REPORT_OPTIONS(false);
handleFloatCastOverflow(Data, From, Opts);
}
-void
-__ubsan::__ubsan_handle_float_cast_overflow_abort(FloatCastOverflowData *Data,
- ValueHandle From) {
+void __ubsan::__ubsan_handle_float_cast_overflow_abort(void *Data,
+ ValueHandle From) {
GET_REPORT_OPTIONS(true);
handleFloatCastOverflow(Data, From, Opts);
Die();
@@ -318,10 +407,16 @@ __ubsan::__ubsan_handle_float_cast_overflow_abort(FloatCastOverflowData *Data,
static void handleLoadInvalidValue(InvalidValueData *Data, ValueHandle Val,
ReportOptions Opts) {
SourceLocation Loc = Data->Loc.acquire();
- if (ignoreReport(Loc, Opts))
+ // This check could be more precise if we used different handlers for
+ // -fsanitize=bool and -fsanitize=enum.
+ bool IsBool = (0 == internal_strcmp(Data->Type.getTypeName(), "'bool'"));
+ ErrorType ET =
+ IsBool ? ErrorType::InvalidBoolLoad : ErrorType::InvalidEnumLoad;
+
+ if (ignoreReport(Loc, Opts, ET))
return;
- ScopedReport R(Opts, Loc);
+ ScopedReport R(Opts, Loc, ET);
Diag(Loc, DL_Error,
"load of value %0, which is not a valid value for type %1")
@@ -344,10 +439,12 @@ static void handleFunctionTypeMismatch(FunctionTypeMismatchData *Data,
ValueHandle Function,
ReportOptions Opts) {
SourceLocation CallLoc = Data->Loc.acquire();
- if (ignoreReport(CallLoc, Opts))
+ ErrorType ET = ErrorType::FunctionTypeMismatch;
+
+ if (ignoreReport(CallLoc, Opts, ET))
return;
- ScopedReport R(Opts, CallLoc);
+ ScopedReport R(Opts, CallLoc, ET);
SymbolizedStackHolder FLoc(getSymbolizedLocation(Function));
const char *FName = FLoc.get()->info.function;
@@ -376,10 +473,12 @@ void __ubsan::__ubsan_handle_function_type_mismatch_abort(
static void handleNonNullReturn(NonNullReturnData *Data, ReportOptions Opts) {
SourceLocation Loc = Data->Loc.acquire();
- if (ignoreReport(Loc, Opts))
+ ErrorType ET = ErrorType::InvalidNullReturn;
+
+ if (ignoreReport(Loc, Opts, ET))
return;
- ScopedReport R(Opts, Loc);
+ ScopedReport R(Opts, Loc, ET);
Diag(Loc, DL_Error, "null pointer returned from function declared to never "
"return null");
@@ -400,10 +499,12 @@ void __ubsan::__ubsan_handle_nonnull_return_abort(NonNullReturnData *Data) {
static void handleNonNullArg(NonNullArgData *Data, ReportOptions Opts) {
SourceLocation Loc = Data->Loc.acquire();
- if (ignoreReport(Loc, Opts))
+ ErrorType ET = ErrorType::InvalidNullArgument;
+
+ if (ignoreReport(Loc, Opts, ET))
return;
- ScopedReport R(Opts, Loc);
+ ScopedReport R(Opts, Loc, ET);
Diag(Loc, DL_Error, "null pointer passed as argument %0, which is declared to "
"never be null") << Data->ArgIndex;
@@ -422,4 +523,38 @@ void __ubsan::__ubsan_handle_nonnull_arg_abort(NonNullArgData *Data) {
Die();
}
+static void handleCFIBadIcall(CFIBadIcallData *Data, ValueHandle Function,
+ ReportOptions Opts) {
+ SourceLocation Loc = Data->Loc.acquire();
+ ErrorType ET = ErrorType::CFIBadType;
+
+ if (ignoreReport(Loc, Opts, ET))
+ return;
+
+ ScopedReport R(Opts, Loc, ET);
+
+ Diag(Loc, DL_Error, "control flow integrity check for type %0 failed during "
+ "indirect function call")
+ << Data->Type;
+
+ SymbolizedStackHolder FLoc(getSymbolizedLocation(Function));
+ const char *FName = FLoc.get()->info.function;
+ if (!FName)
+ FName = "(unknown)";
+ Diag(FLoc, DL_Note, "%0 defined here") << FName;
+}
+
+void __ubsan::__ubsan_handle_cfi_bad_icall(CFIBadIcallData *Data,
+ ValueHandle Function) {
+ GET_REPORT_OPTIONS(false);
+ handleCFIBadIcall(Data, Function, Opts);
+}
+
+void __ubsan::__ubsan_handle_cfi_bad_icall_abort(CFIBadIcallData *Data,
+ ValueHandle Function) {
+ GET_REPORT_OPTIONS(true);
+ handleCFIBadIcall(Data, Function, Opts);
+ Die();
+}
+
#endif // CAN_SANITIZE_UB
diff --git a/contrib/compiler-rt/lib/ubsan/ubsan_handlers.h b/contrib/compiler-rt/lib/ubsan/ubsan_handlers.h
index 87149f259607..6f309cf9aaa9 100644
--- a/contrib/compiler-rt/lib/ubsan/ubsan_handlers.h
+++ b/contrib/compiler-rt/lib/ubsan/ubsan_handlers.h
@@ -97,14 +97,22 @@ struct VLABoundData {
/// \brief Handle a VLA with a non-positive bound.
RECOVERABLE(vla_bound_not_positive, VLABoundData *Data, ValueHandle Bound)
+// Keeping this around for binary compatibility with (sanitized) programs
+// compiled with older compilers.
struct FloatCastOverflowData {
- // FIXME: SourceLocation Loc;
const TypeDescriptor &FromType;
const TypeDescriptor &ToType;
};
-/// \brief Handle overflow in a conversion to or from a floating-point type.
-RECOVERABLE(float_cast_overflow, FloatCastOverflowData *Data, ValueHandle From)
+struct FloatCastOverflowDataV2 {
+ SourceLocation Loc;
+ const TypeDescriptor &FromType;
+ const TypeDescriptor &ToType;
+};
+
+/// Handle overflow in a conversion to or from a floating-point type.
+/// void *Data is one of FloatCastOverflowData* or FloatCastOverflowDataV2*
+RECOVERABLE(float_cast_overflow, void *Data, ValueHandle From)
struct InvalidValueData {
SourceLocation Loc;
@@ -140,6 +148,14 @@ struct NonNullArgData {
/// \brief Handle passing null pointer to function with nonnull attribute.
RECOVERABLE(nonnull_arg, NonNullArgData *Data)
+struct CFIBadIcallData {
+ SourceLocation Loc;
+ const TypeDescriptor &Type;
+};
+
+/// \brief Handle control flow integrity failure for indirect function calls.
+RECOVERABLE(cfi_bad_icall, CFIBadIcallData *Data, ValueHandle Function)
+
}
#endif // UBSAN_HANDLERS_H
diff --git a/contrib/compiler-rt/lib/ubsan/ubsan_handlers_cxx.cc b/contrib/compiler-rt/lib/ubsan/ubsan_handlers_cxx.cc
index 6984a963deb6..3e81be67163b 100644
--- a/contrib/compiler-rt/lib/ubsan/ubsan_handlers_cxx.cc
+++ b/contrib/compiler-rt/lib/ubsan/ubsan_handlers_cxx.cc
@@ -29,23 +29,25 @@ namespace __ubsan {
extern const char *TypeCheckKinds[];
}
-static void HandleDynamicTypeCacheMiss(
+// Returns true if UBSan has printed an error report.
+static bool HandleDynamicTypeCacheMiss(
DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash,
ReportOptions Opts) {
if (checkDynamicType((void*)Pointer, Data->TypeInfo, Hash))
// Just a cache miss. The type matches after all.
- return;
+ return false;
// Check if error report should be suppressed.
DynamicTypeInfo DTI = getDynamicTypeInfoFromObject((void*)Pointer);
if (DTI.isValid() && IsVptrCheckSuppressed(DTI.getMostDerivedTypeName()))
- return;
+ return false;
SourceLocation Loc = Data->Loc.acquire();
- if (Loc.isDisabled())
- return;
+ ErrorType ET = ErrorType::DynamicTypeMismatch;
+ if (ignoreReport(Loc, Opts, ET))
+ return false;
- ScopedReport R(Opts, Loc);
+ ScopedReport R(Opts, Loc, ET);
Diag(Loc, DL_Error,
"%0 address %1 which does not point to an object of type %2")
@@ -69,6 +71,7 @@ static void HandleDynamicTypeCacheMiss(
<< TypeName(DTI.getSubobjectTypeName())
<< Range(Pointer, Pointer + sizeof(uptr),
"vptr for %2 base class of %1");
+ return true;
}
void __ubsan::__ubsan_handle_dynamic_type_cache_miss(
@@ -78,14 +81,21 @@ void __ubsan::__ubsan_handle_dynamic_type_cache_miss(
}
void __ubsan::__ubsan_handle_dynamic_type_cache_miss_abort(
DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash) {
- GET_REPORT_OPTIONS(true);
- HandleDynamicTypeCacheMiss(Data, Pointer, Hash, Opts);
+ // Note: -fsanitize=vptr is always recoverable.
+ GET_REPORT_OPTIONS(false);
+ if (HandleDynamicTypeCacheMiss(Data, Pointer, Hash, Opts))
+ Die();
}
static void HandleCFIBadType(CFIBadTypeData *Data, ValueHandle Vtable,
ReportOptions Opts) {
SourceLocation Loc = Data->Loc.acquire();
- ScopedReport R(Opts, Loc);
+ ErrorType ET = ErrorType::CFIBadType;
+
+ if (ignoreReport(Loc, Opts, ET))
+ return;
+
+ ScopedReport R(Opts, Loc, ET);
DynamicTypeInfo DTI = getDynamicTypeInfoFromVtable((void*)Vtable);
static const char *TypeCheckKinds[] = {
@@ -117,6 +127,7 @@ void __ubsan::__ubsan_handle_cfi_bad_type_abort(CFIBadTypeData *Data,
ValueHandle Vtable) {
GET_REPORT_OPTIONS(true);
HandleCFIBadType(Data, Vtable, Opts);
+ Die();
}
#endif // CAN_SANITIZE_UB