aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2015-12-30 11:52:19 +0000
committerDimitry Andric <dim@FreeBSD.org>2015-12-30 11:52:19 +0000
commit5c909fa013fc285f010a95e8d387e0ef3412da9c (patch)
tree1059d068ad281f4776ff44cd414574f99a460023 /lib
parentf31bcc68c72371a2bf63aead9f3373a1ff2053b6 (diff)
downloadsrc-5c909fa013fc285f010a95e8d387e0ef3412da9c.tar.gz
src-5c909fa013fc285f010a95e8d387e0ef3412da9c.zip
Vendor import of compiler-rt trunk r256633:vendor/compiler-rt/compiler-rt-trunk-r256633
Notes
Notes: svn path=/vendor/compiler-rt/dist/; revision=292925 svn path=/vendor/compiler-rt/compiler-rt-trunk-r256633/; revision=292926; tag=vendor/compiler-rt/compiler-rt-trunk-r256633
Diffstat (limited to 'lib')
-rw-r--r--lib/CMakeLists.txt60
-rw-r--r--lib/asan/.clang-format1
-rw-r--r--lib/asan/CMakeLists.txt149
-rw-r--r--lib/asan/README.txt2
-rw-r--r--lib/asan/asan_activation.cc9
-rw-r--r--lib/asan/asan_allocator.cc22
-rw-r--r--lib/asan/asan_allocator.h5
-rw-r--r--lib/asan/asan_debugging.cc4
-rw-r--r--lib/asan/asan_fake_stack.cc22
-rw-r--r--lib/asan/asan_flags.cc9
-rw-r--r--lib/asan/asan_flags.inc24
-rw-r--r--lib/asan/asan_globals.cc5
-rw-r--r--lib/asan/asan_init_version.h4
-rw-r--r--lib/asan/asan_interceptors.cc74
-rw-r--r--lib/asan/asan_interceptors.h6
-rw-r--r--lib/asan/asan_interface_internal.h23
-rw-r--r--lib/asan/asan_internal.h7
-rw-r--r--lib/asan/asan_linux.cc23
-rw-r--r--lib/asan/asan_mac.cc197
-rw-r--r--lib/asan/asan_malloc_linux.cc21
-rw-r--r--lib/asan/asan_malloc_mac.cc371
-rw-r--r--lib/asan/asan_mapping.h33
-rw-r--r--lib/asan/asan_new_delete.cc10
-rw-r--r--lib/asan/asan_poisoning.cc29
-rw-r--r--lib/asan/asan_posix.cc10
-rw-r--r--lib/asan/asan_report.cc229
-rw-r--r--lib/asan/asan_report.h67
-rw-r--r--lib/asan/asan_rtl.cc152
-rw-r--r--lib/asan/asan_stack.h9
-rw-r--r--lib/asan/asan_thread.cc21
-rw-r--r--lib/asan/asan_thread.h13
-rw-r--r--lib/asan/asan_win.cc20
-rw-r--r--lib/asan/asan_win_dll_thunk.cc29
-rw-r--r--lib/asan/asan_win_dynamic_runtime_thunk.cc2
-rwxr-xr-xlib/asan/scripts/asan_device_setup184
-rwxr-xr-xlib/asan/scripts/asan_symbolize.py28
-rw-r--r--lib/asan/tests/CMakeLists.txt11
-rw-r--r--lib/asan/tests/asan_asm_test.cc10
-rw-r--r--lib/asan/tests/asan_interface_test.cc10
-rw-r--r--lib/asan/tests/asan_mac_test.cc4
-rw-r--r--lib/asan/tests/asan_noinst_test.cc2
-rw-r--r--lib/asan/tests/asan_test.cc19
-rw-r--r--lib/asan/tests/asan_test_main.cc14
-rw-r--r--lib/builtins/CMakeLists.txt172
-rw-r--r--lib/builtins/Darwin-excludes/10.4-x86_64.txt35
-rw-r--r--lib/builtins/Darwin-excludes/10.4.txt96
-rw-r--r--lib/builtins/Darwin-excludes/CMakeLists.txt4
-rw-r--r--lib/builtins/Darwin-excludes/README.TXT11
-rw-r--r--lib/builtins/Darwin-excludes/ios-armv7.txt57
-rw-r--r--lib/builtins/Darwin-excludes/ios-armv7s.txt57
-rw-r--r--lib/builtins/Darwin-excludes/ios.txt1
-rw-r--r--lib/builtins/Darwin-excludes/ios6-armv7.txt120
-rw-r--r--lib/builtins/Darwin-excludes/ios6-armv7s.txt120
-rw-r--r--lib/builtins/Darwin-excludes/ios7-arm64.txt16
-rw-r--r--lib/builtins/Darwin-excludes/iossim-i386.txt82
-rw-r--r--lib/builtins/Darwin-excludes/iossim-x86_64.txt12
-rw-r--r--lib/builtins/Darwin-excludes/iossim.txt1
-rw-r--r--lib/builtins/Darwin-excludes/osx-i386.txt82
-rw-r--r--lib/builtins/Darwin-excludes/osx-x86_64.txt12
-rw-r--r--lib/builtins/Darwin-excludes/osx.txt1
-rw-r--r--lib/builtins/README.txt4
-rw-r--r--lib/builtins/arm/aeabi_cdcmp.S96
-rw-r--r--lib/builtins/arm/aeabi_cdcmpeq_check_nan.c16
-rw-r--r--lib/builtins/arm/aeabi_cfcmp.S91
-rw-r--r--lib/builtins/arm/aeabi_cfcmpeq_check_nan.c16
-rw-r--r--lib/builtins/arm/aeabi_drsub.c19
-rw-r--r--lib/builtins/arm/aeabi_frsub.c19
-rw-r--r--lib/builtins/assembly.h9
-rw-r--r--lib/builtins/atomic.c14
-rw-r--r--lib/builtins/atomic_flag_clear.c10
-rw-r--r--lib/builtins/atomic_flag_clear_explicit.c10
-rw-r--r--lib/builtins/atomic_flag_test_and_set.c8
-rw-r--r--lib/builtins/atomic_flag_test_and_set_explicit.c8
-rw-r--r--lib/builtins/atomic_signal_fence.c8
-rw-r--r--lib/builtins/atomic_thread_fence.c8
-rw-r--r--lib/builtins/comparedf2.c5
-rw-r--r--lib/builtins/comparesf2.c5
-rw-r--r--lib/builtins/comparetf2.c5
-rw-r--r--lib/builtins/divdc3.c22
-rw-r--r--lib/builtins/divsc3.c22
-rw-r--r--lib/builtins/divtc3.c60
-rw-r--r--lib/builtins/divxc3.c22
-rw-r--r--lib/builtins/emutls.c183
-rw-r--r--lib/builtins/enable_execute_stack.c4
-rw-r--r--lib/builtins/extendhfsf2.c4
-rw-r--r--lib/builtins/fixunsdfdi.c4
-rw-r--r--lib/builtins/fixunssfdi.c4
-rw-r--r--lib/builtins/floatdidf.c4
-rw-r--r--lib/builtins/floatditf.c50
-rw-r--r--lib/builtins/floatsitf.c8
-rw-r--r--lib/builtins/floatundidf.c6
-rw-r--r--lib/builtins/floatunditf.c40
-rw-r--r--lib/builtins/fp_add_impl.inc2
-rw-r--r--lib/builtins/fp_extend.h6
-rw-r--r--lib/builtins/fp_extend_impl.inc2
-rw-r--r--lib/builtins/fp_fixint_impl.inc2
-rw-r--r--lib/builtins/fp_fixuint_impl.inc4
-rw-r--r--lib/builtins/fp_lib.h22
-rw-r--r--lib/builtins/fp_mul_impl.inc2
-rw-r--r--lib/builtins/fp_trunc.h4
-rw-r--r--lib/builtins/fp_trunc_impl.inc2
-rw-r--r--lib/builtins/gcc_personality_v0.c13
-rw-r--r--lib/builtins/i386/chkstk.S4
-rw-r--r--lib/builtins/i386/chkstk2.S40
-rw-r--r--lib/builtins/int_lib.h61
-rw-r--r--lib/builtins/int_math.h57
-rw-r--r--lib/builtins/int_types.h25
-rw-r--r--lib/builtins/int_util.c8
-rw-r--r--lib/builtins/int_util.h12
-rw-r--r--lib/builtins/macho_embedded/CMakeLists.txt4
-rw-r--r--lib/builtins/macho_embedded/arm.txt16
-rw-r--r--lib/builtins/macho_embedded/common.txt92
-rw-r--r--lib/builtins/macho_embedded/i386.txt7
-rw-r--r--lib/builtins/macho_embedded/thumb2-64.txt10
-rw-r--r--lib/builtins/macho_embedded/thumb2.txt14
-rw-r--r--lib/builtins/muldc3.c14
-rw-r--r--lib/builtins/mulsc3.c14
-rw-r--r--lib/builtins/multc3.c68
-rw-r--r--lib/builtins/mulxc3.c14
-rw-r--r--lib/builtins/ppc/DD.h43
-rw-r--r--lib/builtins/ppc/divtc3.c5
-rw-r--r--lib/builtins/ppc/multc3.c4
-rw-r--r--lib/builtins/subdf3.c1
-rw-r--r--lib/builtins/subsf3.c1
-rw-r--r--lib/builtins/truncdfhf2.c2
-rw-r--r--lib/builtins/truncsfhf2.c4
-rw-r--r--lib/builtins/x86_64/chkstk.S4
-rw-r--r--lib/builtins/x86_64/chkstk2.S42
-rw-r--r--lib/cfi/CMakeLists.txt40
-rw-r--r--lib/cfi/cfi.cc271
-rw-r--r--lib/cfi/cfi_blacklist.txt26
-rw-r--r--lib/dfsan/.clang-format1
-rw-r--r--lib/dfsan/CMakeLists.txt17
-rw-r--r--lib/dfsan/dfsan.cc97
-rw-r--r--lib/dfsan/dfsan.h7
-rw-r--r--lib/dfsan/dfsan_custom.cc48
-rw-r--r--lib/dfsan/dfsan_platform.h107
-rw-r--r--lib/dfsan/done_abilist.txt35
-rw-r--r--lib/interception/.clang-format1
-rw-r--r--lib/interception/interception_linux.h10
-rw-r--r--lib/interception/interception_win.cc60
-rw-r--r--lib/interception/interception_win.h4
-rw-r--r--lib/lsan/.clang-format1
-rw-r--r--lib/lsan/CMakeLists.txt8
-rw-r--r--lib/lsan/lsan.cc2
-rw-r--r--lib/lsan/lsan_allocator.cc14
-rw-r--r--lib/lsan/lsan_common.cc39
-rw-r--r--lib/lsan/lsan_common.h4
-rw-r--r--lib/lsan/lsan_common_linux.cc9
-rw-r--r--lib/lsan/lsan_flags.inc2
-rw-r--r--lib/lsan/lsan_interceptors.cc10
-rw-r--r--lib/lsan/lsan_thread.cc10
-rw-r--r--lib/msan/.clang-format1
-rw-r--r--lib/msan/CMakeLists.txt24
-rw-r--r--lib/msan/msan.cc44
-rw-r--r--lib/msan/msan.h82
-rw-r--r--lib/msan/msan_allocator.cc36
-rw-r--r--lib/msan/msan_chained_origin_depot.cc10
-rw-r--r--lib/msan/msan_flags.inc4
-rw-r--r--lib/msan/msan_interceptors.cc90
-rw-r--r--lib/msan/msan_interface_internal.h14
-rw-r--r--lib/msan/msan_linux.cc23
-rw-r--r--lib/msan/msan_new_delete.cc4
-rw-r--r--lib/msan/msan_thread.h2
-rw-r--r--lib/msan/tests/CMakeLists.txt39
-rw-r--r--lib/msan/tests/msan_test.cc26
-rw-r--r--lib/profile/CMakeLists.txt62
-rw-r--r--lib/profile/InstrProfData.inc735
-rw-r--r--lib/profile/InstrProfiling.c76
-rw-r--r--lib/profile/InstrProfiling.h77
-rw-r--r--lib/profile/InstrProfilingBuffer.c82
-rw-r--r--lib/profile/InstrProfilingFile.c98
-rw-r--r--lib/profile/InstrProfilingInternal.h78
-rw-r--r--lib/profile/InstrProfilingPlatformDarwin.c45
-rw-r--r--lib/profile/InstrProfilingPlatformLinux.c59
-rw-r--r--lib/profile/InstrProfilingPlatformOther.c48
-rw-r--r--lib/profile/InstrProfilingPort.h76
-rw-r--r--lib/profile/InstrProfilingRuntime.cc3
-rw-r--r--lib/profile/InstrProfilingUtil.c3
-rw-r--r--lib/profile/InstrProfilingValue.c180
-rw-r--r--lib/profile/InstrProfilingWriter.c175
-rw-r--r--lib/safestack/.clang-format1
-rw-r--r--lib/safestack/CMakeLists.txt20
-rw-r--r--lib/safestack/safestack.cc9
-rw-r--r--lib/sanitizer_common/.clang-format1
-rw-r--r--lib/sanitizer_common/CMakeLists.txt57
-rw-r--r--lib/sanitizer_common/Makefile.mk2
-rw-r--r--lib/sanitizer_common/sanitizer_addrhashmap.h8
-rw-r--r--lib/sanitizer_common/sanitizer_allocator.cc17
-rw-r--r--lib/sanitizer_common/sanitizer_allocator.h42
-rw-r--r--lib/sanitizer_common/sanitizer_allocator_internal.h10
-rw-r--r--lib/sanitizer_common/sanitizer_asm.h20
-rw-r--r--lib/sanitizer_common/sanitizer_atomic.h16
-rw-r--r--lib/sanitizer_common/sanitizer_common.cc190
-rw-r--r--lib/sanitizer_common/sanitizer_common.h79
-rw-r--r--lib/sanitizer_common/sanitizer_common_interceptors.inc684
-rw-r--r--lib/sanitizer_common/sanitizer_common_interceptors_format.inc19
-rwxr-xr-xlib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc4
-rw-r--r--lib/sanitizer_common/sanitizer_common_libcdep.cc27
-rw-r--r--lib/sanitizer_common/sanitizer_common_nolibc.cc26
-rw-r--r--lib/sanitizer_common/sanitizer_common_syscalls.inc4
-rw-r--r--lib/sanitizer_common/sanitizer_coverage_libcdep.cc45
-rw-r--r--lib/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc4
-rw-r--r--lib/sanitizer_common/sanitizer_deadlock_detector1.cc8
-rw-r--r--lib/sanitizer_common/sanitizer_deadlock_detector_interface.h6
-rw-r--r--lib/sanitizer_common/sanitizer_flag_parser.cc18
-rw-r--r--lib/sanitizer_common/sanitizer_flag_parser.h1
-rw-r--r--lib/sanitizer_common/sanitizer_flags.cc51
-rw-r--r--lib/sanitizer_common/sanitizer_flags.h2
-rw-r--r--lib/sanitizer_common/sanitizer_flags.inc26
-rw-r--r--lib/sanitizer_common/sanitizer_interface_internal.h5
-rw-r--r--lib/sanitizer_common/sanitizer_internal_defs.h13
-rw-r--r--lib/sanitizer_common/sanitizer_lfstack.h8
-rw-r--r--lib/sanitizer_common/sanitizer_libc.cc46
-rw-r--r--lib/sanitizer_common/sanitizer_libc.h9
-rw-r--r--lib/sanitizer_common/sanitizer_libignore.cc15
-rw-r--r--lib/sanitizer_common/sanitizer_linux.cc237
-rw-r--r--lib/sanitizer_common/sanitizer_linux.h3
-rw-r--r--lib/sanitizer_common/sanitizer_linux_libcdep.cc149
-rw-r--r--lib/sanitizer_common/sanitizer_list.h19
-rw-r--r--lib/sanitizer_common/sanitizer_mac.cc279
-rw-r--r--lib/sanitizer_common/sanitizer_mac.h12
-rw-r--r--lib/sanitizer_common/sanitizer_malloc_mac.inc329
-rw-r--r--lib/sanitizer_common/sanitizer_persistent_allocator.h5
-rw-r--r--lib/sanitizer_common/sanitizer_platform.h24
-rw-r--r--lib/sanitizer_common/sanitizer_platform_interceptors.h15
-rw-r--r--lib/sanitizer_common/sanitizer_platform_limits_posix.cc115
-rw-r--r--lib/sanitizer_common/sanitizer_platform_limits_posix.h19
-rw-r--r--lib/sanitizer_common/sanitizer_posix.cc98
-rw-r--r--lib/sanitizer_common/sanitizer_posix.h3
-rw-r--r--lib/sanitizer_common/sanitizer_posix_libcdep.cc61
-rw-r--r--lib/sanitizer_common/sanitizer_printf.cc10
-rw-r--r--lib/sanitizer_common/sanitizer_procmaps_common.cc13
-rw-r--r--lib/sanitizer_common/sanitizer_procmaps_linux.cc6
-rw-r--r--lib/sanitizer_common/sanitizer_procmaps_mac.cc2
-rw-r--r--lib/sanitizer_common/sanitizer_quarantine.h6
-rw-r--r--lib/sanitizer_common/sanitizer_stackdepot.cc4
-rw-r--r--lib/sanitizer_common/sanitizer_stackdepot.h7
-rw-r--r--lib/sanitizer_common/sanitizer_stackdepotbase.h10
-rw-r--r--lib/sanitizer_common/sanitizer_stacktrace.cc13
-rw-r--r--lib/sanitizer_common/sanitizer_stacktrace.h6
-rw-r--r--lib/sanitizer_common/sanitizer_stacktrace_printer.cc7
-rw-r--r--lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc102
-rw-r--r--lib/sanitizer_common/sanitizer_suppressions.cc19
-rw-r--r--lib/sanitizer_common/sanitizer_suppressions.h6
-rw-r--r--lib/sanitizer_common/sanitizer_symbolizer_internal.h62
-rw-r--r--lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.h1
-rw-r--r--lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc241
-rw-r--r--lib/sanitizer_common/sanitizer_symbolizer_mac.cc96
-rw-r--r--lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc319
-rw-r--r--lib/sanitizer_common/sanitizer_symbolizer_process_libcdep.cc229
-rw-r--r--lib/sanitizer_common/sanitizer_symbolizer_win.cc141
-rw-r--r--lib/sanitizer_common/sanitizer_symbolizer_win.h31
-rw-r--r--lib/sanitizer_common/sanitizer_syscall_linux_aarch64.inc138
-rw-r--r--lib/sanitizer_common/sanitizer_thread_registry.h8
-rw-r--r--lib/sanitizer_common/sanitizer_tls_get_addr.cc11
-rw-r--r--lib/sanitizer_common/sanitizer_win.cc177
-rwxr-xr-xlib/sanitizer_common/scripts/gen_dynamic_list.py2
-rw-r--r--lib/sanitizer_common/tests/CMakeLists.txt11
-rw-r--r--lib/sanitizer_common/tests/sanitizer_allocator_test.cc4
-rw-r--r--lib/sanitizer_common/tests/sanitizer_common_test.cc33
-rw-r--r--lib/sanitizer_common/tests/sanitizer_libc_test.cc108
-rw-r--r--lib/sanitizer_common/tests/sanitizer_linux_test.cc2
-rw-r--r--lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc2
-rw-r--r--lib/sanitizer_common/tests/sanitizer_suppressions_test.cc5
-rw-r--r--lib/sanitizer_common/tests/sanitizer_test_main.cc2
-rw-r--r--lib/tsan/.clang-format1
-rw-r--r--lib/tsan/CMakeLists.txt153
-rw-r--r--lib/tsan/Makefile.old109
-rwxr-xr-xlib/tsan/analyze_libtsan.sh23
-rwxr-xr-xlib/tsan/check_analyze.sh20
-rwxr-xr-xlib/tsan/check_memcpy.sh31
-rw-r--r--lib/tsan/dd/CMakeLists.txt18
-rwxr-xr-xlib/tsan/go/buildgo.sh4
-rw-r--r--lib/tsan/rtl/Makefile.old63
-rw-r--r--lib/tsan/rtl/tsan_clock.cc2
-rw-r--r--lib/tsan/rtl/tsan_defs.h5
-rw-r--r--lib/tsan/rtl/tsan_dense_alloc.h2
-rw-r--r--lib/tsan/rtl/tsan_flags.cc15
-rw-r--r--lib/tsan/rtl/tsan_flags.inc1
-rw-r--r--lib/tsan/rtl/tsan_interceptors.cc456
-rw-r--r--lib/tsan/rtl/tsan_interceptors.h20
-rw-r--r--lib/tsan/rtl/tsan_interceptors_mac.cc91
-rw-r--r--lib/tsan/rtl/tsan_interface_ann.cc34
-rw-r--r--lib/tsan/rtl/tsan_libdispatch_mac.cc284
-rw-r--r--lib/tsan/rtl/tsan_malloc_mac.cc65
-rw-r--r--lib/tsan/rtl/tsan_mman.cc16
-rw-r--r--lib/tsan/rtl/tsan_mman.h1
-rw-r--r--lib/tsan/rtl/tsan_mutex.cc2
-rw-r--r--lib/tsan/rtl/tsan_mutex.h2
-rw-r--r--lib/tsan/rtl/tsan_new_delete.cc16
-rw-r--r--lib/tsan/rtl/tsan_platform.h753
-rw-r--r--lib/tsan/rtl/tsan_platform_linux.cc132
-rw-r--r--lib/tsan/rtl/tsan_platform_mac.cc128
-rw-r--r--lib/tsan/rtl/tsan_platform_posix.cc151
-rw-r--r--lib/tsan/rtl/tsan_platform_windows.cc3
-rw-r--r--lib/tsan/rtl/tsan_ppc_regs.h96
-rw-r--r--lib/tsan/rtl/tsan_report.cc32
-rw-r--r--lib/tsan/rtl/tsan_rtl.cc30
-rw-r--r--lib/tsan/rtl/tsan_rtl.h28
-rw-r--r--lib/tsan/rtl/tsan_rtl_aarch64.S206
-rw-r--r--lib/tsan/rtl/tsan_rtl_amd64.S99
-rw-r--r--lib/tsan/rtl/tsan_rtl_mutex.cc2
-rw-r--r--lib/tsan/rtl/tsan_rtl_ppc64.S288
-rw-r--r--lib/tsan/rtl/tsan_rtl_report.cc189
-rw-r--r--lib/tsan/rtl/tsan_rtl_thread.cc8
-rw-r--r--lib/tsan/rtl/tsan_stat.cc3
-rw-r--r--lib/tsan/rtl/tsan_stat.h3
-rw-r--r--lib/tsan/rtl/tsan_suppressions.cc13
-rw-r--r--lib/tsan/rtl/tsan_symbolize.cc10
-rw-r--r--lib/tsan/rtl/tsan_sync.h6
-rw-r--r--lib/tsan/tests/CMakeLists.txt50
-rw-r--r--lib/tsan/tests/rtl/CMakeLists.txt4
-rw-r--r--lib/tsan/tests/rtl/tsan_posix.cc21
-rw-r--r--lib/tsan/tests/rtl/tsan_test.cc7
-rw-r--r--lib/tsan/tests/rtl/tsan_test_util.h10
-rw-r--r--lib/tsan/tests/rtl/tsan_test_util_posix.cc (renamed from lib/tsan/tests/rtl/tsan_test_util_linux.cc)113
-rw-r--r--lib/tsan/tests/unit/tsan_clock_test.cc7
-rw-r--r--lib/tsan/tests/unit/tsan_flags_test.cc6
-rw-r--r--lib/tsan/tests/unit/tsan_mman_test.cc4
-rw-r--r--lib/ubsan/CMakeLists.txt68
-rw-r--r--lib/ubsan/ubsan_checks.inc45
-rw-r--r--lib/ubsan/ubsan_diag.cc74
-rw-r--r--lib/ubsan/ubsan_diag.h24
-rw-r--r--lib/ubsan/ubsan_flags.cc3
-rw-r--r--lib/ubsan/ubsan_flags.inc3
-rw-r--r--lib/ubsan/ubsan_handlers.cc299
-rw-r--r--lib/ubsan/ubsan_handlers.h22
-rw-r--r--lib/ubsan/ubsan_handlers_cxx.cc29
329 files changed, 12260 insertions, 4089 deletions
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index 009c59f4d68e..4bc6f7a2d576 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -4,39 +4,47 @@
include(AddCompilerRT)
include(SanitizerUtils)
-if(COMPILER_RT_HAS_INTERCEPTION)
- add_subdirectory(interception)
+if(COMPILER_RT_BUILD_BUILTINS)
+ add_subdirectory(builtins)
endif()
-if(COMPILER_RT_HAS_SANITIZER_COMMON)
- add_subdirectory(sanitizer_common)
- add_subdirectory(lsan)
- add_subdirectory(ubsan)
-endif()
+if(COMPILER_RT_BUILD_SANITIZERS)
+ if(COMPILER_RT_HAS_INTERCEPTION)
+ add_subdirectory(interception)
+ endif()
-if(COMPILER_RT_HAS_ASAN)
- add_subdirectory(asan)
-endif()
+ if(COMPILER_RT_HAS_SANITIZER_COMMON)
+ add_subdirectory(sanitizer_common)
+ add_subdirectory(lsan)
+ add_subdirectory(ubsan)
+ endif()
-add_subdirectory(builtins)
+ if(COMPILER_RT_HAS_ASAN)
+ add_subdirectory(asan)
+ endif()
-if(COMPILER_RT_HAS_DFSAN)
- add_subdirectory(dfsan)
-endif()
+ if(COMPILER_RT_HAS_DFSAN)
+ add_subdirectory(dfsan)
+ endif()
-if(COMPILER_RT_HAS_MSAN)
- add_subdirectory(msan)
-endif()
+ if(COMPILER_RT_HAS_MSAN)
+ add_subdirectory(msan)
+ endif()
-if(COMPILER_RT_HAS_PROFILE)
- add_subdirectory(profile)
-endif()
+ if(COMPILER_RT_HAS_PROFILE)
+ add_subdirectory(profile)
+ endif()
-if(COMPILER_RT_HAS_TSAN)
- add_subdirectory(tsan)
- add_subdirectory(tsan/dd)
-endif()
+ if(COMPILER_RT_HAS_TSAN)
+ add_subdirectory(tsan)
+ add_subdirectory(tsan/dd)
+ endif()
+
+ if(COMPILER_RT_HAS_SAFESTACK)
+ add_subdirectory(safestack)
+ endif()
-if(COMPILER_RT_HAS_SAFESTACK)
- add_subdirectory(safestack)
+ if(COMPILER_RT_HAS_CFI)
+ add_subdirectory(cfi)
+ endif()
endif()
diff --git a/lib/asan/.clang-format b/lib/asan/.clang-format
new file mode 100644
index 000000000000..f6cb8ad931f5
--- /dev/null
+++ b/lib/asan/.clang-format
@@ -0,0 +1 @@
+BasedOnStyle: Google
diff --git a/lib/asan/CMakeLists.txt b/lib/asan/CMakeLists.txt
index 28611a8a4659..6716f48b22bd 100644
--- a/lib/asan/CMakeLists.txt
+++ b/lib/asan/CMakeLists.txt
@@ -70,18 +70,18 @@ append_list_if(COMPILER_RT_HAS_LIBRT rt ASAN_DYNAMIC_LIBS)
append_list_if(COMPILER_RT_HAS_LIBM m ASAN_DYNAMIC_LIBS)
append_list_if(COMPILER_RT_HAS_LIBPTHREAD pthread ASAN_DYNAMIC_LIBS)
append_list_if(COMPILER_RT_HAS_LIBSTDCXX stdc++ ASAN_DYNAMIC_LIBS)
-
-append_list_if(ANDROID log ASAN_DYNAMIC_LIBS)
+append_list_if(COMPILER_RT_HAS_LIBLOG log ASAN_DYNAMIC_LIBS)
# Compile ASan sources into an object library.
-if(APPLE)
- add_compiler_rt_object_libraries(RTAsan
- OS ${SANITIZER_COMMON_SUPPORTED_OS}
- ARCHS ${ASAN_SUPPORTED_ARCH}
- SOURCES ${ASAN_SOURCES} ${ASAN_CXX_SOURCES}
- CFLAGS ${ASAN_DYNAMIC_CFLAGS}
- DEFS ${ASAN_DYNAMIC_DEFINITIONS})
-else()
+
+add_compiler_rt_object_libraries(RTAsan_dynamic
+ OS ${SANITIZER_COMMON_SUPPORTED_OS}
+ ARCHS ${ASAN_SUPPORTED_ARCH}
+ SOURCES ${ASAN_SOURCES} ${ASAN_CXX_SOURCES}
+ CFLAGS ${ASAN_DYNAMIC_CFLAGS}
+ DEFS ${ASAN_DYNAMIC_DEFINITIONS})
+
+if(NOT APPLE)
add_compiler_rt_object_libraries(RTAsan
ARCHS ${ASAN_SUPPORTED_ARCH}
SOURCES ${ASAN_SOURCES} CFLAGS ${ASAN_CFLAGS}
@@ -94,11 +94,6 @@ else()
ARCHS ${ASAN_SUPPORTED_ARCH}
SOURCES ${ASAN_PREINIT_SOURCES} CFLAGS ${ASAN_CFLAGS}
DEFS ${ASAN_COMMON_DEFINITIONS})
- add_compiler_rt_object_libraries(RTAsan_dynamic
- ARCHS ${ASAN_SUPPORTED_ARCH}
- SOURCES ${ASAN_SOURCES} ${ASAN_CXX_SOURCES}
- CFLAGS ${ASAN_DYNAMIC_CFLAGS}
- DEFS ${ASAN_DYNAMIC_DEFINITIONS})
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/dummy.cc "")
add_compiler_rt_object_libraries(RTAsan_dynamic_version_script_dummy
@@ -111,49 +106,57 @@ endif()
# Build ASan runtimes shipped with Clang.
add_custom_target(asan)
if(APPLE)
- foreach (os ${SANITIZER_COMMON_SUPPORTED_OS})
- add_compiler_rt_darwin_dynamic_runtime(clang_rt.asan_${os}_dynamic ${os}
- ARCHS ${ASAN_SUPPORTED_ARCH}
- SOURCES $<TARGET_OBJECTS:RTAsan.${os}>
- $<TARGET_OBJECTS:RTInterception.${os}>
- $<TARGET_OBJECTS:RTSanitizerCommon.${os}>
- $<TARGET_OBJECTS:RTLSanCommon.${os}>
- $<TARGET_OBJECTS:RTUbsan.${os}>
- CFLAGS ${ASAN_DYNAMIC_CFLAGS}
- DEFS ${ASAN_DYNAMIC_DEFINITIONS})
- add_dependencies(asan clang_rt.asan_${os}_dynamic)
- endforeach()
+ add_compiler_rt_runtime(clang_rt.asan
+ SHARED
+ OS ${SANITIZER_COMMON_SUPPORTED_OS}
+ ARCHS ${ASAN_SUPPORTED_ARCH}
+ OBJECT_LIBS RTAsan_dynamic
+ RTInterception
+ RTSanitizerCommon
+ RTSanitizerCommonLibc
+ RTLSanCommon
+ RTUbsan
+ CFLAGS ${ASAN_DYNAMIC_CFLAGS}
+ DEFS ${ASAN_DYNAMIC_DEFINITIONS}
+ PARENT_TARGET asan)
else()
# Build separate libraries for each target.
- foreach(arch ${ASAN_SUPPORTED_ARCH})
- set(ASAN_COMMON_RUNTIME_OBJECTS
- $<TARGET_OBJECTS:RTInterception.${arch}>
- $<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
- $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>
- $<TARGET_OBJECTS:RTLSanCommon.${arch}>
- $<TARGET_OBJECTS:RTUbsan.${arch}>)
-
- add_compiler_rt_runtime(clang_rt.asan-${arch} ${arch} STATIC
- SOURCES $<TARGET_OBJECTS:RTAsan_preinit.${arch}>
- $<TARGET_OBJECTS:RTAsan.${arch}>
- ${ASAN_COMMON_RUNTIME_OBJECTS}
+
+ set(ASAN_COMMON_RUNTIME_OBJECT_LIBS
+ RTInterception
+ RTSanitizerCommon
+ RTSanitizerCommonLibc
+ RTLSanCommon
+ RTUbsan)
+
+ add_compiler_rt_runtime(clang_rt.asan
+ STATIC
+ ARCHS ${ASAN_SUPPORTED_ARCH}
+ OBJECT_LIBS RTAsan_preinit
+ RTAsan
+ ${ASAN_COMMON_RUNTIME_OBJECT_LIBS}
CFLAGS ${ASAN_CFLAGS}
- DEFS ${ASAN_COMMON_DEFINITIONS})
- add_dependencies(asan clang_rt.asan-${arch})
+ DEFS ${ASAN_COMMON_DEFINITIONS}
+ PARENT_TARGET asan)
- add_compiler_rt_runtime(clang_rt.asan_cxx-${arch} ${arch} STATIC
- SOURCES $<TARGET_OBJECTS:RTAsan_cxx.${arch}>
- $<TARGET_OBJECTS:RTUbsan_cxx.${arch}>
+ add_compiler_rt_runtime(clang_rt.asan_cxx
+ STATIC
+ ARCHS ${ASAN_SUPPORTED_ARCH}
+ OBJECT_LIBS RTAsan_cxx
+ RTUbsan_cxx
CFLAGS ${ASAN_CFLAGS}
- DEFS ${ASAN_COMMON_DEFINITIONS})
- add_dependencies(asan clang_rt.asan_cxx-${arch})
+ DEFS ${ASAN_COMMON_DEFINITIONS}
+ PARENT_TARGET asan)
- add_compiler_rt_runtime(clang_rt.asan-preinit-${arch} ${arch} STATIC
- SOURCES $<TARGET_OBJECTS:RTAsan_preinit.${arch}>
+ add_compiler_rt_runtime(clang_rt.asan-preinit
+ STATIC
+ ARCHS ${ASAN_SUPPORTED_ARCH}
+ OBJECT_LIBS RTAsan_preinit
CFLAGS ${ASAN_CFLAGS}
- DEFS ${ASAN_COMMON_DEFINITIONS})
- add_dependencies(asan clang_rt.asan-preinit-${arch})
+ DEFS ${ASAN_COMMON_DEFINITIONS}
+ PARENT_TARGET asan)
+ foreach(arch ${ASAN_SUPPORTED_ARCH})
if (UNIX AND NOT ${arch} MATCHES "i386|i686")
add_sanitizer_rt_version_list(clang_rt.asan-dynamic-${arch}
LIBS clang_rt.asan-${arch} clang_rt.asan_cxx-${arch}
@@ -168,48 +171,50 @@ else()
set(VERSION_SCRIPT_FLAG)
endif()
- if (WIN32)
- set(SHARED_ASAN_NAME clang_rt.asan_dynamic-${arch}${COMPILER_RT_OS_SUFFIX})
- else()
- set(SHARED_ASAN_NAME clang_rt.asan-${arch}${COMPILER_RT_OS_SUFFIX})
- endif()
- add_compiler_rt_runtime(clang_rt.asan-dynamic-${arch} ${arch} SHARED
- OUTPUT_NAME ${SHARED_ASAN_NAME}
- SOURCES $<TARGET_OBJECTS:RTAsan_dynamic.${arch}>
+ add_compiler_rt_runtime(clang_rt.asan
+ SHARED
+ ARCHS ${arch}
+ OBJECT_LIBS ${ASAN_COMMON_RUNTIME_OBJECT_LIBS}
+ RTAsan_dynamic
# The only purpose of RTAsan_dynamic_version_script_dummy is to carry
# a dependency of the shared runtime on the version script. With CMake
# 3.1 or later it can be replaced with a straightforward
# add_dependencies(clang_rt.asan-dynamic-${arch} clang_rt.asan-dynamic-${arch}-version-list)
- $<TARGET_OBJECTS:RTAsan_dynamic_version_script_dummy.${arch}>
- $<TARGET_OBJECTS:RTUbsan_cxx.${arch}>
- ${ASAN_COMMON_RUNTIME_OBJECTS}
+ RTAsan_dynamic_version_script_dummy
+ RTUbsan_cxx
CFLAGS ${ASAN_DYNAMIC_CFLAGS}
LINKFLAGS ${ASAN_DYNAMIC_LINK_FLAGS}
${VERSION_SCRIPT_FLAG}
- DEFS ${ASAN_DYNAMIC_DEFINITIONS})
- target_link_libraries(clang_rt.asan-dynamic-${arch} ${ASAN_DYNAMIC_LIBS})
- add_dependencies(asan clang_rt.asan-dynamic-${arch})
+ LINK_LIBS ${ASAN_DYNAMIC_LIBS}
+ DEFS ${ASAN_DYNAMIC_DEFINITIONS}
+ PARENT_TARGET asan)
if (UNIX AND NOT ${arch} MATCHES "i386|i686")
- add_sanitizer_rt_symbols(clang_rt.asan_cxx-${arch})
+ add_sanitizer_rt_symbols(clang_rt.asan_cxx
+ ARCHS ${arch})
add_dependencies(asan clang_rt.asan_cxx-${arch}-symbols)
- add_sanitizer_rt_symbols(clang_rt.asan-${arch} asan.syms.extra)
+ add_sanitizer_rt_symbols(clang_rt.asan
+ ARCHS ${arch}
+ EXTRA asan.syms.extra)
add_dependencies(asan clang_rt.asan-${arch}-symbols)
endif()
if (WIN32)
- add_compiler_rt_runtime(clang_rt.asan_dll_thunk-${arch} ${arch} STATIC
+ add_compiler_rt_runtime(clang_rt.asan_dll_thunk
+ STATIC
+ ARCHS ${arch}
SOURCES asan_win_dll_thunk.cc
$<TARGET_OBJECTS:RTInterception.${arch}>
CFLAGS ${ASAN_CFLAGS} -DASAN_DLL_THUNK
- DEFS ${ASAN_COMMON_DEFINITIONS})
- add_dependencies(asan clang_rt.asan_dll_thunk-${arch})
- add_compiler_rt_runtime(clang_rt.asan_dynamic_runtime_thunk-${arch} ${arch}
+ DEFS ${ASAN_COMMON_DEFINITIONS}
+ PARENT_TARGET asan)
+ add_compiler_rt_runtime(clang_rt.asan_dynamic_runtime_thunk
STATIC
+ ARCHS ${arch}
SOURCES asan_win_dynamic_runtime_thunk.cc
CFLAGS ${ASAN_CFLAGS} -DASAN_DYNAMIC_RUNTIME_THUNK -Zl
- DEFS ${ASAN_COMMON_DEFINITIONS})
- add_dependencies(asan clang_rt.asan_dynamic_runtime_thunk-${arch})
+ DEFS ${ASAN_COMMON_DEFINITIONS}
+ PARENT_TARGET asan)
endif()
endforeach()
endif()
diff --git a/lib/asan/README.txt b/lib/asan/README.txt
index 8cc9bb17b59d..bb6ff42c5cde 100644
--- a/lib/asan/README.txt
+++ b/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/lib/asan/asan_activation.cc b/lib/asan/asan_activation.cc
index 3bc01984898d..9df3b977ea1b 100644
--- a/lib/asan/asan_activation.cc
+++ b/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/lib/asan/asan_allocator.cc b/lib/asan/asan_allocator.cc
index 2df9a510bd9a..56f184a36651 100644
--- a/lib/asan/asan_allocator.cc
+++ b/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/lib/asan/asan_allocator.h b/lib/asan/asan_allocator.h
index 5ccd00c97bab..e3d53330cd2f 100644
--- a/lib/asan/asan_allocator.h
+++ b/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/lib/asan/asan_debugging.cc b/lib/asan/asan_debugging.cc
index 6fc5b690de99..7c3a8a73bd4e 100644
--- a/lib/asan/asan_debugging.cc
+++ b/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/lib/asan/asan_fake_stack.cc b/lib/asan/asan_fake_stack.cc
index d20641155b88..91fdf0aa1dca 100644
--- a/lib/asan/asan_fake_stack.cc
+++ b/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/lib/asan/asan_flags.cc b/lib/asan/asan_flags.cc
index e8ea549b62e3..363ee67e77c6 100644
--- a/lib/asan/asan_flags.cc
+++ b/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/lib/asan/asan_flags.inc b/lib/asan/asan_flags.inc
index 53a8a4039e7e..5e69242fb8e9 100644
--- a/lib/asan/asan_flags.inc
+++ b/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/lib/asan/asan_globals.cc b/lib/asan/asan_globals.cc
index c34b1d3cedf2..eb9f1bfefec2 100644
--- a/lib/asan/asan_globals.cc
+++ b/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/lib/asan/asan_init_version.h b/lib/asan/asan_init_version.h
index 6cf57c4aa2a8..bc8a622f5bb1 100644
--- a/lib/asan/asan_init_version.h
+++ b/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/lib/asan/asan_interceptors.cc b/lib/asan/asan_interceptors.cc
index d8b48d391ab8..d9a0c71a002d 100644
--- a/lib/asan/asan_interceptors.cc
+++ b/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/lib/asan/asan_interceptors.h b/lib/asan/asan_interceptors.h
index 488ada78ab8b..279c5f38451f 100644
--- a/lib/asan/asan_interceptors.h
+++ b/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/lib/asan/asan_interface_internal.h b/lib/asan/asan_interface_internal.h
index ad8ebcd91ad9..9efddcbd42b2 100644
--- a/lib/asan/asan_interface_internal.h
+++ b/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/lib/asan/asan_internal.h b/lib/asan/asan_internal.h
index 107e16ee31b9..0ef0d0eb5263 100644
--- a/lib/asan/asan_internal.h
+++ b/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/lib/asan/asan_linux.cc b/lib/asan/asan_linux.cc
index 9580fc7c06d4..e26b400562df 100644
--- a/lib/asan/asan_linux.cc
+++ b/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/lib/asan/asan_mac.cc b/lib/asan/asan_mac.cc
index 3e028378df28..f00d98f8e5e6 100644
--- a/lib/asan/asan_mac.cc
+++ b/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/lib/asan/asan_malloc_linux.cc b/lib/asan/asan_malloc_linux.cc
index 46a6a9db4a81..d5089f9f7b36 100644
--- a/lib/asan/asan_malloc_linux.cc
+++ b/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/lib/asan/asan_malloc_mac.cc b/lib/asan/asan_malloc_mac.cc
index d7a6307c9bdc..744728d40df5 100644
--- a/lib/asan/asan_malloc_mac.cc
+++ b/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/lib/asan/asan_mapping.h b/lib/asan/asan_mapping.h
index f9e1a527de18..8fe347c8bad0 100644
--- a/lib/asan/asan_mapping.h
+++ b/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/lib/asan/asan_new_delete.cc b/lib/asan/asan_new_delete.cc
index e48bdaf03dd3..b5ba13ef4055 100644
--- a/lib/asan/asan_new_delete.cc
+++ b/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/lib/asan/asan_poisoning.cc b/lib/asan/asan_poisoning.cc
index 569d359aa425..f77ab8780bb7 100644
--- a/lib/asan/asan_poisoning.cc
+++ b/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/lib/asan/asan_posix.cc b/lib/asan/asan_posix.cc
index 2e857f6f624c..9e01bcd091bf 100644
--- a/lib/asan/asan_posix.cc
+++ b/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/lib/asan/asan_report.cc b/lib/asan/asan_report.cc
index c1681e644464..0fb60846c3b4 100644
--- a/lib/asan/asan_report.cc
+++ b/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,93 @@ 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);
+ }
+
+ // Remove color sequences since logs cannot print them.
+ RemoveANSIEscapeSequencesFromString(buffer_copy.data());
+
+ 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 +724,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 +752,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 +769,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 +810,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 +850,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 +952,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 +991,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 +1002,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 +1087,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 +1113,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 +1178,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/lib/asan/asan_report.h b/lib/asan/asan_report.h
index e2786b0f260c..559b8adfd51d 100644
--- a/lib/asan/asan_report.h
+++ b/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/lib/asan/asan_rtl.cc b/lib/asan/asan_rtl.cc
index a8d92b915a9a..7b8b5dd9be1b 100644
--- a/lib/asan/asan_rtl.cc
+++ b/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/lib/asan/asan_stack.h b/lib/asan/asan_stack.h
index 122967a152f8..5c5181509801 100644
--- a/lib/asan/asan_stack.h
+++ b/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/lib/asan/asan_thread.cc b/lib/asan/asan_thread.cc
index 9af5706d86d0..69813546f551 100644
--- a/lib/asan/asan_thread.cc
+++ b/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/lib/asan/asan_thread.h b/lib/asan/asan_thread.h
index 50acfc42d6a2..ac35711f5794 100644
--- a/lib/asan/asan_thread.h
+++ b/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/lib/asan/asan_win.cc b/lib/asan/asan_win.cc
index addb3d40a696..92bd893d10ef 100644
--- a/lib/asan/asan_win.cc
+++ b/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/lib/asan/asan_win_dll_thunk.cc b/lib/asan/asan_win_dll_thunk.cc
index b77f18168ae5..308196d307cc 100644
--- a/lib/asan/asan_win_dll_thunk.cc
+++ b/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,6 +311,7 @@ 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)
@@ -312,6 +320,7 @@ 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/lib/asan/asan_win_dynamic_runtime_thunk.cc b/lib/asan/asan_win_dynamic_runtime_thunk.cc
index d59f9f5768a0..73e5207bb334 100644
--- a/lib/asan/asan_win_dynamic_runtime_thunk.cc
+++ b/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/lib/asan/scripts/asan_device_setup b/lib/asan/scripts/asan_device_setup
index 104e07b722ca..6cb7b94c2197 100755
--- a/lib/asan/scripts/asan_device_setup
+++ b/lib/asan/scripts/asan_device_setup
@@ -88,19 +88,25 @@ function adb_pull {
fi
}
-function get_device_arch { # OUTVAR
+function get_device_arch { # OUT OUT64
local _outvar=$1
+ local _outvar64=$2
local _ABI=$(adb_shell getprop ro.product.cpu.abi)
local _ARCH=
+ local _ARCH64=
if [[ $_ABI == x86* ]]; then
_ARCH=i686
elif [[ $_ABI == armeabi* ]]; then
_ARCH=arm
+ elif [[ $_ABI == arm64-v8a* ]]; then
+ _ARCH=arm
+ _ARCH64=aarch64
else
echo "Unrecognized device ABI: $_ABI"
exit 1
fi
eval $_outvar=\$_ARCH
+ eval $_outvar64=\$_ARCH64
}
while [[ $# > 0 ]]; do
@@ -167,22 +173,33 @@ adb_wait_for_device
adb_remount
adb_wait_for_device
-get_device_arch ARCH
+get_device_arch ARCH ARCH64
echo "Target architecture: $ARCH"
ASAN_RT="libclang_rt.asan-$ARCH-android.so"
+if [[ -n $ARCH64 ]]; then
+ echo "Target architecture: $ARCH64"
+ ASAN_RT64="libclang_rt.asan-$ARCH64-android.so"
+fi
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
+ echo '>> Pre-L device detected.'
+ adb_shell mv /system/bin/app_process.real /system/bin/app_process
+ adb_shell rm /system/bin/asanwrapper
+ elif ! adb_shell ls -l /system/bin/app_process64.real | grep -o 'No such file or directory' >&/dev/null; then
+ # 64-bit installation.
+ adb_shell mv /system/bin/app_process32.real /system/bin/app_process32
+ adb_shell mv /system/bin/app_process64.real /system/bin/app_process64
+ adb_shell rm /system/bin/asanwrapper
+ adb_shell rm /system/bin/asanwrapper64
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
+ # 32-bit installation.
+ 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'
@@ -205,8 +222,13 @@ 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)
+ # Consider ../lib, ../lib/asan, ../lib/linux,
+ # ../lib/clang/$VERSION/lib/linux, and ../lib64/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" \
+ "$HERE"/../lib64/clang/*/lib/linux/"$ASAN_RT" 2>/dev/null | sort | tail -1)
if [[ -n "$P" ]]; then
ASAN_RT_PATH="$(dirname "$P")"
fi
@@ -217,6 +239,13 @@ if [[ -z "$ASAN_RT_PATH" || ! -f "$ASAN_RT_PATH/$ASAN_RT" ]]; then
exit 1
fi
+if [[ -n "$ASAN_RT64" ]]; then
+ if [[ -z "$ASAN_RT_PATH" || ! -f "$ASAN_RT_PATH/$ASAN_RT64" ]]; then
+ echo ">> ASan runtime library not found"
+ exit 1
+ fi
+fi
+
TMPDIRBASE=$(mktemp -d)
TMPDIROLD="$TMPDIRBASE/old"
TMPDIR="$TMPDIRBASE/new"
@@ -241,12 +270,24 @@ if ! adb_shell ls -l /system/bin/app_process | grep -o '\->.*app_process' >&/dev
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
+if [[ -n "$ASAN_RT64" ]]; then
+ adb_pull /system/lib/"$ASAN_RT" "$TMPDIROLD" || true
+ adb_pull /system/lib64/"$ASAN_RT64" "$TMPDIROLD" || true
+ adb_pull /system/bin/app_process32 "$TMPDIROLD" || true
+ adb_pull /system/bin/app_process32.real "$TMPDIROLD" || true
+ adb_pull /system/bin/app_process64 "$TMPDIROLD" || true
+ adb_pull /system/bin/app_process64.real "$TMPDIROLD" || true
+ adb_pull /system/bin/asanwrapper "$TMPDIROLD" || true
+ adb_pull /system/bin/asanwrapper64 "$TMPDIROLD" || true
+else
+ adb_pull /system/lib/"$ASAN_RT" "$TMPDIROLD" || true
+ adb_pull /system/bin/app_process32 "$TMPDIROLD" || true
+ adb_pull /system/bin/app_process.wrap "$TMPDIROLD" || true
+ adb_pull /system/bin/asanwrapper "$TMPDIROLD" || true
+fi
cp -r "$TMPDIROLD" "$TMPDIR"
-if [[ -f "$TMPDIR/app_process.wrap" ]]; then
+if [[ -f "$TMPDIR/app_process.wrap" || -f "$TMPDIR/app_process64.real" ]]; then
echo ">> Previous installation detected"
else
echo ">> New installation"
@@ -255,10 +296,27 @@ fi
echo '>> Generating wrappers'
cp "$ASAN_RT_PATH/$ASAN_RT" "$TMPDIR/"
+if [[ -n "$ASAN_RT64" ]]; then
+ cp "$ASAN_RT_PATH/$ASAN_RT64" "$TMPDIR/"
+fi
# 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
+ASAN_OPTIONS=start_deactivated=1,alloc_dealloc_mismatch=0,malloc_context_size=0
+
+function generate_zygote_wrapper { # from, to, asan_rt
+ local _from=$1
+ local _to=$2
+ local _asan_rt=$3
+ cat <<EOF >"$TMPDIR/$_from"
+#!/system/bin/sh-from-zygote
+ASAN_OPTIONS=$ASAN_OPTIONS \\
+ASAN_ACTIVATION_OPTIONS=include_if_exists=/data/local/tmp/asan.options.%b \\
+LD_PRELOAD=\$LD_PRELOAD:$_asan_rt \\
+exec $_to \$@
+
+EOF
+}
# On Android-L not allowing user segv handler breaks some applications.
if [[ PRE_L -eq 0 ]]; then
@@ -270,13 +328,19 @@ if [[ x$extra_options != x ]] ; then
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
+if [[ -f "$TMPDIR/app_process64" ]]; then
+ # A 64-bit device.
+ if [[ ! -f "$TMPDIR/app_process64.real" ]]; then
+ # New installation.
+ mv "$TMPDIR/app_process32" "$TMPDIR/app_process32.real"
+ mv "$TMPDIR/app_process64" "$TMPDIR/app_process64.real"
+ fi
+ generate_zygote_wrapper "app_process32" "/system/bin/app_process32.real" "$ASAN_RT"
+ generate_zygote_wrapper "app_process64" "/system/bin/app_process64.real" "$ASAN_RT64"
+else
+ # A 32-bit device.
+ generate_zygote_wrapper "app_process.wrap" "/system/bin/app_process32" "$ASAN_RT"
+fi
# General command-line tool wrapper (use for anything that's not started as
# zygote).
@@ -287,25 +351,33 @@ 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
+if [[ -n "$ASAN_RT64" ]]; then
+ cat <<EOF >"$TMPDIR/asanwrapper64"
+#!/system/bin/sh
+LD_PRELOAD=$ASAN_RT64 \\
+exec \$@
+
+EOF
+fi
+
+function install { # from, to, chmod, chcon
+ local _from=$1
+ local _to=$2
+ local _mode=$3
+ local _context=$4
+ local _basename="$(basename "$_from")"
+ echo "Installing $_to/$_basename $_mode $_context"
+ adb_push "$_from" "$_to/$_basename"
+ adb_shell chown root.shell "$_to/$_basename"
+ if [[ -n "$_mode" ]]; then
+ adb_shell chmod "$_mode" "$_to/$_basename"
+ fi
+ if [[ -n "$_context" ]]; then
+ adb_shell chcon "$_context" "$_to/$_basename"
+ fi
+}
+if ! ( cd "$TMPDIRBASE" && diff -qr old/ new/ ) ; then
# Make SELinux happy by keeping app_process wrapper and the shell
# it runs on in zygote domain.
ENFORCING=0
@@ -316,17 +388,35 @@ if ! ( cd "$TMPDIRBASE" && diff -qr old/ new/ ) ; then
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
+
+ echo '>> Pushing files to the device'
+
+ if [[ -n "$ASAN_RT64" ]]; then
+ install "$TMPDIR/$ASAN_RT" /system/lib 644
+ install "$TMPDIR/$ASAN_RT64" /system/lib64 644
+ install "$TMPDIR/app_process32" /system/bin 755 $CTX
+ install "$TMPDIR/app_process32.real" /system/bin 755 $CTX
+ install "$TMPDIR/app_process64" /system/bin 755 $CTX
+ install "$TMPDIR/app_process64.real" /system/bin 755 $CTX
+ install "$TMPDIR/asanwrapper" /system/bin 755
+ install "$TMPDIR/asanwrapper64" /system/bin 755
+ else
+ install "$TMPDIR/$ASAN_RT" /system/lib 644
+ install "$TMPDIR/app_process32" /system/bin 755 $CTX
+ install "$TMPDIR/app_process.wrap" /system/bin 755 $CTX
+ install "$TMPDIR/asanwrapper" /system/bin 755 $CTX
+
+ adb_shell rm /system/bin/app_process
+ adb_shell ln -s /system/bin/app_process.wrap /system/bin/app_process
+ fi
+
+ adb_shell cp /system/bin/sh /system/bin/sh-from-zygote
+ adb_shell chcon $CTX /system/bin/sh-from-zygote
if [ $ENFORCING == 1 ]; then
adb_shell setenforce 1
diff --git a/lib/asan/scripts/asan_symbolize.py b/lib/asan/scripts/asan_symbolize.py
index b9d3ad3ad2fe..8e6fb61f7bf7 100755
--- a/lib/asan/scripts/asan_symbolize.py
+++ b/lib/asan/scripts/asan_symbolize.py
@@ -77,7 +77,7 @@ class LLVMSymbolizer(Symbolizer):
cmd = [self.symbolizer_path,
'--use-symbol-table=true',
'--demangle=%s' % demangle,
- '--functions=short',
+ '--functions=linkage',
'--inlining=true',
'--default-arch=%s' % self.default_arch]
if self.system == 'Darwin':
@@ -135,12 +135,13 @@ class Addr2LineSymbolizer(Symbolizer):
super(Addr2LineSymbolizer, self).__init__()
self.binary = binary
self.pipe = self.open_addr2line()
+ self.output_terminator = -1
def open_addr2line(self):
addr2line_tool = 'addr2line'
if binutils_prefix:
addr2line_tool = binutils_prefix + addr2line_tool
- cmd = [addr2line_tool, '-f']
+ cmd = [addr2line_tool, '-fi']
if demangle:
cmd += ['--demangle']
cmd += ['-e', self.binary]
@@ -153,16 +154,23 @@ class Addr2LineSymbolizer(Symbolizer):
"""Overrides Symbolizer.symbolize."""
if self.binary != binary:
return None
+ lines = []
try:
print >> self.pipe.stdin, offset
- function_name = self.pipe.stdout.readline().rstrip()
- file_name = self.pipe.stdout.readline().rstrip()
+ print >> self.pipe.stdin, self.output_terminator
+ is_first_frame = True
+ while True:
+ function_name = self.pipe.stdout.readline().rstrip()
+ file_name = self.pipe.stdout.readline().rstrip()
+ if is_first_frame:
+ is_first_frame = False
+ elif function_name in ['', '??']:
+ assert file_name == function_name
+ break
+ lines.append((function_name, file_name));
except Exception:
- function_name = ''
- file_name = ''
- file_name = fix_filename(file_name)
- return ['%s in %s %s' % (addr, function_name, file_name)]
-
+ lines.append(('??', '??:0'))
+ return ['%s in %s %s' % (addr, function, fix_filename(file)) for (function, file) in lines]
class UnbufferedLineConverter(object):
"""
@@ -263,7 +271,7 @@ def BreakpadSymbolizerFactory(binary):
def SystemSymbolizerFactory(system, addr, binary):
if system == 'Darwin':
return DarwinSymbolizer(addr, binary)
- elif system == 'Linux':
+ elif system == 'Linux' or system == 'FreeBSD':
return Addr2LineSymbolizer(binary)
diff --git a/lib/asan/tests/CMakeLists.txt b/lib/asan/tests/CMakeLists.txt
index afdd2adf0887..7a8d8f7f106b 100644
--- a/lib/asan/tests/CMakeLists.txt
+++ b/lib/asan/tests/CMakeLists.txt
@@ -106,7 +106,7 @@ append_list_if(COMPILER_RT_HAS_LIBPTHREAD -pthread
# TODO(eugenis): move all -l flags above to _LIBS?
set(ASAN_UNITTEST_NOINST_LIBS)
-append_list_if(ANDROID log ASAN_UNITTEST_NOINST_LIBS)
+append_list_if(COMPILER_RT_HAS_LIBLOG log ASAN_UNITTEST_NOINST_LIBS)
# NDK r10 requires -latomic almost always.
append_list_if(ANDROID atomic ASAN_UNITTEST_NOINST_LIBS)
@@ -217,9 +217,10 @@ macro(add_asan_tests_for_arch_and_kind arch kind)
set(ASAN_TEST_RUNTIME RTAsanTest.${arch}${kind})
if(APPLE)
set(ASAN_TEST_RUNTIME_OBJECTS
- $<TARGET_OBJECTS:RTAsan.osx>
+ $<TARGET_OBJECTS:RTAsan_dynamic.osx>
$<TARGET_OBJECTS:RTInterception.osx>
$<TARGET_OBJECTS:RTSanitizerCommon.osx>
+ $<TARGET_OBJECTS:RTSanitizerCommonLibc.osx>
$<TARGET_OBJECTS:RTLSanCommon.osx>
$<TARGET_OBJECTS:RTUbsan.osx>)
else()
@@ -261,7 +262,11 @@ macro(add_asan_tests_for_arch_and_kind arch kind)
endmacro()
if(COMPILER_RT_CAN_EXECUTE_TESTS AND NOT ANDROID)
- foreach(arch ${ASAN_SUPPORTED_ARCH})
+ set(ASAN_TEST_ARCH ${ASAN_SUPPORTED_ARCH})
+ if(APPLE)
+ darwin_filter_host_archs(ASAN_SUPPORTED_ARCH ASAN_TEST_ARCH)
+ endif()
+ foreach(arch ${ASAN_TEST_ARCH})
add_asan_tests_for_arch_and_kind(${arch} "-inline")
add_asan_tests_for_arch_and_kind(${arch} "-with-calls"
-mllvm -asan-instrumentation-with-call-threshold=0)
diff --git a/lib/asan/tests/asan_asm_test.cc b/lib/asan/tests/asan_asm_test.cc
index 200de2c137a5..09af5c386079 100644
--- a/lib/asan/tests/asan_asm_test.cc
+++ b/lib/asan/tests/asan_asm_test.cc
@@ -14,7 +14,10 @@
#if defined(__linux__)
-#if defined(__x86_64__) || (defined(__i386__) && defined(__SSE2__))
+// Assembly instrumentation is broken on x86 Android (x86 + PIC + shared runtime
+// library). See https://github.com/google/sanitizers/issues/353
+#if defined(__x86_64__) || \
+ (defined(__i386__) && defined(__SSE2__) && !defined(__ANDROID__))
#include <emmintrin.h>
@@ -70,7 +73,7 @@ DECLARE_ASM_REP_MOVS(U8, "movsq");
#endif // defined(__x86_64__)
-#if defined(__i386__) && defined(__SSE2__)
+#if defined(__i386__) && defined(__SSE2__) && !defined(__ANDROID__)
namespace {
@@ -108,7 +111,8 @@ template<> Type asm_read<Type>(Type *ptr) { \
#endif // defined(__i386__) && defined(__SSE2__)
-#if defined(__x86_64__) || (defined(__i386__) && defined(__SSE2__))
+#if defined(__x86_64__) || \
+ (defined(__i386__) && defined(__SSE2__) && !defined(__ANDROID__))
namespace {
diff --git a/lib/asan/tests/asan_interface_test.cc b/lib/asan/tests/asan_interface_test.cc
index a34c8528eae0..f5bfb8046b0a 100644
--- a/lib/asan/tests/asan_interface_test.cc
+++ b/lib/asan/tests/asan_interface_test.cc
@@ -140,16 +140,6 @@ static void DoDoubleFree() {
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.
diff --git a/lib/asan/tests/asan_mac_test.cc b/lib/asan/tests/asan_mac_test.cc
index cabdfd711ea2..dfa6d7596d74 100644
--- a/lib/asan/tests/asan_mac_test.cc
+++ b/lib/asan/tests/asan_mac_test.cc
@@ -216,12 +216,12 @@ TEST(AddressSanitizerMac, NSObjectOOB) {
// 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.
+// See https://github.com/google/sanitizers/issues/70.
TEST(AddressSanitizerMac, NSURLDeallocation) {
TestNSURLDeallocation();
}
-// See http://code.google.com/p/address-sanitizer/issues/detail?id=109.
+// See https://github.com/google/sanitizers/issues/109.
TEST(AddressSanitizerMac, Mstats) {
malloc_statistics_t stats1, stats2;
malloc_zone_statistics(/*all zones*/NULL, &stats1);
diff --git a/lib/asan/tests/asan_noinst_test.cc b/lib/asan/tests/asan_noinst_test.cc
index 6a428fbbc2b9..5f5354f92caf 100644
--- a/lib/asan/tests/asan_noinst_test.cc
+++ b/lib/asan/tests/asan_noinst_test.cc
@@ -34,7 +34,7 @@
// Make sure __asan_init is called before any test case is run.
struct AsanInitCaller {
AsanInitCaller() {
- __asan::DisableReexec();
+ DisableReexec();
__asan_init();
}
};
diff --git a/lib/asan/tests/asan_test.cc b/lib/asan/tests/asan_test.cc
index 07d59e09a72f..71fb27a0ca11 100644
--- a/lib/asan/tests/asan_test.cc
+++ b/lib/asan/tests/asan_test.cc
@@ -250,12 +250,12 @@ TEST(AddressSanitizer, BitFieldNegativeTest) {
#if ASAN_NEEDS_SEGV
namespace {
-const char kUnknownCrash[] = "AddressSanitizer: SEGV on unknown address";
+const char kSEGVCrash[] = "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);
+ EXPECT_DEATH(*c = 0, kSEGVCrash);
}
void my_sigaction_sighandler(int, siginfo_t*, void*) {
@@ -279,10 +279,10 @@ TEST(AddressSanitizer, SignalTest) {
EXPECT_EQ(0, sigaction(SIGBUS, &sigact, 0));
#endif
char *c = (char*)0x123;
- EXPECT_DEATH(*c = 0, kUnknownCrash);
+ EXPECT_DEATH(*c = 0, kSEGVCrash);
// ... and signal().
EXPECT_EQ(0, signal(SIGSEGV, my_signal_sighandler));
- EXPECT_DEATH(*c = 0, kUnknownCrash);
+ EXPECT_DEATH(*c = 0, kSEGVCrash);
}
} // namespace
#endif
@@ -335,6 +335,8 @@ void *ManyThreadsWorker(void *a) {
return 0;
}
+#if !defined(__aarch64__)
+// FIXME: Infinite loop in AArch64 (PR24389).
TEST(AddressSanitizer, ManyThreadsTest) {
const size_t kNumThreads =
(SANITIZER_WORDSIZE == 32 || ASAN_AVOID_EXPENSIVE_TESTS) ? 30 : 1000;
@@ -346,6 +348,7 @@ TEST(AddressSanitizer, ManyThreadsTest) {
PTHREAD_JOIN(t[i], 0);
}
}
+#endif
TEST(AddressSanitizer, ReallocTest) {
const int kMinElem = 5;
@@ -607,7 +610,7 @@ NOINLINE void BuiltinLongJmpFunc1(jmp_buf buf) {
}
// Does not work on Power and ARM:
-// https://code.google.com/p/address-sanitizer/issues/detail?id=185
+// https://github.com/google/sanitizers/issues/185
TEST(AddressSanitizer, BuiltinLongJmpTest) {
static jmp_buf buf;
if (!__builtin_setjmp((void**)buf)) {
@@ -1153,9 +1156,9 @@ TEST(AddressSanitizer, AttributeNoSanitizeAddressTest) {
// 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
+// https://github.com/google/sanitizers/issues/131
// Windows support is tracked here:
-// https://code.google.com/p/address-sanitizer/issues/detail?id=309
+// https://github.com/google/sanitizers/issues/309
#if !defined(__ANDROID__) && \
!defined(__APPLE__) && \
!defined(_WIN32)
@@ -1252,7 +1255,7 @@ TEST(AddressSanitizer, DISABLED_DemoTooMuchMemoryTest) {
}
}
-// http://code.google.com/p/address-sanitizer/issues/detail?id=66
+// https://github.com/google/sanitizers/issues/66
TEST(AddressSanitizer, BufferOverflowAfterManyFrees) {
for (int i = 0; i < 1000000; i++) {
delete [] (Ident(new char [8644]));
diff --git a/lib/asan/tests/asan_test_main.cc b/lib/asan/tests/asan_test_main.cc
index 1746c5f4837b..cdaf801d914b 100644
--- a/lib/asan/tests/asan_test_main.cc
+++ b/lib/asan/tests/asan_test_main.cc
@@ -11,6 +11,20 @@
//
//===----------------------------------------------------------------------===//
#include "asan_test_utils.h"
+#include "sanitizer_common/sanitizer_platform.h"
+
+// Default ASAN_OPTIONS for the unit tests. Let's turn symbolication off to
+// speed up testing (unit tests don't use it anyway).
+extern "C" const char* __asan_default_options() {
+#if SANITIZER_MAC
+ // On Darwin, we default to `abort_on_error=1`, which would make tests run
+ // much slower. Let's override this and run lit tests with 'abort_on_error=0'.
+ // Also, make sure we do not overwhelm the syslog while testing.
+ return "symbolize=false:abort_on_error=0:log_to_syslog=0";
+#else
+ return "symbolize=false";
+#endif
+}
int main(int argc, char **argv) {
testing::GTEST_FLAG(death_test_style) = "threadsafe";
diff --git a/lib/builtins/CMakeLists.txt b/lib/builtins/CMakeLists.txt
index 98d518a83e2c..5ffad1d47b17 100644
--- a/lib/builtins/CMakeLists.txt
+++ b/lib/builtins/CMakeLists.txt
@@ -2,6 +2,9 @@
# generic implementations of the core runtime library along with optimized
# architecture-specific code in various subdirectories.
+# TODO: Need to add a mechanism for logging errors when builtin source files are
+# added to a sub-directory and not this CMakeLists file.
+
set(GENERIC_SOURCES
absvdi2.c
absvsi2.c
@@ -38,6 +41,7 @@ set(GENERIC_SOURCES
divsc3.c
divsf3.c
divsi3.c
+ divtc3.c
divti3.c
divtf3.c
divxc3.c
@@ -139,59 +143,102 @@ set(GENERIC_SOURCES
umodsi3.c
umodti3.c)
+if(APPLE)
+ set(GENERIC_SOURCES
+ ${GENERIC_SOURCES}
+ atomic_flag_clear.c
+ atomic_flag_clear_explicit.c
+ atomic_flag_test_and_set.c
+ atomic_flag_test_and_set_explicit.c
+ atomic_signal_fence.c
+ atomic_thread_fence.c)
+endif()
+
+if(NOT WIN32 OR MINGW)
+ set(GENERIC_SOURCES
+ ${GENERIC_SOURCES}
+ emutls.c)
+endif()
+
if (HAVE_UNWIND_H)
set(GENERIC_SOURCES
${GENERIC_SOURCES}
gcc_personality_v0.c)
endif ()
-set(x86_64_SOURCES
- x86_64/floatdidf.c
- x86_64/floatdisf.c
- x86_64/floatdixf.c
- x86_64/floatundidf.S
- x86_64/floatundisf.S
- x86_64/floatundixf.S
- ${GENERIC_SOURCES})
-
-if(WIN32)
+if (NOT MSVC)
set(x86_64_SOURCES
- ${x86_64_SOURCES}
- x86_64/chkstk.S)
-endif()
+ x86_64/chkstk.S
+ x86_64/chkstk2.S
+ x86_64/floatdidf.c
+ x86_64/floatdisf.c
+ x86_64/floatdixf.c
+ x86_64/floatundidf.S
+ x86_64/floatundisf.S
+ x86_64/floatundixf.S
+ ${GENERIC_SOURCES})
+ set(x86_64h_SOURCES ${x86_64_SOURCES})
-set(i386_SOURCES
- i386/ashldi3.S
- i386/ashrdi3.S
- i386/divdi3.S
- i386/floatdidf.S
- i386/floatdisf.S
- i386/floatdixf.S
- i386/floatundidf.S
- i386/floatundisf.S
- i386/floatundixf.S
- i386/lshrdi3.S
- i386/moddi3.S
- i386/muldi3.S
- i386/udivdi3.S
- i386/umoddi3.S
- ${GENERIC_SOURCES})
+ if (WIN32)
+ set(x86_64_SOURCES
+ ${x86_64_SOURCES}
+ x86_64/chkstk.S
+ x86_64/chkstk2.S)
+ endif()
-if(WIN32)
set(i386_SOURCES
- ${i386_SOURCES}
- i386/chkstk.S)
-endif()
+ i386/ashldi3.S
+ i386/ashrdi3.S
+ i386/chkstk.S
+ i386/chkstk2.S
+ i386/divdi3.S
+ i386/floatdidf.S
+ i386/floatdisf.S
+ i386/floatdixf.S
+ i386/floatundidf.S
+ i386/floatundisf.S
+ i386/floatundixf.S
+ i386/lshrdi3.S
+ i386/moddi3.S
+ i386/muldi3.S
+ i386/udivdi3.S
+ i386/umoddi3.S
+ ${GENERIC_SOURCES})
-set(i686_SOURCES
- ${i386_SOURCES})
+ if (WIN32)
+ set(i386_SOURCES
+ ${i386_SOURCES}
+ i386/chkstk.S
+ i386/chkstk2.S)
+ endif()
+
+ set(i686_SOURCES
+ ${i386_SOURCES})
+else () # MSVC
+ # Use C versions of functions when building on MSVC
+ # MSVC's assembler takes Intel syntax, not AT&T syntax
+ set(x86_64_SOURCES
+ x86_64/floatdidf.c
+ x86_64/floatdisf.c
+ x86_64/floatdixf.c
+ ${GENERIC_SOURCES})
+ set(x86_64h_SOURCES ${x86_64_SOURCES})
+ set(i386_SOURCES ${GENERIC_SOURCES})
+ set(i686_SOURCES ${i386_SOURCES})
+endif () # if (NOT MSVC)
set(arm_SOURCES
arm/adddf3vfp.S
arm/addsf3vfp.S
+ arm/aeabi_cdcmp.S
+ arm/aeabi_cdcmpeq_check_nan.c
+ arm/aeabi_cfcmp.S
+ arm/aeabi_cfcmpeq_check_nan.c
arm/aeabi_dcmp.S
arm/aeabi_div0.c
+ arm/aeabi_drsub.c
arm/aeabi_fcmp.S
+ arm/aeabi_frsub.c
arm/aeabi_idivmod.S
arm/aeabi_ldivmod.S
arm/aeabi_memcmp.S
@@ -202,6 +249,8 @@ set(arm_SOURCES
arm/aeabi_uldivmod.S
arm/bswapdi2.S
arm/bswapsi2.S
+ arm/clzdi2.S
+ arm/clzsi2.S
arm/comparesf2.S
arm/divdf3vfp.S
arm/divmodsi4.S
@@ -270,10 +319,50 @@ set(arm_SOURCES
arm/unordsf2vfp.S
${GENERIC_SOURCES})
+set(aarch64_SOURCES
+ comparetf2.c
+ extenddftf2.c
+ extendsftf2.c
+ fixtfdi.c
+ fixtfsi.c
+ fixtfti.c
+ fixunstfdi.c
+ fixunstfsi.c
+ fixunstfti.c
+ floatditf.c
+ floatsitf.c
+ floatunditf.c
+ floatunsitf.c
+ multc3.c
+ trunctfdf2.c
+ trunctfsf2.c
+ ${GENERIC_SOURCES})
+
+set(armhf_SOURCES ${arm_SOURCES})
+set(armv7_SOURCES ${arm_SOURCES})
+set(armv7s_SOURCES ${arm_SOURCES})
+set(arm64_SOURCES ${aarch64_SOURCES})
+
+# macho_embedded archs
+set(armv6m_SOURCES ${GENERIC_SOURCES})
+set(armv7m_SOURCES ${arm_SOURCES})
+set(armv7em_SOURCES ${arm_SOURCES})
+
+set(mips_SOURCES ${GENERIC_SOURCES})
+set(mipsel_SOURCES ${mips_SOURCES})
+set(mips64_SOURCES ${mips_SOURCES})
+set(mips64el_SOURCES ${mips_SOURCES})
+
add_custom_target(builtins)
-if (NOT WIN32 OR MINGW)
- foreach (arch x86_64 i386 i686 arm)
+if (APPLE)
+ add_subdirectory(Darwin-excludes)
+ add_subdirectory(macho_embedded)
+ darwin_add_builtin_libraries(${BUILTIN_SUPPORTED_OS})
+elseif (NOT WIN32 OR MINGW)
+ append_string_if(COMPILER_RT_HAS_STD_C99_FLAG -std=c99 maybe_stdc99)
+
+ foreach (arch ${BUILTIN_SUPPORTED_ARCH})
if (CAN_TARGET_${arch})
# Filter out generic versions of routines that are re-implemented in
# architecture specific manner. This prevents multiple definitions of the
@@ -286,11 +375,12 @@ if (NOT WIN32 OR MINGW)
endif ()
endforeach ()
- set_source_files_properties(${${arch}_SOURCES} PROPERTIES LANGUAGE C)
- add_compiler_rt_runtime(clang_rt.builtins-${arch} ${arch} STATIC
+ add_compiler_rt_runtime(clang_rt.builtins
+ STATIC
+ ARCHS ${arch}
SOURCES ${${arch}_SOURCES}
- CFLAGS "-std=c99")
- add_dependencies(builtins clang_rt.builtins-${arch})
+ CFLAGS ${maybe_stdc99}
+ PARENT_TARGET builtins)
endif ()
endforeach ()
endif ()
diff --git a/lib/builtins/Darwin-excludes/10.4-x86_64.txt b/lib/builtins/Darwin-excludes/10.4-x86_64.txt
new file mode 100644
index 000000000000..f2ee7fef0c63
--- /dev/null
+++ b/lib/builtins/Darwin-excludes/10.4-x86_64.txt
@@ -0,0 +1,35 @@
+absvti2
+addvti3
+ashlti3
+ashrti3
+clzti2
+cmpti2
+ctzti2
+divti3
+ffsti2
+fixdfti
+fixsfti
+fixunsdfti
+fixunssfti
+fixunsxfti
+fixxfti
+floattidf
+floattisf
+floattixf
+floatuntidf
+floatuntisf
+floatuntixf
+lshrti3
+modti3
+muloti4
+multi3
+mulvti3
+negti2
+negvti2
+parityti2
+popcountti2
+subvti3
+ucmpti2
+udivmodti4
+udivti3
+umodti3
diff --git a/lib/builtins/Darwin-excludes/10.4.txt b/lib/builtins/Darwin-excludes/10.4.txt
new file mode 100644
index 000000000000..70d3644f271c
--- /dev/null
+++ b/lib/builtins/Darwin-excludes/10.4.txt
@@ -0,0 +1,96 @@
+apple_versioning
+absvdi2
+absvsi2
+adddf3
+addsf3
+addvdi3
+addvsi3
+ashldi3
+ashrdi3
+clear_cache
+clzdi2
+clzsi2
+cmpdi2
+ctzdi2
+ctzsi2
+divdc3
+divdf3
+divdi3
+divmoddi4
+divmodsi4
+divsc3
+divsf3
+divsi3
+divxc3
+enable_execute_stack
+comparedf2
+comparesf2
+extendhfsf2
+extendsfdf2
+ffsdi2
+fixdfdi
+fixdfsi
+fixsfdi
+fixsfsi
+fixunsdfdi
+fixunsdfsi
+fixunssfdi
+fixunssfsi
+fixunsxfdi
+fixunsxfsi
+fixxfdi
+floatdidf
+floatdisf
+floatdixf
+floatsidf
+floatsisf
+floatunsidf
+floatunsisf
+gcc_personality_v0
+gnu_f2h_ieee
+gnu_h2f_ieee
+lshrdi3
+moddi3
+modsi3
+muldc3
+muldf3
+muldi3
+mulodi4
+mulosi4
+mulsc3
+mulsf3
+mulvdi3
+mulvsi3
+mulxc3
+negdf2
+negdi2
+negsf2
+negvdi2
+negvsi2
+paritydi2
+paritysi2
+popcountdi2
+popcountsi2
+powidf2
+powisf2
+powixf2
+subdf3
+subsf3
+subvdi3
+subvsi3
+truncdfhf2
+truncdfsf2
+truncsfhf2
+ucmpdi2
+udivdi3
+udivmoddi4
+udivmodsi4
+udivsi3
+umoddi3
+umodsi3
+atomic_flag_clear
+atomic_flag_clear_explicit
+atomic_flag_test_and_set
+atomic_flag_test_and_set_explicit
+atomic_signal_fence
+atomic_thread_fence \ No newline at end of file
diff --git a/lib/builtins/Darwin-excludes/CMakeLists.txt b/lib/builtins/Darwin-excludes/CMakeLists.txt
new file mode 100644
index 000000000000..266e42215243
--- /dev/null
+++ b/lib/builtins/Darwin-excludes/CMakeLists.txt
@@ -0,0 +1,4 @@
+file(GLOB filter_files ${CMAKE_CURRENT_SOURCE_DIR}/*.txt)
+foreach(filter_file ${filter_files})
+ set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${filter_file})
+endforeach()
diff --git a/lib/builtins/Darwin-excludes/README.TXT b/lib/builtins/Darwin-excludes/README.TXT
new file mode 100644
index 000000000000..173eccca6dec
--- /dev/null
+++ b/lib/builtins/Darwin-excludes/README.TXT
@@ -0,0 +1,11 @@
+This folder contains list of symbols that should be excluded from the builtin
+libraries for Darwin. There are two reasons symbols are excluded:
+
+(1) They aren't supported on Darwin
+(2) They are contained within the OS on the minimum supported target
+
+The builtin libraries must contain all symbols not provided by the lowest
+supported target OS. Meaning if minimum deployment target is iOS 6, all builtins
+not included in the ios6-<arch>.txt files need to be included. The one catch is
+that this is per-architecture. Since iOS 6 doesn't support arm64, when supporting
+iOS 6, the minimum deployment target for arm64 binaries is iOS 7.
diff --git a/lib/builtins/Darwin-excludes/ios-armv7.txt b/lib/builtins/Darwin-excludes/ios-armv7.txt
new file mode 100644
index 000000000000..6aa542f7fe4a
--- /dev/null
+++ b/lib/builtins/Darwin-excludes/ios-armv7.txt
@@ -0,0 +1,57 @@
+absvti2
+addtf3
+addvti3
+aeabi_cdcmp
+aeabi_cdcmpeq_check_nan
+aeabi_cfcmp
+aeabi_cfcmpeq_check_nan
+aeabi_dcmp
+aeabi_div0
+aeabi_drsub
+aeabi_fcmp
+aeabi_frsub
+aeabi_idivmod
+aeabi_ldivmod
+aeabi_memcmp
+aeabi_memcpy
+aeabi_memmove
+aeabi_memset
+aeabi_uidivmod
+aeabi_uldivmod
+ashlti3
+ashrti3
+clzti2
+cmpti2
+ctzti2
+divtf3
+divti3
+ffsti2
+fixdfti
+fixsfti
+fixunsdfti
+fixunssfti
+fixunsxfti
+fixxfti
+floattidf
+floattisf
+floattixf
+floatuntidf
+floatuntisf
+floatuntixf
+lshrti3
+modti3
+multf3
+multi3
+mulvti3
+negti2
+negvti2
+parityti2
+popcountti2
+powitf2
+subtf3
+subvti3
+trampoline_setup
+ucmpti2
+udivmodti4
+udivti3
+umodti3
diff --git a/lib/builtins/Darwin-excludes/ios-armv7s.txt b/lib/builtins/Darwin-excludes/ios-armv7s.txt
new file mode 100644
index 000000000000..28167aa4c5db
--- /dev/null
+++ b/lib/builtins/Darwin-excludes/ios-armv7s.txt
@@ -0,0 +1,57 @@
+absvti2
+addtf3
+addvti3
+aeabi_cdcmp
+aeabi_cdcmpeq_check_nan
+aeabi_cfcmp
+aeabi_cfcmpeq_check_nan
+aeabi_dcmp
+aeabi_div0
+aeabi_drsub
+aeabi_fcmp
+aeabi_frsub
+aeabi_idivmod
+aeabi_ldivmod
+aeabi_memcmp
+aeabi_memcpy
+aeabi_memmove
+aeabi_memset
+aeabi_uidivmod
+aeabi_uldivmod
+ashlti3
+ashrti3
+clzti2
+cmpti2
+ctzti2
+divtf3
+divti3
+ffsti2
+fixdfti
+fixsfti
+fixunsdfti
+fixunssfti
+fixunsxfti
+fixxfti
+floattidf
+floattisf
+floattixf
+floatuntidf
+floatuntisf
+floatuntixf
+lshrti3
+modti3
+multf
+multi3
+mulvti3
+negti2
+negvti2
+parityti2
+popcountti2
+powitf2
+subtf3
+subvti3
+trampoline_setup
+ucmpti2
+udivmodti4
+udivti3
+umodti3
diff --git a/lib/builtins/Darwin-excludes/ios.txt b/lib/builtins/Darwin-excludes/ios.txt
new file mode 100644
index 000000000000..5db24000a174
--- /dev/null
+++ b/lib/builtins/Darwin-excludes/ios.txt
@@ -0,0 +1 @@
+apple_versioning
diff --git a/lib/builtins/Darwin-excludes/ios6-armv7.txt b/lib/builtins/Darwin-excludes/ios6-armv7.txt
new file mode 100644
index 000000000000..b01fa711a357
--- /dev/null
+++ b/lib/builtins/Darwin-excludes/ios6-armv7.txt
@@ -0,0 +1,120 @@
+absvdi2
+absvsi2
+adddf3
+adddf3vfp
+addsf3
+addsf3vfp
+addvdi3
+addvsi3
+ashldi3
+ashrdi3
+bswapdi2
+bswapsi2
+clzdi2
+clzsi2
+cmpdi2
+ctzdi2
+ctzsi2
+divdc3
+divdf3
+divdf3vfp
+divdi3
+divmodsi4
+divsc3
+divsf3
+divsf3vfp
+divsi3
+eqdf2
+eqdf2vfp
+eqsf2
+eqsf2vfp
+extendsfdf2
+extendsfdf2vfp
+ffsdi2
+fixdfdi
+fixdfsi
+fixdfsivfp
+fixsfdi
+fixsfsi
+fixsfsivfp
+fixunsdfdi
+fixunsdfsi
+fixunsdfsivfp
+fixunssfdi
+fixunssfsi
+fixunssfsivfp
+floatdidf
+floatdisf
+floatsidf
+floatsidfvfp
+floatsisf
+floatsisfvfp
+floatundidf
+floatundisf
+floatunsidf
+floatunsisf
+floatunssidfvfp
+floatunssisfvfp
+gcc_personality_sj0
+gedf2
+gedf2vfp
+gesf2
+gesf2vfp
+gtdf2
+gtdf2vfp
+gtsf2
+gtsf2vfp
+ledf2
+ledf2vfp
+lesf2
+lesf2vfp
+lshrdi3
+ltdf2
+ltdf2vfp
+ltsf2
+ltsf2vfp
+moddi3
+modsi3
+muldc3
+muldf3
+muldf3vfp
+muldi3
+mulodi4
+mulosi4
+mulsc3
+mulsf3
+mulsf3vfp
+mulvdi3
+mulvsi3
+nedf2
+nedf2vfp
+negdi2
+negvdi2
+negvsi2
+nesf2
+nesf2vfp
+paritydi2
+paritysi2
+popcountdi2
+popcountsi2
+powidf2
+powisf2
+subdf3
+subdf3vfp
+subsf3
+subsf3vfp
+subvdi3
+subvsi3
+truncdfsf2
+truncdfsf2vfp
+ucmpdi2
+udivdi3
+udivmoddi4
+udivmodsi4
+udivsi3
+umoddi3
+umodsi3
+unorddf2
+unorddf2vfp
+unordsf2
+unordsf2vfp
diff --git a/lib/builtins/Darwin-excludes/ios6-armv7s.txt b/lib/builtins/Darwin-excludes/ios6-armv7s.txt
new file mode 100644
index 000000000000..b01fa711a357
--- /dev/null
+++ b/lib/builtins/Darwin-excludes/ios6-armv7s.txt
@@ -0,0 +1,120 @@
+absvdi2
+absvsi2
+adddf3
+adddf3vfp
+addsf3
+addsf3vfp
+addvdi3
+addvsi3
+ashldi3
+ashrdi3
+bswapdi2
+bswapsi2
+clzdi2
+clzsi2
+cmpdi2
+ctzdi2
+ctzsi2
+divdc3
+divdf3
+divdf3vfp
+divdi3
+divmodsi4
+divsc3
+divsf3
+divsf3vfp
+divsi3
+eqdf2
+eqdf2vfp
+eqsf2
+eqsf2vfp
+extendsfdf2
+extendsfdf2vfp
+ffsdi2
+fixdfdi
+fixdfsi
+fixdfsivfp
+fixsfdi
+fixsfsi
+fixsfsivfp
+fixunsdfdi
+fixunsdfsi
+fixunsdfsivfp
+fixunssfdi
+fixunssfsi
+fixunssfsivfp
+floatdidf
+floatdisf
+floatsidf
+floatsidfvfp
+floatsisf
+floatsisfvfp
+floatundidf
+floatundisf
+floatunsidf
+floatunsisf
+floatunssidfvfp
+floatunssisfvfp
+gcc_personality_sj0
+gedf2
+gedf2vfp
+gesf2
+gesf2vfp
+gtdf2
+gtdf2vfp
+gtsf2
+gtsf2vfp
+ledf2
+ledf2vfp
+lesf2
+lesf2vfp
+lshrdi3
+ltdf2
+ltdf2vfp
+ltsf2
+ltsf2vfp
+moddi3
+modsi3
+muldc3
+muldf3
+muldf3vfp
+muldi3
+mulodi4
+mulosi4
+mulsc3
+mulsf3
+mulsf3vfp
+mulvdi3
+mulvsi3
+nedf2
+nedf2vfp
+negdi2
+negvdi2
+negvsi2
+nesf2
+nesf2vfp
+paritydi2
+paritysi2
+popcountdi2
+popcountsi2
+powidf2
+powisf2
+subdf3
+subdf3vfp
+subsf3
+subsf3vfp
+subvdi3
+subvsi3
+truncdfsf2
+truncdfsf2vfp
+ucmpdi2
+udivdi3
+udivmoddi4
+udivmodsi4
+udivsi3
+umoddi3
+umodsi3
+unorddf2
+unorddf2vfp
+unordsf2
+unordsf2vfp
diff --git a/lib/builtins/Darwin-excludes/ios7-arm64.txt b/lib/builtins/Darwin-excludes/ios7-arm64.txt
new file mode 100644
index 000000000000..5e4caf9e9fb7
--- /dev/null
+++ b/lib/builtins/Darwin-excludes/ios7-arm64.txt
@@ -0,0 +1,16 @@
+clzti2
+divti3
+fixdfti
+fixsfti
+fixunsdfti
+floattidf
+floattisf
+floatuntidf
+floatuntisf
+gcc_personality_v0
+modti3
+powidf2
+powisf2
+udivmodti4
+udivti3
+umodti3
diff --git a/lib/builtins/Darwin-excludes/iossim-i386.txt b/lib/builtins/Darwin-excludes/iossim-i386.txt
new file mode 100644
index 000000000000..60c0e2d65056
--- /dev/null
+++ b/lib/builtins/Darwin-excludes/iossim-i386.txt
@@ -0,0 +1,82 @@
+absvti2
+addtf3
+addvti3
+ashlti3
+ashrti3
+clzti2
+cmpti2
+ctzti2
+divti3
+divtf3
+ffsti2
+fixdfti
+fixsfti
+fixunsdfti
+fixunssfti
+fixunsxfti
+fixxfti
+floattidf
+floattisf
+floattixf
+floatuntidf
+floatuntisf
+floatuntixf
+lshrti3
+modti3
+muloti4
+multi3
+multf3
+mulvti3
+negti2
+negvti2
+parityti2
+popcountti2
+powitf2
+subvti3
+subtf3
+trampoline_setup
+ucmpti2
+udivmodti4
+udivti3
+umodti3
+absvti2
+addtf3
+addvti3
+ashlti3
+ashrti3
+clzti2
+cmpti2
+ctzti2
+divti3
+divtf3
+ffsti2
+fixdfti
+fixsfti
+fixunsdfti
+fixunssfti
+fixunsxfti
+fixxfti
+floattidf
+floattisf
+floattixf
+floatuntidf
+floatuntisf
+floatuntixf
+lshrti3
+modti3
+muloti4
+multi3
+multf3
+mulvti3
+negti2
+negvti2
+parityti2
+popcountti2
+powitf2
+subvti3
+subtf3
+trampoline_setup
+ucmpti2
+udivmodti4
+udivti3
+umodti3
diff --git a/lib/builtins/Darwin-excludes/iossim-x86_64.txt b/lib/builtins/Darwin-excludes/iossim-x86_64.txt
new file mode 100644
index 000000000000..de1574e6ce3d
--- /dev/null
+++ b/lib/builtins/Darwin-excludes/iossim-x86_64.txt
@@ -0,0 +1,12 @@
+addtf3
+divtf3
+multf3
+powitf2
+subtf3
+trampoline_setup
+addtf3
+divtf3
+multf3
+powitf2
+subtf3
+trampoline_setup
diff --git a/lib/builtins/Darwin-excludes/iossim.txt b/lib/builtins/Darwin-excludes/iossim.txt
new file mode 100644
index 000000000000..5db24000a174
--- /dev/null
+++ b/lib/builtins/Darwin-excludes/iossim.txt
@@ -0,0 +1 @@
+apple_versioning
diff --git a/lib/builtins/Darwin-excludes/osx-i386.txt b/lib/builtins/Darwin-excludes/osx-i386.txt
new file mode 100644
index 000000000000..60c0e2d65056
--- /dev/null
+++ b/lib/builtins/Darwin-excludes/osx-i386.txt
@@ -0,0 +1,82 @@
+absvti2
+addtf3
+addvti3
+ashlti3
+ashrti3
+clzti2
+cmpti2
+ctzti2
+divti3
+divtf3
+ffsti2
+fixdfti
+fixsfti
+fixunsdfti
+fixunssfti
+fixunsxfti
+fixxfti
+floattidf
+floattisf
+floattixf
+floatuntidf
+floatuntisf
+floatuntixf
+lshrti3
+modti3
+muloti4
+multi3
+multf3
+mulvti3
+negti2
+negvti2
+parityti2
+popcountti2
+powitf2
+subvti3
+subtf3
+trampoline_setup
+ucmpti2
+udivmodti4
+udivti3
+umodti3
+absvti2
+addtf3
+addvti3
+ashlti3
+ashrti3
+clzti2
+cmpti2
+ctzti2
+divti3
+divtf3
+ffsti2
+fixdfti
+fixsfti
+fixunsdfti
+fixunssfti
+fixunsxfti
+fixxfti
+floattidf
+floattisf
+floattixf
+floatuntidf
+floatuntisf
+floatuntixf
+lshrti3
+modti3
+muloti4
+multi3
+multf3
+mulvti3
+negti2
+negvti2
+parityti2
+popcountti2
+powitf2
+subvti3
+subtf3
+trampoline_setup
+ucmpti2
+udivmodti4
+udivti3
+umodti3
diff --git a/lib/builtins/Darwin-excludes/osx-x86_64.txt b/lib/builtins/Darwin-excludes/osx-x86_64.txt
new file mode 100644
index 000000000000..de1574e6ce3d
--- /dev/null
+++ b/lib/builtins/Darwin-excludes/osx-x86_64.txt
@@ -0,0 +1,12 @@
+addtf3
+divtf3
+multf3
+powitf2
+subtf3
+trampoline_setup
+addtf3
+divtf3
+multf3
+powitf2
+subtf3
+trampoline_setup
diff --git a/lib/builtins/Darwin-excludes/osx.txt b/lib/builtins/Darwin-excludes/osx.txt
new file mode 100644
index 000000000000..5db24000a174
--- /dev/null
+++ b/lib/builtins/Darwin-excludes/osx.txt
@@ -0,0 +1 @@
+apple_versioning
diff --git a/lib/builtins/README.txt b/lib/builtins/README.txt
index 1c08e7415e64..ad36e4e5279a 100644
--- a/lib/builtins/README.txt
+++ b/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/lib/builtins/arm/aeabi_cdcmp.S b/lib/builtins/arm/aeabi_cdcmp.S
new file mode 100644
index 000000000000..036a6f542f79
--- /dev/null
+++ b/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/lib/builtins/arm/aeabi_cdcmpeq_check_nan.c b/lib/builtins/arm/aeabi_cdcmpeq_check_nan.c
new file mode 100644
index 000000000000..577f6b2c5535
--- /dev/null
+++ b/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/lib/builtins/arm/aeabi_cfcmp.S b/lib/builtins/arm/aeabi_cfcmp.S
new file mode 100644
index 000000000000..43594e5c3936
--- /dev/null
+++ b/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/lib/builtins/arm/aeabi_cfcmpeq_check_nan.c b/lib/builtins/arm/aeabi_cfcmpeq_check_nan.c
new file mode 100644
index 000000000000..992e31fbd8d6
--- /dev/null
+++ b/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/lib/builtins/arm/aeabi_drsub.c b/lib/builtins/arm/aeabi_drsub.c
new file mode 100644
index 000000000000..fc17d5a4cc76
--- /dev/null
+++ b/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/lib/builtins/arm/aeabi_frsub.c b/lib/builtins/arm/aeabi_frsub.c
new file mode 100644
index 000000000000..64258dc7e070
--- /dev/null
+++ b/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/lib/builtins/assembly.h b/lib/builtins/assembly.h
index 8bb0ddc106bd..c28970534cc4 100644
--- a/lib/builtins/assembly.h
+++ b/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/lib/builtins/atomic.c b/lib/builtins/atomic.c
index 35c8837dcecf..f1ddc3e0c522 100644
--- a/lib/builtins/atomic.c
+++ b/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/lib/builtins/atomic_flag_clear.c b/lib/builtins/atomic_flag_clear.c
index 15984cd5267d..da912af64312 100644
--- a/lib/builtins/atomic_flag_clear.c
+++ b/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/lib/builtins/atomic_flag_clear_explicit.c b/lib/builtins/atomic_flag_clear_explicit.c
index 0f7859c2cd82..1059b787f169 100644
--- a/lib/builtins/atomic_flag_clear_explicit.c
+++ b/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/lib/builtins/atomic_flag_test_and_set.c b/lib/builtins/atomic_flag_test_and_set.c
index 07209fc02d5e..e8811d39ef25 100644
--- a/lib/builtins/atomic_flag_test_and_set.c
+++ b/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/lib/builtins/atomic_flag_test_and_set_explicit.c b/lib/builtins/atomic_flag_test_and_set_explicit.c
index eaa5be08df46..5c8c2df90543 100644
--- a/lib/builtins/atomic_flag_test_and_set_explicit.c
+++ b/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/lib/builtins/atomic_signal_fence.c b/lib/builtins/atomic_signal_fence.c
index ad292d2f1c72..9ccc2ae60ad8 100644
--- a/lib/builtins/atomic_signal_fence.c
+++ b/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/lib/builtins/atomic_thread_fence.c b/lib/builtins/atomic_thread_fence.c
index 71f698c9de75..d22560151bc8 100644
--- a/lib/builtins/atomic_thread_fence.c
+++ b/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/lib/builtins/comparedf2.c b/lib/builtins/comparedf2.c
index 64eea1249055..9e29752231e9 100644
--- a/lib/builtins/comparedf2.c
+++ b/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/lib/builtins/comparesf2.c b/lib/builtins/comparesf2.c
index 442289c1004e..1fd50636abaf 100644
--- a/lib/builtins/comparesf2.c
+++ b/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/lib/builtins/comparetf2.c b/lib/builtins/comparetf2.c
index a6436de89e76..c0ad8ed0aecd 100644
--- a/lib/builtins/comparetf2.c
+++ b/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/lib/builtins/divdc3.c b/lib/builtins/divdc3.c
index 7de78c8711e1..3c88390b5e77 100644
--- a/lib/builtins/divdc3.c
+++ b/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/lib/builtins/divsc3.c b/lib/builtins/divsc3.c
index 710d5320803f..42a48315e66d 100644
--- a/lib/builtins/divsc3.c
+++ b/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/lib/builtins/divtc3.c b/lib/builtins/divtc3.c
new file mode 100644
index 000000000000..04693df471ff
--- /dev/null
+++ b/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/lib/builtins/divxc3.c b/lib/builtins/divxc3.c
index 175ae3cf4aee..6f49280e5f61 100644
--- a/lib/builtins/divxc3.c
+++ b/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/lib/builtins/emutls.c b/lib/builtins/emutls.c
new file mode 100644
index 000000000000..09e79568bd56
--- /dev/null
+++ b/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/lib/builtins/enable_execute_stack.c b/lib/builtins/enable_execute_stack.c
index 23e494051adf..0dc3482c4467 100644
--- a/lib/builtins/enable_execute_stack.c
+++ b/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/lib/builtins/extendhfsf2.c b/lib/builtins/extendhfsf2.c
index 7524e2ea7ed6..27115a48c184 100644
--- a/lib/builtins/extendhfsf2.c
+++ b/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/lib/builtins/fixunsdfdi.c b/lib/builtins/fixunsdfdi.c
index 2e0d87eacf05..4b0bc9e1d051 100644
--- a/lib/builtins/fixunsdfdi.c
+++ b/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/lib/builtins/fixunssfdi.c b/lib/builtins/fixunssfdi.c
index 5a154e82cff4..f8ebab854f95 100644
--- a/lib/builtins/fixunssfdi.c
+++ b/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/lib/builtins/floatdidf.c b/lib/builtins/floatdidf.c
index e53fa2580f6e..a300c9f312d2 100644
--- a/lib/builtins/floatdidf.c
+++ b/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/lib/builtins/floatditf.c b/lib/builtins/floatditf.c
new file mode 100644
index 000000000000..cd51dd8aade4
--- /dev/null
+++ b/lib/builtins/floatditf.c
@@ -0,0 +1,50 @@
+//===-- lib/floatditf.c - integer -> quad-precision conversion ----*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements di_int to quad-precision conversion for the
+// compiler-rt library in the IEEE-754 default round-to-nearest, ties-to-even
+// mode.
+//
+//===----------------------------------------------------------------------===//
+
+#define QUAD_PRECISION
+#include "fp_lib.h"
+
+#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
+COMPILER_RT_ABI fp_t __floatditf(di_int a) {
+
+ const int aWidth = sizeof a * CHAR_BIT;
+
+ // Handle zero as a special case to protect clz
+ if (a == 0)
+ return fromRep(0);
+
+ // All other cases begin by extracting the sign and absolute value of a
+ rep_t sign = 0;
+ du_int aAbs = (du_int)a;
+ if (a < 0) {
+ sign = signBit;
+ aAbs = ~(du_int)a + 1U;
+ }
+
+ // Exponent of (fp_t)a is the width of abs(a).
+ const int exponent = (aWidth - 1) - __builtin_clzll(aAbs);
+ rep_t result;
+
+ // Shift a into the significand field, rounding if it is a right-shift
+ const int shift = significandBits - exponent;
+ result = (rep_t)aAbs << shift ^ implicitBit;
+
+ // Insert the exponent
+ result += (rep_t)(exponent + exponentBias) << significandBits;
+ // Insert the sign bit and return
+ return fromRep(result | sign);
+}
+
+#endif
diff --git a/lib/builtins/floatsitf.c b/lib/builtins/floatsitf.c
index 85346933f81e..f0abca363b5e 100644
--- a/lib/builtins/floatsitf.c
+++ b/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/lib/builtins/floatundidf.c b/lib/builtins/floatundidf.c
index 73b8bac1c1a1..67aa86e5e5b8 100644
--- a/lib/builtins/floatundidf.c
+++ b/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/lib/builtins/floatunditf.c b/lib/builtins/floatunditf.c
new file mode 100644
index 000000000000..8098e95e82bc
--- /dev/null
+++ b/lib/builtins/floatunditf.c
@@ -0,0 +1,40 @@
+//===-- lib/floatunditf.c - uint -> quad-precision conversion -----*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements du_int to quad-precision conversion for the
+// compiler-rt library in the IEEE-754 default round-to-nearest, ties-to-even
+// mode.
+//
+//===----------------------------------------------------------------------===//
+
+#define QUAD_PRECISION
+#include "fp_lib.h"
+
+#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
+COMPILER_RT_ABI fp_t __floatunditf(du_int a) {
+
+ const int aWidth = sizeof a * CHAR_BIT;
+
+ // Handle zero as a special case to protect clz
+ if (a == 0) return fromRep(0);
+
+ // Exponent of (fp_t)a is the width of abs(a).
+ const int exponent = (aWidth - 1) - __builtin_clzll(a);
+ rep_t result;
+
+ // Shift a into the significand field and clear the implicit bit.
+ const int shift = significandBits - exponent;
+ result = (rep_t)a << shift ^ implicitBit;
+
+ // Insert the exponent
+ result += (rep_t)(exponent + exponentBias) << significandBits;
+ return fromRep(result);
+}
+
+#endif
diff --git a/lib/builtins/fp_add_impl.inc b/lib/builtins/fp_add_impl.inc
index 5741889728cd..b47be1b648e6 100644
--- a/lib/builtins/fp_add_impl.inc
+++ b/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/lib/builtins/fp_extend.h b/lib/builtins/fp_extend.h
index 5c2b92310df1..6d95a0680709 100644
--- a/lib/builtins/fp_extend.h
+++ b/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/lib/builtins/fp_extend_impl.inc b/lib/builtins/fp_extend_impl.inc
index edcfa8d2329d..b785cc7687ad 100644
--- a/lib/builtins/fp_extend_impl.inc
+++ b/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/lib/builtins/fp_fixint_impl.inc b/lib/builtins/fp_fixint_impl.inc
index 035e87ca10e0..da70d4d39301 100644
--- a/lib/builtins/fp_fixint_impl.inc
+++ b/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/lib/builtins/fp_fixuint_impl.inc b/lib/builtins/fp_fixuint_impl.inc
index 5fefab0e2d8a..d68ccf27a79c 100644
--- a/lib/builtins/fp_fixuint_impl.inc
+++ b/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/lib/builtins/fp_lib.h b/lib/builtins/fp_lib.h
index faebb99ecd5e..223fb980aaed 100644
--- a/lib/builtins/fp_lib.h
+++ b/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/lib/builtins/fp_mul_impl.inc b/lib/builtins/fp_mul_impl.inc
index ca8a0bb98b10..b34aa1b8f544 100644
--- a/lib/builtins/fp_mul_impl.inc
+++ b/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/lib/builtins/fp_trunc.h b/lib/builtins/fp_trunc.h
index 373ba1b0411d..d5e79bb5b863 100644
--- a/lib/builtins/fp_trunc.h
+++ b/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/lib/builtins/fp_trunc_impl.inc b/lib/builtins/fp_trunc_impl.inc
index 372e8d6014dd..d88ae060913f 100644
--- a/lib/builtins/fp_trunc_impl.inc
+++ b/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/lib/builtins/gcc_personality_v0.c b/lib/builtins/gcc_personality_v0.c
index 4b95cfd43b05..ed544d30b809 100644
--- a/lib/builtins/gcc_personality_v0.c
+++ b/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/lib/builtins/i386/chkstk.S b/lib/builtins/i386/chkstk.S
index 3733d722ef19..b59974868f21 100644
--- a/lib/builtins/i386/chkstk.S
+++ b/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/lib/builtins/i386/chkstk2.S b/lib/builtins/i386/chkstk2.S
new file mode 100644
index 000000000000..7d65bb088928
--- /dev/null
+++ b/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/lib/builtins/int_lib.h b/lib/builtins/int_lib.h
index bca5d81d4414..e66cda3fffb4 100644
--- a/lib/builtins/int_lib.h
+++ b/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__
@@ -28,13 +35,25 @@
# define COMPILER_RT_ABI __attribute__((pcs("aapcs")))
#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,
@@ -71,4 +90,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/lib/builtins/int_math.h b/lib/builtins/int_math.h
index d6b4bdae162b..fc81fb7f0220 100644
--- a/lib/builtins/int_math.h
+++ b/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/lib/builtins/int_types.h b/lib/builtins/int_types.h
index aedae14b2046..2dad43bc7389 100644
--- a/lib/builtins/int_types.h
+++ b/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;
@@ -95,14 +99,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 +144,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/lib/builtins/int_util.c b/lib/builtins/int_util.c
index 323e46179e6c..420d1e237aae 100644
--- a/lib/builtins/int_util.c
+++ b/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/lib/builtins/int_util.h b/lib/builtins/int_util.h
index a9b595db8d0f..a7b20ed66244 100644
--- a/lib/builtins/int_util.h
+++ b/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/lib/builtins/macho_embedded/CMakeLists.txt b/lib/builtins/macho_embedded/CMakeLists.txt
new file mode 100644
index 000000000000..266e42215243
--- /dev/null
+++ b/lib/builtins/macho_embedded/CMakeLists.txt
@@ -0,0 +1,4 @@
+file(GLOB filter_files ${CMAKE_CURRENT_SOURCE_DIR}/*.txt)
+foreach(filter_file ${filter_files})
+ set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${filter_file})
+endforeach()
diff --git a/lib/builtins/macho_embedded/arm.txt b/lib/builtins/macho_embedded/arm.txt
new file mode 100644
index 000000000000..4b1683a6baef
--- /dev/null
+++ b/lib/builtins/macho_embedded/arm.txt
@@ -0,0 +1,16 @@
+aeabi_cdcmpeq
+aeabi_cdrcmple
+aeabi_cfcmpeq
+aeabi_cfrcmple
+aeabi_dcmpeq
+aeabi_dcmpge
+aeabi_dcmpgt
+aeabi_dcmple
+aeabi_dcmplt
+aeabi_drsub
+aeabi_fcmpeq
+aeabi_fcmpge
+aeabi_fcmpgt
+aeabi_fcmple
+aeabi_fcmplt
+aeabi_frsub
diff --git a/lib/builtins/macho_embedded/common.txt b/lib/builtins/macho_embedded/common.txt
new file mode 100644
index 000000000000..6ac85a771fcb
--- /dev/null
+++ b/lib/builtins/macho_embedded/common.txt
@@ -0,0 +1,92 @@
+absvdi2
+absvsi2
+addvdi3
+addvsi3
+ashldi3
+ashrdi3
+clzdi2
+clzsi2
+cmpdi2
+ctzdi2
+ctzsi2
+divdc3
+divdi3
+divsc3
+divmodsi4
+udivmodsi4
+do_global_dtors
+ffsdi2
+fixdfdi
+fixsfdi
+fixunsdfdi
+fixunsdfsi
+fixunssfdi
+fixunssfsi
+floatdidf
+floatdisf
+floatundidf
+floatundisf
+gcc_bcmp
+lshrdi3
+moddi3
+muldc3
+muldi3
+mulsc3
+mulvdi3
+mulvsi3
+negdi2
+negvdi2
+negvsi2
+paritydi2
+paritysi2
+popcountdi2
+popcountsi2
+powidf2
+powisf2
+subvdi3
+subvsi3
+ucmpdi2
+udiv_w_sdiv
+udivdi3
+udivmoddi4
+umoddi3
+adddf3
+addsf3
+cmpdf2
+cmpsf2
+div0
+divdf3
+divsf3
+divsi3
+extendsfdf2
+extendhfsf2
+ffssi2
+fixdfsi
+fixsfsi
+floatsidf
+floatsisf
+floatunsidf
+floatunsisf
+comparedf2
+comparesf2
+modsi3
+muldf3
+mulsf3
+negdf2
+negsf2
+subdf3
+subsf3
+truncdfhf2
+truncdfsf2
+truncsfhf2
+udivsi3
+umodsi3
+unorddf2
+unordsf2
+atomic_flag_clear
+atomic_flag_clear_explicit
+atomic_flag_test_and_set
+atomic_flag_test_and_set_explicit
+atomic_signal_fence
+atomic_thread_fence
+int_util
diff --git a/lib/builtins/macho_embedded/i386.txt b/lib/builtins/macho_embedded/i386.txt
new file mode 100644
index 000000000000..b92e44bb35ae
--- /dev/null
+++ b/lib/builtins/macho_embedded/i386.txt
@@ -0,0 +1,7 @@
+i686.get_pc_thunk.eax
+i686.get_pc_thunk.ebp
+i686.get_pc_thunk.ebx
+i686.get_pc_thunk.ecx
+i686.get_pc_thunk.edi
+i686.get_pc_thunk.edx
+i686.get_pc_thunk.esi
diff --git a/lib/builtins/macho_embedded/thumb2-64.txt b/lib/builtins/macho_embedded/thumb2-64.txt
new file mode 100644
index 000000000000..1c72fb1c3c64
--- /dev/null
+++ b/lib/builtins/macho_embedded/thumb2-64.txt
@@ -0,0 +1,10 @@
+sync_fetch_and_add_8
+sync_fetch_and_sub_8
+sync_fetch_and_and_8
+sync_fetch_and_or_8
+sync_fetch_and_xor_8
+sync_fetch_and_nand_8
+sync_fetch_and_max_8
+sync_fetch_and_umax_8
+sync_fetch_and_min_8
+sync_fetch_and_umin_8
diff --git a/lib/builtins/macho_embedded/thumb2.txt b/lib/builtins/macho_embedded/thumb2.txt
new file mode 100644
index 000000000000..6add5ecd2dc7
--- /dev/null
+++ b/lib/builtins/macho_embedded/thumb2.txt
@@ -0,0 +1,14 @@
+switch16
+switch32
+switch8
+switchu8
+sync_fetch_and_add_4
+sync_fetch_and_sub_4
+sync_fetch_and_and_4
+sync_fetch_and_or_4
+sync_fetch_and_xor_4
+sync_fetch_and_nand_4
+sync_fetch_and_max_4
+sync_fetch_and_umax_4
+sync_fetch_and_min_4
+sync_fetch_and_umin_4
diff --git a/lib/builtins/muldc3.c b/lib/builtins/muldc3.c
index 3bfae2c52224..16d8e98390a3 100644
--- a/lib/builtins/muldc3.c
+++ b/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/lib/builtins/mulsc3.c b/lib/builtins/mulsc3.c
index 29d46c63a799..c89cfd247a15 100644
--- a/lib/builtins/mulsc3.c
+++ b/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/lib/builtins/multc3.c b/lib/builtins/multc3.c
new file mode 100644
index 000000000000..0518bc2569f1
--- /dev/null
+++ b/lib/builtins/multc3.c
@@ -0,0 +1,68 @@
+/* ===-- multc3.c - Implement __multc3 -------------------------------------===
+ *
+ * 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 __multc3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+#include "int_math.h"
+
+/* Returns: the product of a + ib and c + id */
+
+COMPILER_RT_ABI long double _Complex
+__multc3(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)) {
+ int recalc = 0;
+ if (crt_isinf(a) || crt_isinf(b)) {
+ a = crt_copysignl(crt_isinf(a) ? 1 : 0, a);
+ b = crt_copysignl(crt_isinf(b) ? 1 : 0, b);
+ if (crt_isnan(c))
+ c = crt_copysignl(0, c);
+ if (crt_isnan(d))
+ d = crt_copysignl(0, d);
+ recalc = 1;
+ }
+ if (crt_isinf(c) || crt_isinf(d)) {
+ c = crt_copysignl(crt_isinf(c) ? 1 : 0, c);
+ d = crt_copysignl(crt_isinf(d) ? 1 : 0, d);
+ if (crt_isnan(a))
+ a = crt_copysignl(0, a);
+ if (crt_isnan(b))
+ b = crt_copysignl(0, b);
+ recalc = 1;
+ }
+ if (!recalc && (crt_isinf(ac) || crt_isinf(bd) ||
+ crt_isinf(ad) || crt_isinf(bc))) {
+ if (crt_isnan(a))
+ a = crt_copysignl(0, a);
+ if (crt_isnan(b))
+ b = crt_copysignl(0, b);
+ if (crt_isnan(c))
+ c = crt_copysignl(0, c);
+ if (crt_isnan(d))
+ d = crt_copysignl(0, d);
+ recalc = 1;
+ }
+ if (recalc) {
+ __real__ z = CRT_INFINITY * (a * c - b * d);
+ __imag__ z = CRT_INFINITY * (a * d + b * c);
+ }
+ }
+ return z;
+}
diff --git a/lib/builtins/mulxc3.c b/lib/builtins/mulxc3.c
index 161fd0ce0dd4..ba3221691821 100644
--- a/lib/builtins/mulxc3.c
+++ b/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/lib/builtins/ppc/DD.h b/lib/builtins/ppc/DD.h
index fc3e41cbe07e..3e5f9e58c138 100644
--- a/lib/builtins/ppc/DD.h
+++ b/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/lib/builtins/ppc/divtc3.c b/lib/builtins/ppc/divtc3.c
index 299128186312..8ec41c528ab9 100644
--- a/lib/builtins/ppc/divtc3.c
+++ b/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/lib/builtins/ppc/multc3.c b/lib/builtins/ppc/multc3.c
index 738b65a83b03..9dd79c975dde 100644
--- a/lib/builtins/ppc/multc3.c
+++ b/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/lib/builtins/subdf3.c b/lib/builtins/subdf3.c
index 089e062415b7..7a79e5e7765d 100644
--- a/lib/builtins/subdf3.c
+++ b/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/lib/builtins/subsf3.c b/lib/builtins/subsf3.c
index 47f5e5e46ea8..c3b85144af48 100644
--- a/lib/builtins/subsf3.c
+++ b/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/lib/builtins/truncdfhf2.c b/lib/builtins/truncdfhf2.c
index 0852df369625..17195cd9e799 100644
--- a/lib/builtins/truncdfhf2.c
+++ b/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/lib/builtins/truncsfhf2.c b/lib/builtins/truncsfhf2.c
index 381e590c342f..9d61895bfd88 100644
--- a/lib/builtins/truncsfhf2.c
+++ b/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/lib/builtins/x86_64/chkstk.S b/lib/builtins/x86_64/chkstk.S
index 5759e84498c6..4149ac63d9d0 100644
--- a/lib/builtins/x86_64/chkstk.S
+++ b/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/lib/builtins/x86_64/chkstk2.S b/lib/builtins/x86_64/chkstk2.S
new file mode 100644
index 000000000000..ac1eb920e0e8
--- /dev/null
+++ b/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/lib/cfi/CMakeLists.txt b/lib/cfi/CMakeLists.txt
new file mode 100644
index 000000000000..24e51814cdab
--- /dev/null
+++ b/lib/cfi/CMakeLists.txt
@@ -0,0 +1,40 @@
+add_custom_target(cfi)
+
+set(CFI_SOURCES cfi.cc)
+
+include_directories(..)
+
+set(CFI_CFLAGS
+ ${SANITIZER_COMMON_CFLAGS}
+)
+
+set(CFI_DIAG_CFLAGS
+ -DCFI_ENABLE_DIAG=1
+)
+
+foreach(arch ${CFI_SUPPORTED_ARCH})
+ add_compiler_rt_runtime(clang_rt.cfi
+ STATIC
+ ARCHS ${arch}
+ SOURCES ${CFI_SOURCES}
+ OBJECT_LIBS RTInterception
+ RTSanitizerCommon
+ RTSanitizerCommonLibc
+ CFLAGS ${CFI_CFLAGS}
+ PARENT_TARGET cfi)
+ add_compiler_rt_runtime(clang_rt.cfi_diag
+ STATIC
+ ARCHS ${arch}
+ SOURCES ${CFI_SOURCES}
+ OBJECT_LIBS RTInterception
+ RTSanitizerCommon
+ RTSanitizerCommonLibc
+ RTUbsan
+ RTUbsan_cxx
+ CFLAGS ${CFI_CFLAGS} ${CFI_DIAG_CFLAGS}
+ PARENT_TARGET cfi)
+endforeach()
+
+add_compiler_rt_resource_file(cfi_blacklist cfi_blacklist.txt)
+add_dependencies(cfi cfi_blacklist)
+add_dependencies(compiler-rt cfi)
diff --git a/lib/cfi/cfi.cc b/lib/cfi/cfi.cc
new file mode 100644
index 000000000000..0e2a09190699
--- /dev/null
+++ b/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)(uptr, 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(uptr CallSiteTypeId, void *Ptr) {
+ uptr Addr = (uptr)Ptr;
+ VReport(3, "__cfi_slowpath: %zx, %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/lib/cfi/cfi_blacklist.txt b/lib/cfi/cfi_blacklist.txt
new file mode 100644
index 000000000000..1f0eeb355617
--- /dev/null
+++ b/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/lib/dfsan/.clang-format b/lib/dfsan/.clang-format
new file mode 100644
index 000000000000..f6cb8ad931f5
--- /dev/null
+++ b/lib/dfsan/.clang-format
@@ -0,0 +1 @@
+BasedOnStyle: Google
diff --git a/lib/dfsan/CMakeLists.txt b/lib/dfsan/CMakeLists.txt
index 24ea876f210d..19a7909d0429 100644
--- a/lib/dfsan/CMakeLists.txt
+++ b/lib/dfsan/CMakeLists.txt
@@ -15,20 +15,19 @@ add_custom_target(dfsan)
foreach(arch ${DFSAN_SUPPORTED_ARCH})
set(DFSAN_CFLAGS ${DFSAN_COMMON_CFLAGS})
append_list_if(COMPILER_RT_HAS_FPIE_FLAG -fPIE DFSAN_CFLAGS)
- add_compiler_rt_runtime(clang_rt.dfsan-${arch} ${arch} STATIC
+ add_compiler_rt_runtime(clang_rt.dfsan
+ STATIC
+ ARCHS ${arch}
SOURCES ${DFSAN_RTL_SOURCES}
$<TARGET_OBJECTS:RTInterception.${arch}>
$<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
$<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>
- CFLAGS ${DFSAN_CFLAGS})
- set(DFSAN_NOLIBC_CFLAGS ${DFSAN_COMMON_CFLAGS} -DDFSAN_NOLIBC)
- add_compiler_rt_runtime(clang_rt.dfsan-libc-${arch} ${arch} STATIC
- SOURCES ${DFSAN_RTL_SOURCES}
- $<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
- CFLAGS ${DFSAN_NOLIBC_CFLAGS})
- add_sanitizer_rt_symbols(clang_rt.dfsan-${arch} dfsan.syms.extra)
+ CFLAGS ${DFSAN_CFLAGS}
+ PARENT_TARGET dfsan)
+ add_sanitizer_rt_symbols(clang_rt.dfsan
+ ARCHS ${arch}
+ EXTRA dfsan.syms.extra)
add_dependencies(dfsan
- clang_rt.dfsan-${arch}
clang_rt.dfsan-${arch}-symbols)
endforeach()
diff --git a/lib/dfsan/dfsan.cc b/lib/dfsan/dfsan.cc
index d2e137e129c1..7285f202d060 100644
--- a/lib/dfsan/dfsan.cc
+++ b/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/lib/dfsan/dfsan.h b/lib/dfsan/dfsan.h
index ceba3533a233..81f949e3019e 100644
--- a/lib/dfsan/dfsan.h
+++ b/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/lib/dfsan/dfsan_custom.cc b/lib/dfsan/dfsan_custom.cc
index c58b471db53c..e0cd16ab695c 100644
--- a/lib/dfsan/dfsan_custom.cc
+++ b/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/lib/dfsan/dfsan_platform.h b/lib/dfsan/dfsan_platform.h
new file mode 100644
index 000000000000..f1d9f108e908
--- /dev/null
+++ b/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/lib/dfsan/done_abilist.txt b/lib/dfsan/done_abilist.txt
index e6c077ff1208..7ca8aeba32fe 100644
--- a/lib/dfsan/done_abilist.txt
+++ b/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/lib/interception/.clang-format b/lib/interception/.clang-format
new file mode 100644
index 000000000000..f6cb8ad931f5
--- /dev/null
+++ b/lib/interception/.clang-format
@@ -0,0 +1 @@
+BasedOnStyle: Google
diff --git a/lib/interception/interception_linux.h b/lib/interception/interception_linux.h
index d3f774bede9f..27a66c882041 100644
--- a/lib/interception/interception_linux.h
+++ b/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/lib/interception/interception_win.cc b/lib/interception/interception_win.cc
index 19cf184948b9..4c04c83b982b 100644
--- a/lib/interception/interception_win.cc
+++ b/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/lib/interception/interception_win.h b/lib/interception/interception_win.h
index ba768a7233f9..96c4a0c0f5a3 100644
--- a/lib/interception/interception_win.h
+++ b/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/lib/lsan/.clang-format b/lib/lsan/.clang-format
new file mode 100644
index 000000000000..f6cb8ad931f5
--- /dev/null
+++ b/lib/lsan/.clang-format
@@ -0,0 +1 @@
+BasedOnStyle: Google
diff --git a/lib/lsan/CMakeLists.txt b/lib/lsan/CMakeLists.txt
index 37f794e2e11b..20e40932165c 100644
--- a/lib/lsan/CMakeLists.txt
+++ b/lib/lsan/CMakeLists.txt
@@ -26,14 +26,16 @@ add_compiler_rt_object_libraries(RTLSanCommon
if(COMPILER_RT_HAS_LSAN)
foreach(arch ${LSAN_SUPPORTED_ARCH})
- add_compiler_rt_runtime(clang_rt.lsan-${arch} ${arch} STATIC
+ add_compiler_rt_runtime(clang_rt.lsan
+ STATIC
+ ARCHS ${arch}
SOURCES ${LSAN_SOURCES}
$<TARGET_OBJECTS:RTInterception.${arch}>
$<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
$<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>
$<TARGET_OBJECTS:RTLSanCommon.${arch}>
- CFLAGS ${LSAN_CFLAGS})
- add_dependencies(lsan clang_rt.lsan-${arch})
+ CFLAGS ${LSAN_CFLAGS}
+ PARENT_TARGET lsan)
endforeach()
endif()
diff --git a/lib/lsan/lsan.cc b/lib/lsan/lsan.cc
index 6018f7bf6f49..f3e6ad7c9cba 100644
--- a/lib/lsan/lsan.cc
+++ b/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/lib/lsan/lsan_allocator.cc b/lib/lsan/lsan_allocator.cc
index 67125dbb3e45..0a3678132ae1 100644
--- a/lib/lsan/lsan_allocator.cc
+++ b/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/lib/lsan/lsan_common.cc b/lib/lsan/lsan_common.cc
index 0ffba505cc70..1cffac44395c 100644
--- a/lib/lsan/lsan_common.cc
+++ b/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/lib/lsan/lsan_common.h b/lib/lsan/lsan_common.h
index 4f9d24fb3ab9..0dfd0d4c9890 100644
--- a/lib/lsan/lsan_common.h
+++ b/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/lib/lsan/lsan_common_linux.cc b/lib/lsan/lsan_common_linux.cc
index 2955343e1f0b..1dc0561dab71 100644
--- a/lib/lsan/lsan_common_linux.cc
+++ b/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/lib/lsan/lsan_flags.inc b/lib/lsan/lsan_flags.inc
index b19b3452b2fc..c405005deed5 100644
--- a/lib/lsan/lsan_flags.inc
+++ b/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/lib/lsan/lsan_interceptors.cc b/lib/lsan/lsan_interceptors.cc
index 61a92154d95e..be0d0ddc282e 100644
--- a/lib/lsan/lsan_interceptors.cc
+++ b/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/lib/lsan/lsan_thread.cc b/lib/lsan/lsan_thread.cc
index 0f8efc093b56..10ac2c9f499d 100644
--- a/lib/lsan/lsan_thread.cc
+++ b/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/lib/msan/.clang-format b/lib/msan/.clang-format
new file mode 100644
index 000000000000..f6cb8ad931f5
--- /dev/null
+++ b/lib/msan/.clang-format
@@ -0,0 +1 @@
+BasedOnStyle: Google
diff --git a/lib/msan/CMakeLists.txt b/lib/msan/CMakeLists.txt
index de5980e5644b..1b48def46280 100644
--- a/lib/msan/CMakeLists.txt
+++ b/lib/msan/CMakeLists.txt
@@ -27,24 +27,32 @@ set(MSAN_RUNTIME_LIBRARIES)
# Static runtime library.
add_custom_target(msan)
foreach(arch ${MSAN_SUPPORTED_ARCH})
- add_compiler_rt_runtime(clang_rt.msan-${arch} ${arch} STATIC
+ add_compiler_rt_runtime(clang_rt.msan
+ STATIC
+ ARCHS ${arch}
SOURCES ${MSAN_RTL_SOURCES}
$<TARGET_OBJECTS:RTInterception.${arch}>
$<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
$<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>
$<TARGET_OBJECTS:RTUbsan.${arch}>
- CFLAGS ${MSAN_RTL_CFLAGS})
- add_compiler_rt_runtime(clang_rt.msan_cxx-${arch} ${arch} STATIC
+ CFLAGS ${MSAN_RTL_CFLAGS}
+ PARENT_TARGET msan)
+ add_compiler_rt_runtime(clang_rt.msan_cxx
+ STATIC
+ ARCHS ${arch}
SOURCES ${MSAN_RTL_CXX_SOURCES}
$<TARGET_OBJECTS:RTUbsan_cxx.${arch}>
- CFLAGS ${MSAN_RTL_CFLAGS})
- add_dependencies(msan clang_rt.msan-${arch}
- clang_rt.msan_cxx-${arch})
+ CFLAGS ${MSAN_RTL_CFLAGS}
+ PARENT_TARGET msan)
list(APPEND MSAN_RUNTIME_LIBRARIES clang_rt.msan-${arch}
clang_rt.msan_cxx-${arch})
if(UNIX)
- add_sanitizer_rt_symbols(clang_rt.msan-${arch} msan.syms.extra)
- add_sanitizer_rt_symbols(clang_rt.msan_cxx-${arch} msan.syms.extra)
+ add_sanitizer_rt_symbols(clang_rt.msan
+ ARCHS ${arch}
+ EXTRA msan.syms.extra)
+ add_sanitizer_rt_symbols(clang_rt.msan_cxx
+ ARCHS ${arch}
+ EXTRA msan.syms.extra)
add_dependencies(msan clang_rt.msan-${arch}-symbols
clang_rt.msan_cxx-${arch}-symbols)
endif()
diff --git a/lib/msan/msan.cc b/lib/msan/msan.cc
index 163d59dabfa8..9949db4c13a0 100644
--- a/lib/msan/msan.cc
+++ b/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/lib/msan/msan.h b/lib/msan/msan.h
index cd8bc19f51ef..2079a592b7b9 100644
--- a/lib/msan/msan.h
+++ b/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/lib/msan/msan_allocator.cc b/lib/msan/msan_allocator.cc
index 6df35664279f..b7d394729bfc 100644
--- a/lib/msan/msan_allocator.cc
+++ b/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/lib/msan/msan_chained_origin_depot.cc b/lib/msan/msan_chained_origin_depot.cc
index c21e8e82746a..e2796fd46464 100644
--- a/lib/msan/msan_chained_origin_depot.cc
+++ b/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/lib/msan/msan_flags.inc b/lib/msan/msan_flags.inc
index cb58ffc4aba7..a7ff6c586071 100644
--- a/lib/msan/msan_flags.inc
+++ b/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/lib/msan/msan_interceptors.cc b/lib/msan/msan_interceptors.cc
index 6d5a056a3bb3..fc28e080f262 100644
--- a/lib/msan/msan_interceptors.cc
+++ b/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/lib/msan/msan_interface_internal.h b/lib/msan/msan_interface_internal.h
index f4d37d96c5b5..c1e02ce72bf4 100644
--- a/lib/msan/msan_interface_internal.h
+++ b/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/lib/msan/msan_linux.cc b/lib/msan/msan_linux.cc
index 7025ef6c812d..ab3be91fcf8d 100644
--- a/lib/msan/msan_linux.cc
+++ b/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/lib/msan/msan_new_delete.cc b/lib/msan/msan_new_delete.cc
index c8bc0651b507..540100316693 100644
--- a/lib/msan/msan_new_delete.cc
+++ b/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/lib/msan/msan_thread.h b/lib/msan/msan_thread.h
index bc605b89a505..ed22e67edd50 100644
--- a/lib/msan/msan_thread.h
+++ b/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/lib/msan/tests/CMakeLists.txt b/lib/msan/tests/CMakeLists.txt
index bf16a16bcf20..087b1afbd5b3 100644
--- a/lib/msan/tests/CMakeLists.txt
+++ b/lib/msan/tests/CMakeLists.txt
@@ -18,13 +18,13 @@ set(MSAN_UNITTEST_HEADERS
../../../include/sanitizer/msan_interface.h
)
set(MSAN_UNITTEST_COMMON_CFLAGS
- -I${COMPILER_RT_LIBCXX_PATH}/include
+ -nostdinc++
+ -isystem ${COMPILER_RT_LIBCXX_PATH}/include
${COMPILER_RT_TEST_CFLAGS}
${COMPILER_RT_GTEST_CFLAGS}
-I${COMPILER_RT_SOURCE_DIR}/include
-I${COMPILER_RT_SOURCE_DIR}/lib
-I${COMPILER_RT_SOURCE_DIR}/lib/msan
- -stdlib=libc++
-g
-O2
-fno-exceptions
@@ -44,15 +44,13 @@ set(MSAN_UNITTEST_INSTRUMENTED_CFLAGS
)
set(MSAN_UNITTEST_LINK_FLAGS
-fsanitize=memory
+ # Don't need -stdlib=libc++ because we explicitly list libc++.so in the linker
+ # inputs.
# FIXME: we build libcxx without cxxabi and need libstdc++ to provide it.
-lstdc++
)
append_list_if(COMPILER_RT_HAS_LIBDL -ldl MSAN_UNITTEST_LINK_FLAGS)
-set(MSAN_LOADABLE_LINK_FLAGS
- -fsanitize=memory
- -shared
-)
# Compile source for the given architecture, using compiler
# options in ${ARGN}, and add it to the object list.
@@ -90,12 +88,6 @@ set_target_properties(MsanUnitTests PROPERTIES FOLDER "MSan unit tests")
# Adds MSan unit tests and benchmarks for architecture.
macro(add_msan_tests_for_arch arch kind)
- set(LIBCXX_PREFIX ${CMAKE_CURRENT_BINARY_DIR}/../libcxx_msan${kind})
- add_custom_libcxx(libcxx_msan${kind} ${LIBCXX_PREFIX}
- DEPS ${MSAN_RUNTIME_LIBRARIES}
- CFLAGS ${MSAN_LIBCXX_CFLAGS} ${ARGN})
- set(MSAN_LIBCXX_SO ${LIBCXX_PREFIX}/lib/libc++.so)
-
# Build gtest instrumented with MSan.
set(MSAN_INST_GTEST)
msan_compile(MSAN_INST_GTEST ${COMPILER_RT_GTEST_SOURCE} ${arch} "${kind}"
@@ -111,7 +103,7 @@ macro(add_msan_tests_for_arch arch kind)
# Instrumented loadable module objects.
set(MSAN_INST_LOADABLE_OBJECTS)
msan_compile(MSAN_INST_LOADABLE_OBJECTS ${MSAN_LOADABLE_SOURCE} ${arch} "${kind}"
- ${MSAN_UNITTEST_INSTRUMENTED_CFLAGS} ${ARGN})
+ ${MSAN_UNITTEST_INSTRUMENTED_CFLAGS} "-fPIC" ${ARGN})
# Instrumented loadable library tests.
set(MSAN_LOADABLE_SO)
@@ -120,24 +112,31 @@ macro(add_msan_tests_for_arch arch kind)
DEPS ${MSAN_INST_LOADABLE_OBJECTS})
set(MSAN_TEST_OBJECTS ${MSAN_INST_TEST_OBJECTS} ${MSAN_INST_GTEST})
- set(MSAN_TEST_DEPS ${MSAN_TEST_OBJECTS} libcxx_msan${kind}
+ set(MSAN_TEST_DEPS ${MSAN_TEST_OBJECTS} libcxx_msan_${arch}
${MSAN_LOADABLE_SO})
if(NOT COMPILER_RT_STANDALONE_BUILD)
list(APPEND MSAN_TEST_DEPS msan)
endif()
get_target_flags_for_arch(${arch} TARGET_LINK_FLAGS)
add_compiler_rt_test(MsanUnitTests "Msan-${arch}${kind}-Test" ${arch}
- OBJECTS ${MSAN_TEST_OBJECTS} ${MSAN_LIBCXX_SO}
- DEPS ${MSAN_TEST_DEPS}
- LINK_FLAGS ${MSAN_UNITTEST_LINK_FLAGS}
- ${TARGET_LINK_FLAGS}
- "-Wl,-rpath=${CMAKE_CURRENT_BINARY_DIR}"
- "-Wl,-rpath=${LIBCXX_PREFIX}/lib")
+ OBJECTS ${MSAN_TEST_OBJECTS} ${MSAN_LIBCXX_SO}
+ DEPS ${MSAN_TEST_DEPS}
+ LINK_FLAGS ${MSAN_UNITTEST_LINK_FLAGS}
+ ${TARGET_LINK_FLAGS}
+ "-Wl,-rpath=${CMAKE_CURRENT_BINARY_DIR}"
+ "-Wl,-rpath=${LIBCXX_PREFIX}/lib")
endmacro()
# We should only build MSan unit tests if we can build instrumented libcxx.
if(COMPILER_RT_CAN_EXECUTE_TESTS AND COMPILER_RT_HAS_LIBCXX_SOURCES)
foreach(arch ${MSAN_SUPPORTED_ARCH})
+ get_target_flags_for_arch(${arch} TARGET_CFLAGS)
+ set(LIBCXX_PREFIX ${CMAKE_CURRENT_BINARY_DIR}/../libcxx_msan_${arch})
+ add_custom_libcxx(libcxx_msan_${arch} ${LIBCXX_PREFIX}
+ DEPS ${MSAN_RUNTIME_LIBRARIES}
+ CFLAGS ${MSAN_LIBCXX_CFLAGS} ${TARGET_CFLAGS})
+ set(MSAN_LIBCXX_SO ${LIBCXX_PREFIX}/lib/libc++.so)
+
add_msan_tests_for_arch(${arch} "")
add_msan_tests_for_arch(${arch} "-with-call"
-mllvm -msan-instrumentation-with-call-threshold=0)
diff --git a/lib/msan/tests/msan_test.cc b/lib/msan/tests/msan_test.cc
index 00dd20a3d775..b7162b3c081b 100644
--- a/lib/msan/tests/msan_test.cc
+++ b/lib/msan/tests/msan_test.cc
@@ -1883,7 +1883,7 @@ TEST(MemorySanitizer, swprintf) {
ASSERT_EQ(buff[1], '2');
ASSERT_EQ(buff[2], '3');
ASSERT_EQ(buff[6], '7');
- ASSERT_EQ(buff[7], 0);
+ ASSERT_EQ(buff[7], L'\0');
EXPECT_POISONED(buff[8]);
}
@@ -1952,6 +1952,16 @@ TEST(MemorySanitizer, wcsnrtombs) {
EXPECT_POISONED(buff[2]);
}
+TEST(MemorySanitizer, wcrtomb) {
+ wchar_t x = L'a';
+ char buff[10];
+ mbstate_t mbs;
+ memset(&mbs, 0, sizeof(mbs));
+ size_t res = wcrtomb(buff, x, &mbs);
+ EXPECT_EQ(res, (size_t)1);
+ EXPECT_EQ(buff[0], 'a');
+}
+
TEST(MemorySanitizer, wmemset) {
wchar_t x[25];
break_optimization(x);
@@ -2876,6 +2886,8 @@ static void GetPathToLoadable(char *buf, size_t sz) {
static const char basename[] = "libmsan_loadable.mips64.so";
#elif defined(__mips64)
static const char basename[] = "libmsan_loadable.mips64el.so";
+#elif defined(__aarch64__)
+ static const char basename[] = "libmsan_loadable.aarch64.so";
#endif
int res = snprintf(buf, sz, "%.*s/%s",
(int)dir_len, program_path, basename);
@@ -2982,6 +2994,14 @@ static void *SmallStackThread_threadfn(void* data) {
return 0;
}
+#ifdef PTHREAD_STACK_MIN
+# define SMALLSTACKSIZE PTHREAD_STACK_MIN
+# define SMALLPRESTACKSIZE PTHREAD_STACK_MIN
+#else
+# define SMALLSTACKSIZE 64 * 1024
+# define SMALLPRESTACKSIZE 16 * 1024
+#endif
+
TEST(MemorySanitizer, SmallStackThread) {
pthread_attr_t attr;
pthread_t t;
@@ -2989,7 +3009,7 @@ TEST(MemorySanitizer, SmallStackThread) {
int res;
res = pthread_attr_init(&attr);
ASSERT_EQ(0, res);
- res = pthread_attr_setstacksize(&attr, 64 * 1024);
+ res = pthread_attr_setstacksize(&attr, SMALLSTACKSIZE);
ASSERT_EQ(0, res);
res = pthread_create(&t, &attr, SmallStackThread_threadfn, NULL);
ASSERT_EQ(0, res);
@@ -3006,7 +3026,7 @@ TEST(MemorySanitizer, SmallPreAllocatedStackThread) {
res = pthread_attr_init(&attr);
ASSERT_EQ(0, res);
void *stack;
- const size_t kStackSize = 16 * 1024;
+ const size_t kStackSize = SMALLPRESTACKSIZE;
res = posix_memalign(&stack, 4096, kStackSize);
ASSERT_EQ(0, res);
res = pthread_attr_setstack(&attr, stack, kStackSize);
diff --git a/lib/profile/CMakeLists.txt b/lib/profile/CMakeLists.txt
index d03409fc45b7..1b10ade0eee6 100644
--- a/lib/profile/CMakeLists.txt
+++ b/lib/profile/CMakeLists.txt
@@ -1,27 +1,71 @@
+
+CHECK_CXX_SOURCE_COMPILES("
+#ifdef _MSC_VER
+#include <Intrin.h> /* Workaround for PR19898. */
+#include <windows.h>
+#endif
+int main() {
+#ifdef _MSC_VER
+ volatile LONG val = 1;
+ MemoryBarrier();
+ InterlockedCompareExchange(&val, 0, 1);
+ InterlockedIncrement(&val);
+ InterlockedDecrement(&val);
+#else
+ volatile unsigned long val = 1;
+ __sync_synchronize();
+ __sync_val_compare_and_swap(&val, 1, 0);
+ __sync_add_and_fetch(&val, 1);
+ __sync_sub_and_fetch(&val, 1);
+#endif
+ return 0;
+ }
+" COMPILER_RT_TARGET_HAS_ATOMICS)
+
add_custom_target(profile)
set(PROFILE_SOURCES
GCDAProfiling.c
InstrProfiling.c
+ InstrProfilingValue.c
InstrProfilingBuffer.c
InstrProfilingFile.c
+ InstrProfilingWriter.c
InstrProfilingPlatformDarwin.c
+ InstrProfilingPlatformLinux.c
InstrProfilingPlatformOther.c
InstrProfilingRuntime.cc
InstrProfilingUtil.c)
+if(UNIX)
+ set(EXTRA_FLAGS
+ -fPIC
+ -Wno-pedantic)
+else()
+ set(EXTRA_FLAGS
+ -fPIC)
+endif()
+
+if(COMPILER_RT_TARGET_HAS_ATOMICS)
+ set(EXTRA_FLAGS
+ ${EXTRA_FLAGS}
+ -DCOMPILER_RT_HAS_ATOMICS=1)
+endif()
+
if(APPLE)
- add_compiler_rt_osx_static_runtime(clang_rt.profile_osx
+ add_compiler_rt_runtime(clang_rt.profile
+ STATIC
+ OS ${PROFILE_SUPPORTED_OS}
ARCHS ${PROFILE_SUPPORTED_ARCH}
- SOURCES ${PROFILE_SOURCES})
- add_dependencies(profile clang_rt.profile_osx)
+ SOURCES ${PROFILE_SOURCES}
+ PARENT_TARGET profile)
else()
- foreach(arch ${PROFILE_SUPPORTED_ARCH})
- add_compiler_rt_runtime(clang_rt.profile-${arch} ${arch} STATIC
- CFLAGS -fPIC
- SOURCES ${PROFILE_SOURCES})
- add_dependencies(profile clang_rt.profile-${arch})
- endforeach()
+ add_compiler_rt_runtime(clang_rt.profile
+ STATIC
+ ARCHS ${PROFILE_SUPPORTED_ARCH}
+ CFLAGS ${EXTRA_FLAGS}
+ SOURCES ${PROFILE_SOURCES}
+ PARENT_TARGET profile)
endif()
add_dependencies(compiler-rt profile)
diff --git a/lib/profile/InstrProfData.inc b/lib/profile/InstrProfData.inc
new file mode 100644
index 000000000000..48dae506cabb
--- /dev/null
+++ b/lib/profile/InstrProfData.inc
@@ -0,0 +1,735 @@
+/*===-- InstrProfData.inc - instr profiling runtime structures -----------=== *\
+|*
+|* 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. */
+
+
+#ifdef INSTR_PROF_VALUE_PROF_DATA
+#define INSTR_PROF_DATA_DEFINED
+
+/*!
+ * 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
+
+/* 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_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)
+
+/* 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/lib/profile/InstrProfiling.c b/lib/profile/InstrProfiling.c
index 8d010df28f18..58778aeec16a 100644
--- a/lib/profile/InstrProfiling.c
+++ b/lib/profile/InstrProfiling.c
@@ -8,41 +8,61 @@
\*===----------------------------------------------------------------------===*/
#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_VISIBILITY uint64_t __llvm_profile_get_magic(void) {
+ return sizeof(void *) == sizeof(uint64_t) ? (INSTR_PROF_RAW_MAGIC_64)
+ : (INSTR_PROF_RAW_MAGIC_32);
+}
+
+/* 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")))
-uint64_t __llvm_profile_get_version(void) {
- /* This should be bumped any time the output format changes. */
- return 1;
+COMPILER_RT_VISIBILITY uint64_t __llvm_profile_get_version(void) {
+ return INSTR_PROF_RAW_VERSION;
}
-__attribute__((visibility("hidden")))
-void __llvm_profile_reset_counters(void) {
+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/lib/profile/InstrProfiling.h b/lib/profile/InstrProfiling.h
index 3778a88893e6..d27ca569d535 100644
--- a/lib/profile/InstrProfiling.h
+++ b/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/lib/profile/InstrProfilingBuffer.c b/lib/profile/InstrProfilingBuffer.c
index 3c429c8a85ea..4227ca6b66ea 100644
--- a/lib/profile/InstrProfilingBuffer.c
+++ b/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/lib/profile/InstrProfilingFile.c b/lib/profile/InstrProfilingFile.c
index 68e8c7b07871..4ea7fbf9738a 100644
--- a/lib/profile/InstrProfilingFile.c
+++ b/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,39 @@
#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
-
+/* 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 +57,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 +67,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 +175,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 +185,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 +199,28 @@ 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;
+ }
/* 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/lib/profile/InstrProfilingInternal.h b/lib/profile/InstrProfilingInternal.h
index ede39cd9d713..4aab78ea509c 100644
--- a/lib/profile/InstrProfilingInternal.h
+++ b/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/lib/profile/InstrProfilingPlatformDarwin.c b/lib/profile/InstrProfilingPlatformDarwin.c
index 02299cc4630c..30ddbd2e4982 100644
--- a/lib/profile/InstrProfilingPlatformDarwin.c
+++ b/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/lib/profile/InstrProfilingPlatformLinux.c b/lib/profile/InstrProfilingPlatformLinux.c
new file mode 100644
index 000000000000..7843f47caa1b
--- /dev/null
+++ b/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/lib/profile/InstrProfilingPlatformOther.c b/lib/profile/InstrProfilingPlatformOther.c
index 548d6a396b76..58ceb3458a0a 100644
--- a/lib/profile/InstrProfilingPlatformOther.c
+++ b/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/lib/profile/InstrProfilingPort.h b/lib/profile/InstrProfilingPort.h
new file mode 100644
index 000000000000..da4f18fcbb46
--- /dev/null
+++ b/lib/profile/InstrProfilingPort.h
@@ -0,0 +1,76 @@
+/*===- 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
+#define COMPILER_RT_BOOL_CMPXCHG(Ptr, OldV, NewV) \
+ (InterlockedCompareExchange((LONG volatile *)Ptr, (LONG)NewV, (LONG)OldV) == \
+ (LONG)OldV)
+#endif
+#else
+#define COMPILER_RT_BOOL_CMPXCHG(Ptr, OldV, NewV) \
+ __sync_bool_compare_and_swap(Ptr, OldV, NewV)
+#endif
+#else
+#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__) && 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 char uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned int uint32_t;
+typedef unsigned long long uint64_t;
+typedef uint32_t uintptr_t;
+#elif defined(__FreeBSD__) && defined(__x86_64__)
+#define PRIu64 "lu"
+typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned int uint32_t;
+typedef unsigned long long uint64_t;
+typedef unsigned long int uintptr_t;
+
+#else /* defined(__FreeBSD__) && defined(__i386__) */
+
+#include <inttypes.h>
+#include <stdint.h>
+
+#endif /* defined(__FreeBSD__) && defined(__i386__) */
+
+#endif /* PROFILE_INSTRPROFILING_PORT_H_ */
diff --git a/lib/profile/InstrProfilingRuntime.cc b/lib/profile/InstrProfilingRuntime.cc
index 081ecb29e987..12ad9f1573f4 100644
--- a/lib/profile/InstrProfilingRuntime.cc
+++ b/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/lib/profile/InstrProfilingUtil.c b/lib/profile/InstrProfilingUtil.c
index e146dfca83c8..6f0443d3bb5d 100644
--- a/lib/profile/InstrProfilingUtil.c
+++ b/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/lib/profile/InstrProfilingValue.c b/lib/profile/InstrProfilingValue.c
new file mode 100644
index 000000000000..39b4da446a81
--- /dev/null
+++ b/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 >= UCHAR_MAX)
+ 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/lib/profile/InstrProfilingWriter.c b/lib/profile/InstrProfilingWriter.c
new file mode 100644
index 000000000000..a07bc538ed4b
--- /dev/null
+++ b/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/lib/safestack/.clang-format b/lib/safestack/.clang-format
new file mode 100644
index 000000000000..f6cb8ad931f5
--- /dev/null
+++ b/lib/safestack/.clang-format
@@ -0,0 +1 @@
+BasedOnStyle: Google
diff --git a/lib/safestack/CMakeLists.txt b/lib/safestack/CMakeLists.txt
index 1c15d079dbb5..9c11bb6f7e61 100644
--- a/lib/safestack/CMakeLists.txt
+++ b/lib/safestack/CMakeLists.txt
@@ -8,21 +8,27 @@ 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}
+ add_compiler_rt_runtime(clang_rt.safestack
+ STATIC
+ OS osx
+ ARCHS ${SAFESTACK_SUPPORTED_ARCH}
SOURCES ${SAFESTACK_SOURCES}
$<TARGET_OBJECTS:RTInterception.osx>
$<TARGET_OBJECTS:RTSanitizerCommon.osx>
- CFLAGS ${SAFESTACK_CFLAGS})
- add_dependencies(safestack clang_rt.safestack_osx)
+ $<TARGET_OBJECTS:RTSanitizerCommonNoLibc.osx>
+ CFLAGS ${SAFESTACK_CFLAGS}
+ PARENT_TARGET safestack)
else()
# Otherwise, build separate libraries for each target.
foreach(arch ${SAFESTACK_SUPPORTED_ARCH})
- add_compiler_rt_runtime(clang_rt.safestack-${arch} ${arch} STATIC
+ add_compiler_rt_runtime(clang_rt.safestack
+ STATIC
+ ARCHS ${arch}
SOURCES ${SAFESTACK_SOURCES}
$<TARGET_OBJECTS:RTInterception.${arch}>
$<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
- CFLAGS ${SAFESTACK_CFLAGS})
- add_dependencies(safestack clang_rt.safestack-${arch})
+ $<TARGET_OBJECTS:RTSanitizerCommonNoLibc.${arch}>
+ CFLAGS ${SAFESTACK_CFLAGS}
+ PARENT_TARGET safestack)
endforeach()
endif()
diff --git a/lib/safestack/safestack.cc b/lib/safestack/safestack.cc
index 504bd3cd0d99..92c24b35d6d0 100644
--- a/lib/safestack/safestack.cc
+++ b/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/lib/sanitizer_common/.clang-format b/lib/sanitizer_common/.clang-format
new file mode 100644
index 000000000000..f6cb8ad931f5
--- /dev/null
+++ b/lib/sanitizer_common/.clang-format
@@ -0,0 +1 @@
+BasedOnStyle: Google
diff --git a/lib/sanitizer_common/CMakeLists.txt b/lib/sanitizer_common/CMakeLists.txt
index f604c9f201d4..6a20f025507a 100644
--- a/lib/sanitizer_common/CMakeLists.txt
+++ b/lib/sanitizer_common/CMakeLists.txt
@@ -33,6 +33,12 @@ set(SANITIZER_SOURCES
sanitizer_thread_registry.cc
sanitizer_win.cc)
+# Libc functions stubs. These sources should be linked instead of
+# SANITIZER_LIBCDEP_SOURCES when sanitizer_common library must not depend on
+# libc.
+set(SANITIZER_NOLIBC_SOURCES
+ sanitizer_common_nolibc.cc)
+
set(SANITIZER_LIBCDEP_SOURCES
sanitizer_common_libcdep.cc
sanitizer_coverage_libcdep.cc
@@ -43,7 +49,6 @@ set(SANITIZER_LIBCDEP_SOURCES
sanitizer_stoptheworld_linux_libcdep.cc
sanitizer_symbolizer_libcdep.cc
sanitizer_symbolizer_posix_libcdep.cc
- sanitizer_symbolizer_process_libcdep.cc
sanitizer_unwind_linux_libcdep.cc)
# Explicitly list all sanitizer_common headers. Not all of these are
@@ -97,9 +102,9 @@ set(SANITIZER_HEADERS
sanitizer_symbolizer_internal.h
sanitizer_symbolizer_libbacktrace.h
sanitizer_symbolizer_mac.h
- sanitizer_symbolizer_win.h
sanitizer_syscall_generic.inc
sanitizer_syscall_linux_x86_64.inc
+ sanitizer_syscall_linux_aarch64.inc
sanitizer_thread_registry.h)
set(SANITIZER_COMMON_DEFINITIONS)
@@ -124,38 +129,28 @@ append_list_if(SANITIZER_LIMIT_FRAME_SIZE -Wframe-larger-than=570
append_list_if(COMPILER_RT_HAS_WGLOBAL_CONSTRUCTORS_FLAG -Wglobal-constructors
SANITIZER_CFLAGS)
-add_custom_target(sanitizer_common)
-set(SANITIZER_RUNTIME_LIBRARIES)
if(APPLE)
- # Build universal binary on APPLE.
-
- add_compiler_rt_object_libraries(RTSanitizerCommon
- OS ${SANITIZER_COMMON_SUPPORTED_OS}
- ARCHS ${SANITIZER_COMMON_SUPPORTED_ARCH}
- SOURCES ${SANITIZER_SOURCES} ${SANITIZER_LIBCDEP_SOURCES}
- CFLAGS ${SANITIZER_CFLAGS}
- DEFS ${SANITIZER_COMMON_DEFINITIONS})
- foreach(os ${SANITIZER_COMMON_SUPPORTED_OS})
- list(APPEND SANITIZER_RUNTIME_LIBRARIES RTSanitizerCommon.${os})
- endforeach()
-else()
- # Otherwise, build separate libraries for each target.
-
- add_compiler_rt_object_libraries(RTSanitizerCommon
- ARCHS ${SANITIZER_COMMON_SUPPORTED_ARCH}
- SOURCES ${SANITIZER_SOURCES} CFLAGS ${SANITIZER_CFLAGS}
- DEFS ${SANITIZER_COMMON_DEFINITIONS})
- add_compiler_rt_object_libraries(RTSanitizerCommonLibc
- ARCHS ${SANITIZER_COMMON_SUPPORTED_ARCH}
- SOURCES ${SANITIZER_LIBCDEP_SOURCES} CFLAGS ${SANITIZER_CFLAGS}
- DEFS ${SANITIZER_COMMON_DEFINITIONS})
- foreach(arch ${SANITIZER_COMMON_SUPPORTED_ARCH})
- list(APPEND SANITIZER_RUNTIME_LIBRARIES RTSanitizerCommon.${arch}
- RTSanitizerCommonLibc.${arch})
- endforeach()
+ set(OS_OPTION OS ${SANITIZER_COMMON_SUPPORTED_OS})
endif()
-add_dependencies(compiler-rt sanitizer_common)
+add_compiler_rt_object_libraries(RTSanitizerCommon
+ ${OS_OPTION}
+ ARCHS ${SANITIZER_COMMON_SUPPORTED_ARCH}
+ SOURCES ${SANITIZER_SOURCES}
+ CFLAGS ${SANITIZER_CFLAGS}
+ DEFS ${SANITIZER_COMMON_DEFINITIONS})
+add_compiler_rt_object_libraries(RTSanitizerCommonNoLibc
+ ${OS_OPTION}
+ ARCHS ${SANITIZER_COMMON_SUPPORTED_ARCH}
+ SOURCES ${SANITIZER_NOLIBC_SOURCES}
+ CFLAGS ${SANITIZER_CFLAGS}
+ DEFS ${SANITIZER_COMMON_DEFINITIONS})
+add_compiler_rt_object_libraries(RTSanitizerCommonLibc
+ ${OS_OPTION}
+ ARCHS ${SANITIZER_COMMON_SUPPORTED_ARCH}
+ SOURCES ${SANITIZER_LIBCDEP_SOURCES}
+ CFLAGS ${SANITIZER_CFLAGS}
+ DEFS ${SANITIZER_COMMON_DEFINITIONS})
# Unit tests for common sanitizer runtime.
if(COMPILER_RT_INCLUDE_TESTS)
diff --git a/lib/sanitizer_common/Makefile.mk b/lib/sanitizer_common/Makefile.mk
index da83c2d6b3b7..5bb20d076e81 100644
--- a/lib/sanitizer_common/Makefile.mk
+++ b/lib/sanitizer_common/Makefile.mk
@@ -11,6 +11,8 @@ ModuleName := sanitizer_common
SubDirs :=
Sources := $(foreach file,$(wildcard $(Dir)/*.cc),$(notdir $(file)))
+NolibcSources := $(foreach file,$(wildcard $(Dir)/*_nolibc.cc),$(notdir $(file)))
+Sources := $(filter-out $(NolibcSources),$(Sources))
ObjNames := $(Sources:%.cc=%.o)
Implementation := Generic
diff --git a/lib/sanitizer_common/sanitizer_addrhashmap.h b/lib/sanitizer_common/sanitizer_addrhashmap.h
index acf4ff020939..e55fc4f95a9a 100644
--- a/lib/sanitizer_common/sanitizer_addrhashmap.h
+++ b/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/lib/sanitizer_common/sanitizer_allocator.cc b/lib/sanitizer_common/sanitizer_allocator.cc
index 03b3e83153de..538e2db95d4e 100644
--- a/lib/sanitizer_common/sanitizer_allocator.cc
+++ b/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/lib/sanitizer_common/sanitizer_allocator.h b/lib/sanitizer_common/sanitizer_allocator.h
index deaffef7150d..44d6fce3b291 100644
--- a/lib/sanitizer_common/sanitizer_allocator.h
+++ b/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/lib/sanitizer_common/sanitizer_allocator_internal.h b/lib/sanitizer_common/sanitizer_allocator_internal.h
index 9b9cfd0b5931..3dcfccd7cba3 100644
--- a/lib/sanitizer_common/sanitizer_allocator_internal.h
+++ b/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/lib/sanitizer_common/sanitizer_asm.h b/lib/sanitizer_common/sanitizer_asm.h
index 906012a96f11..47c2b12a2049 100644
--- a/lib/sanitizer_common/sanitizer_asm.h
+++ b/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/lib/sanitizer_common/sanitizer_atomic.h b/lib/sanitizer_common/sanitizer_atomic.h
index 7e3374aadd0c..b26693e24f8d 100644
--- a/lib/sanitizer_common/sanitizer_atomic.h
+++ b/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/lib/sanitizer_common/sanitizer_common.cc b/lib/sanitizer_common/sanitizer_common.cc
index d14e98824d99..9b41a3aa0af9 100644
--- a/lib/sanitizer_common/sanitizer_common.cc
+++ b/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/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h
index 2c5a8dbe1238..0585f6b15b87 100644
--- a/lib/sanitizer_common/sanitizer_common.h
+++ b/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);
+#else
+INLINE void WriteOneLineToSyslog(const char *s) {}
+#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);
+bool ShouldLogAfterPrintf();
+#else
+INLINE void AndroidLogInit() {}
+INLINE bool ShouldLogAfterPrintf() { return false; }
+#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/lib/sanitizer_common/sanitizer_common_interceptors.inc b/lib/sanitizer_common/sanitizer_common_interceptors.inc
index a7772b7394a5..4639ddc92c6c 100644
--- a/lib/sanitizer_common/sanitizer_common_interceptors.inc
+++ b/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,9 +213,14 @@ 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)
+
INTERCEPTOR(int, strcmp, const char *s1, const char *s2) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, strcmp, s1, s2);
+ CALL_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strcmp, GET_CALLER_PC(), s1,
+ s2);
unsigned char c1, c2;
uptr i;
for (i = 0;; i++) {
@@ -203,11 +233,16 @@ INTERCEPTOR(int, strcmp, const char *s1, const char *s2) {
return CharCmpX(c1, c2);
}
+DECLARE_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strncmp, uptr called_pc,
+ const char *s1, const char *s2, uptr n)
+
INTERCEPTOR(int, strncmp, const char *s1, const char *s2, uptr size) {
if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED)
return internal_strncmp(s1, s2, size);
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, strncmp, s1, s2, size);
+ CALL_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strncmp, GET_CALLER_PC(), s1,
+ s2, size);
unsigned char c1 = 0, c2 = 0;
uptr i;
for (i = 0; i < size; i++) {
@@ -362,8 +397,52 @@ 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)
+
+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);
+ CALL_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_memcmp, GET_CALLER_PC(), 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));
+ return CharCmpX(c1, c2);
+ }
+ }
+ return REAL(memcmp(a1, a2, size));
+}
+
+#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 +490,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 +501,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 +542,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 +560,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 +578,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 +825,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 +838,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 +851,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 +864,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 +908,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 +1045,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 +1062,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 +1079,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 +1322,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 +1337,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 +1364,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 +1379,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 +1395,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 +1410,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 +1433,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 +1455,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 +1479,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 +1494,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 +1509,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 +1524,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 +1581,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 +1593,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 +1620,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 +1634,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 +1691,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 +1731,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 +1769,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 +1787,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 +1798,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 +1809,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 +1823,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 +1838,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 +1867,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 +1879,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 +1901,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 +1920,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 +1947,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 +1979,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 +2003,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 +2089,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 +2112,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 +2138,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 +2164,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 +2190,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 +2234,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 +2254,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 +2266,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 +2278,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 +2313,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 +2337,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 +2353,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 +2371,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 +2381,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 +2393,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 +2417,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 +2429,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 +2449,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 +2458,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 +2488,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 +2531,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 +2547,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 +2574,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 +2596,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 +2608,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 +2628,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 +2645,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 +2675,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 +2695,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 +2712,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 +2740,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 +2754,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 +2804,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 +2839,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 +2856,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 +2898,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 +2929,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 +2974,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 +3027,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 +3054,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 +3120,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 +3146,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 +3163,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 +3182,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 +3198,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 +3209,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 +3227,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 +3245,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 +3262,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 +3276,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 +3384,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 +3394,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 +3413,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 +3423,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 +3442,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 +3452,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 +3471,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 +3481,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 +3537,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 +3550,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 +3562,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 +3586,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 +3598,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 +3616,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 +3641,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 +3654,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 +3693,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 +3742,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 +3852,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 +3870,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 +3914,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 +3924,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 +3934,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 +3953,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 +3963,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 +3973,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 +4023,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 +4033,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 +4051,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 +4067,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 +4077,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 +4107,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 +4119,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 +4163,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 +4185,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 +4228,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 +4241,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 +4251,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 +4273,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 +4286,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 +4298,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 +4317,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 +4331,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 +4356,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 +4392,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 +4420,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 +4446,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 +4521,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 +4539,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 +4554,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 +4615,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 +4635,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 +4687,7 @@ INTERCEPTOR(void *, tsearch, void *key, void **rootp,
COMMON_INTERCEPTOR_ENTER(ctx,