aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/BlocksRuntime/Block.h59
-rw-r--r--lib/BlocksRuntime/Block_private.h179
-rw-r--r--lib/BlocksRuntime/data.c41
-rw-r--r--lib/BlocksRuntime/runtime.c700
-rw-r--r--lib/CMakeLists.txt232
-rw-r--r--lib/Makefile.mk21
-rw-r--r--lib/absvti2.c33
-rw-r--r--lib/adddf3.c152
-rw-r--r--lib/addsf3.c151
-rw-r--r--lib/addvdi3.c36
-rw-r--r--lib/addvsi3.c36
-rw-r--r--lib/addvti3.c40
-rw-r--r--lib/arm/Makefile.mk20
-rw-r--r--lib/arm/adddf3vfp.S25
-rw-r--r--lib/arm/addsf3vfp.S25
-rw-r--r--lib/arm/aeabi_dcmp.S39
-rw-r--r--lib/arm/aeabi_fcmp.S39
-rw-r--r--lib/arm/aeabi_idivmod.S27
-rw-r--r--lib/arm/aeabi_ldivmod.S30
-rw-r--r--lib/arm/aeabi_memcmp.S19
-rw-r--r--lib/arm/aeabi_memcpy.S19
-rw-r--r--lib/arm/aeabi_memmove.S19
-rw-r--r--lib/arm/aeabi_memset.S32
-rw-r--r--lib/arm/aeabi_uidivmod.S28
-rw-r--r--lib/arm/aeabi_uldivmod.S30
-rw-r--r--lib/arm/bswapdi2.S36
-rw-r--r--lib/arm/bswapsi2.S28
-rw-r--r--lib/arm/comparesf2.S143
-rw-r--r--lib/arm/divdf3vfp.S25
-rw-r--r--lib/arm/divmodsi4.S60
-rw-r--r--lib/arm/divsf3vfp.S25
-rw-r--r--lib/arm/divsi3.S51
-rw-r--r--lib/arm/eqdf2vfp.S28
-rw-r--r--lib/arm/eqsf2vfp.S29
-rw-r--r--lib/arm/extendsfdf2vfp.S25
-rw-r--r--lib/arm/fixdfsivfp.S25
-rw-r--r--lib/arm/fixsfsivfp.S25
-rw-r--r--lib/arm/fixunsdfsivfp.S26
-rw-r--r--lib/arm/fixunssfsivfp.S26
-rw-r--r--lib/arm/floatsidfvfp.S25
-rw-r--r--lib/arm/floatsisfvfp.S25
-rw-r--r--lib/arm/floatunssidfvfp.S25
-rw-r--r--lib/arm/floatunssisfvfp.S25
-rw-r--r--lib/arm/gedf2vfp.S28
-rw-r--r--lib/arm/gesf2vfp.S29
-rw-r--r--lib/arm/gtdf2vfp.S28
-rw-r--r--lib/arm/gtsf2vfp.S29
-rw-r--r--lib/arm/ledf2vfp.S28
-rw-r--r--lib/arm/lesf2vfp.S29
-rw-r--r--lib/arm/ltdf2vfp.S28
-rw-r--r--lib/arm/ltsf2vfp.S29
-rw-r--r--lib/arm/modsi3.S50
-rw-r--r--lib/arm/muldf3vfp.S25
-rw-r--r--lib/arm/mulsf3vfp.S25
-rw-r--r--lib/arm/nedf2vfp.S28
-rw-r--r--lib/arm/negdf2vfp.S22
-rw-r--r--lib/arm/negsf2vfp.S22
-rw-r--r--lib/arm/nesf2vfp.S29
-rw-r--r--lib/arm/restore_vfp_d8_d15_regs.S37
-rw-r--r--lib/arm/save_vfp_d8_d15_regs.S35
-rw-r--r--lib/arm/subdf3vfp.S25
-rw-r--r--lib/arm/subsf3vfp.S26
-rw-r--r--lib/arm/switch16.S45
-rw-r--r--lib/arm/switch32.S47
-rw-r--r--lib/arm/switch8.S44
-rw-r--r--lib/arm/switchu8.S44
-rw-r--r--lib/arm/sync_synchronize.S34
-rw-r--r--lib/arm/truncdfsf2vfp.S25
-rw-r--r--lib/arm/udivmodsi4.S96
-rw-r--r--lib/arm/udivsi3.S93
-rw-r--r--lib/arm/umodsi3.S72
-rw-r--r--lib/arm/unorddf2vfp.S28
-rw-r--r--lib/arm/unordsf2vfp.S29
-rw-r--r--lib/asan/CMakeLists.txt172
-rw-r--r--lib/asan/Makefile.mk11
-rw-r--r--lib/asan/README.txt7
-rw-r--r--lib/asan/asan_activation.cc88
-rw-r--r--lib/asan/asan_activation.h23
-rw-r--r--lib/asan/asan_allocator.h74
-rw-r--r--lib/asan/asan_allocator2.cc203
-rw-r--r--lib/asan/asan_blacklist.txt3
-rw-r--r--lib/asan/asan_debugging.cc141
-rw-r--r--lib/asan/asan_dll_thunk.cc196
-rw-r--r--lib/asan/asan_fake_stack.cc65
-rw-r--r--lib/asan/asan_fake_stack.h8
-rw-r--r--lib/asan/asan_flags.h68
-rw-r--r--lib/asan/asan_globals.cc95
-rw-r--r--lib/asan/asan_init_version.h32
-rw-r--r--lib/asan/asan_intercepted_functions.h79
-rw-r--r--lib/asan/asan_interceptors.cc471
-rw-r--r--lib/asan/asan_interceptors.h72
-rw-r--r--lib/asan/asan_interface_internal.h112
-rw-r--r--lib/asan/asan_internal.h64
-rw-r--r--lib/asan/asan_linux.cc149
-rw-r--r--lib/asan/asan_mac.cc97
-rw-r--r--lib/asan/asan_mac.h59
-rw-r--r--lib/asan/asan_malloc_linux.cc115
-rw-r--r--lib/asan/asan_malloc_mac.cc40
-rw-r--r--lib/asan/asan_malloc_win.cc124
-rw-r--r--lib/asan/asan_mapping.h93
-rw-r--r--lib/asan/asan_new_delete.cc74
-rw-r--r--lib/asan/asan_poisoning.cc181
-rw-r--r--lib/asan/asan_poisoning.h32
-rw-r--r--lib/asan/asan_posix.cc107
-rw-r--r--lib/asan/asan_preinit.cc16
-rw-r--r--lib/asan/asan_report.cc723
-rw-r--r--lib/asan/asan_report.h74
-rw-r--r--lib/asan/asan_rtl.cc496
-rw-r--r--lib/asan/asan_stack.cc34
-rw-r--r--lib/asan/asan_stack.h92
-rw-r--r--lib/asan/asan_stats.cc13
-rw-r--r--lib/asan/asan_stats.h4
-rw-r--r--lib/asan/asan_suppressions.cc87
-rw-r--r--lib/asan/asan_suppressions.h29
-rw-r--r--lib/asan/asan_thread.cc92
-rw-r--r--lib/asan/asan_thread.h51
-rw-r--r--lib/asan/asan_win.cc132
-rw-r--r--lib/asan/asan_win_dll_thunk.cc376
-rw-r--r--lib/asan/asan_win_dynamic_runtime_thunk.cc52
-rw-r--r--lib/asan/lit_tests/32bitConfig/lit.site.cfg.in13
-rw-r--r--lib/asan/lit_tests/64bitConfig/lit.site.cfg.in12
-rw-r--r--lib/asan/lit_tests/CMakeLists.txt42
-rw-r--r--lib/asan/lit_tests/TestCases/Darwin/interface_symbols_darwin.c41
-rw-r--r--lib/asan/lit_tests/TestCases/Darwin/lit.local.cfg9
-rw-r--r--lib/asan/lit_tests/TestCases/Darwin/malloc_set_zone_name-mprotect.cc51
-rw-r--r--lib/asan/lit_tests/TestCases/Darwin/malloc_zone-protected.cc20
-rw-r--r--lib/asan/lit_tests/TestCases/Darwin/reexec-insert-libraries-env.cc20
-rw-r--r--lib/asan/lit_tests/TestCases/Darwin/unset-insert-libraries-on-exec.cc20
-rw-r--r--lib/asan/lit_tests/TestCases/Helpers/blacklist-extra.cc5
-rw-r--r--lib/asan/lit_tests/TestCases/Helpers/echo-env.cc19
-rw-r--r--lib/asan/lit_tests/TestCases/Helpers/init-order-atexit-extra.cc16
-rw-r--r--lib/asan/lit_tests/TestCases/Helpers/init-order-pthread-create-extra.cc2
-rw-r--r--lib/asan/lit_tests/TestCases/Helpers/initialization-blacklist-extra.cc15
-rw-r--r--lib/asan/lit_tests/TestCases/Helpers/initialization-blacklist-extra2.cc4
-rw-r--r--lib/asan/lit_tests/TestCases/Helpers/initialization-blacklist.txt3
-rw-r--r--lib/asan/lit_tests/TestCases/Helpers/initialization-bug-extra.cc5
-rw-r--r--lib/asan/lit_tests/TestCases/Helpers/initialization-bug-extra2.cc6
-rw-r--r--lib/asan/lit_tests/TestCases/Helpers/initialization-constexpr-extra.cc3
-rw-r--r--lib/asan/lit_tests/TestCases/Helpers/initialization-nobug-extra.cc9
-rw-r--r--lib/asan/lit_tests/TestCases/Helpers/lit.local.cfg3
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/asan_prelink_test.cc28
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/clone_test.cc44
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/coverage.cc45
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/glob.cc29
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/glob_test_root/aa0
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/glob_test_root/ab0
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/glob_test_root/ba0
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/heap-overflow-large.cc23
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/heavy_uar_test.cc54
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/initialization-bug-any-order.cc36
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/interception_failure_test.cc22
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/interception_malloc_test.cc23
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/interception_readdir_r_test.cc59
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/interception_test.cc22
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/interface_symbols_linux.c35
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/lit.local.cfg9
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/malloc-in-qsort.cc56
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/malloc_delete_mismatch.cc31
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/overflow-in-qsort.cc51
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/preinit_test.cc27
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/ptrace.cc52
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/rlimit_mmap_test.cc16
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/swapcontext_test.cc90
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/syscalls.cc22
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/time_null_regtest.cc20
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/tsd_dtor_leak.cc39
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/uar_signals.cc70
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/unpoison_tls.cc35
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/zero-base-shadow32.cc24
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/zero-base-shadow64.cc24
-rw-r--r--lib/asan/lit_tests/TestCases/SharedLibs/darwin-dummy-shared-lib-so.cc13
-rw-r--r--lib/asan/lit_tests/TestCases/SharedLibs/dlclose-test-so.cc33
-rw-r--r--lib/asan/lit_tests/TestCases/SharedLibs/init-order-dlopen-so.cc12
-rw-r--r--lib/asan/lit_tests/TestCases/SharedLibs/lit.local.cfg4
-rw-r--r--lib/asan/lit_tests/TestCases/SharedLibs/shared-lib-test-so.cc26
-rw-r--r--lib/asan/lit_tests/TestCases/allocator_returns_null.cc81
-rw-r--r--lib/asan/lit_tests/TestCases/allow_user_segv.cc48
-rw-r--r--lib/asan/lit_tests/TestCases/asan-symbolize-sanity-test.cc39
-rw-r--r--lib/asan/lit_tests/TestCases/assign_large_valloc_to_global.cc8
-rw-r--r--lib/asan/lit_tests/TestCases/atexit_stats.cc13
-rw-r--r--lib/asan/lit_tests/TestCases/blacklist.cc38
-rw-r--r--lib/asan/lit_tests/TestCases/contiguous_container.cc47
-rw-r--r--lib/asan/lit_tests/TestCases/current_allocated_bytes.cc43
-rw-r--r--lib/asan/lit_tests/TestCases/deep_call_stack.cc25
-rw-r--r--lib/asan/lit_tests/TestCases/deep_stack_uaf.cc31
-rw-r--r--lib/asan/lit_tests/TestCases/deep_tail_call.cc20
-rw-r--r--lib/asan/lit_tests/TestCases/deep_thread_stack.cc57
-rw-r--r--lib/asan/lit_tests/TestCases/default_blacklist.cc3
-rw-r--r--lib/asan/lit_tests/TestCases/default_options.cc15
-rw-r--r--lib/asan/lit_tests/TestCases/dlclose-test.cc81
-rw-r--r--lib/asan/lit_tests/TestCases/double-free.cc25
-rw-r--r--lib/asan/lit_tests/TestCases/force_inline_opt0.cc14
-rw-r--r--lib/asan/lit_tests/TestCases/free_hook_realloc.cc32
-rw-r--r--lib/asan/lit_tests/TestCases/global-demangle.cc17
-rw-r--r--lib/asan/lit_tests/TestCases/global-overflow.cc21
-rw-r--r--lib/asan/lit_tests/TestCases/heap-overflow.cc24
-rw-r--r--lib/asan/lit_tests/TestCases/huge_negative_hea_oob.cc13
-rw-r--r--lib/asan/lit_tests/TestCases/init-order-atexit.cc31
-rw-r--r--lib/asan/lit_tests/TestCases/init-order-dlopen.cc57
-rw-r--r--lib/asan/lit_tests/TestCases/init-order-pthread-create.cc32
-rw-r--r--lib/asan/lit_tests/TestCases/initialization-blacklist.cc32
-rw-r--r--lib/asan/lit_tests/TestCases/initialization-bug.cc45
-rw-r--r--lib/asan/lit_tests/TestCases/initialization-constexpr.cc31
-rw-r--r--lib/asan/lit_tests/TestCases/initialization-nobug.cc48
-rw-r--r--lib/asan/lit_tests/TestCases/inline.cc19
-rw-r--r--lib/asan/lit_tests/TestCases/interface_test.cc8
-rw-r--r--lib/asan/lit_tests/TestCases/invalid-free.cc21
-rw-r--r--lib/asan/lit_tests/TestCases/ioctl.cc24
-rw-r--r--lib/asan/lit_tests/TestCases/large_func_test.cc51
-rw-r--r--lib/asan/lit_tests/TestCases/log-path_test.cc39
-rw-r--r--lib/asan/lit_tests/TestCases/log_path_fork_test.cc.disabled22
-rw-r--r--lib/asan/lit_tests/TestCases/lsan_annotations.cc16
-rw-r--r--lib/asan/lit_tests/TestCases/malloc_context_size.cc27
-rw-r--r--lib/asan/lit_tests/TestCases/malloc_fill.cc22
-rw-r--r--lib/asan/lit_tests/TestCases/malloc_hook.cc36
-rw-r--r--lib/asan/lit_tests/TestCases/memcmp_strict_test.cc15
-rw-r--r--lib/asan/lit_tests/TestCases/memcmp_test.cc17
-rw-r--r--lib/asan/lit_tests/TestCases/null_deref.cc19
-rw-r--r--lib/asan/lit_tests/TestCases/on_error_callback.cc16
-rw-r--r--lib/asan/lit_tests/TestCases/partial_right.cc13
-rw-r--r--lib/asan/lit_tests/TestCases/poison_partial.cc19
-rw-r--r--lib/asan/lit_tests/TestCases/print_summary.cc14
-rw-r--r--lib/asan/lit_tests/TestCases/readv.cc32
-rw-r--r--lib/asan/lit_tests/TestCases/sanity_check_pure_c.c19
-rw-r--r--lib/asan/lit_tests/TestCases/shared-lib-test.cc42
-rw-r--r--lib/asan/lit_tests/TestCases/sleep_before_dying.c10
-rw-r--r--lib/asan/lit_tests/TestCases/stack-buffer-overflow-with-position.cc45
-rw-r--r--lib/asan/lit_tests/TestCases/stack-frame-demangle.cc22
-rw-r--r--lib/asan/lit_tests/TestCases/stack-oob-frames.cc59
-rw-r--r--lib/asan/lit_tests/TestCases/stack-overflow.cc16
-rw-r--r--lib/asan/lit_tests/TestCases/stack-use-after-return.cc77
-rw-r--r--lib/asan/lit_tests/TestCases/strdup_oob_test.cc19
-rw-r--r--lib/asan/lit_tests/TestCases/strerror_r_test.cc13
-rw-r--r--lib/asan/lit_tests/TestCases/strip_path_prefix.c12
-rw-r--r--lib/asan/lit_tests/TestCases/strncpy-overflow.cc28
-rw-r--r--lib/asan/lit_tests/TestCases/symbolize_callback.cc17
-rw-r--r--lib/asan/lit_tests/TestCases/throw_call_test.cc45
-rw-r--r--lib/asan/lit_tests/TestCases/throw_invoke_test.cc50
-rw-r--r--lib/asan/lit_tests/TestCases/time_interceptor.cc16
-rw-r--r--lib/asan/lit_tests/TestCases/uar_and_exceptions.cc40
-rw-r--r--lib/asan/lit_tests/TestCases/unaligned_loads_and_stores.cc52
-rw-r--r--lib/asan/lit_tests/TestCases/use-after-free-right.cc34
-rw-r--r--lib/asan/lit_tests/TestCases/use-after-free.cc31
-rw-r--r--lib/asan/lit_tests/TestCases/use-after-poison.cc20
-rw-r--r--lib/asan/lit_tests/TestCases/use-after-scope-dtor-order.cc25
-rw-r--r--lib/asan/lit_tests/TestCases/use-after-scope-inlined.cc27
-rw-r--r--lib/asan/lit_tests/TestCases/use-after-scope-nobug.cc14
-rw-r--r--lib/asan/lit_tests/TestCases/use-after-scope-temp.cc29
-rw-r--r--lib/asan/lit_tests/TestCases/use-after-scope.cc16
-rw-r--r--lib/asan/lit_tests/TestCases/wait.cc63
-rw-r--r--lib/asan/lit_tests/Unit/lit.site.cfg.in16
-rw-r--r--lib/asan/lit_tests/lit.cfg95
-rw-r--r--lib/asan/scripts/CMakeLists.txt4
-rwxr-xr-xlib/asan/scripts/asan_device_setup267
-rwxr-xr-xlib/asan/scripts/asan_symbolize.py199
-rw-r--r--lib/asan/tests/CMakeLists.txt219
-rw-r--r--lib/asan/tests/asan_asm_test.cc267
-rw-r--r--lib/asan/tests/asan_fake_stack_test.cc10
-rw-r--r--lib/asan/tests/asan_interface_test.cc67
-rw-r--r--lib/asan/tests/asan_mem_test.cc15
-rw-r--r--lib/asan/tests/asan_noinst_test.cc110
-rw-r--r--lib/asan/tests/asan_oob_test.cc4
-rw-r--r--lib/asan/tests/asan_racy_double_free_test.cc4
-rw-r--r--lib/asan/tests/asan_str_test.cc52
-rw-r--r--lib/asan/tests/asan_test.cc193
-rw-r--r--lib/asan/tests/asan_test_config.h12
-rw-r--r--lib/asan/tests/asan_test_utils.h20
-rw-r--r--lib/ashlti3.c45
-rw-r--r--lib/ashrti3.c46
-rw-r--r--lib/assembly.h73
-rw-r--r--lib/builtins/CMakeLists.txt278
-rw-r--r--lib/builtins/Makefile.mk25
-rw-r--r--lib/builtins/README.txt343
-rw-r--r--lib/builtins/absvdi2.c (renamed from lib/absvdi2.c)0
-rw-r--r--lib/builtins/absvsi2.c (renamed from lib/absvsi2.c)0
-rw-r--r--lib/builtins/absvti2.c34
-rw-r--r--lib/builtins/adddf3.c22
-rw-r--r--lib/builtins/addsf3.c22
-rw-r--r--lib/builtins/addtf3.c25
-rw-r--r--lib/builtins/addvdi3.c36
-rw-r--r--lib/builtins/addvsi3.c36
-rw-r--r--lib/builtins/addvti3.c40
-rw-r--r--lib/builtins/apple_versioning.c (renamed from lib/apple_versioning.c)0
-rw-r--r--lib/builtins/arm/Makefile.mk20
-rw-r--r--lib/builtins/arm/adddf3vfp.S26
-rw-r--r--lib/builtins/arm/addsf3vfp.S26
-rw-r--r--lib/builtins/arm/aeabi_dcmp.S40
-rw-r--r--lib/builtins/arm/aeabi_div0.c43
-rw-r--r--lib/builtins/arm/aeabi_fcmp.S40
-rw-r--r--lib/builtins/arm/aeabi_idivmod.S28
-rw-r--r--lib/builtins/arm/aeabi_ldivmod.S31
-rw-r--r--lib/builtins/arm/aeabi_memcmp.S20
-rw-r--r--lib/builtins/arm/aeabi_memcpy.S20
-rw-r--r--lib/builtins/arm/aeabi_memmove.S20
-rw-r--r--lib/builtins/arm/aeabi_memset.S34
-rw-r--r--lib/builtins/arm/aeabi_uidivmod.S29
-rw-r--r--lib/builtins/arm/aeabi_uldivmod.S31
-rw-r--r--lib/builtins/arm/bswapdi2.S47
-rw-r--r--lib/builtins/arm/bswapsi2.S39
-rw-r--r--lib/builtins/arm/clzdi2.S97
-rw-r--r--lib/builtins/arm/clzsi2.S76
-rw-r--r--lib/builtins/arm/comparesf2.S148
-rw-r--r--lib/builtins/arm/divdf3vfp.S26
-rw-r--r--lib/builtins/arm/divmodsi4.S74
-rw-r--r--lib/builtins/arm/divsf3vfp.S26
-rw-r--r--lib/builtins/arm/divsi3.S65
-rw-r--r--lib/builtins/arm/eqdf2vfp.S29
-rw-r--r--lib/builtins/arm/eqsf2vfp.S29
-rw-r--r--lib/builtins/arm/extendsfdf2vfp.S26
-rw-r--r--lib/builtins/arm/fixdfsivfp.S26
-rw-r--r--lib/builtins/arm/fixsfsivfp.S26
-rw-r--r--lib/builtins/arm/fixunsdfsivfp.S27
-rw-r--r--lib/builtins/arm/fixunssfsivfp.S27
-rw-r--r--lib/builtins/arm/floatsidfvfp.S26
-rw-r--r--lib/builtins/arm/floatsisfvfp.S26
-rw-r--r--lib/builtins/arm/floatunssidfvfp.S26
-rw-r--r--lib/builtins/arm/floatunssisfvfp.S26
-rw-r--r--lib/builtins/arm/gedf2vfp.S29
-rw-r--r--lib/builtins/arm/gesf2vfp.S29
-rw-r--r--lib/builtins/arm/gtdf2vfp.S29
-rw-r--r--lib/builtins/arm/gtsf2vfp.S29
-rw-r--r--lib/builtins/arm/ledf2vfp.S29
-rw-r--r--lib/builtins/arm/lesf2vfp.S29
-rw-r--r--lib/builtins/arm/ltdf2vfp.S29
-rw-r--r--lib/builtins/arm/ltsf2vfp.S29
-rw-r--r--lib/builtins/arm/modsi3.S63
-rw-r--r--lib/builtins/arm/muldf3vfp.S26
-rw-r--r--lib/builtins/arm/mulsf3vfp.S26
-rw-r--r--lib/builtins/arm/nedf2vfp.S29
-rw-r--r--lib/builtins/arm/negdf2vfp.S23
-rw-r--r--lib/builtins/arm/negsf2vfp.S23
-rw-r--r--lib/builtins/arm/nesf2vfp.S29
-rw-r--r--lib/builtins/arm/restore_vfp_d8_d15_regs.S33
-rw-r--r--lib/builtins/arm/save_vfp_d8_d15_regs.S33
-rw-r--r--lib/builtins/arm/softfloat-alias.list (renamed from lib/arm/softfloat-alias.list)0
-rw-r--r--lib/builtins/arm/subdf3vfp.S26
-rw-r--r--lib/builtins/arm/subsf3vfp.S27
-rw-r--r--lib/builtins/arm/switch16.S44
-rw-r--r--lib/builtins/arm/switch32.S44
-rw-r--r--lib/builtins/arm/switch8.S42
-rw-r--r--lib/builtins/arm/switchu8.S42
-rw-r--r--lib/builtins/arm/sync-ops.h64
-rw-r--r--lib/builtins/arm/sync_fetch_and_add_4.S21
-rw-r--r--lib/builtins/arm/sync_fetch_and_add_8.S24
-rw-r--r--lib/builtins/arm/sync_fetch_and_and_4.S19
-rw-r--r--lib/builtins/arm/sync_fetch_and_and_8.S23
-rw-r--r--lib/builtins/arm/sync_fetch_and_max_4.S20
-rw-r--r--lib/builtins/arm/sync_fetch_and_max_8.S21
-rw-r--r--lib/builtins/arm/sync_fetch_and_min_4.S20
-rw-r--r--lib/builtins/arm/sync_fetch_and_min_8.S21
-rw-r--r--lib/builtins/arm/sync_fetch_and_nand_4.S20
-rw-r--r--lib/builtins/arm/sync_fetch_and_nand_8.S24
-rw-r--r--lib/builtins/arm/sync_fetch_and_or_4.S20
-rw-r--r--lib/builtins/arm/sync_fetch_and_or_8.S24
-rw-r--r--lib/builtins/arm/sync_fetch_and_sub_4.S21
-rw-r--r--lib/builtins/arm/sync_fetch_and_sub_8.S24
-rw-r--r--lib/builtins/arm/sync_fetch_and_umax_4.S20
-rw-r--r--lib/builtins/arm/sync_fetch_and_umax_8.S21
-rw-r--r--lib/builtins/arm/sync_fetch_and_umin_4.S20
-rw-r--r--lib/builtins/arm/sync_fetch_and_umin_8.S21
-rw-r--r--lib/builtins/arm/sync_fetch_and_xor_4.S20
-rw-r--r--lib/builtins/arm/sync_fetch_and_xor_8.S24
-rw-r--r--lib/builtins/arm/sync_synchronize.S35
-rw-r--r--lib/builtins/arm/truncdfsf2vfp.S26
-rw-r--r--lib/builtins/arm/udivmodsi4.S184
-rw-r--r--lib/builtins/arm/udivsi3.S170
-rw-r--r--lib/builtins/arm/umodsi3.S161
-rw-r--r--lib/builtins/arm/unorddf2vfp.S29
-rw-r--r--lib/builtins/arm/unordsf2vfp.S29
-rw-r--r--lib/builtins/arm64/Makefile.mk20
-rw-r--r--lib/builtins/armv6m/Makefile.mk20
-rw-r--r--lib/builtins/ashldi3.c (renamed from lib/ashldi3.c)0
-rw-r--r--lib/builtins/ashlti3.c45
-rw-r--r--lib/builtins/ashrdi3.c (renamed from lib/ashrdi3.c)0
-rw-r--r--lib/builtins/ashrti3.c46
-rw-r--r--lib/builtins/assembly.h149
-rw-r--r--lib/builtins/atomic.c (renamed from lib/atomic.c)0
-rw-r--r--lib/builtins/clear_cache.c96
-rw-r--r--lib/builtins/clzdi2.c (renamed from lib/clzdi2.c)0
-rw-r--r--lib/builtins/clzsi2.c (renamed from lib/clzsi2.c)0
-rw-r--r--lib/builtins/clzti2.c33
-rw-r--r--lib/builtins/cmpdi2.c (renamed from lib/cmpdi2.c)0
-rw-r--r--lib/builtins/cmpti2.c42
-rw-r--r--lib/builtins/comparedf2.c141
-rw-r--r--lib/builtins/comparesf2.c140
-rw-r--r--lib/builtins/comparetf2.c133
-rw-r--r--lib/builtins/ctzdi2.c (renamed from lib/ctzdi2.c)0
-rw-r--r--lib/builtins/ctzsi2.c (renamed from lib/ctzsi2.c)0
-rw-r--r--lib/builtins/ctzti2.c33
-rw-r--r--lib/builtins/divdc3.c60
-rw-r--r--lib/builtins/divdf3.c185
-rw-r--r--lib/builtins/divdi3.c29
-rw-r--r--lib/builtins/divmoddi4.c25
-rw-r--r--lib/builtins/divmodsi4.c27
-rw-r--r--lib/builtins/divsc3.c60
-rw-r--r--lib/builtins/divsf3.c169
-rw-r--r--lib/builtins/divsi3.c37
-rw-r--r--lib/builtins/divtf3.c203
-rw-r--r--lib/builtins/divti3.c33
-rw-r--r--lib/builtins/divxc3.c63
-rw-r--r--lib/builtins/enable_execute_stack.c58
-rw-r--r--lib/builtins/eprintf.c35
-rw-r--r--lib/builtins/extenddftf2.c23
-rw-r--r--lib/builtins/extendsfdf2.c19
-rw-r--r--lib/builtins/extendsftf2.c23
-rw-r--r--lib/builtins/ffsdi2.c (renamed from lib/ffsdi2.c)0
-rw-r--r--lib/builtins/ffsti2.c37
-rw-r--r--lib/builtins/fixdfdi.c45
-rw-r--r--lib/builtins/fixdfsi.c50
-rw-r--r--lib/builtins/fixdfti.c45
-rw-r--r--lib/builtins/fixsfdi.c (renamed from lib/fixsfdi.c)0
-rw-r--r--lib/builtins/fixsfsi.c (renamed from lib/fixsfsi.c)0
-rw-r--r--lib/builtins/fixsfti.c45
-rw-r--r--lib/builtins/fixunsdfdi.c (renamed from lib/fixunsdfdi.c)0
-rw-r--r--lib/builtins/fixunsdfsi.c (renamed from lib/fixunsdfsi.c)0
-rw-r--r--lib/builtins/fixunsdfti.c47
-rw-r--r--lib/builtins/fixunssfdi.c (renamed from lib/fixunssfdi.c)0
-rw-r--r--lib/builtins/fixunssfsi.c (renamed from lib/fixunssfsi.c)0
-rw-r--r--lib/builtins/fixunssfti.c47
-rw-r--r--lib/builtins/fixunsxfdi.c44
-rw-r--r--lib/builtins/fixunsxfsi.c44
-rw-r--r--lib/builtins/fixunsxfti.c49
-rw-r--r--lib/builtins/fixxfdi.c44
-rw-r--r--lib/builtins/fixxfti.c47
-rw-r--r--lib/builtins/floatdidf.c (renamed from lib/floatdidf.c)0
-rw-r--r--lib/builtins/floatdisf.c (renamed from lib/floatdisf.c)0
-rw-r--r--lib/builtins/floatdixf.c46
-rw-r--r--lib/builtins/floatsidf.c53
-rw-r--r--lib/builtins/floatsisf.c59
-rw-r--r--lib/builtins/floatsitf.c52
-rw-r--r--lib/builtins/floattidf.c83
-rw-r--r--lib/builtins/floattisf.c82
-rw-r--r--lib/builtins/floattixf.c84
-rw-r--r--lib/builtins/floatundidf.c106
-rw-r--r--lib/builtins/floatundisf.c (renamed from lib/floatundisf.c)0
-rw-r--r--lib/builtins/floatundixf.c42
-rw-r--r--lib/builtins/floatunsidf.c42
-rw-r--r--lib/builtins/floatunsisf.c50
-rw-r--r--lib/builtins/floatunsitf.c40
-rw-r--r--lib/builtins/floatuntidf.c80
-rw-r--r--lib/builtins/floatuntisf.c79
-rw-r--r--lib/builtins/floatuntixf.c81
-rw-r--r--lib/builtins/fp_add_impl.inc144
-rw-r--r--lib/builtins/fp_extend.h76
-rw-r--r--lib/builtins/fp_extend_impl.inc106
-rw-r--r--lib/builtins/fp_lib.h270
-rw-r--r--lib/builtins/fp_mul_impl.inc116
-rw-r--r--lib/builtins/fp_trunc.h64
-rw-r--r--lib/builtins/fp_trunc_impl.inc135
-rw-r--r--lib/builtins/gcc_personality_v0.c249
-rw-r--r--lib/builtins/i386/Makefile.mk20
-rw-r--r--lib/builtins/i386/ashldi3.S58
-rw-r--r--lib/builtins/i386/ashrdi3.S69
-rw-r--r--lib/builtins/i386/divdi3.S162
-rw-r--r--lib/builtins/i386/floatdidf.S39
-rw-r--r--lib/builtins/i386/floatdisf.S32
-rw-r--r--lib/builtins/i386/floatdixf.S30
-rw-r--r--lib/builtins/i386/floatundidf.S52
-rw-r--r--lib/builtins/i386/floatundisf.S105
-rw-r--r--lib/builtins/i386/floatundixf.S43
-rw-r--r--lib/builtins/i386/lshrdi3.S59
-rw-r--r--lib/builtins/i386/moddi3.S166
-rw-r--r--lib/builtins/i386/muldi3.S30
-rw-r--r--lib/builtins/i386/udivdi3.S115
-rw-r--r--lib/builtins/i386/umoddi3.S126
-rw-r--r--lib/builtins/int_endianness.h112
-rw-r--r--lib/builtins/int_lib.h70
-rw-r--r--lib/builtins/int_math.h (renamed from lib/int_math.h)0
-rw-r--r--lib/builtins/int_types.h143
-rw-r--r--lib/builtins/int_util.c (renamed from lib/int_util.c)0
-rw-r--r--lib/builtins/int_util.h29
-rw-r--r--lib/builtins/lshrdi3.c (renamed from lib/lshrdi3.c)0
-rw-r--r--lib/builtins/lshrti3.c45
-rw-r--r--lib/builtins/moddi3.c30
-rw-r--r--lib/builtins/modsi3.c23
-rw-r--r--lib/builtins/modti3.c34
-rw-r--r--lib/builtins/muldc3.c73
-rw-r--r--lib/builtins/muldf3.c22
-rw-r--r--lib/builtins/muldi3.c (renamed from lib/muldi3.c)0
-rw-r--r--lib/builtins/mulodi4.c58
-rw-r--r--lib/builtins/mulosi4.c58
-rw-r--r--lib/builtins/muloti4.c62
-rw-r--r--lib/builtins/mulsc3.c73
-rw-r--r--lib/builtins/mulsf3.c22
-rw-r--r--lib/builtins/multf3.c25
-rw-r--r--lib/builtins/multi3.c58
-rw-r--r--lib/builtins/mulvdi3.c56
-rw-r--r--lib/builtins/mulvsi3.c56
-rw-r--r--lib/builtins/mulvti3.c60
-rw-r--r--lib/builtins/mulxc3.c77
-rw-r--r--lib/builtins/negdf2.c22
-rw-r--r--lib/builtins/negdi2.c26
-rw-r--r--lib/builtins/negsf2.c (renamed from lib/negsf2.c)0
-rw-r--r--lib/builtins/negti2.c30
-rw-r--r--lib/builtins/negvdi2.c (renamed from lib/negvdi2.c)0
-rw-r--r--lib/builtins/negvsi2.c (renamed from lib/negvsi2.c)0
-rw-r--r--lib/builtins/negvti2.c32
-rw-r--r--lib/builtins/paritydi2.c25
-rw-r--r--lib/builtins/paritysi2.c (renamed from lib/paritysi2.c)0
-rw-r--r--lib/builtins/parityti2.c29
-rw-r--r--lib/builtins/popcountdi2.c (renamed from lib/popcountdi2.c)0
-rw-r--r--lib/builtins/popcountsi2.c (renamed from lib/popcountsi2.c)0
-rw-r--r--lib/builtins/popcountti2.c44
-rw-r--r--lib/builtins/powidf2.c (renamed from lib/powidf2.c)0
-rw-r--r--lib/builtins/powisf2.c (renamed from lib/powisf2.c)0
-rw-r--r--lib/builtins/powitf2.c38
-rw-r--r--lib/builtins/powixf2.c38
-rw-r--r--lib/builtins/ppc/DD.h46
-rw-r--r--lib/builtins/ppc/Makefile.mk20
-rw-r--r--lib/builtins/ppc/divtc3.c (renamed from lib/ppc/divtc3.c)0
-rw-r--r--lib/builtins/ppc/fixtfdi.c104
-rw-r--r--lib/builtins/ppc/fixunstfdi.c (renamed from lib/ppc/fixunstfdi.c)0
-rw-r--r--lib/builtins/ppc/floatditf.c (renamed from lib/ppc/floatditf.c)0
-rw-r--r--lib/builtins/ppc/floatunditf.c (renamed from lib/ppc/floatunditf.c)0
-rw-r--r--lib/builtins/ppc/gcc_qadd.c76
-rw-r--r--lib/builtins/ppc/gcc_qdiv.c (renamed from lib/ppc/gcc_qdiv.c)0
-rw-r--r--lib/builtins/ppc/gcc_qmul.c (renamed from lib/ppc/gcc_qmul.c)0
-rw-r--r--lib/builtins/ppc/gcc_qsub.c76
-rw-r--r--lib/builtins/ppc/multc3.c (renamed from lib/ppc/multc3.c)0
-rw-r--r--lib/builtins/ppc/restFP.S (renamed from lib/ppc/restFP.S)0
-rw-r--r--lib/builtins/ppc/saveFP.S (renamed from lib/ppc/saveFP.S)0
-rw-r--r--lib/builtins/subdf3.c26
-rw-r--r--lib/builtins/subsf3.c26
-rw-r--r--lib/builtins/subtf3.c27
-rw-r--r--lib/builtins/subvdi3.c36
-rw-r--r--lib/builtins/subvsi3.c36
-rw-r--r--lib/builtins/subvti3.c40
-rw-r--r--lib/builtins/trampoline_setup.c48
-rw-r--r--lib/builtins/truncdfsf2.c18
-rw-r--r--lib/builtins/trunctfdf2.c22
-rw-r--r--lib/builtins/trunctfsf2.c22
-rw-r--r--lib/builtins/ucmpdi2.c (renamed from lib/ucmpdi2.c)0
-rw-r--r--lib/builtins/ucmpti2.c42
-rw-r--r--lib/builtins/udivdi3.c23
-rw-r--r--lib/builtins/udivmoddi4.c231
-rw-r--r--lib/builtins/udivmodsi4.c27
-rw-r--r--lib/builtins/udivmodti4.c238
-rw-r--r--lib/builtins/udivsi3.c (renamed from lib/udivsi3.c)0
-rw-r--r--lib/builtins/udivti3.c27
-rw-r--r--lib/builtins/umoddi3.c25
-rw-r--r--lib/builtins/umodsi3.c23
-rw-r--r--lib/builtins/umodti3.c29
-rw-r--r--lib/builtins/x86_64/Makefile.mk20
-rw-r--r--lib/builtins/x86_64/floatdidf.c (renamed from lib/x86_64/floatdidf.c)0
-rw-r--r--lib/builtins/x86_64/floatdisf.c (renamed from lib/x86_64/floatdisf.c)0
-rw-r--r--lib/builtins/x86_64/floatdixf.c (renamed from lib/x86_64/floatdixf.c)0
-rw-r--r--lib/builtins/x86_64/floatundidf.S49
-rw-r--r--lib/builtins/x86_64/floatundisf.S35
-rw-r--r--lib/builtins/x86_64/floatundixf.S68
-rw-r--r--lib/clear_cache.c40
-rw-r--r--lib/clzti2.c33
-rw-r--r--lib/cmpti2.c42
-rw-r--r--lib/comparedf2.c134
-rw-r--r--lib/comparesf2.c133
-rw-r--r--lib/ctzti2.c33
-rw-r--r--lib/dfsan/CMakeLists.txt48
-rw-r--r--lib/dfsan/dfsan.cc119
-rw-r--r--lib/dfsan/dfsan.h12
-rw-r--r--lib/dfsan/dfsan_custom.cc833
-rw-r--r--lib/dfsan/done_abilist.txt255
-rw-r--r--lib/dfsan/libc_ubuntu1204_abilist.txt3685
-rw-r--r--lib/dfsan/libc_ubuntu1404_abilist.txt3433
-rw-r--r--lib/dfsan/lit_tests/CMakeLists.txt21
-rw-r--r--lib/dfsan/lit_tests/Inputs/flags_abilist.txt10
-rw-r--r--lib/dfsan/lit_tests/basic.c21
-rw-r--r--lib/dfsan/lit_tests/custom.c154
-rw-r--r--lib/dfsan/lit_tests/flags.c24
-rw-r--r--lib/dfsan/lit_tests/fncall.c26
-rw-r--r--lib/dfsan/lit_tests/lit.cfg69
-rw-r--r--lib/dfsan/lit_tests/lit.site.cfg.in5
-rw-r--r--lib/dfsan/lit_tests/propagate.c47
-rwxr-xr-xlib/dfsan/scripts/build-libc-list.py36
-rwxr-xr-xlib/dfsan/scripts/check_custom_wrappers.sh50
-rw-r--r--lib/divdc3.c60
-rw-r--r--lib/divdf3.c184
-rw-r--r--lib/divdi3.c31
-rw-r--r--lib/divmoddi4.c27
-rw-r--r--lib/divmodsi4.c30
-rw-r--r--lib/divsc3.c60
-rw-r--r--lib/divsf3.c168
-rw-r--r--lib/divsi3.c39
-rw-r--r--lib/divti3.c35
-rw-r--r--lib/divxc3.c63
-rw-r--r--lib/enable_execute_stack.c59
-rw-r--r--lib/eprintf.c34
-rw-r--r--lib/extendsfdf2.c137
-rw-r--r--lib/ffsti2.c37
-rw-r--r--lib/fixdfdi.c45
-rw-r--r--lib/fixdfsi.c49
-rw-r--r--lib/fixdfti.c45
-rw-r--r--lib/fixsfti.c45
-rw-r--r--lib/fixunsdfti.c47
-rw-r--r--lib/fixunssfti.c47
-rw-r--r--lib/fixunsxfdi.c44
-rw-r--r--lib/fixunsxfsi.c44
-rw-r--r--lib/fixunsxfti.c49
-rw-r--r--lib/fixxfdi.c44
-rw-r--r--lib/fixxfti.c47
-rw-r--r--lib/floatdixf.c46
-rw-r--r--lib/floatsidf.c52
-rw-r--r--lib/floatsisf.c58
-rw-r--r--lib/floattidf.c85
-rw-r--r--lib/floattisf.c84
-rw-r--r--lib/floattixf.c86
-rw-r--r--lib/floatundidf.c107
-rw-r--r--lib/floatundixf.c42
-rw-r--r--lib/floatunsidf.c41
-rw-r--r--lib/floatunsisf.c49
-rw-r--r--lib/floatuntidf.c82
-rw-r--r--lib/floatuntisf.c81
-rw-r--r--lib/floatuntixf.c83
-rw-r--r--lib/fp_lib.h144
-rw-r--r--lib/gcc_personality_v0.c247
-rw-r--r--lib/i386/Makefile.mk20
-rw-r--r--lib/i386/ashldi3.S56
-rw-r--r--lib/i386/ashrdi3.S67
-rw-r--r--lib/i386/divdi3.S161
-rw-r--r--lib/i386/floatdidf.S35
-rw-r--r--lib/i386/floatdisf.S31
-rw-r--r--lib/i386/floatdixf.S29
-rw-r--r--lib/i386/floatundidf.S46
-rw-r--r--lib/i386/floatundisf.S99
-rw-r--r--lib/i386/floatundixf.S37
-rw-r--r--lib/i386/lshrdi3.S57
-rw-r--r--lib/i386/moddi3.S166
-rw-r--r--lib/i386/muldi3.S29
-rw-r--r--lib/i386/udivdi3.S114
-rw-r--r--lib/i386/umoddi3.S125
-rw-r--r--lib/int_endianness.h111
-rw-r--r--lib/int_lib.h46
-rw-r--r--lib/int_types.h140
-rw-r--r--lib/int_util.h29
-rw-r--r--lib/interception/CMakeLists.txt5
-rw-r--r--lib/interception/interception.h31
-rw-r--r--lib/interception/interception_linux.cc6
-rw-r--r--lib/interception/interception_linux.h20
-rw-r--r--lib/interception/interception_type_test.cc12
-rw-r--r--lib/interception/interception_win.cc185
-rw-r--r--lib/interception/interception_win.h32
-rw-r--r--lib/lit.common.cfg62
-rw-r--r--lib/lit.common.configured.in27
-rw-r--r--lib/lit.common.unit.cfg30
-rw-r--r--lib/lit.common.unit.configured.in23
-rw-r--r--lib/lsan/CMakeLists.txt27
-rw-r--r--lib/lsan/lit_tests/AsanConfig/lit.cfg32
-rw-r--r--lib/lsan/lit_tests/AsanConfig/lit.site.cfg.in8
-rw-r--r--lib/lsan/lit_tests/CMakeLists.txt37
-rw-r--r--lib/lsan/lit_tests/LsanConfig/lit.cfg30
-rw-r--r--lib/lsan/lit_tests/LsanConfig/lit.site.cfg.in8
-rw-r--r--lib/lsan/lit_tests/TestCases/SharedLibs/huge_tls_lib_so.cc12
-rw-r--r--lib/lsan/lit_tests/TestCases/SharedLibs/lit.local.cfg4
-rw-r--r--lib/lsan/lit_tests/TestCases/cleanup_in_tsd_destructor.cc45
-rw-r--r--lib/lsan/lit_tests/TestCases/disabler.cc23
-rw-r--r--lib/lsan/lit_tests/TestCases/disabler_in_tsd_destructor.cc38
-rw-r--r--lib/lsan/lit_tests/TestCases/do_leak_check_override.cc36
-rw-r--r--lib/lsan/lit_tests/TestCases/fork.cc24
-rw-r--r--lib/lsan/lit_tests/TestCases/fork_threaded.cc43
-rw-r--r--lib/lsan/lit_tests/TestCases/high_allocator_contention.cc48
-rw-r--r--lib/lsan/lit_tests/TestCases/ignore_object.cc30
-rw-r--r--lib/lsan/lit_tests/TestCases/ignore_object_errors.cc22
-rw-r--r--lib/lsan/lit_tests/TestCases/large_allocation_leak.cc18
-rw-r--r--lib/lsan/lit_tests/TestCases/leak_check_at_exit.cc19
-rw-r--r--lib/lsan/lit_tests/TestCases/link_turned_off.cc24
-rw-r--r--lib/lsan/lit_tests/TestCases/pointer_to_self.cc18
-rw-r--r--lib/lsan/lit_tests/TestCases/sanity_check_pure_c.c10
-rw-r--r--lib/lsan/lit_tests/TestCases/stale_stack_leak.cc42
-rw-r--r--lib/lsan/lit_tests/TestCases/suppressions_default.cc29
-rw-r--r--lib/lsan/lit_tests/TestCases/suppressions_file.cc29
-rw-r--r--lib/lsan/lit_tests/TestCases/suppressions_file.cc.supp1
-rw-r--r--lib/lsan/lit_tests/TestCases/swapcontext.cc42
-rw-r--r--lib/lsan/lit_tests/TestCases/use_after_return.cc23
-rw-r--r--lib/lsan/lit_tests/TestCases/use_globals_initialized.cc21
-rw-r--r--lib/lsan/lit_tests/TestCases/use_globals_uninitialized.cc21
-rw-r--r--lib/lsan/lit_tests/TestCases/use_registers.cc51
-rw-r--r--lib/lsan/lit_tests/TestCases/use_stacks.cc20
-rw-r--r--lib/lsan/lit_tests/TestCases/use_stacks_threaded.cc36
-rw-r--r--lib/lsan/lit_tests/TestCases/use_tls_dynamic.cc33
-rw-r--r--lib/lsan/lit_tests/TestCases/use_tls_pthread_specific_dynamic.cc37
-rw-r--r--lib/lsan/lit_tests/TestCases/use_tls_pthread_specific_static.cc31
-rw-r--r--lib/lsan/lit_tests/TestCases/use_tls_static.cc21
-rw-r--r--lib/lsan/lit_tests/TestCases/use_unaligned.cc23
-rw-r--r--lib/lsan/lit_tests/Unit/lit.site.cfg.in12
-rw-r--r--lib/lsan/lit_tests/lit.common.cfg43
-rw-r--r--lib/lsan/lsan.cc26
-rw-r--r--lib/lsan/lsan.h20
-rw-r--r--lib/lsan/lsan_allocator.cc50
-rw-r--r--lib/lsan/lsan_allocator.h2
-rw-r--r--lib/lsan/lsan_common.cc430
-rw-r--r--lib/lsan/lsan_common.h49
-rw-r--r--lib/lsan/lsan_common_linux.cc32
-rw-r--r--lib/lsan/lsan_interceptors.cc50
-rw-r--r--lib/lsan/lsan_preinit.cc6
-rw-r--r--lib/lsan/tests/CMakeLists.txt58
-rw-r--r--lib/lsan/tests/lsan_dummy_unittest.cc22
-rw-r--r--lib/lsan/tests/lsan_testlib.cc25
-rw-r--r--lib/lshrti3.c45
-rw-r--r--lib/moddi3.c32
-rw-r--r--lib/modsi3.c25
-rw-r--r--lib/modti3.c36
-rw-r--r--lib/msan/CMakeLists.txt42
-rw-r--r--lib/msan/lit_tests/CMakeLists.txt31
-rw-r--r--lib/msan/lit_tests/Linux/glob.cc27
-rw-r--r--lib/msan/lit_tests/Linux/glob_altdirfunc.cc78
-rw-r--r--lib/msan/lit_tests/Linux/glob_nomatch.cc21
-rw-r--r--lib/msan/lit_tests/Linux/glob_test_root/aa0
-rw-r--r--lib/msan/lit_tests/Linux/glob_test_root/ab0
-rw-r--r--lib/msan/lit_tests/Linux/glob_test_root/ba0
-rw-r--r--lib/msan/lit_tests/Linux/lit.local.cfg9
-rw-r--r--lib/msan/lit_tests/Linux/syscalls.cc100
-rw-r--r--lib/msan/lit_tests/Linux/tcgetattr.cc21
-rw-r--r--lib/msan/lit_tests/SharedLibs/dso-origin-so.cc14
-rw-r--r--lib/msan/lit_tests/SharedLibs/dso-origin.h4
-rw-r--r--lib/msan/lit_tests/SharedLibs/lit.local.cfg4
-rw-r--r--lib/msan/lit_tests/Unit/lit.site.cfg.in13
-rw-r--r--lib/msan/lit_tests/allocator_returns_null.cc81
-rw-r--r--lib/msan/lit_tests/backtrace.cc26
-rw-r--r--lib/msan/lit_tests/c-strdup.c17
-rw-r--r--lib/msan/lit_tests/cxa_atexit.cc28
-rw-r--r--lib/msan/lit_tests/default_blacklist.cc3
-rw-r--r--lib/msan/lit_tests/dlerror.cc14
-rw-r--r--lib/msan/lit_tests/dso-origin.cc25
-rw-r--r--lib/msan/lit_tests/errno.cc17
-rw-r--r--lib/msan/lit_tests/getaddrinfo-positive.cc23
-rw-r--r--lib/msan/lit_tests/getaddrinfo.cc24
-rw-r--r--lib/msan/lit_tests/getline.cc30
-rw-r--r--lib/msan/lit_tests/getline_test_data2
-rw-r--r--lib/msan/lit_tests/heap-origin.cc31
-rw-r--r--lib/msan/lit_tests/initgroups.cc11
-rw-r--r--lib/msan/lit_tests/inline.cc20
-rw-r--r--lib/msan/lit_tests/insertvalue_origin.cc35
-rw-r--r--lib/msan/lit_tests/ioctl.cc20
-rw-r--r--lib/msan/lit_tests/ioctl_custom.cc33
-rw-r--r--lib/msan/lit_tests/keep-going-dso.cc33
-rw-r--r--lib/msan/lit_tests/keep-going.cc34
-rw-r--r--lib/msan/lit_tests/lit.cfg74
-rw-r--r--lib/msan/lit_tests/lit.site.cfg.in5
-rw-r--r--lib/msan/lit_tests/malloc_hook.cc36
-rw-r--r--lib/msan/lit_tests/no_sanitize_memory.cc34
-rw-r--r--lib/msan/lit_tests/no_sanitize_memory_prop.cc33
-rw-r--r--lib/msan/lit_tests/poison_in_free.cc16
-rw-r--r--lib/msan/lit_tests/ptrace.cc36
-rw-r--r--lib/msan/lit_tests/readdir64.cc27
-rw-r--r--lib/msan/lit_tests/scandir.cc56
-rw-r--r--lib/msan/lit_tests/scandir_null.cc34
-rw-r--r--lib/msan/lit_tests/scandir_test_root/aaa0
-rw-r--r--lib/msan/lit_tests/scandir_test_root/aab0
-rw-r--r--lib/msan/lit_tests/scandir_test_root/bbb0
-rw-r--r--lib/msan/lit_tests/select.cc22
-rw-r--r--lib/msan/lit_tests/setlocale.cc13
-rw-r--r--lib/msan/lit_tests/signal_stress_test.cc71
-rw-r--r--lib/msan/lit_tests/sigwait.cc30
-rw-r--r--lib/msan/lit_tests/sigwaitinfo.cc31
-rw-r--r--lib/msan/lit_tests/stack-origin.cc31
-rw-r--r--lib/msan/lit_tests/sync_lock_set_and_test.cc7
-rw-r--r--lib/msan/lit_tests/tzset.cc16
-rw-r--r--lib/msan/lit_tests/unaligned_read_origin.cc16
-rw-r--r--lib/msan/lit_tests/use-after-free.cc34
-rw-r--r--lib/msan/lit_tests/vector_cvt.cc23
-rw-r--r--lib/msan/lit_tests/vector_select.cc13
-rw-r--r--lib/msan/lit_tests/wrap_indirect_calls.cc64
-rw-r--r--lib/msan/lit_tests/wrap_indirect_calls/caller.cc51
-rw-r--r--lib/msan/lit_tests/wrap_indirect_calls/lit.local.cfg3
-rw-r--r--lib/msan/lit_tests/wrap_indirect_calls/one.cc3
-rw-r--r--lib/msan/lit_tests/wrap_indirect_calls/two.cc11
-rw-r--r--lib/msan/lit_tests/wrap_indirect_calls/wrapper.cc11
-rw-r--r--lib/msan/msan.cc394
-rw-r--r--lib/msan/msan.h156
-rw-r--r--lib/msan/msan_allocator.cc154
-rw-r--r--lib/msan/msan_allocator.h33
-rw-r--r--lib/msan/msan_chained_origin_depot.cc126
-rw-r--r--lib/msan/msan_chained_origin_depot.h29
-rw-r--r--lib/msan/msan_flags.h5
-rw-r--r--lib/msan/msan_interceptors.cc1030
-rw-r--r--lib/msan/msan_interface_internal.h75
-rw-r--r--lib/msan/msan_linux.cc156
-rw-r--r--lib/msan/msan_new_delete.cc13
-rw-r--r--lib/msan/msan_origin.h169
-rw-r--r--lib/msan/msan_report.cc221
-rw-r--r--lib/msan/msan_thread.cc93
-rw-r--r--lib/msan/msan_thread.h71
-rw-r--r--lib/msan/tests/CMakeLists.txt137
-rw-r--r--lib/msan/tests/msan_loadable.cc18
-rw-r--r--lib/msan/tests/msan_test.cc1322
-rw-r--r--lib/msan/tests/msandr_test_so.cc38
-rw-r--r--lib/msan/tests/msandr_test_so.h24
-rw-r--r--lib/msandr/CMakeLists.txt26
-rw-r--r--lib/msandr/README.txt40
-rw-r--r--lib/msandr/msandr.cc871
-rw-r--r--lib/muldc3.c73
-rw-r--r--lib/muldf3.c122
-rw-r--r--lib/mulodi4.c58
-rw-r--r--lib/mulosi4.c58
-rw-r--r--lib/muloti4.c62
-rw-r--r--lib/mulsc3.c73
-rw-r--r--lib/mulsf3.c112
-rw-r--r--lib/multi3.c58
-rw-r--r--lib/mulvdi3.c56
-rw-r--r--lib/mulvsi3.c56
-rw-r--r--lib/mulvti3.c60
-rw-r--r--lib/mulxc3.c77
-rw-r--r--lib/negdf2.c21
-rw-r--r--lib/negdi2.c26
-rw-r--r--lib/negti2.c30
-rw-r--r--lib/negvti2.c32
-rw-r--r--lib/paritydi2.c27
-rw-r--r--lib/parityti2.c31
-rw-r--r--lib/popcountti2.c44
-rw-r--r--lib/powitf2.c38
-rw-r--r--lib/powixf2.c38
-rw-r--r--lib/ppc/DD.h46
-rw-r--r--lib/ppc/Makefile.mk20
-rw-r--r--lib/ppc/fixtfdi.c104
-rw-r--r--lib/ppc/gcc_qadd.c76
-rw-r--r--lib/ppc/gcc_qsub.c76
-rw-r--r--lib/profile/CMakeLists.txt20
-rw-r--r--lib/profile/GCDAProfiling.c127
-rw-r--r--lib/profile/InstrProfiling.c48
-rw-r--r--lib/profile/InstrProfiling.h92
-rw-r--r--lib/profile/InstrProfilingBuffer.c104
-rw-r--r--lib/profile/InstrProfilingFile.c194
-rw-r--r--lib/profile/InstrProfilingInternal.h40
-rw-r--r--lib/profile/InstrProfilingPlatformDarwin.c43
-rw-r--r--lib/profile/InstrProfilingPlatformOther.c74
-rw-r--r--lib/profile/InstrProfilingRuntime.cc30
-rw-r--r--lib/profile/Makefile.mk4
-rw-r--r--lib/sanitizer_common/CMakeLists.txt90
-rw-r--r--lib/sanitizer_common/sanitizer_addrhashmap.h342
-rw-r--r--lib/sanitizer_common/sanitizer_allocator.cc4
-rw-r--r--lib/sanitizer_common/sanitizer_allocator.h128
-rw-r--r--lib/sanitizer_common/sanitizer_allocator_interface.h38
-rw-r--r--lib/sanitizer_common/sanitizer_allocator_internal.h32
-rw-r--r--lib/sanitizer_common/sanitizer_asm.h40
-rw-r--r--lib/sanitizer_common/sanitizer_atomic.h3
-rw-r--r--lib/sanitizer_common/sanitizer_atomic_clang.h71
-rw-r--r--lib/sanitizer_common/sanitizer_atomic_clang_other.h97
-rw-r--r--lib/sanitizer_common/sanitizer_atomic_clang_x86.h116
-rw-r--r--lib/sanitizer_common/sanitizer_atomic_msvc.h100
-rw-r--r--lib/sanitizer_common/sanitizer_bitvector.h351
-rw-r--r--lib/sanitizer_common/sanitizer_bvgraph.h165
-rw-r--r--lib/sanitizer_common/sanitizer_common.cc187
-rw-r--r--lib/sanitizer_common/sanitizer_common.h156
-rw-r--r--lib/sanitizer_common/sanitizer_common_interceptors.inc2604
-rw-r--r--lib/sanitizer_common/sanitizer_common_interceptors_format.inc559
-rwxr-xr-xlib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc60
-rw-r--r--lib/sanitizer_common/sanitizer_common_interceptors_scanf.inc311
-rw-r--r--lib/sanitizer_common/sanitizer_common_libcdep.cc54
-rw-r--r--lib/sanitizer_common/sanitizer_common_syscalls.inc163
-rw-r--r--lib/sanitizer_common/sanitizer_coverage.cc113
-rw-r--r--lib/sanitizer_common/sanitizer_coverage_libcdep.cc581
-rw-r--r--lib/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc125
-rw-r--r--lib/sanitizer_common/sanitizer_deadlock_detector.h412
-rw-r--r--lib/sanitizer_common/sanitizer_deadlock_detector1.cc189
-rw-r--r--lib/sanitizer_common/sanitizer_deadlock_detector2.cc428
-rw-r--r--lib/sanitizer_common/sanitizer_deadlock_detector_interface.h93
-rw-r--r--lib/sanitizer_common/sanitizer_flags.cc212
-rw-r--r--lib/sanitizer_common/sanitizer_flags.h59
-rw-r--r--lib/sanitizer_common/sanitizer_freebsd.h137
-rw-r--r--lib/sanitizer_common/sanitizer_internal_defs.h53
-rw-r--r--lib/sanitizer_common/sanitizer_libc.cc34
-rw-r--r--lib/sanitizer_common/sanitizer_libc.h8
-rw-r--r--lib/sanitizer_common/sanitizer_libignore.cc17
-rw-r--r--lib/sanitizer_common/sanitizer_linux.cc642
-rw-r--r--lib/sanitizer_common/sanitizer_linux.h27
-rw-r--r--lib/sanitizer_common/sanitizer_linux_libcdep.cc295
-rw-r--r--lib/sanitizer_common/sanitizer_list.h17
-rw-r--r--lib/sanitizer_common/sanitizer_mac.cc258
-rw-r--r--lib/sanitizer_common/sanitizer_mac.h37
-rw-r--r--lib/sanitizer_common/sanitizer_mutex.h84
-rw-r--r--lib/sanitizer_common/sanitizer_persistent_allocator.cc19
-rw-r--r--lib/sanitizer_common/sanitizer_persistent_allocator.h71
-rw-r--r--lib/sanitizer_common/sanitizer_platform.h73
-rw-r--r--lib/sanitizer_common/sanitizer_platform_interceptors.h276
-rw-r--r--lib/sanitizer_common/sanitizer_platform_limits_linux.cc26
-rw-r--r--lib/sanitizer_common/sanitizer_platform_limits_posix.cc448
-rw-r--r--lib/sanitizer_common/sanitizer_platform_limits_posix.h508
-rw-r--r--lib/sanitizer_common/sanitizer_posix.cc154
-rw-r--r--lib/sanitizer_common/sanitizer_posix_libcdep.cc133
-rw-r--r--lib/sanitizer_common/sanitizer_printf.cc31
-rw-r--r--lib/sanitizer_common/sanitizer_procmaps.h77
-rw-r--r--lib/sanitizer_common/sanitizer_procmaps_common.cc178
-rw-r--r--lib/sanitizer_common/sanitizer_procmaps_freebsd.cc88
-rw-r--r--lib/sanitizer_common/sanitizer_procmaps_linux.cc90
-rw-r--r--lib/sanitizer_common/sanitizer_procmaps_mac.cc190
-rw-r--r--lib/sanitizer_common/sanitizer_report_decorator.h12
-rw-r--r--lib/sanitizer_common/sanitizer_stackdepot.cc272
-rw-r--r--lib/sanitizer_common/sanitizer_stackdepot.h33
-rw-r--r--lib/sanitizer_common/sanitizer_stackdepotbase.h176
-rw-r--r--lib/sanitizer_common/sanitizer_stacktrace.cc177
-rw-r--r--lib/sanitizer_common/sanitizer_stacktrace.h65
-rw-r--r--lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc57
-rw-r--r--lib/sanitizer_common/sanitizer_stacktrace_printer.cc132
-rw-r--r--lib/sanitizer_common/sanitizer_stacktrace_printer.h62
-rw-r--r--lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc73
-rw-r--r--lib/sanitizer_common/sanitizer_suppressions.cc45
-rw-r--r--lib/sanitizer_common/sanitizer_suppressions.h16
-rw-r--r--lib/sanitizer_common/sanitizer_symbolizer.cc57
-rw-r--r--lib/sanitizer_common/sanitizer_symbolizer.h90
-rw-r--r--lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.cc211
-rw-r--r--lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.h50
-rw-r--r--lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc21
-rw-r--r--lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc613
-rw-r--r--lib/sanitizer_common/sanitizer_symbolizer_win.cc101
-rw-r--r--lib/sanitizer_common/sanitizer_syscall_generic.inc12
-rw-r--r--lib/sanitizer_common/sanitizer_syscall_linux_x86_64.inc2
-rw-r--r--lib/sanitizer_common/sanitizer_thread_registry.cc20
-rw-r--r--lib/sanitizer_common/sanitizer_thread_registry.h8
-rw-r--r--lib/sanitizer_common/sanitizer_tls_get_addr.cc131
-rw-r--r--lib/sanitizer_common/sanitizer_tls_get_addr.h60
-rw-r--r--lib/sanitizer_common/sanitizer_unwind_posix_libcdep.cc158
-rw-r--r--lib/sanitizer_common/sanitizer_win.cc179
-rwxr-xr-xlib/sanitizer_common/scripts/check_lint.sh63
-rwxr-xr-xlib/sanitizer_common/scripts/cpplint.py4
-rwxr-xr-xlib/sanitizer_common/scripts/gen_dynamic_list.py14
-rwxr-xr-xlib/sanitizer_common/scripts/litlint.py72
-rwxr-xr-xlib/sanitizer_common/scripts/litlint_test.py23
-rwxr-xr-xlib/sanitizer_common/scripts/sancov.py105
-rw-r--r--lib/sanitizer_common/tests/CMakeLists.txt109
-rw-r--r--lib/sanitizer_common/tests/lit.site.cfg.in14
-rw-r--r--lib/sanitizer_common/tests/sanitizer_allocator_test.cc81
-rw-r--r--lib/sanitizer_common/tests/sanitizer_allocator_testlib.cc4
-rw-r--r--lib/sanitizer_common/tests/sanitizer_atomic_test.cc73
-rw-r--r--lib/sanitizer_common/tests/sanitizer_bitvector_test.cc176
-rw-r--r--lib/sanitizer_common/tests/sanitizer_bvgraph_test.cc339
-rw-r--r--lib/sanitizer_common/tests/sanitizer_common_test.cc46
-rw-r--r--lib/sanitizer_common/tests/sanitizer_deadlock_detector_test.cc496
-rw-r--r--lib/sanitizer_common/tests/sanitizer_flags_test.cc12
-rw-r--r--lib/sanitizer_common/tests/sanitizer_format_interceptor_test.cc259
-rw-r--r--lib/sanitizer_common/tests/sanitizer_ioctl_test.cc26
-rw-r--r--lib/sanitizer_common/tests/sanitizer_libc_test.cc3
-rw-r--r--lib/sanitizer_common/tests/sanitizer_mutex_test.cc15
-rw-r--r--lib/sanitizer_common/tests/sanitizer_posix_test.cc18
-rw-r--r--lib/sanitizer_common/tests/sanitizer_printf_test.cc23
-rw-r--r--lib/sanitizer_common/tests/sanitizer_procmaps_test.cc37
-rw-r--r--lib/sanitizer_common/tests/sanitizer_pthread_wrappers.h66
-rw-r--r--lib/sanitizer_common/tests/sanitizer_scanf_interceptor_test.cc178
-rw-r--r--lib/sanitizer_common/tests/sanitizer_stackdepot_test.cc87
-rw-r--r--lib/sanitizer_common/tests/sanitizer_stacktrace_printer_test.cc122
-rw-r--r--lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc65
-rw-r--r--lib/sanitizer_common/tests/sanitizer_suppressions_test.cc26
-rw-r--r--lib/sanitizer_common/tests/sanitizer_test_config.h30
-rw-r--r--lib/sanitizer_common/tests/sanitizer_test_utils.h63
-rw-r--r--lib/sanitizer_common/tests/sanitizer_thread_registry_test.cc13
-rw-r--r--lib/subdf3.c29
-rw-r--r--lib/subsf3.c28
-rw-r--r--lib/subvdi3.c36
-rw-r--r--lib/subvsi3.c36
-rw-r--r--lib/subvti3.c40
-rw-r--r--lib/trampoline_setup.c47
-rw-r--r--lib/truncdfsf2.c168
-rw-r--r--lib/tsan/CMakeLists.txt74
-rw-r--r--lib/tsan/Makefile.old9
-rwxr-xr-xlib/tsan/check_analyze.sh20
-rwxr-xr-xlib/tsan/check_cmake.sh8
-rwxr-xr-xlib/tsan/check_memcpy.sh31
-rw-r--r--lib/tsan/dd/CMakeLists.txt41
-rw-r--r--lib/tsan/dd/dd_interceptors.cc333
-rw-r--r--lib/tsan/dd/dd_rtl.cc151
-rw-r--r--lib/tsan/dd/dd_rtl.h67
-rw-r--r--lib/tsan/go/build.bat4
-rwxr-xr-xlib/tsan/go/buildgo.sh48
-rw-r--r--lib/tsan/go/test.c20
-rw-r--r--lib/tsan/go/tsan_go.cc138
-rw-r--r--lib/tsan/lit_tests/CMakeLists.txt35
-rw-r--r--lib/tsan/lit_tests/Helpers/blacklist.txt1
-rw-r--r--lib/tsan/lit_tests/Helpers/lit.local.cfg2
-rw-r--r--lib/tsan/lit_tests/SharedLibs/lit.local.cfg4
-rw-r--r--lib/tsan/lit_tests/SharedLibs/load_shared_lib-so.cc22
-rw-r--r--lib/tsan/lit_tests/Unit/lit.cfg23
-rw-r--r--lib/tsan/lit_tests/Unit/lit.site.cfg.in8
-rw-r--r--lib/tsan/lit_tests/aligned_vs_unaligned_race.cc34
-rw-r--r--lib/tsan/lit_tests/allocator_returns_null.cc64
-rw-r--r--lib/tsan/lit_tests/atomic_free.cc19
-rw-r--r--lib/tsan/lit_tests/atomic_free2.cc19
-rw-r--r--lib/tsan/lit_tests/atomic_norace.cc61
-rw-r--r--lib/tsan/lit_tests/atomic_race.cc80
-rw-r--r--lib/tsan/lit_tests/atomic_stack.cc29
-rw-r--r--lib/tsan/lit_tests/benign_race.cc39
-rw-r--r--lib/tsan/lit_tests/blacklist.cc31
-rw-r--r--lib/tsan/lit_tests/cond.c53
-rw-r--r--lib/tsan/lit_tests/cond_race.cc36
-rw-r--r--lib/tsan/lit_tests/cond_version.c44
-rw-r--r--lib/tsan/lit_tests/deep_stack1.cc44
-rw-r--r--lib/tsan/lit_tests/default_options.cc32
-rw-r--r--lib/tsan/lit_tests/fd_close_norace.cc33
-rw-r--r--lib/tsan/lit_tests/fd_close_norace2.cc30
-rw-r--r--lib/tsan/lit_tests/fd_dup_norace.cc34
-rw-r--r--lib/tsan/lit_tests/fd_location.cc33
-rw-r--r--lib/tsan/lit_tests/fd_pipe_norace.cc33
-rw-r--r--lib/tsan/lit_tests/fd_pipe_race.cc37
-rw-r--r--lib/tsan/lit_tests/fd_socket_connect_norace.cc45
-rw-r--r--lib/tsan/lit_tests/fd_socket_norace.cc52
-rw-r--r--lib/tsan/lit_tests/fd_socketpair_norace.cc37
-rw-r--r--lib/tsan/lit_tests/fd_stdout_race.cc41
-rw-r--r--lib/tsan/lit_tests/free_race.c49
-rw-r--r--lib/tsan/lit_tests/free_race.c.supp2
-rw-r--r--lib/tsan/lit_tests/free_race2.c26
-rw-r--r--lib/tsan/lit_tests/global_race.cc42
-rw-r--r--lib/tsan/lit_tests/halt_on_error.cc25
-rw-r--r--lib/tsan/lit_tests/heap_race.cc20
-rw-r--r--lib/tsan/lit_tests/ignore_free.cc35
-rw-r--r--lib/tsan/lit_tests/ignore_lib0.cc30
-rw-r--r--lib/tsan/lit_tests/ignore_lib0.cc.supp2
-rw-r--r--lib/tsan/lit_tests/ignore_lib1.cc42
-rw-r--r--lib/tsan/lit_tests/ignore_lib1.cc.supp2
-rw-r--r--lib/tsan/lit_tests/ignore_lib2.cc33
-rw-r--r--lib/tsan/lit_tests/ignore_lib2.cc.supp2
-rw-r--r--lib/tsan/lit_tests/ignore_lib3.cc33
-rw-r--r--lib/tsan/lit_tests/ignore_lib3.cc.supp2
-rw-r--r--lib/tsan/lit_tests/ignore_lib_lib.h25
-rw-r--r--lib/tsan/lit_tests/ignore_malloc.cc38
-rw-r--r--lib/tsan/lit_tests/ignore_race.cc31
-rw-r--r--lib/tsan/lit_tests/ignore_sync.cc30
-rw-r--r--lib/tsan/lit_tests/inlined_memcpy_race.cc55
-rw-r--r--lib/tsan/lit_tests/java.h20
-rw-r--r--lib/tsan/lit_tests/java_alloc.cc32
-rw-r--r--lib/tsan/lit_tests/java_lock.cc35
-rw-r--r--lib/tsan/lit_tests/java_lock_move.cc40
-rw-r--r--lib/tsan/lit_tests/java_lock_rec.cc54
-rw-r--r--lib/tsan/lit_tests/java_lock_rec_race.cc48
-rw-r--r--lib/tsan/lit_tests/java_race.cc23
-rw-r--r--lib/tsan/lit_tests/java_race_move.cc31
-rw-r--r--lib/tsan/lit_tests/java_rwlock.cc35
-rw-r--r--lib/tsan/lit_tests/lit.cfg81
-rw-r--r--lib/tsan/lit_tests/lit.site.cfg.in8
-rw-r--r--lib/tsan/lit_tests/load_shared_lib.cc44
-rw-r--r--lib/tsan/lit_tests/longjmp.cc22
-rw-r--r--lib/tsan/lit_tests/longjmp2.cc24
-rw-r--r--lib/tsan/lit_tests/longjmp3.cc48
-rw-r--r--lib/tsan/lit_tests/longjmp4.cc51
-rw-r--r--lib/tsan/lit_tests/malloc_overflow.cc23
-rw-r--r--lib/tsan/lit_tests/malloc_stack.cc25
-rw-r--r--lib/tsan/lit_tests/memcpy_race.cc42
-rw-r--r--lib/tsan/lit_tests/mop_with_offset.cc36
-rw-r--r--lib/tsan/lit_tests/mop_with_offset2.cc36
-rw-r--r--lib/tsan/lit_tests/mutex_destroy_locked.cc22
-rw-r--r--lib/tsan/lit_tests/mutex_robust.cc36
-rw-r--r--lib/tsan/lit_tests/mutex_robust2.cc41
-rw-r--r--lib/tsan/lit_tests/mutexset1.cc37
-rw-r--r--lib/tsan/lit_tests/mutexset2.cc37
-rw-r--r--lib/tsan/lit_tests/mutexset3.cc45
-rw-r--r--lib/tsan/lit_tests/mutexset4.cc45
-rw-r--r--lib/tsan/lit_tests/mutexset5.cc46
-rw-r--r--lib/tsan/lit_tests/mutexset6.cc53
-rw-r--r--lib/tsan/lit_tests/mutexset7.cc39
-rw-r--r--lib/tsan/lit_tests/mutexset8.cc39
-rw-r--r--lib/tsan/lit_tests/oob_race.cc24
-rw-r--r--lib/tsan/lit_tests/race_on_barrier.c31
-rw-r--r--lib/tsan/lit_tests/race_on_barrier2.c31
-rw-r--r--lib/tsan/lit_tests/race_on_heap.cc47
-rw-r--r--lib/tsan/lit_tests/race_on_mutex.c42
-rw-r--r--lib/tsan/lit_tests/race_on_mutex2.c24
-rw-r--r--lib/tsan/lit_tests/race_on_read.cc32
-rw-r--r--lib/tsan/lit_tests/race_on_write.cc39
-rw-r--r--lib/tsan/lit_tests/race_with_finished_thread.cc43
-rw-r--r--lib/tsan/lit_tests/signal_errno.cc43
-rw-r--r--lib/tsan/lit_tests/signal_malloc.cc26
-rw-r--r--lib/tsan/lit_tests/sigsuspend.cc38
-rw-r--r--lib/tsan/lit_tests/simple_race.c26
-rw-r--r--lib/tsan/lit_tests/simple_race.cc26
-rw-r--r--lib/tsan/lit_tests/simple_stack.c66
-rw-r--r--lib/tsan/lit_tests/simple_stack2.cc53
-rw-r--r--lib/tsan/lit_tests/sleep_sync.cc30
-rw-r--r--lib/tsan/lit_tests/sleep_sync2.cc22
-rw-r--r--lib/tsan/lit_tests/stack_race.cc20
-rw-r--r--lib/tsan/lit_tests/stack_race2.cc28
-rw-r--r--lib/tsan/lit_tests/static_init1.cc27
-rw-r--r--lib/tsan/lit_tests/static_init2.cc33
-rw-r--r--lib/tsan/lit_tests/static_init3.cc47
-rw-r--r--lib/tsan/lit_tests/static_init4.cc37
-rw-r--r--lib/tsan/lit_tests/static_init5.cc42
-rw-r--r--lib/tsan/lit_tests/static_init6.cc42
-rw-r--r--lib/tsan/lit_tests/suppress_same_address.cc27
-rw-r--r--lib/tsan/lit_tests/suppress_same_stacks.cc27
-rw-r--r--lib/tsan/lit_tests/suppressions_global.cc29
-rw-r--r--lib/tsan/lit_tests/suppressions_global.cc.supp2
-rw-r--r--lib/tsan/lit_tests/suppressions_race.cc31
-rw-r--r--lib/tsan/lit_tests/suppressions_race.cc.supp2
-rw-r--r--lib/tsan/lit_tests/suppressions_race2.cc31
-rw-r--r--lib/tsan/lit_tests/suppressions_race2.cc.supp2
-rwxr-xr-xlib/tsan/lit_tests/test_output.sh58
-rw-r--r--lib/tsan/lit_tests/thread_end_with_ignore.cc19
-rw-r--r--lib/tsan/lit_tests/thread_end_with_ignore2.cc9
-rw-r--r--lib/tsan/lit_tests/thread_leak.c17
-rw-r--r--lib/tsan/lit_tests/thread_leak2.c17
-rw-r--r--lib/tsan/lit_tests/thread_leak3.c17
-rw-r--r--lib/tsan/lit_tests/thread_leak4.c18
-rw-r--r--lib/tsan/lit_tests/thread_leak5.c19
-rw-r--r--lib/tsan/lit_tests/thread_name.cc38
-rw-r--r--lib/tsan/lit_tests/thread_name2.cc32
-rw-r--r--lib/tsan/lit_tests/tiny_race.c21
-rw-r--r--lib/tsan/lit_tests/tls_race.cc19
-rw-r--r--lib/tsan/lit_tests/tls_race2.cc28
-rw-r--r--lib/tsan/lit_tests/tsan-vs-gvn.cc38
-rw-r--r--lib/tsan/lit_tests/unaligned_norace.cc84
-rw-r--r--lib/tsan/lit_tests/unaligned_race.cc135
-rw-r--r--lib/tsan/lit_tests/user_fopen.cc34
-rw-r--r--lib/tsan/lit_tests/user_malloc.cc27
-rw-r--r--lib/tsan/lit_tests/virtual_inheritance_compile_bug.cc15
-rw-r--r--lib/tsan/lit_tests/vptr_benign_race.cc51
-rw-r--r--lib/tsan/lit_tests/vptr_harmful_race.cc51
-rw-r--r--lib/tsan/lit_tests/vptr_harmful_race2.cc51
-rw-r--r--lib/tsan/lit_tests/write_in_reader_lock.cc35
-rw-r--r--lib/tsan/rtl/Makefile.old4
-rw-r--r--lib/tsan/rtl/tsan_clock.cc454
-rw-r--r--lib/tsan/rtl/tsan_clock.h95
-rw-r--r--lib/tsan/rtl/tsan_defs.h30
-rw-r--r--lib/tsan/rtl/tsan_dense_alloc.h137
-rw-r--r--lib/tsan/rtl/tsan_fd.cc26
-rw-r--r--lib/tsan/rtl/tsan_fd.h4
-rw-r--r--lib/tsan/rtl/tsan_flags.cc82
-rw-r--r--lib/tsan/rtl/tsan_flags.h24
-rw-r--r--lib/tsan/rtl/tsan_ignoreset.cc47
-rw-r--r--lib/tsan/rtl/tsan_ignoreset.h38
-rw-r--r--lib/tsan/rtl/tsan_interceptors.cc1140
-rw-r--r--lib/tsan/rtl/tsan_interface_ann.cc35
-rw-r--r--lib/tsan/rtl/tsan_interface_atomic.cc470
-rw-r--r--lib/tsan/rtl/tsan_interface_atomic.h205
-rw-r--r--lib/tsan/rtl/tsan_interface_java.cc166
-rw-r--r--lib/tsan/rtl/tsan_interface_java.h7
-rw-r--r--lib/tsan/rtl/tsan_md5.cc14
-rw-r--r--lib/tsan/rtl/tsan_mman.cc174
-rw-r--r--lib/tsan/rtl/tsan_mman.h10
-rw-r--r--lib/tsan/rtl/tsan_mutex.cc53
-rw-r--r--lib/tsan/rtl/tsan_mutex.h10
-rw-r--r--lib/tsan/rtl/tsan_mutexset.h11
-rw-r--r--lib/tsan/rtl/tsan_platform.h320
-rw-r--r--lib/tsan/rtl/tsan_platform_linux.cc336
-rw-r--r--lib/tsan/rtl/tsan_platform_mac.cc57
-rw-r--r--lib/tsan/rtl/tsan_platform_windows.cc12
-rw-r--r--lib/tsan/rtl/tsan_report.cc182
-rw-r--r--lib/tsan/rtl/tsan_report.h40
-rw-r--r--lib/tsan/rtl/tsan_rtl.cc522
-rw-r--r--lib/tsan/rtl/tsan_rtl.h322
-rw-r--r--lib/tsan/rtl/tsan_rtl_amd64.S271
-rw-r--r--lib/tsan/rtl/tsan_rtl_mutex.cc297
-rw-r--r--lib/tsan/rtl/tsan_rtl_report.cc454
-rw-r--r--lib/tsan/rtl/tsan_rtl_thread.cc123
-rw-r--r--lib/tsan/rtl/tsan_stack_trace.cc46
-rw-r--r--lib/tsan/rtl/tsan_stack_trace.h39
-rw-r--r--lib/tsan/rtl/tsan_stat.cc354
-rw-r--r--lib/tsan/rtl/tsan_stat.h355
-rw-r--r--lib/tsan/rtl/tsan_suppressions.cc100
-rw-r--r--lib/tsan/rtl/tsan_suppressions.h1
-rw-r--r--lib/tsan/rtl/tsan_symbolize.cc104
-rw-r--r--lib/tsan/rtl/tsan_symbolize.h8
-rw-r--r--lib/tsan/rtl/tsan_symbolize_addr2line_linux.cc193
-rw-r--r--lib/tsan/rtl/tsan_sync.cc419
-rw-r--r--lib/tsan/rtl/tsan_sync.h100
-rw-r--r--lib/tsan/rtl/tsan_trace.h22
-rw-r--r--lib/tsan/rtl/tsan_update_shadow_word_inl.h13
-rw-r--r--lib/tsan/rtl/tsan_vector.h22
-rw-r--r--lib/tsan/tests/CMakeLists.txt22
-rw-r--r--lib/tsan/tests/rtl/tsan_test.cc3
-rw-r--r--lib/tsan/tests/rtl/tsan_test_util.h2
-rw-r--r--lib/tsan/tests/rtl/tsan_test_util_linux.cc11
-rw-r--r--lib/tsan/tests/unit/tsan_clock_test.cc453
-rw-r--r--lib/tsan/tests/unit/tsan_dense_alloc_test.cc55
-rw-r--r--lib/tsan/tests/unit/tsan_flags_test.cc146
-rw-r--r--lib/tsan/tests/unit/tsan_mman_test.cc78
-rw-r--r--lib/tsan/tests/unit/tsan_stack_test.cc104
-rw-r--r--lib/tsan/tests/unit/tsan_sync_test.cc140
-rw-r--r--lib/tsan/tests/unit/tsan_vector_test.cc2
-rw-r--r--lib/ubsan/CMakeLists.txt27
-rw-r--r--lib/ubsan/lit_tests/AsanConfig/lit.cfg25
-rw-r--r--lib/ubsan/lit_tests/AsanConfig/lit.site.cfg.in9
-rw-r--r--lib/ubsan/lit_tests/CMakeLists.txt23
-rw-r--r--lib/ubsan/lit_tests/TestCases/Float/cast-overflow.cpp99
-rw-r--r--lib/ubsan/lit_tests/TestCases/Integer/add-overflow.cpp32
-rw-r--r--lib/ubsan/lit_tests/TestCases/Integer/div-overflow.cpp10
-rw-r--r--lib/ubsan/lit_tests/TestCases/Integer/div-zero.cpp15
-rw-r--r--lib/ubsan/lit_tests/TestCases/Integer/incdec-overflow.cpp16
-rw-r--r--lib/ubsan/lit_tests/TestCases/Integer/mul-overflow.cpp14
-rw-r--r--lib/ubsan/lit_tests/TestCases/Integer/negate-overflow.cpp12
-rw-r--r--lib/ubsan/lit_tests/TestCases/Integer/no-recover.cpp22
-rw-r--r--lib/ubsan/lit_tests/TestCases/Integer/shift.cpp37
-rw-r--r--lib/ubsan/lit_tests/TestCases/Integer/sub-overflow.cpp31
-rw-r--r--lib/ubsan/lit_tests/TestCases/Integer/uadd-overflow.cpp32
-rw-r--r--lib/ubsan/lit_tests/TestCases/Integer/uincdec-overflow.cpp16
-rw-r--r--lib/ubsan/lit_tests/TestCases/Integer/umul-overflow.cpp19
-rw-r--r--lib/ubsan/lit_tests/TestCases/Integer/usub-overflow.cpp31
-rw-r--r--lib/ubsan/lit_tests/TestCases/Misc/bool.cpp10
-rw-r--r--lib/ubsan/lit_tests/TestCases/Misc/bounds.cpp15
-rw-r--r--lib/ubsan/lit_tests/TestCases/Misc/deduplication.cpp25
-rw-r--r--lib/ubsan/lit_tests/TestCases/Misc/enum.cpp17
-rw-r--r--lib/ubsan/lit_tests/TestCases/Misc/missing_return.cpp9
-rw-r--r--lib/ubsan/lit_tests/TestCases/Misc/unreachable.cpp6
-rw-r--r--lib/ubsan/lit_tests/TestCases/Misc/vla.c11
-rw-r--r--lib/ubsan/lit_tests/TestCases/TypeCheck/Function/function.cpp17
-rw-r--r--lib/ubsan/lit_tests/TestCases/TypeCheck/Function/lit.local.cfg3
-rw-r--r--lib/ubsan/lit_tests/TestCases/TypeCheck/misaligned.cpp73
-rw-r--r--lib/ubsan/lit_tests/TestCases/TypeCheck/null.cpp38
-rw-r--r--lib/ubsan/lit_tests/TestCases/TypeCheck/vptr.cpp117
-rw-r--r--lib/ubsan/lit_tests/UbsanConfig/lit.cfg23
-rw-r--r--lib/ubsan/lit_tests/UbsanConfig/lit.site.cfg.in8
-rw-r--r--lib/ubsan/lit_tests/lit.common.cfg31
-rw-r--r--lib/ubsan/ubsan_diag.cc151
-rw-r--r--lib/ubsan/ubsan_diag.h29
-rw-r--r--lib/ubsan/ubsan_flags.cc63
-rw-r--r--lib/ubsan/ubsan_flags.h40
-rw-r--r--lib/ubsan/ubsan_handlers.cc311
-rw-r--r--lib/ubsan/ubsan_handlers.h29
-rw-r--r--lib/ubsan/ubsan_handlers_cxx.cc36
-rw-r--r--lib/ubsan/ubsan_init.cc61
-rw-r--r--lib/ubsan/ubsan_init.h24
-rw-r--r--lib/ubsan/ubsan_type_hash.cc47
-rw-r--r--lib/ubsan/ubsan_value.cc1
-rw-r--r--lib/ubsan/ubsan_value.h10
-rw-r--r--lib/ucmpti2.c42
-rw-r--r--lib/udivdi3.c25
-rw-r--r--lib/udivmoddi4.c251
-rw-r--r--lib/udivmodsi4.c30
-rw-r--r--lib/udivmodti4.c256
-rw-r--r--lib/udivti3.c29
-rw-r--r--lib/umoddi3.c27
-rw-r--r--lib/umodsi3.c25
-rw-r--r--lib/umodti3.c31
-rw-r--r--lib/x86_64/Makefile.mk20
-rw-r--r--lib/x86_64/floatundidf.S43
-rw-r--r--lib/x86_64/floatundisf.S33
-rw-r--r--lib/x86_64/floatundixf.S62
1220 files changed, 47863 insertions, 39126 deletions
diff --git a/lib/BlocksRuntime/Block.h b/lib/BlocksRuntime/Block.h
new file mode 100644
index 000000000000..55cdd01a9123
--- /dev/null
+++ b/lib/BlocksRuntime/Block.h
@@ -0,0 +1,59 @@
+/*
+ * Block.h
+ *
+ * Copyright 2008-2010 Apple, Inc. Permission is hereby granted, free of charge,
+ * to any person obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to permit
+ * persons to whom the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifndef _BLOCK_H_
+#define _BLOCK_H_
+
+#if !defined(BLOCK_EXPORT)
+# if defined(__cplusplus)
+# define BLOCK_EXPORT extern "C"
+# else
+# define BLOCK_EXPORT extern
+# endif
+#endif
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/* Create a heap based copy of a Block or simply add a reference to an existing one.
+ * This must be paired with Block_release to recover memory, even when running
+ * under Objective-C Garbage Collection.
+ */
+BLOCK_EXPORT void *_Block_copy(const void *aBlock);
+
+/* Lose the reference, and if heap based and last reference, recover the memory. */
+BLOCK_EXPORT void _Block_release(const void *aBlock);
+
+#if defined(__cplusplus)
+}
+#endif
+
+/* Type correct macros. */
+
+#define Block_copy(...) ((__typeof(__VA_ARGS__))_Block_copy((const void *)(__VA_ARGS__)))
+#define Block_release(...) _Block_release((const void *)(__VA_ARGS__))
+
+
+#endif
diff --git a/lib/BlocksRuntime/Block_private.h b/lib/BlocksRuntime/Block_private.h
new file mode 100644
index 000000000000..8ae821815ebe
--- /dev/null
+++ b/lib/BlocksRuntime/Block_private.h
@@ -0,0 +1,179 @@
+/*
+ * Block_private.h
+ *
+ * Copyright 2008-2010 Apple, Inc. Permission is hereby granted, free of charge,
+ * to any person obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to permit
+ * persons to whom the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifndef _BLOCK_PRIVATE_H_
+#define _BLOCK_PRIVATE_H_
+
+#if !defined(BLOCK_EXPORT)
+# if defined(__cplusplus)
+# define BLOCK_EXPORT extern "C"
+# else
+# define BLOCK_EXPORT extern
+# endif
+#endif
+
+#ifndef _MSC_VER
+#include <stdbool.h>
+#else
+/* MSVC doesn't have <stdbool.h>. Compensate. */
+typedef char bool;
+#define true (bool)1
+#define false (bool)0
+#endif
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+enum {
+ BLOCK_REFCOUNT_MASK = (0xffff),
+ BLOCK_NEEDS_FREE = (1 << 24),
+ BLOCK_HAS_COPY_DISPOSE = (1 << 25),
+ BLOCK_HAS_CTOR = (1 << 26), /* Helpers have C++ code. */
+ BLOCK_IS_GC = (1 << 27),
+ BLOCK_IS_GLOBAL = (1 << 28),
+ BLOCK_HAS_DESCRIPTOR = (1 << 29)
+};
+
+
+/* Revised new layout. */
+struct Block_descriptor {
+ unsigned long int reserved;
+ unsigned long int size;
+ void (*copy)(void *dst, void *src);
+ void (*dispose)(void *);
+};
+
+
+struct Block_layout {
+ void *isa;
+ int flags;
+ int reserved;
+ void (*invoke)(void *, ...);
+ struct Block_descriptor *descriptor;
+ /* Imported variables. */
+};
+
+
+struct Block_byref {
+ void *isa;
+ struct Block_byref *forwarding;
+ int flags; /* refcount; */
+ int size;
+ void (*byref_keep)(struct Block_byref *dst, struct Block_byref *src);
+ void (*byref_destroy)(struct Block_byref *);
+ /* long shared[0]; */
+};
+
+
+struct Block_byref_header {
+ void *isa;
+ struct Block_byref *forwarding;
+ int flags;
+ int size;
+};
+
+
+/* Runtime support functions used by compiler when generating copy/dispose helpers. */
+
+enum {
+ /* See function implementation for a more complete description of these fields and combinations */
+ BLOCK_FIELD_IS_OBJECT = 3, /* id, NSObject, __attribute__((NSObject)), block, ... */
+ BLOCK_FIELD_IS_BLOCK = 7, /* a block variable */
+ BLOCK_FIELD_IS_BYREF = 8, /* the on stack structure holding the __block variable */
+ BLOCK_FIELD_IS_WEAK = 16, /* declared __weak, only used in byref copy helpers */
+ BLOCK_BYREF_CALLER = 128 /* called from __block (byref) copy/dispose support routines. */
+};
+
+/* Runtime entry point called by compiler when assigning objects inside copy helper routines */
+BLOCK_EXPORT void _Block_object_assign(void *destAddr, const void *object, const int flags);
+ /* BLOCK_FIELD_IS_BYREF is only used from within block copy helpers */
+
+
+/* runtime entry point called by the compiler when disposing of objects inside dispose helper routine */
+BLOCK_EXPORT void _Block_object_dispose(const void *object, const int flags);
+
+
+
+/* Other support functions */
+
+/* Runtime entry to get total size of a closure */
+BLOCK_EXPORT unsigned long int Block_size(void *block_basic);
+
+
+
+/* the raw data space for runtime classes for blocks */
+/* class+meta used for stack, malloc, and collectable based blocks */
+BLOCK_EXPORT void * _NSConcreteStackBlock[32];
+BLOCK_EXPORT void * _NSConcreteMallocBlock[32];
+BLOCK_EXPORT void * _NSConcreteAutoBlock[32];
+BLOCK_EXPORT void * _NSConcreteFinalizingBlock[32];
+BLOCK_EXPORT void * _NSConcreteGlobalBlock[32];
+BLOCK_EXPORT void * _NSConcreteWeakBlockVariable[32];
+
+
+/* the intercept routines that must be used under GC */
+BLOCK_EXPORT void _Block_use_GC( void *(*alloc)(const unsigned long, const bool isOne, const bool isObject),
+ void (*setHasRefcount)(const void *, const bool),
+ void (*gc_assign_strong)(void *, void **),
+ void (*gc_assign_weak)(const void *, void *),
+ void (*gc_memmove)(void *, void *, unsigned long));
+
+/* earlier version, now simply transitional */
+BLOCK_EXPORT void _Block_use_GC5( void *(*alloc)(const unsigned long, const bool isOne, const bool isObject),
+ void (*setHasRefcount)(const void *, const bool),
+ void (*gc_assign_strong)(void *, void **),
+ void (*gc_assign_weak)(const void *, void *));
+
+BLOCK_EXPORT void _Block_use_RR( void (*retain)(const void *),
+ void (*release)(const void *));
+
+/* make a collectable GC heap based Block. Not useful under non-GC. */
+BLOCK_EXPORT void *_Block_copy_collectable(const void *aBlock);
+
+/* thread-unsafe diagnostic */
+BLOCK_EXPORT const char *_Block_dump(const void *block);
+
+
+/* Obsolete */
+
+/* first layout */
+struct Block_basic {
+ void *isa;
+ int Block_flags; /* int32_t */
+ int Block_size; /* XXX should be packed into Block_flags */
+ void (*Block_invoke)(void *);
+ void (*Block_copy)(void *dst, void *src); /* iff BLOCK_HAS_COPY_DISPOSE */
+ void (*Block_dispose)(void *); /* iff BLOCK_HAS_COPY_DISPOSE */
+ /* long params[0]; // where const imports, __block storage references, etc. get laid down */
+};
+
+
+#if defined(__cplusplus)
+}
+#endif
+
+
+#endif /* _BLOCK_PRIVATE_H_ */
diff --git a/lib/BlocksRuntime/data.c b/lib/BlocksRuntime/data.c
new file mode 100644
index 000000000000..b4eb02e0b01e
--- /dev/null
+++ b/lib/BlocksRuntime/data.c
@@ -0,0 +1,41 @@
+/*
+ * data.c
+ *
+ * Copyright 2008-2010 Apple, Inc. Permission is hereby granted, free of charge,
+ * to any person obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to permit
+ * persons to whom the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+/********************
+NSBlock support
+
+We allocate space and export a symbol to be used as the Class for the on-stack and malloc'ed copies until ObjC arrives on the scene. These data areas are set up by Foundation to link in as real classes post facto.
+
+We keep these in a separate file so that we can include the runtime code in test subprojects but not include the data so that compiled code that sees the data in libSystem doesn't get confused by a second copy. Somehow these don't get unified in a common block.
+**********************/
+
+void * _NSConcreteStackBlock[32] = { 0 };
+void * _NSConcreteMallocBlock[32] = { 0 };
+void * _NSConcreteAutoBlock[32] = { 0 };
+void * _NSConcreteFinalizingBlock[32] = { 0 };
+void * _NSConcreteGlobalBlock[32] = { 0 };
+void * _NSConcreteWeakBlockVariable[32] = { 0 };
+
+void _Block_copy_error(void) {
+}
diff --git a/lib/BlocksRuntime/runtime.c b/lib/BlocksRuntime/runtime.c
new file mode 100644
index 000000000000..a059c2234df1
--- /dev/null
+++ b/lib/BlocksRuntime/runtime.c
@@ -0,0 +1,700 @@
+/*
+ * runtime.c
+ *
+ * Copyright 2008-2010 Apple, Inc. Permission is hereby granted, free of charge,
+ * to any person obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to permit
+ * persons to whom the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#include "Block_private.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+
+#include "config.h"
+
+#ifdef HAVE_AVAILABILITY_MACROS_H
+#include <AvailabilityMacros.h>
+#endif /* HAVE_AVAILABILITY_MACROS_H */
+
+#ifdef HAVE_TARGET_CONDITIONALS_H
+#include <TargetConditionals.h>
+#endif /* HAVE_TARGET_CONDITIONALS_H */
+
+#if defined(HAVE_OSATOMIC_COMPARE_AND_SWAP_INT) && defined(HAVE_OSATOMIC_COMPARE_AND_SWAP_LONG)
+
+#ifdef HAVE_LIBKERN_OSATOMIC_H
+#include <libkern/OSAtomic.h>
+#endif /* HAVE_LIBKERN_OSATOMIC_H */
+
+#elif defined(__WIN32__) || defined(_WIN32)
+#define _CRT_SECURE_NO_WARNINGS 1
+#include <windows.h>
+
+static __inline bool OSAtomicCompareAndSwapLong(long oldl, long newl, long volatile *dst) {
+ /* fixme barrier is overkill -- see objc-os.h */
+ long original = InterlockedCompareExchange(dst, newl, oldl);
+ return (original == oldl);
+}
+
+static __inline bool OSAtomicCompareAndSwapInt(int oldi, int newi, int volatile *dst) {
+ /* fixme barrier is overkill -- see objc-os.h */
+ int original = InterlockedCompareExchange(dst, newi, oldi);
+ return (original == oldi);
+}
+
+/*
+ * Check to see if the GCC atomic built-ins are available. If we're on
+ * a 64-bit system, make sure we have an 8-byte atomic function
+ * available.
+ *
+ */
+
+#elif defined(HAVE_SYNC_BOOL_COMPARE_AND_SWAP_INT) && defined(HAVE_SYNC_BOOL_COMPARE_AND_SWAP_LONG)
+
+static __inline bool OSAtomicCompareAndSwapLong(long oldl, long newl, long volatile *dst) {
+ return __sync_bool_compare_and_swap(dst, oldl, newl);
+}
+
+static __inline bool OSAtomicCompareAndSwapInt(int oldi, int newi, int volatile *dst) {
+ return __sync_bool_compare_and_swap(dst, oldi, newi);
+}
+
+#else
+#error unknown atomic compare-and-swap primitive
+#endif /* HAVE_OSATOMIC_COMPARE_AND_SWAP_INT && HAVE_OSATOMIC_COMPARE_AND_SWAP_LONG */
+
+
+/*
+ * Globals:
+ */
+
+static void *_Block_copy_class = _NSConcreteMallocBlock;
+static void *_Block_copy_finalizing_class = _NSConcreteMallocBlock;
+static int _Block_copy_flag = BLOCK_NEEDS_FREE;
+static int _Byref_flag_initial_value = BLOCK_NEEDS_FREE | 2;
+
+static const int WANTS_ONE = (1 << 16);
+
+static bool isGC = false;
+
+/*
+ * Internal Utilities:
+ */
+
+#if 0
+static unsigned long int latching_incr_long(unsigned long int *where) {
+ while (1) {
+ unsigned long int old_value = *(volatile unsigned long int *)where;
+ if ((old_value & BLOCK_REFCOUNT_MASK) == BLOCK_REFCOUNT_MASK) {
+ return BLOCK_REFCOUNT_MASK;
+ }
+ if (OSAtomicCompareAndSwapLong(old_value, old_value+1, (volatile long int *)where)) {
+ return old_value+1;
+ }
+ }
+}
+#endif /* if 0 */
+
+static int latching_incr_int(int *where) {
+ while (1) {
+ int old_value = *(volatile int *)where;
+ if ((old_value & BLOCK_REFCOUNT_MASK) == BLOCK_REFCOUNT_MASK) {
+ return BLOCK_REFCOUNT_MASK;
+ }
+ if (OSAtomicCompareAndSwapInt(old_value, old_value+1, (volatile int *)where)) {
+ return old_value+1;
+ }
+ }
+}
+
+#if 0
+static int latching_decr_long(unsigned long int *where) {
+ while (1) {
+ unsigned long int old_value = *(volatile int *)where;
+ if ((old_value & BLOCK_REFCOUNT_MASK) == BLOCK_REFCOUNT_MASK) {
+ return BLOCK_REFCOUNT_MASK;
+ }
+ if ((old_value & BLOCK_REFCOUNT_MASK) == 0) {
+ return 0;
+ }
+ if (OSAtomicCompareAndSwapLong(old_value, old_value-1, (volatile long int *)where)) {
+ return old_value-1;
+ }
+ }
+}
+#endif /* if 0 */
+
+static int latching_decr_int(int *where) {
+ while (1) {
+ int old_value = *(volatile int *)where;
+ if ((old_value & BLOCK_REFCOUNT_MASK) == BLOCK_REFCOUNT_MASK) {
+ return BLOCK_REFCOUNT_MASK;
+ }
+ if ((old_value & BLOCK_REFCOUNT_MASK) == 0) {
+ return 0;
+ }
+ if (OSAtomicCompareAndSwapInt(old_value, old_value-1, (volatile int *)where)) {
+ return old_value-1;
+ }
+ }
+}
+
+
+/*
+ * GC support stub routines:
+ */
+#if 0
+#pragma mark GC Support Routines
+#endif /* if 0 */
+
+
+static void *_Block_alloc_default(const unsigned long size, const bool initialCountIsOne, const bool isObject) {
+ return malloc(size);
+}
+
+static void _Block_assign_default(void *value, void **destptr) {
+ *destptr = value;
+}
+
+static void _Block_setHasRefcount_default(const void *ptr, const bool hasRefcount) {
+}
+
+static void _Block_do_nothing(const void *aBlock) { }
+
+static void _Block_retain_object_default(const void *ptr) {
+ if (!ptr) return;
+}
+
+static void _Block_release_object_default(const void *ptr) {
+ if (!ptr) return;
+}
+
+static void _Block_assign_weak_default(const void *ptr, void *dest) {
+ *(void **)dest = (void *)ptr;
+}
+
+static void _Block_memmove_default(void *dst, void *src, unsigned long size) {
+ memmove(dst, src, (size_t)size);
+}
+
+static void _Block_memmove_gc_broken(void *dest, void *src, unsigned long size) {
+ void **destp = (void **)dest;
+ void **srcp = (void **)src;
+ while (size) {
+ _Block_assign_default(*srcp, destp);
+ destp++;
+ srcp++;
+ size -= sizeof(void *);
+ }
+}
+
+/*
+ * GC support callout functions - initially set to stub routines:
+ */
+
+static void *(*_Block_allocator)(const unsigned long, const bool isOne, const bool isObject) = _Block_alloc_default;
+static void (*_Block_deallocator)(const void *) = (void (*)(const void *))free;
+static void (*_Block_assign)(void *value, void **destptr) = _Block_assign_default;
+static void (*_Block_setHasRefcount)(const void *ptr, const bool hasRefcount) = _Block_setHasRefcount_default;
+static void (*_Block_retain_object)(const void *ptr) = _Block_retain_object_default;
+static void (*_Block_release_object)(const void *ptr) = _Block_release_object_default;
+static void (*_Block_assign_weak)(const void *dest, void *ptr) = _Block_assign_weak_default;
+static void (*_Block_memmove)(void *dest, void *src, unsigned long size) = _Block_memmove_default;
+
+
+/*
+ * GC support SPI functions - called from ObjC runtime and CoreFoundation:
+ */
+
+/* Public SPI
+ * Called from objc-auto to turn on GC.
+ * version 3, 4 arg, but changed 1st arg
+ */
+void _Block_use_GC( void *(*alloc)(const unsigned long, const bool isOne, const bool isObject),
+ void (*setHasRefcount)(const void *, const bool),
+ void (*gc_assign)(void *, void **),
+ void (*gc_assign_weak)(const void *, void *),
+ void (*gc_memmove)(void *, void *, unsigned long)) {
+
+ isGC = true;
+ _Block_allocator = alloc;
+ _Block_deallocator = _Block_do_nothing;
+ _Block_assign = gc_assign;
+ _Block_copy_flag = BLOCK_IS_GC;
+ _Block_copy_class = _NSConcreteAutoBlock;
+ /* blocks with ctors & dtors need to have the dtor run from a class with a finalizer */
+ _Block_copy_finalizing_class = _NSConcreteFinalizingBlock;
+ _Block_setHasRefcount = setHasRefcount;
+ _Byref_flag_initial_value = BLOCK_IS_GC; // no refcount
+ _Block_retain_object = _Block_do_nothing;
+ _Block_release_object = _Block_do_nothing;
+ _Block_assign_weak = gc_assign_weak;
+ _Block_memmove = gc_memmove;
+}
+
+/* transitional */
+void _Block_use_GC5( void *(*alloc)(const unsigned long, const bool isOne, const bool isObject),
+ void (*setHasRefcount)(const void *, const bool),
+ void (*gc_assign)(void *, void **),
+ void (*gc_assign_weak)(const void *, void *)) {
+ /* until objc calls _Block_use_GC it will call us; supply a broken internal memmove implementation until then */
+ _Block_use_GC(alloc, setHasRefcount, gc_assign, gc_assign_weak, _Block_memmove_gc_broken);
+}
+
+
+/*
+ * Called from objc-auto to alternatively turn on retain/release.
+ * Prior to this the only "object" support we can provide is for those
+ * super special objects that live in libSystem, namely dispatch queues.
+ * Blocks and Block_byrefs have their own special entry points.
+ *
+ */
+void _Block_use_RR( void (*retain)(const void *),
+ void (*release)(const void *)) {
+ _Block_retain_object = retain;
+ _Block_release_object = release;
+}
+
+/*
+ * Internal Support routines for copying:
+ */
+
+#if 0
+#pragma mark Copy/Release support
+#endif /* if 0 */
+
+/* Copy, or bump refcount, of a block. If really copying, call the copy helper if present. */
+static void *_Block_copy_internal(const void *arg, const int flags) {
+ struct Block_layout *aBlock;
+ const bool wantsOne = (WANTS_ONE & flags) == WANTS_ONE;
+
+ //printf("_Block_copy_internal(%p, %x)\n", arg, flags);
+ if (!arg) return NULL;
+
+
+ // The following would be better done as a switch statement
+ aBlock = (struct Block_layout *)arg;
+ if (aBlock->flags & BLOCK_NEEDS_FREE) {
+ // latches on high
+ latching_incr_int(&aBlock->flags);
+ return aBlock;
+ }
+ else if (aBlock->flags & BLOCK_IS_GC) {
+ // GC refcounting is expensive so do most refcounting here.
+ if (wantsOne && ((latching_incr_int(&aBlock->flags) & BLOCK_REFCOUNT_MASK) == 1)) {
+ // Tell collector to hang on this - it will bump the GC refcount version
+ _Block_setHasRefcount(aBlock, true);
+ }
+ return aBlock;
+ }
+ else if (aBlock->flags & BLOCK_IS_GLOBAL) {
+ return aBlock;
+ }
+
+ // Its a stack block. Make a copy.
+ if (!isGC) {
+ struct Block_layout *result = malloc(aBlock->descriptor->size);
+ if (!result) return (void *)0;
+ memmove(result, aBlock, aBlock->descriptor->size); // bitcopy first
+ // reset refcount
+ result->flags &= ~(BLOCK_REFCOUNT_MASK); // XXX not needed
+ result->flags |= BLOCK_NEEDS_FREE | 1;
+ result->isa = _NSConcreteMallocBlock;
+ if (result->flags & BLOCK_HAS_COPY_DISPOSE) {
+ //printf("calling block copy helper %p(%p, %p)...\n", aBlock->descriptor->copy, result, aBlock);
+ (*aBlock->descriptor->copy)(result, aBlock); // do fixup
+ }
+ return result;
+ }
+ else {
+ // Under GC want allocation with refcount 1 so we ask for "true" if wantsOne
+ // This allows the copy helper routines to make non-refcounted block copies under GC
+ unsigned long int flags = aBlock->flags;
+ bool hasCTOR = (flags & BLOCK_HAS_CTOR) != 0;
+ struct Block_layout *result = _Block_allocator(aBlock->descriptor->size, wantsOne, hasCTOR);
+ if (!result) return (void *)0;
+ memmove(result, aBlock, aBlock->descriptor->size); // bitcopy first
+ // reset refcount
+ // if we copy a malloc block to a GC block then we need to clear NEEDS_FREE.
+ flags &= ~(BLOCK_NEEDS_FREE|BLOCK_REFCOUNT_MASK); // XXX not needed
+ if (wantsOne)
+ flags |= BLOCK_IS_GC | 1;
+ else
+ flags |= BLOCK_IS_GC;
+ result->flags = flags;
+ if (flags & BLOCK_HAS_COPY_DISPOSE) {
+ //printf("calling block copy helper...\n");
+ (*aBlock->descriptor->copy)(result, aBlock); // do fixup
+ }
+ if (hasCTOR) {
+ result->isa = _NSConcreteFinalizingBlock;
+ }
+ else {
+ result->isa = _NSConcreteAutoBlock;
+ }
+ return result;
+ }
+}
+
+
+/*
+ * Runtime entry points for maintaining the sharing knowledge of byref data blocks.
+ *
+ * A closure has been copied and its fixup routine is asking us to fix up the reference to the shared byref data
+ * Closures that aren't copied must still work, so everyone always accesses variables after dereferencing the forwarding ptr.
+ * We ask if the byref pointer that we know about has already been copied to the heap, and if so, increment it.
+ * Otherwise we need to copy it and update the stack forwarding pointer
+ * XXX We need to account for weak/nonretained read-write barriers.
+ */
+
+static void _Block_byref_assign_copy(void *dest, const void *arg, const int flags) {
+ struct Block_byref **destp = (struct Block_byref **)dest;
+ struct Block_byref *src = (struct Block_byref *)arg;
+
+ //printf("_Block_byref_assign_copy called, byref destp %p, src %p, flags %x\n", destp, src, flags);
+ //printf("src dump: %s\n", _Block_byref_dump(src));
+ if (src->forwarding->flags & BLOCK_IS_GC) {
+ ; // don't need to do any more work
+ }
+ else if ((src->forwarding->flags & BLOCK_REFCOUNT_MASK) == 0) {
+ //printf("making copy\n");
+ // src points to stack
+ bool isWeak = ((flags & (BLOCK_FIELD_IS_BYREF|BLOCK_FIELD_IS_WEAK)) == (BLOCK_FIELD_IS_BYREF|BLOCK_FIELD_IS_WEAK));
+ // if its weak ask for an object (only matters under GC)
+ struct Block_byref *copy = (struct Block_byref *)_Block_allocator(src->size, false, isWeak);
+ copy->flags = src->flags | _Byref_flag_initial_value; // non-GC one for caller, one for stack
+ copy->forwarding = copy; // patch heap copy to point to itself (skip write-barrier)
+ src->forwarding = copy; // patch stack to point to heap copy
+ copy->size = src->size;
+ if (isWeak) {
+ copy->isa = &_NSConcreteWeakBlockVariable; // mark isa field so it gets weak scanning
+ }
+ if (src->flags & BLOCK_HAS_COPY_DISPOSE) {
+ // Trust copy helper to copy everything of interest
+ // If more than one field shows up in a byref block this is wrong XXX
+ copy->byref_keep = src->byref_keep;
+ copy->byref_destroy = src->byref_destroy;
+ (*src->byref_keep)(copy, src);
+ }
+ else {
+ // just bits. Blast 'em using _Block_memmove in case they're __strong
+ _Block_memmove(
+ (void *)&copy->byref_keep,
+ (void *)&src->byref_keep,
+ src->size - sizeof(struct Block_byref_header));
+ }
+ }
+ // already copied to heap
+ else if ((src->forwarding->flags & BLOCK_NEEDS_FREE) == BLOCK_NEEDS_FREE) {
+ latching_incr_int(&src->forwarding->flags);
+ }
+ // assign byref data block pointer into new Block
+ _Block_assign(src->forwarding, (void **)destp);
+}
+
+// Old compiler SPI
+static void _Block_byref_release(const void *arg) {
+ struct Block_byref *shared_struct = (struct Block_byref *)arg;
+ int refcount;
+
+ // dereference the forwarding pointer since the compiler isn't doing this anymore (ever?)
+ shared_struct = shared_struct->forwarding;
+
+ //printf("_Block_byref_release %p called, flags are %x\n", shared_struct, shared_struct->flags);
+ // To support C++ destructors under GC we arrange for there to be a finalizer for this
+ // by using an isa that directs the code to a finalizer that calls the byref_destroy method.
+ if ((shared_struct->flags & BLOCK_NEEDS_FREE) == 0) {
+ return; // stack or GC or global
+ }
+ refcount = shared_struct->flags & BLOCK_REFCOUNT_MASK;
+ if (refcount <= 0) {
+ printf("_Block_byref_release: Block byref data structure at %p underflowed\n", arg);
+ }
+ else if ((latching_decr_int(&shared_struct->flags) & BLOCK_REFCOUNT_MASK) == 0) {
+ //printf("disposing of heap based byref block\n");
+ if (shared_struct->flags & BLOCK_HAS_COPY_DISPOSE) {
+ //printf("calling out to helper\n");
+ (*shared_struct->byref_destroy)(shared_struct);
+ }
+ _Block_deallocator((struct Block_layout *)shared_struct);
+ }
+}
+
+
+/*
+ *
+ * API supporting SPI
+ * _Block_copy, _Block_release, and (old) _Block_destroy
+ *
+ */
+
+#if 0
+#pragma mark SPI/API
+#endif /* if 0 */
+
+void *_Block_copy(const void *arg) {
+ return _Block_copy_internal(arg, WANTS_ONE);
+}
+
+
+// API entry point to release a copied Block
+void _Block_release(void *arg) {
+ struct Block_layout *aBlock = (struct Block_layout *)arg;
+ int32_t newCount;
+ if (!aBlock) return;
+ newCount = latching_decr_int(&aBlock->flags) & BLOCK_REFCOUNT_MASK;
+ if (newCount > 0) return;
+ // Hit zero
+ if (aBlock->flags & BLOCK_IS_GC) {
+ // Tell GC we no longer have our own refcounts. GC will decr its refcount
+ // and unless someone has done a CFRetain or marked it uncollectable it will
+ // now be subject to GC reclamation.
+ _Block_setHasRefcount(aBlock, false);
+ }
+ else if (aBlock->flags & BLOCK_NEEDS_FREE) {
+ if (aBlock->flags & BLOCK_HAS_COPY_DISPOSE)(*aBlock->descriptor->dispose)(aBlock);
+ _Block_deallocator(aBlock);
+ }
+ else if (aBlock->flags & BLOCK_IS_GLOBAL) {
+ ;
+ }
+ else {
+ printf("Block_release called upon a stack Block: %p, ignored\n", (void *)aBlock);
+ }
+}
+
+
+
+// Old Compiler SPI point to release a copied Block used by the compiler in dispose helpers
+static void _Block_destroy(const void *arg) {
+ struct Block_layout *aBlock;
+ if (!arg) return;
+ aBlock = (struct Block_layout *)arg;
+ if (aBlock->flags & BLOCK_IS_GC) {
+ // assert(aBlock->Block_flags & BLOCK_HAS_CTOR);
+ return; // ignore, we are being called because of a DTOR
+ }
+ _Block_release(aBlock);
+}
+
+
+
+/*
+ *
+ * SPI used by other layers
+ *
+ */
+
+// SPI, also internal. Called from NSAutoBlock only under GC
+void *_Block_copy_collectable(const void *aBlock) {
+ return _Block_copy_internal(aBlock, 0);
+}
+
+
+// SPI
+unsigned long int Block_size(void *arg) {
+ return ((struct Block_layout *)arg)->descriptor->size;
+}
+
+
+#if 0
+#pragma mark Compiler SPI entry points
+#endif /* if 0 */
+
+
+/*******************************************************
+
+Entry points used by the compiler - the real API!
+
+
+A Block can reference four different kinds of things that require help when the Block is copied to the heap.
+1) C++ stack based objects
+2) References to Objective-C objects
+3) Other Blocks
+4) __block variables
+
+In these cases helper functions are synthesized by the compiler for use in Block_copy and Block_release, called the copy and dispose helpers. The copy helper emits a call to the C++ const copy constructor for C++ stack based objects and for the rest calls into the runtime support function _Block_object_assign. The dispose helper has a call to the C++ destructor for case 1 and a call into _Block_object_dispose for the rest.
+
+The flags parameter of _Block_object_assign and _Block_object_dispose is set to
+ * BLOCK_FIELD_IS_OBJECT (3), for the case of an Objective-C Object,
+ * BLOCK_FIELD_IS_BLOCK (7), for the case of another Block, and
+ * BLOCK_FIELD_IS_BYREF (8), for the case of a __block variable.
+If the __block variable is marked weak the compiler also or's in BLOCK_FIELD_IS_WEAK (16).
+
+So the Block copy/dispose helpers should only ever generate the four flag values of 3, 7, 8, and 24.
+
+When a __block variable is either a C++ object, an Objective-C object, or another Block then the compiler also generates copy/dispose helper functions. Similarly to the Block copy helper, the "__block" copy helper (formerly and still a.k.a. "byref" copy helper) will do a C++ copy constructor (not a const one though!) and the dispose helper will do the destructor. And similarly the helpers will call into the same two support functions with the same values for objects and Blocks with the additional BLOCK_BYREF_CALLER (128) bit of information supplied.
+
+So the __block copy/dispose helpers will generate flag values of 3 or 7 for objects and Blocks respectively, with BLOCK_FIELD_IS_WEAK (16) or'ed as appropriate and always 128 or'd in, for the following set of possibilities:
+ __block id 128+3
+ __weak block id 128+3+16
+ __block (^Block) 128+7
+ __weak __block (^Block) 128+7+16
+
+The implementation of the two routines would be improved by switch statements enumerating the eight cases.
+
+********************************************************/
+
+/*
+ * When Blocks or Block_byrefs hold objects then their copy routine helpers use this entry point
+ * to do the assignment.
+ */
+void _Block_object_assign(void *destAddr, const void *object, const int flags) {
+ //printf("_Block_object_assign(*%p, %p, %x)\n", destAddr, object, flags);
+ if ((flags & BLOCK_BYREF_CALLER) == BLOCK_BYREF_CALLER) {
+ if ((flags & BLOCK_FIELD_IS_WEAK) == BLOCK_FIELD_IS_WEAK) {
+ _Block_assign_weak(object, destAddr);
+ }
+ else {
+ // do *not* retain or *copy* __block variables whatever they are
+ _Block_assign((void *)object, destAddr);
+ }
+ }
+ else if ((flags & BLOCK_FIELD_IS_BYREF) == BLOCK_FIELD_IS_BYREF) {
+ // copying a __block reference from the stack Block to the heap
+ // flags will indicate if it holds a __weak reference and needs a special isa
+ _Block_byref_assign_copy(destAddr, object, flags);
+ }
+ // (this test must be before next one)
+ else if ((flags & BLOCK_FIELD_IS_BLOCK) == BLOCK_FIELD_IS_BLOCK) {
+ // copying a Block declared variable from the stack Block to the heap
+ _Block_assign(_Block_copy_internal(object, flags), destAddr);
+ }
+ // (this test must be after previous one)
+ else if ((flags & BLOCK_FIELD_IS_OBJECT) == BLOCK_FIELD_IS_OBJECT) {
+ //printf("retaining object at %p\n", object);
+ _Block_retain_object(object);
+ //printf("done retaining object at %p\n", object);
+ _Block_assign((void *)object, destAddr);
+ }
+}
+
+// When Blocks or Block_byrefs hold objects their destroy helper routines call this entry point
+// to help dispose of the contents
+// Used initially only for __attribute__((NSObject)) marked pointers.
+void _Block_object_dispose(const void *object, const int flags) {
+ //printf("_Block_object_dispose(%p, %x)\n", object, flags);
+ if (flags & BLOCK_FIELD_IS_BYREF) {
+ // get rid of the __block data structure held in a Block
+ _Block_byref_release(object);
+ }
+ else if ((flags & (BLOCK_FIELD_IS_BLOCK|BLOCK_BYREF_CALLER)) == BLOCK_FIELD_IS_BLOCK) {
+ // get rid of a referenced Block held by this Block
+ // (ignore __block Block variables, compiler doesn't need to call us)
+ _Block_destroy(object);
+ }
+ else if ((flags & (BLOCK_FIELD_IS_WEAK|BLOCK_FIELD_IS_BLOCK|BLOCK_BYREF_CALLER)) == BLOCK_FIELD_IS_OBJECT) {
+ // get rid of a referenced object held by this Block
+ // (ignore __block object variables, compiler doesn't need to call us)
+ _Block_release_object(object);
+ }
+}
+
+
+/*
+ * Debugging support:
+ */
+#if 0
+#pragma mark Debugging
+#endif /* if 0 */
+
+
+const char *_Block_dump(const void *block) {
+ struct Block_layout *closure = (struct Block_layout *)block;
+ static char buffer[512];
+ char *cp = buffer;
+ if (closure == NULL) {
+ sprintf(cp, "NULL passed to _Block_dump\n");
+ return buffer;
+ }
+ if (! (closure->flags & BLOCK_HAS_DESCRIPTOR)) {
+ printf("Block compiled by obsolete compiler, please recompile source for this Block\n");
+ exit(1);
+ }
+ cp += sprintf(cp, "^%p (new layout) =\n", (void *)closure);
+ if (closure->isa == NULL) {
+ cp += sprintf(cp, "isa: NULL\n");
+ }
+ else if (closure->isa == _NSConcreteStackBlock) {
+ cp += sprintf(cp, "isa: stack Block\n");
+ }
+ else if (closure->isa == _NSConcreteMallocBlock) {
+ cp += sprintf(cp, "isa: malloc heap Block\n");
+ }
+ else if (closure->isa == _NSConcreteAutoBlock) {
+ cp += sprintf(cp, "isa: GC heap Block\n");
+ }
+ else if (closure->isa == _NSConcreteGlobalBlock) {
+ cp += sprintf(cp, "isa: global Block\n");
+ }
+ else if (closure->isa == _NSConcreteFinalizingBlock) {
+ cp += sprintf(cp, "isa: finalizing Block\n");
+ }
+ else {
+ cp += sprintf(cp, "isa?: %p\n", (void *)closure->isa);
+ }
+ cp += sprintf(cp, "flags:");
+ if (closure->flags & BLOCK_HAS_DESCRIPTOR) {
+ cp += sprintf(cp, " HASDESCRIPTOR");
+ }
+ if (closure->flags & BLOCK_NEEDS_FREE) {
+ cp += sprintf(cp, " FREEME");
+ }
+ if (closure->flags & BLOCK_IS_GC) {
+ cp += sprintf(cp, " ISGC");
+ }
+ if (closure->flags & BLOCK_HAS_COPY_DISPOSE) {
+ cp += sprintf(cp, " HASHELP");
+ }
+ if (closure->flags & BLOCK_HAS_CTOR) {
+ cp += sprintf(cp, " HASCTOR");
+ }
+ cp += sprintf(cp, "\nrefcount: %u\n", closure->flags & BLOCK_REFCOUNT_MASK);
+ cp += sprintf(cp, "invoke: %p\n", (void *)(uintptr_t)closure->invoke);
+ {
+ struct Block_descriptor *dp = closure->descriptor;
+ cp += sprintf(cp, "descriptor: %p\n", (void *)dp);
+ cp += sprintf(cp, "descriptor->reserved: %lu\n", dp->reserved);
+ cp += sprintf(cp, "descriptor->size: %lu\n", dp->size);
+
+ if (closure->flags & BLOCK_HAS_COPY_DISPOSE) {
+ cp += sprintf(cp, "descriptor->copy helper: %p\n", (void *)(uintptr_t)dp->copy);
+ cp += sprintf(cp, "descriptor->dispose helper: %p\n", (void *)(uintptr_t)dp->dispose);
+ }
+ }
+ return buffer;
+}
+
+
+const char *_Block_byref_dump(struct Block_byref *src) {
+ static char buffer[256];
+ char *cp = buffer;
+ cp += sprintf(cp, "byref data block %p contents:\n", (void *)src);
+ cp += sprintf(cp, " forwarding: %p\n", (void *)src->forwarding);
+ cp += sprintf(cp, " flags: 0x%x\n", src->flags);
+ cp += sprintf(cp, " size: %d\n", src->size);
+ if (src->flags & BLOCK_HAS_COPY_DISPOSE) {
+ cp += sprintf(cp, " copy helper: %p\n", (void *)(uintptr_t)src->byref_keep);
+ cp += sprintf(cp, " dispose helper: %p\n", (void *)(uintptr_t)src->byref_destroy);
+ }
+ return buffer;
+}
+
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index b620828beb2b..6929e682fac6 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -1,216 +1,42 @@
# First, add the subdirectories which contain feature-based runtime libraries
# and several convenience helper libraries.
-# Don't build sanitizers in the bootstrap build.
-if(LLVM_USE_SANITIZER STREQUAL "")
- # AddressSanitizer is supported on Linux and Mac OS X.
- # 32-bit Windows support is experimental.
- if(CMAKE_SYSTEM_NAME MATCHES "Darwin|Linux")
- set(SUPPORTS_BUILDING_ASAN TRUE)
- elseif(CMAKE_SYSTEM_NAME MATCHES "Windows"
- AND MSVC AND CMAKE_SIZEOF_VOID_P EQUAL 4)
- set(SUPPORTS_BUILDING_ASAN TRUE)
- else()
- set(SUPPORTS_BUILDING_ASAN FALSE)
- endif()
- if(SUPPORTS_BUILDING_ASAN)
- add_subdirectory(asan)
- add_subdirectory(interception)
- add_subdirectory(sanitizer_common)
- endif()
- if(CMAKE_SYSTEM_NAME MATCHES "Darwin|Linux" AND NOT ANDROID)
- # LSan, UBsan and profile can be built on Mac OS and Linux.
- add_subdirectory(lsan)
- add_subdirectory(profile)
- add_subdirectory(ubsan)
- endif()
- if(CMAKE_SYSTEM_NAME MATCHES "Linux" AND NOT ANDROID)
- # ThreadSanitizer and MemorySanitizer are supported on Linux only.
- add_subdirectory(tsan)
- add_subdirectory(msan)
- add_subdirectory(msandr)
- add_subdirectory(dfsan)
- endif()
+include(AddCompilerRT)
+include(SanitizerUtils)
+
+if(COMPILER_RT_HAS_SANITIZER_COMMON)
+ add_subdirectory(interception)
+ add_subdirectory(sanitizer_common)
+endif()
+
+if(COMPILER_RT_HAS_ASAN)
+ add_subdirectory(asan)
endif()
-# The top-level lib directory contains a large amount of C code which provides
-# generic implementations of the core runtime library along with optimized
-# architecture-specific code in various subdirectories.
+add_subdirectory(builtins)
-set(GENERIC_SOURCES
- absvdi2.c
- absvsi2.c
- absvti2.c
- adddf3.c
- addsf3.c
- addvdi3.c
- addvsi3.c
- addvti3.c
- apple_versioning.c
- ashldi3.c
- ashlti3.c
- ashrdi3.c
- ashrti3.c
- # FIXME: atomic.c may only be compiled if host compiler understands _Atomic
- # atomic.c
- clear_cache.c
- clzdi2.c
- clzsi2.c
- clzti2.c
- cmpdi2.c
- cmpti2.c
- comparedf2.c
- comparesf2.c
- ctzdi2.c
- ctzsi2.c
- ctzti2.c
- divdc3.c
- divdf3.c
- divdi3.c
- divmoddi4.c
- divmodsi4.c
- divsc3.c
- divsf3.c
- divsi3.c
- divti3.c
- divxc3.c
- enable_execute_stack.c
- eprintf.c
- extendsfdf2.c
- ffsdi2.c
- ffsti2.c
- fixdfdi.c
- fixdfsi.c
- fixdfti.c
- fixsfdi.c
- fixsfsi.c
- fixsfti.c
- fixunsdfdi.c
- fixunsdfsi.c
- fixunsdfti.c
- fixunssfdi.c
- fixunssfsi.c
- fixunssfti.c
- fixunsxfdi.c
- fixunsxfsi.c
- fixunsxfti.c
- fixxfdi.c
- fixxfti.c
- floatdidf.c
- floatdisf.c
- floatdixf.c
- floatsidf.c
- floatsisf.c
- floattidf.c
- floattisf.c
- floattixf.c
- floatundidf.c
- floatundisf.c
- floatundixf.c
- floatunsidf.c
- floatunsisf.c
- floatuntidf.c
- floatuntisf.c
- floatuntixf.c
- gcc_personality_v0.c
- int_util.c
- lshrdi3.c
- lshrti3.c
- moddi3.c
- modsi3.c
- modti3.c
- muldc3.c
- muldf3.c
- muldi3.c
- mulodi4.c
- mulosi4.c
- muloti4.c
- mulsc3.c
- mulsf3.c
- multi3.c
- mulvdi3.c
- mulvsi3.c
- mulvti3.c
- mulxc3.c
- negdf2.c
- negdi2.c
- negsf2.c
- negti2.c
- negvdi2.c
- negvsi2.c
- negvti2.c
- paritydi2.c
- paritysi2.c
- parityti2.c
- popcountdi2.c
- popcountsi2.c
- popcountti2.c
- powidf2.c
- powisf2.c
- powitf2.c
- powixf2.c
- subdf3.c
- subsf3.c
- subvdi3.c
- subvsi3.c
- subvti3.c
- trampoline_setup.c
- truncdfsf2.c
- ucmpdi2.c
- ucmpti2.c
- udivdi3.c
- udivmoddi4.c
- udivmodsi4.c
- udivmodti4.c
- udivsi3.c
- udivti3.c
- umoddi3.c
- umodsi3.c
- umodti3.c
- )
+if(COMPILER_RT_HAS_DFSAN)
+ add_subdirectory(dfsan)
+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(COMPILER_RT_HAS_LSAN OR COMPILER_RT_HAS_LSAN_COMMON)
+ add_subdirectory(lsan)
+endif()
-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(COMPILER_RT_HAS_MSAN)
+ add_subdirectory(msan)
+endif()
-if (NOT WIN32)
- foreach(arch x86_64 i386)
- if(CAN_TARGET_${arch})
- add_compiler_rt_static_runtime(clang_rt.${arch} ${arch}
- SOURCES ${${arch}_SOURCES}
- CFLAGS "-std=c99")
- endif()
- endforeach()
+if(COMPILER_RT_HAS_PROFILE)
+ add_subdirectory(profile)
endif()
-# Generate configs for running lit and unit tests.
-configure_lit_site_cfg(
- ${CMAKE_CURRENT_SOURCE_DIR}/lit.common.configured.in
- ${CMAKE_CURRENT_BINARY_DIR}/lit.common.configured)
+if(COMPILER_RT_HAS_TSAN)
+ add_subdirectory(tsan)
+ add_subdirectory(tsan/dd)
+endif()
-configure_lit_site_cfg(
- ${CMAKE_CURRENT_SOURCE_DIR}/lit.common.unit.configured.in
- ${CMAKE_CURRENT_BINARY_DIR}/lit.common.unit.configured)
+if(COMPILER_RT_HAS_UBSAN)
+ add_subdirectory(ubsan)
+endif()
diff --git a/lib/Makefile.mk b/lib/Makefile.mk
index f9d7800cc4c4..ed9690d467aa 100644
--- a/lib/Makefile.mk
+++ b/lib/Makefile.mk
@@ -7,27 +7,16 @@
#
#===------------------------------------------------------------------------===#
-ModuleName := builtins
SubDirs :=
-# Add arch specific optimized implementations.
-SubDirs += i386 ppc x86_64 arm
-
-# Add other submodules.
+# Add submodules.
SubDirs += asan
+SubDirs += builtins
+SubDirs += dfsan
SubDirs += interception
+SubDirs += lsan
+SubDirs += msan
SubDirs += profile
SubDirs += sanitizer_common
SubDirs += tsan
-SubDirs += msan
SubDirs += ubsan
-SubDirs += lsan
-SubDirs += dfsan
-
-# Define the variables for this specific directory.
-Sources := $(foreach file,$(wildcard $(Dir)/*.c),$(notdir $(file)))
-ObjNames := $(Sources:%.c=%.o)
-Implementation := Generic
-
-# FIXME: use automatic dependencies?
-Dependencies := $(wildcard $(Dir)/*.h)
diff --git a/lib/absvti2.c b/lib/absvti2.c
deleted file mode 100644
index c1c7277986ab..000000000000
--- a/lib/absvti2.c
+++ /dev/null
@@ -1,33 +0,0 @@
-/* ===-- absvti2.c - Implement __absvdi2 -----------------------------------===
- *
- * 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 __absvti2 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-#if __x86_64
-
-/* Returns: absolute value */
-
-/* Effects: aborts if abs(x) < 0 */
-
-ti_int
-__absvti2(ti_int a)
-{
- const int N = (int)(sizeof(ti_int) * CHAR_BIT);
- if (a == ((ti_int)1 << (N-1)))
- compilerrt_abort();
- const ti_int s = a >> (N - 1);
- return (a ^ s) - s;
-}
-
-#endif
diff --git a/lib/adddf3.c b/lib/adddf3.c
deleted file mode 100644
index a55e82d21179..000000000000
--- a/lib/adddf3.c
+++ /dev/null
@@ -1,152 +0,0 @@
-//===-- lib/adddf3.c - Double-precision addition ------------------*- 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 double-precision soft-float addition with the IEEE-754
-// default rounding (to nearest, ties to even).
-//
-//===----------------------------------------------------------------------===//
-
-#define DOUBLE_PRECISION
-#include "fp_lib.h"
-
-ARM_EABI_FNALIAS(dadd, adddf3)
-
-COMPILER_RT_ABI fp_t
-__adddf3(fp_t a, fp_t b) {
-
- rep_t aRep = toRep(a);
- rep_t bRep = toRep(b);
- const rep_t aAbs = aRep & absMask;
- const rep_t bAbs = bRep & absMask;
-
- // Detect if a or b is zero, infinity, or NaN.
- if (aAbs - 1U >= infRep - 1U || bAbs - 1U >= infRep - 1U) {
-
- // NaN + anything = qNaN
- if (aAbs > infRep) return fromRep(toRep(a) | quietBit);
- // anything + NaN = qNaN
- if (bAbs > infRep) return fromRep(toRep(b) | quietBit);
-
- if (aAbs == infRep) {
- // +/-infinity + -/+infinity = qNaN
- if ((toRep(a) ^ toRep(b)) == signBit) return fromRep(qnanRep);
- // +/-infinity + anything remaining = +/- infinity
- else return a;
- }
-
- // anything remaining + +/-infinity = +/-infinity
- if (bAbs == infRep) return b;
-
- // zero + anything = anything
- if (!aAbs) {
- // but we need to get the sign right for zero + zero
- if (!bAbs) return fromRep(toRep(a) & toRep(b));
- else return b;
- }
-
- // anything + zero = anything
- if (!bAbs) return a;
- }
-
- // Swap a and b if necessary so that a has the larger absolute value.
- if (bAbs > aAbs) {
- const rep_t temp = aRep;
- aRep = bRep;
- bRep = temp;
- }
-
- // Extract the exponent and significand from the (possibly swapped) a and b.
- int aExponent = aRep >> significandBits & maxExponent;
- int bExponent = bRep >> significandBits & maxExponent;
- rep_t aSignificand = aRep & significandMask;
- rep_t bSignificand = bRep & significandMask;
-
- // Normalize any denormals, and adjust the exponent accordingly.
- if (aExponent == 0) aExponent = normalize(&aSignificand);
- if (bExponent == 0) bExponent = normalize(&bSignificand);
-
- // The sign of the result is the sign of the larger operand, a. If they
- // have opposite signs, we are performing a subtraction; otherwise addition.
- const rep_t resultSign = aRep & signBit;
- const bool subtraction = (aRep ^ bRep) & signBit;
-
- // Shift the significands to give us round, guard and sticky, and or in the
- // implicit significand bit. (If we fell through from the denormal path it
- // was already set by normalize( ), but setting it twice won't hurt
- // anything.)
- aSignificand = (aSignificand | implicitBit) << 3;
- bSignificand = (bSignificand | implicitBit) << 3;
-
- // Shift the significand of b by the difference in exponents, with a sticky
- // bottom bit to get rounding correct.
- const unsigned int align = aExponent - bExponent;
- if (align) {
- if (align < typeWidth) {
- const bool sticky = bSignificand << (typeWidth - align);
- bSignificand = bSignificand >> align | sticky;
- } else {
- bSignificand = 1; // sticky; b is known to be non-zero.
- }
- }
-
- if (subtraction) {
- aSignificand -= bSignificand;
-
- // If a == -b, return +zero.
- if (aSignificand == 0) return fromRep(0);
-
- // If partial cancellation occured, we need to left-shift the result
- // and adjust the exponent:
- if (aSignificand < implicitBit << 3) {
- const int shift = rep_clz(aSignificand) - rep_clz(implicitBit << 3);
- aSignificand <<= shift;
- aExponent -= shift;
- }
- }
-
- else /* addition */ {
- aSignificand += bSignificand;
-
- // If the addition carried up, we need to right-shift the result and
- // adjust the exponent:
- if (aSignificand & implicitBit << 4) {
- const bool sticky = aSignificand & 1;
- aSignificand = aSignificand >> 1 | sticky;
- aExponent += 1;
- }
- }
-
- // If we have overflowed the type, return +/- infinity:
- if (aExponent >= maxExponent) return fromRep(infRep | resultSign);
-
- if (aExponent <= 0) {
- // Result is denormal before rounding; the exponent is zero and we
- // need to shift the significand.
- const int shift = 1 - aExponent;
- const bool sticky = aSignificand << (typeWidth - shift);
- aSignificand = aSignificand >> shift | sticky;
- aExponent = 0;
- }
-
- // Low three bits are round, guard, and sticky.
- const int roundGuardSticky = aSignificand & 0x7;
-
- // Shift the significand into place, and mask off the implicit bit.
- rep_t result = aSignificand >> 3 & significandMask;
-
- // Insert the exponent and sign.
- result |= (rep_t)aExponent << significandBits;
- result |= resultSign;
-
- // Final rounding. The result may overflow to infinity, but that is the
- // correct result in that case.
- if (roundGuardSticky > 0x4) result++;
- if (roundGuardSticky == 0x4) result += result & 1;
- return fromRep(result);
-}
diff --git a/lib/addsf3.c b/lib/addsf3.c
deleted file mode 100644
index 0268324deaab..000000000000
--- a/lib/addsf3.c
+++ /dev/null
@@ -1,151 +0,0 @@
-//===-- lib/addsf3.c - Single-precision addition ------------------*- 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 single-precision soft-float addition with the IEEE-754
-// default rounding (to nearest, ties to even).
-//
-//===----------------------------------------------------------------------===//
-
-#define SINGLE_PRECISION
-#include "fp_lib.h"
-
-ARM_EABI_FNALIAS(fadd, addsf3)
-
-fp_t __addsf3(fp_t a, fp_t b) {
-
- rep_t aRep = toRep(a);
- rep_t bRep = toRep(b);
- const rep_t aAbs = aRep & absMask;
- const rep_t bAbs = bRep & absMask;
-
- // Detect if a or b is zero, infinity, or NaN.
- if (aAbs - 1U >= infRep - 1U || bAbs - 1U >= infRep - 1U) {
-
- // NaN + anything = qNaN
- if (aAbs > infRep) return fromRep(toRep(a) | quietBit);
- // anything + NaN = qNaN
- if (bAbs > infRep) return fromRep(toRep(b) | quietBit);
-
- if (aAbs == infRep) {
- // +/-infinity + -/+infinity = qNaN
- if ((toRep(a) ^ toRep(b)) == signBit) return fromRep(qnanRep);
- // +/-infinity + anything remaining = +/- infinity
- else return a;
- }
-
- // anything remaining + +/-infinity = +/-infinity
- if (bAbs == infRep) return b;
-
- // zero + anything = anything
- if (!aAbs) {
- // but we need to get the sign right for zero + zero
- if (!bAbs) return fromRep(toRep(a) & toRep(b));
- else return b;
- }
-
- // anything + zero = anything
- if (!bAbs) return a;
- }
-
- // Swap a and b if necessary so that a has the larger absolute value.
- if (bAbs > aAbs) {
- const rep_t temp = aRep;
- aRep = bRep;
- bRep = temp;
- }
-
- // Extract the exponent and significand from the (possibly swapped) a and b.
- int aExponent = aRep >> significandBits & maxExponent;
- int bExponent = bRep >> significandBits & maxExponent;
- rep_t aSignificand = aRep & significandMask;
- rep_t bSignificand = bRep & significandMask;
-
- // Normalize any denormals, and adjust the exponent accordingly.
- if (aExponent == 0) aExponent = normalize(&aSignificand);
- if (bExponent == 0) bExponent = normalize(&bSignificand);
-
- // The sign of the result is the sign of the larger operand, a. If they
- // have opposite signs, we are performing a subtraction; otherwise addition.
- const rep_t resultSign = aRep & signBit;
- const bool subtraction = (aRep ^ bRep) & signBit;
-
- // Shift the significands to give us round, guard and sticky, and or in the
- // implicit significand bit. (If we fell through from the denormal path it
- // was already set by normalize( ), but setting it twice won't hurt
- // anything.)
- aSignificand = (aSignificand | implicitBit) << 3;
- bSignificand = (bSignificand | implicitBit) << 3;
-
- // Shift the significand of b by the difference in exponents, with a sticky
- // bottom bit to get rounding correct.
- const unsigned int align = aExponent - bExponent;
- if (align) {
- if (align < typeWidth) {
- const bool sticky = bSignificand << (typeWidth - align);
- bSignificand = bSignificand >> align | sticky;
- } else {
- bSignificand = 1; // sticky; b is known to be non-zero.
- }
- }
-
- if (subtraction) {
- aSignificand -= bSignificand;
-
- // If a == -b, return +zero.
- if (aSignificand == 0) return fromRep(0);
-
- // If partial cancellation occured, we need to left-shift the result
- // and adjust the exponent:
- if (aSignificand < implicitBit << 3) {
- const int shift = rep_clz(aSignificand) - rep_clz(implicitBit << 3);
- aSignificand <<= shift;
- aExponent -= shift;
- }
- }
-
- else /* addition */ {
- aSignificand += bSignificand;
-
- // If the addition carried up, we need to right-shift the result and
- // adjust the exponent:
- if (aSignificand & implicitBit << 4) {
- const bool sticky = aSignificand & 1;
- aSignificand = aSignificand >> 1 | sticky;
- aExponent += 1;
- }
- }
-
- // If we have overflowed the type, return +/- infinity:
- if (aExponent >= maxExponent) return fromRep(infRep | resultSign);
-
- if (aExponent <= 0) {
- // Result is denormal before rounding; the exponent is zero and we
- // need to shift the significand.
- const int shift = 1 - aExponent;
- const bool sticky = aSignificand << (typeWidth - shift);
- aSignificand = aSignificand >> shift | sticky;
- aExponent = 0;
- }
-
- // Low three bits are round, guard, and sticky.
- const int roundGuardSticky = aSignificand & 0x7;
-
- // Shift the significand into place, and mask off the implicit bit.
- rep_t result = aSignificand >> 3 & significandMask;
-
- // Insert the exponent and sign.
- result |= (rep_t)aExponent << significandBits;
- result |= resultSign;
-
- // Final rounding. The result may overflow to infinity, but that is the
- // correct result in that case.
- if (roundGuardSticky > 0x4) result++;
- if (roundGuardSticky == 0x4) result += result & 1;
- return fromRep(result);
-}
diff --git a/lib/addvdi3.c b/lib/addvdi3.c
deleted file mode 100644
index db45a27f0784..000000000000
--- a/lib/addvdi3.c
+++ /dev/null
@@ -1,36 +0,0 @@
-/* ===-- addvdi3.c - Implement __addvdi3 -----------------------------------===
- *
- * 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 __addvdi3 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-/* Returns: a + b */
-
-/* Effects: aborts if a + b overflows */
-
-COMPILER_RT_ABI di_int
-__addvdi3(di_int a, di_int b)
-{
- di_int s = a + b;
- if (b >= 0)
- {
- if (s < a)
- compilerrt_abort();
- }
- else
- {
- if (s >= a)
- compilerrt_abort();
- }
- return s;
-}
diff --git a/lib/addvsi3.c b/lib/addvsi3.c
deleted file mode 100644
index 81f515cd7bb1..000000000000
--- a/lib/addvsi3.c
+++ /dev/null
@@ -1,36 +0,0 @@
-/* ===-- addvsi3.c - Implement __addvsi3 -----------------------------------===
- *
- * 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 __addvsi3 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-/* Returns: a + b */
-
-/* Effects: aborts if a + b overflows */
-
-COMPILER_RT_ABI si_int
-__addvsi3(si_int a, si_int b)
-{
- si_int s = a + b;
- if (b >= 0)
- {
- if (s < a)
- compilerrt_abort();
- }
- else
- {
- if (s >= a)
- compilerrt_abort();
- }
- return s;
-}
diff --git a/lib/addvti3.c b/lib/addvti3.c
deleted file mode 100644
index 2efcf3b408e4..000000000000
--- a/lib/addvti3.c
+++ /dev/null
@@ -1,40 +0,0 @@
-/* ===-- addvti3.c - Implement __addvti3 -----------------------------------===
- *
- * 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 __addvti3 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-#if __x86_64
-
-/* Returns: a + b */
-
-/* Effects: aborts if a + b overflows */
-
-ti_int
-__addvti3(ti_int a, ti_int b)
-{
- ti_int s = a + b;
- if (b >= 0)
- {
- if (s < a)
- compilerrt_abort();
- }
- else
- {
- if (s >= a)
- compilerrt_abort();
- }
- return s;
-}
-
-#endif
diff --git a/lib/arm/Makefile.mk b/lib/arm/Makefile.mk
deleted file mode 100644
index a2df115f926f..000000000000
--- a/lib/arm/Makefile.mk
+++ /dev/null
@@ -1,20 +0,0 @@
-#===- lib/arm/Makefile.mk ----------------------------------*- Makefile -*--===#
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-#===------------------------------------------------------------------------===#
-
-ModuleName := builtins
-SubDirs :=
-OnlyArchs := armv5 armv6 armv7 armv7f armv7k armv7m armv7em armv7s
-
-AsmSources := $(foreach file,$(wildcard $(Dir)/*.S),$(notdir $(file)))
-Sources := $(foreach file,$(wildcard $(Dir)/*.c),$(notdir $(file)))
-ObjNames := $(Sources:%.c=%.o) $(AsmSources:%.S=%.o)
-Implementation := Optimized
-
-# FIXME: use automatic dependencies?
-Dependencies := $(wildcard lib/*.h $(Dir)/*.h)
diff --git a/lib/arm/adddf3vfp.S b/lib/arm/adddf3vfp.S
deleted file mode 100644
index c90b0c2eabe6..000000000000
--- a/lib/arm/adddf3vfp.S
+++ /dev/null
@@ -1,25 +0,0 @@
-//===-- adddf3vfp.S - Implement adddf3vfp ---------------------------------===//
-//
-// 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"
-
-//
-// double __adddf3vfp(double a, double b) { return a + b; }
-//
-// Adds two double precision floating point numbers using the Darwin
-// calling convention where double arguments are passsed in GPR pairs
-//
- .syntax unified
- .align 2
-DEFINE_COMPILERRT_FUNCTION(__adddf3vfp)
- vmov d6, r0, r1 // move first param from r0/r1 pair into d6
- vmov d7, r2, r3 // move second param from r2/r3 pair into d7
- vadd.f64 d6, d6, d7
- vmov r0, r1, d6 // move result back to r0/r1 pair
- bx lr
diff --git a/lib/arm/addsf3vfp.S b/lib/arm/addsf3vfp.S
deleted file mode 100644
index 43653d5265c0..000000000000
--- a/lib/arm/addsf3vfp.S
+++ /dev/null
@@ -1,25 +0,0 @@
-//===-- addsf3vfp.S - Implement addsf3vfp ---------------------------------===//
-//
-// 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"
-
-//
-// extern float __addsf3vfp(float a, float b);
-//
-// Adds two single precision floating point numbers using the Darwin
-// calling convention where single arguments are passsed in GPRs
-//
- .syntax unified
- .align 2
-DEFINE_COMPILERRT_FUNCTION(__addsf3vfp)
- vmov s14, r0 // move first param from r0 into float register
- vmov s15, r1 // move second param from r1 into float register
- vadd.f32 s14, s14, s15
- vmov r0, s14 // move result back to r0
- bx lr
diff --git a/lib/arm/aeabi_dcmp.S b/lib/arm/aeabi_dcmp.S
deleted file mode 100644
index c4d07727a380..000000000000
--- a/lib/arm/aeabi_dcmp.S
+++ /dev/null
@@ -1,39 +0,0 @@
-//===-- aeabi_dcmp.S - EABI dcmp* 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"
-
-// int __aeabi_dcmp{eq,lt,le,ge,gt}(double a, double b) {
-// int result = __{eq,lt,le,ge,gt}df2(a, b);
-// if (result {==,<,<=,>=,>} 0) {
-// return 1;
-// } else {
-// return 0;
-// }
-// }
-
-#define DEFINE_AEABI_DCMP(cond) \
- .syntax unified SEPARATOR \
- .align 2 SEPARATOR \
-DEFINE_COMPILERRT_FUNCTION(__aeabi_dcmp ## cond) \
- push { r4, lr } SEPARATOR \
- bl SYMBOL_NAME(__ ## cond ## df2) SEPARATOR \
- cmp r0, #0 SEPARATOR \
- b ## cond 1f SEPARATOR \
- mov r0, #0 SEPARATOR \
- pop { r4, pc } SEPARATOR \
-1: SEPARATOR \
- mov r0, #1 SEPARATOR \
- pop { r4, pc }
-
-DEFINE_AEABI_DCMP(eq)
-DEFINE_AEABI_DCMP(lt)
-DEFINE_AEABI_DCMP(le)
-DEFINE_AEABI_DCMP(ge)
-DEFINE_AEABI_DCMP(gt)
diff --git a/lib/arm/aeabi_fcmp.S b/lib/arm/aeabi_fcmp.S
deleted file mode 100644
index 576a33f25542..000000000000
--- a/lib/arm/aeabi_fcmp.S
+++ /dev/null
@@ -1,39 +0,0 @@
-//===-- aeabi_fcmp.S - EABI fcmp* 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"
-
-// int __aeabi_fcmp{eq,lt,le,ge,gt}(float a, float b) {
-// int result = __{eq,lt,le,ge,gt}sf2(a, b);
-// if (result {==,<,<=,>=,>} 0) {
-// return 1;
-// } else {
-// return 0;
-// }
-// }
-
-#define DEFINE_AEABI_FCMP(cond) \
- .syntax unified SEPARATOR \
- .align 2 SEPARATOR \
-DEFINE_COMPILERRT_FUNCTION(__aeabi_fcmp ## cond) \
- push { r4, lr } SEPARATOR \
- bl SYMBOL_NAME(__ ## cond ## sf2) SEPARATOR \
- cmp r0, #0 SEPARATOR \
- b ## cond 1f SEPARATOR \
- mov r0, #0 SEPARATOR \
- pop { r4, pc } SEPARATOR \
-1: SEPARATOR \
- mov r0, #1 SEPARATOR \
- pop { r4, pc }
-
-DEFINE_AEABI_FCMP(eq)
-DEFINE_AEABI_FCMP(lt)
-DEFINE_AEABI_FCMP(le)
-DEFINE_AEABI_FCMP(ge)
-DEFINE_AEABI_FCMP(gt)
diff --git a/lib/arm/aeabi_idivmod.S b/lib/arm/aeabi_idivmod.S
deleted file mode 100644
index 0237f2221d7b..000000000000
--- a/lib/arm/aeabi_idivmod.S
+++ /dev/null
@@ -1,27 +0,0 @@
-//===-- aeabi_idivmod.S - EABI idivmod 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"
-
-// struct { int quot, int rem} __aeabi_idivmod(int numerator, int denominator) {
-// int rem, quot;
-// quot = __divmodsi4(numerator, denominator, &rem);
-// return {quot, rem};
-// }
-
- .syntax unified
- .align 2
-DEFINE_COMPILERRT_FUNCTION(__aeabi_idivmod)
- push { lr }
- sub sp, sp, #4
- mov r2, sp
- bl SYMBOL_NAME(__divmodsi4)
- ldr r1, [sp]
- add sp, sp, #4
- pop { pc }
diff --git a/lib/arm/aeabi_ldivmod.S b/lib/arm/aeabi_ldivmod.S
deleted file mode 100644
index 197c459eb381..000000000000
--- a/lib/arm/aeabi_ldivmod.S
+++ /dev/null
@@ -1,30 +0,0 @@
-//===-- aeabi_ldivmod.S - EABI ldivmod 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"
-
-// struct { int64_t quot, int64_t rem}
-// __aeabi_ldivmod(int64_t numerator, int64_t denominator) {
-// int64_t rem, quot;
-// quot = __divmoddi4(numerator, denominator, &rem);
-// return {quot, rem};
-// }
-
- .syntax unified
- .align 2
-DEFINE_COMPILERRT_FUNCTION(__aeabi_ldivmod)
- push {r11, lr}
- sub sp, sp, #16
- add r12, sp, #8
- str r12, [sp]
- bl SYMBOL_NAME(__divmoddi4)
- ldr r2, [sp, #8]
- ldr r3, [sp, #12]
- add sp, sp, #16
- pop {r11, pc}
diff --git a/lib/arm/aeabi_memcmp.S b/lib/arm/aeabi_memcmp.S
deleted file mode 100644
index ca29c10c65b6..000000000000
--- a/lib/arm/aeabi_memcmp.S
+++ /dev/null
@@ -1,19 +0,0 @@
-//===-- aeabi_memcmp.S - EABI memcmp 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"
-
-// void __aeabi_memcmp(void *dest, void *src, size_t n) { memcmp(dest, src, n); }
-
- .align 2
-DEFINE_COMPILERRT_FUNCTION(__aeabi_memcmp)
- b memcmp
-
-DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memcmp4, __aeabi_memcmp)
-DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memcmp8, __aeabi_memcmp)
diff --git a/lib/arm/aeabi_memcpy.S b/lib/arm/aeabi_memcpy.S
deleted file mode 100644
index 8b9c7fdf5f19..000000000000
--- a/lib/arm/aeabi_memcpy.S
+++ /dev/null
@@ -1,19 +0,0 @@
-//===-- aeabi_memcpy.S - EABI memcpy 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"
-
-// void __aeabi_memcpy(void *dest, void *src, size_t n) { memcpy(dest, src, n); }
-
- .align 2
-DEFINE_COMPILERRT_FUNCTION(__aeabi_memcpy)
- b memcpy
-
-DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memcpy4, __aeabi_memcpy)
-DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memcpy8, __aeabi_memcpy)
diff --git a/lib/arm/aeabi_memmove.S b/lib/arm/aeabi_memmove.S
deleted file mode 100644
index c94ed2b210e8..000000000000
--- a/lib/arm/aeabi_memmove.S
+++ /dev/null
@@ -1,19 +0,0 @@
-//===-- aeabi_memmove.S - EABI memmove 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"
-
-// void __aeabi_memmove(void *dest, void *src, size_t n) { memmove(dest, src, n); }
-
- .align 2
-DEFINE_COMPILERRT_FUNCTION(__aeabi_memmove)
- b memmove
-
-DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memmove4, __aeabi_memmove)
-DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memmove8, __aeabi_memmove)
diff --git a/lib/arm/aeabi_memset.S b/lib/arm/aeabi_memset.S
deleted file mode 100644
index 30ab4bae5a5d..000000000000
--- a/lib/arm/aeabi_memset.S
+++ /dev/null
@@ -1,32 +0,0 @@
-//===-- aeabi_memset.S - EABI memset 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"
-
-// void __aeabi_memset(void *dest, size_t n, int c) { memset(dest, c, n); }
-// void __aeabi_memclr(void *dest, size_t n) { __aeabi_memset(dest, n, 0); }
-
- .align 2
-DEFINE_COMPILERRT_FUNCTION(__aeabi_memset)
- mov r3, r1
- mov r1, r2
- mov r2, r3
- b memset
-
-DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memset4, __aeabi_memset)
-DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memset8, __aeabi_memset)
-
-DEFINE_COMPILERRT_FUNCTION(__aeabi_memclr)
- mov r2, r1
- mov r1, #0
- b memset
-
-DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memclr4, __aeabi_memclr)
-DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memclr8, __aeabi_memclr)
-
diff --git a/lib/arm/aeabi_uidivmod.S b/lib/arm/aeabi_uidivmod.S
deleted file mode 100644
index f7e1d2ebed1a..000000000000
--- a/lib/arm/aeabi_uidivmod.S
+++ /dev/null
@@ -1,28 +0,0 @@
-//===-- aeabi_uidivmod.S - EABI uidivmod 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"
-
-// struct { unsigned quot, unsigned rem}
-// __aeabi_uidivmod(unsigned numerator, unsigned denominator) {
-// unsigned rem, quot;
-// quot = __udivmodsi4(numerator, denominator, &rem);
-// return {quot, rem};
-// }
-
- .syntax unified
- .align 2
-DEFINE_COMPILERRT_FUNCTION(__aeabi_uidivmod)
- push { lr }
- sub sp, sp, #4
- mov r2, sp
- bl SYMBOL_NAME(__udivmodsi4)
- ldr r1, [sp]
- add sp, sp, #4
- pop { pc }
diff --git a/lib/arm/aeabi_uldivmod.S b/lib/arm/aeabi_uldivmod.S
deleted file mode 100644
index 724049dd9ccd..000000000000
--- a/lib/arm/aeabi_uldivmod.S
+++ /dev/null
@@ -1,30 +0,0 @@
-//===-- aeabi_uldivmod.S - EABI uldivmod 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"
-
-// struct { uint64_t quot, uint64_t rem}
-// __aeabi_uldivmod(uint64_t numerator, uint64_t denominator) {
-// uint64_t rem, quot;
-// quot = __udivmoddi4(numerator, denominator, &rem);
-// return {quot, rem};
-// }
-
- .syntax unified
- .align 2
-DEFINE_COMPILERRT_FUNCTION(__aeabi_uldivmod)
- push {r11, lr}
- sub sp, sp, #16
- add r12, sp, #8
- str r12, [sp]
- bl SYMBOL_NAME(__udivmoddi4)
- ldr r2, [sp, #8]
- ldr r3, [sp, #12]
- add sp, sp, #16
- pop {r11, pc} \ No newline at end of file
diff --git a/lib/arm/bswapdi2.S b/lib/arm/bswapdi2.S
deleted file mode 100644
index a0283e14e1e0..000000000000
--- a/lib/arm/bswapdi2.S
+++ /dev/null
@@ -1,36 +0,0 @@
-//===------- bswapdi2 - Implement bswapdi2 --------------------------------===//
-//
-// 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"
-
-//
-// extern uint64_t __bswapdi2(uint64_t);
-//
-// Reverse all the bytes in a 64-bit integer.
-//
-.align 2
-DEFINE_COMPILERRT_FUNCTION(__bswapdi2)
-#if __ARM_ARCH_5TEJ__ || __ARM_ARCH_4T__
- // before armv6 does not have "rev" instruction
- // r2 = rev(r0)
- eor r2, r0, r0, ror #16
- bic r2, r2, #0xff0000
- mov r2, r2, lsr #8
- eor r2, r2, r0, ror #8
- // r0 = rev(r1)
- eor r0, r1, r1, ror #16
- bic r0, r0, #0xff0000
- mov r0, r0, lsr #8
- eor r0, r0, r1, ror #8
-#else
- rev r2, r0 // r2 = rev(r0)
- rev r0, r1 // r0 = rev(r1)
-#endif
- mov r1, r2 // r1 = r2 = rev(r0)
- bx lr
diff --git a/lib/arm/bswapsi2.S b/lib/arm/bswapsi2.S
deleted file mode 100644
index 4c3af1f6d04d..000000000000
--- a/lib/arm/bswapsi2.S
+++ /dev/null
@@ -1,28 +0,0 @@
-//===------- bswapsi2 - Implement bswapsi2 --------------------------------===//
-//
-// 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"
-
-//
-// extern uint32_t __bswapsi2(uint32_t);
-//
-// Reverse all the bytes in a 32-bit integer.
-//
-.align 2
-DEFINE_COMPILERRT_FUNCTION(__bswapsi2)
-#if __ARM_ARCH_5TEJ__ || __ARM_ARCH_4T__
- // before armv6 does not have "rev" instruction
- eor r1, r0, r0, ror #16
- bic r1, r1, #0xff0000
- mov r1, r1, lsr #8
- eor r0, r1, r0, ror #8
-#else
- rev r0, r0
-#endif
- bx lr
diff --git a/lib/arm/comparesf2.S b/lib/arm/comparesf2.S
deleted file mode 100644
index ce6f4b9efd00..000000000000
--- a/lib/arm/comparesf2.S
+++ /dev/null
@@ -1,143 +0,0 @@
-//===-- comparesf2.S - Implement single-precision soft-float comparisons --===//
-//
-// 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 the following soft-fp_t comparison routines:
-//
-// __eqsf2 __gesf2 __unordsf2
-// __lesf2 __gtsf2
-// __ltsf2
-// __nesf2
-//
-// The semantics of the routines grouped in each column are identical, so there
-// is a single implementation for each, with multiple names.
-//
-// The routines behave as follows:
-//
-// __lesf2(a,b) returns -1 if a < b
-// 0 if a == b
-// 1 if a > b
-// 1 if either a or b is NaN
-//
-// __gesf2(a,b) returns -1 if a < b
-// 0 if a == b
-// 1 if a > b
-// -1 if either a or b is NaN
-//
-// __unordsf2(a,b) returns 0 if both a and b are numbers
-// 1 if either a or b is NaN
-//
-// Note that __lesf2( ) and __gesf2( ) are identical except in their handling of
-// NaN values.
-//
-//===----------------------------------------------------------------------===//
-
-#include "../assembly.h"
-.syntax unified
-
-.align 2
-DEFINE_COMPILERRT_FUNCTION(__eqsf2)
-DEFINE_COMPILERRT_FUNCTION(__lesf2)
-DEFINE_COMPILERRT_FUNCTION(__ltsf2)
-DEFINE_COMPILERRT_FUNCTION(__nesf2)
- // Make copies of a and b with the sign bit shifted off the top. These will
- // be used to detect zeros and NaNs.
- mov r2, r0, lsl #1
- mov r3, r1, lsl #1
-
- // We do the comparison in three stages (ignoring NaN values for the time
- // being). First, we orr the absolute values of a and b; this sets the Z
- // flag if both a and b are zero (of either sign). The shift of r3 doesn't
- // effect this at all, but it *does* make sure that the C flag is clear for
- // the subsequent operations.
- orrs r12, r2, r3, lsr #1
-
- // Next, we check if a and b have the same or different signs. If they have
- // opposite signs, this eor will set the N flag.
- it ne
- eorsne r12, r0, r1
-
- // If a and b are equal (either both zeros or bit identical; again, we're
- // ignoring NaNs for now), this subtract will zero out r0. If they have the
- // same sign, the flags are updated as they would be for a comparison of the
- // absolute values of a and b.
- it pl
- subspl r0, r2, r3
-
- // If a is smaller in magnitude than b and both have the same sign, place
- // the negation of the sign of b in r0. Thus, if both are negative and
- // a > b, this sets r0 to 0; if both are positive and a < b, this sets
- // r0 to -1.
- //
- // This is also done if a and b have opposite signs and are not both zero,
- // because in that case the subtract was not performed and the C flag is
- // still clear from the shift argument in orrs; if a is positive and b
- // negative, this places 0 in r0; if a is negative and b positive, -1 is
- // placed in r0.
- it lo
- mvnlo r0, r1, asr #31
-
- // If a is greater in magnitude than b and both have the same sign, place
- // the sign of b in r0. Thus, if both are negative and a < b, -1 is placed
- // in r0, which is the desired result. Conversely, if both are positive
- // and a > b, zero is placed in r0.
- it hi
- movhi r0, r1, asr #31
-
- // If you've been keeping track, at this point r0 contains -1 if a < b and
- // 0 if a >= b. All that remains to be done is to set it to 1 if a > b.
- // If a == b, then the Z flag is set, so we can get the correct final value
- // into r0 by simply or'ing with 1 if Z is clear.
- it ne
- orrne r0, r0, #1
-
- // Finally, we need to deal with NaNs. If either argument is NaN, replace
- // the value in r0 with 1.
- cmp r2, #0xff000000
- ite ls
- cmpls r3, #0xff000000
- movhi r0, #1
- bx lr
-
-.align 2
-DEFINE_COMPILERRT_FUNCTION(__gesf2)
-DEFINE_COMPILERRT_FUNCTION(__gtsf2)
- // Identical to the preceeding except in that we return -1 for NaN values.
- // Given that the two paths share so much code, one might be tempted to
- // unify them; however, the extra code needed to do so makes the code size
- // to performance tradeoff very hard to justify for such small functions.
- mov r2, r0, lsl #1
- mov r3, r1, lsl #1
- orrs r12, r2, r3, lsr #1
- it ne
- eorsne r12, r0, r1
- it pl
- subspl r0, r2, r3
- it lo
- mvnlo r0, r1, asr #31
- it hi
- movhi r0, r1, asr #31
- it ne
- orrne r0, r0, #1
- cmp r2, #0xff000000
- ite ls
- cmpls r3, #0xff000000
- movhi r0, #-1
- bx lr
-
-.align 2
-DEFINE_COMPILERRT_FUNCTION(__unordsf2)
- // Return 1 for NaN values, 0 otherwise.
- mov r2, r0, lsl #1
- mov r3, r1, lsl #1
- mov r0, #0
- cmp r2, #0xff000000
- ite ls
- cmpls r3, #0xff000000
- movhi r0, #1
- bx lr
diff --git a/lib/arm/divdf3vfp.S b/lib/arm/divdf3vfp.S
deleted file mode 100644
index 52de67f7fdcd..000000000000
--- a/lib/arm/divdf3vfp.S
+++ /dev/null
@@ -1,25 +0,0 @@
-//===-- divdf3vfp.S - Implement divdf3vfp ---------------------------------===//
-//
-// 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"
-
-//
-// extern double __divdf3vfp(double a, double b);
-//
-// Divides two double precision floating point numbers using the Darwin
-// calling convention where double arguments are passsed in GPR pairs
-//
- .syntax unified
- .align 2
-DEFINE_COMPILERRT_FUNCTION(__divdf3vfp)
- vmov d6, r0, r1 // move first param from r0/r1 pair into d6
- vmov d7, r2, r3 // move second param from r2/r3 pair into d7
- vdiv.f64 d5, d6, d7
- vmov r0, r1, d5 // move result back to r0/r1 pair
- bx lr
diff --git a/lib/arm/divmodsi4.S b/lib/arm/divmodsi4.S
deleted file mode 100644
index 6495a8b4cc3a..000000000000
--- a/lib/arm/divmodsi4.S
+++ /dev/null
@@ -1,60 +0,0 @@
-/*===-- divmodsi4.S - 32-bit signed integer divide and modulus ------------===//
- *
- * 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 the __divmodsi4 (32-bit signed integer divide and
- * modulus) function for the ARM architecture. A naive digit-by-digit
- * computation is employed for simplicity.
- *
- *===----------------------------------------------------------------------===*/
-
-#include "../assembly.h"
-
-#define ESTABLISH_FRAME \
- push {r4-r7, lr} ;\
- add r7, sp, #12
-#define CLEAR_FRAME_AND_RETURN \
- pop {r4-r7, pc}
-
-.syntax unified
-.align 3
-DEFINE_COMPILERRT_FUNCTION(__divmodsi4)
-#if __ARM_ARCH_EXT_IDIV__
- tst r1, r1
- beq LOCAL_LABEL(divzero)
- mov r3, r0
- sdiv r0, r3, r1
- mls r1, r0, r1, r3
- str r1, [r2]
- bx lr
-LOCAL_LABEL(divzero):
- mov r0, #0
- bx lr
-#else
- ESTABLISH_FRAME
-// Set aside the sign of the quotient and modulus, and the address for the
-// modulus.
- eor r4, r0, r1
- mov r5, r0
- mov r6, r2
-// Take the absolute value of a and b via abs(x) = (x^(x >> 31)) - (x >> 31).
- eor ip, r0, r0, asr #31
- eor lr, r1, r1, asr #31
- sub r0, ip, r0, asr #31
- sub r1, lr, r1, asr #31
-// Unsigned divmod:
- bl SYMBOL_NAME(__udivmodsi4)
-// Apply the sign of quotient and modulus
- ldr r1, [r6]
- eor r0, r0, r4, asr #31
- eor r1, r1, r5, asr #31
- sub r0, r0, r4, asr #31
- sub r1, r1, r5, asr #31
- str r1, [r6]
- CLEAR_FRAME_AND_RETURN
-#endif
diff --git a/lib/arm/divsf3vfp.S b/lib/arm/divsf3vfp.S
deleted file mode 100644
index 81ba90307897..000000000000
--- a/lib/arm/divsf3vfp.S
+++ /dev/null
@@ -1,25 +0,0 @@
-//===-- divsf3vfp.S - Implement divsf3vfp ---------------------------------===//
-//
-// 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"
-
-//
-// extern float __divsf3vfp(float a, float b);
-//
-// Divides two single precision floating point numbers using the Darwin
-// calling convention where single arguments are passsed like 32-bit ints.
-//
- .syntax unified
- .align 2
-DEFINE_COMPILERRT_FUNCTION(__divsf3vfp)
- vmov s14, r0 // move first param from r0 into float register
- vmov s15, r1 // move second param from r1 into float register
- vdiv.f32 s13, s14, s15
- vmov r0, s13 // move result back to r0
- bx lr
diff --git a/lib/arm/divsi3.S b/lib/arm/divsi3.S
deleted file mode 100644
index b631db292b8a..000000000000
--- a/lib/arm/divsi3.S
+++ /dev/null
@@ -1,51 +0,0 @@
-/*===-- divsi3.S - 32-bit signed integer divide ---------------------------===//
- *
- * 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 the __divsi3 (32-bit signed integer divide) function
- * for the ARM architecture as a wrapper around the unsigned routine.
- *
- *===----------------------------------------------------------------------===*/
-
-#include "../assembly.h"
-
-#define ESTABLISH_FRAME \
- push {r4, r7, lr} ;\
- add r7, sp, #4
-#define CLEAR_FRAME_AND_RETURN \
- pop {r4, r7, pc}
-
-.syntax unified
-.align 3
-// Ok, APCS and AAPCS agree on 32 bit args, so it's safe to use the same routine.
-DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_idiv, __divsi3)
-DEFINE_COMPILERRT_FUNCTION(__divsi3)
-#if __ARM_ARCH_EXT_IDIV__
- tst r1,r1
- beq LOCAL_LABEL(divzero)
- sdiv r0, r0, r1
- bx lr
-LOCAL_LABEL(divzero):
- mov r0,#0
- bx lr
-#else
-ESTABLISH_FRAME
-// Set aside the sign of the quotient.
- eor r4, r0, r1
-// Take absolute value of a and b via abs(x) = (x^(x >> 31)) - (x >> 31).
- eor r2, r0, r0, asr #31
- eor r3, r1, r1, asr #31
- sub r0, r2, r0, asr #31
- sub r1, r3, r1, asr #31
-// abs(a) / abs(b)
- bl SYMBOL_NAME(__udivsi3)
-// Apply sign of quotient to result and return.
- eor r0, r0, r4, asr #31
- sub r0, r0, r4, asr #31
- CLEAR_FRAME_AND_RETURN
-#endif
diff --git a/lib/arm/eqdf2vfp.S b/lib/arm/eqdf2vfp.S
deleted file mode 100644
index c41e55a34685..000000000000
--- a/lib/arm/eqdf2vfp.S
+++ /dev/null
@@ -1,28 +0,0 @@
-//===-- eqdf2vfp.S - Implement eqdf2vfp -----------------------------------===//
-//
-// 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"
-
-//
-// extern int __eqdf2vfp(double a, double b);
-//
-// Returns one iff a == b and neither is NaN.
-// Uses Darwin calling convention where double precision arguments are passsed
-// like in GPR pairs.
-//
- .syntax unified
- .align 2
-DEFINE_COMPILERRT_FUNCTION(__eqdf2vfp)
- vmov d6, r0, r1 // load r0/r1 pair in double register
- vmov d7, r2, r3 // load r2/r3 pair in double register
- vcmp.f64 d6, d7
- vmrs apsr_nzcv, fpscr
- moveq r0, #1 // set result register to 1 if equal
- movne r0, #0
- bx lr
diff --git a/lib/arm/eqsf2vfp.S b/lib/arm/eqsf2vfp.S
deleted file mode 100644
index 730ef88da68c..000000000000
--- a/lib/arm/eqsf2vfp.S
+++ /dev/null
@@ -1,29 +0,0 @@
-//===-- eqsf2vfp.S - Implement eqsf2vfp -----------------------------------===//
-//
-// 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"
-
-//
-// extern int __eqsf2vfp(float a, float b);
-//
-// Returns one iff a == b and neither is NaN.
-// Uses Darwin calling convention where single precision arguments are passsed
-// like 32-bit ints
-//
- .syntax unified
- .align 2
-DEFINE_COMPILERRT_FUNCTION(__eqsf2vfp)
- vmov s14, r0 // move from GPR 0 to float register
- vmov s15, r1 // move from GPR 1 to float register
- vcmp.f32 s14, s15
- vmrs apsr_nzcv, fpscr
- moveq r0, #1 // set result register to 1 if equal
- movne r0, #0
- bx lr
-
diff --git a/lib/arm/extendsfdf2vfp.S b/lib/arm/extendsfdf2vfp.S
deleted file mode 100644
index 17a146e0280a..000000000000
--- a/lib/arm/extendsfdf2vfp.S
+++ /dev/null
@@ -1,25 +0,0 @@
-//===-- extendsfdf2vfp.S - Implement extendsfdf2vfp -----------------------===//
-//
-// 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"
-
-//
-// extern double __extendsfdf2vfp(float a);
-//
-// Converts single precision float to double precision result.
-// Uses Darwin calling convention where a single precision parameter is
-// passed in a GPR and a double precision result is returned in R0/R1 pair.
-//
- .syntax unified
- .align 2
-DEFINE_COMPILERRT_FUNCTION(__extendsfdf2vfp)
- vmov s15, r0 // load float register from R0
- vcvt.f64.f32 d7, s15 // convert single to double
- vmov r0, r1, d7 // return result in r0/r1 pair
- bx lr
diff --git a/lib/arm/fixdfsivfp.S b/lib/arm/fixdfsivfp.S
deleted file mode 100644
index b7c3299d1c4d..000000000000
--- a/lib/arm/fixdfsivfp.S
+++ /dev/null
@@ -1,25 +0,0 @@
-//===-- fixdfsivfp.S - Implement fixdfsivfp -----------------------===//
-//
-// 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"
-
-//
-// extern int __fixdfsivfp(double a);
-//
-// Converts double precision float to a 32-bit int rounding towards zero.
-// Uses Darwin calling convention where a double precision parameter is
-// passed in GPR register pair.
-//
- .syntax unified
- .align 2
-DEFINE_COMPILERRT_FUNCTION(__fixdfsivfp)
- vmov d7, r0, r1 // load double register from R0/R1
- vcvt.s32.f64 s15, d7 // convert double to 32-bit int into s15
- vmov r0, s15 // move s15 to result register
- bx lr
diff --git a/lib/arm/fixsfsivfp.S b/lib/arm/fixsfsivfp.S
deleted file mode 100644
index 1cea6a486d6d..000000000000
--- a/lib/arm/fixsfsivfp.S
+++ /dev/null
@@ -1,25 +0,0 @@
-//===-- fixsfsivfp.S - Implement fixsfsivfp -----------------------===//
-//
-// 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"
-
-//
-// extern int __fixsfsivfp(float a);
-//
-// Converts single precision float to a 32-bit int rounding towards zero.
-// Uses Darwin calling convention where a single precision parameter is
-// passed in a GPR..
-//
- .syntax unified
- .align 2
-DEFINE_COMPILERRT_FUNCTION(__fixsfsivfp)
- vmov s15, r0 // load float register from R0
- vcvt.s32.f32 s15, s15 // convert single to 32-bit int into s15
- vmov r0, s15 // move s15 to result register
- bx lr
diff --git a/lib/arm/fixunsdfsivfp.S b/lib/arm/fixunsdfsivfp.S
deleted file mode 100644
index 54b03592b457..000000000000
--- a/lib/arm/fixunsdfsivfp.S
+++ /dev/null
@@ -1,26 +0,0 @@
-//===-- fixunsdfsivfp.S - Implement fixunsdfsivfp -------------------------===//
-//
-// 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"
-
-//
-// extern unsigned int __fixunsdfsivfp(double a);
-//
-// Converts double precision float to a 32-bit unsigned int rounding towards
-// zero. All negative values become zero.
-// Uses Darwin calling convention where a double precision parameter is
-// passed in GPR register pair.
-//
- .syntax unified
- .align 2
-DEFINE_COMPILERRT_FUNCTION(__fixunsdfsivfp)
- vmov d7, r0, r1 // load double register from R0/R1
- vcvt.u32.f64 s15, d7 // convert double to 32-bit int into s15
- vmov r0, s15 // move s15 to result register
- bx lr
diff --git a/lib/arm/fixunssfsivfp.S b/lib/arm/fixunssfsivfp.S
deleted file mode 100644
index 12adb529ae7a..000000000000
--- a/lib/arm/fixunssfsivfp.S
+++ /dev/null
@@ -1,26 +0,0 @@
-//===-- fixunssfsivfp.S - Implement fixunssfsivfp -------------------------===//
-//
-// 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"
-
-//
-// extern unsigned int __fixunssfsivfp(float a);
-//
-// Converts single precision float to a 32-bit unsigned int rounding towards
-// zero. All negative values become zero.
-// Uses Darwin calling convention where a single precision parameter is
-// passed in a GPR..
-//
- .syntax unified
- .align 2
-DEFINE_COMPILERRT_FUNCTION(__fixunssfsivfp)
- vmov s15, r0 // load float register from R0
- vcvt.u32.f32 s15, s15 // convert single to 32-bit unsigned into s15
- vmov r0, s15 // move s15 to result register
- bx lr
diff --git a/lib/arm/floatsidfvfp.S b/lib/arm/floatsidfvfp.S
deleted file mode 100644
index e6a1eb3e497f..000000000000
--- a/lib/arm/floatsidfvfp.S
+++ /dev/null
@@ -1,25 +0,0 @@
-//===-- floatsidfvfp.S - Implement floatsidfvfp ---------------------------===//
-//
-// 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"
-
-//
-// extern double __floatsidfvfp(int a);
-//
-// Converts a 32-bit int to a double precision float.
-// Uses Darwin calling convention where a double precision result is
-// return in GPR register pair.
-//
- .syntax unified
- .align 2
-DEFINE_COMPILERRT_FUNCTION(__floatsidfvfp)
- vmov s15, r0 // move int to float register s15
- vcvt.f64.s32 d7, s15 // convert 32-bit int in s15 to double in d7
- vmov r0, r1, d7 // move d7 to result register pair r0/r1
- bx lr
diff --git a/lib/arm/floatsisfvfp.S b/lib/arm/floatsisfvfp.S
deleted file mode 100644
index 0d3a24fc1ece..000000000000
--- a/lib/arm/floatsisfvfp.S
+++ /dev/null
@@ -1,25 +0,0 @@
-//===-- floatsisfvfp.S - Implement floatsisfvfp ---------------------------===//
-//
-// 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"
-
-//
-// extern float __floatsisfvfp(int a);
-//
-// Converts single precision float to a 32-bit int rounding towards zero.
-// Uses Darwin calling convention where a single precision result is
-// return in a GPR..
-//
- .syntax unified
- .align 2
-DEFINE_COMPILERRT_FUNCTION(__floatsisfvfp)
- vmov s15, r0 // move int to float register s15
- vcvt.f32.s32 s15, s15 // convert 32-bit int in s15 to float in s15
- vmov r0, s15 // move s15 to result register
- bx lr
diff --git a/lib/arm/floatunssidfvfp.S b/lib/arm/floatunssidfvfp.S
deleted file mode 100644
index 770b20292fd4..000000000000
--- a/lib/arm/floatunssidfvfp.S
+++ /dev/null
@@ -1,25 +0,0 @@
-//===-- floatunssidfvfp.S - Implement floatunssidfvfp ---------------------===//
-//
-// 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"
-
-//
-// extern double __floatunssidfvfp(unsigned int a);
-//
-// Converts a 32-bit int to a double precision float.
-// Uses Darwin calling convention where a double precision result is
-// return in GPR register pair.
-//
- .syntax unified
- .align 2
-DEFINE_COMPILERRT_FUNCTION(__floatunssidfvfp)
- vmov s15, r0 // move int to float register s15
- vcvt.f64.u32 d7, s15 // convert 32-bit int in s15 to double in d7
- vmov r0, r1, d7 // move d7 to result register pair r0/r1
- bx lr
diff --git a/lib/arm/floatunssisfvfp.S b/lib/arm/floatunssisfvfp.S
deleted file mode 100644
index 16b3ffb104ba..000000000000
--- a/lib/arm/floatunssisfvfp.S
+++ /dev/null
@@ -1,25 +0,0 @@
-//===-- floatunssisfvfp.S - Implement floatunssisfvfp ---------------------===//
-//
-// 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"
-
-//
-// extern float __floatunssisfvfp(unsigned int a);
-//
-// Converts single precision float to a 32-bit int rounding towards zero.
-// Uses Darwin calling convention where a single precision result is
-// return in a GPR..
-//
- .syntax unified
- .align 2
-DEFINE_COMPILERRT_FUNCTION(__floatunssisfvfp)
- vmov s15, r0 // move int to float register s15
- vcvt.f32.u32 s15, s15 // convert 32-bit int in s15 to float in s15
- vmov r0, s15 // move s15 to result register
- bx lr
diff --git a/lib/arm/gedf2vfp.S b/lib/arm/gedf2vfp.S
deleted file mode 100644
index 55603b83e306..000000000000
--- a/lib/arm/gedf2vfp.S
+++ /dev/null
@@ -1,28 +0,0 @@
-//===-- gedf2vfp.S - Implement gedf2vfp -----------------------------------===//
-//
-// 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"
-
-//
-// extern int __gedf2vfp(double a, double b);
-//
-// Returns one iff a >= b and neither is NaN.
-// Uses Darwin calling convention where double precision arguments are passsed
-// like in GPR pairs.
-//
- .syntax unified
- .align 2
-DEFINE_COMPILERRT_FUNCTION(__gedf2vfp)
- vmov d6, r0, r1 // load r0/r1 pair in double register
- vmov d7, r2, r3 // load r2/r3 pair in double register
- vcmp.f64 d6, d7
- vmrs apsr_nzcv, fpscr
- movge r0, #1 // set result register to 1 if greater than or equal
- movlt r0, #0
- bx lr
diff --git a/lib/arm/gesf2vfp.S b/lib/arm/gesf2vfp.S
deleted file mode 100644
index 02da35c02e92..000000000000
--- a/lib/arm/gesf2vfp.S
+++ /dev/null
@@ -1,29 +0,0 @@
-//===-- gesf2vfp.S - Implement gesf2vfp -----------------------------------===//
-//
-// 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"
-
-//
-// extern int __gesf2vfp(float a, float b);
-//
-// Returns one iff a >= b and neither is NaN.
-// Uses Darwin calling convention where single precision arguments are passsed
-// like 32-bit ints
-//
- .syntax unified
- .align 2
-DEFINE_COMPILERRT_FUNCTION(__gesf2vfp)
- vmov s14, r0 // move from GPR 0 to float register
- vmov s15, r1 // move from GPR 1 to float register
- vcmp.f32 s14, s15
- vmrs apsr_nzcv, fpscr
- movge r0, #1 // set result register to 1 if greater than or equal
- movlt r0, #0
- bx lr
-
diff --git a/lib/arm/gtdf2vfp.S b/lib/arm/gtdf2vfp.S
deleted file mode 100644
index b5b1e1482762..000000000000
--- a/lib/arm/gtdf2vfp.S
+++ /dev/null
@@ -1,28 +0,0 @@
-//===-- gtdf2vfp.S - Implement gtdf2vfp -----------------------------------===//
-//
-// 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"
-
-//
-// extern double __gtdf2vfp(double a, double b);
-//
-// Returns one iff a > b and neither is NaN.
-// Uses Darwin calling convention where double precision arguments are passsed
-// like in GPR pairs.
-//
- .syntax unified
- .align 2
-DEFINE_COMPILERRT_FUNCTION(__gtdf2vfp)
- vmov d6, r0, r1 // load r0/r1 pair in double register
- vmov d7, r2, r3 // load r2/r3 pair in double register
- vcmp.f64 d6, d7
- vmrs apsr_nzcv, fpscr
- movgt r0, #1 // set result register to 1 if equal
- movle r0, #0
- bx lr
diff --git a/lib/arm/gtsf2vfp.S b/lib/arm/gtsf2vfp.S
deleted file mode 100644
index 685a9cec96ca..000000000000
--- a/lib/arm/gtsf2vfp.S
+++ /dev/null
@@ -1,29 +0,0 @@
-//===-- gtsf2vfp.S - Implement gtsf2vfp -----------------------------------===//
-//
-// 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"
-
-//
-// extern int __gtsf2vfp(float a, float b);
-//
-// Returns one iff a > b and neither is NaN.
-// Uses Darwin calling convention where single precision arguments are passsed
-// like 32-bit ints
-//
- .syntax unified
- .align 2
-DEFINE_COMPILERRT_FUNCTION(__gtsf2vfp)
- vmov s14, r0 // move from GPR 0 to float register
- vmov s15, r1 // move from GPR 1 to float register
- vcmp.f32 s14, s15
- vmrs apsr_nzcv, fpscr
- movgt r0, #1 // set result register to 1 if equal
- movle r0, #0
- bx lr
-
diff --git a/lib/arm/ledf2vfp.S b/lib/arm/ledf2vfp.S
deleted file mode 100644
index 6e140dde8764..000000000000
--- a/lib/arm/ledf2vfp.S
+++ /dev/null
@@ -1,28 +0,0 @@
-//===-- ledf2vfp.S - Implement ledf2vfp -----------------------------------===//
-//
-// 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"
-
-//
-// extern double __ledf2vfp(double a, double b);
-//
-// Returns one iff a <= b and neither is NaN.
-// Uses Darwin calling convention where double precision arguments are passsed
-// like in GPR pairs.
-//
- .syntax unified
- .align 2
-DEFINE_COMPILERRT_FUNCTION(__ledf2vfp)
- vmov d6, r0, r1 // load r0/r1 pair in double register
- vmov d7, r2, r3 // load r2/r3 pair in double register
- vcmp.f64 d6, d7
- vmrs apsr_nzcv, fpscr
- movls r0, #1 // set result register to 1 if equal
- movhi r0, #0
- bx lr
diff --git a/lib/arm/lesf2vfp.S b/lib/arm/lesf2vfp.S
deleted file mode 100644
index 7b2825097a87..000000000000
--- a/lib/arm/lesf2vfp.S
+++ /dev/null
@@ -1,29 +0,0 @@
-//===-- lesf2vfp.S - Implement lesf2vfp -----------------------------------===//
-//
-// 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"
-
-//
-// extern int __lesf2vfp(float a, float b);
-//
-// Returns one iff a <= b and neither is NaN.
-// Uses Darwin calling convention where single precision arguments are passsed
-// like 32-bit ints
-//
- .syntax unified
- .align 2
-DEFINE_COMPILERRT_FUNCTION(__lesf2vfp)
- vmov s14, r0 // move from GPR 0 to float register
- vmov s15, r1 // move from GPR 1 to float register
- vcmp.f32 s14, s15
- vmrs apsr_nzcv, fpscr
- movls r0, #1 // set result register to 1 if equal
- movhi r0, #0
- bx lr
-
diff --git a/lib/arm/ltdf2vfp.S b/lib/arm/ltdf2vfp.S
deleted file mode 100644
index a09e67a2f43d..000000000000
--- a/lib/arm/ltdf2vfp.S
+++ /dev/null
@@ -1,28 +0,0 @@
-//===-- ltdf2vfp.S - Implement ltdf2vfp -----------------------------------===//
-//
-// 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"
-
-//
-// extern double __ltdf2vfp(double a, double b);
-//
-// Returns one iff a < b and neither is NaN.
-// Uses Darwin calling convention where double precision arguments are passsed
-// like in GPR pairs.
-//
- .syntax unified
- .align 2
-DEFINE_COMPILERRT_FUNCTION(__ltdf2vfp)
- vmov d6, r0, r1 // load r0/r1 pair in double register
- vmov d7, r2, r3 // load r2/r3 pair in double register
- vcmp.f64 d6, d7
- vmrs apsr_nzcv, fpscr
- movmi r0, #1 // set result register to 1 if equal
- movpl r0, #0
- bx lr
diff --git a/lib/arm/ltsf2vfp.S b/lib/arm/ltsf2vfp.S
deleted file mode 100644
index 8c7f9a863f34..000000000000
--- a/lib/arm/ltsf2vfp.S
+++ /dev/null
@@ -1,29 +0,0 @@
-//===-- ltsf2vfp.S - Implement ltsf2vfp -----------------------------------===//
-//
-// 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"
-
-//
-// extern int __ltsf2vfp(float a, float b);
-//
-// Returns one iff a < b and neither is NaN.
-// Uses Darwin calling convention where single precision arguments are passsed
-// like 32-bit ints
-//
- .syntax unified
- .align 2
-DEFINE_COMPILERRT_FUNCTION(__ltsf2vfp)
- vmov s14, r0 // move from GPR 0 to float register
- vmov s15, r1 // move from GPR 1 to float register
- vcmp.f32 s14, s15
- vmrs apsr_nzcv, fpscr
- movmi r0, #1 // set result register to 1 if equal
- movpl r0, #0
- bx lr
-
diff --git a/lib/arm/modsi3.S b/lib/arm/modsi3.S
deleted file mode 100644
index fe75b41b1331..000000000000
--- a/lib/arm/modsi3.S
+++ /dev/null
@@ -1,50 +0,0 @@
-/*===-- modsi3.S - 32-bit signed integer modulus --------------------------===//
- *
- * 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 the __modsi3 (32-bit signed integer modulus) function
- * for the ARM architecture as a wrapper around the unsigned routine.
- *
- *===----------------------------------------------------------------------===*/
-
-#include "../assembly.h"
-
-#define ESTABLISH_FRAME \
- push {r4, r7, lr} ;\
- add r7, sp, #4
-#define CLEAR_FRAME_AND_RETURN \
- pop {r4, r7, pc}
-
-.syntax unified
-.align 3
-DEFINE_COMPILERRT_FUNCTION(__modsi3)
-#if __ARM_ARCH_EXT_IDIV__
- tst r1, r1
- beq LOCAL_LABEL(divzero)
- sdiv r2, r0, r1
- mls r0, r2, r1, r0
- bx lr
-LOCAL_LABEL(divzero):
- mov r0, #0
- bx lr
-#else
- ESTABLISH_FRAME
- // Set aside the sign of the dividend.
- mov r4, r0
- // Take absolute value of a and b via abs(x) = (x^(x >> 31)) - (x >> 31).
- eor r2, r0, r0, asr #31
- eor r3, r1, r1, asr #31
- sub r0, r2, r0, asr #31
- sub r1, r3, r1, asr #31
- // abs(a) % abs(b)
- bl SYMBOL_NAME(__umodsi3)
- // Apply sign of dividend to result and return.
- eor r0, r0, r4, asr #31
- sub r0, r0, r4, asr #31
- CLEAR_FRAME_AND_RETURN
-#endif
diff --git a/lib/arm/muldf3vfp.S b/lib/arm/muldf3vfp.S
deleted file mode 100644
index 838581eb1097..000000000000
--- a/lib/arm/muldf3vfp.S
+++ /dev/null
@@ -1,25 +0,0 @@
-//===-- muldf3vfp.S - Implement muldf3vfp ---------------------------------===//
-//
-// 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"
-
-//
-// extern double __muldf3vfp(double a, double b);
-//
-// Multiplies two double precision floating point numbers using the Darwin
-// calling convention where double arguments are passsed in GPR pairs
-//
- .syntax unified
- .align 2
-DEFINE_COMPILERRT_FUNCTION(__muldf3vfp)
- vmov d6, r0, r1 // move first param from r0/r1 pair into d6
- vmov d7, r2, r3 // move second param from r2/r3 pair into d7
- vmul.f64 d6, d6, d7
- vmov r0, r1, d6 // move result back to r0/r1 pair
- bx lr
diff --git a/lib/arm/mulsf3vfp.S b/lib/arm/mulsf3vfp.S
deleted file mode 100644
index ea25913cc49d..000000000000
--- a/lib/arm/mulsf3vfp.S
+++ /dev/null
@@ -1,25 +0,0 @@
-//===-- mulsf3vfp.S - Implement mulsf3vfp ---------------------------------===//
-//
-// 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"
-
-//
-// extern float __mulsf3vfp(float a, float b);
-//
-// Multiplies two single precision floating point numbers using the Darwin
-// calling convention where single arguments are passsed like 32-bit ints.
-//
- .syntax unified
- .align 2
-DEFINE_COMPILERRT_FUNCTION(__mulsf3vfp)
- vmov s14, r0 // move first param from r0 into float register
- vmov s15, r1 // move second param from r1 into float register
- vmul.f32 s13, s14, s15
- vmov r0, s13 // move result back to r0
- bx lr
diff --git a/lib/arm/nedf2vfp.S b/lib/arm/nedf2vfp.S
deleted file mode 100644
index 21670816c609..000000000000
--- a/lib/arm/nedf2vfp.S
+++ /dev/null
@@ -1,28 +0,0 @@
-//===-- nedf2vfp.S - Implement nedf2vfp -----------------------------------===//
-//
-// 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"
-
-//
-// extern double __nedf2vfp(double a, double b);
-//
-// Returns zero if a and b are unequal and neither is NaN.
-// Uses Darwin calling convention where double precision arguments are passsed
-// like in GPR pairs.
-//
- .syntax unified
- .align 2
-DEFINE_COMPILERRT_FUNCTION(__nedf2vfp)
- vmov d6, r0, r1 // load r0/r1 pair in double register
- vmov d7, r2, r3 // load r2/r3 pair in double register
- vcmp.f64 d6, d7
- vmrs apsr_nzcv, fpscr
- movne r0, #1 // set result register to 0 if unequal
- moveq r0, #0
- bx lr
diff --git a/lib/arm/negdf2vfp.S b/lib/arm/negdf2vfp.S
deleted file mode 100644
index 64c9b692f454..000000000000
--- a/lib/arm/negdf2vfp.S
+++ /dev/null
@@ -1,22 +0,0 @@
-//===-- negdf2vfp.S - Implement negdf2vfp ---------------------------------===//
-//
-// 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"
-
-//
-// extern double __negdf2vfp(double a, double b);
-//
-// Returns the negation a double precision floating point numbers using the
-// Darwin calling convention where double arguments are passsed in GPR pairs.
-//
- .syntax unified
- .align 2
-DEFINE_COMPILERRT_FUNCTION(__negdf2vfp)
- eor r1, r1, #-2147483648 // flip sign bit on double in r0/r1 pair
- bx lr
diff --git a/lib/arm/negsf2vfp.S b/lib/arm/negsf2vfp.S
deleted file mode 100644
index b883b733df64..000000000000
--- a/lib/arm/negsf2vfp.S
+++ /dev/null
@@ -1,22 +0,0 @@
-//===-- negsf2vfp.S - Implement negsf2vfp ---------------------------------===//
-//
-// 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"
-
-//
-// extern float __negsf2vfp(float a);
-//
-// Returns the negation of a single precision floating point numbers using the
-// Darwin calling convention where single arguments are passsed like 32-bit ints
-//
- .syntax unified
- .align 2
-DEFINE_COMPILERRT_FUNCTION(__negsf2vfp)
- eor r0, r0, #-2147483648 // flip sign bit on float in r0
- bx lr
diff --git a/lib/arm/nesf2vfp.S b/lib/arm/nesf2vfp.S
deleted file mode 100644
index fa7aa80e1912..000000000000
--- a/lib/arm/nesf2vfp.S
+++ /dev/null
@@ -1,29 +0,0 @@
-//===-- nesf2vfp.S - Implement nesf2vfp -----------------------------------===//
-//
-// 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"
-
-//
-// extern int __nesf2vfp(float a, float b);
-//
-// Returns one iff a != b and neither is NaN.
-// Uses Darwin calling convention where single precision arguments are passsed
-// like 32-bit ints
-//
- .syntax unified
- .align 2
-DEFINE_COMPILERRT_FUNCTION(__nesf2vfp)
- vmov s14, r0 // move from GPR 0 to float register
- vmov s15, r1 // move from GPR 1 to float register
- vcmp.f32 s14, s15
- vmrs apsr_nzcv, fpscr
- movne r0, #1 // set result register to 1 if unequal
- moveq r0, #0
- bx lr
-
diff --git a/lib/arm/restore_vfp_d8_d15_regs.S b/lib/arm/restore_vfp_d8_d15_regs.S
deleted file mode 100644
index 7f441db5383b..000000000000
--- a/lib/arm/restore_vfp_d8_d15_regs.S
+++ /dev/null
@@ -1,37 +0,0 @@
-//===-- save_restore_regs.S - Implement save/restore* ---------------------===//
-//
-// 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"
-
-//
-// When compiling C++ functions that need to handle thrown exceptions the
-// compiler is required to save all registers and call __Unwind_SjLj_Register
-// in the function prolog. But when compiling for thumb1, there are
-// no instructions to access the floating point registers, so the
-// compiler needs to add a call to the helper function _save_vfp_d8_d15_regs
-// written in ARM to save the float registers. In the epilog, the compiler
-// must also add a call to __restore_vfp_d8_d15_regs to restore those registers.
-//
-
- .text
- .syntax unified
-
-//
-// Restore registers d8-d15 from stack
-//
- .align 2
-DEFINE_COMPILERRT_PRIVATE_FUNCTION(__restore_vfp_d8_d15_regs)
- vldmia sp!, {d8-d15} // pop registers d8-d15 off stack
- bx lr // return to prolog
-
-
-
- // tell linker it can break up file at label boundaries
- .subsections_via_symbols
-
diff --git a/lib/arm/save_vfp_d8_d15_regs.S b/lib/arm/save_vfp_d8_d15_regs.S
deleted file mode 100644
index fbd21ba38358..000000000000
--- a/lib/arm/save_vfp_d8_d15_regs.S
+++ /dev/null
@@ -1,35 +0,0 @@
-//===-- save_restore_regs.S - Implement save/restore* ---------------------===//
-//
-// 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"
-
-//
-// When compiling C++ functions that need to handle thrown exceptions the
-// compiler is required to save all registers and call __Unwind_SjLj_Register
-// in the function prolog. But when compiling for thumb1, there are
-// no instructions to access the floating point registers, so the
-// compiler needs to add a call to the helper function _save_vfp_d8_d15_regs
-// written in ARM to save the float registers. In the epilog, the compiler
-// must also add a call to __restore_vfp_d8_d15_regs to restore those registers.
-//
-
- .text
- .syntax unified
-
-//
-// Save registers d8-d15 onto stack
-//
- .align 2
-DEFINE_COMPILERRT_PRIVATE_FUNCTION(__save_vfp_d8_d15_regs)
- vstmdb sp!, {d8-d15} // push registers d8-d15 onto stack
- bx lr // return to prolog
-
- // tell linker it can break up file at label boundaries
- .subsections_via_symbols
-
diff --git a/lib/arm/subdf3vfp.S b/lib/arm/subdf3vfp.S
deleted file mode 100644
index 3f88baacd5bf..000000000000
--- a/lib/arm/subdf3vfp.S
+++ /dev/null
@@ -1,25 +0,0 @@
-//===-- subdf3vfp.S - Implement subdf3vfp ---------------------------------===//
-//
-// 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"
-
-//
-// extern double __subdf3vfp(double a, double b);
-//
-// Returns difference between two double precision floating point numbers using
-// the Darwin calling convention where double arguments are passsed in GPR pairs
-//
- .syntax unified
- .align 2
-DEFINE_COMPILERRT_FUNCTION(__subdf3vfp)
- vmov d6, r0, r1 // move first param from r0/r1 pair into d6
- vmov d7, r2, r3 // move second param from r2/r3 pair into d7
- vsub.f64 d6, d6, d7
- vmov r0, r1, d6 // move result back to r0/r1 pair
- bx lr
diff --git a/lib/arm/subsf3vfp.S b/lib/arm/subsf3vfp.S
deleted file mode 100644
index ed02ba92167f..000000000000
--- a/lib/arm/subsf3vfp.S
+++ /dev/null
@@ -1,26 +0,0 @@
-//===-- subsf3vfp.S - Implement subsf3vfp ---------------------------------===//
-//
-// 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"
-
-//
-// extern float __subsf3vfp(float a, float b);
-//
-// Returns the difference between two single precision floating point numbers
-// using the Darwin calling convention where single arguments are passsed
-// like 32-bit ints.
-//
- .syntax unified
- .align 2
-DEFINE_COMPILERRT_FUNCTION(__subsf3vfp)
- vmov s14, r0 // move first param from r0 into float register
- vmov s15, r1 // move second param from r1 into float register
- vsub.f32 s14, s14, s15
- vmov r0, s14 // move result back to r0
- bx lr
diff --git a/lib/arm/switch16.S b/lib/arm/switch16.S
deleted file mode 100644
index 9c3f0cf9915f..000000000000
--- a/lib/arm/switch16.S
+++ /dev/null
@@ -1,45 +0,0 @@
-//===-- switch.S - Implement switch* --------------------------------------===//
-//
-// 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"
-
-//
-// When compiling switch statements in thumb mode, the compiler
-// can use these __switch* helper functions The compiler emits a blx to
-// the __switch* function followed by a table of displacements for each
-// case statement. On entry, R0 is the index into the table. The __switch*
-// function uses the return address in lr to find the start of the table.
-// The first entry in the table is the count of the entries in the table.
-// It then uses R0 to index into the table and get the displacement of the
-// address to jump to. If R0 is greater than the size of the table, it jumps
-// to the last entry in the table. Each displacement in the table is actually
-// the distance from lr to the label, thus making the tables PIC.
-
-
- .text
- .syntax unified
-
-//
-// The table contains signed 2-byte sized elements which are 1/2 the distance
-// from lr to the target label.
-//
- .align 2
-DEFINE_COMPILERRT_PRIVATE_FUNCTION(__switch16)
- ldrh ip, [lr, #-1] // get first 16-bit word in table
- cmp r0, ip // compare with index
- add r0, lr, r0, lsl #1 // compute address of element in table
- add ip, lr, ip, lsl #1 // compute address of last element in table
- ite lo
- ldrshlo r0, [r0, #1] // load 16-bit element if r0 is in range
- ldrshhs r0, [ip, #1] // load 16-bit element if r0 out of range
- add ip, lr, r0, lsl #1 // compute label = lr + element*2
- bx ip // jump to computed label
-
- // tell linker it can break up file at label boundaries
- .subsections_via_symbols
diff --git a/lib/arm/switch32.S b/lib/arm/switch32.S
deleted file mode 100644
index 3152dfa1d0be..000000000000
--- a/lib/arm/switch32.S
+++ /dev/null
@@ -1,47 +0,0 @@
-//===-- switch.S - Implement switch* --------------------------------------===//
-//
-// 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"
-
-//
-// When compiling switch statements in thumb mode, the compiler
-// can use these __switch* helper functions The compiler emits a blx to
-// the __switch* function followed by a table of displacements for each
-// case statement. On entry, R0 is the index into the table. The __switch*
-// function uses the return address in lr to find the start of the table.
-// The first entry in the table is the count of the entries in the table.
-// It then uses R0 to index into the table and get the displacement of the
-// address to jump to. If R0 is greater than the size of the table, it jumps
-// to the last entry in the table. Each displacement in the table is actually
-// the distance from lr to the label, thus making the tables PIC.
-
-
- .text
- .syntax unified
-
-//
-// The table contains signed 4-byte sized elements which are the distance
-// from lr to the target label.
-//
- .align 2
-DEFINE_COMPILERRT_PRIVATE_FUNCTION(__switch32)
- ldr ip, [lr, #-1] // get first 32-bit word in table
- cmp r0, ip // compare with index
- add r0, lr, r0, lsl #2 // compute address of element in table
- add ip, lr, ip, lsl #2 // compute address of last element in table
- ite lo
- ldrlo r0, [r0, #3] // load 32-bit element if r0 is in range
- ldrhs r0, [ip, #3] // load 32-bit element if r0 out of range
- add ip, lr, r0 // compute label = lr + element
- bx ip // jump to computed label
-
-
- // tell linker it can break up file at label boundaries
- .subsections_via_symbols
-
diff --git a/lib/arm/switch8.S b/lib/arm/switch8.S
deleted file mode 100644
index 15729ebc3165..000000000000
--- a/lib/arm/switch8.S
+++ /dev/null
@@ -1,44 +0,0 @@
-//===-- switch.S - Implement switch* --------------------------------------===//
-//
-// 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"
-
-//
-// When compiling switch statements in thumb mode, the compiler
-// can use these __switch* helper functions The compiler emits a blx to
-// the __switch* function followed by a table of displacements for each
-// case statement. On entry, R0 is the index into the table. The __switch*
-// function uses the return address in lr to find the start of the table.
-// The first entry in the table is the count of the entries in the table.
-// It then uses R0 to index into the table and get the displacement of the
-// address to jump to. If R0 is greater than the size of the table, it jumps
-// to the last entry in the table. Each displacement in the table is actually
-// the distance from lr to the label, thus making the tables PIC.
-
-
- .text
- .syntax unified
-
-//
-// The table contains signed byte sized elements which are 1/2 the distance
-// from lr to the target label.
-//
- .align 2
-DEFINE_COMPILERRT_PRIVATE_FUNCTION(__switch8)
- ldrb ip, [lr, #-1] // get first byte in table
- cmp r0, ip // signed compare with index
- ite lo
- ldrsblo r0, [lr, r0] // get indexed byte out of table
- ldrsbhs r0, [lr, ip] // if out of range, use last entry in table
- add ip, lr, r0, lsl #1 // compute label = lr + element*2
- bx ip // jump to computed label
-
- // tell linker it can break up file at label boundaries
- .subsections_via_symbols
-
diff --git a/lib/arm/switchu8.S b/lib/arm/switchu8.S
deleted file mode 100644
index 0a4efac88abe..000000000000
--- a/lib/arm/switchu8.S
+++ /dev/null
@@ -1,44 +0,0 @@
-//===-- switch.S - Implement switch* --------------------------------------===//
-//
-// 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"
-
-//
-// When compiling switch statements in thumb mode, the compiler
-// can use these __switch* helper functions The compiler emits a blx to
-// the __switch* function followed by a table of displacements for each
-// case statement. On entry, R0 is the index into the table. The __switch*
-// function uses the return address in lr to find the start of the table.
-// The first entry in the table is the count of the entries in the table.
-// It then uses R0 to index into the table and get the displacement of the
-// address to jump to. If R0 is greater than the size of the table, it jumps
-// to the last entry in the table. Each displacement in the table is actually
-// the distance from lr to the label, thus making the tables PIC.
-
-
- .text
- .syntax unified
-
-//
-// The table contains unsigned byte sized elements which are 1/2 the distance
-// from lr to the target label.
-//
- .align 2
-DEFINE_COMPILERRT_PRIVATE_FUNCTION(__switchu8)
- ldrb ip, [lr, #-1] // get first byte in table
- cmp r0, ip // compare with index
- ite lo
- ldrblo r0, [lr, r0] // get indexed byte out of table
- ldrbhs r0, [lr, ip] // if out of range, use last entry in table
- add ip, lr, r0, lsl #1 // compute label = lr + element*2
- bx ip // jump to computed label
-
- // tell linker it can break up file at label boundaries
- .subsections_via_symbols
-
diff --git a/lib/arm/sync_synchronize.S b/lib/arm/sync_synchronize.S
deleted file mode 100644
index 06dade964728..000000000000
--- a/lib/arm/sync_synchronize.S
+++ /dev/null
@@ -1,34 +0,0 @@
-//===-- sync_synchronize - Implement memory barrier * ----------------------===//
-//
-// 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"
-
-//
-// When compiling a use of the gcc built-in __sync_synchronize() in thumb1 mode
-// the compiler may emit a call to __sync_synchronize.
-// On Darwin the implementation jumps to an OS supplied function named
-// OSMemoryBarrier
-//
-
- .text
- .syntax unified
-
-#if __APPLE__
-
- .align 2
-DEFINE_COMPILERRT_PRIVATE_FUNCTION(__sync_synchronize)
- stmfd sp!, {r7, lr}
- add r7, sp, #0
- bl _OSMemoryBarrier
- ldmfd sp!, {r7, pc}
-
- // tell linker it can break up file at label boundaries
- .subsections_via_symbols
-
-#endif
diff --git a/lib/arm/truncdfsf2vfp.S b/lib/arm/truncdfsf2vfp.S
deleted file mode 100644
index 371aee94b16a..000000000000
--- a/lib/arm/truncdfsf2vfp.S
+++ /dev/null
@@ -1,25 +0,0 @@
-//===-- truncdfsf2vfp.S - Implement truncdfsf2vfp -------------------------===//
-//
-// 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"
-
-//
-// extern float __truncdfsf2vfp(double a);
-//
-// Converts double precision float to signle precision result.
-// Uses Darwin calling convention where a double precision parameter is
-// passed in a R0/R1 pair and a signle precision result is returned in R0.
-//
- .syntax unified
- .align 2
-DEFINE_COMPILERRT_FUNCTION(__truncdfsf2vfp)
- vmov d7, r0, r1 // load double from r0/r1 pair
- vcvt.f32.f64 s15, d7 // convert double to single (trucate precision)
- vmov r0, s15 // return result in r0
- bx lr
diff --git a/lib/arm/udivmodsi4.S b/lib/arm/udivmodsi4.S
deleted file mode 100644
index aee2776671f7..000000000000
--- a/lib/arm/udivmodsi4.S
+++ /dev/null
@@ -1,96 +0,0 @@
-/*===-- udivmodsi4.S - 32-bit unsigned integer divide and modulus ---------===//
- *
- * 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 the __udivmodsi4 (32-bit unsigned integer divide and
- * modulus) function for the ARM architecture. A naive digit-by-digit
- * computation is employed for simplicity.
- *
- *===----------------------------------------------------------------------===*/
-
-#include "../assembly.h"
-
-#define ESTABLISH_FRAME \
- push {r4, r7, lr} ;\
- add r7, sp, #4
-#define CLEAR_FRAME_AND_RETURN \
- pop {r4, r7, pc}
-
-#define a r0
-#define b r1
-#define i r3
-#define r r4
-#define q ip
-#define one lr
-
-.syntax unified
-.align 3
-DEFINE_COMPILERRT_FUNCTION(__udivmodsi4)
-#if __ARM_ARCH_EXT_IDIV__
- tst r1, r1
- beq LOCAL_LABEL(divzero)
- mov r3, r0
- udiv r0, r3, r1
- mls r1, r0, r1, r3
- str r1, [r2]
- bx lr
-LOCAL_LABEL(divzero):
- mov r0, #0
- bx lr
-#else
-// We use a simple digit by digit algorithm; before we get into the actual
-// divide loop, we must calculate the left-shift amount necessary to align
-// the MSB of the divisor with that of the dividend (If this shift is
-// negative, then the result is zero, and we early out). We also conjure a
-// bit mask of 1 to use in constructing the quotient, and initialize the
-// quotient to zero.
- ESTABLISH_FRAME
- clz r4, a
- tst b, b // detect divide-by-zero
- clz r3, b
- mov q, #0
- beq LOCAL_LABEL(return) // return 0 if b is zero.
- mov one, #1
- subs i, r3, r4
- blt LOCAL_LABEL(return) // return 0 if MSB(a) < MSB(b)
-
-LOCAL_LABEL(mainLoop):
-// This loop basically implements the following:
-//
-// do {
-// if (a >= b << i) {
-// a -= b << i;
-// q |= 1 << i;
-// if (a == 0) break;
-// }
-// } while (--i)
-//
-// Note that this does not perform the final iteration (i == 0); by doing it
-// this way, we can merge the two branches which is a substantial win for
-// such a tight loop on current ARM architectures.
- subs r, a, b, lsl i
- itt hs
- orrhs q, q,one, lsl i
- movhs a, r
- it ne
- subsne i, i, #1
- bhi LOCAL_LABEL(mainLoop)
-
-// Do the final test subtraction and update of quotient (i == 0), as it is
-// not performed in the main loop.
- subs r, a, b
- itt hs
- orrhs q, #1
- movhs a, r
-
-LOCAL_LABEL(return):
-// Store the remainder, and move the quotient to r0, then return.
- str a, [r2]
- mov r0, q
- CLEAR_FRAME_AND_RETURN
-#endif
diff --git a/lib/arm/udivsi3.S b/lib/arm/udivsi3.S
deleted file mode 100644
index 2bb14123ca31..000000000000
--- a/lib/arm/udivsi3.S
+++ /dev/null
@@ -1,93 +0,0 @@
-/*===-- udivsi3.S - 32-bit unsigned integer divide ------------------------===//
- *
- * 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 the __udivsi3 (32-bit unsigned integer divide)
- * function for the ARM architecture. A naive digit-by-digit computation is
- * employed for simplicity.
- *
- *===----------------------------------------------------------------------===*/
-
-#include "../assembly.h"
-
-#define ESTABLISH_FRAME \
- push {r7, lr} ;\
- mov r7, sp
-#define CLEAR_FRAME_AND_RETURN \
- pop {r7, pc}
-
-#define a r0
-#define b r1
-#define r r2
-#define i r3
-#define q ip
-#define one lr
-
-.syntax unified
-.align 3
-// Ok, APCS and AAPCS agree on 32 bit args, so it's safe to use the same routine.
-DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_uidiv, __udivsi3)
-DEFINE_COMPILERRT_FUNCTION(__udivsi3)
-#if __ARM_ARCH_EXT_IDIV__
- tst r1,r1
- beq LOCAL_LABEL(divzero)
- udiv r0, r0, r1
- bx lr
- LOCAL_LABEL(divzero):
- mov r0,#0
- bx lr
-#else
-// We use a simple digit by digit algorithm; before we get into the actual
-// divide loop, we must calculate the left-shift amount necessary to align
-// the MSB of the divisor with that of the dividend (If this shift is
-// negative, then the result is zero, and we early out). We also conjure a
-// bit mask of 1 to use in constructing the quotient, and initialize the
-// quotient to zero.
- ESTABLISH_FRAME
- clz r2, a
- tst b, b // detect divide-by-zero
- clz r3, b
- mov q, #0
- beq LOCAL_LABEL(return) // return 0 if b is zero.
- mov one, #1
- subs i, r3, r2
- blt LOCAL_LABEL(return) // return 0 if MSB(a) < MSB(b)
-
-LOCAL_LABEL(mainLoop):
-// This loop basically implements the following:
-//
-// do {
-// if (a >= b << i) {
-// a -= b << i;
-// q |= 1 << i;
-// if (a == 0) break;
-// }
-// } while (--i)
-//
-// Note that this does not perform the final iteration (i == 0); by doing it
-// this way, we can merge the two branches which is a substantial win for
-// such a tight loop on current ARM architectures.
- subs r, a, b, lsl i
- itt hs
- orrhs q, q,one, lsl i
- movhs a, r
- it ne
- subsne i, i, #1
- bhi LOCAL_LABEL(mainLoop)
-
-// Do the final test subtraction and update of quotient (i == 0), as it is
-// not performed in the main loop.
- subs r, a, b
- it hs
- orrhs q, #1
-
-LOCAL_LABEL(return):
-// Move the quotient to r0 and return.
- mov r0, q
- CLEAR_FRAME_AND_RETURN
-#endif
diff --git a/lib/arm/umodsi3.S b/lib/arm/umodsi3.S
deleted file mode 100644
index 092a4f1a2062..000000000000
--- a/lib/arm/umodsi3.S
+++ /dev/null
@@ -1,72 +0,0 @@
-/*===-- umodsi3.S - 32-bit unsigned integer modulus -----------------------===//
- *
- * 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 the __umodsi3 (32-bit unsigned integer modulus)
- * function for the ARM architecture. A naive digit-by-digit computation is
- * employed for simplicity.
- *
- *===----------------------------------------------------------------------===*/
-
-#include "../assembly.h"
-
-#define a r0
-#define b r1
-#define r r2
-#define i r3
-
-.syntax unified
-.align 3
-DEFINE_COMPILERRT_FUNCTION(__umodsi3)
-#if __ARM_ARCH_EXT_IDIV__
- tst r1, r1
- beq LOCAL_LABEL(divzero)
- udiv r2, r0, r1
- mls r0, r2, r1, r0
- bx lr
-LOCAL_LABEL(divzero):
- mov r0, #0
- bx lr
-#else
-// We use a simple digit by digit algorithm; before we get into the actual
-// divide loop, we must calculate the left-shift amount necessary to align
-// the MSB of the divisor with that of the dividend.
- clz r2, a
- tst b, b // detect b == 0
- clz r3, b
- bxeq lr // return a if b == 0
- subs i, r3, r2
- bxlt lr // return a if MSB(a) < MSB(b)
-
-LOCAL_LABEL(mainLoop):
-// This loop basically implements the following:
-//
-// do {
-// if (a >= b << i) {
-// a -= b << i;
-// if (a == 0) break;
-// }
-// } while (--i)
-//
-// Note that this does not perform the final iteration (i == 0); by doing it
-// this way, we can merge the two branches which is a substantial win for
-// such a tight loop on current ARM architectures.
- subs r, a, b, lsl i
- it hs
- movhs a, r
- it ne
- subsne i, i, #1
- bhi LOCAL_LABEL(mainLoop)
-
-// Do the final test subtraction and update of remainder (i == 0), as it is
-// not performed in the main loop.
- subs r, a, b
- it hs
- movhs a, r
- bx lr
-#endif
diff --git a/lib/arm/unorddf2vfp.S b/lib/arm/unorddf2vfp.S
deleted file mode 100644
index c49e55f29a4b..000000000000
--- a/lib/arm/unorddf2vfp.S
+++ /dev/null
@@ -1,28 +0,0 @@
-//===-- unorddf2vfp.S - Implement unorddf2vfp ------------------------------===//
-//
-// 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"
-
-//
-// extern int __unorddf2vfp(double a, double b);
-//
-// Returns one iff a or b is NaN
-// Uses Darwin calling convention where double precision arguments are passsed
-// like in GPR pairs.
-//
- .syntax unified
- .align 2
-DEFINE_COMPILERRT_FUNCTION(__unorddf2vfp)
- vmov d6, r0, r1 // load r0/r1 pair in double register
- vmov d7, r2, r3 // load r2/r3 pair in double register
- vcmp.f64 d6, d7
- vmrs apsr_nzcv, fpscr
- movvs r0, #1 // set result register to 1 if "overflow" (any NaNs)
- movvc r0, #0
- bx lr
diff --git a/lib/arm/unordsf2vfp.S b/lib/arm/unordsf2vfp.S
deleted file mode 100644
index 0ab27edf51ad..000000000000
--- a/lib/arm/unordsf2vfp.S
+++ /dev/null
@@ -1,29 +0,0 @@
-//===-- unordsf2vfp.S - Implement unordsf2vfp -----------------------------===//
-//
-// 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"
-
-//
-// extern int __unordsf2vfp(float a, float b);
-//
-// Returns one iff a or b is NaN
-// Uses Darwin calling convention where single precision arguments are passsed
-// like 32-bit ints
-//
- .syntax unified
- .align 2
-DEFINE_COMPILERRT_FUNCTION(__unordsf2vfp)
- vmov s14, r0 // move from GPR 0 to float register
- vmov s15, r1 // move from GPR 1 to float register
- vcmp.f32 s14, s15
- vmrs apsr_nzcv, fpscr
- movvs r0, #1 // set result register to 1 if "overflow" (any NaNs)
- movvc r0, #0
- bx lr
-
diff --git a/lib/asan/CMakeLists.txt b/lib/asan/CMakeLists.txt
index ad3f05488ebf..47486b7caf89 100644
--- a/lib/asan/CMakeLists.txt
+++ b/lib/asan/CMakeLists.txt
@@ -2,6 +2,8 @@
set(ASAN_SOURCES
asan_allocator2.cc
+ asan_activation.cc
+ asan_debugging.cc
asan_fake_stack.cc
asan_globals.cc
asan_interceptors.cc
@@ -10,81 +12,85 @@ set(ASAN_SOURCES
asan_malloc_linux.cc
asan_malloc_mac.cc
asan_malloc_win.cc
- asan_new_delete.cc
asan_poisoning.cc
asan_posix.cc
- asan_preinit.cc
asan_report.cc
asan_rtl.cc
asan_stack.cc
asan_stats.cc
+ asan_suppressions.cc
asan_thread.cc
asan_win.cc)
+set(ASAN_CXX_SOURCES
+ asan_new_delete.cc)
+
+set(ASAN_PREINIT_SOURCES
+ asan_preinit.cc)
+
include_directories(..)
-if (NOT MSVC)
- set(ASAN_CFLAGS
- ${SANITIZER_COMMON_CFLAGS}
- -fno-rtti)
-else()
- set(ASAN_CFLAGS
- ${SANITIZER_COMMON_CFLAGS}
- /GR-)
-endif()
+set(ASAN_CFLAGS ${SANITIZER_COMMON_CFLAGS})
+append_no_rtti_flag(ASAN_CFLAGS)
set(ASAN_COMMON_DEFINITIONS
ASAN_HAS_EXCEPTIONS=1)
if(ANDROID)
list(APPEND ASAN_COMMON_DEFINITIONS
- ASAN_FLEXIBLE_MAPPING_AND_OFFSET=0
- ASAN_NEEDS_SEGV=0
ASAN_LOW_MEMORY=1)
-elseif(MSVC)
- list(APPEND ASAN_COMMON_DEFINITIONS
- ASAN_FLEXIBLE_MAPPING_AND_OFFSET=0
- ASAN_NEEDS_SEGV=0)
-else()
- list(APPEND ASAN_COMMON_DEFINITIONS
- ASAN_FLEXIBLE_MAPPING_AND_OFFSET=1
- ASAN_NEEDS_SEGV=1)
endif()
-# Architectures supported by ASan.
-filter_available_targets(ASAN_SUPPORTED_ARCH
- x86_64 i386 powerpc64)
+set(ASAN_DYNAMIC_DEFINITIONS
+ ${ASAN_COMMON_DEFINITIONS} ASAN_DYNAMIC=1)
+append_list_if(WIN32 INTERCEPTION_DYNAMIC_CRT ASAN_DYNAMIC_DEFINITIONS)
+
+set(ASAN_DYNAMIC_CFLAGS ${ASAN_CFLAGS})
+append_list_if(COMPILER_RT_HAS_FTLS_MODEL_INITIAL_EXEC
+ -ftls-model=initial-exec ASAN_DYNAMIC_CFLAGS)
+append_list_if(MSVC /DEBUG ASAN_DYNAMIC_CFLAGS)
+
+append_list_if(COMPILER_RT_HAS_LIBC c ASAN_DYNAMIC_LIBS)
+append_list_if(COMPILER_RT_HAS_LIBDL dl 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)
# Compile ASan sources into an object library.
if(APPLE)
foreach(os ${SANITIZER_COMMON_SUPPORTED_DARWIN_OS})
add_compiler_rt_darwin_object_library(RTAsan ${os}
ARCH ${ASAN_SUPPORTED_ARCH}
- SOURCES ${ASAN_SOURCES}
+ SOURCES ${ASAN_SOURCES} ${ASAN_CXX_SOURCES}
CFLAGS ${ASAN_CFLAGS}
DEFS ${ASAN_COMMON_DEFINITIONS})
endforeach()
-elseif(ANDROID)
- add_library(RTAsan.arm.android OBJECT ${ASAN_SOURCES})
- set_target_compile_flags(RTAsan.arm.android ${ASAN_CFLAGS})
- set_property(TARGET RTAsan.arm.android APPEND PROPERTY
- COMPILE_DEFINITIONS ${ASAN_COMMON_DEFINITIONS})
else()
foreach(arch ${ASAN_SUPPORTED_ARCH})
add_compiler_rt_object_library(RTAsan ${arch}
SOURCES ${ASAN_SOURCES} CFLAGS ${ASAN_CFLAGS}
DEFS ${ASAN_COMMON_DEFINITIONS})
+ add_compiler_rt_object_library(RTAsan_cxx ${arch}
+ SOURCES ${ASAN_CXX_SOURCES} CFLAGS ${ASAN_CFLAGS}
+ DEFS ${ASAN_COMMON_DEFINITIONS})
+ add_compiler_rt_object_library(RTAsan_preinit ${arch}
+ SOURCES ${ASAN_PREINIT_SOURCES} CFLAGS ${ASAN_CFLAGS}
+ DEFS ${ASAN_COMMON_DEFINITIONS})
+ if (COMPILER_RT_BUILD_SHARED_ASAN)
+ add_compiler_rt_object_library(RTAsan_dynamic ${arch}
+ SOURCES ${ASAN_SOURCES} ${ASAN_CXX_SOURCES}
+ CFLAGS ${ASAN_DYNAMIC_CFLAGS}
+ DEFS ${ASAN_DYNAMIC_DEFINITIONS})
+ endif()
endforeach()
endif()
# Build ASan runtimes shipped with Clang.
-set(ASAN_RUNTIME_LIBRARIES)
+add_custom_target(asan)
if(APPLE)
foreach (os ${SANITIZER_COMMON_SUPPORTED_DARWIN_OS})
- # Dynamic lookup is needed because shadow scale and offset are
- # provided by the instrumented modules.
- set(ASAN_RUNTIME_LDFLAGS
- "-undefined dynamic_lookup")
add_compiler_rt_darwin_dynamic_runtime(clang_rt.asan_${os}_dynamic ${os}
ARCH ${ASAN_SUPPORTED_ARCH}
SOURCES $<TARGET_OBJECTS:RTAsan.${os}>
@@ -92,63 +98,89 @@ if(APPLE)
$<TARGET_OBJECTS:RTSanitizerCommon.${os}>
$<TARGET_OBJECTS:RTLSanCommon.${os}>
CFLAGS ${ASAN_CFLAGS}
- DEFS ${ASAN_COMMON_DEFINITIONS}
- LINKFLAGS ${ASAN_RUNTIME_LDFLAGS})
- list(APPEND ASAN_RUNTIME_LIBRARIES clang_rt.asan_${os}_dynamic)
+ DEFS ${ASAN_COMMON_DEFINITIONS})
+ add_dependencies(asan clang_rt.asan_${os}_dynamic)
endforeach()
-
-elseif(ANDROID)
- add_library(clang_rt.asan-arm-android SHARED
- $<TARGET_OBJECTS:RTAsan.arm.android>
- $<TARGET_OBJECTS:RTInterception.arm.android>
- $<TARGET_OBJECTS:RTSanitizerCommon.arm.android>)
- set_target_compile_flags(clang_rt.asan-arm-android
- ${ASAN_CFLAGS})
- set_property(TARGET clang_rt.asan-arm-android APPEND PROPERTY
- COMPILE_DEFINITIONS ${ASAN_COMMON_DEFINITIONS})
- target_link_libraries(clang_rt.asan-arm-android dl)
- list(APPEND ASAN_RUNTIME_LIBRARIES clang_rt.asan-arm-android)
else()
# Build separate libraries for each target.
foreach(arch ${ASAN_SUPPORTED_ARCH})
- set(ASAN_RUNTIME_OBJECTS
- $<TARGET_OBJECTS:RTAsan.${arch}>
+ set(ASAN_COMMON_RUNTIME_OBJECTS
$<TARGET_OBJECTS:RTInterception.${arch}>
$<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
$<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>)
- if (NOT WIN32)
+ if(NOT WIN32)
# We can't build Leak Sanitizer on Windows yet.
- list(APPEND ASAN_RUNTIME_OBJECTS $<TARGET_OBJECTS:RTLSanCommon.${arch}>)
+ list(APPEND ASAN_COMMON_RUNTIME_OBJECTS
+ $<TARGET_OBJECTS:RTLSanCommon.${arch}>)
endif()
- add_compiler_rt_static_runtime(clang_rt.asan-${arch} ${arch}
- SOURCES ${ASAN_RUNTIME_OBJECTS}
+ add_compiler_rt_runtime(clang_rt.asan-${arch} ${arch} STATIC
+ SOURCES $<TARGET_OBJECTS:RTAsan_preinit.${arch}>
+ $<TARGET_OBJECTS:RTAsan.${arch}>
+ ${ASAN_COMMON_RUNTIME_OBJECTS}
+ CFLAGS ${ASAN_CFLAGS}
+ DEFS ${ASAN_COMMON_DEFINITIONS})
+ add_dependencies(asan clang_rt.asan-${arch})
+
+ add_compiler_rt_runtime(clang_rt.asan_cxx-${arch} ${arch} STATIC
+ SOURCES $<TARGET_OBJECTS:RTAsan_cxx.${arch}>
CFLAGS ${ASAN_CFLAGS}
DEFS ${ASAN_COMMON_DEFINITIONS})
- list(APPEND ASAN_RUNTIME_LIBRARIES clang_rt.asan-${arch})
- if (UNIX AND NOT ${arch} STREQUAL "i386")
+ add_dependencies(asan clang_rt.asan_cxx-${arch})
+
+ if (COMPILER_RT_BUILD_SHARED_ASAN)
+ add_compiler_rt_runtime(clang_rt.asan-preinit-${arch} ${arch} STATIC
+ SOURCES $<TARGET_OBJECTS:RTAsan_preinit.${arch}>
+ CFLAGS ${ASAN_CFLAGS}
+ DEFS ${ASAN_COMMON_DEFINITIONS})
+ add_dependencies(asan clang_rt.asan-preinit-${arch})
+
+ 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}>
+ ${ASAN_COMMON_RUNTIME_OBJECTS}
+ CFLAGS ${ASAN_DYNAMIC_CFLAGS}
+ DEFS ${ASAN_DYNAMIC_DEFINITIONS})
+ target_link_libraries(clang_rt.asan-dynamic-${arch} ${ASAN_DYNAMIC_LIBS})
+ add_dependencies(asan clang_rt.asan-dynamic-${arch})
+ endif()
+
+ if (UNIX AND NOT ${arch} STREQUAL "i386" AND NOT ${arch} STREQUAL "i686")
+ add_sanitizer_rt_symbols(clang_rt.asan_cxx-${arch})
+ add_dependencies(asan clang_rt.asan_cxx-${arch}-symbols)
add_sanitizer_rt_symbols(clang_rt.asan-${arch} asan.syms.extra)
- list(APPEND ASAN_RUNTIME_LIBRARIES clang_rt.asan-${arch}-symbols)
+ add_dependencies(asan clang_rt.asan-${arch}-symbols)
endif()
if (WIN32)
- add_compiler_rt_static_runtime(clang_rt.asan_dll_thunk-${arch} ${arch}
- SOURCES asan_dll_thunk.cc
- CFLAGS ${ASAN_CFLAGS} -DASAN_DLL_THUNK
- DEFS ${ASAN_COMMON_DEFINITIONS})
- list(APPEND ASAN_RUNTIME_LIBRARIES clang_rt.asan_dll_thunk-${arch})
+ add_compiler_rt_runtime(clang_rt.asan_dll_thunk-${arch} ${arch} STATIC
+ 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}
+ STATIC
+ 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})
endif()
endforeach()
endif()
add_compiler_rt_resource_file(asan_blacklist asan_blacklist.txt)
+add_dependencies(asan asan_blacklist)
+add_dependencies(compiler-rt asan)
-# All ASan runtime dependencies.
-add_custom_target(asan_runtime_libraries
- DEPENDS asan_blacklist ${ASAN_RUNTIME_LIBRARIES})
+add_subdirectory(scripts)
-if(LLVM_INCLUDE_TESTS)
+if(COMPILER_RT_INCLUDE_TESTS)
add_subdirectory(tests)
endif()
-
-add_subdirectory(lit_tests)
diff --git a/lib/asan/Makefile.mk b/lib/asan/Makefile.mk
index 97da64bec573..0dafefc2fd8c 100644
--- a/lib/asan/Makefile.mk
+++ b/lib/asan/Makefile.mk
@@ -10,8 +10,12 @@
ModuleName := asan
SubDirs :=
-Sources := $(foreach file,$(wildcard $(Dir)/*.cc),$(notdir $(file)))
-ObjNames := $(Sources:%.cc=%.o)
+CCSources := $(foreach file,$(wildcard $(Dir)/*.cc),$(notdir $(file)))
+CXXOnlySources := asan_new_delete.cc
+COnlySources := $(filter-out $(CXXOnlySources),$(CCSources))
+SSources := $(foreach file,$(wildcard $(Dir)/*.S),$(notdir $(file)))
+Sources := $(CCSources) $(SSources)
+ObjNames := $(CCSources:%.cc=%.o) $(SSources:%.S=%.o)
Implementation := Generic
@@ -21,4 +25,5 @@ Dependencies += $(wildcard $(Dir)/../interception/*.h)
Dependencies += $(wildcard $(Dir)/../sanitizer_common/*.h)
# Define a convenience variable for all the asan functions.
-AsanFunctions := $(Sources:%.cc=%)
+AsanFunctions := $(COnlySources:%.cc=%) $(SSources:%.S=%)
+AsanCXXFunctions := $(CXXOnlySources:%.cc=%)
diff --git a/lib/asan/README.txt b/lib/asan/README.txt
index e4f4961c5d4f..b9c43acd5fe4 100644
--- a/lib/asan/README.txt
+++ b/lib/asan/README.txt
@@ -1,16 +1,15 @@
AddressSanitizer RT
================================
-This directory contains sources of the AddressSanitizer (asan) run-time library.
+This directory contains sources of the AddressSanitizer (asan) runtime library.
We are in the process of integrating AddressSanitizer with LLVM, stay tuned.
-Directory structre:
+Directory structure:
README.txt : This file.
Makefile.mk : File for make-based build.
CMakeLists.txt : File for cmake-based build.
-asan_*.{cc,h} : Sources of the asan run-time lirbary.
+asan_*.{cc,h} : Sources of the asan runtime library.
scripts/* : Helper scripts.
tests/* : ASan unit tests.
-lit_tests/* : ASan output tests.
Also ASan runtime needs the following libraries:
lib/interception/ : Machinery used to intercept function calls.
diff --git a/lib/asan/asan_activation.cc b/lib/asan/asan_activation.cc
new file mode 100644
index 000000000000..eb4a6db0b85e
--- /dev/null
+++ b/lib/asan/asan_activation.cc
@@ -0,0 +1,88 @@
+//===-- asan_activation.cc --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// ASan activation/deactivation logic.
+//===----------------------------------------------------------------------===//
+
+#include "asan_activation.h"
+#include "asan_allocator.h"
+#include "asan_flags.h"
+#include "asan_internal.h"
+#include "sanitizer_common/sanitizer_flags.h"
+
+namespace __asan {
+
+static struct AsanDeactivatedFlags {
+ int quarantine_size;
+ int max_redzone;
+ int malloc_context_size;
+ bool poison_heap;
+ bool alloc_dealloc_mismatch;
+ bool allocator_may_return_null;
+} asan_deactivated_flags;
+
+static bool asan_is_deactivated;
+
+void AsanStartDeactivated() {
+ VReport(1, "Deactivating ASan\n");
+ // Save flag values.
+ asan_deactivated_flags.quarantine_size = flags()->quarantine_size;
+ asan_deactivated_flags.max_redzone = flags()->max_redzone;
+ asan_deactivated_flags.poison_heap = flags()->poison_heap;
+ asan_deactivated_flags.malloc_context_size =
+ common_flags()->malloc_context_size;
+ asan_deactivated_flags.alloc_dealloc_mismatch =
+ flags()->alloc_dealloc_mismatch;
+ asan_deactivated_flags.allocator_may_return_null =
+ common_flags()->allocator_may_return_null;
+
+ flags()->quarantine_size = 0;
+ flags()->max_redzone = 16;
+ flags()->poison_heap = false;
+ common_flags()->malloc_context_size = 0;
+ flags()->alloc_dealloc_mismatch = false;
+ common_flags()->allocator_may_return_null = true;
+
+ asan_is_deactivated = true;
+}
+
+void AsanActivate() {
+ if (!asan_is_deactivated) return;
+ VReport(1, "Activating ASan\n");
+
+ // Restore flag values.
+ // FIXME: this is not atomic, and there may be other threads alive.
+ flags()->quarantine_size = asan_deactivated_flags.quarantine_size;
+ flags()->max_redzone = asan_deactivated_flags.max_redzone;
+ flags()->poison_heap = asan_deactivated_flags.poison_heap;
+ common_flags()->malloc_context_size =
+ asan_deactivated_flags.malloc_context_size;
+ flags()->alloc_dealloc_mismatch =
+ asan_deactivated_flags.alloc_dealloc_mismatch;
+ common_flags()->allocator_may_return_null =
+ asan_deactivated_flags.allocator_may_return_null;
+
+ ParseExtraActivationFlags();
+
+ ReInitializeAllocator();
+
+ asan_is_deactivated = false;
+ VReport(
+ 1,
+ "quarantine_size %d, max_redzone %d, poison_heap %d, "
+ "malloc_context_size %d, alloc_dealloc_mismatch %d, "
+ "allocator_may_return_null %d\n",
+ flags()->quarantine_size, flags()->max_redzone, flags()->poison_heap,
+ common_flags()->malloc_context_size, flags()->alloc_dealloc_mismatch,
+ common_flags()->allocator_may_return_null);
+}
+
+} // namespace __asan
diff --git a/lib/asan/asan_activation.h b/lib/asan/asan_activation.h
new file mode 100644
index 000000000000..dafb840a6042
--- /dev/null
+++ b/lib/asan/asan_activation.h
@@ -0,0 +1,23 @@
+//===-- asan_activation.h ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// ASan activation/deactivation logic.
+//===----------------------------------------------------------------------===//
+
+#ifndef ASAN_ACTIVATION_H
+#define ASAN_ACTIVATION_H
+
+namespace __asan {
+void AsanStartDeactivated();
+void AsanActivate();
+} // namespace __asan
+
+#endif // ASAN_ACTIVATION_H
diff --git a/lib/asan/asan_allocator.h b/lib/asan/asan_allocator.h
index c5fcbbb5d64b..6d3a99282a4a 100644
--- a/lib/asan/asan_allocator.h
+++ b/lib/asan/asan_allocator.h
@@ -17,6 +17,7 @@
#include "asan_internal.h"
#include "asan_interceptors.h"
+#include "sanitizer_common/sanitizer_allocator.h"
#include "sanitizer_common/sanitizer_list.h"
namespace __asan {
@@ -31,6 +32,7 @@ static const uptr kNumberOfSizeClasses = 255;
struct AsanChunk;
void InitializeAllocator();
+void ReInitializeAllocator();
class AsanChunkView {
public:
@@ -42,8 +44,9 @@ class AsanChunkView {
uptr UsedSize(); // Size requested by the user.
uptr AllocTid();
uptr FreeTid();
- void GetAllocStack(StackTrace *stack);
- void GetFreeStack(StackTrace *stack);
+ bool Eq(const AsanChunkView &c) const { return chunk_ == c.chunk_; }
+ StackTrace GetAllocStack();
+ StackTrace GetFreeStack();
bool AddrIsInside(uptr addr, uptr access_size, sptr *offset) {
if (addr >= Beg() && (addr + access_size) <= End()) {
*offset = addr - Beg();
@@ -90,31 +93,66 @@ class AsanChunkFifoList: public IntrusiveList<AsanChunk> {
uptr size_;
};
-struct AsanThreadLocalMallocStorage {
- explicit AsanThreadLocalMallocStorage(LinkerInitialized x)
- { }
- AsanThreadLocalMallocStorage() {
- CHECK(REAL(memset));
- REAL(memset)(this, 0, sizeof(AsanThreadLocalMallocStorage));
- }
+struct AsanMapUnmapCallback {
+ void OnMap(uptr p, uptr size) const;
+ void OnUnmap(uptr p, uptr size) const;
+};
+
+#if SANITIZER_CAN_USE_ALLOCATOR64
+# if defined(__powerpc64__)
+const uptr kAllocatorSpace = 0xa0000000000ULL;
+const uptr kAllocatorSize = 0x20000000000ULL; // 2T.
+# else
+const uptr kAllocatorSpace = 0x600000000000ULL;
+const uptr kAllocatorSize = 0x40000000000ULL; // 4T.
+# endif
+typedef DefaultSizeClassMap SizeClassMap;
+typedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize, 0 /*metadata*/,
+ SizeClassMap, AsanMapUnmapCallback> PrimaryAllocator;
+#else // Fallback to SizeClassAllocator32.
+static const uptr kRegionSizeLog = 20;
+static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog;
+# if SANITIZER_WORDSIZE == 32
+typedef FlatByteMap<kNumRegions> ByteMap;
+# elif SANITIZER_WORDSIZE == 64
+typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap;
+# endif
+typedef CompactSizeClassMap SizeClassMap;
+typedef SizeClassAllocator32<0, SANITIZER_MMAP_RANGE_SIZE, 16,
+ SizeClassMap, kRegionSizeLog,
+ ByteMap,
+ AsanMapUnmapCallback> PrimaryAllocator;
+#endif // SANITIZER_CAN_USE_ALLOCATOR64
+
+typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache;
+typedef LargeMmapAllocator<AsanMapUnmapCallback> SecondaryAllocator;
+typedef CombinedAllocator<PrimaryAllocator, AllocatorCache,
+ SecondaryAllocator> Allocator;
+
+struct AsanThreadLocalMallocStorage {
uptr quarantine_cache[16];
- uptr allocator2_cache[96 * (512 * 8 + 16)]; // Opaque.
+ AllocatorCache allocator2_cache;
void CommitBack();
+ private:
+ // These objects are allocated via mmap() and are zero-initialized.
+ AsanThreadLocalMallocStorage() {}
};
-void *asan_memalign(uptr alignment, uptr size, StackTrace *stack,
+void *asan_memalign(uptr alignment, uptr size, BufferedStackTrace *stack,
AllocType alloc_type);
-void asan_free(void *ptr, StackTrace *stack, AllocType alloc_type);
+void asan_free(void *ptr, BufferedStackTrace *stack, AllocType alloc_type);
+void asan_sized_free(void *ptr, uptr size, BufferedStackTrace *stack,
+ AllocType alloc_type);
-void *asan_malloc(uptr size, StackTrace *stack);
-void *asan_calloc(uptr nmemb, uptr size, StackTrace *stack);
-void *asan_realloc(void *p, uptr size, StackTrace *stack);
-void *asan_valloc(uptr size, StackTrace *stack);
-void *asan_pvalloc(uptr size, StackTrace *stack);
+void *asan_malloc(uptr size, BufferedStackTrace *stack);
+void *asan_calloc(uptr nmemb, uptr size, BufferedStackTrace *stack);
+void *asan_realloc(void *p, uptr size, BufferedStackTrace *stack);
+void *asan_valloc(uptr size, BufferedStackTrace *stack);
+void *asan_pvalloc(uptr size, BufferedStackTrace *stack);
int asan_posix_memalign(void **memptr, uptr alignment, uptr size,
- StackTrace *stack);
+ BufferedStackTrace *stack);
uptr asan_malloc_usable_size(void *ptr, uptr pc, uptr bp);
uptr asan_mz_size(const void *ptr);
diff --git a/lib/asan/asan_allocator2.cc b/lib/asan/asan_allocator2.cc
index 7a29975d711e..52bdcf607f57 100644
--- a/lib/asan/asan_allocator2.cc
+++ b/lib/asan/asan_allocator2.cc
@@ -19,8 +19,9 @@
#include "asan_mapping.h"
#include "asan_poisoning.h"
#include "asan_report.h"
+#include "asan_stack.h"
#include "asan_thread.h"
-#include "sanitizer_common/sanitizer_allocator.h"
+#include "sanitizer_common/sanitizer_allocator_interface.h"
#include "sanitizer_common/sanitizer_flags.h"
#include "sanitizer_common/sanitizer_internal_defs.h"
#include "sanitizer_common/sanitizer_list.h"
@@ -30,65 +31,30 @@
namespace __asan {
-struct AsanMapUnmapCallback {
- void OnMap(uptr p, uptr size) const {
- PoisonShadow(p, size, kAsanHeapLeftRedzoneMagic);
- // Statistics.
- AsanStats &thread_stats = GetCurrentThreadStats();
- thread_stats.mmaps++;
- thread_stats.mmaped += size;
- }
- void OnUnmap(uptr p, uptr size) const {
- PoisonShadow(p, size, 0);
- // We are about to unmap a chunk of user memory.
- // Mark the corresponding shadow memory as not needed.
- // Since asan's mapping is compacting, the shadow chunk may be
- // not page-aligned, so we only flush the page-aligned portion.
- uptr page_size = GetPageSizeCached();
- uptr shadow_beg = RoundUpTo(MemToShadow(p), page_size);
- uptr shadow_end = RoundDownTo(MemToShadow(p + size), page_size);
- FlushUnneededShadowMemory(shadow_beg, shadow_end - shadow_beg);
- // Statistics.
- AsanStats &thread_stats = GetCurrentThreadStats();
- thread_stats.munmaps++;
- thread_stats.munmaped += size;
- }
-};
-
-#if SANITIZER_WORDSIZE == 64
-#if defined(__powerpc64__)
-const uptr kAllocatorSpace = 0xa0000000000ULL;
-const uptr kAllocatorSize = 0x20000000000ULL; // 2T.
-#else
-const uptr kAllocatorSpace = 0x600000000000ULL;
-const uptr kAllocatorSize = 0x40000000000ULL; // 4T.
-#endif
-typedef DefaultSizeClassMap SizeClassMap;
-typedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize, 0 /*metadata*/,
- SizeClassMap, AsanMapUnmapCallback> PrimaryAllocator;
-#elif SANITIZER_WORDSIZE == 32
-static const u64 kAddressSpaceSize = 1ULL << 32;
-typedef CompactSizeClassMap SizeClassMap;
-static const uptr kRegionSizeLog = 20;
-static const uptr kFlatByteMapSize = kAddressSpaceSize >> kRegionSizeLog;
-typedef SizeClassAllocator32<0, kAddressSpaceSize, 16,
- SizeClassMap, kRegionSizeLog,
- FlatByteMap<kFlatByteMapSize>,
- AsanMapUnmapCallback> PrimaryAllocator;
-#endif
-
-typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache;
-typedef LargeMmapAllocator<AsanMapUnmapCallback> SecondaryAllocator;
-typedef CombinedAllocator<PrimaryAllocator, AllocatorCache,
- SecondaryAllocator> Allocator;
+void AsanMapUnmapCallback::OnMap(uptr p, uptr size) const {
+ PoisonShadow(p, size, kAsanHeapLeftRedzoneMagic);
+ // Statistics.
+ AsanStats &thread_stats = GetCurrentThreadStats();
+ thread_stats.mmaps++;
+ thread_stats.mmaped += size;
+}
+void AsanMapUnmapCallback::OnUnmap(uptr p, uptr size) const {
+ PoisonShadow(p, size, 0);
+ // We are about to unmap a chunk of user memory.
+ // Mark the corresponding shadow memory as not needed.
+ FlushUnneededASanShadowMemory(p, size);
+ // Statistics.
+ AsanStats &thread_stats = GetCurrentThreadStats();
+ thread_stats.munmaps++;
+ thread_stats.munmaped += size;
+}
// We can not use THREADLOCAL because it is not supported on some of the
// platforms we care about (OSX 10.6, Android).
// static THREADLOCAL AllocatorCache cache;
AllocatorCache *GetAllocatorCache(AsanThreadLocalMallocStorage *ms) {
CHECK(ms);
- CHECK_LE(sizeof(AllocatorCache), sizeof(ms->allocator2_cache));
- return reinterpret_cast<AllocatorCache *>(ms->allocator2_cache);
+ return &ms->allocator2_cache;
}
static Allocator allocator;
@@ -134,7 +100,8 @@ static uptr ComputeRZLog(uptr user_requested_size) {
user_requested_size <= (1 << 14) - 256 ? 4 :
user_requested_size <= (1 << 15) - 512 ? 5 :
user_requested_size <= (1 << 16) - 1024 ? 6 : 7;
- return Max(rz_log, RZSize2Log(flags()->redzone));
+ return Min(Max(rz_log, RZSize2Log(flags()->redzone)),
+ RZSize2Log(flags()->max_redzone));
}
// The memory chunk allocated from the underlying allocator looks like this:
@@ -201,23 +168,6 @@ struct AsanChunk: ChunkBase {
}
return reinterpret_cast<void*>(Beg() - RZLog2Size(rz_log));
}
- // If we don't use stack depot, we store the alloc/free stack traces
- // in the chunk itself.
- u32 *AllocStackBeg() {
- return (u32*)(Beg() - RZLog2Size(rz_log));
- }
- uptr AllocStackSize() {
- CHECK_LE(RZLog2Size(rz_log), kChunkHeaderSize);
- return (RZLog2Size(rz_log) - kChunkHeaderSize) / sizeof(u32);
- }
- u32 *FreeStackBeg() {
- return (u32*)(Beg() + kChunkHeader2Size);
- }
- uptr FreeStackSize() {
- if (user_requested_size < kChunkHeader2Size) return 0;
- uptr available = RoundUpTo(user_requested_size, SHADOW_GRANULARITY);
- return (available - kChunkHeader2Size) / sizeof(u32);
- }
bool AddrIsInside(uptr addr, bool locked_version = false) {
return (addr >= Beg()) && (addr < Beg() + UsedSize(locked_version));
}
@@ -232,20 +182,19 @@ uptr AsanChunkView::UsedSize() { return chunk_->UsedSize(); }
uptr AsanChunkView::AllocTid() { return chunk_->alloc_tid; }
uptr AsanChunkView::FreeTid() { return chunk_->free_tid; }
-static void GetStackTraceFromId(u32 id, StackTrace *stack) {
+static StackTrace GetStackTraceFromId(u32 id) {
CHECK(id);
- uptr size = 0;
- const uptr *trace = StackDepotGet(id, &size);
- CHECK(trace);
- stack->CopyFrom(trace, size);
+ StackTrace res = StackDepotGet(id);
+ CHECK(res.trace);
+ return res;
}
-void AsanChunkView::GetAllocStack(StackTrace *stack) {
- GetStackTraceFromId(chunk_->alloc_context_id, stack);
+StackTrace AsanChunkView::GetAllocStack() {
+ return GetStackTraceFromId(chunk_->alloc_context_id);
}
-void AsanChunkView::GetFreeStack(StackTrace *stack) {
- GetStackTraceFromId(chunk_->free_context_id, stack);
+StackTrace AsanChunkView::GetFreeStack() {
+ return GetStackTraceFromId(chunk_->free_context_id);
}
struct QuarantineCallback;
@@ -309,10 +258,14 @@ void InitializeAllocator() {
quarantine.Init((uptr)flags()->quarantine_size, kMaxThreadLocalQuarantine);
}
-static void *Allocate(uptr size, uptr alignment, StackTrace *stack,
+void ReInitializeAllocator() {
+ quarantine.Init((uptr)flags()->quarantine_size, kMaxThreadLocalQuarantine);
+}
+
+static void *Allocate(uptr size, uptr alignment, BufferedStackTrace *stack,
AllocType alloc_type, bool can_fill) {
- if (!asan_inited)
- __asan_init();
+ if (UNLIKELY(!asan_inited))
+ AsanInitFromRtl();
Flags &fl = *flags();
CHECK(stack);
const uptr min_alignment = SHADOW_GRANULARITY;
@@ -357,6 +310,16 @@ static void *Allocate(uptr size, uptr alignment, StackTrace *stack,
AllocatorCache *cache = &fallback_allocator_cache;
allocated = allocator.Allocate(cache, needed_size, 8, false);
}
+
+ if (*(u8 *)MEM_TO_SHADOW((uptr)allocated) == 0 && flags()->poison_heap) {
+ // Heap poisoning is enabled, but the allocator provides an unpoisoned
+ // chunk. This is possible if flags()->poison_heap was disabled for some
+ // time, for example, due to flags()->start_disabled.
+ // Anyway, poison the block before using it for anything else.
+ uptr allocated_size = allocator.GetActuallyAllocatedSize(allocated);
+ PoisonShadow((uptr)allocated, allocated_size, kAsanHeapLeftRedzoneMagic);
+ }
+
uptr alloc_beg = reinterpret_cast<uptr>(allocated);
uptr alloc_end = alloc_beg + needed_size;
uptr beg_plus_redzone = alloc_beg + rz_size;
@@ -391,7 +354,7 @@ static void *Allocate(uptr size, uptr alignment, StackTrace *stack,
meta[1] = chunk_beg;
}
- m->alloc_context_id = StackDepotPut(stack->trace, stack->size);
+ m->alloc_context_id = StackDepotPut(*stack);
uptr size_rounded_down_to_granularity = RoundDownTo(size, SHADOW_GRANULARITY);
// Unpoison the bulk of the memory region.
@@ -427,15 +390,16 @@ static void *Allocate(uptr size, uptr alignment, StackTrace *stack,
return res;
}
-static void ReportInvalidFree(void *ptr, u8 chunk_state, StackTrace *stack) {
+static void ReportInvalidFree(void *ptr, u8 chunk_state,
+ BufferedStackTrace *stack) {
if (chunk_state == CHUNK_QUARANTINE)
ReportDoubleFree((uptr)ptr, stack);
else
ReportFreeNotMalloced((uptr)ptr, stack);
}
-static void AtomicallySetQuarantineFlag(AsanChunk *m,
- void *ptr, StackTrace *stack) {
+static void AtomicallySetQuarantineFlag(AsanChunk *m, void *ptr,
+ BufferedStackTrace *stack) {
u8 old_chunk_state = CHUNK_ALLOCATED;
// Flip the chunk_state atomically to avoid race on double-free.
if (!atomic_compare_exchange_strong((atomic_uint8_t*)m, &old_chunk_state,
@@ -446,8 +410,8 @@ static void AtomicallySetQuarantineFlag(AsanChunk *m,
// Expects the chunk to already be marked as quarantined by using
// AtomicallySetQuarantineFlag.
-static void QuarantineChunk(AsanChunk *m, void *ptr,
- StackTrace *stack, AllocType alloc_type) {
+static void QuarantineChunk(AsanChunk *m, void *ptr, BufferedStackTrace *stack,
+ AllocType alloc_type) {
CHECK_EQ(m->chunk_state, CHUNK_QUARANTINE);
if (m->alloc_type != alloc_type && flags()->alloc_dealloc_mismatch)
@@ -459,7 +423,7 @@ static void QuarantineChunk(AsanChunk *m, void *ptr,
CHECK_EQ(m->free_tid, kInvalidTid);
AsanThread *t = GetCurrentThread();
m->free_tid = t ? t->tid() : 0;
- m->free_context_id = StackDepotPut(stack->trace, stack->size);
+ m->free_context_id = StackDepotPut(*stack);
// Poison the region.
PoisonShadow(m->Beg(),
RoundUpTo(m->UsedSize(), SHADOW_GRANULARITY),
@@ -483,19 +447,25 @@ static void QuarantineChunk(AsanChunk *m, void *ptr,
}
}
-static void Deallocate(void *ptr, StackTrace *stack, AllocType alloc_type) {
+static void Deallocate(void *ptr, uptr delete_size, BufferedStackTrace *stack,
+ AllocType alloc_type) {
uptr p = reinterpret_cast<uptr>(ptr);
if (p == 0) return;
uptr chunk_beg = p - kChunkHeaderSize;
AsanChunk *m = reinterpret_cast<AsanChunk *>(chunk_beg);
+ if (delete_size && flags()->new_delete_type_mismatch &&
+ delete_size != m->UsedSize()) {
+ ReportNewDeleteSizeMismatch(p, delete_size, stack);
+ }
ASAN_FREE_HOOK(ptr);
// Must mark the chunk as quarantined before any changes to its metadata.
AtomicallySetQuarantineFlag(m, ptr, stack);
QuarantineChunk(m, ptr, stack, alloc_type);
}
-static void *Reallocate(void *old_ptr, uptr new_size, StackTrace *stack) {
+static void *Reallocate(void *old_ptr, uptr new_size,
+ BufferedStackTrace *stack) {
CHECK(old_ptr && new_size);
uptr p = reinterpret_cast<uptr>(old_ptr);
uptr chunk_beg = p - kChunkHeaderSize;
@@ -515,7 +485,7 @@ static void *Reallocate(void *old_ptr, uptr new_size, StackTrace *stack) {
// If realloc() races with free(), we may start copying freed memory.
// However, we will report racy double-free later anyway.
REAL(memcpy)(new_ptr, old_ptr, memcpy_size);
- Deallocate(old_ptr, stack, FROM_MALLOC);
+ Deallocate(old_ptr, 0, stack, FROM_MALLOC);
}
return new_ptr;
}
@@ -608,20 +578,25 @@ void PrintInternalAllocatorStats() {
allocator.PrintStats();
}
-void *asan_memalign(uptr alignment, uptr size, StackTrace *stack,
+void *asan_memalign(uptr alignment, uptr size, BufferedStackTrace *stack,
AllocType alloc_type) {
return Allocate(size, alignment, stack, alloc_type, true);
}
-void asan_free(void *ptr, StackTrace *stack, AllocType alloc_type) {
- Deallocate(ptr, stack, alloc_type);
+void asan_free(void *ptr, BufferedStackTrace *stack, AllocType alloc_type) {
+ Deallocate(ptr, 0, stack, alloc_type);
}
-void *asan_malloc(uptr size, StackTrace *stack) {
+void asan_sized_free(void *ptr, uptr size, BufferedStackTrace *stack,
+ AllocType alloc_type) {
+ Deallocate(ptr, size, stack, alloc_type);
+}
+
+void *asan_malloc(uptr size, BufferedStackTrace *stack) {
return Allocate(size, 8, stack, FROM_MALLOC, true);
}
-void *asan_calloc(uptr nmemb, uptr size, StackTrace *stack) {
+void *asan_calloc(uptr nmemb, uptr size, BufferedStackTrace *stack) {
if (CallocShouldReturnNullDueToOverflow(size, nmemb))
return AllocatorReturnNull();
void *ptr = Allocate(nmemb * size, 8, stack, FROM_MALLOC, false);
@@ -632,21 +607,21 @@ void *asan_calloc(uptr nmemb, uptr size, StackTrace *stack) {
return ptr;
}
-void *asan_realloc(void *p, uptr size, StackTrace *stack) {
+void *asan_realloc(void *p, uptr size, BufferedStackTrace *stack) {
if (p == 0)
return Allocate(size, 8, stack, FROM_MALLOC, true);
if (size == 0) {
- Deallocate(p, stack, FROM_MALLOC);
+ Deallocate(p, 0, stack, FROM_MALLOC);
return 0;
}
return Reallocate(p, size, stack);
}
-void *asan_valloc(uptr size, StackTrace *stack) {
+void *asan_valloc(uptr size, BufferedStackTrace *stack) {
return Allocate(size, GetPageSizeCached(), stack, FROM_MALLOC, true);
}
-void *asan_pvalloc(uptr size, StackTrace *stack) {
+void *asan_pvalloc(uptr size, BufferedStackTrace *stack) {
uptr PageSize = GetPageSizeCached();
size = RoundUpTo(size, PageSize);
if (size == 0) {
@@ -657,7 +632,7 @@ void *asan_pvalloc(uptr size, StackTrace *stack) {
}
int asan_posix_memalign(void **memptr, uptr alignment, uptr size,
- StackTrace *stack) {
+ BufferedStackTrace *stack) {
void *ptr = Allocate(size, alignment, stack, FROM_MALLOC, true);
CHECK(IsAligned((uptr)ptr, alignment));
*memptr = ptr;
@@ -710,8 +685,12 @@ uptr PointsIntoChunk(void* p) {
__asan::AsanChunk *m = __asan::GetAsanChunkByAddrFastLocked(addr);
if (!m) return 0;
uptr chunk = m->Beg();
- if ((m->chunk_state == __asan::CHUNK_ALLOCATED) &&
- m->AddrIsInside(addr, /*locked_version=*/true))
+ if (m->chunk_state != __asan::CHUNK_ALLOCATED)
+ return 0;
+ if (m->AddrIsInside(addr, /*locked_version=*/true))
+ return chunk;
+ if (IsSpecialCaseOfOperatorNew0(chunk, m->UsedSize(/*locked_version*/ true),
+ addr))
return chunk;
return 0;
}
@@ -776,23 +755,23 @@ using namespace __asan; // NOLINT
// ASan allocator doesn't reserve extra bytes, so normally we would
// just return "size". We don't want to expose our redzone sizes, etc here.
-uptr __asan_get_estimated_allocated_size(uptr size) {
+uptr __sanitizer_get_estimated_allocated_size(uptr size) {
return size;
}
-bool __asan_get_ownership(const void *p) {
+int __sanitizer_get_ownership(const void *p) {
uptr ptr = reinterpret_cast<uptr>(p);
return (AllocationSize(ptr) > 0);
}
-uptr __asan_get_allocated_size(const void *p) {
+uptr __sanitizer_get_allocated_size(const void *p) {
if (p == 0) return 0;
uptr ptr = reinterpret_cast<uptr>(p);
uptr allocated_size = AllocationSize(ptr);
// Die if p is not malloced or if it is already freed.
if (allocated_size == 0) {
GET_STACK_TRACE_FATAL_HERE;
- ReportAsanGetAllocatedSizeNotOwned(ptr, &stack);
+ ReportSanitizerGetAllocatedSizeNotOwned(ptr, &stack);
}
return allocated_size;
}
@@ -801,12 +780,12 @@ uptr __asan_get_allocated_size(const void *p) {
// Provide default (no-op) implementation of malloc hooks.
extern "C" {
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
-void __asan_malloc_hook(void *ptr, uptr size) {
+void __sanitizer_malloc_hook(void *ptr, uptr size) {
(void)ptr;
(void)size;
}
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
-void __asan_free_hook(void *ptr) {
+void __sanitizer_free_hook(void *ptr) {
(void)ptr;
}
} // extern "C"
diff --git a/lib/asan/asan_blacklist.txt b/lib/asan/asan_blacklist.txt
index 63b3c315b26b..c25921fd5fe7 100644
--- a/lib/asan/asan_blacklist.txt
+++ b/lib/asan/asan_blacklist.txt
@@ -8,3 +8,6 @@
# global:*global_with_bad_access_or_initialization*
# global:*global_with_initialization_issues*=init
# type:*Namespace::ClassName*=init
+
+# Stack buffer overflow in VC/INCLUDE/xlocnum, see http://goo.gl/L4qqUG
+fun:*_Find_elem@*@std*
diff --git a/lib/asan/asan_debugging.cc b/lib/asan/asan_debugging.cc
new file mode 100644
index 000000000000..2b66dd5265fc
--- /dev/null
+++ b/lib/asan/asan_debugging.cc
@@ -0,0 +1,141 @@
+//===-- asan_debugging.cc -------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// This file contains various functions that are generally useful to call when
+// using a debugger (LLDB, GDB).
+//===----------------------------------------------------------------------===//
+
+#include "asan_allocator.h"
+#include "asan_flags.h"
+#include "asan_internal.h"
+#include "asan_mapping.h"
+#include "asan_report.h"
+#include "asan_thread.h"
+
+namespace __asan {
+
+void GetInfoForStackVar(uptr addr, AddressDescription *descr, AsanThread *t) {
+ descr->name[0] = 0;
+ descr->region_address = 0;
+ descr->region_size = 0;
+ descr->region_kind = "stack";
+
+ AsanThread::StackFrameAccess access;
+ if (!t->GetStackFrameAccessByAddr(addr, &access))
+ return;
+ InternalMmapVector<StackVarDescr> vars(16);
+ if (!ParseFrameDescription(access.frame_descr, &vars)) {
+ return;
+ }
+
+ for (uptr i = 0; i < vars.size(); i++) {
+ if (access.offset <= vars[i].beg + vars[i].size) {
+ internal_strncat(descr->name, vars[i].name_pos,
+ Min(descr->name_size, vars[i].name_len));
+ descr->region_address = addr - (access.offset - vars[i].beg);
+ descr->region_size = vars[i].size;
+ return;
+ }
+ }
+}
+
+void GetInfoForHeapAddress(uptr addr, AddressDescription *descr) {
+ AsanChunkView chunk = FindHeapChunkByAddress(addr);
+
+ descr->name[0] = 0;
+ descr->region_address = 0;
+ descr->region_size = 0;
+
+ if (!chunk.IsValid()) {
+ descr->region_kind = "heap-invalid";
+ return;
+ }
+
+ descr->region_address = chunk.Beg();
+ descr->region_size = chunk.UsedSize();
+ descr->region_kind = "heap";
+}
+
+void AsanLocateAddress(uptr addr, AddressDescription *descr) {
+ if (DescribeAddressIfShadow(addr, descr, /* print */ false)) {
+ return;
+ }
+ if (GetInfoForAddressIfGlobal(addr, descr)) {
+ return;
+ }
+ asanThreadRegistry().Lock();
+ AsanThread *thread = FindThreadByStackAddress(addr);
+ asanThreadRegistry().Unlock();
+ if (thread) {
+ GetInfoForStackVar(addr, descr, thread);
+ return;
+ }
+ GetInfoForHeapAddress(addr, descr);
+}
+
+uptr AsanGetStack(uptr addr, uptr *trace, uptr size, u32 *thread_id,
+ bool alloc_stack) {
+ AsanChunkView chunk = FindHeapChunkByAddress(addr);
+ if (!chunk.IsValid()) return 0;
+
+ StackTrace stack(nullptr, 0);
+ if (alloc_stack) {
+ if (chunk.AllocTid() == kInvalidTid) return 0;
+ stack = chunk.GetAllocStack();
+ if (thread_id) *thread_id = chunk.AllocTid();
+ } else {
+ if (chunk.FreeTid() == kInvalidTid) return 0;
+ stack = chunk.GetFreeStack();
+ if (thread_id) *thread_id = chunk.FreeTid();
+ }
+
+ if (trace && size) {
+ size = Min(size, Min(stack.size, kStackTraceMax));
+ for (uptr i = 0; i < size; i++)
+ trace[i] = StackTrace::GetPreviousInstructionPc(stack.trace[i]);
+
+ return size;
+ }
+
+ return 0;
+}
+
+} // 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 };
+ AsanLocateAddress(addr, &descr);
+ if (region_address) *region_address = descr.region_address;
+ if (region_size) *region_size = descr.region_size;
+ return descr.region_kind;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+uptr __asan_get_alloc_stack(uptr addr, uptr *trace, uptr size, u32 *thread_id) {
+ return AsanGetStack(addr, trace, size, thread_id, /* alloc_stack */ true);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+uptr __asan_get_free_stack(uptr addr, uptr *trace, uptr size, u32 *thread_id) {
+ return AsanGetStack(addr, trace, size, thread_id, /* alloc_stack */ false);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __asan_get_shadow_mapping(uptr *shadow_scale, uptr *shadow_offset) {
+ if (shadow_scale)
+ *shadow_scale = SHADOW_SCALE;
+ if (shadow_offset)
+ *shadow_offset = SHADOW_OFFSET;
+}
diff --git a/lib/asan/asan_dll_thunk.cc b/lib/asan/asan_dll_thunk.cc
deleted file mode 100644
index cedd60d342f6..000000000000
--- a/lib/asan/asan_dll_thunk.cc
+++ /dev/null
@@ -1,196 +0,0 @@
-//===-- asan_dll_thunk.cc -------------------------------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file is a part of AddressSanitizer, an address sanity checker.
-//
-// This 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.
-//===----------------------------------------------------------------------===//
-
-// Only compile this code when buidling asan_dll_thunk.lib
-// Using #ifdef rather than relying on Makefiles etc.
-// simplifies the build procedure.
-#ifdef ASAN_DLL_THUNK
-
-// ----------------- Helper functions and macros --------------------- {{{1
-extern "C" {
-void *__stdcall GetModuleHandleA(const char *module_name);
-void *__stdcall GetProcAddress(void *module, const char *proc_name);
-void abort();
-}
-
-static void *getRealProcAddressOrDie(const char *name) {
- void *ret = GetProcAddress(GetModuleHandleA(0), name);
- if (!ret)
- abort();
- return ret;
-}
-
-#define WRAP_V_V(name) \
- extern "C" void name() { \
- typedef void (*fntype)(); \
- static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
- fn(); \
- }
-
-#define WRAP_V_W(name) \
- extern "C" void name(void *arg) { \
- typedef void (*fntype)(void *arg); \
- static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
- fn(arg); \
- }
-
-#define WRAP_V_WW(name) \
- extern "C" void name(void *arg1, void *arg2) { \
- typedef void (*fntype)(void *, void *); \
- static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
- fn(arg1, arg2); \
- }
-
-#define WRAP_V_WWW(name) \
- extern "C" void name(void *arg1, void *arg2, void *arg3) { \
- typedef void *(*fntype)(void *, void *, void *); \
- static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
- fn(arg1, arg2, arg3); \
- }
-
-#define WRAP_W_V(name) \
- extern "C" void *name() { \
- typedef void *(*fntype)(); \
- static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
- return fn(); \
- }
-
-#define WRAP_W_W(name) \
- extern "C" void *name(void *arg) { \
- typedef void *(*fntype)(void *arg); \
- static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
- return fn(arg); \
- }
-
-#define WRAP_W_WW(name) \
- extern "C" void *name(void *arg1, void *arg2) { \
- typedef void *(*fntype)(void *, void *); \
- static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
- return fn(arg1, arg2); \
- }
-
-#define WRAP_W_WWW(name) \
- extern "C" void *name(void *arg1, void *arg2, void *arg3) { \
- typedef void *(*fntype)(void *, void *, void *); \
- static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
- return fn(arg1, arg2, arg3); \
- }
-
-#define WRAP_W_WWWW(name) \
- extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4) { \
- typedef void *(*fntype)(void *, void *, void *, void *); \
- static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
- return fn(arg1, arg2, arg3, arg4); \
- }
-
-#define WRAP_W_WWWWW(name) \
- extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4, \
- void *arg5) { \
- typedef void *(*fntype)(void *, void *, void *, void *, void *); \
- static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
- return fn(arg1, arg2, arg3, arg4, arg5); \
- }
-
-#define WRAP_W_WWWWWW(name) \
- extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4, \
- void *arg5, void *arg6) { \
- typedef void *(*fntype)(void *, void *, void *, void *, void *, void *); \
- static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
- return fn(arg1, arg2, arg3, arg4, arg5, arg6); \
- }
-// }}}
-
-// ----------------- ASan own interface functions --------------------
-WRAP_W_V(__asan_should_detect_stack_use_after_return)
-
-extern "C" {
- int __asan_option_detect_stack_use_after_return;
-
- // Manually wrap __asan_init as we need to initialize
- // __asan_option_detect_stack_use_after_return afterwards.
- void __asan_init_v3() {
- typedef void (*fntype)();
- static fntype fn = (fntype)getRealProcAddressOrDie("__asan_init_v3");
- fn();
- __asan_option_detect_stack_use_after_return =
- (__asan_should_detect_stack_use_after_return() != 0);
- }
-}
-
-WRAP_V_W(__asan_report_store1)
-WRAP_V_W(__asan_report_store2)
-WRAP_V_W(__asan_report_store4)
-WRAP_V_W(__asan_report_store8)
-WRAP_V_W(__asan_report_store16)
-WRAP_V_WW(__asan_report_store_n)
-
-WRAP_V_W(__asan_report_load1)
-WRAP_V_W(__asan_report_load2)
-WRAP_V_W(__asan_report_load4)
-WRAP_V_W(__asan_report_load8)
-WRAP_V_W(__asan_report_load16)
-WRAP_V_WW(__asan_report_load_n)
-
-WRAP_V_WW(__asan_register_globals)
-WRAP_V_WW(__asan_unregister_globals)
-
-WRAP_W_WW(__asan_stack_malloc_0)
-WRAP_W_WW(__asan_stack_malloc_1)
-WRAP_W_WW(__asan_stack_malloc_2)
-WRAP_W_WW(__asan_stack_malloc_3)
-WRAP_W_WW(__asan_stack_malloc_4)
-WRAP_W_WW(__asan_stack_malloc_5)
-WRAP_W_WW(__asan_stack_malloc_6)
-WRAP_W_WW(__asan_stack_malloc_7)
-WRAP_W_WW(__asan_stack_malloc_8)
-WRAP_W_WW(__asan_stack_malloc_9)
-WRAP_W_WW(__asan_stack_malloc_10)
-
-WRAP_V_WWW(__asan_stack_free_0)
-WRAP_V_WWW(__asan_stack_free_1)
-WRAP_V_WWW(__asan_stack_free_2)
-WRAP_V_WWW(__asan_stack_free_4)
-WRAP_V_WWW(__asan_stack_free_5)
-WRAP_V_WWW(__asan_stack_free_6)
-WRAP_V_WWW(__asan_stack_free_7)
-WRAP_V_WWW(__asan_stack_free_8)
-WRAP_V_WWW(__asan_stack_free_9)
-WRAP_V_WWW(__asan_stack_free_10)
-
-// TODO(timurrrr): Add more interface functions on the as-needed basis.
-
-// ----------------- Memory allocation functions ---------------------
-WRAP_V_W(free)
-WRAP_V_WW(_free_dbg)
-
-WRAP_W_W(malloc)
-WRAP_W_WWWW(_malloc_dbg)
-
-WRAP_W_WW(calloc)
-WRAP_W_WWWWW(_calloc_dbg)
-WRAP_W_WWW(_calloc_impl)
-
-WRAP_W_WW(realloc)
-WRAP_W_WWW(_realloc_dbg)
-WRAP_W_WWW(_recalloc)
-
-WRAP_W_W(_msize)
-
-// TODO(timurrrr): Do we need to add _Crt* stuff here? (see asan_malloc_win.cc).
-
-#endif // ASAN_DLL_THUNK
diff --git a/lib/asan/asan_fake_stack.cc b/lib/asan/asan_fake_stack.cc
index d3e55bff1e6e..c95bc11f6cd3 100644
--- a/lib/asan/asan_fake_stack.cc
+++ b/lib/asan/asan_fake_stack.cc
@@ -27,8 +27,10 @@ ALWAYS_INLINE void SetShadow(uptr ptr, uptr size, uptr class_id, u64 magic) {
CHECK_EQ(SHADOW_SCALE, 3); // This code expects SHADOW_SCALE=3.
u64 *shadow = reinterpret_cast<u64*>(MemToShadow(ptr));
if (class_id <= 6) {
- for (uptr i = 0; i < (1U << class_id); i++)
+ for (uptr i = 0; i < (1U << class_id); i++) {
shadow[i] = magic;
+ SanitizerBreakOptimization(0); // Make sure this does not become memset.
+ }
} else {
// The size class is too big, it's cheaper to poison only size bytes.
PoisonShadow(ptr, size, static_cast<u8>(magic));
@@ -42,21 +44,32 @@ FakeStack *FakeStack::Create(uptr stack_size_log) {
stack_size_log = kMinStackSizeLog;
if (stack_size_log > kMaxStackSizeLog)
stack_size_log = kMaxStackSizeLog;
+ uptr size = RequiredSize(stack_size_log);
FakeStack *res = reinterpret_cast<FakeStack *>(
- MmapOrDie(RequiredSize(stack_size_log), "FakeStack"));
+ flags()->uar_noreserve ? MmapNoReserveOrDie(size, "FakeStack")
+ : MmapOrDie(size, "FakeStack"));
res->stack_size_log_ = stack_size_log;
- if (common_flags()->verbosity) {
- u8 *p = reinterpret_cast<u8 *>(res);
- Report("T%d: FakeStack created: %p -- %p stack_size_log: %zd \n",
- GetCurrentTidOrInvalid(), p,
- p + FakeStack::RequiredSize(stack_size_log), stack_size_log);
- }
+ u8 *p = reinterpret_cast<u8 *>(res);
+ VReport(1, "T%d: FakeStack created: %p -- %p stack_size_log: %zd; "
+ "mmapped %zdK, noreserve=%d \n",
+ GetCurrentTidOrInvalid(), p,
+ p + FakeStack::RequiredSize(stack_size_log), stack_size_log,
+ size >> 10, flags()->uar_noreserve);
return res;
}
-void FakeStack::Destroy() {
+void FakeStack::Destroy(int tid) {
PoisonAll(0);
- UnmapOrDie(this, RequiredSize(stack_size_log_));
+ if (common_flags()->verbosity >= 2) {
+ InternalScopedString str(kNumberOfSizeClasses * 50);
+ for (uptr class_id = 0; class_id < kNumberOfSizeClasses; class_id++)
+ str.append("%zd: %zd/%zd; ", class_id, hint_position_[class_id],
+ NumberOfFrames(stack_size_log(), class_id));
+ Report("T%d: FakeStack destroyed: %s\n", tid, str.data());
+ }
+ uptr size = RequiredSize(stack_size_log_);
+ FlushUnneededASanShadowMemory(reinterpret_cast<uptr>(this), size);
+ UnmapOrDie(this, size);
}
void FakeStack::PoisonAll(u8 magic) {
@@ -93,7 +106,7 @@ FakeFrame *FakeStack::Allocate(uptr stack_size_log, uptr class_id,
return 0; // We are out of fake stack.
}
-uptr FakeStack::AddrIsInFakeStack(uptr ptr) {
+uptr FakeStack::AddrIsInFakeStack(uptr ptr, uptr *frame_beg, uptr *frame_end) {
uptr stack_size_log = this->stack_size_log();
uptr beg = reinterpret_cast<uptr>(GetFrame(stack_size_log, 0, 0));
uptr end = reinterpret_cast<uptr>(this) + RequiredSize(stack_size_log);
@@ -103,7 +116,10 @@ uptr FakeStack::AddrIsInFakeStack(uptr ptr) {
CHECK_LE(base, ptr);
CHECK_LT(ptr, base + (1UL << stack_size_log));
uptr pos = (ptr - base) >> (kMinStackFrameSizeLog + class_id);
- return base + pos * BytesInSizeClass(class_id);
+ uptr res = base + pos * BytesInSizeClass(class_id);
+ *frame_end = res + BytesInSizeClass(class_id);
+ *frame_beg = res + sizeof(FakeFrame);
+ return res;
}
void FakeStack::HandleNoReturn() {
@@ -197,14 +213,15 @@ ALWAYS_INLINE void OnFree(uptr ptr, uptr class_id, uptr size, uptr real_stack) {
} // namespace __asan
// ---------------------- Interface ---------------- {{{1
+using namespace __asan;
#define DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(class_id) \
extern "C" SANITIZER_INTERFACE_ATTRIBUTE uptr \
__asan_stack_malloc_##class_id(uptr size, uptr real_stack) { \
- return __asan::OnMalloc(class_id, size, real_stack); \
+ return OnMalloc(class_id, size, real_stack); \
} \
extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __asan_stack_free_##class_id( \
uptr ptr, uptr size, uptr real_stack) { \
- __asan::OnFree(ptr, class_id, size, real_stack); \
+ OnFree(ptr, class_id, size, real_stack); \
}
DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(0)
@@ -218,3 +235,23 @@ DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(7)
DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(8)
DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(9)
DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(10)
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE
+void *__asan_get_current_fake_stack() { return GetFakeStackFast(); }
+
+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;
+ 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->magic != kCurrentStackFrameMagic)
+ return 0;
+ if (beg) *beg = reinterpret_cast<void*>(frame_beg);
+ if (end) *end = reinterpret_cast<void*>(frame_end);
+ return reinterpret_cast<void*>(frame->real_stack);
+}
+} // extern "C"
diff --git a/lib/asan/asan_fake_stack.h b/lib/asan/asan_fake_stack.h
index f17ee0268917..3b1d9eb3b57e 100644
--- a/lib/asan/asan_fake_stack.h
+++ b/lib/asan/asan_fake_stack.h
@@ -65,7 +65,7 @@ class FakeStack {
// CTOR: create the FakeStack as a single mmap-ed object.
static FakeStack *Create(uptr stack_size_log);
- void Destroy();
+ void Destroy(int tid);
// stack_size_log is at least 15 (stack_size >= 32K).
static uptr SizeRequiredForFlags(uptr stack_size_log) {
@@ -129,7 +129,11 @@ class FakeStack {
void PoisonAll(u8 magic);
// Return the beginning of the FakeFrame or 0 if the address is not ours.
- uptr AddrIsInFakeStack(uptr addr);
+ uptr AddrIsInFakeStack(uptr addr, uptr *frame_beg, uptr *frame_end);
+ USED uptr AddrIsInFakeStack(uptr addr) {
+ uptr t1, t2;
+ return AddrIsInFakeStack(addr, &t1, &t2);
+ }
// Number of bytes in a fake frame of this size class.
static uptr BytesInSizeClass(uptr class_id) {
diff --git a/lib/asan/asan_flags.h b/lib/asan/asan_flags.h
index 89662f28b29c..3df4dd3050bc 100644
--- a/lib/asan/asan_flags.h
+++ b/lib/asan/asan_flags.h
@@ -28,88 +28,44 @@
namespace __asan {
struct Flags {
- // Size (in bytes) of quarantine used to detect use-after-free errors.
- // Lower value may reduce memory usage but increase the chance of
- // false negatives.
+ // Flag descriptions are in asan_rtl.cc.
int quarantine_size;
- // Size (in bytes) of redzones around heap objects.
- // Requirement: redzone >= 32, is a power of two.
int redzone;
- // If set, prints some debugging information and does additional checks.
+ int max_redzone;
bool debug;
- // Controls the way to handle globals (0 - don't detect buffer overflow
- // on globals, 1 - detect buffer overflow, 2 - print data about registered
- // globals).
int report_globals;
- // If set, attempts to catch initialization order issues.
bool check_initialization_order;
- // If set, uses custom wrappers and replacements for libc string functions
- // to find more errors.
bool replace_str;
- // If set, uses custom wrappers for memset/memcpy/memmove intinsics.
bool replace_intrin;
- // Used on Mac only.
bool mac_ignore_invalid_free;
- // Enables stack-use-after-return checking at run-time.
bool detect_stack_use_after_return;
- // The minimal fake stack size log.
- int uar_stack_size_log;
- // ASan allocator flag. max_malloc_fill_size is the maximal amount of bytes
- // that will be filled with malloc_fill_byte on malloc.
+ int min_uar_stack_size_log;
+ int max_uar_stack_size_log;
+ bool uar_noreserve;
int max_malloc_fill_size, malloc_fill_byte;
- // Override exit status if something was reported.
int exitcode;
- // If set, user may manually mark memory regions as poisoned or unpoisoned.
bool allow_user_poisoning;
- // Number of seconds to sleep between printing an error report and
- // terminating application. Useful for debug purposes (when one needs
- // to attach gdb, for example).
int sleep_before_dying;
- // If set, registers ASan custom segv handler.
- bool handle_segv;
- // If set, allows user register segv handler even if ASan registers one.
- bool allow_user_segv_handler;
- // If set, uses alternate stack for signal handling.
- bool use_sigaltstack;
- // Allow the users to work around the bug in Nvidia drivers prior to 295.*.
bool check_malloc_usable_size;
- // If set, explicitly unmaps (huge) shadow at exit.
bool unmap_shadow_on_exit;
- // If set, calls abort() instead of _exit() after printing an error report.
bool abort_on_error;
- // Print various statistics after printing an error message or if atexit=1.
bool print_stats;
- // Print the legend for the shadow bytes.
bool print_legend;
- // If set, prints ASan exit stats even after program terminates successfully.
bool atexit;
- // If set, coverage information will be dumped at shutdown time if the
- // appropriate instrumentation was enabled.
- bool coverage;
- // By default, disable core dumper on 64-bit - it makes little sense
- // to dump 16T+ core.
- bool disable_core;
- // Allow the tool to re-exec the program. This may interfere badly with the
- // debugger.
bool allow_reexec;
- // If set, prints not only thread creation stacks for threads in error report,
- // but also thread creation stacks for threads that created those threads,
- // etc. up to main thread.
bool print_full_thread_history;
- // Poison (or not) the heap memory on [de]allocation. Zero value is useful
- // for benchmarking the allocator or instrumentator.
bool poison_heap;
- // If true, poison partially addressable 8-byte aligned words (default=true).
- // This flag affects heap and global buffers, but not stack buffers.
bool poison_partial;
- // Report errors on malloc/delete, new/free, new/delete[], etc.
+ bool poison_array_cookie;
bool alloc_dealloc_mismatch;
- // If true, assume that memcmp(p1, p2, n) always reads n bytes before
- // comparing p1 and p2.
+ bool new_delete_type_mismatch;
bool strict_memcmp;
- // If true, assume that dynamic initializers can never access globals from
- // other modules, even if the latter are already initialized.
bool strict_init_order;
+ bool start_deactivated;
+ int detect_invalid_pointer_pairs;
+ bool detect_container_overflow;
+ int detect_odr_violation;
+ bool dump_instruction_bytes;
};
extern Flags asan_flags_dont_use_directly;
diff --git a/lib/asan/asan_globals.cc b/lib/asan/asan_globals.cc
index 81699676b574..be111d4fb4cf 100644
--- a/lib/asan/asan_globals.cc
+++ b/lib/asan/asan_globals.cc
@@ -22,6 +22,7 @@
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_mutex.h"
#include "sanitizer_common/sanitizer_placement_new.h"
+#include "sanitizer_common/sanitizer_stackdepot.h"
namespace __asan {
@@ -45,6 +46,14 @@ typedef InternalMmapVector<DynInitGlobal> VectorOfGlobals;
// Lazy-initialized and never deleted.
static VectorOfGlobals *dynamic_init_globals;
+// We want to remember where a certain range of globals was registered.
+struct GlobalRegistrationSite {
+ u32 stack_id;
+ Global *g_first, *g_last;
+};
+typedef InternalMmapVector<GlobalRegistrationSite> GlobalRegistrationSiteVector;
+static GlobalRegistrationSiteVector *global_registration_site_vector;
+
ALWAYS_INLINE void PoisonShadowForGlobal(const Global *g, u8 value) {
FastPoisonShadow(g->beg, g->size_with_redzone, value);
}
@@ -62,25 +71,74 @@ ALWAYS_INLINE void PoisonRedZones(const Global &g) {
}
}
+const uptr kMinimalDistanceFromAnotherGlobal = 64;
+
+bool IsAddressNearGlobal(uptr addr, const __asan_global &g) {
+ if (addr <= g.beg - kMinimalDistanceFromAnotherGlobal) return false;
+ if (addr >= g.beg + g.size_with_redzone) return false;
+ return true;
+}
+
static void ReportGlobal(const Global &g, const char *prefix) {
- Report("%s Global: beg=%p size=%zu/%zu name=%s module=%s dyn_init=%zu\n",
- prefix, (void*)g.beg, g.size, g.size_with_redzone, g.name,
+ Report("%s Global[%p]: beg=%p size=%zu/%zu name=%s module=%s dyn_init=%zu\n",
+ prefix, &g, (void *)g.beg, g.size, g.size_with_redzone, g.name,
g.module_name, g.has_dynamic_init);
+ if (g.location) {
+ Report(" location (%p): name=%s[%p], %d %d\n", g.location,
+ g.location->filename, g.location->filename, g.location->line_no,
+ g.location->column_no);
+ }
}
-bool DescribeAddressIfGlobal(uptr addr, uptr size) {
+static bool DescribeOrGetInfoIfGlobal(uptr addr, uptr size, bool print,
+ Global *output_global) {
if (!flags()->report_globals) return false;
BlockingMutexLock lock(&mu_for_globals);
bool res = false;
for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) {
const Global &g = *l->g;
- if (flags()->report_globals >= 2)
- ReportGlobal(g, "Search");
- res |= DescribeAddressRelativeToGlobal(addr, size, g);
+ if (print) {
+ if (flags()->report_globals >= 2)
+ ReportGlobal(g, "Search");
+ res |= DescribeAddressRelativeToGlobal(addr, size, g);
+ } else {
+ if (IsAddressNearGlobal(addr, g)) {
+ CHECK(output_global);
+ *output_global = g;
+ return true;
+ }
+ }
}
return res;
}
+bool DescribeAddressIfGlobal(uptr addr, uptr size) {
+ return DescribeOrGetInfoIfGlobal(addr, size, /* print */ true,
+ /* output_global */ nullptr);
+}
+
+bool GetInfoForAddressIfGlobal(uptr addr, AddressDescription *descr) {
+ Global g = {};
+ if (DescribeOrGetInfoIfGlobal(addr, /* size */ 1, /* print */ false, &g)) {
+ internal_strncpy(descr->name, g.name, descr->name_size);
+ descr->region_address = g.beg;
+ descr->region_size = g.size;
+ descr->region_kind = "global";
+ return true;
+ }
+ return false;
+}
+
+u32 FindRegistrationSite(const Global *g) {
+ CHECK(global_registration_site_vector);
+ for (uptr i = 0, n = global_registration_site_vector->size(); i < n; i++) {
+ GlobalRegistrationSite &grs = (*global_registration_site_vector)[i];
+ if (g >= grs.g_first && g <= grs.g_last)
+ return grs.stack_id;
+ }
+ return 0;
+}
+
// Register a global variable.
// This function may be called more than once for every global
// so we store the globals in a map.
@@ -92,6 +150,20 @@ static void RegisterGlobal(const Global *g) {
CHECK(AddrIsInMem(g->beg));
CHECK(AddrIsAlignedByGranularity(g->beg));
CHECK(AddrIsAlignedByGranularity(g->size_with_redzone));
+ if (flags()->detect_odr_violation) {
+ // Try detecting ODR (One Definition Rule) violation, i.e. the situation
+ // where two globals with the same name are defined in different modules.
+ if (__asan_region_is_poisoned(g->beg, g->size_with_redzone)) {
+ // This check may not be enough: if the first global is much larger
+ // the entire redzone of the second global may be within the first global.
+ for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) {
+ if (g->beg == l->g->beg &&
+ (flags()->detect_odr_violation >= 2 || g->size != l->g->size))
+ ReportODRViolation(g, FindRegistrationSite(g),
+ l->g, FindRegistrationSite(l->g));
+ }
+ }
+ }
if (flags()->poison_heap)
PoisonRedZones(*g);
ListOfGlobals *l = new(allocator_for_globals) ListOfGlobals;
@@ -144,7 +216,18 @@ using namespace __asan; // NOLINT
// Register an array of globals.
void __asan_register_globals(__asan_global *globals, uptr n) {
if (!flags()->report_globals) return;
+ GET_STACK_TRACE_FATAL_HERE;
+ u32 stack_id = StackDepotPut(stack);
BlockingMutexLock lock(&mu_for_globals);
+ if (!global_registration_site_vector)
+ global_registration_site_vector =
+ new(allocator_for_globals) GlobalRegistrationSiteVector(128);
+ GlobalRegistrationSite site = {stack_id, &globals[0], &globals[n - 1]};
+ global_registration_site_vector->push_back(site);
+ if (flags()->report_globals >= 2) {
+ PRINT_CURRENT_STACK();
+ Printf("=== ID %d; %p %p\n", stack_id, &globals[0], &globals[n - 1]);
+ }
for (uptr i = 0; i < n; i++) {
RegisterGlobal(&globals[i]);
}
diff --git a/lib/asan/asan_init_version.h b/lib/asan/asan_init_version.h
new file mode 100644
index 000000000000..77aea81bd298
--- /dev/null
+++ b/lib/asan/asan_init_version.h
@@ -0,0 +1,32 @@
+//===-- asan_init_version.h -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// This header defines a versioned __asan_init function to be called at the
+// startup of the instrumented program.
+//===----------------------------------------------------------------------===//
+#ifndef ASAN_INIT_VERSION_H
+#define ASAN_INIT_VERSION_H
+
+extern "C" {
+ // Every time the ASan ABI changes we also change the version number in the
+ // __asan_init function name. Objects built with incompatible ASan ABI
+ // versions will not link with run-time.
+ // Changes between ABI versions:
+ // v1=>v2: added 'module_name' to __asan_global
+ // v2=>v3: stack frame description (created by the compiler)
+ // contains the function PC as the 3-rd field (see
+ // DescribeAddressIfStack).
+ // v3=>v4: added '__asan_global_source_location' to __asan_global.
+ #define __asan_init __asan_init_v4
+ #define __asan_init_name "__asan_init_v4"
+}
+
+#endif // ASAN_INIT_VERSION_H
diff --git a/lib/asan/asan_intercepted_functions.h b/lib/asan/asan_intercepted_functions.h
deleted file mode 100644
index de42cd6d5ca6..000000000000
--- a/lib/asan/asan_intercepted_functions.h
+++ /dev/null
@@ -1,79 +0,0 @@
-//===-- asan_intercepted_functions.h ----------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file is a part of AddressSanitizer, an address sanity checker.
-//
-// ASan-private header containing prototypes for wrapper functions and wrappers
-//===----------------------------------------------------------------------===//
-#ifndef ASAN_INTERCEPTED_FUNCTIONS_H
-#define ASAN_INTERCEPTED_FUNCTIONS_H
-
-#include "sanitizer_common/sanitizer_platform_interceptors.h"
-
-// Use macro to describe if specific function should be
-// intercepted on a given platform.
-#if !SANITIZER_WINDOWS
-# define ASAN_INTERCEPT_ATOLL_AND_STRTOLL 1
-# define ASAN_INTERCEPT__LONGJMP 1
-# define ASAN_INTERCEPT_STRDUP 1
-# define ASAN_INTERCEPT_INDEX 1
-# define ASAN_INTERCEPT_PTHREAD_CREATE 1
-# define ASAN_INTERCEPT_MLOCKX 1
-#else
-# define ASAN_INTERCEPT_ATOLL_AND_STRTOLL 0
-# define ASAN_INTERCEPT__LONGJMP 0
-# define ASAN_INTERCEPT_STRDUP 0
-# define ASAN_INTERCEPT_INDEX 0
-# define ASAN_INTERCEPT_PTHREAD_CREATE 0
-# define ASAN_INTERCEPT_MLOCKX 0
-#endif
-
-#if SANITIZER_LINUX
-# define ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX 1
-#else
-# define ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX 0
-#endif
-
-#if !SANITIZER_MAC
-# define ASAN_INTERCEPT_STRNLEN 1
-#else
-# define ASAN_INTERCEPT_STRNLEN 0
-#endif
-
-#if SANITIZER_LINUX && !SANITIZER_ANDROID
-# define ASAN_INTERCEPT_SWAPCONTEXT 1
-#else
-# define ASAN_INTERCEPT_SWAPCONTEXT 0
-#endif
-
-#if !SANITIZER_ANDROID && !SANITIZER_WINDOWS
-# define ASAN_INTERCEPT_SIGNAL_AND_SIGACTION 1
-#else
-# define ASAN_INTERCEPT_SIGNAL_AND_SIGACTION 0
-#endif
-
-#if !SANITIZER_WINDOWS
-# define ASAN_INTERCEPT_SIGLONGJMP 1
-#else
-# define ASAN_INTERCEPT_SIGLONGJMP 0
-#endif
-
-#if ASAN_HAS_EXCEPTIONS && !SANITIZER_WINDOWS
-# define ASAN_INTERCEPT___CXA_THROW 1
-#else
-# define ASAN_INTERCEPT___CXA_THROW 0
-#endif
-
-#if !SANITIZER_WINDOWS
-# define ASAN_INTERCEPT___CXA_ATEXIT 1
-#else
-# define ASAN_INTERCEPT___CXA_ATEXIT 0
-#endif
-
-#endif // ASAN_INTERCEPTED_FUNCTIONS_H
diff --git a/lib/asan/asan_interceptors.cc b/lib/asan/asan_interceptors.cc
index a25827b6b9ae..910cd3addcb0 100644
--- a/lib/asan/asan_interceptors.cc
+++ b/lib/asan/asan_interceptors.cc
@@ -14,14 +14,13 @@
#include "asan_interceptors.h"
#include "asan_allocator.h"
-#include "asan_intercepted_functions.h"
#include "asan_internal.h"
#include "asan_mapping.h"
#include "asan_poisoning.h"
#include "asan_report.h"
#include "asan_stack.h"
#include "asan_stats.h"
-#include "interception/interception.h"
+#include "asan_suppressions.h"
#include "sanitizer_common/sanitizer_libc.h"
namespace __asan {
@@ -36,24 +35,45 @@ static inline bool QuickCheckForUnpoisonedRegion(uptr beg, uptr size) {
return false;
}
+struct AsanInterceptorContext {
+ const char *interceptor_name;
+};
+
// We implement ACCESS_MEMORY_RANGE, ASAN_READ_RANGE,
// and ASAN_WRITE_RANGE as macro instead of function so
// that no extra frames are created, and stack trace contains
// relevant information only.
// We check all shadow bytes.
-#define ACCESS_MEMORY_RANGE(offset, size, isWrite) do { \
+#define ACCESS_MEMORY_RANGE(ctx, offset, size, isWrite) do { \
uptr __offset = (uptr)(offset); \
uptr __size = (uptr)(size); \
uptr __bad = 0; \
+ if (__offset > __offset + __size) { \
+ GET_STACK_TRACE_FATAL_HERE; \
+ ReportStringFunctionSizeOverflow(__offset, __size, &stack); \
+ } \
if (!QuickCheckForUnpoisonedRegion(__offset, __size) && \
(__bad = __asan_region_is_poisoned(__offset, __size))) { \
- GET_CURRENT_PC_BP_SP; \
- __asan_report_error(pc, bp, sp, __bad, isWrite, __size); \
+ AsanInterceptorContext *_ctx = (AsanInterceptorContext *)ctx; \
+ bool suppressed = false; \
+ if (_ctx) { \
+ suppressed = IsInterceptorSuppressed(_ctx->interceptor_name); \
+ if (!suppressed && HaveStackTraceBasedSuppressions()) { \
+ GET_STACK_TRACE_FATAL_HERE; \
+ suppressed = IsStackTraceSuppressed(&stack); \
+ } \
+ } \
+ if (!suppressed) { \
+ GET_CURRENT_PC_BP_SP; \
+ __asan_report_error(pc, bp, sp, __bad, isWrite, __size); \
+ } \
} \
} while (0)
-#define ASAN_READ_RANGE(offset, size) ACCESS_MEMORY_RANGE(offset, size, false)
-#define ASAN_WRITE_RANGE(offset, size) ACCESS_MEMORY_RANGE(offset, size, true)
+#define ASAN_READ_RANGE(ctx, offset, size) \
+ ACCESS_MEMORY_RANGE(ctx, offset, size, false)
+#define ASAN_WRITE_RANGE(ctx, offset, size) \
+ ACCESS_MEMORY_RANGE(ctx, offset, size, true)
// Behavior of functions like "memcpy" or "strcpy" is undefined
// if memory intervals overlap. We report error in this case.
@@ -72,13 +92,6 @@ static inline bool RangesOverlap(const char *offset1, uptr length1,
} \
} while (0)
-#define ENSURE_ASAN_INITED() do { \
- CHECK(!asan_init_is_running); \
- if (!asan_inited) { \
- __asan_init(); \
- } \
-} while (0)
-
static inline uptr MaybeRealStrnlen(const char *s, uptr maxlen) {
#if ASAN_INTERCEPT_STRNLEN
if (REAL(strnlen) != 0) {
@@ -108,31 +121,34 @@ DECLARE_REAL_AND_INTERCEPTOR(void *, malloc, uptr)
DECLARE_REAL_AND_INTERCEPTOR(void, free, void *)
#if !SANITIZER_MAC
-#define ASAN_INTERCEPT_FUNC(name) \
- do { \
- if ((!INTERCEPT_FUNCTION(name) || !REAL(name)) && \
- common_flags()->verbosity > 0) \
- Report("AddressSanitizer: failed to intercept '" #name "'\n"); \
+#define ASAN_INTERCEPT_FUNC(name) \
+ do { \
+ if ((!INTERCEPT_FUNCTION(name) || !REAL(name))) \
+ VReport(1, "AddressSanitizer: failed to intercept '" #name "'\n"); \
} while (0)
#else
// OS X interceptors don't need to be initialized with INTERCEPT_FUNCTION.
#define ASAN_INTERCEPT_FUNC(name)
#endif // SANITIZER_MAC
+#define ASAN_INTERCEPTOR_ENTER(ctx, func) \
+ AsanInterceptorContext _ctx = {#func}; \
+ ctx = (void *)&_ctx; \
+ (void) ctx; \
+
#define COMMON_INTERCEPT_FUNCTION(name) ASAN_INTERCEPT_FUNC(name)
-#define COMMON_INTERCEPTOR_UNPOISON_PARAM(ctx, count) \
- do { \
- } while (false)
#define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \
- ASAN_WRITE_RANGE(ptr, size)
-#define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) ASAN_READ_RANGE(ptr, size)
-#define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \
- do { \
- if (asan_init_is_running) return REAL(func)(__VA_ARGS__); \
- ctx = 0; \
- (void) ctx; \
- if (SANITIZER_MAC && !asan_inited) return REAL(func)(__VA_ARGS__); \
- ENSURE_ASAN_INITED(); \
+ ASAN_WRITE_RANGE(ctx, ptr, size)
+#define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) \
+ ASAN_READ_RANGE(ctx, ptr, size)
+#define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \
+ do { \
+ if (asan_init_is_running) \
+ return REAL(func)(__VA_ARGS__); \
+ ASAN_INTERCEPTOR_ENTER(ctx, func); \
+ if (SANITIZER_MAC && UNLIKELY(!asan_inited)) \
+ return REAL(func)(__VA_ARGS__); \
+ ENSURE_ASAN_INITED(); \
} while (false)
#define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd) \
do { \
@@ -153,10 +169,15 @@ DECLARE_REAL_AND_INTERCEPTOR(void, free, void *)
} while (false)
#define COMMON_INTERCEPTOR_BLOCK_REAL(name) REAL(name)
#define COMMON_INTERCEPTOR_ON_EXIT(ctx) OnExit()
+#define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, res) CovUpdateMapping()
+#define COMMON_INTERCEPTOR_LIBRARY_UNLOADED() CovUpdateMapping()
+#define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED (!asan_inited)
#include "sanitizer_common/sanitizer_common_interceptors.inc"
-#define COMMON_SYSCALL_PRE_READ_RANGE(p, s) ASAN_READ_RANGE(p, s)
-#define COMMON_SYSCALL_PRE_WRITE_RANGE(p, s) ASAN_WRITE_RANGE(p, s)
+// Syscall interceptors don't have contexts, we don't support suppressions
+// for them.
+#define COMMON_SYSCALL_PRE_READ_RANGE(p, s) ASAN_READ_RANGE(nullptr, p, s)
+#define COMMON_SYSCALL_PRE_WRITE_RANGE(p, s) ASAN_WRITE_RANGE(nullptr, p, s)
#define COMMON_SYSCALL_POST_READ_RANGE(p, s) \
do { \
(void)(p); \
@@ -169,47 +190,90 @@ DECLARE_REAL_AND_INTERCEPTOR(void, free, void *)
} while (false)
#include "sanitizer_common/sanitizer_common_syscalls.inc"
+struct ThreadStartParam {
+ atomic_uintptr_t t;
+ atomic_uintptr_t is_registered;
+};
+
static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) {
- AsanThread *t = (AsanThread*)arg;
+ ThreadStartParam *param = reinterpret_cast<ThreadStartParam *>(arg);
+ AsanThread *t = nullptr;
+ while ((t = reinterpret_cast<AsanThread *>(
+ atomic_load(&param->t, memory_order_acquire))) == 0)
+ internal_sched_yield();
SetCurrentThread(t);
- return t->ThreadStart(GetTid());
+ return t->ThreadStart(GetTid(), &param->is_registered);
}
#if ASAN_INTERCEPT_PTHREAD_CREATE
INTERCEPTOR(int, pthread_create, void *thread,
void *attr, void *(*start_routine)(void*), void *arg) {
EnsureMainThreadIDIsCorrect();
- // Strict init-order checking in thread-hostile.
+ // Strict init-order checking is thread-hostile.
if (flags()->strict_init_order)
StopInitOrderChecking();
GET_STACK_TRACE_THREAD;
int detached = 0;
if (attr != 0)
REAL(pthread_attr_getdetachstate)(attr, &detached);
-
- u32 current_tid = GetCurrentTidOrInvalid();
- AsanThread *t = AsanThread::Create(start_routine, arg);
- CreateThreadContextArgs args = { t, &stack };
- asanThreadRegistry().CreateThread(*(uptr*)t, detached, current_tid, &args);
- return REAL(pthread_create)(thread, attr, asan_thread_start, t);
+ ThreadStartParam param;
+ atomic_store(&param.t, 0, memory_order_relaxed);
+ atomic_store(&param.is_registered, 0, memory_order_relaxed);
+ int result = REAL(pthread_create)(thread, attr, asan_thread_start, &param);
+ if (result == 0) {
+ u32 current_tid = GetCurrentTidOrInvalid();
+ AsanThread *t =
+ AsanThread::Create(start_routine, arg, current_tid, &stack, detached);
+ atomic_store(&param.t, reinterpret_cast<uptr>(t), memory_order_release);
+ // Wait until the AsanThread object is initialized and the ThreadRegistry
+ // entry is in "started" state. One reason for this is that after this
+ // interceptor exits, the child thread's stack may be the only thing holding
+ // the |arg| pointer. This may cause LSan to report a leak if leak checking
+ // happens at a point when the interceptor has already exited, but the stack
+ // range for the child thread is not yet known.
+ while (atomic_load(&param.is_registered, memory_order_acquire) == 0)
+ internal_sched_yield();
+ }
+ return result;
}
#endif // ASAN_INTERCEPT_PTHREAD_CREATE
#if ASAN_INTERCEPT_SIGNAL_AND_SIGACTION
+
+#if SANITIZER_ANDROID
+INTERCEPTOR(void*, bsd_signal, int signum, void *handler) {
+ if (!AsanInterceptsSignal(signum) ||
+ common_flags()->allow_user_segv_handler) {
+ return REAL(bsd_signal)(signum, handler);
+ }
+ return 0;
+}
+#else
INTERCEPTOR(void*, signal, int signum, void *handler) {
- if (!AsanInterceptsSignal(signum) || flags()->allow_user_segv_handler) {
+ if (!AsanInterceptsSignal(signum) ||
+ common_flags()->allow_user_segv_handler) {
return REAL(signal)(signum, handler);
}
return 0;
}
+#endif
INTERCEPTOR(int, sigaction, int signum, const struct sigaction *act,
struct sigaction *oldact) {
- if (!AsanInterceptsSignal(signum) || flags()->allow_user_segv_handler) {
+ if (!AsanInterceptsSignal(signum) ||
+ common_flags()->allow_user_segv_handler) {
return REAL(sigaction)(signum, act, oldact);
}
return 0;
}
+
+namespace __sanitizer {
+int real_sigaction(int signum, const void *act, void *oldact) {
+ return REAL(sigaction)(signum, (const struct sigaction *)act,
+ (struct sigaction *)oldact);
+}
+} // namespace __sanitizer
+
#elif SANITIZER_POSIX
// We need to have defined REAL(sigaction) on posix systems.
DEFINE_REAL(int, sigaction, int signum, const struct sigaction *act,
@@ -279,52 +343,45 @@ INTERCEPTOR(void, __cxa_throw, void *a, void *b, void *c) {
}
#endif
-// intercept mlock and friends.
-// Since asan maps 16T of RAM, mlock is completely unfriendly to asan.
-// All functions return 0 (success).
-static void MlockIsUnsupported() {
- static bool printed = false;
- if (printed) return;
- printed = true;
- if (common_flags()->verbosity > 0) {
- Printf("INFO: AddressSanitizer ignores "
- "mlock/mlockall/munlock/munlockall\n");
- }
-}
-
-INTERCEPTOR(int, mlock, const void *addr, uptr len) {
- MlockIsUnsupported();
- return 0;
-}
-
-INTERCEPTOR(int, munlock, const void *addr, uptr len) {
- MlockIsUnsupported();
- return 0;
+#if SANITIZER_WINDOWS
+INTERCEPTOR_WINAPI(void, RaiseException, void *a, void *b, void *c, void *d) {
+ CHECK(REAL(RaiseException));
+ __asan_handle_no_return();
+ REAL(RaiseException)(a, b, c, d);
}
-INTERCEPTOR(int, mlockall, int flags) {
- MlockIsUnsupported();
- return 0;
+INTERCEPTOR(int, _except_handler3, void *a, void *b, void *c, void *d) {
+ CHECK(REAL(_except_handler3));
+ __asan_handle_no_return();
+ return REAL(_except_handler3)(a, b, c, d);
}
-INTERCEPTOR(int, munlockall, void) {
- MlockIsUnsupported();
- return 0;
+#if ASAN_DYNAMIC
+// This handler is named differently in -MT and -MD CRTs.
+#define _except_handler4 _except_handler4_common
+#endif
+INTERCEPTOR(int, _except_handler4, void *a, void *b, void *c, void *d) {
+ CHECK(REAL(_except_handler4));
+ __asan_handle_no_return();
+ return REAL(_except_handler4)(a, b, c, d);
}
+#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) {
- if (!asan_inited) return internal_memcmp(a1, a2, 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(a1, size);
- ASAN_READ_RANGE(a2, size);
+ ASAN_READ_RANGE(ctx, a1, size);
+ ASAN_READ_RANGE(ctx, a2, size);
// Fallthrough to REAL(memcmp) below.
} else {
unsigned char c1 = 0, c2 = 0;
@@ -336,51 +393,81 @@ INTERCEPTOR(int, memcmp, const void *a1, const void *a2, uptr size) {
c2 = s2[i];
if (c1 != c2) break;
}
- ASAN_READ_RANGE(s1, Min(i + 1, size));
- ASAN_READ_RANGE(s2, Min(i + 1, size));
+ 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));
}
-#define MEMMOVE_BODY { \
- if (!asan_inited) return internal_memmove(to, from, size); \
- if (asan_init_is_running) { \
- return REAL(memmove)(to, from, size); \
- } \
- ENSURE_ASAN_INITED(); \
- if (flags()->replace_intrin) { \
- ASAN_READ_RANGE(from, size); \
- ASAN_WRITE_RANGE(to, size); \
- } \
- return internal_memmove(to, from, 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.
+#define ASAN_MEMCPY_IMPL(ctx, to, from, size) do { \
+ if (UNLIKELY(!asan_inited)) return internal_memcpy(to, from, size); \
+ if (asan_init_is_running) { \
+ return REAL(memcpy)(to, from, size); \
+ } \
+ ENSURE_ASAN_INITED(); \
+ if (flags()->replace_intrin) { \
+ if (to != from) { \
+ CHECK_RANGES_OVERLAP("memcpy", to, size, from, size); \
+ } \
+ ASAN_READ_RANGE(ctx, from, size); \
+ ASAN_WRITE_RANGE(ctx, to, size); \
+ } \
+ return REAL(memcpy)(to, from, size); \
+ } while (0)
+
+
+void *__asan_memcpy(void *to, const void *from, uptr size) {
+ ASAN_MEMCPY_IMPL(nullptr, to, from, size);
+}
+
+// memset is called inside Printf.
+#define ASAN_MEMSET_IMPL(ctx, block, c, size) do { \
+ if (UNLIKELY(!asan_inited)) return internal_memset(block, c, size); \
+ if (asan_init_is_running) { \
+ return REAL(memset)(block, c, size); \
+ } \
+ ENSURE_ASAN_INITED(); \
+ if (flags()->replace_intrin) { \
+ ASAN_WRITE_RANGE(ctx, block, size); \
+ } \
+ return REAL(memset)(block, c, size); \
+ } while (0)
+
+void *__asan_memset(void *block, int c, uptr size) {
+ ASAN_MEMSET_IMPL(nullptr, block, c, size);
+}
+
+#define ASAN_MEMMOVE_IMPL(ctx, to, from, size) do { \
+ if (UNLIKELY(!asan_inited)) \
+ return internal_memmove(to, from, size); \
+ ENSURE_ASAN_INITED(); \
+ if (flags()->replace_intrin) { \
+ ASAN_READ_RANGE(ctx, from, size); \
+ ASAN_WRITE_RANGE(ctx, to, size); \
+ } \
+ return internal_memmove(to, from, size); \
+ } while (0)
+
+void *__asan_memmove(void *to, const void *from, uptr size) {
+ ASAN_MEMMOVE_IMPL(nullptr, to, from, size);
}
-INTERCEPTOR(void*, memmove, void *to, const void *from, uptr size) MEMMOVE_BODY
+INTERCEPTOR(void*, memmove, void *to, const void *from, uptr size) {
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, memmove);
+ ASAN_MEMMOVE_IMPL(ctx, to, from, size);
+}
INTERCEPTOR(void*, memcpy, void *to, const void *from, uptr size) {
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, memcpy);
#if !SANITIZER_MAC
- if (!asan_inited) return internal_memcpy(to, from, size);
- // memcpy is called during __asan_init() from the internals
- // of printf(...).
- if (asan_init_is_running) {
- return REAL(memcpy)(to, from, size);
- }
- ENSURE_ASAN_INITED();
- if (flags()->replace_intrin) {
- if (to != from) {
- // We do not treat memcpy with to==from as a bug.
- // See http://llvm.org/bugs/show_bug.cgi?id=11763.
- CHECK_RANGES_OVERLAP("memcpy", to, size, from, size);
- }
- ASAN_READ_RANGE(from, size);
- ASAN_WRITE_RANGE(to, size);
- }
- // Interposing of resolver functions is broken on Mac OS 10.7 and 10.8, so
- // calling REAL(memcpy) here leads to infinite recursion.
- // See also http://code.google.com/p/address-sanitizer/issues/detail?id=116.
- return internal_memcpy(to, from, size);
+ ASAN_MEMCPY_IMPL(ctx, to, from, size);
#else
// At least on 10.7 and 10.8 both memcpy() and memmove() are being replaced
// with WRAP(memcpy). As a result, false positives are reported for memmove()
@@ -388,25 +475,20 @@ INTERCEPTOR(void*, memcpy, void *to, const void *from, uptr size) {
// ASAN_OPTIONS=replace_intrin=0, memmove() is still replaced with
// internal_memcpy(), which may lead to crashes, see
// http://llvm.org/bugs/show_bug.cgi?id=16362.
- MEMMOVE_BODY
+ ASAN_MEMMOVE_IMPL(ctx, to, from, size);
#endif // !SANITIZER_MAC
}
INTERCEPTOR(void*, memset, void *block, int c, uptr size) {
- if (!asan_inited) return internal_memset(block, c, size);
- // memset is called inside Printf.
- if (asan_init_is_running) {
- return REAL(memset)(block, c, size);
- }
- ENSURE_ASAN_INITED();
- if (flags()->replace_intrin) {
- ASAN_WRITE_RANGE(block, size);
- }
- return REAL(memset)(block, c, size);
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, memset);
+ ASAN_MEMSET_IMPL(ctx, block, c, size);
}
INTERCEPTOR(char*, strchr, const char *str, int c) {
- if (!asan_inited) return internal_strchr(str, c);
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, strchr);
+ if (UNLIKELY(!asan_inited)) return internal_strchr(str, c);
// strchr is called inside create_purgeable_zone() when MallocGuardEdges=1 is
// used.
if (asan_init_is_running) {
@@ -416,7 +498,7 @@ INTERCEPTOR(char*, strchr, const char *str, int c) {
char *result = REAL(strchr)(str, c);
if (flags()->replace_str) {
uptr bytes_read = (result ? result - str : REAL(strlen)(str)) + 1;
- ASAN_READ_RANGE(str, bytes_read);
+ ASAN_READ_RANGE(ctx, str, bytes_read);
}
return result;
}
@@ -438,13 +520,15 @@ DEFINE_REAL(char*, index, const char *string, int c)
// For both strcat() and strncat() we need to check the validity of |to|
// argument irrespective of the |from| length.
INTERCEPTOR(char*, strcat, char *to, const char *from) { // NOLINT
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, strcat); // NOLINT
ENSURE_ASAN_INITED();
if (flags()->replace_str) {
uptr from_length = REAL(strlen)(from);
- ASAN_READ_RANGE(from, from_length + 1);
+ ASAN_READ_RANGE(ctx, from, from_length + 1);
uptr to_length = REAL(strlen)(to);
- ASAN_READ_RANGE(to, to_length);
- ASAN_WRITE_RANGE(to + to_length, from_length + 1);
+ ASAN_READ_RANGE(ctx, to, to_length);
+ ASAN_WRITE_RANGE(ctx, to + to_length, from_length + 1);
// If the copying actually happens, the |from| string should not overlap
// with the resulting string starting at |to|, which has a length of
// to_length + from_length + 1.
@@ -457,14 +541,16 @@ INTERCEPTOR(char*, strcat, char *to, const char *from) { // NOLINT
}
INTERCEPTOR(char*, strncat, char *to, const char *from, uptr size) {
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, strncat);
ENSURE_ASAN_INITED();
if (flags()->replace_str) {
uptr from_length = MaybeRealStrnlen(from, size);
uptr copy_length = Min(size, from_length + 1);
- ASAN_READ_RANGE(from, copy_length);
+ ASAN_READ_RANGE(ctx, from, copy_length);
uptr to_length = REAL(strlen)(to);
- ASAN_READ_RANGE(to, to_length);
- ASAN_WRITE_RANGE(to + to_length, from_length + 1);
+ ASAN_READ_RANGE(ctx, to, to_length);
+ ASAN_WRITE_RANGE(ctx, to + to_length, from_length + 1);
if (from_length > 0) {
CHECK_RANGES_OVERLAP("strncat", to, to_length + copy_length + 1,
from, copy_length);
@@ -474,8 +560,10 @@ INTERCEPTOR(char*, strncat, char *to, const char *from, uptr size) {
}
INTERCEPTOR(char*, strcpy, char *to, const char *from) { // NOLINT
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, strcpy); // NOLINT
#if SANITIZER_MAC
- if (!asan_inited) return REAL(strcpy)(to, from); // NOLINT
+ if (UNLIKELY(!asan_inited)) return REAL(strcpy)(to, from); // NOLINT
#endif
// strcpy is called from malloc_default_purgeable_zone()
// in __asan::ReplaceSystemAlloc() on Mac.
@@ -486,19 +574,21 @@ INTERCEPTOR(char*, strcpy, char *to, const char *from) { // NOLINT
if (flags()->replace_str) {
uptr from_size = REAL(strlen)(from) + 1;
CHECK_RANGES_OVERLAP("strcpy", to, from_size, from, from_size);
- ASAN_READ_RANGE(from, from_size);
- ASAN_WRITE_RANGE(to, from_size);
+ ASAN_READ_RANGE(ctx, from, from_size);
+ ASAN_WRITE_RANGE(ctx, to, from_size);
}
return REAL(strcpy)(to, from); // NOLINT
}
#if ASAN_INTERCEPT_STRDUP
INTERCEPTOR(char*, strdup, const char *s) {
- if (!asan_inited) return internal_strdup(s);
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, strdup);
+ if (UNLIKELY(!asan_inited)) return internal_strdup(s);
ENSURE_ASAN_INITED();
uptr length = REAL(strlen)(s);
if (flags()->replace_str) {
- ASAN_READ_RANGE(s, length + 1);
+ ASAN_READ_RANGE(ctx, s, length + 1);
}
GET_STACK_TRACE_MALLOC;
void *new_mem = asan_malloc(length + 1, &stack);
@@ -507,47 +597,55 @@ INTERCEPTOR(char*, strdup, const char *s) {
}
#endif
-INTERCEPTOR(uptr, strlen, const char *s) {
- if (!asan_inited) return internal_strlen(s);
+INTERCEPTOR(SIZE_T, strlen, const char *s) {
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, strlen);
+ if (UNLIKELY(!asan_inited)) return internal_strlen(s);
// strlen is called from malloc_default_purgeable_zone()
// in __asan::ReplaceSystemAlloc() on Mac.
if (asan_init_is_running) {
return REAL(strlen)(s);
}
ENSURE_ASAN_INITED();
- uptr length = REAL(strlen)(s);
+ SIZE_T length = REAL(strlen)(s);
if (flags()->replace_str) {
- ASAN_READ_RANGE(s, length + 1);
+ ASAN_READ_RANGE(ctx, s, length + 1);
}
return length;
}
-INTERCEPTOR(uptr, wcslen, const wchar_t *s) {
- uptr length = REAL(wcslen)(s);
+INTERCEPTOR(SIZE_T, wcslen, const wchar_t *s) {
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, wcslen);
+ SIZE_T length = REAL(wcslen)(s);
if (!asan_init_is_running) {
ENSURE_ASAN_INITED();
- ASAN_READ_RANGE(s, (length + 1) * sizeof(wchar_t));
+ ASAN_READ_RANGE(ctx, s, (length + 1) * sizeof(wchar_t));
}
return length;
}
INTERCEPTOR(char*, strncpy, char *to, const char *from, uptr size) {
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, strncpy);
ENSURE_ASAN_INITED();
if (flags()->replace_str) {
uptr from_size = Min(size, MaybeRealStrnlen(from, size) + 1);
CHECK_RANGES_OVERLAP("strncpy", to, from_size, from, from_size);
- ASAN_READ_RANGE(from, from_size);
- ASAN_WRITE_RANGE(to, size);
+ ASAN_READ_RANGE(ctx, from, from_size);
+ ASAN_WRITE_RANGE(ctx, to, size);
}
return REAL(strncpy)(to, from, size);
}
#if ASAN_INTERCEPT_STRNLEN
INTERCEPTOR(uptr, strnlen, const char *s, uptr maxlen) {
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, strnlen);
ENSURE_ASAN_INITED();
uptr length = REAL(strnlen)(s, maxlen);
if (flags()->replace_str) {
- ASAN_READ_RANGE(s, Min(length + 1, maxlen));
+ ASAN_READ_RANGE(ctx, s, Min(length + 1, maxlen));
}
return length;
}
@@ -565,13 +663,15 @@ static inline void FixRealStrtolEndptr(const char *nptr, char **endptr) {
// We get this symbol by skipping leading blanks and optional +/- sign.
while (IsSpace(*nptr)) nptr++;
if (*nptr == '+' || *nptr == '-') nptr++;
- *endptr = (char*)nptr;
+ *endptr = const_cast<char *>(nptr);
}
CHECK(*endptr >= nptr);
}
INTERCEPTOR(long, strtol, const char *nptr, // NOLINT
char **endptr, int base) {
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, strtol);
ENSURE_ASAN_INITED();
if (!flags()->replace_str) {
return REAL(strtol)(nptr, endptr, base);
@@ -583,14 +683,16 @@ INTERCEPTOR(long, strtol, const char *nptr, // NOLINT
}
if (IsValidStrtolBase(base)) {
FixRealStrtolEndptr(nptr, &real_endptr);
- ASAN_READ_RANGE(nptr, (real_endptr - nptr) + 1);
+ ASAN_READ_RANGE(ctx, nptr, (real_endptr - nptr) + 1);
}
return result;
}
INTERCEPTOR(int, atoi, const char *nptr) {
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, atoi);
#if SANITIZER_MAC
- if (!asan_inited) return REAL(atoi)(nptr);
+ if (UNLIKELY(!asan_inited)) return REAL(atoi)(nptr);
#endif
ENSURE_ASAN_INITED();
if (!flags()->replace_str) {
@@ -603,13 +705,15 @@ INTERCEPTOR(int, atoi, const char *nptr) {
// different from int). So, we just imitate this behavior.
int result = REAL(strtol)(nptr, &real_endptr, 10);
FixRealStrtolEndptr(nptr, &real_endptr);
- ASAN_READ_RANGE(nptr, (real_endptr - nptr) + 1);
+ ASAN_READ_RANGE(ctx, nptr, (real_endptr - nptr) + 1);
return result;
}
INTERCEPTOR(long, atol, const char *nptr) { // NOLINT
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, atol);
#if SANITIZER_MAC
- if (!asan_inited) return REAL(atol)(nptr);
+ if (UNLIKELY(!asan_inited)) return REAL(atol)(nptr);
#endif
ENSURE_ASAN_INITED();
if (!flags()->replace_str) {
@@ -618,13 +722,15 @@ INTERCEPTOR(long, atol, const char *nptr) { // NOLINT
char *real_endptr;
long result = REAL(strtol)(nptr, &real_endptr, 10); // NOLINT
FixRealStrtolEndptr(nptr, &real_endptr);
- ASAN_READ_RANGE(nptr, (real_endptr - nptr) + 1);
+ ASAN_READ_RANGE(ctx, nptr, (real_endptr - nptr) + 1);
return result;
}
#if ASAN_INTERCEPT_ATOLL_AND_STRTOLL
INTERCEPTOR(long long, strtoll, const char *nptr, // NOLINT
char **endptr, int base) {
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, strtoll);
ENSURE_ASAN_INITED();
if (!flags()->replace_str) {
return REAL(strtoll)(nptr, endptr, base);
@@ -639,12 +745,14 @@ INTERCEPTOR(long long, strtoll, const char *nptr, // NOLINT
// if base is valid.
if (IsValidStrtolBase(base)) {
FixRealStrtolEndptr(nptr, &real_endptr);
- ASAN_READ_RANGE(nptr, (real_endptr - nptr) + 1);
+ ASAN_READ_RANGE(ctx, nptr, (real_endptr - nptr) + 1);
}
return result;
}
INTERCEPTOR(long long, atoll, const char *nptr) { // NOLINT
+ void *ctx;
+ ASAN_INTERCEPTOR_ENTER(ctx, atoll);
ENSURE_ASAN_INITED();
if (!flags()->replace_str) {
return REAL(atoll)(nptr);
@@ -652,7 +760,7 @@ INTERCEPTOR(long long, atoll, const char *nptr) { // NOLINT
char *real_endptr;
long long result = REAL(strtoll)(nptr, &real_endptr, 10); // NOLINT
FixRealStrtolEndptr(nptr, &real_endptr);
- ASAN_READ_RANGE(nptr, (real_endptr - nptr) + 1);
+ ASAN_READ_RANGE(ctx, nptr, (real_endptr - nptr) + 1);
return result;
}
#endif // ASAN_INTERCEPT_ATOLL_AND_STRTOLL
@@ -666,7 +774,7 @@ static void AtCxaAtexit(void *unused) {
INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg,
void *dso_handle) {
#if SANITIZER_MAC
- if (!asan_inited) return REAL(__cxa_atexit)(func, arg, dso_handle);
+ if (UNLIKELY(!asan_inited)) return REAL(__cxa_atexit)(func, arg, dso_handle);
#endif
ENSURE_ASAN_INITED();
int res = REAL(__cxa_atexit)(func, arg, dso_handle);
@@ -675,27 +783,50 @@ INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg,
}
#endif // ASAN_INTERCEPT___CXA_ATEXIT
+#if ASAN_INTERCEPT_FORK
+INTERCEPTOR(int, fork, void) {
+ ENSURE_ASAN_INITED();
+ if (common_flags()->coverage) CovBeforeFork();
+ int pid = REAL(fork)();
+ if (common_flags()->coverage) CovAfterFork(pid);
+ return pid;
+}
+#endif // ASAN_INTERCEPT_FORK
+
#if SANITIZER_WINDOWS
INTERCEPTOR_WINAPI(DWORD, CreateThread,
void* security, uptr stack_size,
DWORD (__stdcall *start_routine)(void*), void* arg,
DWORD thr_flags, void* tid) {
- // Strict init-order checking in thread-hostile.
+ // Strict init-order checking is thread-hostile.
if (flags()->strict_init_order)
StopInitOrderChecking();
GET_STACK_TRACE_THREAD;
- u32 current_tid = GetCurrentTidOrInvalid();
- AsanThread *t = AsanThread::Create(start_routine, arg);
- CreateThreadContextArgs args = { t, &stack };
bool detached = false; // FIXME: how can we determine it on Windows?
- asanThreadRegistry().CreateThread(*(uptr*)t, detached, current_tid, &args);
- return REAL(CreateThread)(security, stack_size,
- asan_thread_start, t, thr_flags, tid);
+ ThreadStartParam param;
+ atomic_store(&param.t, 0, memory_order_relaxed);
+ atomic_store(&param.is_registered, 0, memory_order_relaxed);
+ DWORD result = REAL(CreateThread)(security, stack_size, asan_thread_start,
+ &param, thr_flags, tid);
+ if (result) {
+ u32 current_tid = GetCurrentTidOrInvalid();
+ AsanThread *t =
+ AsanThread::Create(start_routine, arg, current_tid, &stack, detached);
+ atomic_store(&param.t, reinterpret_cast<uptr>(t), memory_order_release);
+ // The pthread_create interceptor waits here, so we do the same for
+ // consistency.
+ while (atomic_load(&param.is_registered, memory_order_acquire) == 0)
+ internal_sched_yield();
+ }
+ return result;
}
namespace __asan {
void InitializeWindowsInterceptors() {
ASAN_INTERCEPT_FUNC(CreateThread);
+ ASAN_INTERCEPT_FUNC(RaiseException);
+ ASAN_INTERCEPT_FUNC(_except_handler3);
+ ASAN_INTERCEPT_FUNC(_except_handler4);
}
} // namespace __asan
@@ -707,7 +838,7 @@ void InitializeAsanInterceptors() {
static bool was_called_once;
CHECK(was_called_once == false);
was_called_once = true;
- SANITIZER_COMMON_INTERCEPTORS_INIT;
+ InitializeCommonInterceptors();
// Intercept mem* functions.
ASAN_INTERCEPT_FUNC(memcmp);
@@ -743,20 +874,16 @@ void InitializeAsanInterceptors() {
ASAN_INTERCEPT_FUNC(strtoll);
#endif
-#if ASAN_INTERCEPT_MLOCKX
- // Intercept mlock/munlock.
- ASAN_INTERCEPT_FUNC(mlock);
- ASAN_INTERCEPT_FUNC(munlock);
- ASAN_INTERCEPT_FUNC(mlockall);
- ASAN_INTERCEPT_FUNC(munlockall);
-#endif
-
// Intecept signal- and jump-related functions.
ASAN_INTERCEPT_FUNC(longjmp);
#if ASAN_INTERCEPT_SIGNAL_AND_SIGACTION
ASAN_INTERCEPT_FUNC(sigaction);
+#if SANITIZER_ANDROID
+ ASAN_INTERCEPT_FUNC(bsd_signal);
+#else
ASAN_INTERCEPT_FUNC(signal);
#endif
+#endif
#if ASAN_INTERCEPT_SWAPCONTEXT
ASAN_INTERCEPT_FUNC(swapcontext);
#endif
@@ -769,7 +896,7 @@ void InitializeAsanInterceptors() {
// Intercept exception handling functions.
#if ASAN_INTERCEPT___CXA_THROW
- INTERCEPT_FUNCTION(__cxa_throw);
+ ASAN_INTERCEPT_FUNC(__cxa_throw);
#endif
// Intercept threading-related functions
@@ -782,14 +909,16 @@ void InitializeAsanInterceptors() {
ASAN_INTERCEPT_FUNC(__cxa_atexit);
#endif
+#if ASAN_INTERCEPT_FORK
+ ASAN_INTERCEPT_FUNC(fork);
+#endif
+
// Some Windows-specific interceptors.
#if SANITIZER_WINDOWS
InitializeWindowsInterceptors();
#endif
- if (common_flags()->verbosity > 0) {
- Report("AddressSanitizer: libc interceptors initialized\n");
- }
+ VReport(1, "AddressSanitizer: libc interceptors initialized\n");
}
} // namespace __asan
diff --git a/lib/asan/asan_interceptors.h b/lib/asan/asan_interceptors.h
index 91830aa145a9..ee3b82aa7ef9 100644
--- a/lib/asan/asan_interceptors.h
+++ b/lib/asan/asan_interceptors.h
@@ -16,12 +16,75 @@
#include "asan_internal.h"
#include "interception/interception.h"
+#include "sanitizer_common/sanitizer_platform_interceptors.h"
+
+// Use macro to describe if specific function should be
+// intercepted on a given platform.
+#if !SANITIZER_WINDOWS
+# define ASAN_INTERCEPT_ATOLL_AND_STRTOLL 1
+# define ASAN_INTERCEPT__LONGJMP 1
+# define ASAN_INTERCEPT_STRDUP 1
+# define ASAN_INTERCEPT_INDEX 1
+# define ASAN_INTERCEPT_PTHREAD_CREATE 1
+# define ASAN_INTERCEPT_FORK 1
+#else
+# define ASAN_INTERCEPT_ATOLL_AND_STRTOLL 0
+# define ASAN_INTERCEPT__LONGJMP 0
+# define ASAN_INTERCEPT_STRDUP 0
+# define ASAN_INTERCEPT_INDEX 0
+# define ASAN_INTERCEPT_PTHREAD_CREATE 0
+# define ASAN_INTERCEPT_FORK 0
+#endif
+
+#if SANITIZER_FREEBSD || SANITIZER_LINUX
+# define ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX 1
+#else
+# define ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX 0
+#endif
+
+#if !SANITIZER_MAC
+# define ASAN_INTERCEPT_STRNLEN 1
+#else
+# define ASAN_INTERCEPT_STRNLEN 0
+#endif
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+# define ASAN_INTERCEPT_SWAPCONTEXT 1
+#else
+# define ASAN_INTERCEPT_SWAPCONTEXT 0
+#endif
+
+#if !SANITIZER_WINDOWS
+# define ASAN_INTERCEPT_SIGNAL_AND_SIGACTION 1
+#else
+# define ASAN_INTERCEPT_SIGNAL_AND_SIGACTION 0
+#endif
+
+#if !SANITIZER_WINDOWS
+# define ASAN_INTERCEPT_SIGLONGJMP 1
+#else
+# define ASAN_INTERCEPT_SIGLONGJMP 0
+#endif
+
+// Android bug: https://code.google.com/p/android/issues/detail?id=61799
+#if ASAN_HAS_EXCEPTIONS && !SANITIZER_WINDOWS && \
+ !(SANITIZER_ANDROID && defined(__i386))
+# define ASAN_INTERCEPT___CXA_THROW 1
+#else
+# define ASAN_INTERCEPT___CXA_THROW 0
+#endif
+
+#if !SANITIZER_WINDOWS
+# define ASAN_INTERCEPT___CXA_ATEXIT 1
+#else
+# define ASAN_INTERCEPT___CXA_ATEXIT 0
+#endif
DECLARE_REAL(int, memcmp, const void *a1, const void *a2, uptr size)
DECLARE_REAL(void*, memcpy, void *to, const void *from, uptr size)
DECLARE_REAL(void*, memset, void *block, int c, uptr size)
DECLARE_REAL(char*, strchr, const char *str, int c)
-DECLARE_REAL(uptr, strlen, const char *s)
+DECLARE_REAL(SIZE_T, strlen, const char *s)
DECLARE_REAL(char*, strncpy, char *to, const char *from, uptr size)
DECLARE_REAL(uptr, strnlen, const char *s, uptr maxlen)
DECLARE_REAL(char*, strstr, const char *s1, const char *s2)
@@ -33,6 +96,13 @@ namespace __asan {
void InitializeAsanInterceptors();
+#define ENSURE_ASAN_INITED() do { \
+ CHECK(!asan_init_is_running); \
+ if (UNLIKELY(!asan_inited)) { \
+ AsanInitFromRtl(); \
+ } \
+} while (0)
+
} // namespace __asan
#endif // ASAN_INTERCEPTORS_H
diff --git a/lib/asan/asan_interface_internal.h b/lib/asan/asan_interface_internal.h
index 5c1d025296fb..edaf44d7893a 100644
--- a/lib/asan/asan_interface_internal.h
+++ b/lib/asan/asan_interface_internal.h
@@ -17,21 +17,24 @@
#include "sanitizer_common/sanitizer_internal_defs.h"
+#include "asan_init_version.h"
+
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.
- // Everytime the asan ABI changes we also change the version number in this
- // name. Objects build with incompatible asan ABI version
- // will not link with run-time.
- // Changes between ABI versions:
- // v1=>v2: added 'module_name' to __asan_global
- // v2=>v3: stack frame description (created by the compiler)
- // contains the function PC as the 3-rd field (see
- // DescribeAddressIfStack).
- SANITIZER_INTERFACE_ATTRIBUTE void __asan_init_v3();
- #define __asan_init __asan_init_v3
+ // 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 structure is used to describe the source location of a place where
+ // global was defined.
+ struct __asan_global_source_location {
+ const char *filename;
+ int line_no;
+ int column_no;
+ };
// This structure describes an instrumented global variable.
struct __asan_global {
@@ -42,6 +45,8 @@ extern "C" {
const char *module_name; // Module name as a C string. This pointer is a
// unique identifier of a module.
uptr has_dynamic_init; // Non-zero if the global has dynamic initializer.
+ __asan_global_source_location *location; // Source location of a global,
+ // or NULL if it is unknown.
};
// These two functions should be called by the instrumented code.
@@ -77,7 +82,7 @@ extern "C" {
void __asan_unpoison_memory_region(void const volatile *addr, uptr size);
SANITIZER_INTERFACE_ATTRIBUTE
- bool __asan_address_is_poisoned(void const volatile *addr);
+ int __asan_address_is_poisoned(void const volatile *addr);
SANITIZER_INTERFACE_ATTRIBUTE
uptr __asan_region_is_poisoned(uptr beg, uptr size);
@@ -86,8 +91,41 @@ extern "C" {
void __asan_describe_address(uptr addr);
SANITIZER_INTERFACE_ATTRIBUTE
+ int __asan_report_present();
+
+ SANITIZER_INTERFACE_ATTRIBUTE
+ uptr __asan_get_report_pc();
+ SANITIZER_INTERFACE_ATTRIBUTE
+ uptr __asan_get_report_bp();
+ SANITIZER_INTERFACE_ATTRIBUTE
+ uptr __asan_get_report_sp();
+ SANITIZER_INTERFACE_ATTRIBUTE
+ uptr __asan_get_report_address();
+ SANITIZER_INTERFACE_ATTRIBUTE
+ int __asan_get_report_access_type();
+ SANITIZER_INTERFACE_ATTRIBUTE
+ uptr __asan_get_report_access_size();
+ SANITIZER_INTERFACE_ATTRIBUTE
+ const char * __asan_get_report_description();
+
+ SANITIZER_INTERFACE_ATTRIBUTE
+ const char * __asan_locate_address(uptr addr, char *name, uptr name_size,
+ uptr *region_address, uptr *region_size);
+
+ SANITIZER_INTERFACE_ATTRIBUTE
+ uptr __asan_get_alloc_stack(uptr addr, uptr *trace, uptr size,
+ u32 *thread_id);
+
+ SANITIZER_INTERFACE_ATTRIBUTE
+ uptr __asan_get_free_stack(uptr addr, uptr *trace, uptr size,
+ u32 *thread_id);
+
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __asan_get_shadow_mapping(uptr *shadow_scale, uptr *shadow_offset);
+
+ SANITIZER_INTERFACE_ATTRIBUTE
void __asan_report_error(uptr pc, uptr bp, uptr sp,
- uptr addr, bool is_write, uptr access_size);
+ uptr addr, int is_write, uptr access_size);
SANITIZER_INTERFACE_ATTRIBUTE
int __asan_set_error_exit_code(int exit_code);
@@ -99,32 +137,46 @@ extern "C" {
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
/* OPTIONAL */ void __asan_on_error();
- SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
- /* OPTIONAL */ bool __asan_symbolize(const void *pc, char *out_buffer,
- int out_size);
-
- SANITIZER_INTERFACE_ATTRIBUTE
- uptr __asan_get_estimated_allocated_size(uptr size);
-
- SANITIZER_INTERFACE_ATTRIBUTE bool __asan_get_ownership(const void *p);
- SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_get_allocated_size(const void *p);
- SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_get_current_allocated_bytes();
- SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_get_heap_size();
- SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_get_free_bytes();
- SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_get_unmapped_bytes();
SANITIZER_INTERFACE_ATTRIBUTE void __asan_print_accumulated_stats();
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
/* OPTIONAL */ const char* __asan_default_options();
- SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
- /* OPTIONAL */ void __asan_malloc_hook(void *ptr, uptr size);
- SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
- /* OPTIONAL */ void __asan_free_hook(void *ptr);
-
// Global flag, copy of ASAN_OPTIONS=detect_stack_use_after_return
SANITIZER_INTERFACE_ATTRIBUTE
extern int __asan_option_detect_stack_use_after_return;
+
+ SANITIZER_INTERFACE_ATTRIBUTE
+ extern uptr *__asan_test_only_reported_buggy_pointer;
+
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_load1(uptr p);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_load2(uptr p);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_load4(uptr p);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_load8(uptr p);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_load16(uptr p);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_store1(uptr p);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_store2(uptr p);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_store4(uptr p);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_store8(uptr p);
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_store16(uptr p);
+ 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_memcpy(void *dst, const void *src, uptr size);
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void* __asan_memset(void *s, int c, uptr n);
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void* __asan_memmove(void* dest, const void* src, uptr n);
+
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __asan_poison_cxx_array_cookie(uptr p);
+ SANITIZER_INTERFACE_ATTRIBUTE
+ uptr __asan_load_cxx_array_cookie(uptr *p);
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __asan_poison_intra_object_redzone(uptr p, uptr size);
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __asan_unpoison_intra_object_redzone(uptr p, uptr size);
} // extern "C"
#endif // ASAN_INTERFACE_INTERNAL_H
diff --git a/lib/asan/asan_internal.h b/lib/asan/asan_internal.h
index 70e55ea0afef..65d4a47d3d9e 100644
--- a/lib/asan/asan_internal.h
+++ b/lib/asan/asan_internal.h
@@ -30,26 +30,11 @@
// Build-time configuration options.
-// If set, asan will install its own SEGV signal handler.
-#ifndef ASAN_NEEDS_SEGV
-# if SANITIZER_ANDROID == 1
-# define ASAN_NEEDS_SEGV 0
-# else
-# define ASAN_NEEDS_SEGV 1
-# endif
-#endif
-
// If set, asan will intercept C++ exception api call(s).
#ifndef ASAN_HAS_EXCEPTIONS
# define ASAN_HAS_EXCEPTIONS 1
#endif
-// If set, asan uses the values of SHADOW_SCALE and SHADOW_OFFSET
-// provided by the instrumented objects. Otherwise constants are used.
-#ifndef ASAN_FLEXIBLE_MAPPING_AND_OFFSET
-# define ASAN_FLEXIBLE_MAPPING_AND_OFFSET 0
-#endif
-
// If set, values like allocator chunk size, as well as defaults for some flags
// will be changed towards less memory overhead.
#ifndef ASAN_LOW_MEMORY
@@ -60,36 +45,56 @@
# endif
#endif
-#ifndef ASAN_USE_PREINIT_ARRAY
-# define ASAN_USE_PREINIT_ARRAY (SANITIZER_LINUX && !SANITIZER_ANDROID)
+#ifndef ASAN_DYNAMIC
+# ifdef PIC
+# define ASAN_DYNAMIC 1
+# else
+# define ASAN_DYNAMIC 0
+# endif
#endif
// All internal functions in asan reside inside the __asan namespace
// to avoid namespace collisions with the user programs.
-// Seperate namespace also makes it simpler to distinguish the asan run-time
+// Separate namespace also makes it simpler to distinguish the asan run-time
// functions from the instrumented user code in a profile.
namespace __asan {
class AsanThread;
using __sanitizer::StackTrace;
+struct SignalContext {
+ void *context;
+ uptr addr;
+ uptr pc;
+ uptr sp;
+ uptr bp;
+
+ SignalContext(void *context, uptr addr, uptr pc, uptr sp, uptr bp) :
+ context(context), addr(addr), pc(pc), sp(sp), bp(bp) {
+ }
+
+ // Creates signal context in a platform-specific manner.
+ static SignalContext Create(void *siginfo, void *context);
+};
+
+void AsanInitFromRtl();
+
// asan_rtl.cc
void NORETURN ShowStatsAndAbort();
-void ReplaceOperatorsNewAndDelete();
// asan_malloc_linux.cc / asan_malloc_mac.cc
void ReplaceSystemMalloc();
// asan_linux.cc / asan_mac.cc / asan_win.cc
void *AsanDoesNotSupportStaticLinkage();
+void AsanCheckDynamicRTPrereqs();
+void AsanCheckIncompatibleRT();
void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp);
+void AsanOnSIGSEGV(int, void *siginfo, void *context);
void MaybeReexec();
bool AsanInterceptsSignal(int signum);
-void SetAlternateSignalStack();
-void UnsetAlternateSignalStack();
-void InstallSignalHandlers();
void ReadContextStack(void *context, uptr *stack, uptr *ssize);
void AsanPlatformThreadInit();
void StopInitOrderChecking();
@@ -102,7 +107,11 @@ void PlatformTSDDtor(void *tsd);
void AppendToErrorMessageBuffer(const char *buffer);
-// Platfrom-specific options.
+void ParseExtraActivationFlags();
+
+void *AsanDlSymNext(const char *sym);
+
+// Platform-specific options.
#if SANITIZER_MAC
bool PlatformHasDifferentMemcpyAndMemmove();
# define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE \
@@ -114,9 +123,9 @@ bool PlatformHasDifferentMemcpyAndMemmove();
// Add convenient macro for interface functions that may be represented as
// weak hooks.
#define ASAN_MALLOC_HOOK(ptr, size) \
- if (&__asan_malloc_hook) __asan_malloc_hook(ptr, size)
+ if (&__sanitizer_malloc_hook) __sanitizer_malloc_hook(ptr, size)
#define ASAN_FREE_HOOK(ptr) \
- if (&__asan_free_hook) __asan_free_hook(ptr)
+ if (&__sanitizer_free_hook) __sanitizer_free_hook(ptr)
#define ASAN_ON_ERROR() \
if (&__asan_on_error) __asan_on_error()
@@ -136,9 +145,14 @@ const int kAsanStackPartialRedzoneMagic = 0xf4;
const int kAsanStackAfterReturnMagic = 0xf5;
const int kAsanInitializationOrderMagic = 0xf6;
const int kAsanUserPoisonedMemoryMagic = 0xf7;
+const int kAsanContiguousContainerOOBMagic = 0xfc;
const int kAsanStackUseAfterScopeMagic = 0xf8;
const int kAsanGlobalRedzoneMagic = 0xf9;
const int kAsanInternalHeapMagic = 0xfe;
+const int kAsanArrayCookieMagic = 0xac;
+const int kAsanIntraObjectRedzone = 0xbb;
+const int kAsanAllocaLeftMagic = 0xca;
+const int kAsanAllocaRightMagic = 0xcb;
static const uptr kCurrentStackFrameMagic = 0x41B58AB3;
static const uptr kRetiredStackFrameMagic = 0x45E0360E;
diff --git a/lib/asan/asan_linux.cc b/lib/asan/asan_linux.cc
index 39eec3bfd301..fdd009c960d8 100644
--- a/lib/asan/asan_linux.cc
+++ b/lib/asan/asan_linux.cc
@@ -13,11 +13,13 @@
//===----------------------------------------------------------------------===//
#include "sanitizer_common/sanitizer_platform.h"
-#if SANITIZER_LINUX
+#if SANITIZER_FREEBSD || SANITIZER_LINUX
#include "asan_interceptors.h"
#include "asan_internal.h"
#include "asan_thread.h"
+#include "sanitizer_common/sanitizer_flags.h"
+#include "sanitizer_common/sanitizer_freebsd.h"
#include "sanitizer_common/sanitizer_libc.h"
#include "sanitizer_common/sanitizer_procmaps.h"
@@ -26,18 +28,43 @@
#include <sys/mman.h>
#include <sys/syscall.h>
#include <sys/types.h>
+#include <dlfcn.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <unwind.h>
-#if !SANITIZER_ANDROID
-// FIXME: where to get ucontext on Android?
-#include <sys/ucontext.h>
+#if SANITIZER_FREEBSD
+#include <sys/link_elf.h>
#endif
+#if SANITIZER_ANDROID || SANITIZER_FREEBSD
+#include <ucontext.h>
extern "C" void* _DYNAMIC;
+#else
+#include <sys/ucontext.h>
+#include <link.h>
+#endif
+
+// x86-64 FreeBSD 9.2 and older define 'ucontext_t' incorrectly in
+// 32-bit mode.
+#if SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32) && \
+ __FreeBSD_version <= 902001 // v9.2
+#define ucontext_t xucontext_t
+#endif
+
+typedef enum {
+ ASAN_RT_VERSION_UNDEFINED = 0,
+ ASAN_RT_VERSION_DYNAMIC,
+ ASAN_RT_VERSION_STATIC,
+} asan_rt_version_t;
+
+// FIXME: perhaps also store abi version here?
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE
+asan_rt_version_t __asan_rt_version;
+}
namespace __asan {
@@ -50,38 +77,126 @@ void *AsanDoesNotSupportStaticLinkage() {
return &_DYNAMIC; // defined in link.h
}
-void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
#if SANITIZER_ANDROID
- *pc = *sp = *bp = 0;
-#elif defined(__arm__)
+// FIXME: should we do anything for Android?
+void AsanCheckDynamicRTPrereqs() {}
+void AsanCheckIncompatibleRT() {}
+#else
+static int FindFirstDSOCallback(struct dl_phdr_info *info, size_t size,
+ void *data) {
+ // Continue until the first dynamic library is found
+ if (!info->dlpi_name || info->dlpi_name[0] == 0)
+ return 0;
+
+ // Ignore vDSO
+ if (internal_strncmp(info->dlpi_name, "linux-", sizeof("linux-") - 1) == 0)
+ return 0;
+
+ *(const char **)data = info->dlpi_name;
+ return 1;
+}
+
+static bool IsDynamicRTName(const char *libname) {
+ return internal_strstr(libname, "libclang_rt.asan") ||
+ internal_strstr(libname, "libasan.so");
+}
+
+static void ReportIncompatibleRT() {
+ Report("Your application is linked against incompatible ASan runtimes.\n");
+ Die();
+}
+
+void AsanCheckDynamicRTPrereqs() {
+ // Ensure that dynamic RT is the first DSO in the list
+ const char *first_dso_name = 0;
+ 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; "
+ "you should either link runtime to your application or "
+ "manually preload it with LD_PRELOAD.\n");
+ Die();
+ }
+}
+
+void AsanCheckIncompatibleRT() {
+ if (ASAN_DYNAMIC) {
+ if (__asan_rt_version == ASAN_RT_VERSION_UNDEFINED) {
+ __asan_rt_version = ASAN_RT_VERSION_DYNAMIC;
+ } else if (__asan_rt_version != ASAN_RT_VERSION_DYNAMIC) {
+ ReportIncompatibleRT();
+ }
+ } else {
+ if (__asan_rt_version == ASAN_RT_VERSION_UNDEFINED) {
+ // Ensure that dynamic runtime is not present. We should detect it
+ // as early as possible, otherwise ASan interceptors could bind to
+ // the functions in dynamic ASan runtime instead of the functions in
+ // 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)) {
+ if (IsDynamicRTName(filename)) {
+ Report("Your application is linked against "
+ "incompatible ASan runtimes.\n");
+ Die();
+ }
+ }
+ __asan_rt_version = ASAN_RT_VERSION_STATIC;
+ } else if (__asan_rt_version != ASAN_RT_VERSION_STATIC) {
+ ReportIncompatibleRT();
+ }
+ }
+}
+#endif // SANITIZER_ANDROID
+
+void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
+#if defined(__arm__)
ucontext_t *ucontext = (ucontext_t*)context;
*pc = ucontext->uc_mcontext.arm_pc;
*bp = ucontext->uc_mcontext.arm_fp;
*sp = ucontext->uc_mcontext.arm_sp;
-# elif defined(__hppa__)
+#elif defined(__aarch64__)
+ ucontext_t *ucontext = (ucontext_t*)context;
+ *pc = ucontext->uc_mcontext.pc;
+ *bp = ucontext->uc_mcontext.regs[29];
+ *sp = ucontext->uc_mcontext.sp;
+#elif defined(__hppa__)
ucontext_t *ucontext = (ucontext_t*)context;
*pc = ucontext->uc_mcontext.sc_iaoq[0];
/* GCC uses %r3 whenever a frame pointer is needed. */
*bp = ucontext->uc_mcontext.sc_gr[3];
*sp = ucontext->uc_mcontext.sc_gr[30];
-# elif defined(__x86_64__)
+#elif defined(__x86_64__)
+# if SANITIZER_FREEBSD
+ ucontext_t *ucontext = (ucontext_t*)context;
+ *pc = ucontext->uc_mcontext.mc_rip;
+ *bp = ucontext->uc_mcontext.mc_rbp;
+ *sp = ucontext->uc_mcontext.mc_rsp;
+# else
ucontext_t *ucontext = (ucontext_t*)context;
*pc = ucontext->uc_mcontext.gregs[REG_RIP];
*bp = ucontext->uc_mcontext.gregs[REG_RBP];
*sp = ucontext->uc_mcontext.gregs[REG_RSP];
-# elif defined(__i386__)
+# endif
+#elif defined(__i386__)
+# if SANITIZER_FREEBSD
+ ucontext_t *ucontext = (ucontext_t*)context;
+ *pc = ucontext->uc_mcontext.mc_eip;
+ *bp = ucontext->uc_mcontext.mc_ebp;
+ *sp = ucontext->uc_mcontext.mc_esp;
+# else
ucontext_t *ucontext = (ucontext_t*)context;
*pc = ucontext->uc_mcontext.gregs[REG_EIP];
*bp = ucontext->uc_mcontext.gregs[REG_EBP];
*sp = ucontext->uc_mcontext.gregs[REG_ESP];
-# elif defined(__powerpc__) || defined(__powerpc64__)
+# endif
+#elif defined(__powerpc__) || defined(__powerpc64__)
ucontext_t *ucontext = (ucontext_t*)context;
*pc = ucontext->uc_mcontext.regs->nip;
*sp = ucontext->uc_mcontext.regs->gpr[PT_R1];
// The powerpc{,64}-linux ABIs do not specify r31 as the frame
// pointer, but GCC always uses r31 when we need a frame pointer.
*bp = ucontext->uc_mcontext.regs->gpr[PT_R31];
-# elif defined(__sparc__)
+#elif defined(__sparc__)
ucontext_t *ucontext = (ucontext_t*)context;
uptr *stk_ptr;
# if defined (__arch64__)
@@ -95,7 +210,7 @@ void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
stk_ptr = (uptr *) *sp;
*bp = stk_ptr[15];
# endif
-# elif defined(__mips__)
+#elif defined(__mips__)
ucontext_t *ucontext = (ucontext_t*)context;
*pc = ucontext->uc_mcontext.gregs[31];
*bp = ucontext->uc_mcontext.gregs[30];
@@ -106,7 +221,7 @@ void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
}
bool AsanInterceptsSignal(int signum) {
- return signum == SIGSEGV && flags()->handle_segv;
+ return signum == SIGSEGV && common_flags()->handle_segv;
}
void AsanPlatformThreadInit() {
@@ -125,6 +240,10 @@ void ReadContextStack(void *context, uptr *stack, uptr *ssize) {
}
#endif
+void *AsanDlSymNext(const char *sym) {
+ return dlsym(RTLD_NEXT, sym);
+}
+
} // namespace __asan
-#endif // SANITIZER_LINUX
+#endif // SANITIZER_FREEBSD || SANITIZER_LINUX
diff --git a/lib/asan/asan_mac.cc b/lib/asan/asan_mac.cc
index e27d70adb81e..ae0fa15b6523 100644
--- a/lib/asan/asan_mac.cc
+++ b/lib/asan/asan_mac.cc
@@ -17,12 +17,12 @@
#include "asan_interceptors.h"
#include "asan_internal.h"
-#include "asan_mac.h"
#include "asan_mapping.h"
#include "asan_stack.h"
#include "asan_thread.h"
#include "sanitizer_common/sanitizer_atomic.h"
#include "sanitizer_common/sanitizer_libc.h"
+#include "sanitizer_common/sanitizer_mac.h"
#include <crt_externs.h> // for _NSGetArgv
#include <dlfcn.h> // for dladdr()
@@ -53,43 +53,6 @@ void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
# endif // SANITIZER_WORDSIZE
}
-MacosVersion cached_macos_version = MACOS_VERSION_UNINITIALIZED;
-
-MacosVersion GetMacosVersionInternal() {
- int mib[2] = { CTL_KERN, KERN_OSRELEASE };
- char version[100];
- uptr len = 0, maxlen = sizeof(version) / sizeof(version[0]);
- for (uptr i = 0; i < maxlen; i++) version[i] = '\0';
- // Get the version length.
- CHECK_NE(sysctl(mib, 2, 0, &len, 0, 0), -1);
- CHECK_LT(len, maxlen);
- CHECK_NE(sysctl(mib, 2, version, &len, 0, 0), -1);
- switch (version[0]) {
- case '9': return MACOS_VERSION_LEOPARD;
- case '1': {
- switch (version[1]) {
- case '0': return MACOS_VERSION_SNOW_LEOPARD;
- case '1': return MACOS_VERSION_LION;
- case '2': return MACOS_VERSION_MOUNTAIN_LION;
- case '3': return MACOS_VERSION_MAVERICKS;
- default: return MACOS_VERSION_UNKNOWN;
- }
- }
- default: return MACOS_VERSION_UNKNOWN;
- }
-}
-
-MacosVersion GetMacosVersion() {
- atomic_uint32_t *cache =
- reinterpret_cast<atomic_uint32_t*>(&cached_macos_version);
- MacosVersion result =
- static_cast<MacosVersion>(atomic_load(cache, memory_order_acquire));
- if (result == MACOS_VERSION_UNINITIALIZED) {
- result = GetMacosVersionInternal();
- atomic_store(cache, result, memory_order_release);
- }
- return result;
-}
bool PlatformHasDifferentMemcpyAndMemmove() {
// On OS X 10.7 memcpy() and memmove() are both resolved
@@ -151,7 +114,7 @@ void MaybeReexec() {
internal_strlen(dyld_insert_libraries) : 0;
uptr fname_len = internal_strlen(info.dli_fname);
if (!dyld_insert_libraries ||
- !REAL(strstr)(dyld_insert_libraries, info.dli_fname)) {
+ !REAL(strstr)(dyld_insert_libraries, StripModuleName(info.dli_fname))) {
// DYLD_INSERT_LIBRARIES is not set or does not contain the runtime
// library.
char program_name[1024];
@@ -174,12 +137,10 @@ void MaybeReexec() {
// Set DYLD_INSERT_LIBRARIES equal to the runtime dylib name.
setenv(kDyldInsertLibraries, info.dli_fname, /*overwrite*/0);
}
- if (common_flags()->verbosity >= 1) {
- Report("exec()-ing the program with\n");
- Report("%s=%s\n", kDyldInsertLibraries, new_env);
- Report("to enable ASan wrappers.\n");
- Report("Set ASAN_OPTIONS=allow_reexec=0 to disable this.\n");
- }
+ VReport(1, "exec()-ing the program with\n");
+ VReport(1, "%s=%s\n", kDyldInsertLibraries, new_env);
+ VReport(1, "to enable ASan wrappers.\n");
+ VReport(1, "Set ASAN_OPTIONS=allow_reexec=0 to disable this.\n");
execv(program_name, *_NSGetArgv());
} else {
// DYLD_INSERT_LIBRARIES is set and contains the runtime library.
@@ -238,8 +199,15 @@ void *AsanDoesNotSupportStaticLinkage() {
return 0;
}
+// No-op. Mac does not support static linkage anyway.
+void AsanCheckDynamicRTPrereqs() {}
+
+// No-op. Mac does not support static linkage anyway.
+void AsanCheckIncompatibleRT() {}
+
bool AsanInterceptsSignal(int signum) {
- return (signum == SIGSEGV || signum == SIGBUS) && flags()->handle_segv;
+ return (signum == SIGSEGV || signum == SIGBUS) &&
+ common_flags()->handle_segv;
}
void AsanPlatformThreadInit() {
@@ -296,9 +264,8 @@ ALWAYS_INLINE
void asan_register_worker_thread(int parent_tid, StackTrace *stack) {
AsanThread *t = GetCurrentThread();
if (!t) {
- t = AsanThread::Create(0, 0);
- CreateThreadContextArgs args = { t, stack };
- asanThreadRegistry().CreateThread(*(uptr*)t, true, parent_tid, &args);
+ t = AsanThread::Create(/* start_routine */ nullptr, /* arg */ nullptr,
+ parent_tid, stack, /* detached */ true);
t->Init();
asanThreadRegistry().StartThread(t->tid(), 0, 0);
SetCurrentThread(t);
@@ -311,11 +278,10 @@ extern "C"
void asan_dispatch_call_block_and_release(void *block) {
GET_STACK_TRACE_THREAD;
asan_block_context_t *context = (asan_block_context_t*)block;
- if (common_flags()->verbosity >= 2) {
- Report("asan_dispatch_call_block_and_release(): "
- "context: %p, pthread_self: %p\n",
- block, pthread_self());
- }
+ VReport(2,
+ "asan_dispatch_call_block_and_release(): "
+ "context: %p, pthread_self: %p\n",
+ block, pthread_self());
asan_register_worker_thread(context->parent_tid, &stack);
// Call the original dispatcher for the block.
context->func(context->block);
@@ -330,7 +296,7 @@ using namespace __asan; // NOLINT
// The caller retains control of the allocated context.
extern "C"
asan_block_context_t *alloc_asan_context(void *ctxt, dispatch_function_t func,
- StackTrace *stack) {
+ BufferedStackTrace *stack) {
asan_block_context_t *asan_ctxt =
(asan_block_context_t*) asan_malloc(sizeof(asan_block_context_t), stack);
asan_ctxt->block = ctxt;
@@ -349,10 +315,10 @@ asan_block_context_t *alloc_asan_context(void *ctxt, dispatch_function_t func,
if (common_flags()->verbosity >= 2) { \
Report(#dispatch_x_f "(): context: %p, pthread_self: %p\n", \
asan_ctxt, pthread_self()); \
- PRINT_CURRENT_STACK(); \
- } \
- return REAL(dispatch_x_f)(dq, (void*)asan_ctxt, \
- asan_dispatch_call_block_and_release); \
+ PRINT_CURRENT_STACK(); \
+ } \
+ return REAL(dispatch_x_f)(dq, (void*)asan_ctxt, \
+ asan_dispatch_call_block_and_release); \
}
INTERCEPT_DISPATCH_X_F_3(dispatch_async_f)
@@ -388,7 +354,6 @@ INTERCEPTOR(void, dispatch_group_async_f, dispatch_group_t group,
#if !defined(MISSING_BLOCKS_SUPPORT)
extern "C" {
-// FIXME: consolidate these declarations with asan_intercepted_functions.h.
void dispatch_async(dispatch_queue_t dq, void(^work)(void));
void dispatch_group_async(dispatch_group_t dg, dispatch_queue_t dq,
void(^work)(void));
@@ -408,32 +373,44 @@ void dispatch_source_set_event_handler(dispatch_source_t ds, void(^work)(void));
work(); \
}
+// Forces the compiler to generate a frame pointer in the function.
+#define ENABLE_FRAME_POINTER \
+ do { \
+ volatile uptr enable_fp; \
+ enable_fp = GET_CURRENT_FRAME(); \
+ } while (0)
+
INTERCEPTOR(void, dispatch_async,
dispatch_queue_t dq, void(^work)(void)) {
+ ENABLE_FRAME_POINTER;
GET_ASAN_BLOCK(work);
REAL(dispatch_async)(dq, asan_block);
}
INTERCEPTOR(void, dispatch_group_async,
dispatch_group_t dg, dispatch_queue_t dq, void(^work)(void)) {
+ ENABLE_FRAME_POINTER;
GET_ASAN_BLOCK(work);
REAL(dispatch_group_async)(dg, dq, asan_block);
}
INTERCEPTOR(void, dispatch_after,
dispatch_time_t when, dispatch_queue_t queue, void(^work)(void)) {
+ ENABLE_FRAME_POINTER;
GET_ASAN_BLOCK(work);
REAL(dispatch_after)(when, queue, asan_block);
}
INTERCEPTOR(void, dispatch_source_set_cancel_handler,
dispatch_source_t ds, void(^work)(void)) {
+ ENABLE_FRAME_POINTER;
GET_ASAN_BLOCK(work);
REAL(dispatch_source_set_cancel_handler)(ds, asan_block);
}
INTERCEPTOR(void, dispatch_source_set_event_handler,
dispatch_source_t ds, void(^work)(void)) {
+ ENABLE_FRAME_POINTER;
GET_ASAN_BLOCK(work);
REAL(dispatch_source_set_event_handler)(ds, asan_block);
}
diff --git a/lib/asan/asan_mac.h b/lib/asan/asan_mac.h
deleted file mode 100644
index 827b8b001699..000000000000
--- a/lib/asan/asan_mac.h
+++ /dev/null
@@ -1,59 +0,0 @@
-//===-- asan_mac.h ----------------------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file is a part of AddressSanitizer, an address sanity checker.
-//
-// Mac-specific ASan definitions.
-//===----------------------------------------------------------------------===//
-#ifndef ASAN_MAC_H
-#define ASAN_MAC_H
-
-// CF_RC_BITS, the layout of CFRuntimeBase and __CFStrIsConstant are internal
-// and subject to change in further CoreFoundation versions. Apple does not
-// guarantee any binary compatibility from release to release.
-
-// See http://opensource.apple.com/source/CF/CF-635.15/CFInternal.h
-#if defined(__BIG_ENDIAN__)
-#define CF_RC_BITS 0
-#endif
-
-#if defined(__LITTLE_ENDIAN__)
-#define CF_RC_BITS 3
-#endif
-
-// See http://opensource.apple.com/source/CF/CF-635.15/CFRuntime.h
-typedef struct __CFRuntimeBase {
- uptr _cfisa;
- u8 _cfinfo[4];
-#if __LP64__
- u32 _rc;
-#endif
-} CFRuntimeBase;
-
-enum MacosVersion {
- MACOS_VERSION_UNINITIALIZED = 0,
- MACOS_VERSION_UNKNOWN,
- MACOS_VERSION_LEOPARD,
- MACOS_VERSION_SNOW_LEOPARD,
- MACOS_VERSION_LION,
- MACOS_VERSION_MOUNTAIN_LION,
- MACOS_VERSION_MAVERICKS
-};
-
-// Used by asan_malloc_mac.cc and asan_mac.cc
-extern "C" void __CFInitialize();
-
-namespace __asan {
-
-MacosVersion GetMacosVersion();
-void MaybeReplaceCFAllocator();
-
-} // namespace __asan
-
-#endif // ASAN_MAC_H
diff --git a/lib/asan/asan_malloc_linux.cc b/lib/asan/asan_malloc_linux.cc
index 24b7f6977927..46a6a9db4a81 100644
--- a/lib/asan/asan_malloc_linux.cc
+++ b/lib/asan/asan_malloc_linux.cc
@@ -15,48 +15,14 @@
//===----------------------------------------------------------------------===//
#include "sanitizer_common/sanitizer_platform.h"
-#if SANITIZER_LINUX
+#if SANITIZER_FREEBSD || SANITIZER_LINUX
+#include "sanitizer_common/sanitizer_tls_get_addr.h"
#include "asan_allocator.h"
#include "asan_interceptors.h"
#include "asan_internal.h"
#include "asan_stack.h"
-#if SANITIZER_ANDROID
-DECLARE_REAL_AND_INTERCEPTOR(void*, malloc, uptr size)
-DECLARE_REAL_AND_INTERCEPTOR(void, free, void *ptr)
-DECLARE_REAL_AND_INTERCEPTOR(void*, calloc, uptr nmemb, uptr size)
-DECLARE_REAL_AND_INTERCEPTOR(void*, realloc, void *ptr, uptr size)
-DECLARE_REAL_AND_INTERCEPTOR(void*, memalign, uptr boundary, uptr size)
-
-struct MallocDebug {
- void* (*malloc)(uptr bytes);
- void (*free)(void* mem);
- void* (*calloc)(uptr n_elements, uptr elem_size);
- void* (*realloc)(void* oldMem, uptr bytes);
- void* (*memalign)(uptr alignment, uptr bytes);
-};
-
-const MallocDebug asan_malloc_dispatch ALIGNED(32) = {
- WRAP(malloc), WRAP(free), WRAP(calloc), WRAP(realloc), WRAP(memalign)
-};
-
-extern "C" const MallocDebug* __libc_malloc_dispatch;
-
-namespace __asan {
-void ReplaceSystemMalloc() {
- __libc_malloc_dispatch = &asan_malloc_dispatch;
-}
-} // namespace __asan
-
-#else // ANDROID
-
-namespace __asan {
-void ReplaceSystemMalloc() {
-}
-} // namespace __asan
-#endif // ANDROID
-
// ---------------------- Replacement functions ---------------- {{{1
using namespace __asan; // NOLINT
@@ -76,7 +42,7 @@ INTERCEPTOR(void*, malloc, uptr size) {
}
INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) {
- if (!asan_inited) {
+ 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];
@@ -101,8 +67,17 @@ INTERCEPTOR(void*, memalign, uptr boundary, uptr size) {
return asan_memalign(boundary, size, &stack, FROM_MALLOC);
}
-INTERCEPTOR(void*, __libc_memalign, uptr align, uptr s)
- ALIAS("memalign");
+INTERCEPTOR(void*, aligned_alloc, uptr boundary, uptr size) {
+ GET_STACK_TRACE_MALLOC;
+ return asan_memalign(boundary, size, &stack, FROM_MALLOC);
+}
+
+INTERCEPTOR(void*, __libc_memalign, uptr boundary, uptr size) {
+ GET_STACK_TRACE_MALLOC;
+ void *res = asan_memalign(boundary, size, &stack, FROM_MALLOC);
+ DTLS_on_libc_memalign(res, size * boundary);
+ return res;
+}
INTERCEPTOR(uptr, malloc_usable_size, void *ptr) {
GET_CURRENT_PC_BP_SP;
@@ -148,4 +123,64 @@ INTERCEPTOR(void, malloc_stats, void) {
__asan_print_accumulated_stats();
}
-#endif // SANITIZER_LINUX
+#if SANITIZER_ANDROID
+// Format of __libc_malloc_dispatch has changed in Android L.
+// While we are moving towards a solution that does not depend on bionic
+// internals, here is something to support both K* and L releases.
+struct MallocDebugK {
+ void *(*malloc)(uptr bytes);
+ void (*free)(void *mem);
+ void *(*calloc)(uptr n_elements, uptr elem_size);
+ void *(*realloc)(void *oldMem, uptr bytes);
+ void *(*memalign)(uptr alignment, uptr bytes);
+ uptr (*malloc_usable_size)(void *mem);
+};
+
+struct MallocDebugL {
+ void *(*calloc)(uptr n_elements, uptr elem_size);
+ void (*free)(void *mem);
+ fake_mallinfo (*mallinfo)(void);
+ void *(*malloc)(uptr bytes);
+ uptr (*malloc_usable_size)(void *mem);
+ void *(*memalign)(uptr alignment, uptr bytes);
+ int (*posix_memalign)(void **memptr, uptr alignment, uptr size);
+ void* (*pvalloc)(uptr size);
+ void *(*realloc)(void *oldMem, uptr bytes);
+ void* (*valloc)(uptr size);
+};
+
+ALIGNED(32) const MallocDebugK asan_malloc_dispatch_k = {
+ WRAP(malloc), WRAP(free), WRAP(calloc),
+ WRAP(realloc), WRAP(memalign), WRAP(malloc_usable_size)};
+
+ALIGNED(32) const MallocDebugL asan_malloc_dispatch_l = {
+ WRAP(calloc), WRAP(free), WRAP(mallinfo),
+ WRAP(malloc), WRAP(malloc_usable_size), WRAP(memalign),
+ WRAP(posix_memalign), WRAP(pvalloc), WRAP(realloc),
+ WRAP(valloc)};
+
+namespace __asan {
+void ReplaceSystemMalloc() {
+ void **__libc_malloc_dispatch_p =
+ (void **)AsanDlSymNext("__libc_malloc_dispatch");
+ if (__libc_malloc_dispatch_p) {
+ // Decide on K vs L dispatch format by the presence of
+ // __libc_malloc_default_dispatch export in libc.
+ void *default_dispatch_p = AsanDlSymNext("__libc_malloc_default_dispatch");
+ if (default_dispatch_p)
+ *__libc_malloc_dispatch_p = (void *)&asan_malloc_dispatch_k;
+ else
+ *__libc_malloc_dispatch_p = (void *)&asan_malloc_dispatch_l;
+ }
+}
+} // namespace __asan
+
+#else // SANITIZER_ANDROID
+
+namespace __asan {
+void ReplaceSystemMalloc() {
+}
+} // namespace __asan
+#endif // SANITIZER_ANDROID
+
+#endif // SANITIZER_FREEBSD || SANITIZER_LINUX
diff --git a/lib/asan/asan_malloc_mac.cc b/lib/asan/asan_malloc_mac.cc
index f9f08f0201c2..79b6dfae10f6 100644
--- a/lib/asan/asan_malloc_mac.cc
+++ b/lib/asan/asan_malloc_mac.cc
@@ -24,10 +24,10 @@
#include "asan_allocator.h"
#include "asan_interceptors.h"
#include "asan_internal.h"
-#include "asan_mac.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.
@@ -41,7 +41,7 @@ static malloc_zone_t asan_zone;
INTERCEPTOR(malloc_zone_t *, malloc_create_zone,
vm_size_t start_size, unsigned zone_flags) {
- if (!asan_inited) __asan_init();
+ ENSURE_ASAN_INITED();
GET_STACK_TRACE_MALLOC;
uptr page_size = GetPageSizeCached();
uptr allocated_size = RoundUpTo(sizeof(asan_zone), page_size);
@@ -60,39 +60,39 @@ INTERCEPTOR(malloc_zone_t *, malloc_create_zone,
}
INTERCEPTOR(malloc_zone_t *, malloc_default_zone, void) {
- if (!asan_inited) __asan_init();
+ 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
- if (!asan_inited) __asan_init();
+ 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.
- if (!asan_inited) __asan_init();
+ ENSURE_ASAN_INITED();
}
INTERCEPTOR(int, malloc_make_nonpurgeable, void *ptr) {
// FIXME: ASan should support purgeable allocations. Ignoring them is fine
// for now.
- if (!asan_inited) __asan_init();
+ 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) {
- if (!asan_inited) __asan_init();
+ ENSURE_ASAN_INITED();
// Allocate |strlen("asan-") + 1 + internal_strlen(name)| bytes.
size_t buflen = 6 + (name ? internal_strlen(name) : 0);
- InternalScopedBuffer<char> new_name(buflen);
+ InternalScopedString new_name(buflen);
if (name && zone->introspect == asan_zone.introspect) {
- internal_snprintf(new_name.data(), buflen, "asan-%s", name);
+ new_name.append("asan-%s", name);
name = new_name.data();
}
@@ -102,44 +102,44 @@ INTERCEPTOR(void, malloc_set_zone_name, malloc_zone_t *zone, const char *name) {
}
INTERCEPTOR(void *, malloc, size_t size) {
- if (!asan_inited) __asan_init();
+ ENSURE_ASAN_INITED();
GET_STACK_TRACE_MALLOC;
void *res = asan_malloc(size, &stack);
return res;
}
INTERCEPTOR(void, free, void *ptr) {
- if (!asan_inited) __asan_init();
+ ENSURE_ASAN_INITED();
if (!ptr) return;
GET_STACK_TRACE_FREE;
asan_free(ptr, &stack, FROM_MALLOC);
}
INTERCEPTOR(void *, realloc, void *ptr, size_t size) {
- if (!asan_inited) __asan_init();
+ ENSURE_ASAN_INITED();
GET_STACK_TRACE_MALLOC;
return asan_realloc(ptr, size, &stack);
}
INTERCEPTOR(void *, calloc, size_t nmemb, size_t size) {
- if (!asan_inited) __asan_init();
+ ENSURE_ASAN_INITED();
GET_STACK_TRACE_MALLOC;
return asan_calloc(nmemb, size, &stack);
}
INTERCEPTOR(void *, valloc, size_t size) {
- if (!asan_inited) __asan_init();
+ ENSURE_ASAN_INITED();
GET_STACK_TRACE_MALLOC;
return asan_memalign(GetPageSizeCached(), size, &stack, FROM_MALLOC);
}
INTERCEPTOR(size_t, malloc_good_size, size_t size) {
- if (!asan_inited) __asan_init();
+ ENSURE_ASAN_INITED();
return asan_zone.introspect->good_size(&asan_zone, size);
}
INTERCEPTOR(int, posix_memalign, void **memptr, size_t alignment, size_t size) {
- if (!asan_inited) __asan_init();
+ ENSURE_ASAN_INITED();
CHECK(memptr);
GET_STACK_TRACE_MALLOC;
void *result = asan_memalign(alignment, size, &stack, FROM_MALLOC);
@@ -159,7 +159,7 @@ size_t mz_size(malloc_zone_t* zone, const void* ptr) {
}
void *mz_malloc(malloc_zone_t *zone, size_t size) {
- if (!asan_inited) {
+ if (UNLIKELY(!asan_inited)) {
CHECK(system_malloc_zone);
return malloc_zone_malloc(system_malloc_zone, size);
}
@@ -168,7 +168,7 @@ void *mz_malloc(malloc_zone_t *zone, size_t size) {
}
void *mz_calloc(malloc_zone_t *zone, size_t nmemb, size_t size) {
- if (!asan_inited) {
+ 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];
@@ -184,7 +184,7 @@ void *mz_calloc(malloc_zone_t *zone, size_t nmemb, size_t size) {
}
void *mz_valloc(malloc_zone_t *zone, size_t size) {
- if (!asan_inited) {
+ if (UNLIKELY(!asan_inited)) {
CHECK(system_malloc_zone);
return malloc_zone_valloc(system_malloc_zone, size);
}
@@ -242,7 +242,7 @@ void mz_destroy(malloc_zone_t* zone) {
#if defined(MAC_OS_X_VERSION_10_6) && \
MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
void *mz_memalign(malloc_zone_t *zone, size_t align, size_t size) {
- if (!asan_inited) {
+ if (UNLIKELY(!asan_inited)) {
CHECK(system_malloc_zone);
return malloc_zone_memalign(system_malloc_zone, align, size);
}
diff --git a/lib/asan/asan_malloc_win.cc b/lib/asan/asan_malloc_win.cc
index 73e4c825092c..c99e31234951 100644
--- a/lib/asan/asan_malloc_win.cc
+++ b/lib/asan/asan_malloc_win.cc
@@ -23,71 +23,77 @@
#include <stddef.h>
-// ---------------------- Replacement functions ---------------- {{{1
using namespace __asan; // NOLINT
-// FIXME: Simply defining functions with the same signature in *.obj
-// files overrides the standard functions in *.lib
-// This works well for simple helloworld-like tests but might need to be
-// revisited in the future.
+// MT: Simply defining functions with the same signature in *.obj
+// files overrides the standard functions in the CRT.
+// MD: Memory allocation functions are defined in the CRT .dll,
+// so we have to intercept them before they are called for the first time.
+
+#if ASAN_DYNAMIC
+# define ALLOCATION_FUNCTION_ATTRIBUTE
+#else
+# define ALLOCATION_FUNCTION_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
+#endif
extern "C" {
-SANITIZER_INTERFACE_ATTRIBUTE
+ALLOCATION_FUNCTION_ATTRIBUTE
void free(void *ptr) {
GET_STACK_TRACE_FREE;
return asan_free(ptr, &stack, FROM_MALLOC);
}
-SANITIZER_INTERFACE_ATTRIBUTE
-void _free_dbg(void* ptr, int) {
+ALLOCATION_FUNCTION_ATTRIBUTE
+void _free_dbg(void *ptr, int) {
free(ptr);
}
+ALLOCATION_FUNCTION_ATTRIBUTE
void cfree(void *ptr) {
- CHECK(!"cfree() should not be used on Windows?");
+ CHECK(!"cfree() should not be used on Windows");
}
-SANITIZER_INTERFACE_ATTRIBUTE
+ALLOCATION_FUNCTION_ATTRIBUTE
void *malloc(size_t size) {
GET_STACK_TRACE_MALLOC;
return asan_malloc(size, &stack);
}
-SANITIZER_INTERFACE_ATTRIBUTE
-void* _malloc_dbg(size_t size, int , const char*, int) {
+ALLOCATION_FUNCTION_ATTRIBUTE
+void *_malloc_dbg(size_t size, int, const char *, int) {
return malloc(size);
}
-SANITIZER_INTERFACE_ATTRIBUTE
+ALLOCATION_FUNCTION_ATTRIBUTE
void *calloc(size_t nmemb, size_t size) {
GET_STACK_TRACE_MALLOC;
return asan_calloc(nmemb, size, &stack);
}
-SANITIZER_INTERFACE_ATTRIBUTE
-void* _calloc_dbg(size_t n, size_t size, int, const char*, int) {
- return calloc(n, size);
+ALLOCATION_FUNCTION_ATTRIBUTE
+void *_calloc_dbg(size_t nmemb, size_t size, int, const char *, int) {
+ return calloc(nmemb, size);
}
-SANITIZER_INTERFACE_ATTRIBUTE
+ALLOCATION_FUNCTION_ATTRIBUTE
void *_calloc_impl(size_t nmemb, size_t size, int *errno_tmp) {
return calloc(nmemb, size);
}
-SANITIZER_INTERFACE_ATTRIBUTE
+ALLOCATION_FUNCTION_ATTRIBUTE
void *realloc(void *ptr, size_t size) {
GET_STACK_TRACE_MALLOC;
return asan_realloc(ptr, size, &stack);
}
-SANITIZER_INTERFACE_ATTRIBUTE
+ALLOCATION_FUNCTION_ATTRIBUTE
void *_realloc_dbg(void *ptr, size_t size, int) {
CHECK(!"_realloc_dbg should not exist!");
return 0;
}
-SANITIZER_INTERFACE_ATTRIBUTE
-void* _recalloc(void* p, size_t n, size_t elem_size) {
+ALLOCATION_FUNCTION_ATTRIBUTE
+void *_recalloc(void *p, size_t n, size_t elem_size) {
if (!p)
return calloc(n, elem_size);
const size_t size = n * elem_size;
@@ -96,13 +102,28 @@ void* _recalloc(void* p, size_t n, size_t elem_size) {
return realloc(p, size);
}
-SANITIZER_INTERFACE_ATTRIBUTE
+ALLOCATION_FUNCTION_ATTRIBUTE
size_t _msize(void *ptr) {
GET_CURRENT_PC_BP_SP;
(void)sp;
return asan_malloc_usable_size(ptr, pc, bp);
}
+ALLOCATION_FUNCTION_ATTRIBUTE
+void *_expand(void *memblock, size_t size) {
+ // _expand is used in realloc-like functions to resize the buffer if possible.
+ // We don't want memory to stand still while resizing buffers, so return 0.
+ return 0;
+}
+
+ALLOCATION_FUNCTION_ATTRIBUTE
+void *_expand_dbg(void *memblock, size_t size) {
+ return _expand(memblock, size);
+}
+
+// TODO(timurrrr): Might want to add support for _aligned_* allocation
+// functions to detect a bit more bugs. Those functions seem to wrap malloc().
+
int _CrtDbgReport(int, const char*, int,
const char*, const char*, ...) {
ShowStatsAndAbort();
@@ -118,37 +139,38 @@ int _CrtSetReportMode(int, int) {
}
} // extern "C"
-using __interception::GetRealFunctionAddress;
-
-// We don't want to include "windows.h" in this file to avoid extra attributes
-// set on malloc/free etc (e.g. dllimport), so declare a few things manually:
-extern "C" int __stdcall VirtualProtect(void* addr, size_t size,
- DWORD prot, DWORD *old_prot);
-const int PAGE_EXECUTE_READWRITE = 0x40;
-
namespace __asan {
void ReplaceSystemMalloc() {
-#if defined(_DLL)
-# ifdef _WIN64
-# error ReplaceSystemMalloc was not tested on x64
-# endif
- char *crt_malloc;
- if (GetRealFunctionAddress("malloc", (void**)&crt_malloc)) {
- // Replace malloc in the CRT dll with a jump to our malloc.
- DWORD old_prot, unused;
- CHECK(VirtualProtect(crt_malloc, 16, PAGE_EXECUTE_READWRITE, &old_prot));
- REAL(memset)(crt_malloc, 0xCC /* int 3 */, 16); // just in case.
-
- ptrdiff_t jmp_offset = (char*)malloc - (char*)crt_malloc - 5;
- crt_malloc[0] = 0xE9; // jmp, should be followed by an offset.
- REAL(memcpy)(crt_malloc + 1, &jmp_offset, sizeof(jmp_offset));
-
- CHECK(VirtualProtect(crt_malloc, 16, old_prot, &unused));
-
- // FYI: FlushInstructionCache is needed on Itanium etc but not on x86/x64.
- }
-
- // FIXME: investigate whether anything else is needed.
+#if defined(ASAN_DYNAMIC)
+ // We don't check the result because CRT might not be used in the process.
+ __interception::OverrideFunction("free", (uptr)free);
+ __interception::OverrideFunction("malloc", (uptr)malloc);
+ __interception::OverrideFunction("_malloc_crt", (uptr)malloc);
+ __interception::OverrideFunction("calloc", (uptr)calloc);
+ __interception::OverrideFunction("_calloc_crt", (uptr)calloc);
+ __interception::OverrideFunction("realloc", (uptr)realloc);
+ __interception::OverrideFunction("_realloc_crt", (uptr)realloc);
+ __interception::OverrideFunction("_recalloc", (uptr)_recalloc);
+ __interception::OverrideFunction("_recalloc_crt", (uptr)_recalloc);
+ __interception::OverrideFunction("_msize", (uptr)_msize);
+ __interception::OverrideFunction("_expand", (uptr)_expand);
+
+ // Override different versions of 'operator new' and 'operator delete'.
+ // No need to override the nothrow versions as they just wrap the throw
+ // versions.
+ // FIXME: Unfortunately, MSVC miscompiles the statements that take the
+ // addresses of the array versions of these operators,
+ // see https://connect.microsoft.com/VisualStudio/feedbackdetail/view/946992
+ // We might want to try to work around this by [inline] assembly or compiling
+ // parts of the RTL with Clang.
+ void *(*op_new)(size_t sz) = operator new;
+ void (*op_delete)(void *p) = operator delete;
+ void *(*op_array_new)(size_t sz) = operator new[];
+ void (*op_array_delete)(void *p) = operator delete[];
+ __interception::OverrideFunction("??2@YAPAXI@Z", (uptr)op_new);
+ __interception::OverrideFunction("??3@YAXPAX@Z", (uptr)op_delete);
+ __interception::OverrideFunction("??_U@YAPAXI@Z", (uptr)op_array_new);
+ __interception::OverrideFunction("??_V@YAXPAX@Z", (uptr)op_array_delete);
#endif
}
} // namespace __asan
diff --git a/lib/asan/asan_mapping.h b/lib/asan/asan_mapping.h
index 1fecaeb35e1e..2746754152b6 100644
--- a/lib/asan/asan_mapping.h
+++ b/lib/asan/asan_mapping.h
@@ -43,54 +43,87 @@
// || `[0x00007fff8000, 0x00008fff6fff]` || LowShadow ||
// || `[0x000000000000, 0x00007fff7fff]` || LowMem ||
//
-// Default Linux/i386 mapping:
+// Default Linux/i386 mapping on x86_64 machine:
// || `[0x40000000, 0xffffffff]` || HighMem ||
// || `[0x28000000, 0x3fffffff]` || HighShadow ||
// || `[0x24000000, 0x27ffffff]` || ShadowGap ||
// || `[0x20000000, 0x23ffffff]` || LowShadow ||
// || `[0x00000000, 0x1fffffff]` || LowMem ||
//
+// Default Linux/i386 mapping on i386 machine
+// (addresses starting with 0xc0000000 are reserved
+// for kernel and thus not sanitized):
+// || `[0x38000000, 0xbfffffff]` || HighMem ||
+// || `[0x27000000, 0x37ffffff]` || HighShadow ||
+// || `[0x24000000, 0x26ffffff]` || ShadowGap ||
+// || `[0x20000000, 0x23ffffff]` || LowShadow ||
+// || `[0x00000000, 0x1fffffff]` || LowMem ||
+//
// Default Linux/MIPS mapping:
-// || `[0x2aaa8000, 0xffffffff]` || HighMem ||
-// || `[0x0fffd000, 0x2aaa7fff]` || HighShadow ||
-// || `[0x0bffd000, 0x0fffcfff]` || ShadowGap ||
-// || `[0x0aaa8000, 0x0bffcfff]` || LowShadow ||
-// || `[0x00000000, 0x0aaa7fff]` || LowMem ||
+// || `[0x2aaa0000, 0xffffffff]` || HighMem ||
+// || `[0x0fff4000, 0x2aa9ffff]` || HighShadow ||
+// || `[0x0bff4000, 0x0fff3fff]` || ShadowGap ||
+// || `[0x0aaa0000, 0x0bff3fff]` || LowShadow ||
+// || `[0x00000000, 0x0aa9ffff]` || LowMem ||
+//
+// Shadow mapping on FreeBSD/x86-64 with SHADOW_OFFSET == 0x400000000000:
+// || `[0x500000000000, 0x7fffffffffff]` || HighMem ||
+// || `[0x4a0000000000, 0x4fffffffffff]` || HighShadow ||
+// || `[0x480000000000, 0x49ffffffffff]` || ShadowGap ||
+// || `[0x400000000000, 0x47ffffffffff]` || LowShadow ||
+// || `[0x000000000000, 0x3fffffffffff]` || LowMem ||
+//
+// Shadow mapping on FreeBSD/i386 with SHADOW_OFFSET == 0x40000000:
+// || `[0x60000000, 0xffffffff]` || HighMem ||
+// || `[0x4c000000, 0x5fffffff]` || HighShadow ||
+// || `[0x48000000, 0x4bffffff]` || ShadowGap ||
+// || `[0x40000000, 0x47ffffff]` || LowShadow ||
+// || `[0x00000000, 0x3fffffff]` || LowMem ||
static const u64 kDefaultShadowScale = 3;
-static const u64 kDefaultShadowOffset32 = 1ULL << 29;
+static const u64 kDefaultShadowOffset32 = 1ULL << 29; // 0x20000000
+static const u64 kIosShadowOffset32 = 1ULL << 30; // 0x40000000
static const u64 kDefaultShadowOffset64 = 1ULL << 44;
static const u64 kDefaultShort64bitShadowOffset = 0x7FFF8000; // < 2G.
+static const u64 kAArch64_ShadowOffset64 = 1ULL << 36;
+static const u64 kMIPS32_ShadowOffset32 = 0x0aaa0000;
+static const u64 kMIPS64_ShadowOffset64 = 1ULL << 36;
static const u64 kPPC64_ShadowOffset64 = 1ULL << 41;
-static const u64 kMIPS32_ShadowOffset32 = 0x0aaa8000;
+static const u64 kFreeBSD_ShadowOffset32 = 1ULL << 30; // 0x40000000
+static const u64 kFreeBSD_ShadowOffset64 = 1ULL << 46; // 0x400000000000
-#if ASAN_FLEXIBLE_MAPPING_AND_OFFSET == 1
-extern SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_mapping_scale;
-extern SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_mapping_offset;
-# define SHADOW_SCALE (__asan_mapping_scale)
-# define SHADOW_OFFSET (__asan_mapping_offset)
+#define SHADOW_SCALE kDefaultShadowScale
+#if SANITIZER_ANDROID
+# define SHADOW_OFFSET (0)
#else
-# define SHADOW_SCALE kDefaultShadowScale
-# if SANITIZER_ANDROID
-# define SHADOW_OFFSET (0)
-# else
-# if SANITIZER_WORDSIZE == 32
-# if defined(__mips__)
-# define SHADOW_OFFSET kMIPS32_ShadowOffset32
-# else
-# define SHADOW_OFFSET kDefaultShadowOffset32
-# endif
+# if SANITIZER_WORDSIZE == 32
+# if defined(__mips__)
+# define SHADOW_OFFSET kMIPS32_ShadowOffset32
+# elif SANITIZER_FREEBSD
+# define SHADOW_OFFSET kFreeBSD_ShadowOffset32
# else
-# if defined(__powerpc64__)
+# if SANITIZER_IOS
+# define SHADOW_OFFSET kIosShadowOffset32
+# else
+# define SHADOW_OFFSET kDefaultShadowOffset32
+# endif
+# endif
+# else
+# if defined(__aarch64__)
+# define SHADOW_OFFSET kAArch64_ShadowOffset64
+# elif defined(__powerpc64__)
# define SHADOW_OFFSET kPPC64_ShadowOffset64
-# elif SANITIZER_MAC
-# define SHADOW_OFFSET kDefaultShadowOffset64
-# else
-# define SHADOW_OFFSET kDefaultShort64bitShadowOffset
-# endif
+# elif SANITIZER_FREEBSD
+# define SHADOW_OFFSET kFreeBSD_ShadowOffset64
+# elif SANITIZER_MAC
+# define SHADOW_OFFSET kDefaultShadowOffset64
+# elif defined(__mips64)
+# define SHADOW_OFFSET kMIPS64_ShadowOffset64
+# else
+# define SHADOW_OFFSET kDefaultShort64bitShadowOffset
# endif
# endif
-#endif // ASAN_FLEXIBLE_MAPPING_AND_OFFSET
+#endif
#define SHADOW_GRANULARITY (1ULL << SHADOW_SCALE)
#define MEM_TO_SHADOW(mem) (((mem) >> SHADOW_SCALE) + (SHADOW_OFFSET))
diff --git a/lib/asan/asan_new_delete.cc b/lib/asan/asan_new_delete.cc
index d5eb6eca9321..e48bdaf03dd3 100644
--- a/lib/asan/asan_new_delete.cc
+++ b/lib/asan/asan_new_delete.cc
@@ -16,20 +16,21 @@
#include "asan_internal.h"
#include "asan_stack.h"
+#include "interception/interception.h"
+
#include <stddef.h>
-namespace __asan {
-// This function is a no-op. We need it to make sure that object file
-// with our replacements will actually be loaded from static ASan
-// run-time library at link-time.
-void ReplaceOperatorsNewAndDelete() { }
-}
+// C++ operators can't have visibility attributes on Windows.
+#if SANITIZER_WINDOWS
+# define CXX_OPERATOR_ATTRIBUTE
+#else
+# define CXX_OPERATOR_ATTRIBUTE INTERCEPTOR_ATTRIBUTE
+#endif
using namespace __asan; // NOLINT
-// On Android new() goes through malloc interceptors.
-// See also https://code.google.com/p/address-sanitizer/issues/detail?id=131.
-#if !SANITIZER_ANDROID
+// This code has issues on OSX.
+// See https://code.google.com/p/address-sanitizer/issues/detail?id=131.
// Fake std::nothrow_t to avoid including <new>.
namespace std {
@@ -48,14 +49,23 @@ struct nothrow_t {};
// To make sure that C++ allocation/deallocation operators are overridden on
// OS X we need to intercept them using their mangled names.
#if !SANITIZER_MAC
-INTERCEPTOR_ATTRIBUTE
+// FreeBSD prior v9.2 have wrong definition of 'size_t'.
+// http://svnweb.freebsd.org/base?view=revision&revision=232261
+#if SANITIZER_FREEBSD && SANITIZER_WORDSIZE == 32
+#include <sys/param.h>
+#if __FreeBSD_version <= 902001 // v9.2
+#define size_t unsigned
+#endif // __FreeBSD_version
+#endif // SANITIZER_FREEBSD && SANITIZER_WORDSIZE == 32
+
+CXX_OPERATOR_ATTRIBUTE
void *operator new(size_t size) { OPERATOR_NEW_BODY(FROM_NEW); }
-INTERCEPTOR_ATTRIBUTE
+CXX_OPERATOR_ATTRIBUTE
void *operator new[](size_t size) { OPERATOR_NEW_BODY(FROM_NEW_BR); }
-INTERCEPTOR_ATTRIBUTE
+CXX_OPERATOR_ATTRIBUTE
void *operator new(size_t size, std::nothrow_t const&)
{ OPERATOR_NEW_BODY(FROM_NEW); }
-INTERCEPTOR_ATTRIBUTE
+CXX_OPERATOR_ATTRIBUTE
void *operator new[](size_t size, std::nothrow_t const&)
{ OPERATOR_NEW_BODY(FROM_NEW_BR); }
@@ -79,16 +89,32 @@ INTERCEPTOR(void *, _ZnamRKSt9nothrow_t, size_t size, std::nothrow_t const&) {
asan_free(ptr, &stack, type);
#if !SANITIZER_MAC
-INTERCEPTOR_ATTRIBUTE
-void operator delete(void *ptr) { OPERATOR_DELETE_BODY(FROM_NEW); }
-INTERCEPTOR_ATTRIBUTE
-void operator delete[](void *ptr) { OPERATOR_DELETE_BODY(FROM_NEW_BR); }
-INTERCEPTOR_ATTRIBUTE
-void operator delete(void *ptr, std::nothrow_t const&)
-{ OPERATOR_DELETE_BODY(FROM_NEW); }
-INTERCEPTOR_ATTRIBUTE
-void operator delete[](void *ptr, std::nothrow_t const&)
-{ OPERATOR_DELETE_BODY(FROM_NEW_BR); }
+CXX_OPERATOR_ATTRIBUTE
+void operator delete(void *ptr) throw() {
+ OPERATOR_DELETE_BODY(FROM_NEW);
+}
+CXX_OPERATOR_ATTRIBUTE
+void operator delete[](void *ptr) throw() {
+ OPERATOR_DELETE_BODY(FROM_NEW_BR);
+}
+CXX_OPERATOR_ATTRIBUTE
+void operator delete(void *ptr, std::nothrow_t const&) {
+ OPERATOR_DELETE_BODY(FROM_NEW);
+}
+CXX_OPERATOR_ATTRIBUTE
+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() {
+ GET_STACK_TRACE_FREE;
+ asan_sized_free(ptr, size, &stack, FROM_NEW);
+}
+CXX_OPERATOR_ATTRIBUTE
+void operator delete[](void *ptr, size_t size) throw() {
+ GET_STACK_TRACE_FREE;
+ asan_sized_free(ptr, size, &stack, FROM_NEW_BR);
+}
#else // SANITIZER_MAC
INTERCEPTOR(void, _ZdlPv, void *ptr) {
@@ -104,5 +130,3 @@ INTERCEPTOR(void, _ZdaPvRKSt9nothrow_t, void *ptr, std::nothrow_t const&) {
OPERATOR_DELETE_BODY(FROM_NEW_BR);
}
#endif
-
-#endif
diff --git a/lib/asan/asan_poisoning.cc b/lib/asan/asan_poisoning.cc
index 280aaeb909a3..1c6e92f69c65 100644
--- a/lib/asan/asan_poisoning.cc
+++ b/lib/asan/asan_poisoning.cc
@@ -13,6 +13,8 @@
//===----------------------------------------------------------------------===//
#include "asan_poisoning.h"
+#include "asan_report.h"
+#include "asan_stack.h"
#include "sanitizer_common/sanitizer_libc.h"
#include "sanitizer_common/sanitizer_flags.h"
@@ -50,6 +52,36 @@ struct ShadowSegmentEndpoint {
}
};
+void FlushUnneededASanShadowMemory(uptr p, uptr size) {
+ // Since asan's mapping is compacting, the shadow chunk may be
+ // not page-aligned, so we only flush the page-aligned portion.
+ uptr page_size = GetPageSizeCached();
+ uptr shadow_beg = RoundUpTo(MemToShadow(p), page_size);
+ uptr shadow_end = RoundDownTo(MemToShadow(p + size), page_size);
+ FlushUnneededShadowMemory(shadow_beg, shadow_end - shadow_beg);
+}
+
+void AsanPoisonOrUnpoisonIntraObjectRedzone(uptr ptr, uptr size, bool poison) {
+ uptr end = ptr + size;
+ if (common_flags()->verbosity) {
+ Printf("__asan_%spoison_intra_object_redzone [%p,%p) %zd\n",
+ poison ? "" : "un", ptr, end, size);
+ if (common_flags()->verbosity >= 2)
+ PRINT_CURRENT_STACK();
+ }
+ CHECK(size);
+ CHECK_LE(size, 4096);
+ CHECK(IsAligned(end, SHADOW_GRANULARITY));
+ if (!IsAligned(ptr, SHADOW_GRANULARITY)) {
+ *(u8 *)MemToShadow(ptr) =
+ poison ? static_cast<u8>(ptr % SHADOW_GRANULARITY) : 0;
+ ptr |= SHADOW_GRANULARITY - 1;
+ ptr++;
+ }
+ for (; ptr < end; ptr += SHADOW_GRANULARITY)
+ *(u8*)MemToShadow(ptr) = poison ? kAsanIntraObjectRedzone : 0;
+}
+
} // namespace __asan
// ---------------------- Interface ---------------- {{{1
@@ -69,10 +101,8 @@ void __asan_poison_memory_region(void const volatile *addr, uptr size) {
if (!flags()->allow_user_poisoning || size == 0) return;
uptr beg_addr = (uptr)addr;
uptr end_addr = beg_addr + size;
- if (common_flags()->verbosity >= 1) {
- Printf("Trying to poison memory region [%p, %p)\n",
- (void*)beg_addr, (void*)end_addr);
- }
+ VPrintf(1, "Trying to poison memory region [%p, %p)\n", (void *)beg_addr,
+ (void *)end_addr);
ShadowSegmentEndpoint beg(beg_addr);
ShadowSegmentEndpoint end(end_addr);
if (beg.chunk == end.chunk) {
@@ -111,10 +141,8 @@ void __asan_unpoison_memory_region(void const volatile *addr, uptr size) {
if (!flags()->allow_user_poisoning || size == 0) return;
uptr beg_addr = (uptr)addr;
uptr end_addr = beg_addr + size;
- if (common_flags()->verbosity >= 1) {
- Printf("Trying to unpoison memory region [%p, %p)\n",
- (void*)beg_addr, (void*)end_addr);
- }
+ VPrintf(1, "Trying to unpoison memory region [%p, %p)\n", (void *)beg_addr,
+ (void *)end_addr);
ShadowSegmentEndpoint beg(beg_addr);
ShadowSegmentEndpoint end(end_addr);
if (beg.chunk == end.chunk) {
@@ -139,7 +167,7 @@ void __asan_unpoison_memory_region(void const volatile *addr, uptr size) {
}
}
-bool __asan_address_is_poisoned(void const volatile *addr) {
+int __asan_address_is_poisoned(void const volatile *addr) {
return __asan::AddressIsPoisoned((uptr)addr);
}
@@ -148,6 +176,7 @@ uptr __asan_region_is_poisoned(uptr beg, uptr size) {
uptr end = beg + size;
if (!AddrIsInMem(beg)) return beg;
if (!AddrIsInMem(end)) return end;
+ CHECK_LT(beg, end);
uptr aligned_b = RoundUpTo(beg, SHADOW_GRANULARITY);
uptr aligned_e = RoundDownTo(end, SHADOW_GRANULARITY);
uptr shadow_beg = MemToShadow(aligned_b);
@@ -219,6 +248,36 @@ void __sanitizer_unaligned_store64(uu64 *p, u64 x) {
*p = x;
}
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+void __asan_poison_cxx_array_cookie(uptr p) {
+ if (SANITIZER_WORDSIZE != 64) return;
+ if (!flags()->poison_array_cookie) return;
+ uptr s = MEM_TO_SHADOW(p);
+ *reinterpret_cast<u8*>(s) = kAsanArrayCookieMagic;
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+uptr __asan_load_cxx_array_cookie(uptr *p) {
+ if (SANITIZER_WORDSIZE != 64) return *p;
+ if (!flags()->poison_array_cookie) return *p;
+ uptr s = MEM_TO_SHADOW(reinterpret_cast<uptr>(p));
+ u8 sval = *reinterpret_cast<u8*>(s);
+ if (sval == kAsanArrayCookieMagic) return *p;
+ // If sval is not kAsanArrayCookieMagic it can only be freed memory,
+ // which means that we are going to get double-free. So, return 0 to avoid
+ // infinite loop of destructors. We don't want to report a double-free here
+ // though, so print a warning just in case.
+ // CHECK_EQ(sval, kAsanHeapFreeMagic);
+ if (sval == kAsanHeapFreeMagic) {
+ Report("AddressSanitizer: loaded array cookie from free-d memory; "
+ "expect a double-free report\n");
+ return 0;
+ }
+ // The cookie may remain unpoisoned if e.g. it comes from a custom
+ // operator new defined inside a class.
+ return *p;
+}
+
// This is a simplified version of __asan_(un)poison_memory_region, which
// assumes that left border of region to be poisoned is properly aligned.
static void PoisonAlignedStackMemory(uptr addr, uptr size, bool do_poison) {
@@ -245,55 +304,113 @@ static void PoisonAlignedStackMemory(uptr addr, uptr size, bool do_poison) {
}
void __asan_poison_stack_memory(uptr addr, uptr size) {
- if (common_flags()->verbosity > 0)
- Report("poisoning: %p %zx\n", (void*)addr, size);
+ VReport(1, "poisoning: %p %zx\n", (void *)addr, size);
PoisonAlignedStackMemory(addr, size, true);
}
void __asan_unpoison_stack_memory(uptr addr, uptr size) {
- if (common_flags()->verbosity > 0)
- Report("unpoisoning: %p %zx\n", (void*)addr, size);
+ VReport(1, "unpoisoning: %p %zx\n", (void *)addr, size);
PoisonAlignedStackMemory(addr, size, false);
}
-void __sanitizer_annotate_contiguous_container(void *beg_p, void *end_p,
- void *old_mid_p,
- void *new_mid_p) {
+void __sanitizer_annotate_contiguous_container(const void *beg_p,
+ const void *end_p,
+ const void *old_mid_p,
+ const void *new_mid_p) {
+ if (!flags()->detect_container_overflow) return;
+ VPrintf(2, "contiguous_container: %p %p %p %p\n", beg_p, end_p, old_mid_p,
+ new_mid_p);
uptr beg = reinterpret_cast<uptr>(beg_p);
- uptr end= reinterpret_cast<uptr>(end_p);
+ uptr end = reinterpret_cast<uptr>(end_p);
uptr old_mid = reinterpret_cast<uptr>(old_mid_p);
uptr new_mid = reinterpret_cast<uptr>(new_mid_p);
uptr granularity = SHADOW_GRANULARITY;
- CHECK(beg <= end && beg <= old_mid && beg <= new_mid && old_mid <= end &&
- new_mid <= end && IsAligned(beg, granularity));
+ if (!(beg <= old_mid && beg <= new_mid && old_mid <= end && new_mid <= end &&
+ IsAligned(beg, granularity))) {
+ GET_STACK_TRACE_FATAL_HERE;
+ ReportBadParamsToAnnotateContiguousContainer(beg, end, old_mid, new_mid,
+ &stack);
+ }
CHECK_LE(end - beg,
FIRST_32_SECOND_64(1UL << 30, 1UL << 34)); // Sanity check.
uptr a = RoundDownTo(Min(old_mid, new_mid), granularity);
uptr c = RoundUpTo(Max(old_mid, new_mid), granularity);
- uptr b = new_mid;
- uptr b1 = RoundDownTo(b, granularity);
- uptr b2 = RoundUpTo(b, granularity);
- uptr d = old_mid;
- uptr d1 = RoundDownTo(d, granularity);
- uptr d2 = RoundUpTo(d, granularity);
+ uptr d1 = RoundDownTo(old_mid, granularity);
+ // uptr d2 = RoundUpTo(old_mid, granularity);
// Currently we should be in this state:
// [a, d1) is good, [d2, c) is bad, [d1, d2) is partially good.
// Make a quick sanity check that we are indeed in this state.
- if (d1 != d2)
- CHECK_EQ(*(u8*)MemToShadow(d1), d - d1);
+ //
+ // FIXME: Two of these three checks are disabled until we fix
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=258.
+ // if (d1 != d2)
+ // CHECK_EQ(*(u8*)MemToShadow(d1), old_mid - d1);
if (a + granularity <= d1)
CHECK_EQ(*(u8*)MemToShadow(a), 0);
- if (d2 + granularity <= c && c <= end)
- CHECK_EQ(*(u8 *)MemToShadow(c - granularity), kAsanUserPoisonedMemoryMagic);
+ // if (d2 + granularity <= c && c <= end)
+ // CHECK_EQ(*(u8 *)MemToShadow(c - granularity),
+ // kAsanContiguousContainerOOBMagic);
+ uptr b1 = RoundDownTo(new_mid, granularity);
+ uptr b2 = RoundUpTo(new_mid, granularity);
// New state:
// [a, b1) is good, [b2, c) is bad, [b1, b2) is partially good.
- // FIXME: we may want to have a separate poison magic value.
PoisonShadow(a, b1 - a, 0);
- PoisonShadow(b2, c - b2, kAsanUserPoisonedMemoryMagic);
+ PoisonShadow(b2, c - b2, kAsanContiguousContainerOOBMagic);
if (b1 != b2) {
CHECK_EQ(b2 - b1, granularity);
- *(u8*)MemToShadow(b1) = static_cast<u8>(b - b1);
+ *(u8*)MemToShadow(b1) = static_cast<u8>(new_mid - b1);
}
}
+
+int __sanitizer_verify_contiguous_container(const void *beg_p,
+ const void *mid_p,
+ const void *end_p) {
+ if (!flags()->detect_container_overflow) return 1;
+ uptr beg = reinterpret_cast<uptr>(beg_p);
+ uptr end = reinterpret_cast<uptr>(end_p);
+ uptr mid = reinterpret_cast<uptr>(mid_p);
+ CHECK_LE(beg, mid);
+ CHECK_LE(mid, end);
+ // Check some bytes starting from beg, some bytes around mid, and some bytes
+ // ending with end.
+ uptr kMaxRangeToCheck = 32;
+ uptr r1_beg = beg;
+ uptr r1_end = Min(end + kMaxRangeToCheck, mid);
+ uptr r2_beg = Max(beg, mid - kMaxRangeToCheck);
+ uptr r2_end = Min(end, mid + kMaxRangeToCheck);
+ uptr r3_beg = Max(end - kMaxRangeToCheck, mid);
+ uptr r3_end = end;
+ for (uptr i = r1_beg; i < r1_end; i++)
+ if (AddressIsPoisoned(i))
+ return 0;
+ for (uptr i = r2_beg; i < mid; i++)
+ if (AddressIsPoisoned(i))
+ return 0;
+ for (uptr i = mid; i < r2_end; i++)
+ if (!AddressIsPoisoned(i))
+ return 0;
+ for (uptr i = r3_beg; i < r3_end; i++)
+ if (!AddressIsPoisoned(i))
+ return 0;
+ return 1;
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+void __asan_poison_intra_object_redzone(uptr ptr, uptr size) {
+ AsanPoisonOrUnpoisonIntraObjectRedzone(ptr, size, true);
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+void __asan_unpoison_intra_object_redzone(uptr ptr, uptr size) {
+ AsanPoisonOrUnpoisonIntraObjectRedzone(ptr, size, false);
+}
+
+// --- Implementation of LSan-specific functions --- {{{1
+namespace __lsan {
+bool WordIsPoisoned(uptr addr) {
+ return (__asan_region_is_poisoned(addr, sizeof(uptr)) != 0);
+}
+}
+
diff --git a/lib/asan/asan_poisoning.h b/lib/asan/asan_poisoning.h
index fbac21196b8f..feda1a984544 100644
--- a/lib/asan/asan_poisoning.h
+++ b/lib/asan/asan_poisoning.h
@@ -15,6 +15,7 @@
#include "asan_interceptors.h"
#include "asan_internal.h"
#include "asan_mapping.h"
+#include "sanitizer_common/sanitizer_flags.h"
namespace __asan {
@@ -37,7 +38,32 @@ ALWAYS_INLINE void FastPoisonShadow(uptr aligned_beg, uptr aligned_size,
uptr shadow_beg = MEM_TO_SHADOW(aligned_beg);
uptr shadow_end = MEM_TO_SHADOW(
aligned_beg + aligned_size - SHADOW_GRANULARITY) + 1;
- REAL(memset)((void*)shadow_beg, value, shadow_end - shadow_beg);
+ // FIXME: Page states are different on Windows, so using the same interface
+ // for mapping shadow and zeroing out pages doesn't "just work", so we should
+ // probably provide higher-level interface for these operations.
+ // For now, just memset on Windows.
+ if (value ||
+ SANITIZER_WINDOWS == 1 ||
+ shadow_end - shadow_beg < common_flags()->clear_shadow_mmap_threshold) {
+ REAL(memset)((void*)shadow_beg, value, shadow_end - shadow_beg);
+ } else {
+ uptr page_size = GetPageSizeCached();
+ uptr page_beg = RoundUpTo(shadow_beg, page_size);
+ uptr page_end = RoundDownTo(shadow_end, page_size);
+
+ if (page_beg >= page_end) {
+ REAL(memset)((void *)shadow_beg, 0, shadow_end - shadow_beg);
+ } else {
+ if (page_beg != shadow_beg) {
+ REAL(memset)((void *)shadow_beg, 0, page_beg - shadow_beg);
+ }
+ if (page_end != shadow_end) {
+ REAL(memset)((void *)page_end, 0, shadow_end - page_end);
+ }
+ void *res = MmapFixedNoReserve(page_beg, page_end - page_beg);
+ CHECK_EQ(page_beg, res);
+ }
+ }
}
ALWAYS_INLINE void FastPoisonShadowPartialRightRedzone(
@@ -57,4 +83,8 @@ ALWAYS_INLINE void FastPoisonShadowPartialRightRedzone(
}
}
+// Calls __sanitizer::FlushUnneededShadowMemory() on
+// [MemToShadow(p), MemToShadow(p+size)] with proper rounding.
+void FlushUnneededASanShadowMemory(uptr p, uptr size);
+
} // namespace __asan
diff --git a/lib/asan/asan_posix.cc b/lib/asan/asan_posix.cc
index bcc6b381a785..ad31458df28d 100644
--- a/lib/asan/asan_posix.cc
+++ b/lib/asan/asan_posix.cc
@@ -13,7 +13,7 @@
//===----------------------------------------------------------------------===//
#include "sanitizer_common/sanitizer_platform.h"
-#if SANITIZER_LINUX || SANITIZER_MAC
+#if SANITIZER_POSIX
#include "asan_internal.h"
#include "asan_interceptors.h"
@@ -30,70 +30,59 @@
#include <sys/resource.h>
#include <unistd.h>
-static const uptr kAltStackSize = SIGSTKSZ * 4; // SIGSTKSZ is not enough.
-
namespace __asan {
-static void MaybeInstallSigaction(int signum,
- void (*handler)(int, siginfo_t *, void *)) {
- if (!AsanInterceptsSignal(signum))
- return;
- struct sigaction sigact;
- REAL(memset)(&sigact, 0, sizeof(sigact));
- sigact.sa_sigaction = handler;
- sigact.sa_flags = SA_SIGINFO;
- if (flags()->use_sigaltstack) sigact.sa_flags |= SA_ONSTACK;
- CHECK_EQ(0, REAL(sigaction)(signum, &sigact, 0));
- if (common_flags()->verbosity >= 1) {
- Report("Installed the sigaction for signal %d\n", signum);
- }
-}
-
-static void ASAN_OnSIGSEGV(int, siginfo_t *siginfo, void *context) {
- uptr addr = (uptr)siginfo->si_addr;
- // Write the first message using the bullet-proof write.
- if (13 != internal_write(2, "ASAN:SIGSEGV\n", 13)) Die();
+SignalContext SignalContext::Create(void *siginfo, void *context) {
+ uptr addr = (uptr)((siginfo_t*)siginfo)->si_addr;
uptr pc, sp, bp;
GetPcSpBp(context, &pc, &sp, &bp);
- ReportSIGSEGV(pc, sp, bp, addr);
+ return SignalContext(context, addr, pc, sp, bp);
}
-void SetAlternateSignalStack() {
- stack_t altstack, oldstack;
- CHECK_EQ(0, sigaltstack(0, &oldstack));
- // If the alternate stack is already in place, do nothing.
- if ((oldstack.ss_flags & SS_DISABLE) == 0) return;
- // TODO(glider): the mapped stack should have the MAP_STACK flag in the
- // future. It is not required by man 2 sigaltstack now (they're using
- // malloc()).
- void* base = MmapOrDie(kAltStackSize, __FUNCTION__);
- altstack.ss_sp = base;
- altstack.ss_flags = 0;
- altstack.ss_size = kAltStackSize;
- CHECK_EQ(0, sigaltstack(&altstack, 0));
- if (common_flags()->verbosity > 0) {
- Report("Alternative stack for T%d set: [%p,%p)\n",
- GetCurrentTidOrInvalid(),
- altstack.ss_sp, (char*)altstack.ss_sp + altstack.ss_size);
+void AsanOnSIGSEGV(int, 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();
+ SignalContext sig = SignalContext::Create(siginfo, context);
+
+ // Access at a reasonable offset above SP, or slightly below it (to account
+ // for x86_64 or PowerPC redzone, ARM push of multiple registers, etc) is
+ // probably a stack overflow.
+ bool IsStackAccess = sig.addr + 512 > sig.sp && sig.addr < sig.sp + 0xFFFF;
+
+#if __powerpc__
+ // Large stack frames can be allocated with e.g.
+ // lis r0,-10000
+ // stdux r1,r1,r0 # store sp to [sp-10000] and update sp by -10000
+ // If the store faults then sp will not have been updated, so test above
+ // will not work, becase the fault address will be more than just "slightly"
+ // below sp.
+ if (!IsStackAccess && IsAccessibleMemoryRange(sig.pc, 4)) {
+ u32 inst = *(unsigned *)sig.pc;
+ u32 ra = (inst >> 16) & 0x1F;
+ u32 opcd = inst >> 26;
+ u32 xo = (inst >> 1) & 0x3FF;
+ // Check for store-with-update to sp. The instructions we accept are:
+ // stbu rs,d(ra) stbux rs,ra,rb
+ // sthu rs,d(ra) sthux rs,ra,rb
+ // stwu rs,d(ra) stwux rs,ra,rb
+ // stdu rs,ds(ra) stdux rs,ra,rb
+ // where ra is r1 (the stack pointer).
+ if (ra == 1 &&
+ (opcd == 39 || opcd == 45 || opcd == 37 || opcd == 62 ||
+ (opcd == 31 && (xo == 247 || xo == 439 || xo == 183 || xo == 181))))
+ IsStackAccess = true;
}
-}
-
-void UnsetAlternateSignalStack() {
- stack_t altstack, oldstack;
- altstack.ss_sp = 0;
- altstack.ss_flags = SS_DISABLE;
- altstack.ss_size = 0;
- CHECK_EQ(0, sigaltstack(&altstack, &oldstack));
- UnmapOrDie(oldstack.ss_sp, oldstack.ss_size);
-}
-
-void InstallSignalHandlers() {
- // Set the alternate signal stack for the main thread.
- // This will cause SetAlternateSignalStack to be called twice, but the stack
- // will be actually set only once.
- if (flags()->use_sigaltstack) SetAlternateSignalStack();
- MaybeInstallSigaction(SIGSEGV, ASAN_OnSIGSEGV);
- MaybeInstallSigaction(SIGBUS, ASAN_OnSIGSEGV);
+#endif // __powerpc__
+
+ // We also check si_code to filter out SEGV caused by something else other
+ // then hitting the guard page or unmapped memory, like, for example,
+ // unaligned memory access.
+ if (IsStackAccess && (code == si_SEGV_MAPERR || code == si_SEGV_ACCERR))
+ ReportStackOverflow(sig);
+ else
+ ReportSIGSEGV("SEGV", sig);
}
// ---------------------- TSD ---------------- {{{1
@@ -127,4 +116,4 @@ void PlatformTSDDtor(void *tsd) {
}
} // namespace __asan
-#endif // SANITIZER_LINUX || SANITIZER_MAC
+#endif // SANITIZER_POSIX
diff --git a/lib/asan/asan_preinit.cc b/lib/asan/asan_preinit.cc
index 586f551c23c3..a3986d24f9c3 100644
--- a/lib/asan/asan_preinit.cc
+++ b/lib/asan/asan_preinit.cc
@@ -10,22 +10,16 @@
// This file is a part of AddressSanitizer, an address sanity checker.
//
// Call __asan_init at the very early stage of process startup.
-// On Linux we use .preinit_array section (unless PIC macro is defined).
//===----------------------------------------------------------------------===//
#include "asan_internal.h"
-#if ASAN_USE_PREINIT_ARRAY && !defined(PIC)
- // On Linux, we force __asan_init to be called before anyone else
- // by placing it into .preinit_array section.
- // FIXME: do we have anything like this on Mac?
+using namespace __asan;
+
+#if SANITIZER_CAN_USE_PREINIT_ARRAY
// The symbol is called __local_asan_preinit, because it's not intended to be
// exported.
+ // This code linked into the main executable when -fsanitize=address is in
+ // the link flags. It can only use exported interface functions.
__attribute__((section(".preinit_array"), used))
void (*__local_asan_preinit)(void) = __asan_init;
-#elif SANITIZER_WINDOWS && defined(_DLL)
- // On Windows, when using dynamic CRT (/MD), we can put a pointer
- // to __asan_init into the global list of C initializers.
- // See crt0dat.c in the CRT sources for the details.
- #pragma section(".CRT$XIB", long, read) // NOLINT
- __declspec(allocate(".CRT$XIB")) void (*__asan_preinit)() = __asan_init;
#endif
diff --git a/lib/asan/asan_report.cc b/lib/asan/asan_report.cc
index ed4e433c7a54..0fb50276186b 100644
--- a/lib/asan/asan_report.cc
+++ b/lib/asan/asan_report.cc
@@ -31,6 +31,19 @@ static char *error_message_buffer = 0;
static uptr error_message_buffer_pos = 0;
static uptr error_message_buffer_size = 0;
+struct ReportData {
+ uptr pc;
+ uptr sp;
+ uptr bp;
+ uptr addr;
+ bool is_write;
+ uptr access_size;
+ const char *description;
+};
+
+static bool report_happened = false;
+static ReportData report_data = {};
+
void AppendToErrorMessageBuffer(const char *buffer) {
if (error_message_buffer) {
uptr length = internal_strlen(buffer);
@@ -45,11 +58,9 @@ void AppendToErrorMessageBuffer(const char *buffer) {
}
// ---------------------- Decorator ------------------------------ {{{1
-class Decorator: private __sanitizer::AnsiColorDecorator {
+class Decorator: public __sanitizer::SanitizerCommonDecorator {
public:
- Decorator() : __sanitizer::AnsiColorDecorator(PrintsToTtyCached()) { }
- const char *Warning() { return Red(); }
- const char *EndWarning() { return Default(); }
+ Decorator() : SanitizerCommonDecorator() { }
const char *Access() { return Blue(); }
const char *EndAccess() { return Default(); }
const char *Location() { return Green(); }
@@ -61,6 +72,7 @@ class Decorator: private __sanitizer::AnsiColorDecorator {
switch (byte) {
case kAsanHeapLeftRedzoneMagic:
case kAsanHeapRightRedzoneMagic:
+ case kAsanArrayCookieMagic:
return Red();
case kAsanHeapFreeMagic:
return Magenta();
@@ -74,6 +86,9 @@ class Decorator: private __sanitizer::AnsiColorDecorator {
case kAsanInitializationOrderMagic:
return Cyan();
case kAsanUserPoisonedMemoryMagic:
+ case kAsanContiguousContainerOOBMagic:
+ case kAsanAllocaLeftMagic:
+ case kAsanAllocaRightMagic:
return Blue();
case kAsanStackUseAfterScopeMagic:
return Magenta();
@@ -81,75 +96,119 @@ class Decorator: private __sanitizer::AnsiColorDecorator {
return Red();
case kAsanInternalHeapMagic:
return Yellow();
+ case kAsanIntraObjectRedzone:
+ return Yellow();
default:
return Default();
}
}
const char *EndShadowByte() { return Default(); }
+ const char *MemoryByte() { return Magenta(); }
+ const char *EndMemoryByte() { return Default(); }
};
// ---------------------- Helper functions ----------------------- {{{1
-static void PrintShadowByte(const char *before, u8 byte,
- const char *after = "\n") {
+static void PrintMemoryByte(InternalScopedString *str, const char *before,
+ u8 byte, bool in_shadow, const char *after = "\n") {
Decorator d;
- Printf("%s%s%x%x%s%s", before,
- d.ShadowByte(byte), byte >> 4, byte & 15, d.EndShadowByte(), after);
+ str->append("%s%s%x%x%s%s", before,
+ in_shadow ? d.ShadowByte(byte) : d.MemoryByte(),
+ byte >> 4, byte & 15,
+ in_shadow ? d.EndShadowByte() : d.EndMemoryByte(), after);
+}
+
+static void PrintShadowByte(InternalScopedString *str, const char *before,
+ u8 byte, const char *after = "\n") {
+ PrintMemoryByte(str, before, byte, /*in_shadow*/true, after);
}
-static void PrintShadowBytes(const char *before, u8 *bytes,
- u8 *guilty, uptr n) {
+static void PrintShadowBytes(InternalScopedString *str, const char *before,
+ u8 *bytes, u8 *guilty, uptr n) {
Decorator d;
- if (before)
- Printf("%s%p:", before, bytes);
+ if (before) str->append("%s%p:", before, bytes);
for (uptr i = 0; i < n; i++) {
u8 *p = bytes + i;
- const char *before = p == guilty ? "[" :
- (p - 1 == guilty && i != 0) ? "" : " ";
+ const char *before =
+ p == guilty ? "[" : (p - 1 == guilty && i != 0) ? "" : " ";
const char *after = p == guilty ? "]" : "";
- PrintShadowByte(before, *p, after);
+ PrintShadowByte(str, before, *p, after);
}
- Printf("\n");
-}
-
-static void PrintLegend() {
- Printf("Shadow byte legend (one shadow byte represents %d "
- "application bytes):\n", (int)SHADOW_GRANULARITY);
- PrintShadowByte(" Addressable: ", 0);
- Printf(" Partially addressable: ");
- for (u8 i = 1; i < SHADOW_GRANULARITY; i++)
- PrintShadowByte("", i, " ");
- Printf("\n");
- PrintShadowByte(" Heap left redzone: ", kAsanHeapLeftRedzoneMagic);
- PrintShadowByte(" Heap right redzone: ", kAsanHeapRightRedzoneMagic);
- PrintShadowByte(" Freed heap region: ", kAsanHeapFreeMagic);
- PrintShadowByte(" Stack left redzone: ", kAsanStackLeftRedzoneMagic);
- PrintShadowByte(" Stack mid redzone: ", kAsanStackMidRedzoneMagic);
- PrintShadowByte(" Stack right redzone: ", kAsanStackRightRedzoneMagic);
- PrintShadowByte(" Stack partial redzone: ", kAsanStackPartialRedzoneMagic);
- PrintShadowByte(" Stack after return: ", kAsanStackAfterReturnMagic);
- PrintShadowByte(" Stack use after scope: ", kAsanStackUseAfterScopeMagic);
- PrintShadowByte(" Global redzone: ", kAsanGlobalRedzoneMagic);
- PrintShadowByte(" Global init order: ", kAsanInitializationOrderMagic);
- PrintShadowByte(" Poisoned by user: ", kAsanUserPoisonedMemoryMagic);
- PrintShadowByte(" ASan internal: ", kAsanInternalHeapMagic);
+ str->append("\n");
}
-static void PrintShadowMemoryForAddress(uptr addr) {
- if (!AddrIsInMem(addr))
+static void PrintLegend(InternalScopedString *str) {
+ str->append(
+ "Shadow byte legend (one shadow byte represents %d "
+ "application bytes):\n",
+ (int)SHADOW_GRANULARITY);
+ PrintShadowByte(str, " Addressable: ", 0);
+ str->append(" Partially addressable: ");
+ for (u8 i = 1; i < SHADOW_GRANULARITY; i++) PrintShadowByte(str, "", i, " ");
+ str->append("\n");
+ PrintShadowByte(str, " Heap left redzone: ",
+ kAsanHeapLeftRedzoneMagic);
+ PrintShadowByte(str, " Heap right redzone: ",
+ kAsanHeapRightRedzoneMagic);
+ PrintShadowByte(str, " Freed heap region: ", kAsanHeapFreeMagic);
+ PrintShadowByte(str, " Stack left redzone: ",
+ kAsanStackLeftRedzoneMagic);
+ PrintShadowByte(str, " Stack mid redzone: ",
+ kAsanStackMidRedzoneMagic);
+ PrintShadowByte(str, " Stack right redzone: ",
+ kAsanStackRightRedzoneMagic);
+ PrintShadowByte(str, " Stack partial redzone: ",
+ kAsanStackPartialRedzoneMagic);
+ PrintShadowByte(str, " Stack after return: ",
+ kAsanStackAfterReturnMagic);
+ PrintShadowByte(str, " Stack use after scope: ",
+ kAsanStackUseAfterScopeMagic);
+ PrintShadowByte(str, " Global redzone: ", kAsanGlobalRedzoneMagic);
+ PrintShadowByte(str, " Global init order: ",
+ kAsanInitializationOrderMagic);
+ PrintShadowByte(str, " Poisoned by user: ",
+ kAsanUserPoisonedMemoryMagic);
+ PrintShadowByte(str, " Container overflow: ",
+ kAsanContiguousContainerOOBMagic);
+ PrintShadowByte(str, " Array cookie: ",
+ kAsanArrayCookieMagic);
+ PrintShadowByte(str, " Intra object redzone: ",
+ kAsanIntraObjectRedzone);
+ PrintShadowByte(str, " ASan internal: ", kAsanInternalHeapMagic);
+ PrintShadowByte(str, " Left alloca redzone: ", kAsanAllocaLeftMagic);
+ PrintShadowByte(str, " Right alloca redzone: ", kAsanAllocaRightMagic);
+}
+
+void MaybeDumpInstructionBytes(uptr pc) {
+ if (!flags()->dump_instruction_bytes || (pc < GetPageSizeCached()))
return;
+ InternalScopedString str(1024);
+ str.append("First 16 instruction bytes at pc: ");
+ if (IsAccessibleMemoryRange(pc, 16)) {
+ for (int i = 0; i < 16; ++i) {
+ PrintMemoryByte(&str, "", ((u8 *)pc)[i], /*in_shadow*/false, " ");
+ }
+ str.append("\n");
+ } else {
+ str.append("unaccessible\n");
+ }
+ Report("%s", str.data());
+}
+
+static void PrintShadowMemoryForAddress(uptr addr) {
+ if (!AddrIsInMem(addr)) return;
uptr shadow_addr = MemToShadow(addr);
const uptr n_bytes_per_row = 16;
uptr aligned_shadow = shadow_addr & ~(n_bytes_per_row - 1);
- Printf("Shadow bytes around the buggy address:\n");
+ InternalScopedString str(4096 * 8);
+ str.append("Shadow bytes around the buggy address:\n");
for (int i = -5; i <= 5; i++) {
const char *prefix = (i == 0) ? "=>" : " ";
- PrintShadowBytes(prefix,
- (u8*)(aligned_shadow + i * n_bytes_per_row),
- (u8*)shadow_addr, n_bytes_per_row);
+ PrintShadowBytes(&str, prefix, (u8 *)(aligned_shadow + i * n_bytes_per_row),
+ (u8 *)shadow_addr, n_bytes_per_row);
}
- if (flags()->print_legend)
- PrintLegend();
+ if (flags()->print_legend) PrintLegend(&str);
+ Printf("%s", str.data());
}
static void PrintZoneForPointer(uptr ptr, uptr zone_ptr,
@@ -181,62 +240,89 @@ static bool IsASCII(unsigned char c) {
static const char *MaybeDemangleGlobalName(const char *name) {
// We can spoil names of globals with C linkage, so use an heuristic
// approach to check if the name should be demangled.
- return (name[0] == '_' && name[1] == 'Z')
- ? Symbolizer::Get()->Demangle(name)
- : name;
+ bool should_demangle = false;
+ if (name[0] == '_' && name[1] == 'Z')
+ should_demangle = true;
+ else if (SANITIZER_WINDOWS && name[0] == '\01' && name[1] == '?')
+ should_demangle = true;
+
+ return should_demangle ? Symbolizer::GetOrInit()->Demangle(name) : name;
}
// Check if the global is a zero-terminated ASCII string. If so, print it.
-static void PrintGlobalNameIfASCII(const __asan_global &g) {
+static void PrintGlobalNameIfASCII(InternalScopedString *str,
+ const __asan_global &g) {
for (uptr p = g.beg; p < g.beg + g.size - 1; p++) {
unsigned char c = *(unsigned char*)p;
if (c == '\0' || !IsASCII(c)) return;
}
if (*(char*)(g.beg + g.size - 1) != '\0') return;
- Printf(" '%s' is ascii string '%s'\n",
- MaybeDemangleGlobalName(g.name), (char*)g.beg);
+ str->append(" '%s' is ascii string '%s'\n", MaybeDemangleGlobalName(g.name),
+ (char *)g.beg);
+}
+
+static const char *GlobalFilename(const __asan_global &g) {
+ const char *res = g.module_name;
+ // Prefer the filename from source location, if is available.
+ if (g.location)
+ res = g.location->filename;
+ CHECK(res);
+ return res;
+}
+
+static void PrintGlobalLocation(InternalScopedString *str,
+ const __asan_global &g) {
+ str->append("%s", GlobalFilename(g));
+ if (!g.location)
+ return;
+ if (g.location->line_no)
+ str->append(":%d", g.location->line_no);
+ if (g.location->column_no)
+ str->append(":%d", g.location->column_no);
}
bool DescribeAddressRelativeToGlobal(uptr addr, uptr size,
const __asan_global &g) {
- static const uptr kMinimalDistanceFromAnotherGlobal = 64;
- if (addr <= g.beg - kMinimalDistanceFromAnotherGlobal) return false;
- if (addr >= g.beg + g.size_with_redzone) return false;
+ if (!IsAddressNearGlobal(addr, g)) return false;
+ InternalScopedString str(4096);
Decorator d;
- Printf("%s", d.Location());
+ str.append("%s", d.Location());
if (addr < g.beg) {
- Printf("%p is located %zd bytes to the left", (void*)addr, g.beg - addr);
+ str.append("%p is located %zd bytes to the left", (void *)addr,
+ g.beg - addr);
} else if (addr + size > g.beg + g.size) {
if (addr < g.beg + g.size)
addr = g.beg + g.size;
- Printf("%p is located %zd bytes to the right", (void*)addr,
- addr - (g.beg + g.size));
+ str.append("%p is located %zd bytes to the right", (void *)addr,
+ addr - (g.beg + g.size));
} else {
// Can it happen?
- Printf("%p is located %zd bytes inside", (void*)addr, addr - g.beg);
+ str.append("%p is located %zd bytes inside", (void *)addr, addr - g.beg);
}
- Printf(" of global variable '%s' from '%s' (0x%zx) of size %zu\n",
- MaybeDemangleGlobalName(g.name), g.module_name, g.beg, g.size);
- Printf("%s", d.EndLocation());
- PrintGlobalNameIfASCII(g);
+ str.append(" of global variable '%s' defined in '",
+ MaybeDemangleGlobalName(g.name));
+ PrintGlobalLocation(&str, g);
+ str.append("' (0x%zx) of size %zu\n", g.beg, g.size);
+ str.append("%s", d.EndLocation());
+ PrintGlobalNameIfASCII(&str, g);
+ Printf("%s", str.data());
return true;
}
-bool DescribeAddressIfShadow(uptr addr) {
+bool DescribeAddressIfShadow(uptr addr, AddressDescription *descr, bool print) {
if (AddrIsInMem(addr))
return false;
- static const char kAddrInShadowReport[] =
- "Address %p is located in the %s.\n";
- if (AddrIsInShadowGap(addr)) {
- Printf(kAddrInShadowReport, addr, "shadow gap area");
- return true;
- }
- if (AddrIsInHighShadow(addr)) {
- Printf(kAddrInShadowReport, addr, "high shadow area");
- return true;
- }
- if (AddrIsInLowShadow(addr)) {
- Printf(kAddrInShadowReport, addr, "low shadow area");
+ const char *area_type = nullptr;
+ if (AddrIsInShadowGap(addr)) area_type = "shadow gap";
+ else if (AddrIsInHighShadow(addr)) area_type = "high shadow";
+ else if (AddrIsInLowShadow(addr)) area_type = "low shadow";
+ if (area_type != nullptr) {
+ if (print) {
+ Printf("Address %p is located in the %s area.\n", addr, area_type);
+ } else {
+ CHECK(descr);
+ descr->region_kind = area_type;
+ }
return true;
}
CHECK(0 && "Address is not in memory and not in shadow?");
@@ -263,16 +349,15 @@ const char *ThreadNameWithParenthesis(u32 tid, char buff[],
return ThreadNameWithParenthesis(t, buff, buff_len);
}
-void PrintAccessAndVarIntersection(const char *var_name,
- uptr var_beg, uptr var_size,
- uptr addr, uptr access_size,
- uptr prev_var_end, uptr next_var_beg) {
- uptr var_end = var_beg + var_size;
+static void PrintAccessAndVarIntersection(const StackVarDescr &var, uptr addr,
+ uptr access_size, uptr prev_var_end,
+ uptr next_var_beg) {
+ uptr var_end = var.beg + var.size;
uptr addr_end = addr + access_size;
const char *pos_descr = 0;
- // If the variable [var_beg, var_end) is the nearest variable to the
+ // 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) {
+ if (addr >= var.beg) {
if (addr_end <= var_end)
pos_descr = "is inside"; // May happen if this is a use-after-return.
else if (addr < var_end)
@@ -281,59 +366,77 @@ void PrintAccessAndVarIntersection(const char *var_name,
next_var_beg - addr_end >= addr - var_end)
pos_descr = "overflows";
} else {
- if (addr_end > var_beg)
+ if (addr_end > var.beg)
pos_descr = "partially underflows";
else if (addr >= prev_var_end &&
- addr - prev_var_end >= var_beg - addr_end)
+ addr - prev_var_end >= var.beg - addr_end)
pos_descr = "underflows";
}
- Printf(" [%zd, %zd) '%s'", var_beg, var_beg + var_size, var_name);
+ InternalScopedString str(1024);
+ str.append(" [%zd, %zd)", var.beg, var_end);
+ // Render variable name.
+ str.append(" '");
+ for (uptr i = 0; i < var.name_len; ++i) {
+ str.append("%c", var.name_pos[i]);
+ }
+ str.append("'");
if (pos_descr) {
Decorator d;
// FIXME: we may want to also print the size of the access here,
// but in case of accesses generated by memset it may be confusing.
- Printf("%s <== Memory access at offset %zd %s this variable%s\n",
- d.Location(), addr, pos_descr, d.EndLocation());
+ str.append("%s <== Memory access at offset %zd %s this variable%s\n",
+ d.Location(), addr, pos_descr, d.EndLocation());
} else {
- Printf("\n");
+ str.append("\n");
}
+ Printf("%s", str.data());
}
-struct StackVarDescr {
- uptr beg;
- uptr size;
- const char *name_pos;
- uptr name_len;
-};
+bool ParseFrameDescription(const char *frame_descr,
+ InternalMmapVector<StackVarDescr> *vars) {
+ CHECK(frame_descr);
+ char *p;
+ // This string is created by the compiler and has the following form:
+ // "n alloc_1 alloc_2 ... alloc_n"
+ // where alloc_i looks like "offset size len ObjectName".
+ uptr n_objects = (uptr)internal_simple_strtoll(frame_descr, &p, 10);
+ if (n_objects == 0)
+ return false;
+
+ for (uptr i = 0; i < n_objects; i++) {
+ uptr beg = (uptr)internal_simple_strtoll(p, &p, 10);
+ uptr size = (uptr)internal_simple_strtoll(p, &p, 10);
+ uptr len = (uptr)internal_simple_strtoll(p, &p, 10);
+ if (beg == 0 || size == 0 || *p != ' ') {
+ return false;
+ }
+ p++;
+ StackVarDescr var = {beg, size, p, len};
+ vars->push_back(var);
+ p += len;
+ }
+
+ return true;
+}
bool DescribeAddressIfStack(uptr addr, uptr access_size) {
AsanThread *t = FindThreadByStackAddress(addr);
if (!t) return false;
- const uptr kBufSize = 4095;
- char buf[kBufSize];
- uptr offset = 0;
- uptr frame_pc = 0;
- char tname[128];
- const char *frame_descr = t->GetFrameNameByAddr(addr, &offset, &frame_pc);
-#ifdef __powerpc64__
- // On PowerPC64, the address of a function actually points to a
- // three-doubleword data structure with the first field containing
- // the address of the function's code.
- frame_pc = *reinterpret_cast<uptr *>(frame_pc);
-#endif
-
- // This string is created by the compiler and has the following form:
- // "n alloc_1 alloc_2 ... alloc_n"
- // where alloc_i looks like "offset size len ObjectName ".
- CHECK(frame_descr);
Decorator d;
+ char tname[128];
Printf("%s", d.Location());
- Printf("Address %p is located in stack of thread T%d%s "
- "at offset %zu in frame\n",
- addr, t->tid(),
- ThreadNameWithParenthesis(t->tid(), tname, sizeof(tname)),
- offset);
+ Printf("Address %p is located in stack of thread T%d%s", addr, t->tid(),
+ ThreadNameWithParenthesis(t->tid(), tname, sizeof(tname)));
+
+ // Try to fetch precise stack frame for this access.
+ AsanThread::StackFrameAccess access;
+ if (!t->GetStackFrameAccessByAddr(addr, &access)) {
+ Printf("%s\n", d.EndLocation());
+ return true;
+ }
+ Printf(" at offset %zu in frame%s\n", access.offset, d.EndLocation());
+
// Now we print the frame where the alloca has happened.
// We print this frame as a stack trace with one element.
// The symbolizer may print more than one frame if inlining was involved.
@@ -341,50 +444,42 @@ bool DescribeAddressIfStack(uptr addr, uptr access_size) {
// previously. That's unfortunate, but I have no better solution,
// especially given that the alloca may be from entirely different place
// (e.g. use-after-scope, or different thread's stack).
- StackTrace alloca_stack;
- alloca_stack.trace[0] = frame_pc + 16;
- alloca_stack.size = 1;
+#if defined(__powerpc64__) && defined(__BIG_ENDIAN__)
+ // On PowerPC64 ELFv1, the address of a function actually points to a
+ // three-doubleword data structure with the first field containing
+ // the address of the function's code.
+ access.frame_pc = *reinterpret_cast<uptr *>(access.frame_pc);
+#endif
+ access.frame_pc += 16;
Printf("%s", d.EndLocation());
- PrintStack(&alloca_stack);
+ StackTrace alloca_stack(&access.frame_pc, 1);
+ alloca_stack.Print();
+
+ InternalMmapVector<StackVarDescr> vars(16);
+ if (!ParseFrameDescription(access.frame_descr, &vars)) {
+ Printf("AddressSanitizer can't parse the stack frame "
+ "descriptor: |%s|\n", access.frame_descr);
+ // 'addr' is a stack address, so return true even if we can't parse frame
+ return true;
+ }
+ uptr n_objects = vars.size();
// Report the number of stack objects.
- char *p;
- uptr n_objects = (uptr)internal_simple_strtoll(frame_descr, &p, 10);
- CHECK_GT(n_objects, 0);
Printf(" This frame has %zu object(s):\n", n_objects);
// Report all objects in this frame.
- InternalScopedBuffer<StackVarDescr> vars(n_objects);
for (uptr i = 0; i < n_objects; i++) {
- uptr beg, size;
- uptr len;
- beg = (uptr)internal_simple_strtoll(p, &p, 10);
- size = (uptr)internal_simple_strtoll(p, &p, 10);
- len = (uptr)internal_simple_strtoll(p, &p, 10);
- if (beg == 0 || size == 0 || *p != ' ') {
- Printf("AddressSanitizer can't parse the stack frame "
- "descriptor: |%s|\n", frame_descr);
- break;
- }
- p++;
- vars[i].beg = beg;
- vars[i].size = size;
- vars[i].name_pos = p;
- vars[i].name_len = len;
- p += len;
- }
- for (uptr i = 0; i < n_objects; i++) {
- buf[0] = 0;
- internal_strncat(buf, vars[i].name_pos,
- static_cast<uptr>(Min(kBufSize, vars[i].name_len)));
uptr prev_var_end = i ? vars[i - 1].beg + vars[i - 1].size : 0;
uptr next_var_beg = i + 1 < n_objects ? vars[i + 1].beg : ~(0UL);
- PrintAccessAndVarIntersection(buf, vars[i].beg, vars[i].size,
- offset, access_size,
+ PrintAccessAndVarIntersection(vars[i], access.offset, access_size,
prev_var_end, next_var_beg);
}
Printf("HINT: this may be a false positive if your program uses "
- "some custom stack unwind mechanism or swapcontext\n"
- " (longjmp and C++ exceptions *are* supported)\n");
+ "some custom stack unwind mechanism or swapcontext\n");
+ if (SANITIZER_WINDOWS)
+ Printf(" (longjmp, SEH and C++ exceptions *are* supported)\n");
+ else
+ Printf(" (longjmp and C++ exceptions *are* supported)\n");
+
DescribeThread(t);
return true;
}
@@ -393,24 +488,26 @@ static void DescribeAccessToHeapChunk(AsanChunkView chunk, uptr addr,
uptr access_size) {
sptr offset;
Decorator d;
- Printf("%s", d.Location());
+ InternalScopedString str(4096);
+ str.append("%s", d.Location());
if (chunk.AddrIsAtLeft(addr, access_size, &offset)) {
- Printf("%p is located %zd bytes to the left of", (void*)addr, offset);
+ str.append("%p is located %zd bytes to the left of", (void *)addr, offset);
} else if (chunk.AddrIsAtRight(addr, access_size, &offset)) {
if (offset < 0) {
addr -= offset;
offset = 0;
}
- Printf("%p is located %zd bytes to the right of", (void*)addr, offset);
+ str.append("%p is located %zd bytes to the right of", (void *)addr, offset);
} else if (chunk.AddrIsInside(addr, access_size, &offset)) {
- Printf("%p is located %zd bytes inside of", (void*)addr, offset);
+ str.append("%p is located %zd bytes inside of", (void*)addr, offset);
} else {
- Printf("%p is located somewhere around (this is AddressSanitizer bug!)",
- (void*)addr);
+ str.append("%p is located somewhere around (this is AddressSanitizer bug!)",
+ (void *)addr);
}
- Printf(" %zu-byte region [%p,%p)\n", chunk.UsedSize(),
- (void*)(chunk.Beg()), (void*)(chunk.End()));
- Printf("%s", d.EndLocation());
+ str.append(" %zu-byte region [%p,%p)\n", chunk.UsedSize(),
+ (void *)(chunk.Beg()), (void *)(chunk.End()));
+ str.append("%s", d.EndLocation());
+ Printf("%s", str.data());
}
void DescribeHeapAddress(uptr addr, uptr access_size) {
@@ -425,8 +522,7 @@ void DescribeHeapAddress(uptr addr, uptr access_size) {
asanThreadRegistry().CheckLocked();
AsanThreadContext *alloc_thread =
GetThreadContextByTidLocked(chunk.AllocTid());
- StackTrace alloc_stack;
- chunk.GetAllocStack(&alloc_stack);
+ StackTrace alloc_stack = chunk.GetAllocStack();
char tname[128];
Decorator d;
AsanThreadContext *free_thread = 0;
@@ -436,9 +532,8 @@ void DescribeHeapAddress(uptr addr, uptr access_size) {
free_thread->tid,
ThreadNameWithParenthesis(free_thread, tname, sizeof(tname)),
d.EndAllocation());
- StackTrace free_stack;
- chunk.GetFreeStack(&free_stack);
- PrintStack(&free_stack);
+ StackTrace free_stack = chunk.GetFreeStack();
+ free_stack.Print();
Printf("%spreviously allocated by thread T%d%s here:%s\n",
d.Allocation(), alloc_thread->tid,
ThreadNameWithParenthesis(alloc_thread, tname, sizeof(tname)),
@@ -449,7 +544,7 @@ void DescribeHeapAddress(uptr addr, uptr access_size) {
ThreadNameWithParenthesis(alloc_thread, tname, sizeof(tname)),
d.EndAllocation());
}
- PrintStack(&alloc_stack);
+ alloc_stack.Print();
DescribeThread(GetCurrentThread());
if (free_thread)
DescribeThread(free_thread);
@@ -480,15 +575,14 @@ void DescribeThread(AsanThreadContext *context) {
}
context->announced = true;
char tname[128];
- Printf("Thread T%d%s", context->tid,
- ThreadNameWithParenthesis(context->tid, tname, sizeof(tname)));
- Printf(" created by T%d%s here:\n",
- context->parent_tid,
- ThreadNameWithParenthesis(context->parent_tid,
- tname, sizeof(tname)));
- uptr stack_size;
- const uptr *stack_trace = StackDepotGet(context->stack_id, &stack_size);
- PrintStack(stack_trace, stack_size);
+ InternalScopedString str(1024);
+ str.append("Thread T%d%s", context->tid,
+ ThreadNameWithParenthesis(context->tid, tname, sizeof(tname)));
+ str.append(
+ " created by T%d%s here:\n", context->parent_tid,
+ ThreadNameWithParenthesis(context->parent_tid, tname, sizeof(tname)));
+ Printf("%s", str.data());
+ StackDepotGet(context->stack_id).Print();
// Recursively described parent thread if needed.
if (flags()->print_full_thread_history) {
AsanThreadContext *parent_context =
@@ -503,14 +597,14 @@ void DescribeThread(AsanThreadContext *context) {
// immediately after printing error report.
class ScopedInErrorReport {
public:
- ScopedInErrorReport() {
+ 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) {
// 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.
- Report("AddressSanitizer: while reporting a bug found another one."
+ Report("AddressSanitizer: while reporting a bug found another one. "
"Ignoring.\n");
u32 current_tid = GetCurrentTidOrInvalid();
if (current_tid != reporting_thread_tid) {
@@ -523,6 +617,8 @@ class ScopedInErrorReport {
// Die() to bypass any additional checks.
internal__exit(flags()->exitcode);
}
+ if (report) report_data = *report;
+ report_happened = true;
ASAN_ON_ERROR();
// Make sure the registry and sanitizer report mutexes are locked while
// we're printing an error report.
@@ -538,6 +634,8 @@ class ScopedInErrorReport {
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();
@@ -549,22 +647,42 @@ class ScopedInErrorReport {
}
};
-void ReportSIGSEGV(uptr pc, uptr sp, uptr bp, uptr addr) {
+void ReportStackOverflow(const SignalContext &sig) {
ScopedInErrorReport in_report;
Decorator d;
Printf("%s", d.Warning());
- Report("ERROR: AddressSanitizer: SEGV on unknown address %p"
- " (pc %p sp %p bp %p T%d)\n",
- (void*)addr, (void*)pc, (void*)sp, (void*)bp,
- GetCurrentTidOrInvalid());
+ Report(
+ "ERROR: AddressSanitizer: stack-overflow on address %p"
+ " (pc %p bp %p sp %p T%d)\n",
+ (void *)sig.addr, (void *)sig.pc, (void *)sig.bp, (void *)sig.sp,
+ GetCurrentTidOrInvalid());
Printf("%s", d.EndWarning());
- GET_STACK_TRACE_FATAL(pc, bp);
- PrintStack(&stack);
+ GET_STACK_TRACE_SIGNAL(sig);
+ stack.Print();
+ ReportErrorSummary("stack-overflow", &stack);
+}
+
+void ReportSIGSEGV(const char *description, const SignalContext &sig) {
+ ScopedInErrorReport in_report;
+ Decorator d;
+ Printf("%s", d.Warning());
+ Report(
+ "ERROR: AddressSanitizer: %s on unknown address %p"
+ " (pc %p bp %p sp %p T%d)\n",
+ description, (void *)sig.addr, (void *)sig.pc, (void *)sig.bp,
+ (void *)sig.sp, GetCurrentTidOrInvalid());
+ if (sig.pc < GetPageSizeCached()) {
+ Report("Hint: pc points to the zero page.\n");
+ }
+ Printf("%s", d.EndWarning());
+ GET_STACK_TRACE_SIGNAL(sig);
+ stack.Print();
+ MaybeDumpInstructionBytes(sig.pc);
Printf("AddressSanitizer can not provide additional info.\n");
ReportErrorSummary("SEGV", &stack);
}
-void ReportDoubleFree(uptr addr, StackTrace *free_stack) {
+void ReportDoubleFree(uptr addr, BufferedStackTrace *free_stack) {
ScopedInErrorReport in_report;
Decorator d;
Printf("%s", d.Warning());
@@ -577,12 +695,36 @@ void ReportDoubleFree(uptr addr, StackTrace *free_stack) {
Printf("%s", d.EndWarning());
CHECK_GT(free_stack->size, 0);
GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp);
- PrintStack(&stack);
+ stack.Print();
DescribeHeapAddress(addr, 1);
ReportErrorSummary("double-free", &stack);
}
-void ReportFreeNotMalloced(uptr addr, StackTrace *free_stack) {
+void ReportNewDeleteSizeMismatch(uptr addr, uptr delete_size,
+ BufferedStackTrace *free_stack) {
+ ScopedInErrorReport in_report;
+ Decorator d;
+ Printf("%s", d.Warning());
+ char tname[128];
+ u32 curr_tid = GetCurrentTidOrInvalid();
+ Report("ERROR: AddressSanitizer: new-delete-type-mismatch on %p in "
+ "thread T%d%s:\n",
+ addr, curr_tid,
+ ThreadNameWithParenthesis(curr_tid, tname, sizeof(tname)));
+ Printf("%s object passed to delete has wrong type:\n", d.EndWarning());
+ Printf(" size of the allocated type: %zd bytes;\n"
+ " size of the deallocated type: %zd bytes.\n",
+ asan_mz_size(reinterpret_cast<void*>(addr)), delete_size);
+ CHECK_GT(free_stack->size, 0);
+ GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp);
+ stack.Print();
+ DescribeHeapAddress(addr, 1);
+ ReportErrorSummary("new-delete-type-mismatch", &stack);
+ Report("HINT: if you don't care about these warnings you may set "
+ "ASAN_OPTIONS=new_delete_type_mismatch=0\n");
+}
+
+void ReportFreeNotMalloced(uptr addr, BufferedStackTrace *free_stack) {
ScopedInErrorReport in_report;
Decorator d;
Printf("%s", d.Warning());
@@ -594,12 +736,12 @@ void ReportFreeNotMalloced(uptr addr, StackTrace *free_stack) {
Printf("%s", d.EndWarning());
CHECK_GT(free_stack->size, 0);
GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp);
- PrintStack(&stack);
+ stack.Print();
DescribeHeapAddress(addr, 1);
ReportErrorSummary("bad-free", &stack);
}
-void ReportAllocTypeMismatch(uptr addr, StackTrace *free_stack,
+void ReportAllocTypeMismatch(uptr addr, BufferedStackTrace *free_stack,
AllocType alloc_type,
AllocType dealloc_type) {
static const char *alloc_names[] =
@@ -615,14 +757,14 @@ void ReportAllocTypeMismatch(uptr addr, StackTrace *free_stack,
Printf("%s", d.EndWarning());
CHECK_GT(free_stack->size, 0);
GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp);
- PrintStack(&stack);
+ stack.Print();
DescribeHeapAddress(addr, 1);
ReportErrorSummary("alloc-dealloc-mismatch", &stack);
Report("HINT: if you don't care about these warnings you may set "
"ASAN_OPTIONS=alloc_dealloc_mismatch=0\n");
}
-void ReportMallocUsableSizeNotOwned(uptr addr, StackTrace *stack) {
+void ReportMallocUsableSizeNotOwned(uptr addr, BufferedStackTrace *stack) {
ScopedInErrorReport in_report;
Decorator d;
Printf("%s", d.Warning());
@@ -630,27 +772,29 @@ void ReportMallocUsableSizeNotOwned(uptr addr, StackTrace *stack) {
"malloc_usable_size() for pointer which is "
"not owned: %p\n", addr);
Printf("%s", d.EndWarning());
- PrintStack(stack);
+ stack->Print();
DescribeHeapAddress(addr, 1);
ReportErrorSummary("bad-malloc_usable_size", stack);
}
-void ReportAsanGetAllocatedSizeNotOwned(uptr addr, StackTrace *stack) {
+void ReportSanitizerGetAllocatedSizeNotOwned(uptr addr,
+ BufferedStackTrace *stack) {
ScopedInErrorReport in_report;
Decorator d;
Printf("%s", d.Warning());
Report("ERROR: AddressSanitizer: attempting to call "
- "__asan_get_allocated_size() for pointer which is "
+ "__sanitizer_get_allocated_size() for pointer which is "
"not owned: %p\n", addr);
Printf("%s", d.EndWarning());
- PrintStack(stack);
+ stack->Print();
DescribeHeapAddress(addr, 1);
- ReportErrorSummary("bad-__asan_get_allocated_size", stack);
+ ReportErrorSummary("bad-__sanitizer_get_allocated_size", stack);
}
-void ReportStringFunctionMemoryRangesOverlap(
- const char *function, const char *offset1, uptr length1,
- const char *offset2, uptr length2, StackTrace *stack) {
+void ReportStringFunctionMemoryRangesOverlap(const char *function,
+ const char *offset1, uptr length1,
+ const char *offset2, uptr length2,
+ BufferedStackTrace *stack) {
ScopedInErrorReport in_report;
Decorator d;
char bug_type[100];
@@ -660,44 +804,129 @@ void ReportStringFunctionMemoryRangesOverlap(
"memory ranges [%p,%p) and [%p, %p) overlap\n", \
bug_type, offset1, offset1 + length1, offset2, offset2 + length2);
Printf("%s", d.EndWarning());
- PrintStack(stack);
+ stack->Print();
DescribeAddress((uptr)offset1, length1);
DescribeAddress((uptr)offset2, length2);
ReportErrorSummary(bug_type, stack);
}
+void ReportStringFunctionSizeOverflow(uptr offset, uptr size,
+ BufferedStackTrace *stack) {
+ ScopedInErrorReport in_report;
+ Decorator d;
+ const char *bug_type = "negative-size-param";
+ Printf("%s", d.Warning());
+ Report("ERROR: AddressSanitizer: %s: (size=%zd)\n", bug_type, size);
+ Printf("%s", d.EndWarning());
+ stack->Print();
+ DescribeAddress(offset, size);
+ ReportErrorSummary(bug_type, stack);
+}
+
+void ReportBadParamsToAnnotateContiguousContainer(uptr beg, uptr end,
+ uptr old_mid, uptr new_mid,
+ BufferedStackTrace *stack) {
+ ScopedInErrorReport in_report;
+ Report("ERROR: AddressSanitizer: bad parameters to "
+ "__sanitizer_annotate_contiguous_container:\n"
+ " beg : %p\n"
+ " end : %p\n"
+ " old_mid : %p\n"
+ " new_mid : %p\n",
+ beg, end, old_mid, new_mid);
+ stack->Print();
+ ReportErrorSummary("bad-__sanitizer_annotate_contiguous_container", stack);
+}
+
+void ReportODRViolation(const __asan_global *g1, u32 stack_id1,
+ const __asan_global *g2, u32 stack_id2) {
+ ScopedInErrorReport in_report;
+ Decorator d;
+ Printf("%s", d.Warning());
+ Report("ERROR: AddressSanitizer: odr-violation (%p):\n", g1->beg);
+ Printf("%s", d.EndWarning());
+ InternalScopedString g1_loc(256), g2_loc(256);
+ PrintGlobalLocation(&g1_loc, *g1);
+ PrintGlobalLocation(&g2_loc, *g2);
+ Printf(" [1] size=%zd '%s' %s\n", g1->size,
+ MaybeDemangleGlobalName(g1->name), g1_loc.data());
+ Printf(" [2] size=%zd '%s' %s\n", g2->size,
+ MaybeDemangleGlobalName(g2->name), g2_loc.data());
+ if (stack_id1 && stack_id2) {
+ Printf("These globals were registered at these points:\n");
+ Printf(" [1]:\n");
+ StackDepotGet(stack_id1).Print();
+ Printf(" [2]:\n");
+ StackDepotGet(stack_id2).Print();
+ }
+ Report("HINT: if you don't care about these warnings you may set "
+ "ASAN_OPTIONS=detect_odr_violation=0\n");
+ InternalScopedString error_msg(256);
+ error_msg.append("odr-violation: global '%s' at %s",
+ MaybeDemangleGlobalName(g1->name), g1_loc.data());
+ ReportErrorSummary(error_msg.data());
+}
+
+// ----------------------- CheckForInvalidPointerPair ----------- {{{1
+static NOINLINE void
+ReportInvalidPointerPair(uptr pc, uptr bp, uptr sp, uptr a1, uptr a2) {
+ ScopedInErrorReport in_report;
+ Decorator d;
+ Printf("%s", d.Warning());
+ Report("ERROR: AddressSanitizer: invalid-pointer-pair: %p %p\n", a1, a2);
+ Printf("%s", d.EndWarning());
+ GET_STACK_TRACE_FATAL(pc, bp);
+ stack.Print();
+ DescribeAddress(a1, 1);
+ DescribeAddress(a2, 1);
+ ReportErrorSummary("invalid-pointer-pair", &stack);
+}
+
+static INLINE void CheckForInvalidPointerPair(void *p1, void *p2) {
+ if (!flags()->detect_invalid_pointer_pairs) return;
+ uptr a1 = reinterpret_cast<uptr>(p1);
+ uptr a2 = reinterpret_cast<uptr>(p2);
+ AsanChunkView chunk1 = FindHeapChunkByAddress(a1);
+ AsanChunkView chunk2 = FindHeapChunkByAddress(a2);
+ bool valid1 = chunk1.IsValid();
+ bool valid2 = chunk2.IsValid();
+ if ((valid1 != valid2) || (valid1 && valid2 && !chunk1.Eq(chunk2))) {
+ GET_CALLER_PC_BP_SP; \
+ return ReportInvalidPointerPair(pc, bp, sp, a1, a2);
+ }
+}
// ----------------------- Mac-specific reports ----------------- {{{1
-void WarnMacFreeUnallocated(
- uptr addr, uptr zone_ptr, const char *zone_name, StackTrace *stack) {
+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);
- PrintStack(stack);
+ stack->Print();
DescribeHeapAddress(addr, 1);
}
-void ReportMacMzReallocUnknown(
- uptr addr, uptr zone_ptr, const char *zone_name, StackTrace *stack) {
+void ReportMacMzReallocUnknown(uptr addr, uptr zone_ptr, const char *zone_name,
+ BufferedStackTrace *stack) {
ScopedInErrorReport in_report;
Printf("mz_realloc(%p) -- attempting to realloc unallocated memory.\n"
"This is an unrecoverable problem, exiting now.\n",
addr);
PrintZoneForPointer(addr, zone_ptr, zone_name);
- PrintStack(stack);
+ stack->Print();
DescribeHeapAddress(addr, 1);
}
-void ReportMacCfReallocUnknown(
- uptr addr, uptr zone_ptr, const char *zone_name, StackTrace *stack) {
+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);
- PrintStack(stack);
+ stack->Print();
DescribeHeapAddress(addr, 1);
}
@@ -706,10 +935,8 @@ void ReportMacCfReallocUnknown(
// --------------------------- Interface --------------------- {{{1
using namespace __asan; // NOLINT
-void __asan_report_error(uptr pc, uptr bp, uptr sp,
- uptr addr, bool is_write, uptr access_size) {
- ScopedInErrorReport in_report;
-
+void __asan_report_error(uptr pc, uptr bp, uptr sp, uptr addr, int is_write,
+ uptr access_size) {
// Determine the error type.
const char *bug_descr = "unknown-crash";
if (AddrIsInMem(addr)) {
@@ -723,6 +950,7 @@ void __asan_report_error(uptr pc, uptr bp, uptr sp,
switch (*shadow_addr) {
case kAsanHeapLeftRedzoneMagic:
case kAsanHeapRightRedzoneMagic:
+ case kAsanArrayCookieMagic:
bug_descr = "heap-buffer-overflow";
break;
case kAsanHeapFreeMagic:
@@ -745,18 +973,33 @@ void __asan_report_error(uptr pc, uptr bp, uptr sp,
case kAsanUserPoisonedMemoryMagic:
bug_descr = "use-after-poison";
break;
+ case kAsanContiguousContainerOOBMagic:
+ bug_descr = "container-overflow";
+ break;
case kAsanStackUseAfterScopeMagic:
bug_descr = "stack-use-after-scope";
break;
case kAsanGlobalRedzoneMagic:
bug_descr = "global-buffer-overflow";
break;
+ case kAsanIntraObjectRedzone:
+ bug_descr = "intra-object-overflow";
+ break;
+ case kAsanAllocaLeftMagic:
+ case kAsanAllocaRightMagic:
+ bug_descr = "dynamic-stack-buffer-overflow";
+ break;
}
}
+
+ ReportData report = { pc, sp, bp, addr, (bool)is_write, access_size,
+ bug_descr };
+ ScopedInErrorReport in_report(&report);
+
Decorator d;
Printf("%s", d.Warning());
Report("ERROR: AddressSanitizer: %s on address "
- "%p at pc 0x%zx bp 0x%zx sp 0x%zx\n",
+ "%p at pc %p bp %p sp %p\n",
bug_descr, (void*)addr, pc, bp, sp);
Printf("%s", d.EndWarning());
@@ -770,7 +1013,7 @@ void __asan_report_error(uptr pc, uptr bp, uptr sp,
d.EndAccess());
GET_STACK_TRACE_FATAL(pc, bp);
- PrintStack(&stack);
+ stack.Print();
DescribeAddress(addr, access_size);
ReportErrorSummary(bug_descr, &stack);
@@ -782,14 +1025,60 @@ void NOINLINE __asan_set_error_report_callback(void (*callback)(const char*)) {
if (callback) {
error_message_buffer_size = 1 << 16;
error_message_buffer =
- (char*)MmapOrDie(error_message_buffer_size, __FUNCTION__);
+ (char*)MmapOrDie(error_message_buffer_size, __func__);
error_message_buffer_pos = 0;
}
}
void __asan_describe_address(uptr addr) {
+ // Thread registry must be locked while we're describing an address.
+ asanThreadRegistry().Lock();
DescribeAddress(addr, 1);
+ asanThreadRegistry().Unlock();
+}
+
+int __asan_report_present() {
+ return report_happened ? 1 : 0;
+}
+
+uptr __asan_get_report_pc() {
+ return report_data.pc;
+}
+
+uptr __asan_get_report_bp() {
+ return report_data.bp;
+}
+
+uptr __asan_get_report_sp() {
+ return report_data.sp;
+}
+
+uptr __asan_get_report_address() {
+ return report_data.addr;
+}
+
+int __asan_get_report_access_type() {
+ return report_data.is_write ? 1 : 0;
+}
+
+uptr __asan_get_report_access_size() {
+ return report_data.access_size;
+}
+
+const char *__asan_get_report_description() {
+ return report_data.description;
+}
+
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_ptr_sub(void *a, void *b) {
+ CheckForInvalidPointerPair(a, b);
+}
+SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_ptr_cmp(void *a, void *b) {
+ CheckForInvalidPointerPair(a, b);
}
+} // 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 f55b57bd4d9f..029c914b8a04 100644
--- a/lib/asan/asan_report.h
+++ b/lib/asan/asan_report.h
@@ -18,13 +18,33 @@
namespace __asan {
+struct StackVarDescr {
+ uptr beg;
+ uptr size;
+ const char *name_pos;
+ uptr name_len;
+};
+
+struct AddressDescription {
+ char *name;
+ uptr name_size;
+ uptr region_address;
+ uptr region_size;
+ const char *region_kind;
+};
+
// The following functions prints address description depending
// on the memory type (shadow/heap/stack/global).
void DescribeHeapAddress(uptr addr, uptr access_size);
bool DescribeAddressIfGlobal(uptr addr, uptr access_size);
bool DescribeAddressRelativeToGlobal(uptr addr, uptr access_size,
const __asan_global &g);
-bool DescribeAddressIfShadow(uptr addr);
+bool IsAddressNearGlobal(uptr addr, const __asan_global &g);
+bool GetInfoForAddressIfGlobal(uptr addr, AddressDescription *descr);
+bool DescribeAddressIfShadow(uptr addr, AddressDescription *descr = nullptr,
+ bool print = true);
+bool ParseFrameDescription(const char *frame_descr,
+ InternalMmapVector<StackVarDescr> *vars);
bool DescribeAddressIfStack(uptr addr, uptr access_size);
// Determines memory type on its own.
void DescribeAddress(uptr addr, uptr access_size);
@@ -32,26 +52,44 @@ void DescribeAddress(uptr addr, uptr access_size);
void DescribeThread(AsanThreadContext *context);
// Different kinds of error reports.
-void NORETURN ReportSIGSEGV(uptr pc, uptr sp, uptr bp, uptr addr);
-void NORETURN ReportDoubleFree(uptr addr, StackTrace *free_stack);
-void NORETURN ReportFreeNotMalloced(uptr addr, StackTrace *free_stack);
-void NORETURN ReportAllocTypeMismatch(uptr addr, StackTrace *free_stack,
+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,
- StackTrace *stack);
-void NORETURN ReportAsanGetAllocatedSizeNotOwned(uptr addr,
- StackTrace *stack);
-void NORETURN ReportStringFunctionMemoryRangesOverlap(
- const char *function, const char *offset1, uptr length1,
- const char *offset2, uptr length2, StackTrace *stack);
+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 NORETURN
+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, StackTrace *stack);
-void NORETURN ReportMacMzReallocUnknown(
- uptr addr, uptr zone_ptr, const char *zone_name, StackTrace *stack);
-void NORETURN ReportMacCfReallocUnknown(
- uptr addr, uptr zone_ptr, const char *zone_name, StackTrace *stack);
+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);
} // namespace __asan
diff --git a/lib/asan/asan_rtl.cc b/lib/asan/asan_rtl.cc
index 11f05954d31e..34fb111d5607 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"
#include "asan_interface_internal.h"
@@ -20,6 +21,7 @@
#include "asan_report.h"
#include "asan_stack.h"
#include "asan_stats.h"
+#include "asan_suppressions.h"
#include "asan_thread.h"
#include "sanitizer_common/sanitizer_atomic.h"
#include "sanitizer_common/sanitizer_flags.h"
@@ -28,6 +30,7 @@
#include "lsan/lsan_common.h"
int __asan_option_detect_stack_use_after_return; // Global interface symbol.
+uptr *__asan_test_only_reported_buggy_pointer; // Used only for testing asan.
namespace __asan {
@@ -51,6 +54,8 @@ static void AsanDie() {
UnmapOrDie((void*)kLowShadowBeg, kHighShadowEnd - kLowShadowBeg);
}
}
+ if (common_flags()->coverage)
+ __sanitizer_cov_dump();
if (death_callback)
death_callback();
if (flags()->abort_on_error)
@@ -60,10 +65,10 @@ static void AsanDie() {
static void AsanCheckFailed(const char *file, int line, const char *cond,
u64 v1, u64 v2) {
- Report("AddressSanitizer CHECK failed: %s:%d \"%s\" (0x%zx, 0x%zx)\n",
- file, line, cond, (uptr)v1, (uptr)v2);
+ Report("AddressSanitizer CHECK failed: %s:%d \"%s\" (0x%zx, 0x%zx)\n", file,
+ line, cond, (uptr)v1, (uptr)v2);
// FIXME: check for infinite recursion without a thread-local counter here.
- PRINT_CURRENT_STACK();
+ PRINT_CURRENT_STACK_CHECK();
Die();
}
@@ -76,7 +81,7 @@ static const char *MaybeCallAsanDefaultOptions() {
return (&__asan_default_options) ? __asan_default_options() : "";
}
-static const char *MaybeUseAsanDefaultOptionsCompileDefiniton() {
+static const char *MaybeUseAsanDefaultOptionsCompileDefinition() {
#ifdef ASAN_DEFAULT_OPTIONS
// Stringize the macro value.
# define ASAN_STRINGIZE(x) #x
@@ -88,58 +93,162 @@ static const char *MaybeUseAsanDefaultOptionsCompileDefiniton() {
}
static void ParseFlagsFromString(Flags *f, const char *str) {
- ParseCommonFlagsFromString(str);
- CHECK((uptr)common_flags()->malloc_context_size <= kStackTraceMax);
-
- ParseFlag(str, &f->quarantine_size, "quarantine_size");
- ParseFlag(str, &f->redzone, "redzone");
+ CommonFlags *cf = common_flags();
+ ParseCommonFlagsFromString(cf, str);
+ CHECK((uptr)cf->malloc_context_size <= kStackTraceMax);
+ // Please write meaningful flag descriptions when adding new flags.
+ ParseFlag(str, &f->quarantine_size, "quarantine_size",
+ "Size (in bytes) of quarantine used to detect use-after-free "
+ "errors. Lower value may reduce memory usage but increase the "
+ "chance of false negatives.");
+ ParseFlag(str, &f->redzone, "redzone",
+ "Minimal size (in bytes) of redzones around heap objects. "
+ "Requirement: redzone >= 16, is a power of two.");
+ ParseFlag(str, &f->max_redzone, "max_redzone",
+ "Maximal size (in bytes) of redzones around heap objects.");
CHECK_GE(f->redzone, 16);
+ CHECK_GE(f->max_redzone, f->redzone);
+ CHECK_LE(f->max_redzone, 2048);
CHECK(IsPowerOfTwo(f->redzone));
-
- ParseFlag(str, &f->debug, "debug");
- ParseFlag(str, &f->report_globals, "report_globals");
- ParseFlag(str, &f->check_initialization_order, "check_initialization_order");
-
- ParseFlag(str, &f->replace_str, "replace_str");
- ParseFlag(str, &f->replace_intrin, "replace_intrin");
- ParseFlag(str, &f->mac_ignore_invalid_free, "mac_ignore_invalid_free");
+ CHECK(IsPowerOfTwo(f->max_redzone));
+
+ ParseFlag(str, &f->debug, "debug",
+ "If set, prints some debugging information and does additional checks.");
+ ParseFlag(str, &f->report_globals, "report_globals",
+ "Controls the way to handle globals (0 - don't detect buffer overflow on "
+ "globals, 1 - detect buffer overflow, 2 - print data about registered "
+ "globals).");
+
+ ParseFlag(str, &f->check_initialization_order,
+ "check_initialization_order",
+ "If set, attempts to catch initialization order issues.");
+
+ ParseFlag(str, &f->replace_str, "replace_str",
+ "If set, uses custom wrappers and replacements for libc string functions "
+ "to find more errors.");
+
+ ParseFlag(str, &f->replace_intrin, "replace_intrin",
+ "If set, uses custom wrappers for memset/memcpy/memmove intinsics.");
+ ParseFlag(str, &f->mac_ignore_invalid_free, "mac_ignore_invalid_free",
+ "Ignore invalid free() calls to work around some bugs. Used on OS X "
+ "only.");
ParseFlag(str, &f->detect_stack_use_after_return,
- "detect_stack_use_after_return");
- ParseFlag(str, &f->uar_stack_size_log, "uar_stack_size_log");
- ParseFlag(str, &f->max_malloc_fill_size, "max_malloc_fill_size");
- ParseFlag(str, &f->malloc_fill_byte, "malloc_fill_byte");
- ParseFlag(str, &f->exitcode, "exitcode");
- ParseFlag(str, &f->allow_user_poisoning, "allow_user_poisoning");
- ParseFlag(str, &f->sleep_before_dying, "sleep_before_dying");
- ParseFlag(str, &f->handle_segv, "handle_segv");
- ParseFlag(str, &f->allow_user_segv_handler, "allow_user_segv_handler");
- ParseFlag(str, &f->use_sigaltstack, "use_sigaltstack");
- ParseFlag(str, &f->check_malloc_usable_size, "check_malloc_usable_size");
- ParseFlag(str, &f->unmap_shadow_on_exit, "unmap_shadow_on_exit");
- ParseFlag(str, &f->abort_on_error, "abort_on_error");
- ParseFlag(str, &f->print_stats, "print_stats");
- ParseFlag(str, &f->print_legend, "print_legend");
- ParseFlag(str, &f->atexit, "atexit");
- ParseFlag(str, &f->coverage, "coverage");
- ParseFlag(str, &f->disable_core, "disable_core");
- ParseFlag(str, &f->allow_reexec, "allow_reexec");
- ParseFlag(str, &f->print_full_thread_history, "print_full_thread_history");
- ParseFlag(str, &f->poison_heap, "poison_heap");
- ParseFlag(str, &f->poison_partial, "poison_partial");
- ParseFlag(str, &f->alloc_dealloc_mismatch, "alloc_dealloc_mismatch");
- ParseFlag(str, &f->strict_memcmp, "strict_memcmp");
- ParseFlag(str, &f->strict_init_order, "strict_init_order");
+ "detect_stack_use_after_return",
+ "Enables stack-use-after-return checking at run-time.");
+ ParseFlag(str, &f->min_uar_stack_size_log, "min_uar_stack_size_log",
+ "Minimum fake stack size log.");
+ ParseFlag(str, &f->max_uar_stack_size_log, "max_uar_stack_size_log",
+ "Maximum fake stack size log.");
+ ParseFlag(str, &f->uar_noreserve, "uar_noreserve",
+ "Use mmap with 'norserve' flag to allocate fake stack.");
+ ParseFlag(str, &f->max_malloc_fill_size, "max_malloc_fill_size",
+ "ASan allocator flag. max_malloc_fill_size is the maximal amount of "
+ "bytes that will be filled with malloc_fill_byte on malloc.");
+ ParseFlag(str, &f->malloc_fill_byte, "malloc_fill_byte",
+ "Value used to fill the newly allocated memory.");
+ ParseFlag(str, &f->exitcode, "exitcode",
+ "Override the program exit status if the tool found an error.");
+ ParseFlag(str, &f->allow_user_poisoning, "allow_user_poisoning",
+ "If set, user may manually mark memory regions as poisoned or "
+ "unpoisoned.");
+ ParseFlag(str, &f->sleep_before_dying, "sleep_before_dying",
+ "Number of seconds to sleep between printing an error report and "
+ "terminating the program. Useful for debugging purposes (e.g. when one "
+ "needs to attach gdb).");
+
+ ParseFlag(str, &f->check_malloc_usable_size, "check_malloc_usable_size",
+ "Allows the users to work around the bug in Nvidia drivers prior to "
+ "295.*.");
+
+ ParseFlag(str, &f->unmap_shadow_on_exit, "unmap_shadow_on_exit",
+ "If set, explicitly unmaps the (huge) shadow at exit.");
+ ParseFlag(str, &f->abort_on_error, "abort_on_error",
+ "If set, the tool calls abort() instead of _exit() after printing the "
+ "error report.");
+ ParseFlag(str, &f->print_stats, "print_stats",
+ "Print various statistics after printing an error message or if "
+ "atexit=1.");
+ ParseFlag(str, &f->print_legend, "print_legend",
+ "Print the legend for the shadow bytes.");
+ ParseFlag(str, &f->atexit, "atexit",
+ "If set, prints ASan exit stats even after program terminates "
+ "successfully.");
+
+ ParseFlag(str, &f->allow_reexec, "allow_reexec",
+ "Allow the tool to re-exec the program. This may interfere badly with "
+ "the debugger.");
+
+ ParseFlag(str, &f->print_full_thread_history,
+ "print_full_thread_history",
+ "If set, prints thread creation stacks for the threads involved in the "
+ "report and their ancestors up to the main thread.");
+
+ ParseFlag(str, &f->poison_heap, "poison_heap",
+ "Poison (or not) the heap memory on [de]allocation. Zero value is useful "
+ "for benchmarking the allocator or instrumentator.");
+
+ ParseFlag(str, &f->poison_array_cookie, "poison_array_cookie",
+ "Poison (or not) the array cookie after operator new[].");
+
+ ParseFlag(str, &f->poison_partial, "poison_partial",
+ "If true, poison partially addressable 8-byte aligned words "
+ "(default=true). This flag affects heap and global buffers, but not "
+ "stack buffers.");
+
+ ParseFlag(str, &f->alloc_dealloc_mismatch, "alloc_dealloc_mismatch",
+ "Report errors on malloc/delete, new/free, new/delete[], etc.");
+
+ ParseFlag(str, &f->new_delete_type_mismatch, "new_delete_type_mismatch",
+ "Report errors on mismatch betwen size of new and delete.");
+
+ ParseFlag(str, &f->strict_memcmp, "strict_memcmp",
+ "If true, assume that memcmp(p1, p2, n) always reads n bytes before "
+ "comparing p1 and p2.");
+
+ ParseFlag(str, &f->strict_init_order, "strict_init_order",
+ "If true, assume that dynamic initializers can never access globals from "
+ "other modules, even if the latter are already initialized.");
+
+ ParseFlag(str, &f->start_deactivated, "start_deactivated",
+ "If true, ASan tweaks a bunch of other flags (quarantine, redzone, heap "
+ "poisoning) to reduce memory consumption as much as possible, and "
+ "restores them to original values when the first instrumented module is "
+ "loaded into the process. This is mainly intended to be used on "
+ "Android. ");
+
+ ParseFlag(str, &f->detect_invalid_pointer_pairs,
+ "detect_invalid_pointer_pairs",
+ "If non-zero, try to detect operations like <, <=, >, >= and - on "
+ "invalid pointer pairs (e.g. when pointers belong to different objects). "
+ "The bigger the value the harder we try.");
+
+ ParseFlag(str, &f->detect_container_overflow,
+ "detect_container_overflow",
+ "If true, honor the container overflow annotations. "
+ "See https://code.google.com/p/address-sanitizer/wiki/ContainerOverflow");
+
+ ParseFlag(str, &f->detect_odr_violation, "detect_odr_violation",
+ "If >=2, detect violation of One-Definition-Rule (ODR); "
+ "If ==1, detect ODR-violation only if the two variables "
+ "have different sizes");
+
+ ParseFlag(str, &f->dump_instruction_bytes, "dump_instruction_bytes",
+ "If true, dump 16 bytes starting at the instruction that caused SEGV");
}
void InitializeFlags(Flags *f, const char *env) {
CommonFlags *cf = common_flags();
- SetCommonFlagDefaults();
+ SetCommonFlagsDefaults(cf);
+ cf->detect_leaks = CAN_SANITIZE_LEAKS;
cf->external_symbolizer_path = GetEnv("ASAN_SYMBOLIZER_PATH");
cf->malloc_context_size = kDefaultMallocContextSize;
+ cf->intercept_tls_get_addr = true;
+ cf->coverage = false;
internal_memset(f, 0, sizeof(*f));
f->quarantine_size = (ASAN_LOW_MEMORY) ? 1UL << 26 : 1UL << 28;
f->redzone = 16;
+ f->max_redzone = 2048;
f->debug = false;
f->report_globals = 1;
f->check_initialization_order = false;
@@ -147,53 +256,58 @@ void InitializeFlags(Flags *f, const char *env) {
f->replace_intrin = true;
f->mac_ignore_invalid_free = false;
f->detect_stack_use_after_return = false; // Also needs the compiler flag.
- f->uar_stack_size_log = 0;
+ f->min_uar_stack_size_log = 16; // We can't do smaller anyway.
+ f->max_uar_stack_size_log = 20; // 1Mb per size class, i.e. ~11Mb per thread.
+ f->uar_noreserve = false;
f->max_malloc_fill_size = 0x1000; // By default, fill only the first 4K.
f->malloc_fill_byte = 0xbe;
f->exitcode = ASAN_DEFAULT_FAILURE_EXITCODE;
f->allow_user_poisoning = true;
f->sleep_before_dying = 0;
- f->handle_segv = ASAN_NEEDS_SEGV;
- f->allow_user_segv_handler = false;
- f->use_sigaltstack = false;
f->check_malloc_usable_size = true;
f->unmap_shadow_on_exit = false;
f->abort_on_error = false;
f->print_stats = false;
f->print_legend = true;
f->atexit = false;
- f->coverage = false;
- f->disable_core = (SANITIZER_WORDSIZE == 64);
f->allow_reexec = true;
f->print_full_thread_history = true;
f->poison_heap = true;
+ f->poison_array_cookie = true;
f->poison_partial = true;
// 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
// TODO(glider,timurrrr): Fix known issues and enable this back.
f->alloc_dealloc_mismatch = (SANITIZER_MAC == 0) && (SANITIZER_WINDOWS == 0);
+ f->new_delete_type_mismatch = true;
f->strict_memcmp = true;
f->strict_init_order = false;
+ f->start_deactivated = false;
+ f->detect_invalid_pointer_pairs = 0;
+ f->detect_container_overflow = true;
+ f->detect_odr_violation = 2;
+ f->dump_instruction_bytes = false;
// Override from compile definition.
- ParseFlagsFromString(f, MaybeUseAsanDefaultOptionsCompileDefiniton());
+ ParseFlagsFromString(f, MaybeUseAsanDefaultOptionsCompileDefinition());
// Override from user-specified string.
ParseFlagsFromString(f, MaybeCallAsanDefaultOptions());
- if (common_flags()->verbosity) {
- Report("Using the defaults from __asan_default_options: %s\n",
- MaybeCallAsanDefaultOptions());
- }
+ VReport(1, "Using the defaults from __asan_default_options: %s\n",
+ MaybeCallAsanDefaultOptions());
// Override from command line.
ParseFlagsFromString(f, env);
+ if (common_flags()->help) {
+ PrintFlagDescriptions();
+ }
-#if !CAN_SANITIZE_LEAKS
- if (cf->detect_leaks) {
+ if (!CAN_SANITIZE_LEAKS && cf->detect_leaks) {
Report("%s: detect_leaks is not supported on this platform.\n",
SanitizerToolName);
cf->detect_leaks = false;
}
-#endif
// Make "strict_init_order" imply "check_initialization_order".
// TODO(samsonov): Use a single runtime flag for an init-order checker.
@@ -202,6 +316,17 @@ void InitializeFlags(Flags *f, const char *env) {
}
}
+// Parse flags that may change between startup and activation.
+// On Android they come from a system property.
+// On other platforms this is no-op.
+void ParseExtraActivationFlags() {
+ char buf[100];
+ GetExtraActivationFlags(buf, sizeof(buf));
+ ParseFlagsFromString(flags(), buf);
+ if (buf[0] != '\0')
+ VReport(1, "Extra activation flags: %s\n", buf);
+}
+
// -------------------------- Globals --------------------- {{{1
int asan_inited;
bool asan_init_is_running;
@@ -223,6 +348,7 @@ static void ReserveShadowMemoryRange(uptr beg, uptr end) {
CHECK_EQ((beg % GetPageSizeCached()), 0);
CHECK_EQ(((end + 1) % GetPageSizeCached()), 0);
uptr size = end - beg + 1;
+ DecreaseTotalMmap(size); // Don't count the shadow against mmap_limit_mb.
void *res = MmapFixedNoReserve(beg, size);
if (res != (void*)beg) {
Report("ReserveShadowMemoryRange failed while trying to map 0x%zx bytes. "
@@ -268,6 +394,53 @@ void __asan_report_ ## type ## _n(uptr addr, uptr size) { \
ASAN_REPORT_ERROR_N(load, false)
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); \
+ void __asan_##type##size(uptr addr) { \
+ uptr sp = MEM_TO_SHADOW(addr); \
+ uptr s = size <= SHADOW_GRANULARITY ? *reinterpret_cast<u8 *>(sp) \
+ : *reinterpret_cast<u16 *>(sp); \
+ if (UNLIKELY(s)) { \
+ if (UNLIKELY(size >= SHADOW_GRANULARITY || \
+ ((s8)((addr & (SHADOW_GRANULARITY - 1)) + size - 1)) >= \
+ (s8)s)) { \
+ if (__asan_test_only_reported_buggy_pointer) { \
+ *__asan_test_only_reported_buggy_pointer = addr; \
+ } else { \
+ GET_CALLER_PC_BP_SP; \
+ __asan_report_error(pc, bp, sp, addr, is_write, size); \
+ } \
+ } \
+ } \
+ }
+
+ASAN_MEMORY_ACCESS_CALLBACK(load, false, 1)
+ASAN_MEMORY_ACCESS_CALLBACK(load, false, 2)
+ASAN_MEMORY_ACCESS_CALLBACK(load, false, 4)
+ASAN_MEMORY_ACCESS_CALLBACK(load, false, 8)
+ASAN_MEMORY_ACCESS_CALLBACK(load, false, 16)
+ASAN_MEMORY_ACCESS_CALLBACK(store, true, 1)
+ASAN_MEMORY_ACCESS_CALLBACK(store, true, 2)
+ASAN_MEMORY_ACCESS_CALLBACK(store, true, 4)
+ASAN_MEMORY_ACCESS_CALLBACK(store, true, 8)
+ASAN_MEMORY_ACCESS_CALLBACK(store, true, 16)
+
+extern "C"
+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);
+ }
+}
+
+extern "C"
+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);
+ }
+}
+
// Force the linker to keep the symbols for various ASan interface functions.
// We want to keep those in the executable in order to let the instrumented
// dynamic libraries access the symbol even if it is not used by the executable
@@ -294,13 +467,6 @@ static NOINLINE void force_interface_symbols() {
case 15: __asan_set_error_report_callback(0); break;
case 16: __asan_handle_no_return(); break;
case 17: __asan_address_is_poisoned(0); break;
- case 18: __asan_get_allocated_size(0); break;
- case 19: __asan_get_current_allocated_bytes(); break;
- case 20: __asan_get_estimated_allocated_size(0); break;
- case 21: __asan_get_free_bytes(); break;
- case 22: __asan_get_heap_size(); break;
- case 23: __asan_get_ownership(0); break;
- case 24: __asan_get_unmapped_bytes(); break;
case 25: __asan_poison_memory_region(0, 0); break;
case 26: __asan_unpoison_memory_region(0, 0); break;
case 27: __asan_set_error_exit_code(0); break;
@@ -371,7 +537,8 @@ static void PrintAddressSpaceLayout() {
(void*)MEM_TO_SHADOW(kMidShadowEnd));
}
Printf("\n");
- Printf("red_zone=%zu\n", (uptr)flags()->redzone);
+ Printf("redzone=%zu\n", (uptr)flags()->redzone);
+ Printf("max_redzone=%zu\n", (uptr)flags()->max_redzone);
Printf("quarantine_size=%zuM\n", (uptr)flags()->quarantine_size >> 20);
Printf("malloc_context_size=%zu\n",
(uptr)common_flags()->malloc_context_size);
@@ -386,59 +553,17 @@ static void PrintAddressSpaceLayout() {
kHighShadowBeg > kMidMemEnd);
}
-} // namespace __asan
-
-// ---------------------- Interface ---------------- {{{1
-using namespace __asan; // NOLINT
-
-#if !SANITIZER_SUPPORTS_WEAK_HOOKS
-extern "C" {
-SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
-const char* __asan_default_options() { return ""; }
-} // extern "C"
-#endif
-
-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);
- static const uptr kMaxExpectedCleanupSize = 64 << 20; // 64M
- if (top - bottom > kMaxExpectedCleanupSize) {
- static bool reported_warning = false;
- if (reported_warning)
- return;
- reported_warning = true;
- Report("WARNING: ASan is ignoring requested __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",
- top, bottom, top - bottom, top - bottom);
- return;
- }
- PoisonShadow(bottom, top - bottom, 0);
- if (curr_thread->has_fake_stack())
- curr_thread->fake_stack()->HandleNoReturn();
-}
-
-void NOINLINE __asan_set_death_callback(void (*callback)(void)) {
- death_callback = callback;
-}
-
-void __asan_init() {
- if (asan_inited) return;
+static void AsanInitInternal() {
+ if (LIKELY(asan_inited)) return;
SanitizerToolName = "AddressSanitizer";
CHECK(!asan_init_is_running && "ASan init calls itself!");
asan_init_is_running = true;
+
+ // Initialize flags. This must be done early, because most of the
+ // initialization steps look at flags().
+ const char *options = GetEnv("ASAN_OPTIONS");
+ InitializeFlags(flags(), options);
+
InitializeHighMemEnd();
// Make sure we are not statically linked.
@@ -449,18 +574,21 @@ void __asan_init() {
SetCheckFailedCallback(AsanCheckFailed);
SetPrintfAndReportCallback(AppendToErrorMessageBuffer);
- // Initialize flags. This must be done early, because most of the
- // initialization steps look at flags().
- const char *options = GetEnv("ASAN_OPTIONS");
- InitializeFlags(flags(), options);
+ if (!flags()->start_deactivated)
+ ParseExtraActivationFlags();
+
__sanitizer_set_report_path(common_flags()->log_path);
__asan_option_detect_stack_use_after_return =
flags()->detect_stack_use_after_return;
+ CHECK_LE(flags()->min_uar_stack_size_log, flags()->max_uar_stack_size_log);
- if (common_flags()->verbosity && options) {
- Report("Parsed ASAN_OPTIONS: %s\n", options);
+ if (options) {
+ VReport(1, "Parsed ASAN_OPTIONS: %s\n", options);
}
+ if (flags()->start_deactivated)
+ AsanStartDeactivated();
+
// Re-exec ourselves if we need to set additional env or command line args.
MaybeReexec();
@@ -469,8 +597,12 @@ void __asan_init() {
InitializeAsanInterceptors();
+ // Enable system log ("adb logcat") on Android.
+ // Doing this before interceptors are initialized crashes in:
+ // AsanInitInternal -> android_log_write -> __interceptor_strcmp
+ AndroidLogInit();
+
ReplaceSystemMalloc();
- ReplaceOperatorsNewAndDelete();
uptr shadow_start = kLowShadowBeg;
if (kLowShadowBeg)
@@ -478,7 +610,8 @@ void __asan_init() {
bool full_shadow_is_available =
MemoryRangeIsAvailable(shadow_start, kHighShadowEnd);
-#if SANITIZER_LINUX && defined(__x86_64__) && !ASAN_FIXED_MAPPING
+#if SANITIZER_LINUX && defined(__x86_64__) && defined(_LP64) && \
+ !ASAN_FIXED_MAPPING
if (!full_shadow_is_available) {
kMidMemBeg = kLowMemEnd < 0x3000000000ULL ? 0x3000000000ULL : 0;
kMidMemEnd = kLowMemEnd < 0x3000000000ULL ? 0x4fffffffffULL : 0;
@@ -488,9 +621,7 @@ void __asan_init() {
if (common_flags()->verbosity)
PrintAddressSpaceLayout();
- if (flags()->disable_core) {
- DisableCoreDumper();
- }
+ DisableCoreDumperIfNecessary();
if (full_shadow_is_available) {
// mmap the low shadow plus at least one page at the left.
@@ -500,6 +631,7 @@ void __asan_init() {
ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd);
// protect the gap.
ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1);
+ CHECK_EQ(kShadowGapEnd, kHighShadowBeg - 1);
} else if (kMidMemBeg &&
MemoryRangeIsAvailable(shadow_start, kMidMemBeg - 1) &&
MemoryRangeIsAvailable(kMidMemEnd + 1, kHighShadowEnd)) {
@@ -522,19 +654,10 @@ void __asan_init() {
}
AsanTSDInit(PlatformTSDDtor);
- InstallSignalHandlers();
+ InstallDeadlySignalHandlers(AsanOnSIGSEGV);
- // Allocator should be initialized before starting external symbolizer, as
- // fork() on Mac locks the allocator.
InitializeAllocator();
- // Start symbolizer process if necessary.
- if (common_flags()->symbolize) {
- Symbolizer::Init(common_flags()->external_symbolizer_path);
- } else {
- Symbolizer::Disable();
- }
-
// On Linux AsanThread::ThreadStart() calls malloc() that's why asan_inited
// should be set to 1 prior to initializing the threads.
asan_inited = 1;
@@ -543,30 +666,111 @@ void __asan_init() {
if (flags()->atexit)
Atexit(asan_atexit);
- if (flags()->coverage)
+ if (common_flags()->coverage) {
+ __sanitizer_cov_init();
Atexit(__sanitizer_cov_dump);
+ }
// interceptors
InitTlsSize();
// Create main thread.
- AsanThread *main_thread = AsanThread::Create(0, 0);
- CreateThreadContextArgs create_main_args = { main_thread, 0 };
- u32 main_tid = asanThreadRegistry().CreateThread(
- 0, true, 0, &create_main_args);
- CHECK_EQ(0, main_tid);
+ AsanThread *main_thread = AsanThread::Create(
+ /* start_routine */ nullptr, /* arg */ nullptr, /* parent_tid */ 0,
+ /* stack */ nullptr, /* detached */ true);
+ CHECK_EQ(0, main_thread->tid());
SetCurrentThread(main_thread);
- main_thread->ThreadStart(internal_getpid());
+ main_thread->ThreadStart(internal_getpid(),
+ /* signal_thread_is_registered */ nullptr);
force_interface_symbols(); // no-op.
+ SanitizerInitializeUnwinder();
#if CAN_SANITIZE_LEAKS
- __lsan::InitCommonLsan();
+ __lsan::InitCommonLsan(false);
if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit) {
Atexit(__lsan::DoLeakCheck);
}
#endif // CAN_SANITIZE_LEAKS
- if (common_flags()->verbosity) {
- Report("AddressSanitizer Init done\n");
+ InitializeSuppressions();
+
+ VReport(1, "AddressSanitizer Init done\n");
+}
+
+// Initialize as requested from some part of ASan runtime library (interceptors,
+// allocator, etc).
+void AsanInitFromRtl() {
+ AsanInitInternal();
+}
+
+#if ASAN_DYNAMIC
+// Initialize runtime in case it's LD_PRELOAD-ed into unsanitized executable
+// (and thus normal initializer from .preinit_array haven't run).
+
+class AsanInitializer {
+public: // NOLINT
+ AsanInitializer() {
+ AsanCheckIncompatibleRT();
+ AsanCheckDynamicRTPrereqs();
+ AsanInitFromRtl();
+ }
+};
+
+static AsanInitializer asan_initializer;
+#endif // ASAN_DYNAMIC
+
+} // namespace __asan
+
+// ---------------------- Interface ---------------- {{{1
+using namespace __asan; // NOLINT
+
+#if !SANITIZER_SUPPORTS_WEAK_HOOKS
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+const char* __asan_default_options() { return ""; }
+} // extern "C"
+#endif
+
+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);
+ static const uptr kMaxExpectedCleanupSize = 64 << 20; // 64M
+ if (top - bottom > kMaxExpectedCleanupSize) {
+ static bool reported_warning = false;
+ if (reported_warning)
+ return;
+ reported_warning = true;
+ Report("WARNING: ASan is ignoring requested __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",
+ top, bottom, top - bottom, top - bottom);
+ return;
}
+ PoisonShadow(bottom, top - bottom, 0);
+ if (curr_thread->has_fake_stack())
+ curr_thread->fake_stack()->HandleNoReturn();
+}
+
+void NOINLINE __asan_set_death_callback(void (*callback)(void)) {
+ death_callback = callback;
+}
+
+// Initialize as requested from instrumented application code.
+// We use this call as a trigger to wake up ASan from deactivated state.
+void __asan_init() {
+ AsanCheckIncompatibleRT();
+ AsanActivate();
+ AsanInitInternal();
}
diff --git a/lib/asan/asan_stack.cc b/lib/asan/asan_stack.cc
index 0bc5a5f2d036..8188f3b5b6e9 100644
--- a/lib/asan/asan_stack.cc
+++ b/lib/asan/asan_stack.cc
@@ -12,36 +12,14 @@
// Code for ASan stack trace.
//===----------------------------------------------------------------------===//
#include "asan_internal.h"
-#include "asan_flags.h"
#include "asan_stack.h"
-#include "sanitizer_common/sanitizer_flags.h"
-
-namespace __asan {
-
-static bool MaybeCallAsanSymbolize(const void *pc, char *out_buffer,
- int out_size) {
- return (&__asan_symbolize) ? __asan_symbolize(pc, out_buffer, out_size)
- : false;
-}
-
-void PrintStack(const uptr *trace, uptr size) {
- StackTrace::PrintStack(trace, size, MaybeCallAsanSymbolize);
-}
-
-void PrintStack(StackTrace *stack) {
- PrintStack(stack->trace, stack->size);
-}
-
-} // namespace __asan
// ------------------ Interface -------------- {{{1
-// Provide default implementation of __asan_symbolize that does nothing
-// and may be overriden by user if he wants to use his own symbolization.
-// ASan on Windows has its own implementation of this.
-#if !SANITIZER_WINDOWS && !SANITIZER_SUPPORTS_WEAK_HOOKS
-SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE NOINLINE
-bool __asan_symbolize(const void *pc, char *out_buffer, int out_size) {
- return false;
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_print_stack_trace() {
+ using namespace __asan;
+ PRINT_CURRENT_STACK();
}
-#endif
+} // extern "C"
diff --git a/lib/asan/asan_stack.h b/lib/asan/asan_stack.h
index 7f5fd661eec8..a995256212e1 100644
--- a/lib/asan/asan_stack.h
+++ b/lib/asan/asan_stack.h
@@ -21,48 +21,75 @@
namespace __asan {
-void PrintStack(StackTrace *stack);
-void PrintStack(const uptr *trace, uptr size);
-
-} // namespace __asan
-
// Get the stack trace with the given pc and bp.
// The pc will be in the position 0 of the resulting stack trace.
// The bp may refer to the current frame or to the caller's frame.
+ALWAYS_INLINE
+void GetStackTraceWithPcBpAndContext(BufferedStackTrace *stack, uptr max_depth,
+ uptr pc, uptr bp, void *context,
+ bool fast) {
#if SANITIZER_WINDOWS
-#define GET_STACK_TRACE_WITH_PC_AND_BP(max_s, pc, bp, fast) \
- StackTrace stack; \
- stack.Unwind(max_s, pc, bp, 0, 0, fast)
+ stack->Unwind(max_depth, pc, bp, context, 0, 0, fast);
#else
-#define GET_STACK_TRACE_WITH_PC_AND_BP(max_s, pc, bp, fast) \
- StackTrace stack; \
- { \
- AsanThread *t; \
- stack.size = 0; \
- if (asan_inited && (t = GetCurrentThread()) && !t->isUnwinding()) { \
- uptr stack_top = t->stack_top(); \
- uptr stack_bottom = t->stack_bottom(); \
- ScopedUnwinding unwind_scope(t); \
- stack.Unwind(max_s, pc, bp, stack_top, stack_bottom, fast); \
- } \
+ AsanThread *t;
+ stack->size = 0;
+ if (LIKELY(asan_inited)) {
+ if ((t = GetCurrentThread()) && !t->isUnwinding()) {
+ // On FreeBSD the slow unwinding that leverages _Unwind_Backtrace()
+ // yields the call stack of the signal's handler and not of the code
+ // that raised the signal (as it does on Linux).
+ if (SANITIZER_FREEBSD && t->isInDeadlySignal()) fast = true;
+ uptr stack_top = t->stack_top();
+ 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) {
+ /* If GetCurrentThread() has failed, try to do slow unwind anyways. */
+ stack->Unwind(max_depth, pc, bp, context, 0, 0, false);
+ }
}
#endif // SANITIZER_WINDOWS
+}
+
+} // 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
// don't want stack trace to contain functions from ASan internals.
-#define GET_STACK_TRACE(max_size, fast) \
- GET_STACK_TRACE_WITH_PC_AND_BP(max_size, \
- StackTrace::GetCurrentPc(), GET_CURRENT_FRAME(), fast)
+#define GET_STACK_TRACE(max_size, fast) \
+ BufferedStackTrace stack; \
+ if (max_size <= 2) { \
+ stack.size = max_size; \
+ if (max_size > 0) { \
+ stack.top_frame_bp = GET_CURRENT_FRAME(); \
+ stack.trace_buffer[0] = StackTrace::GetCurrentPc(); \
+ if (max_size > 1) \
+ stack.trace_buffer[1] = GET_CALLER_PC(); \
+ } \
+ } else { \
+ GetStackTraceWithPcBpAndContext(&stack, max_size, \
+ StackTrace::GetCurrentPc(), \
+ GET_CURRENT_FRAME(), 0, fast); \
+ }
+
+#define GET_STACK_TRACE_FATAL(pc, bp) \
+ BufferedStackTrace stack; \
+ GetStackTraceWithPcBpAndContext(&stack, kStackTraceMax, pc, bp, 0, \
+ common_flags()->fast_unwind_on_fatal)
-#define GET_STACK_TRACE_FATAL(pc, bp) \
- GET_STACK_TRACE_WITH_PC_AND_BP(kStackTraceMax, pc, bp, \
- common_flags()->fast_unwind_on_fatal)
+#define GET_STACK_TRACE_SIGNAL(sig) \
+ BufferedStackTrace stack; \
+ GetStackTraceWithPcBpAndContext(&stack, kStackTraceMax, \
+ (sig).pc, (sig).bp, (sig).context, \
+ common_flags()->fast_unwind_on_fatal)
#define GET_STACK_TRACE_FATAL_HERE \
GET_STACK_TRACE(kStackTraceMax, common_flags()->fast_unwind_on_fatal)
+#define GET_STACK_TRACE_CHECK_HERE \
+ GET_STACK_TRACE(kStackTraceMax, common_flags()->fast_unwind_on_check)
+
#define GET_STACK_TRACE_THREAD \
GET_STACK_TRACE(kStackTraceMax, true)
@@ -72,11 +99,16 @@ void PrintStack(const uptr *trace, uptr size);
#define GET_STACK_TRACE_FREE GET_STACK_TRACE_MALLOC
-#define PRINT_CURRENT_STACK() \
- { \
- GET_STACK_TRACE(kStackTraceMax, \
- common_flags()->fast_unwind_on_fatal); \
- PrintStack(&stack); \
+#define PRINT_CURRENT_STACK() \
+ { \
+ GET_STACK_TRACE_FATAL_HERE; \
+ stack.Print(); \
+ }
+
+#define PRINT_CURRENT_STACK_CHECK() \
+ { \
+ GET_STACK_TRACE_CHECK_HERE; \
+ stack.Print(); \
}
#endif // ASAN_STACK_H
diff --git a/lib/asan/asan_stats.cc b/lib/asan/asan_stats.cc
index 73dc3c5ac44f..a78b7b1e926d 100644
--- a/lib/asan/asan_stats.cc
+++ b/lib/asan/asan_stats.cc
@@ -15,6 +15,7 @@
#include "asan_internal.h"
#include "asan_stats.h"
#include "asan_thread.h"
+#include "sanitizer_common/sanitizer_allocator_interface.h"
#include "sanitizer_common/sanitizer_mutex.h"
#include "sanitizer_common/sanitizer_stackdepot.h"
@@ -129,8 +130,8 @@ static void PrintAccumulatedStats() {
BlockingMutexLock lock(&print_lock);
stats.Print();
StackDepotStats *stack_depot_stats = StackDepotGetStats();
- Printf("Stats: StackDepot: %zd ids; %zdM mapped\n",
- stack_depot_stats->n_uniq_ids, stack_depot_stats->mapped >> 20);
+ Printf("Stats: StackDepot: %zd ids; %zdM allocated\n",
+ stack_depot_stats->n_uniq_ids, stack_depot_stats->allocated >> 20);
PrintInternalAllocatorStats();
}
@@ -139,7 +140,7 @@ static void PrintAccumulatedStats() {
// ---------------------- Interface ---------------- {{{1
using namespace __asan; // NOLINT
-uptr __asan_get_current_allocated_bytes() {
+uptr __sanitizer_get_current_allocated_bytes() {
AsanStats stats;
GetAccumulatedStats(&stats);
uptr malloced = stats.malloced;
@@ -149,13 +150,13 @@ uptr __asan_get_current_allocated_bytes() {
return (malloced > freed) ? malloced - freed : 1;
}
-uptr __asan_get_heap_size() {
+uptr __sanitizer_get_heap_size() {
AsanStats stats;
GetAccumulatedStats(&stats);
return stats.mmaped - stats.munmaped;
}
-uptr __asan_get_free_bytes() {
+uptr __sanitizer_get_free_bytes() {
AsanStats stats;
GetAccumulatedStats(&stats);
uptr total_free = stats.mmaped
@@ -169,7 +170,7 @@ uptr __asan_get_free_bytes() {
return (total_free > total_used) ? total_free - total_used : 1;
}
-uptr __asan_get_unmapped_bytes() {
+uptr __sanitizer_get_unmapped_bytes() {
return 0;
}
diff --git a/lib/asan/asan_stats.h b/lib/asan/asan_stats.h
index e3030e88fdc2..c66848dc5713 100644
--- a/lib/asan/asan_stats.h
+++ b/lib/asan/asan_stats.h
@@ -47,9 +47,9 @@ struct AsanStats {
uptr malloc_large;
uptr malloc_small_slow;
- // Ctor for global AsanStats (accumulated stats and main thread stats).
+ // Ctor for global AsanStats (accumulated stats for dead threads).
explicit AsanStats(LinkerInitialized) { }
- // Default ctor for thread-local stats.
+ // Creates empty stats.
AsanStats();
void Print(); // Prints formatted stats to stderr.
diff --git a/lib/asan/asan_suppressions.cc b/lib/asan/asan_suppressions.cc
new file mode 100644
index 000000000000..ef554716faa0
--- /dev/null
+++ b/lib/asan/asan_suppressions.cc
@@ -0,0 +1,87 @@
+//===-- asan_suppressions.cc ----------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Issue suppression and suppression-related functions.
+//===----------------------------------------------------------------------===//
+
+#include "asan_suppressions.h"
+
+#include "asan_stack.h"
+#include "sanitizer_common/sanitizer_suppressions.h"
+#include "sanitizer_common/sanitizer_symbolizer.h"
+
+namespace __asan {
+
+static bool suppressions_inited = false;
+
+void InitializeSuppressions() {
+ CHECK(!suppressions_inited);
+ SuppressionContext::InitIfNecessary();
+ suppressions_inited = true;
+}
+
+bool IsInterceptorSuppressed(const char *interceptor_name) {
+ CHECK(suppressions_inited);
+ SuppressionContext *ctx = SuppressionContext::Get();
+ Suppression *s;
+ // Match "interceptor_name" suppressions.
+ return ctx->Match(interceptor_name, SuppressionInterceptorName, &s);
+}
+
+bool HaveStackTraceBasedSuppressions() {
+ CHECK(suppressions_inited);
+ SuppressionContext *ctx = SuppressionContext::Get();
+ return ctx->HasSuppressionType(SuppressionInterceptorViaFunction) ||
+ ctx->HasSuppressionType(SuppressionInterceptorViaLibrary);
+}
+
+bool IsStackTraceSuppressed(const StackTrace *stack) {
+ CHECK(suppressions_inited);
+ if (!HaveStackTraceBasedSuppressions())
+ return false;
+
+ SuppressionContext *ctx = SuppressionContext::Get();
+ Symbolizer *symbolizer = Symbolizer::GetOrInit();
+ Suppression *s;
+ for (uptr i = 0; i < stack->size && stack->trace[i]; i++) {
+ uptr addr = stack->trace[i];
+
+ if (ctx->HasSuppressionType(SuppressionInterceptorViaLibrary)) {
+ const char *module_name;
+ uptr module_offset;
+ // Match "interceptor_via_lib" suppressions.
+ if (symbolizer->GetModuleNameAndOffsetForPC(addr, &module_name,
+ &module_offset) &&
+ ctx->Match(module_name, SuppressionInterceptorViaLibrary, &s)) {
+ return true;
+ }
+ }
+
+ if (ctx->HasSuppressionType(SuppressionInterceptorViaFunction)) {
+ SymbolizedStack *frames = symbolizer->SymbolizePC(addr);
+ for (SymbolizedStack *cur = frames; cur; cur = cur->next) {
+ const char *function_name = cur->info.function;
+ if (!function_name) {
+ continue;
+ }
+ // Match "interceptor_via_fun" suppressions.
+ if (ctx->Match(function_name, SuppressionInterceptorViaFunction, &s)) {
+ frames->ClearAll();
+ return true;
+ }
+ }
+ frames->ClearAll();
+ }
+ }
+ return false;
+}
+
+} // namespace __asan
diff --git a/lib/asan/asan_suppressions.h b/lib/asan/asan_suppressions.h
new file mode 100644
index 000000000000..cd7ba2ef0ae7
--- /dev/null
+++ b/lib/asan/asan_suppressions.h
@@ -0,0 +1,29 @@
+//===-- asan_suppressions.h -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// ASan-private header for asan_suppressions.cc.
+//===----------------------------------------------------------------------===//
+#ifndef ASAN_SUPPRESSIONS_H
+#define ASAN_SUPPRESSIONS_H
+
+#include "asan_internal.h"
+#include "sanitizer_common/sanitizer_stacktrace.h"
+
+namespace __asan {
+
+void InitializeSuppressions();
+bool IsInterceptorSuppressed(const char *interceptor_name);
+bool HaveStackTraceBasedSuppressions();
+bool IsStackTraceSuppressed(const StackTrace *stack);
+
+} // namespace __asan
+
+#endif // ASAN_SUPPRESSIONS_H
diff --git a/lib/asan/asan_thread.cc b/lib/asan/asan_thread.cc
index 328ac2fcd398..9af5706d86d0 100644
--- a/lib/asan/asan_thread.cc
+++ b/lib/asan/asan_thread.cc
@@ -20,16 +20,22 @@
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_placement_new.h"
#include "sanitizer_common/sanitizer_stackdepot.h"
+#include "sanitizer_common/sanitizer_tls_get_addr.h"
#include "lsan/lsan_common.h"
namespace __asan {
// AsanThreadContext implementation.
+struct CreateThreadContextArgs {
+ AsanThread *thread;
+ StackTrace *stack;
+};
+
void AsanThreadContext::OnCreated(void *arg) {
CreateThreadContextArgs *args = static_cast<CreateThreadContextArgs*>(arg);
if (args->stack)
- stack_id = StackDepotPut(args->stack->trace, args->stack->size);
+ stack_id = StackDepotPut(*args->stack);
thread = args->thread;
thread->set_context(this);
}
@@ -74,42 +80,44 @@ AsanThreadContext *GetThreadContextByTidLocked(u32 tid) {
// AsanThread implementation.
-AsanThread *AsanThread::Create(thread_callback_t start_routine,
- void *arg) {
+AsanThread *AsanThread::Create(thread_callback_t start_routine, void *arg,
+ u32 parent_tid, StackTrace *stack,
+ bool detached) {
uptr PageSize = GetPageSizeCached();
uptr size = RoundUpTo(sizeof(AsanThread), PageSize);
- AsanThread *thread = (AsanThread*)MmapOrDie(size, __FUNCTION__);
+ AsanThread *thread = (AsanThread*)MmapOrDie(size, __func__);
thread->start_routine_ = start_routine;
thread->arg_ = arg;
- thread->context_ = 0;
+ CreateThreadContextArgs args = { thread, stack };
+ asanThreadRegistry().CreateThread(*reinterpret_cast<uptr *>(thread), detached,
+ parent_tid, &args);
return thread;
}
void AsanThread::TSDDtor(void *tsd) {
AsanThreadContext *context = (AsanThreadContext*)tsd;
- if (common_flags()->verbosity >= 1)
- Report("T%d TSDDtor\n", context->tid);
+ VReport(1, "T%d TSDDtor\n", context->tid);
if (context->thread)
context->thread->Destroy();
}
void AsanThread::Destroy() {
- if (common_flags()->verbosity >= 1) {
- Report("T%d exited\n", tid());
- }
+ int tid = this->tid();
+ VReport(1, "T%d exited\n", tid);
malloc_storage().CommitBack();
- if (flags()->use_sigaltstack) UnsetAlternateSignalStack();
- asanThreadRegistry().FinishThread(tid());
+ if (common_flags()->use_sigaltstack) UnsetAlternateSignalStack();
+ asanThreadRegistry().FinishThread(tid);
FlushToDeadThreadStats(&stats_);
// We also clear the shadow on thread destruction because
// some code may still be executing in later TSD destructors
// and we don't want it to have any poisoned stack.
ClearShadowForThreadStackAndTLS();
- DeleteFakeStack();
+ DeleteFakeStack(tid);
uptr size = RoundUpTo(sizeof(AsanThread), GetPageSizeCached());
UnmapOrDie(this, size);
+ DTLS_Destroy();
}
// We want to create the FakeStack lazyly on the first use, but not eralier
@@ -124,13 +132,16 @@ FakeStack *AsanThread::AsyncSignalSafeLazyInitFakeStack() {
// 1 -- being initialized
// ptr -- initialized
// This CAS checks if the state was 0 and if so changes it to state 1,
- // if that was successfull, it initilizes the pointer.
+ // if that was successful, it initializes the pointer.
if (atomic_compare_exchange_strong(
reinterpret_cast<atomic_uintptr_t *>(&fake_stack_), &old_val, 1UL,
memory_order_relaxed)) {
uptr stack_size_log = Log2(RoundUpToPowerOfTwo(stack_size));
- if (flags()->uar_stack_size_log)
- stack_size_log = static_cast<uptr>(flags()->uar_stack_size_log);
+ CHECK_LE(flags()->min_uar_stack_size_log, flags()->max_uar_stack_size_log);
+ stack_size_log =
+ Min(stack_size_log, static_cast<uptr>(flags()->max_uar_stack_size_log));
+ stack_size_log =
+ Max(stack_size_log, static_cast<uptr>(flags()->min_uar_stack_size_log));
fake_stack_ = FakeStack::Create(stack_size_log);
SetTLSFakeStack(fake_stack_);
return fake_stack_;
@@ -139,24 +150,28 @@ FakeStack *AsanThread::AsyncSignalSafeLazyInitFakeStack() {
}
void AsanThread::Init() {
+ fake_stack_ = 0; // Will be initialized lazily if needed.
+ CHECK_EQ(this->stack_size(), 0U);
SetThreadStackAndTls();
+ CHECK_GT(this->stack_size(), 0U);
CHECK(AddrIsInMem(stack_bottom_));
CHECK(AddrIsInMem(stack_top_ - 1));
ClearShadowForThreadStackAndTLS();
- if (common_flags()->verbosity >= 1) {
- int local = 0;
- Report("T%d: stack [%p,%p) size 0x%zx; local=%p\n",
- tid(), (void*)stack_bottom_, (void*)stack_top_,
- stack_top_ - stack_bottom_, &local);
- }
- fake_stack_ = 0; // Will be initialized lazily if needed.
+ int local = 0;
+ 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) {
+thread_return_t AsanThread::ThreadStart(
+ uptr os_id, atomic_uintptr_t *signal_thread_is_registered) {
Init();
asanThreadRegistry().StartThread(tid(), os_id, 0);
- if (flags()->use_sigaltstack) SetAlternateSignalStack();
+ if (signal_thread_is_registered)
+ atomic_store(signal_thread_is_registered, 1, memory_order_release);
+
+ if (common_flags()->use_sigaltstack) SetAlternateSignalStack();
if (!start_routine_) {
// start_routine_ == 0 if we're on the main thread or on one of the
@@ -196,17 +211,18 @@ void AsanThread::ClearShadowForThreadStackAndTLS() {
PoisonShadow(tls_begin_, tls_end_ - tls_begin_, 0);
}
-const char *AsanThread::GetFrameNameByAddr(uptr addr, uptr *offset,
- uptr *frame_pc) {
+bool AsanThread::GetStackFrameAccessByAddr(uptr addr,
+ StackFrameAccess *access) {
uptr bottom = 0;
if (AddrIsInStack(addr)) {
bottom = stack_bottom();
} else if (has_fake_stack()) {
bottom = fake_stack()->AddrIsInFakeStack(addr);
CHECK(bottom);
- *offset = addr - bottom;
- *frame_pc = ((uptr*)bottom)[2];
- return (const char *)((uptr*)bottom)[1];
+ access->offset = addr - bottom;
+ access->frame_pc = ((uptr*)bottom)[2];
+ access->frame_descr = (const char *)((uptr*)bottom)[1];
+ return true;
}
uptr aligned_addr = addr & ~(SANITIZER_WORDSIZE/8 - 1); // align addr.
u8 *shadow_ptr = (u8*)MemToShadow(aligned_addr);
@@ -223,15 +239,15 @@ const char *AsanThread::GetFrameNameByAddr(uptr addr, uptr *offset,
}
if (shadow_ptr < shadow_bottom) {
- *offset = 0;
- return "UNKNOWN";
+ return false;
}
uptr* ptr = (uptr*)SHADOW_TO_MEM((uptr)(shadow_ptr + 1));
CHECK(ptr[0] == kCurrentStackFrameMagic);
- *offset = addr - (uptr)ptr;
- *frame_pc = ptr[2];
- return (const char*)ptr[1];
+ access->offset = addr - (uptr)ptr;
+ access->frame_pc = ptr[2];
+ access->frame_descr = (const char*)ptr[1];
+ return true;
}
static bool ThreadStackContainsAddress(ThreadContextBase *tctx_base,
@@ -268,10 +284,8 @@ AsanThread *GetCurrentThread() {
void SetCurrentThread(AsanThread *t) {
CHECK(t->context());
- if (common_flags()->verbosity >= 2) {
- Report("SetCurrentThread: %p for thread %p\n",
- t->context(), (void*)GetThreadSelf());
- }
+ VReport(2, "SetCurrentThread: %p for thread %p\n", t->context(),
+ (void *)GetThreadSelf());
// Make sure we do not reset the current AsanThread.
CHECK_EQ(0, AsanTSDGet());
AsanTSDSet(t->context());
diff --git a/lib/asan/asan_thread.h b/lib/asan/asan_thread.h
index 11771ecd09f0..9da136c87ef1 100644
--- a/lib/asan/asan_thread.h
+++ b/lib/asan/asan_thread.h
@@ -17,7 +17,6 @@
#include "asan_allocator.h"
#include "asan_internal.h"
#include "asan_fake_stack.h"
-#include "asan_stack.h"
#include "asan_stats.h"
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_libc.h"
@@ -56,12 +55,14 @@ COMPILER_CHECK(sizeof(AsanThreadContext) <= 256);
// AsanThread are stored in TSD and destroyed when the thread dies.
class AsanThread {
public:
- static AsanThread *Create(thread_callback_t start_routine, void *arg);
+ static AsanThread *Create(thread_callback_t start_routine, void *arg,
+ u32 parent_tid, StackTrace *stack, bool detached);
static void TSDDtor(void *tsd);
void Destroy();
void Init(); // Should be called from the thread itself.
- thread_return_t ThreadStart(uptr os_id);
+ thread_return_t ThreadStart(uptr os_id,
+ atomic_uintptr_t *signal_thread_is_registered);
uptr stack_top() { return stack_top_; }
uptr stack_bottom() { return stack_bottom_; }
@@ -72,18 +73,23 @@ class AsanThread {
AsanThreadContext *context() { return context_; }
void set_context(AsanThreadContext *context) { context_ = context; }
- const char *GetFrameNameByAddr(uptr addr, uptr *offset, uptr *frame_pc);
+ struct StackFrameAccess {
+ uptr offset;
+ uptr frame_pc;
+ const char *frame_descr;
+ };
+ bool GetStackFrameAccessByAddr(uptr addr, StackFrameAccess *access);
bool AddrIsInStack(uptr addr) {
return addr >= stack_bottom_ && addr < stack_top_;
}
- void DeleteFakeStack() {
+ void DeleteFakeStack(int tid) {
if (!fake_stack_) return;
FakeStack *t = fake_stack_;
fake_stack_ = 0;
SetTLSFakeStack(0);
- t->Destroy();
+ t->Destroy(tid);
}
bool has_fake_stack() {
@@ -101,14 +107,19 @@ class AsanThread {
// True is this thread is currently unwinding stack (i.e. collecting a stack
// trace). Used to prevent deadlocks on platforms where libc unwinder calls
// malloc internally. See PR17116 for more details.
- bool isUnwinding() const { return unwinding; }
- void setUnwinding(bool b) { unwinding = b; }
+ bool isUnwinding() const { return unwinding_; }
+ void setUnwinding(bool b) { unwinding_ = b; }
+
+ // True if we are in a deadly signal handler.
+ bool isInDeadlySignal() const { return in_deadly_signal_; }
+ void setInDeadlySignal(bool b) { in_deadly_signal_ = b; }
AsanThreadLocalMallocStorage &malloc_storage() { return malloc_storage_; }
AsanStats &stats() { return stats_; }
private:
- AsanThread() : unwinding(false) {}
+ // NOTE: There is no AsanThread constructor. It is allocated
+ // via mmap() and *must* be valid in zero-initialized state.
void SetThreadStackAndTls();
void ClearShadowForThreadStackAndTLS();
FakeStack *AsyncSignalSafeLazyInitFakeStack();
@@ -116,18 +127,19 @@ class AsanThread {
AsanThreadContext *context_;
thread_callback_t start_routine_;
void *arg_;
- uptr stack_top_;
- uptr stack_bottom_;
+ uptr stack_top_;
+ uptr stack_bottom_;
// stack_size_ == stack_top_ - stack_bottom_;
// It needs to be set in a async-signal-safe manner.
- uptr stack_size_;
+ uptr stack_size_;
uptr tls_begin_;
uptr tls_end_;
FakeStack *fake_stack_;
AsanThreadLocalMallocStorage malloc_storage_;
AsanStats stats_;
- bool unwinding;
+ bool unwinding_;
+ bool in_deadly_signal_;
};
// ScopedUnwinding is a scope for stacktracing member of a context
@@ -142,9 +154,18 @@ class ScopedUnwinding {
AsanThread *thread;
};
-struct CreateThreadContextArgs {
+// ScopedDeadlySignal is a scope for handling deadly signals.
+class ScopedDeadlySignal {
+ public:
+ explicit ScopedDeadlySignal(AsanThread *t) : thread(t) {
+ if (thread) thread->setInDeadlySignal(true);
+ }
+ ~ScopedDeadlySignal() {
+ if (thread) thread->setInDeadlySignal(false);
+ }
+
+ private:
AsanThread *thread;
- StackTrace *stack;
};
// Returns a single instance of registry.
diff --git a/lib/asan/asan_win.cc b/lib/asan/asan_win.cc
index 9e66b3417a1e..4f02b022fe79 100644
--- a/lib/asan/asan_win.cc
+++ b/lib/asan/asan_win.cc
@@ -21,6 +21,7 @@
#include "asan_interceptors.h"
#include "asan_internal.h"
+#include "asan_report.h"
#include "asan_thread.h"
#include "sanitizer_common/sanitizer_libc.h"
#include "sanitizer_common/sanitizer_mutex.h"
@@ -35,11 +36,6 @@ extern "C" {
namespace __asan {
-// ---------------------- Stacktraces, symbols, etc. ---------------- {{{1
-static BlockingMutex dbghelp_lock(LINKER_INITIALIZED);
-static bool dbghelp_initialized = false;
-#pragma comment(lib, "dbghelp.lib")
-
// ---------------------- TSD ---------------- {{{1
static bool tsd_key_inited = false;
@@ -75,17 +71,9 @@ void *AsanDoesNotSupportStaticLinkage() {
return 0;
}
-void SetAlternateSignalStack() {
- // FIXME: Decide what to do on Windows.
-}
+void AsanCheckDynamicRTPrereqs() {}
-void UnsetAlternateSignalStack() {
- // FIXME: Decide what to do on Windows.
-}
-
-void InstallSignalHandlers() {
- // FIXME: Decide what to do on Windows.
-}
+void AsanCheckIncompatibleRT() {}
void AsanPlatformThreadInit() {
// Nothing here for now.
@@ -95,54 +83,82 @@ void ReadContextStack(void *context, uptr *stack, uptr *ssize) {
UNIMPLEMENTED();
}
-} // namespace __asan
+void AsanOnSIGSEGV(int, void *siginfo, void *context) {
+ UNIMPLEMENTED();
+}
-// ---------------------- Interface ---------------- {{{1
-using namespace __asan; // NOLINT
+static LPTOP_LEVEL_EXCEPTION_FILTER default_seh_handler;
-extern "C" {
-SANITIZER_INTERFACE_ATTRIBUTE NOINLINE
-bool __asan_symbolize(const void *addr, char *out_buffer, int buffer_size) {
- BlockingMutexLock lock(&dbghelp_lock);
- if (!dbghelp_initialized) {
- SymSetOptions(SYMOPT_DEFERRED_LOADS |
- SYMOPT_UNDNAME |
- SYMOPT_LOAD_LINES);
- CHECK(SymInitialize(GetCurrentProcess(), 0, TRUE));
- // FIXME: We don't call SymCleanup() on exit yet - should we?
- dbghelp_initialized = true;
- }
+SignalContext SignalContext::Create(void *siginfo, void *context) {
+ EXCEPTION_RECORD *exception_record = (EXCEPTION_RECORD*)siginfo;
+ CONTEXT *context_record = (CONTEXT*)context;
- // See http://msdn.microsoft.com/en-us/library/ms680578(VS.85).aspx
- char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(CHAR)];
- PSYMBOL_INFO symbol = (PSYMBOL_INFO)buffer;
- symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
- symbol->MaxNameLen = MAX_SYM_NAME;
- DWORD64 offset = 0;
- BOOL got_objname = SymFromAddr(GetCurrentProcess(),
- (DWORD64)addr, &offset, symbol);
- if (!got_objname)
- return false;
-
- DWORD unused;
- IMAGEHLP_LINE64 info;
- info.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
- BOOL got_fileline = SymGetLineFromAddr64(GetCurrentProcess(),
- (DWORD64)addr, &unused, &info);
- int written = 0;
- out_buffer[0] = '\0';
- // FIXME: it might be useful to print out 'obj' or 'obj+offset' info too.
- if (got_fileline) {
- written += internal_snprintf(out_buffer + written, buffer_size - written,
- " %s %s:%d", symbol->Name,
- info.FileName, info.LineNumber);
- } else {
- written += internal_snprintf(out_buffer + written, buffer_size - written,
- " %s+0x%p", symbol->Name, offset);
+ uptr pc = (uptr)exception_record->ExceptionAddress;
+#ifdef _WIN64
+ uptr bp = (uptr)context_record->Rbp;
+ uptr sp = (uptr)context_record->Rsp;
+#else
+ uptr bp = (uptr)context_record->Ebp;
+ uptr sp = (uptr)context_record->Esp;
+#endif
+ uptr access_addr = exception_record->ExceptionInformation[1];
+
+ return SignalContext(context, access_addr, pc, sp, bp);
+}
+
+static long WINAPI SEHHandler(EXCEPTION_POINTERS *info) {
+ EXCEPTION_RECORD *exception_record = info->ExceptionRecord;
+ CONTEXT *context = info->ContextRecord;
+
+ if (exception_record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION ||
+ exception_record->ExceptionCode == EXCEPTION_IN_PAGE_ERROR) {
+ const char *description =
+ (exception_record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
+ ? "access-violation"
+ : "in-page-error";
+ SignalContext sig = SignalContext::Create(exception_record, context);
+ ReportSIGSEGV(description, sig);
}
- return true;
+
+ // FIXME: Handle EXCEPTION_STACK_OVERFLOW here.
+
+ return default_seh_handler(info);
+}
+
+// We want to install our own exception handler (EH) to print helpful reports
+// on access violations and whatnot. Unfortunately, the CRT initializers assume
+// they are run before any user code and drop any previously-installed EHs on
+// the floor, so we can't install our handler inside __asan_init.
+// (See crt0dat.c in the CRT sources for the details)
+//
+// Things get even more complicated with the dynamic runtime, as it finishes its
+// initialization before the .exe module CRT begins to initialize.
+//
+// For the static runtime (-MT), it's enough to put a callback to
+// __asan_set_seh_filter in the last section for C initializers.
+//
+// For the dynamic runtime (-MD), we want link the same
+// asan_dynamic_runtime_thunk.lib to all the modules, thus __asan_set_seh_filter
+// will be called for each instrumented module. This ensures that at least one
+// __asan_set_seh_filter call happens after the .exe module CRT is initialized.
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+int __asan_set_seh_filter() {
+ // We should only store the previous handler if it's not our own handler in
+ // order to avoid loops in the EH chain.
+ auto prev_seh_handler = SetUnhandledExceptionFilter(SEHHandler);
+ if (prev_seh_handler != &SEHHandler)
+ default_seh_handler = prev_seh_handler;
+ return 0;
}
-} // extern "C"
+#if !ASAN_DYNAMIC
+// 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"))
+ int (*__intercept_seh)() = __asan_set_seh_filter;
+#endif
+
+} // namespace __asan
#endif // _WIN32
diff --git a/lib/asan/asan_win_dll_thunk.cc b/lib/asan/asan_win_dll_thunk.cc
new file mode 100644
index 000000000000..b38a2d16087f
--- /dev/null
+++ b/lib/asan/asan_win_dll_thunk.cc
@@ -0,0 +1,376 @@
+//===-- asan_win_dll_thunk.cc ---------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// This 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.
+//===----------------------------------------------------------------------===//
+
+// Only compile this code when buidling asan_dll_thunk.lib
+// Using #ifdef rather than relying on Makefiles etc.
+// simplifies the build procedure.
+#ifdef ASAN_DLL_THUNK
+#include "asan_init_version.h"
+#include "interception/interception.h"
+
+// ---------- Function interception helper functions and macros ----------- {{{1
+extern "C" {
+void *__stdcall GetModuleHandleA(const char *module_name);
+void *__stdcall GetProcAddress(void *module, const char *proc_name);
+void abort();
+}
+
+static void *getRealProcAddressOrDie(const char *name) {
+ void *ret = GetProcAddress(GetModuleHandleA(0), name);
+ if (!ret)
+ abort();
+ return ret;
+}
+
+// We need to intercept some functions (e.g. ASan interface, memory allocator --
+// let's call them "hooks") exported by the DLL thunk and forward the hooks to
+// the runtime in the main module.
+// However, we don't want to keep two lists of these hooks.
+// To avoid that, the list of hooks should be defined using the
+// INTERCEPT_WHEN_POSSIBLE macro. Then, all these hooks can be intercepted
+// at once by calling INTERCEPT_HOOKS().
+
+// Use macro+template magic to automatically generate the list of hooks.
+// Each hook at line LINE defines a template class with a static
+// FunctionInterceptor<LINE>::Execute() method intercepting the hook.
+// The default implementation of FunctionInterceptor<LINE> is to call
+// the Execute() method corresponding to the previous line.
+template<int LINE>
+struct FunctionInterceptor {
+ static void Execute() { FunctionInterceptor<LINE-1>::Execute(); }
+};
+
+// There shouldn't be any hooks with negative definition line number.
+template<>
+struct FunctionInterceptor<0> {
+ static void Execute() {}
+};
+
+#define INTERCEPT_WHEN_POSSIBLE(main_function, dll_function) \
+ template<> struct FunctionInterceptor<__LINE__> { \
+ static void Execute() { \
+ void *wrapper = getRealProcAddressOrDie(main_function); \
+ if (!__interception::OverrideFunction((uptr)dll_function, \
+ (uptr)wrapper, 0)) \
+ abort(); \
+ FunctionInterceptor<__LINE__-1>::Execute(); \
+ } \
+ };
+
+// Special case of hooks -- ASan own interface functions. Those are only called
+// after __asan_init, thus an empty implementation is sufficient.
+#define INTERFACE_FUNCTION(name) \
+ extern "C" __declspec(noinline) void name() { \
+ volatile int prevent_icf = (__LINE__ << 8); (void)prevent_icf; \
+ __debugbreak(); \
+ } \
+ INTERCEPT_WHEN_POSSIBLE(#name, name)
+
+// INTERCEPT_HOOKS must be used after the last INTERCEPT_WHEN_POSSIBLE.
+#define INTERCEPT_HOOKS FunctionInterceptor<__LINE__>::Execute
+
+// We can't define our own version of strlen etc. because that would lead to
+// link-time or even type mismatch errors. Instead, we can declare a function
+// just to be able to get its address. Me may miss the first few calls to the
+// functions since it can be called before __asan_init, but that would lead to
+// false negatives in the startup code before user's global initializers, which
+// isn't a big deal.
+#define INTERCEPT_LIBRARY_FUNCTION(name) \
+ extern "C" void name(); \
+ INTERCEPT_WHEN_POSSIBLE(WRAPPER_NAME(name), name)
+
+// Disable compiler warnings that show up if we declare our own version
+// of a compiler intrinsic (e.g. strlen).
+#pragma warning(disable: 4391)
+#pragma warning(disable: 4392)
+
+static void InterceptHooks();
+// }}}
+
+// ---------- Function wrapping helpers ----------------------------------- {{{1
+#define WRAP_V_V(name) \
+ extern "C" void name() { \
+ typedef void (*fntype)(); \
+ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
+ fn(); \
+ } \
+ INTERCEPT_WHEN_POSSIBLE(#name, name);
+
+#define WRAP_V_W(name) \
+ extern "C" void name(void *arg) { \
+ typedef void (*fntype)(void *arg); \
+ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
+ fn(arg); \
+ } \
+ INTERCEPT_WHEN_POSSIBLE(#name, name);
+
+#define WRAP_V_WW(name) \
+ extern "C" void name(void *arg1, void *arg2) { \
+ typedef void (*fntype)(void *, void *); \
+ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
+ fn(arg1, arg2); \
+ } \
+ INTERCEPT_WHEN_POSSIBLE(#name, name);
+
+#define WRAP_V_WWW(name) \
+ extern "C" void name(void *arg1, void *arg2, void *arg3) { \
+ typedef void *(*fntype)(void *, void *, void *); \
+ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
+ fn(arg1, arg2, arg3); \
+ } \
+ INTERCEPT_WHEN_POSSIBLE(#name, name);
+
+#define WRAP_W_V(name) \
+ extern "C" void *name() { \
+ typedef void *(*fntype)(); \
+ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
+ return fn(); \
+ } \
+ INTERCEPT_WHEN_POSSIBLE(#name, name);
+
+#define WRAP_W_W(name) \
+ extern "C" void *name(void *arg) { \
+ typedef void *(*fntype)(void *arg); \
+ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
+ return fn(arg); \
+ } \
+ INTERCEPT_WHEN_POSSIBLE(#name, name);
+
+#define WRAP_W_WW(name) \
+ extern "C" void *name(void *arg1, void *arg2) { \
+ typedef void *(*fntype)(void *, void *); \
+ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
+ return fn(arg1, arg2); \
+ } \
+ INTERCEPT_WHEN_POSSIBLE(#name, name);
+
+#define WRAP_W_WWW(name) \
+ extern "C" void *name(void *arg1, void *arg2, void *arg3) { \
+ typedef void *(*fntype)(void *, void *, void *); \
+ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
+ return fn(arg1, arg2, arg3); \
+ } \
+ INTERCEPT_WHEN_POSSIBLE(#name, name);
+
+#define WRAP_W_WWWW(name) \
+ extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4) { \
+ typedef void *(*fntype)(void *, void *, void *, void *); \
+ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
+ return fn(arg1, arg2, arg3, arg4); \
+ } \
+ INTERCEPT_WHEN_POSSIBLE(#name, name);
+
+#define WRAP_W_WWWWW(name) \
+ extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4, \
+ void *arg5) { \
+ typedef void *(*fntype)(void *, void *, void *, void *, void *); \
+ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
+ return fn(arg1, arg2, arg3, arg4, arg5); \
+ } \
+ INTERCEPT_WHEN_POSSIBLE(#name, name);
+
+#define WRAP_W_WWWWWW(name) \
+ extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4, \
+ void *arg5, void *arg6) { \
+ typedef void *(*fntype)(void *, void *, void *, void *, void *, void *); \
+ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
+ return fn(arg1, arg2, arg3, arg4, arg5, arg6); \
+ } \
+ INTERCEPT_WHEN_POSSIBLE(#name, name);
+// }}}
+
+// ----------------- ASan own interface functions --------------------
+// Don't use the INTERFACE_FUNCTION machinery for this function as we actually
+// want to call it in the __asan_init interceptor.
+WRAP_W_V(__asan_should_detect_stack_use_after_return)
+
+extern "C" {
+ int __asan_option_detect_stack_use_after_return;
+
+ // Manually wrap __asan_init as we need to initialize
+ // __asan_option_detect_stack_use_after_return afterwards.
+ void __asan_init() {
+ typedef void (*fntype)();
+ static fntype fn = 0;
+ // __asan_init is expected to be called by only one thread.
+ if (fn) return;
+
+ fn = (fntype)getRealProcAddressOrDie(__asan_init_name);
+ fn();
+ __asan_option_detect_stack_use_after_return =
+ (__asan_should_detect_stack_use_after_return() != 0);
+
+ InterceptHooks();
+ }
+}
+
+INTERFACE_FUNCTION(__asan_handle_no_return)
+
+INTERFACE_FUNCTION(__asan_report_store1)
+INTERFACE_FUNCTION(__asan_report_store2)
+INTERFACE_FUNCTION(__asan_report_store4)
+INTERFACE_FUNCTION(__asan_report_store8)
+INTERFACE_FUNCTION(__asan_report_store16)
+INTERFACE_FUNCTION(__asan_report_store_n)
+
+INTERFACE_FUNCTION(__asan_report_load1)
+INTERFACE_FUNCTION(__asan_report_load2)
+INTERFACE_FUNCTION(__asan_report_load4)
+INTERFACE_FUNCTION(__asan_report_load8)
+INTERFACE_FUNCTION(__asan_report_load16)
+INTERFACE_FUNCTION(__asan_report_load_n)
+
+INTERFACE_FUNCTION(__asan_store1)
+INTERFACE_FUNCTION(__asan_store2)
+INTERFACE_FUNCTION(__asan_store4)
+INTERFACE_FUNCTION(__asan_store8)
+INTERFACE_FUNCTION(__asan_store16)
+INTERFACE_FUNCTION(__asan_storeN)
+
+INTERFACE_FUNCTION(__asan_load1)
+INTERFACE_FUNCTION(__asan_load2)
+INTERFACE_FUNCTION(__asan_load4)
+INTERFACE_FUNCTION(__asan_load8)
+INTERFACE_FUNCTION(__asan_load16)
+INTERFACE_FUNCTION(__asan_loadN)
+
+INTERFACE_FUNCTION(__asan_memcpy);
+INTERFACE_FUNCTION(__asan_memset);
+INTERFACE_FUNCTION(__asan_memmove);
+
+INTERFACE_FUNCTION(__asan_register_globals)
+INTERFACE_FUNCTION(__asan_unregister_globals)
+
+INTERFACE_FUNCTION(__asan_before_dynamic_init)
+INTERFACE_FUNCTION(__asan_after_dynamic_init)
+
+INTERFACE_FUNCTION(__asan_poison_stack_memory)
+INTERFACE_FUNCTION(__asan_unpoison_stack_memory)
+
+INTERFACE_FUNCTION(__asan_poison_memory_region)
+INTERFACE_FUNCTION(__asan_unpoison_memory_region)
+
+INTERFACE_FUNCTION(__asan_address_is_poisoned)
+INTERFACE_FUNCTION(__asan_region_is_poisoned)
+
+INTERFACE_FUNCTION(__asan_get_current_fake_stack)
+INTERFACE_FUNCTION(__asan_addr_is_in_fake_stack)
+
+INTERFACE_FUNCTION(__asan_stack_malloc_0)
+INTERFACE_FUNCTION(__asan_stack_malloc_1)
+INTERFACE_FUNCTION(__asan_stack_malloc_2)
+INTERFACE_FUNCTION(__asan_stack_malloc_3)
+INTERFACE_FUNCTION(__asan_stack_malloc_4)
+INTERFACE_FUNCTION(__asan_stack_malloc_5)
+INTERFACE_FUNCTION(__asan_stack_malloc_6)
+INTERFACE_FUNCTION(__asan_stack_malloc_7)
+INTERFACE_FUNCTION(__asan_stack_malloc_8)
+INTERFACE_FUNCTION(__asan_stack_malloc_9)
+INTERFACE_FUNCTION(__asan_stack_malloc_10)
+
+INTERFACE_FUNCTION(__asan_stack_free_0)
+INTERFACE_FUNCTION(__asan_stack_free_1)
+INTERFACE_FUNCTION(__asan_stack_free_2)
+INTERFACE_FUNCTION(__asan_stack_free_4)
+INTERFACE_FUNCTION(__asan_stack_free_5)
+INTERFACE_FUNCTION(__asan_stack_free_6)
+INTERFACE_FUNCTION(__asan_stack_free_7)
+INTERFACE_FUNCTION(__asan_stack_free_8)
+INTERFACE_FUNCTION(__asan_stack_free_9)
+INTERFACE_FUNCTION(__asan_stack_free_10)
+
+INTERFACE_FUNCTION(__sanitizer_cov_module_init)
+
+// TODO(timurrrr): Add more interface functions on the as-needed basis.
+
+// ----------------- Memory allocation functions ---------------------
+WRAP_V_W(free)
+WRAP_V_WW(_free_dbg)
+
+WRAP_W_W(malloc)
+WRAP_W_WWWW(_malloc_dbg)
+
+WRAP_W_WW(calloc)
+WRAP_W_WWWWW(_calloc_dbg)
+WRAP_W_WWW(_calloc_impl)
+
+WRAP_W_WW(realloc)
+WRAP_W_WWW(_realloc_dbg)
+WRAP_W_WWW(_recalloc)
+
+WRAP_W_W(_msize)
+WRAP_W_W(_expand)
+WRAP_W_W(_expand_dbg)
+
+// TODO(timurrrr): Might want to add support for _aligned_* allocation
+// functions to detect a bit more bugs. Those functions seem to wrap malloc().
+
+// TODO(timurrrr): Do we need to add _Crt* stuff here? (see asan_malloc_win.cc).
+
+INTERCEPT_LIBRARY_FUNCTION(atoi);
+INTERCEPT_LIBRARY_FUNCTION(atol);
+INTERCEPT_LIBRARY_FUNCTION(_except_handler3);
+
+// _except_handler4 checks -GS cookie which is different for each module, so we
+// can't use INTERCEPT_LIBRARY_FUNCTION(_except_handler4).
+INTERCEPTOR(int, _except_handler4, void *a, void *b, void *c, void *d) {
+ __asan_handle_no_return();
+ return REAL(_except_handler4)(a, b, c, d);
+}
+
+INTERCEPT_LIBRARY_FUNCTION(frexp);
+INTERCEPT_LIBRARY_FUNCTION(longjmp);
+INTERCEPT_LIBRARY_FUNCTION(memchr);
+INTERCEPT_LIBRARY_FUNCTION(memcmp);
+INTERCEPT_LIBRARY_FUNCTION(memcpy);
+INTERCEPT_LIBRARY_FUNCTION(memmove);
+INTERCEPT_LIBRARY_FUNCTION(memset);
+INTERCEPT_LIBRARY_FUNCTION(strcat); // NOLINT
+INTERCEPT_LIBRARY_FUNCTION(strchr);
+INTERCEPT_LIBRARY_FUNCTION(strcmp);
+INTERCEPT_LIBRARY_FUNCTION(strcpy); // NOLINT
+INTERCEPT_LIBRARY_FUNCTION(strlen);
+INTERCEPT_LIBRARY_FUNCTION(strncat);
+INTERCEPT_LIBRARY_FUNCTION(strncmp);
+INTERCEPT_LIBRARY_FUNCTION(strncpy);
+INTERCEPT_LIBRARY_FUNCTION(strnlen);
+INTERCEPT_LIBRARY_FUNCTION(strtol);
+INTERCEPT_LIBRARY_FUNCTION(wcslen);
+
+// Must be after all the interceptor declarations due to the way INTERCEPT_HOOKS
+// is defined.
+void InterceptHooks() {
+ INTERCEPT_HOOKS();
+ INTERCEPT_FUNCTION(_except_handler4);
+}
+
+// We want to call __asan_init before C/C++ initializers/constructors are
+// executed, otherwise functions like memset might be invoked.
+// For some strange reason, merely linking in asan_preinit.cc doesn't work
+// as the callback is never called... Is link.exe doing something too smart?
+
+// In DLLs, the callbacks are expected to return 0,
+// otherwise CRT initialization fails.
+static int call_asan_init() {
+ __asan_init();
+ return 0;
+}
+#pragma section(".CRT$XIB", long, read) // NOLINT
+__declspec(allocate(".CRT$XIB")) int (*__asan_preinit)() = call_asan_init;
+
+#endif // ASAN_DLL_THUNK
diff --git a/lib/asan/asan_win_dynamic_runtime_thunk.cc b/lib/asan/asan_win_dynamic_runtime_thunk.cc
new file mode 100644
index 000000000000..3a4de7dbf1fb
--- /dev/null
+++ b/lib/asan/asan_win_dynamic_runtime_thunk.cc
@@ -0,0 +1,52 @@
+//===-- asan_win_uar_thunk.cc ---------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// This file defines things that need to be present in the application modules
+// to interact with the ASan DLL runtime correctly and can't be implemented
+// using the default "import library" generated when linking the DLL RTL.
+//
+// This includes:
+// - forwarding the detect_stack_use_after_return runtime option
+// - installing a custom SEH handler
+//
+//===----------------------------------------------------------------------===//
+
+// Only compile this code when buidling asan_dynamic_runtime_thunk.lib
+// Using #ifdef rather than relying on Makefiles etc.
+// simplifies the build procedure.
+#ifdef ASAN_DYNAMIC_RUNTIME_THUNK
+extern "C" {
+__declspec(dllimport) int __asan_set_seh_filter();
+__declspec(dllimport) int __asan_should_detect_stack_use_after_return();
+
+// Define a copy of __asan_option_detect_stack_use_after_return that should be
+// used when linking an MD runtime with a set of object files on Windows.
+//
+// The ASan MD runtime dllexports '__asan_option_detect_stack_use_after_return',
+// so normally we would just dllimport it. Unfortunately, the dllimport
+// attribute adds __imp_ prefix to the symbol name of a variable.
+// Since in general we don't know if a given TU is going to be used
+// with a MT or MD runtime and we don't want to use ugly __imp_ names on Windows
+// just to work around this issue, let's clone the a variable that is
+// constant after initialization anyways.
+int __asan_option_detect_stack_use_after_return =
+ __asan_should_detect_stack_use_after_return();
+
+// Set the ASan-specific SEH handler at the end of CRT initialization of each
+// module (see asan_win.cc for the details).
+//
+// Unfortunately, putting a pointer to __asan_set_seh_filter into
+// __asan_intercept_seh gets optimized out, so we have to use an extra function.
+static int SetSEHFilter() { return __asan_set_seh_filter(); }
+#pragma section(".CRT$XIZ", long, read) // NOLINT
+__declspec(allocate(".CRT$XIZ")) int (*__asan_seh_interceptor)() = SetSEHFilter;
+}
+#endif // ASAN_DYNAMIC_RUNTIME_THUNK
diff --git a/lib/asan/lit_tests/32bitConfig/lit.site.cfg.in b/lib/asan/lit_tests/32bitConfig/lit.site.cfg.in
deleted file mode 100644
index faef4e8c9b17..000000000000
--- a/lib/asan/lit_tests/32bitConfig/lit.site.cfg.in
+++ /dev/null
@@ -1,13 +0,0 @@
-## Autogenerated by LLVM/Clang configuration.
-# Do not edit!
-
-# Load common config for all compiler-rt lit tests.
-lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/lib/lit.common.configured")
-
-# Tool-specific config options.
-config.asan_source_dir = "@ASAN_SOURCE_DIR@"
-config.bits = "32"
-
-# Load tool-specific config that would do the real work.
-lit_config.load_config(config, "@ASAN_SOURCE_DIR@/lit_tests/lit.cfg")
-
diff --git a/lib/asan/lit_tests/64bitConfig/lit.site.cfg.in b/lib/asan/lit_tests/64bitConfig/lit.site.cfg.in
deleted file mode 100644
index a35994484d5f..000000000000
--- a/lib/asan/lit_tests/64bitConfig/lit.site.cfg.in
+++ /dev/null
@@ -1,12 +0,0 @@
-## Autogenerated by LLVM/Clang configuration.
-# Do not edit!
-
-# Load common config for all compiler-rt lit tests.
-lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/lib/lit.common.configured")
-
-# Tool-specific config options.
-config.asan_source_dir = "@ASAN_SOURCE_DIR@"
-config.bits = "64"
-
-# Load tool-specific config that would do the real work.
-lit_config.load_config(config, "@ASAN_SOURCE_DIR@/lit_tests/lit.cfg")
diff --git a/lib/asan/lit_tests/CMakeLists.txt b/lib/asan/lit_tests/CMakeLists.txt
deleted file mode 100644
index 72a3f5439b70..000000000000
--- a/lib/asan/lit_tests/CMakeLists.txt
+++ /dev/null
@@ -1,42 +0,0 @@
-set(ASAN_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/..)
-set(ASAN_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/..)
-
-configure_lit_site_cfg(
- ${CMAKE_CURRENT_SOURCE_DIR}/64bitConfig/lit.site.cfg.in
- ${CMAKE_CURRENT_BINARY_DIR}/64bitConfig/lit.site.cfg
- )
-
-configure_lit_site_cfg(
- ${CMAKE_CURRENT_SOURCE_DIR}/32bitConfig/lit.site.cfg.in
- ${CMAKE_CURRENT_BINARY_DIR}/32bitConfig/lit.site.cfg
- )
-
-configure_lit_site_cfg(
- ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.in
- ${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg
- )
-
-if(COMPILER_RT_CAN_EXECUTE_TESTS)
- set(ASAN_TESTSUITES)
- if(CAN_TARGET_i386)
- list(APPEND ASAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/32bitConfig)
- endif()
- if(CAN_TARGET_x86_64 OR CAN_TARGET_powerpc64)
- list(APPEND ASAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/64bitConfig)
- endif()
- # Run ASan tests only if we're sure we may produce working binaries.
- set(ASAN_TEST_DEPS
- ${SANITIZER_COMMON_LIT_TEST_DEPS}
- asan_runtime_libraries)
- set(ASAN_TEST_PARAMS
- asan_site_config=${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg)
- if(LLVM_INCLUDE_TESTS)
- list(APPEND ASAN_TEST_DEPS AsanUnitTests)
- list(APPEND ASAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/Unit)
- endif()
- add_lit_testsuite(check-asan "Running the AddressSanitizer tests"
- ${ASAN_TESTSUITES}
- PARAMS ${ASAN_TEST_PARAMS}
- DEPENDS ${ASAN_TEST_DEPS})
- set_target_properties(check-asan PROPERTIES FOLDER "ASan tests")
-endif()
diff --git a/lib/asan/lit_tests/TestCases/Darwin/interface_symbols_darwin.c b/lib/asan/lit_tests/TestCases/Darwin/interface_symbols_darwin.c
deleted file mode 100644
index b453b64cafd2..000000000000
--- a/lib/asan/lit_tests/TestCases/Darwin/interface_symbols_darwin.c
+++ /dev/null
@@ -1,41 +0,0 @@
-// Check the presense of interface symbols in the ASan runtime dylib.
-// If you're changing this file, please also change
-// ../Linux/interface_symbols.c
-
-// RUN: %clang_asan -dead_strip -O2 %s -o %t.exe
-// RUN: rm -f %t.symbols %t.interface
-
-// RUN: nm -g `otool -L %t.exe | grep "asan_osx_dynamic.dylib" | \
-// RUN: tr -d '\011' | \
-// RUN: sed "s/.dylib.*/.dylib/"` \
-// RUN: | grep " T " | sed "s/.* T //" \
-// RUN: | grep "__asan_" | sed "s/___asan_/__asan_/" \
-// RUN: | grep -v "__asan_malloc_hook" \
-// RUN: | grep -v "__asan_free_hook" \
-// RUN: | grep -v "__asan_symbolize" \
-// RUN: | grep -v "__asan_default_options" \
-// RUN: | grep -v "__asan_on_error" > %t.symbols
-
-// RUN: cat %p/../../../asan_interface_internal.h \
-// RUN: | sed "s/\/\/.*//" | sed "s/typedef.*//" \
-// RUN: | grep -v "OPTIONAL" \
-// RUN: | grep "__asan_.*(" | sed "s/.* __asan_/__asan_/;s/(.*//" \
-// RUN: > %t.interface
-// RUN: echo __asan_report_load1 >> %t.interface
-// RUN: echo __asan_report_load2 >> %t.interface
-// RUN: echo __asan_report_load4 >> %t.interface
-// RUN: echo __asan_report_load8 >> %t.interface
-// RUN: echo __asan_report_load16 >> %t.interface
-// RUN: echo __asan_report_store1 >> %t.interface
-// RUN: echo __asan_report_store2 >> %t.interface
-// RUN: echo __asan_report_store4 >> %t.interface
-// RUN: echo __asan_report_store8 >> %t.interface
-// RUN: echo __asan_report_store16 >> %t.interface
-// RUN: echo __asan_report_load_n >> %t.interface
-// RUN: echo __asan_report_store_n >> %t.interface
-// RUN: for i in `jot - 0 10`; do echo __asan_stack_malloc_$i >> %t.interface; done
-// RUN: for i in `jot - 0 10`; do echo __asan_stack_free_$i >> %t.interface; done
-
-// RUN: cat %t.interface | sort -u | diff %t.symbols -
-
-int main() { return 0; }
diff --git a/lib/asan/lit_tests/TestCases/Darwin/lit.local.cfg b/lib/asan/lit_tests/TestCases/Darwin/lit.local.cfg
deleted file mode 100644
index a85dfcd24c08..000000000000
--- a/lib/asan/lit_tests/TestCases/Darwin/lit.local.cfg
+++ /dev/null
@@ -1,9 +0,0 @@
-def getRoot(config):
- if not config.parent:
- return config
- return getRoot(config.parent)
-
-root = getRoot(config)
-
-if root.host_os not in ['Darwin']:
- config.unsupported = True
diff --git a/lib/asan/lit_tests/TestCases/Darwin/malloc_set_zone_name-mprotect.cc b/lib/asan/lit_tests/TestCases/Darwin/malloc_set_zone_name-mprotect.cc
deleted file mode 100644
index 807a8283e788..000000000000
--- a/lib/asan/lit_tests/TestCases/Darwin/malloc_set_zone_name-mprotect.cc
+++ /dev/null
@@ -1,51 +0,0 @@
-// Regression test for a bug in malloc_create_zone()
-// (https://code.google.com/p/address-sanitizer/issues/detail?id=203)
-// The old implementation of malloc_create_zone() didn't always return a
-// page-aligned address, so we can only test on a best-effort basis.
-
-// RUN: %clangxx_asan %s -o %t
-// RUN: %t 2>&1
-
-#include <malloc/malloc.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-
-const int kNumIter = 4096;
-const int kNumZones = 100;
-int main() {
- char *mem[kNumIter * 2];
- // Allocate memory chunks from different size classes up to 1 page.
- // (For the case malloc() returns memory chunks in descending order)
- for (int i = 0; i < kNumIter; i++) {
- mem[i] = (char*)malloc(8 * i);
- }
- // Try to allocate a page-aligned malloc zone. Otherwise the mprotect() call
- // in malloc_set_zone_name() will silently fail.
- malloc_zone_t *zone = NULL;
- bool aligned = false;
- for (int i = 0; i < kNumZones; i++) {
- zone = malloc_create_zone(0, 0);
- if (((uintptr_t)zone & (~0xfff)) == (uintptr_t)zone) {
- aligned = true;
- break;
- }
- }
- if (!aligned) {
- printf("Warning: couldn't allocate a page-aligned zone.");
- return 0;
- }
- // malloc_set_zone_name() calls mprotect(zone, 4096, PROT_READ | PROT_WRITE),
- // modifies the zone contents and then calls mprotect(zone, 4096, PROT_READ).
- malloc_set_zone_name(zone, "foobar");
- // Allocate memory chunks from different size classes again.
- for (int i = 0; i < kNumIter; i++) {
- mem[i + kNumIter] = (char*)malloc(8 * i);
- }
- // Access the allocated memory chunks and free them.
- for (int i = 0; i < kNumIter * 2; i++) {
- memset(mem[i], 'a', 8 * (i % kNumIter));
- free(mem[i]);
- }
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/Darwin/malloc_zone-protected.cc b/lib/asan/lit_tests/TestCases/Darwin/malloc_zone-protected.cc
deleted file mode 100644
index d5f6c7c12e67..000000000000
--- a/lib/asan/lit_tests/TestCases/Darwin/malloc_zone-protected.cc
+++ /dev/null
@@ -1,20 +0,0 @@
-// Make sure the zones created by malloc_create_zone() are write-protected.
-#include <malloc/malloc.h>
-#include <stdio.h>
-
-// RUN: %clangxx_asan %s -o %t
-// RUN: not %t 2>&1 | FileCheck %s
-
-
-void *pwn(malloc_zone_t *unused_zone, size_t unused_size) {
- printf("PWNED\n");
- return NULL;
-}
-
-int main() {
- malloc_zone_t *zone = malloc_create_zone(0, 0);
- zone->malloc = pwn;
- void *v = malloc_zone_malloc(zone, 1);
- // CHECK-NOT: PWNED
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/Darwin/reexec-insert-libraries-env.cc b/lib/asan/lit_tests/TestCases/Darwin/reexec-insert-libraries-env.cc
deleted file mode 100644
index 208fe43ac7e4..000000000000
--- a/lib/asan/lit_tests/TestCases/Darwin/reexec-insert-libraries-env.cc
+++ /dev/null
@@ -1,20 +0,0 @@
-// Make sure ASan doesn't hang in an exec loop if DYLD_INSERT_LIBRARIES is set.
-// This is a regression test for
-// https://code.google.com/p/address-sanitizer/issues/detail?id=159
-
-// RUN: %clangxx_asan %s -o %t
-// RUN: %clangxx %p/../SharedLibs/darwin-dummy-shared-lib-so.cc \
-// RUN: -dynamiclib -o darwin-dummy-shared-lib-so.dylib
-
-// FIXME: the following command line may hang in the case of a regression.
-// RUN: DYLD_INSERT_LIBRARIES=darwin-dummy-shared-lib-so.dylib \
-// RUN: %t 2>&1 | FileCheck %s || exit 1
-#include <stdio.h>
-#include <stdlib.h>
-
-int main() {
- const char kEnvName[] = "DYLD_INSERT_LIBRARIES";
- printf("%s=%s\n", kEnvName, getenv(kEnvName));
- // CHECK: {{DYLD_INSERT_LIBRARIES=.*darwin-dummy-shared-lib-so.dylib.*}}
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/Darwin/unset-insert-libraries-on-exec.cc b/lib/asan/lit_tests/TestCases/Darwin/unset-insert-libraries-on-exec.cc
deleted file mode 100644
index fa0dd4f9df88..000000000000
--- a/lib/asan/lit_tests/TestCases/Darwin/unset-insert-libraries-on-exec.cc
+++ /dev/null
@@ -1,20 +0,0 @@
-// Make sure ASan removes the runtime library from DYLD_INSERT_LIBRARIES before
-// executing other programs.
-
-// RUN: %clangxx_asan %s -o %t
-// RUN: %clangxx %p/../Helpers/echo-env.cc -o %T/echo-env
-// RUN: %clangxx %p/../SharedLibs/darwin-dummy-shared-lib-so.cc \
-// RUN: -dynamiclib -o %t-darwin-dummy-shared-lib-so.dylib
-
-// Make sure DYLD_INSERT_LIBRARIES doesn't contain the runtime library before
-// execl().
-
-// RUN: %t %T/echo-env >/dev/null 2>&1
-// RUN: DYLD_INSERT_LIBRARIES=%t-darwin-dummy-shared-lib-so.dylib \
-// RUN: %t %T/echo-env 2>&1 | FileCheck %s || exit 1
-#include <unistd.h>
-int main(int argc, char *argv[]) {
- execl(argv[1], argv[1], "DYLD_INSERT_LIBRARIES", NULL);
- // CHECK: {{DYLD_INSERT_LIBRARIES = .*darwin-dummy-shared-lib-so.dylib.*}}
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/Helpers/blacklist-extra.cc b/lib/asan/lit_tests/TestCases/Helpers/blacklist-extra.cc
deleted file mode 100644
index 627115cdda2b..000000000000
--- a/lib/asan/lit_tests/TestCases/Helpers/blacklist-extra.cc
+++ /dev/null
@@ -1,5 +0,0 @@
-// This function is broken, but this file is blacklisted
-int externalBrokenFunction(int argc) {
- char x[10] = {0};
- return x[argc * 10]; // BOOM
-}
diff --git a/lib/asan/lit_tests/TestCases/Helpers/echo-env.cc b/lib/asan/lit_tests/TestCases/Helpers/echo-env.cc
deleted file mode 100644
index 65e91c155c84..000000000000
--- a/lib/asan/lit_tests/TestCases/Helpers/echo-env.cc
+++ /dev/null
@@ -1,19 +0,0 @@
-// Helper binary for
-// lit_tests/TestCases/Darwin/unset-insert-libraries-on-exec.cc
-// Prints the environment variable with the given name.
-#include <stdio.h>
-#include <stdlib.h>
-
-int main(int argc, char *argv[]) {
- if (argc != 2) {
- printf("Usage: %s ENVNAME\n", argv[0]);
- exit(1);
- }
- const char *value = getenv(argv[1]);
- if (value) {
- printf("%s = %s\n", argv[1], value);
- } else {
- printf("%s not set.\n", argv[1]);
- }
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/Helpers/init-order-atexit-extra.cc b/lib/asan/lit_tests/TestCases/Helpers/init-order-atexit-extra.cc
deleted file mode 100644
index e4189d19d099..000000000000
--- a/lib/asan/lit_tests/TestCases/Helpers/init-order-atexit-extra.cc
+++ /dev/null
@@ -1,16 +0,0 @@
-#include <stdio.h>
-
-class C {
- public:
- C() { value = 42; }
- ~C() { }
- int value;
-};
-
-C c;
-
-void AccessC() {
- printf("C value: %d\n", c.value);
-}
-
-int main() { return 0; }
diff --git a/lib/asan/lit_tests/TestCases/Helpers/init-order-pthread-create-extra.cc b/lib/asan/lit_tests/TestCases/Helpers/init-order-pthread-create-extra.cc
deleted file mode 100644
index d4606f0afb52..000000000000
--- a/lib/asan/lit_tests/TestCases/Helpers/init-order-pthread-create-extra.cc
+++ /dev/null
@@ -1,2 +0,0 @@
-void *bar(void *input);
-void *glob2 = bar((void*)0x2345);
diff --git a/lib/asan/lit_tests/TestCases/Helpers/initialization-blacklist-extra.cc b/lib/asan/lit_tests/TestCases/Helpers/initialization-blacklist-extra.cc
deleted file mode 100644
index 09aed2112d5e..000000000000
--- a/lib/asan/lit_tests/TestCases/Helpers/initialization-blacklist-extra.cc
+++ /dev/null
@@ -1,15 +0,0 @@
-int zero_init() { return 0; }
-int badGlobal = zero_init();
-int readBadGlobal() { return badGlobal; }
-
-namespace badNamespace {
-class BadClass {
- public:
- BadClass() { value = 0; }
- int value;
-};
-// Global object with non-trivial constructor.
-BadClass bad_object;
-} // namespace badNamespace
-
-int accessBadObject() { return badNamespace::bad_object.value; }
diff --git a/lib/asan/lit_tests/TestCases/Helpers/initialization-blacklist-extra2.cc b/lib/asan/lit_tests/TestCases/Helpers/initialization-blacklist-extra2.cc
deleted file mode 100644
index 69455a0a6fc9..000000000000
--- a/lib/asan/lit_tests/TestCases/Helpers/initialization-blacklist-extra2.cc
+++ /dev/null
@@ -1,4 +0,0 @@
-int zero_init();
-int badSrcGlobal = zero_init();
-int readBadSrcGlobal() { return badSrcGlobal; }
-
diff --git a/lib/asan/lit_tests/TestCases/Helpers/initialization-blacklist.txt b/lib/asan/lit_tests/TestCases/Helpers/initialization-blacklist.txt
deleted file mode 100644
index 83294635622d..000000000000
--- a/lib/asan/lit_tests/TestCases/Helpers/initialization-blacklist.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-global:*badGlobal*=init
-type:*badNamespace::BadClass*=init
-src:*initialization-blacklist-extra2.cc=init
diff --git a/lib/asan/lit_tests/TestCases/Helpers/initialization-bug-extra.cc b/lib/asan/lit_tests/TestCases/Helpers/initialization-bug-extra.cc
deleted file mode 100644
index 3c4cb411defa..000000000000
--- a/lib/asan/lit_tests/TestCases/Helpers/initialization-bug-extra.cc
+++ /dev/null
@@ -1,5 +0,0 @@
-// This file simply declares a dynamically initialized var by the name of 'y'.
-int initY() {
- return 5;
-}
-int y = initY();
diff --git a/lib/asan/lit_tests/TestCases/Helpers/initialization-bug-extra2.cc b/lib/asan/lit_tests/TestCases/Helpers/initialization-bug-extra2.cc
deleted file mode 100644
index a3d8f190e58b..000000000000
--- a/lib/asan/lit_tests/TestCases/Helpers/initialization-bug-extra2.cc
+++ /dev/null
@@ -1,6 +0,0 @@
-// 'z' is dynamically initialized global from different TU.
-extern int z;
-int __attribute__((noinline)) initY() {
- return z + 1;
-}
-int y = initY();
diff --git a/lib/asan/lit_tests/TestCases/Helpers/initialization-constexpr-extra.cc b/lib/asan/lit_tests/TestCases/Helpers/initialization-constexpr-extra.cc
deleted file mode 100644
index b32466a981b3..000000000000
--- a/lib/asan/lit_tests/TestCases/Helpers/initialization-constexpr-extra.cc
+++ /dev/null
@@ -1,3 +0,0 @@
-// Constexpr:
-int getCoolestInteger();
-static int coolest_integer = getCoolestInteger();
diff --git a/lib/asan/lit_tests/TestCases/Helpers/initialization-nobug-extra.cc b/lib/asan/lit_tests/TestCases/Helpers/initialization-nobug-extra.cc
deleted file mode 100644
index 886165affd76..000000000000
--- a/lib/asan/lit_tests/TestCases/Helpers/initialization-nobug-extra.cc
+++ /dev/null
@@ -1,9 +0,0 @@
-// Linker initialized:
-int getAB();
-static int ab = getAB();
-// Function local statics:
-int countCalls();
-static int one = countCalls();
-// Trivial constructor, non-trivial destructor:
-int getStructWithDtorValue();
-static int val = getStructWithDtorValue();
diff --git a/lib/asan/lit_tests/TestCases/Helpers/lit.local.cfg b/lib/asan/lit_tests/TestCases/Helpers/lit.local.cfg
deleted file mode 100644
index 2fc4d99456b0..000000000000
--- a/lib/asan/lit_tests/TestCases/Helpers/lit.local.cfg
+++ /dev/null
@@ -1,3 +0,0 @@
-# Sources in this directory are helper files for tests which test functionality
-# involving multiple translation units.
-config.suffixes = []
diff --git a/lib/asan/lit_tests/TestCases/Linux/asan_prelink_test.cc b/lib/asan/lit_tests/TestCases/Linux/asan_prelink_test.cc
deleted file mode 100644
index 0f158c1bb3dd..000000000000
--- a/lib/asan/lit_tests/TestCases/Linux/asan_prelink_test.cc
+++ /dev/null
@@ -1,28 +0,0 @@
-// Test if asan works with prelink.
-// It does not actually use prelink, but relies on ld's flag -Ttext-segment
-// or gold's flag -Ttext (we try the first flag first, if that fails we
-// try the second flag).
-//
-// RUN: %clangxx_asan -c %s -o %t.o
-// RUN: %clangxx_asan -DBUILD_SO=1 -fPIC -shared %s -o %t.so -Wl,-Ttext-segment=0x3600000000 ||\
-// RUN: %clangxx_asan -DBUILD_SO=1 -fPIC -shared %s -o %t.so -Wl,-Ttext=0x3600000000
-// RUN: %clangxx_asan %t.o %t.so -Wl,-R. -o %t
-// RUN: ASAN_OPTIONS=verbosity=1 %t 2>&1 | FileCheck %s
-
-// REQUIRES: x86_64-supported-target, asan-64-bits
-#if BUILD_SO
-int G;
-int *getG() {
- return &G;
-}
-#else
-#include <stdio.h>
-extern int *getG();
-int main(int argc, char **argv) {
- long p = (long)getG();
- printf("SO mapped at %lx\n", p & ~0xffffffffUL);
- *getG() = 0;
-}
-#endif
-// CHECK: 0x003000000000, 0x004fffffffff{{.*}} MidMem
-// CHECK: SO mapped at 3600000000
diff --git a/lib/asan/lit_tests/TestCases/Linux/clone_test.cc b/lib/asan/lit_tests/TestCases/Linux/clone_test.cc
deleted file mode 100644
index 0e12f35b400a..000000000000
--- a/lib/asan/lit_tests/TestCases/Linux/clone_test.cc
+++ /dev/null
@@ -1,44 +0,0 @@
-// Regression test for:
-// http://code.google.com/p/address-sanitizer/issues/detail?id=37
-
-// RUN: %clangxx_asan -O0 %s -o %t && %t | FileCheck %s
-// RUN: %clangxx_asan -O1 %s -o %t && %t | FileCheck %s
-// RUN: %clangxx_asan -O2 %s -o %t && %t | FileCheck %s
-// RUN: %clangxx_asan -O3 %s -o %t && %t | FileCheck %s
-
-#include <stdio.h>
-#include <sched.h>
-#include <sys/syscall.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-int Child(void *arg) {
- char x[32] = {0}; // Stack gets poisoned.
- printf("Child: %p\n", x);
- _exit(1); // NoReturn, stack will remain unpoisoned unless we do something.
-}
-
-int main(int argc, char **argv) {
- const int kStackSize = 1 << 20;
- char child_stack[kStackSize + 1];
- char *sp = child_stack + kStackSize; // Stack grows down.
- printf("Parent: %p\n", sp);
- pid_t clone_pid = clone(Child, sp, CLONE_FILES | CLONE_VM, NULL, 0, 0, 0);
- int status;
- pid_t wait_result = waitpid(clone_pid, &status, __WCLONE);
- if (wait_result < 0) {
- perror("waitpid");
- return 0;
- }
- if (wait_result == clone_pid && WIFEXITED(status)) {
- // Make sure the child stack was indeed unpoisoned.
- for (int i = 0; i < kStackSize; i++)
- child_stack[i] = i;
- int ret = child_stack[argc - 1];
- printf("PASSED\n");
- // CHECK: PASSED
- return ret;
- }
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/Linux/coverage.cc b/lib/asan/lit_tests/TestCases/Linux/coverage.cc
deleted file mode 100644
index 4373e9b13c68..000000000000
--- a/lib/asan/lit_tests/TestCases/Linux/coverage.cc
+++ /dev/null
@@ -1,45 +0,0 @@
-// RUN: %clangxx_asan -mllvm -asan-coverage=1 -DSHARED %s -shared -o %t.so -fPIC
-// RUN: %clangxx_asan -mllvm -asan-coverage=1 %s -o %t -Wl,-R. %t.so
-// RUN: export ASAN_OPTIONS=coverage=1:verbosity=1
-// RUN: %t 2>&1 | FileCheck %s --check-prefix=CHECK-main
-// RUN: %t foo 2>&1 | FileCheck %s --check-prefix=CHECK-foo
-// RUN: %t bar 2>&1 | FileCheck %s --check-prefix=CHECK-bar
-// RUN: %t foo bar 2>&1 | FileCheck %s --check-prefix=CHECK-foo-bar
-
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-
-#ifdef SHARED
-void bar() { printf("bar\n"); }
-#else
-__attribute__((noinline))
-void foo() { printf("foo\n"); }
-extern void bar();
-
-int main(int argc, char **argv) {
- fprintf(stderr, "PID: %d\n", getpid());
- for (int i = 1; i < argc; i++) {
- if (!strcmp(argv[i], "foo"))
- foo();
- if (!strcmp(argv[i], "bar"))
- bar();
- }
-}
-#endif
-
-// CHECK-main: PID: [[PID:[0-9]+]]
-// CHECK-main: [[PID]].sancov: 1 PCs written
-// CHECK-main-NOT: .so.[[PID]]
-//
-// CHECK-foo: PID: [[PID:[0-9]+]]
-// CHECK-foo: [[PID]].sancov: 2 PCs written
-// CHECK-foo-NOT: .so.[[PID]]
-//
-// CHECK-bar: PID: [[PID:[0-9]+]]
-// CHECK-bar: [[PID]].sancov: 1 PCs written
-// CHECK-bar: .so.[[PID]].sancov: 1 PCs written
-//
-// CHECK-foo-bar: PID: [[PID:[0-9]+]]
-// CHECK-foo-bar: [[PID]].sancov: 2 PCs written
-// CHECK-foo-bar: so.[[PID]].sancov: 1 PCs written
diff --git a/lib/asan/lit_tests/TestCases/Linux/glob.cc b/lib/asan/lit_tests/TestCases/Linux/glob.cc
deleted file mode 100644
index 123768b099ed..000000000000
--- a/lib/asan/lit_tests/TestCases/Linux/glob.cc
+++ /dev/null
@@ -1,29 +0,0 @@
-// RUN: %clangxx_asan -O0 %s -o %t && %t %p 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O3 %s -o %t && %t %p 2>&1 | FileCheck %s
-
-#include <assert.h>
-#include <glob.h>
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <string>
-
-
-int main(int argc, char *argv[]) {
- std::string path = argv[1];
- std::string pattern = path + "/glob_test_root/*a";
- printf("pattern: %s\n", pattern.c_str());
-
- glob_t globbuf;
- int res = glob(pattern.c_str(), 0, 0, &globbuf);
-
- printf("%d %s\n", errno, strerror(errno));
- assert(res == 0);
- assert(globbuf.gl_pathc == 2);
- printf("%zu\n", strlen(globbuf.gl_pathv[0]));
- printf("%zu\n", strlen(globbuf.gl_pathv[1]));
- globfree(&globbuf);
- printf("PASS\n");
- // CHECK: PASS
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/Linux/glob_test_root/aa b/lib/asan/lit_tests/TestCases/Linux/glob_test_root/aa
deleted file mode 100644
index e69de29bb2d1..000000000000
--- a/lib/asan/lit_tests/TestCases/Linux/glob_test_root/aa
+++ /dev/null
diff --git a/lib/asan/lit_tests/TestCases/Linux/glob_test_root/ab b/lib/asan/lit_tests/TestCases/Linux/glob_test_root/ab
deleted file mode 100644
index e69de29bb2d1..000000000000
--- a/lib/asan/lit_tests/TestCases/Linux/glob_test_root/ab
+++ /dev/null
diff --git a/lib/asan/lit_tests/TestCases/Linux/glob_test_root/ba b/lib/asan/lit_tests/TestCases/Linux/glob_test_root/ba
deleted file mode 100644
index e69de29bb2d1..000000000000
--- a/lib/asan/lit_tests/TestCases/Linux/glob_test_root/ba
+++ /dev/null
diff --git a/lib/asan/lit_tests/TestCases/Linux/heap-overflow-large.cc b/lib/asan/lit_tests/TestCases/Linux/heap-overflow-large.cc
deleted file mode 100644
index 67e9c3718d59..000000000000
--- a/lib/asan/lit_tests/TestCases/Linux/heap-overflow-large.cc
+++ /dev/null
@@ -1,23 +0,0 @@
-// Regression test for
-// https://code.google.com/p/address-sanitizer/issues/detail?id=183
-
-// RUN: %clangxx_asan -O2 %s -o %t
-// RUN: not %t 12 2>&1 | FileCheck %s
-// RUN: not %t 100 2>&1 | FileCheck %s
-// RUN: not %t 10000 2>&1 | FileCheck %s
-
-#include <stdlib.h>
-#include <string.h>
-
-int main(int argc, char *argv[]) {
- int *x = new int[5];
- memset(x, 0, sizeof(x[0]) * 5);
- int index = atoi(argv[1]);
- int res = x[index];
- // CHECK: AddressSanitizer: {{(heap-buffer-overflow|SEGV)}}
- // CHECK: #0 0x{{.*}} in main {{.*}}heap-overflow-large.cc:[[@LINE-2]]
- // CHECK: AddressSanitizer can not {{(provide additional info|describe address in more detail \(wild memory access suspected\))}}
- // CHECK: SUMMARY: AddressSanitizer: {{(heap-buffer-overflow|SEGV)}}
- delete[] x;
- return res;
-}
diff --git a/lib/asan/lit_tests/TestCases/Linux/heavy_uar_test.cc b/lib/asan/lit_tests/TestCases/Linux/heavy_uar_test.cc
deleted file mode 100644
index 27b179e83624..000000000000
--- a/lib/asan/lit_tests/TestCases/Linux/heavy_uar_test.cc
+++ /dev/null
@@ -1,54 +0,0 @@
-// RUN: export ASAN_OPTIONS=detect_stack_use_after_return=1
-// RUN: %clangxx_asan -O0 %s -o %t && \
-// RUN: not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O2 %s -o %t && \
-// RUN: not %t 2>&1 | FileCheck %s
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-
-__attribute__((noinline))
-char *pretend_to_do_something(char *x) {
- __asm__ __volatile__("" : : "r" (x) : "memory");
- return x;
-}
-
-__attribute__((noinline))
-char *LeakStack() {
- char x[1024];
- memset(x, 0, sizeof(x));
- return pretend_to_do_something(x);
-}
-
-template<size_t kFrameSize>
-__attribute__((noinline))
-void RecuriveFunctionWithStackFrame(int depth) {
- if (depth <= 0) return;
- char x[kFrameSize];
- x[0] = depth;
- pretend_to_do_something(x);
- RecuriveFunctionWithStackFrame<kFrameSize>(depth - 1);
-}
-
-int main(int argc, char **argv) {
- int n_iter = argc >= 2 ? atoi(argv[1]) : 1000;
- int depth = argc >= 3 ? atoi(argv[2]) : 500;
- for (int i = 0; i < n_iter; i++) {
- RecuriveFunctionWithStackFrame<10>(depth);
- RecuriveFunctionWithStackFrame<100>(depth);
- RecuriveFunctionWithStackFrame<500>(depth);
- RecuriveFunctionWithStackFrame<1024>(depth);
- RecuriveFunctionWithStackFrame<2000>(depth);
- RecuriveFunctionWithStackFrame<5000>(depth);
- RecuriveFunctionWithStackFrame<10000>(depth);
- }
- char *stale_stack = LeakStack();
- RecuriveFunctionWithStackFrame<1024>(10);
- stale_stack[100]++;
- // CHECK: ERROR: AddressSanitizer: stack-use-after-return on address
- // CHECK: is located in stack of thread T0 at offset 132 in frame
- // CHECK: in LeakStack(){{.*}}heavy_uar_test.cc:
- // CHECK: [32, 1056) 'x'
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/Linux/initialization-bug-any-order.cc b/lib/asan/lit_tests/TestCases/Linux/initialization-bug-any-order.cc
deleted file mode 100644
index 042a07e428d9..000000000000
--- a/lib/asan/lit_tests/TestCases/Linux/initialization-bug-any-order.cc
+++ /dev/null
@@ -1,36 +0,0 @@
-// Test to make sure basic initialization order errors are caught.
-// Check that on Linux initialization order bugs are caught
-// independently on order in which we list source files (if we specify
-// strict init-order checking).
-
-// RUN: %clangxx_asan -O0 %s %p/../Helpers/initialization-bug-extra.cc -o %t
-// RUN: ASAN_OPTIONS=strict_init_order=true not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O0 %p/../Helpers/initialization-bug-extra.cc %s -o %t
-// RUN: ASAN_OPTIONS=strict_init_order=true not %t 2>&1 | FileCheck %s
-
-// Do not test with optimization -- the error may be optimized away.
-
-#include <cstdio>
-
-// 'y' is a dynamically initialized global residing in a different TU. This
-// dynamic initializer will read the value of 'y' before main starts. The
-// result is undefined behavior, which should be caught by initialization order
-// checking.
-extern int y;
-int __attribute__((noinline)) initX() {
- return y + 1;
- // CHECK: {{AddressSanitizer: initialization-order-fiasco}}
- // CHECK: {{READ of size .* at 0x.* thread T0}}
- // CHECK: {{#0 0x.* in .*initX.* .*initialization-bug-any-order.cc:}}[[@LINE-3]]
- // CHECK: {{0x.* is located 0 bytes inside of global variable .*y.*}}
-}
-
-// This initializer begins our initialization order problems.
-static int x = initX();
-
-int main() {
- // ASan should have caused an exit before main runs.
- printf("PASS\n");
- // CHECK-NOT: PASS
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/Linux/interception_failure_test.cc b/lib/asan/lit_tests/TestCases/Linux/interception_failure_test.cc
deleted file mode 100644
index 9d161aa2dccb..000000000000
--- a/lib/asan/lit_tests/TestCases/Linux/interception_failure_test.cc
+++ /dev/null
@@ -1,22 +0,0 @@
-// If user provides his own libc functions, ASan doesn't
-// intercept these functions.
-
-// RUN: %clangxx_asan -O0 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O1 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O2 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O3 %s -o %t && %t 2>&1 | FileCheck %s
-#include <stdlib.h>
-#include <stdio.h>
-
-extern "C" long strtol(const char *nptr, char **endptr, int base) {
- fprintf(stderr, "my_strtol_interceptor\n");
- return 0;
-}
-
-int main() {
- char *x = (char*)malloc(10 * sizeof(char));
- free(x);
- return (int)strtol(x, 0, 10);
- // CHECK: my_strtol_interceptor
- // CHECK-NOT: heap-use-after-free
-}
diff --git a/lib/asan/lit_tests/TestCases/Linux/interception_malloc_test.cc b/lib/asan/lit_tests/TestCases/Linux/interception_malloc_test.cc
deleted file mode 100644
index cdd7239ab7bc..000000000000
--- a/lib/asan/lit_tests/TestCases/Linux/interception_malloc_test.cc
+++ /dev/null
@@ -1,23 +0,0 @@
-// ASan interceptor can be accessed with __interceptor_ prefix.
-
-// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>&1 | FileCheck %s
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-
-extern "C" void *__interceptor_malloc(size_t size);
-extern "C" void *malloc(size_t size) {
- write(2, "malloc call\n", sizeof("malloc call\n") - 1);
- return __interceptor_malloc(size);
-}
-
-int main() {
- char *x = (char*)malloc(10 * sizeof(char));
- free(x);
- return (int)strtol(x, 0, 10);
- // CHECK: malloc call
- // CHECK: heap-use-after-free
-}
diff --git a/lib/asan/lit_tests/TestCases/Linux/interception_readdir_r_test.cc b/lib/asan/lit_tests/TestCases/Linux/interception_readdir_r_test.cc
deleted file mode 100644
index 198e1f3884dd..000000000000
--- a/lib/asan/lit_tests/TestCases/Linux/interception_readdir_r_test.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-// RUN: %clangxx_asan -O0 %s -DTEMP_DIR='"'"%T"'"' -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O1 %s -DTEMP_DIR='"'"%T"'"' -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O2 %s -DTEMP_DIR='"'"%T"'"' -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O3 %s -DTEMP_DIR='"'"%T"'"' -o %t && %t 2>&1 | FileCheck %s
-//
-// RUN: %clangxx_asan -O0 %s -D_FILE_OFFSET_BITS=64 -DTEMP_DIR='"'"%T"'"' -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O1 %s -D_FILE_OFFSET_BITS=64 -DTEMP_DIR='"'"%T"'"' -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O2 %s -D_FILE_OFFSET_BITS=64 -DTEMP_DIR='"'"%T"'"' -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O3 %s -D_FILE_OFFSET_BITS=64 -DTEMP_DIR='"'"%T"'"' -o %t && %t 2>&1 | FileCheck %s
-
-#include <dirent.h>
-#include <memory.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-
-int main() {
- // Ensure the readdir_r interceptor doesn't erroneously mark the entire dirent
- // as written when the end of the directory pointer is reached.
- fputs("test1: reading the " TEMP_DIR " directory...\n", stderr);
- DIR *d = opendir(TEMP_DIR);
- struct dirent *result = (struct dirent *)(0xfeedbeef);
- // We assume the temp dir for this test doesn't have crazy long file names.
- char entry_buffer[4096];
- memset(entry_buffer, 0xab, sizeof(entry_buffer));
- unsigned count = 0;
- do {
- // Stamp the entry struct to try to trick the interceptor.
- ((struct dirent *)entry_buffer)->d_reclen = 9999;
- if (readdir_r(d, (struct dirent *)entry_buffer, &result) != 0)
- abort();
- ++count;
- } while (result != NULL);
- fprintf(stderr, "read %d entries\n", count);
- closedir(d);
- // CHECK: test1: reading the {{.*}} directory...
- // CHECK-NOT: stack-buffer-overflow
- // CHECK: read {{.*}} entries
-
- // Ensure the readdir64_r interceptor doesn't have the bug either.
- fputs("test2: reading the " TEMP_DIR " directory...\n", stderr);
- d = opendir(TEMP_DIR);
- struct dirent64 *result64;
- memset(entry_buffer, 0xab, sizeof(entry_buffer));
- count = 0;
- do {
- // Stamp the entry struct to try to trick the interceptor.
- ((struct dirent64 *)entry_buffer)->d_reclen = 9999;
- if (readdir64_r(d, (struct dirent64 *)entry_buffer, &result64) != 0)
- abort();
- ++count;
- } while (result64 != NULL);
- fprintf(stderr, "read %d entries\n", count);
- closedir(d);
- // CHECK: test2: reading the {{.*}} directory...
- // CHECK-NOT: stack-buffer-overflow
- // CHECK: read {{.*}} entries
-}
diff --git a/lib/asan/lit_tests/TestCases/Linux/interception_test.cc b/lib/asan/lit_tests/TestCases/Linux/interception_test.cc
deleted file mode 100644
index 2b3316d7dc8a..000000000000
--- a/lib/asan/lit_tests/TestCases/Linux/interception_test.cc
+++ /dev/null
@@ -1,22 +0,0 @@
-// ASan interceptor can be accessed with __interceptor_ prefix.
-
-// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>&1 | FileCheck %s
-#include <stdlib.h>
-#include <stdio.h>
-
-extern "C" long __interceptor_strtol(const char *nptr, char **endptr, int base);
-extern "C" long strtol(const char *nptr, char **endptr, int base) {
- fprintf(stderr, "my_strtol_interceptor\n");
- return __interceptor_strtol(nptr, endptr, base);
-}
-
-int main() {
- char *x = (char*)malloc(10 * sizeof(char));
- free(x);
- return (int)strtol(x, 0, 10);
- // CHECK: my_strtol_interceptor
- // CHECK: heap-use-after-free
-}
diff --git a/lib/asan/lit_tests/TestCases/Linux/interface_symbols_linux.c b/lib/asan/lit_tests/TestCases/Linux/interface_symbols_linux.c
deleted file mode 100644
index d6ceda7af8b6..000000000000
--- a/lib/asan/lit_tests/TestCases/Linux/interface_symbols_linux.c
+++ /dev/null
@@ -1,35 +0,0 @@
-// Check the presense of interface symbols in compiled file.
-
-// RUN: %clang_asan -O2 %s -o %t.exe
-// RUN: nm -D %t.exe | grep " T " | sed "s/.* T //" \
-// RUN: | grep "__asan_" | sed "s/___asan_/__asan_/" \
-// RUN: | grep -v "__asan_malloc_hook" \
-// RUN: | grep -v "__asan_free_hook" \
-// RUN: | grep -v "__asan_symbolize" \
-// RUN: | grep -v "__asan_default_options" \
-// RUN: | grep -v "__asan_stack_" \
-// RUN: | grep -v "__asan_on_error" > %t.symbols
-// RUN: cat %p/../../../asan_interface_internal.h \
-// RUN: | sed "s/\/\/.*//" | sed "s/typedef.*//" \
-// RUN: | grep -v "OPTIONAL" \
-// RUN: | grep "__asan_.*(" | sed "s/.* __asan_/__asan_/;s/(.*//" \
-// RUN: > %t.interface
-// RUN: echo __asan_report_load1 >> %t.interface
-// RUN: echo __asan_report_load2 >> %t.interface
-// RUN: echo __asan_report_load4 >> %t.interface
-// RUN: echo __asan_report_load8 >> %t.interface
-// RUN: echo __asan_report_load16 >> %t.interface
-// RUN: echo __asan_report_store1 >> %t.interface
-// RUN: echo __asan_report_store2 >> %t.interface
-// RUN: echo __asan_report_store4 >> %t.interface
-// RUN: echo __asan_report_store8 >> %t.interface
-// RUN: echo __asan_report_store16 >> %t.interface
-// RUN: echo __asan_report_load_n >> %t.interface
-// RUN: echo __asan_report_store_n >> %t.interface
-// RUN: cat %t.interface | sort -u | diff %t.symbols -
-
-// FIXME: nm -D on powerpc somewhy shows ASan interface symbols residing
-// in "initialized data section".
-// REQUIRES: x86_64-supported-target,i386-supported-target
-
-int main() { return 0; }
diff --git a/lib/asan/lit_tests/TestCases/Linux/lit.local.cfg b/lib/asan/lit_tests/TestCases/Linux/lit.local.cfg
deleted file mode 100644
index 57271b8078a4..000000000000
--- a/lib/asan/lit_tests/TestCases/Linux/lit.local.cfg
+++ /dev/null
@@ -1,9 +0,0 @@
-def getRoot(config):
- if not config.parent:
- return config
- return getRoot(config.parent)
-
-root = getRoot(config)
-
-if root.host_os not in ['Linux']:
- config.unsupported = True
diff --git a/lib/asan/lit_tests/TestCases/Linux/malloc-in-qsort.cc b/lib/asan/lit_tests/TestCases/Linux/malloc-in-qsort.cc
deleted file mode 100644
index 3251b35e143c..000000000000
--- a/lib/asan/lit_tests/TestCases/Linux/malloc-in-qsort.cc
+++ /dev/null
@@ -1,56 +0,0 @@
-// RUN: %clangxx_asan -O2 %s -o %t
-// RUN: ASAN_OPTIONS=fast_unwind_on_malloc=1 not %t 2>&1 | FileCheck %s --check-prefix=CHECK-FAST
-// RUN: ASAN_OPTIONS=fast_unwind_on_malloc=0 not %t 2>&1 | FileCheck %s --check-prefix=CHECK-SLOW
-
-// Test how well we unwind in presence of qsort in the stack
-// (i.e. if we can unwind through a function compiled w/o frame pointers).
-// https://code.google.com/p/address-sanitizer/issues/detail?id=137
-
-// Fast unwinder is only avaliable on x86_64 and i386.
-// REQUIRES: x86_64-supported-target
-
-// REQUIRES: compiler-rt-optimized
-
-#include <stdlib.h>
-#include <stdio.h>
-
-int *GlobalPtr;
-
-extern "C" {
-int QsortCallback(const void *a, const void *b) {
- char *x = (char*)a;
- char *y = (char*)b;
- printf("Calling QsortCallback\n");
- GlobalPtr = new int[10];
- return (int)*x - (int)*y;
-}
-
-__attribute__((noinline))
-void MyQsort(char *a, size_t size) {
- printf("Calling qsort\n");
- qsort(a, size, sizeof(char), QsortCallback);
- printf("Done\n"); // Avoid tail call.
-}
-} // extern "C"
-
-int main() {
- char a[2] = {1, 2};
- MyQsort(a, 2);
- return GlobalPtr[10];
-}
-
-// Fast unwind: can not unwind through qsort.
-// FIXME: this test does not properly work with slow unwind yet.
-
-// CHECK-FAST: ERROR: AddressSanitizer: heap-buffer-overflow
-// CHECK-FAST: is located 0 bytes to the right
-// CHECK-FAST: #0{{.*}}operator new
-// CHECK-FAST-NEXT: #1{{.*}}QsortCallback
-// CHECK-FAST-NOT: MyQsort
-//
-// CHECK-SLOW: ERROR: AddressSanitizer: heap-buffer-overflow
-// CHECK-SLOW: is located 0 bytes to the right
-// CHECK-SLOW: #0{{.*}}operator new
-// CHECK-SLOW-NEXT: #1{{.*}}QsortCallback
-// CHECK-SLOW: #{{.*}}MyQsort
-// CHECK-SLOW-NEXT: #{{.*}}main
diff --git a/lib/asan/lit_tests/TestCases/Linux/malloc_delete_mismatch.cc b/lib/asan/lit_tests/TestCases/Linux/malloc_delete_mismatch.cc
deleted file mode 100644
index 7010eb2de2e7..000000000000
--- a/lib/asan/lit_tests/TestCases/Linux/malloc_delete_mismatch.cc
+++ /dev/null
@@ -1,31 +0,0 @@
-// Check that we detect malloc/delete mismatch only if the approptiate flag
-// is set.
-
-// RUN: %clangxx_asan -g %s -o %t 2>&1
-
-// Find error and provide malloc context.
-// RUN: ASAN_OPTIONS=alloc_dealloc_mismatch=1 not %t 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=ALLOC-STACK
-
-// No error here.
-// RUN: ASAN_OPTIONS=alloc_dealloc_mismatch=0 %t
-
-// Also works if no malloc context is available.
-// RUN: ASAN_OPTIONS=alloc_dealloc_mismatch=1:malloc_context_size=0:fast_unwind_on_malloc=0 not %t 2>&1 | FileCheck %s
-// RUN: ASAN_OPTIONS=alloc_dealloc_mismatch=1:malloc_context_size=0:fast_unwind_on_malloc=1 not %t 2>&1 | FileCheck %s
-#include <stdlib.h>
-
-static volatile char *x;
-
-int main() {
- x = (char*)malloc(10);
- x[0] = 0;
- delete x;
-}
-// CHECK: ERROR: AddressSanitizer: alloc-dealloc-mismatch (malloc vs operator delete) on 0x
-// CHECK-NEXT: #0{{.*}}operator delete
-// CHECK: #{{.*}}main
-// CHECK: is located 0 bytes inside of 10-byte region
-// CHECK-NEXT: allocated by thread T0 here:
-// ALLOC-STACK-NEXT: #0{{.*}}malloc
-// ALLOC-STACK: #{{.*}}main
-// CHECK: HINT: {{.*}} you may set ASAN_OPTIONS=alloc_dealloc_mismatch=0
diff --git a/lib/asan/lit_tests/TestCases/Linux/overflow-in-qsort.cc b/lib/asan/lit_tests/TestCases/Linux/overflow-in-qsort.cc
deleted file mode 100644
index 139977261ec9..000000000000
--- a/lib/asan/lit_tests/TestCases/Linux/overflow-in-qsort.cc
+++ /dev/null
@@ -1,51 +0,0 @@
-// RUN: %clangxx_asan -O2 %s -o %t
-// RUN: ASAN_OPTIONS=fast_unwind_on_fatal=1 not %t 2>&1 | FileCheck %s --check-prefix=CHECK-FAST
-// RUN: ASAN_OPTIONS=fast_unwind_on_fatal=0 not %t 2>&1 | FileCheck %s --check-prefix=CHECK-SLOW
-
-// Test how well we unwind in presence of qsort in the stack
-// (i.e. if we can unwind through a function compiled w/o frame pointers).
-// https://code.google.com/p/address-sanitizer/issues/detail?id=137
-
-// Fast unwinder is only avaliable on x86_64 and i386.
-// REQUIRES: x86_64-supported-target
-
-#include <stdlib.h>
-#include <stdio.h>
-
-int global_array[10];
-volatile int one = 1;
-
-extern "C" {
-int QsortCallback(const void *a, const void *b) {
- char *x = (char*)a;
- char *y = (char*)b;
- printf("Calling QsortCallback\n");
- global_array[one * 10] = 0; // BOOM
- return (int)*x - (int)*y;
-}
-
-__attribute__((noinline))
-void MyQsort(char *a, size_t size) {
- printf("Calling qsort\n");
- qsort(a, size, sizeof(char), QsortCallback);
- printf("Done\n"); // Avoid tail call.
-}
-} // extern "C"
-
-int main() {
- char a[2] = {1, 2};
- MyQsort(a, 2);
-}
-
-// Fast unwind: can not unwind through qsort.
-
-// CHECK-FAST: ERROR: AddressSanitizer: global-buffer-overflow
-// CHECK-FAST: #0{{.*}} in QsortCallback
-// CHECK-FAST-NOT: MyQsort
-// CHECK-FAST: is located 0 bytes to the right of global variable 'global_array
-
-// CHECK-SLOW: ERROR: AddressSanitizer: global-buffer-overflow
-// CHECK-SLOW: #0{{.*}} in QsortCallback
-// CHECK-SLOW: #{{.*}} in MyQsort
-// CHECK-SLOW: #{{.*}} in main
-// CHECK-SLOW: is located 0 bytes to the right of global variable 'global_array
diff --git a/lib/asan/lit_tests/TestCases/Linux/preinit_test.cc b/lib/asan/lit_tests/TestCases/Linux/preinit_test.cc
deleted file mode 100644
index 28e509472c0c..000000000000
--- a/lib/asan/lit_tests/TestCases/Linux/preinit_test.cc
+++ /dev/null
@@ -1,27 +0,0 @@
-// RUN: %clangxx -DFUNC=zzzz %s -shared -o %t.so -fPIC
-// RUN: %clangxx_asan -DFUNC=main %s -o %t -Wl,-R. %t.so
-// RUN: %t
-
-// This test ensures that we call __asan_init early enough.
-// We build a shared library w/o asan instrumentation
-// and the binary with asan instrumentation.
-// Both files include the same header (emulated by -DFUNC here)
-// with C++ template magic which runs global initializer at library load time.
-// The function get() is instrumented with asan, but called
-// before the usual constructors are run.
-// So, we must make sure that __asan_init is executed even earlier.
-//
-// See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=56393
-
-struct A {
- int foo() const { return 0; }
-};
-A get () { return A(); }
-template <class> struct O {
- static A const e;
-};
-template <class T> A const O <T>::e = get();
-int FUNC() {
- return O<int>::e.foo();
-}
-
diff --git a/lib/asan/lit_tests/TestCases/Linux/ptrace.cc b/lib/asan/lit_tests/TestCases/Linux/ptrace.cc
deleted file mode 100644
index 8831b81efa96..000000000000
--- a/lib/asan/lit_tests/TestCases/Linux/ptrace.cc
+++ /dev/null
@@ -1,52 +0,0 @@
-// RUN: %clangxx_asan -O0 %s -o %t && %t
-// RUN: %clangxx_asan -DPOSITIVE -O0 %s -o %t && not %t 2>&1 | FileCheck %s
-
-#include <assert.h>
-#include <stdio.h>
-#include <sys/ptrace.h>
-#include <sys/types.h>
-#include <sys/user.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-int main(void) {
- pid_t pid;
- pid = fork();
- if (pid == 0) { // child
- ptrace(PTRACE_TRACEME, 0, NULL, NULL);
- execl("/bin/true", "true", NULL);
- } else {
- wait(NULL);
- user_regs_struct regs;
- int res;
- user_regs_struct * volatile pregs = &regs;
-#ifdef POSITIVE
- ++pregs;
-#endif
- res = ptrace(PTRACE_GETREGS, pid, NULL, pregs);
- // CHECK: AddressSanitizer: stack-buffer-overflow
- // CHECK: {{.*ptrace.cc:}}[[@LINE-2]]
- assert(!res);
-#if __WORDSIZE == 64
- printf("%zx\n", regs.rip);
-#else
- printf("%lx\n", regs.eip);
-#endif
-
- user_fpregs_struct fpregs;
- res = ptrace(PTRACE_GETFPREGS, pid, NULL, &fpregs);
- assert(!res);
- printf("%lx\n", (unsigned long)fpregs.cwd);
-
-#if __WORDSIZE == 32
- user_fpxregs_struct fpxregs;
- res = ptrace(PTRACE_GETFPXREGS, pid, NULL, &fpxregs);
- assert(!res);
- printf("%lx\n", (unsigned long)fpxregs.mxcsr);
-#endif
-
- ptrace(PTRACE_CONT, pid, NULL, NULL);
- wait(NULL);
- }
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/Linux/rlimit_mmap_test.cc b/lib/asan/lit_tests/TestCases/Linux/rlimit_mmap_test.cc
deleted file mode 100644
index 0d1d4baa7671..000000000000
--- a/lib/asan/lit_tests/TestCases/Linux/rlimit_mmap_test.cc
+++ /dev/null
@@ -1,16 +0,0 @@
-// Check that we properly report mmap failure.
-// RUN: %clangxx_asan %s -o %t && not %t 2>&1 | FileCheck %s
-#include <stdlib.h>
-#include <assert.h>
-#include <sys/time.h>
-#include <sys/resource.h>
-
-static volatile void *x;
-
-int main(int argc, char **argv) {
- struct rlimit mmap_resource_limit = { 0, 0 };
- assert(0 == setrlimit(RLIMIT_AS, &mmap_resource_limit));
- x = malloc(10000000);
-// CHECK: ERROR: Failed to mmap
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/Linux/swapcontext_test.cc b/lib/asan/lit_tests/TestCases/Linux/swapcontext_test.cc
deleted file mode 100644
index 6cbb69a35321..000000000000
--- a/lib/asan/lit_tests/TestCases/Linux/swapcontext_test.cc
+++ /dev/null
@@ -1,90 +0,0 @@
-// Check that ASan plays well with easy cases of makecontext/swapcontext.
-
-// RUN: %clangxx_asan -O0 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O1 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O2 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O3 %s -o %t && %t 2>&1 | FileCheck %s
-//
-// This test is too sublte to try on non-x86 arch for now.
-// REQUIRES: x86_64-supported-target,i386-supported-target
-
-#include <stdio.h>
-#include <ucontext.h>
-#include <unistd.h>
-
-ucontext_t orig_context;
-ucontext_t child_context;
-
-const int kStackSize = 1 << 20;
-
-__attribute__((noinline))
-void Throw() {
- throw 1;
-}
-
-__attribute__((noinline))
-void ThrowAndCatch() {
- try {
- Throw();
- } catch(int a) {
- printf("ThrowAndCatch: %d\n", a);
- }
-}
-
-void Child(int mode) {
- char x[32] = {0}; // Stack gets poisoned.
- printf("Child: %p\n", x);
- ThrowAndCatch(); // Simulate __asan_handle_no_return().
- // (a) Do nothing, just return to parent function.
- // (b) Jump into the original function. Stack remains poisoned unless we do
- // something.
- if (mode == 1) {
- if (swapcontext(&child_context, &orig_context) < 0) {
- perror("swapcontext");
- _exit(0);
- }
- }
-}
-
-int Run(int arg, int mode, char *child_stack) {
- printf("Child stack: %p\n", child_stack);
- // Setup child context.
- getcontext(&child_context);
- child_context.uc_stack.ss_sp = child_stack;
- child_context.uc_stack.ss_size = kStackSize / 2;
- if (mode == 0) {
- child_context.uc_link = &orig_context;
- }
- makecontext(&child_context, (void (*)())Child, 1, mode);
- if (swapcontext(&orig_context, &child_context) < 0) {
- perror("swapcontext");
- return 0;
- }
- // Touch childs's stack to make sure it's unpoisoned.
- for (int i = 0; i < kStackSize; i++) {
- child_stack[i] = i;
- }
- return child_stack[arg];
-}
-
-int main(int argc, char **argv) {
- char stack[kStackSize + 1];
- // CHECK: WARNING: ASan doesn't fully support makecontext/swapcontext
- int ret = 0;
- ret += Run(argc - 1, 0, stack);
- printf("Test1 passed\n");
- // CHECK: Test1 passed
- ret += Run(argc - 1, 1, stack);
- printf("Test2 passed\n");
- // CHECK: Test2 passed
- char *heap = new char[kStackSize + 1];
- ret += Run(argc - 1, 0, heap);
- printf("Test3 passed\n");
- // CHECK: Test3 passed
- ret += Run(argc - 1, 1, heap);
- printf("Test4 passed\n");
- // CHECK: Test4 passed
-
- delete [] heap;
- return ret;
-}
diff --git a/lib/asan/lit_tests/TestCases/Linux/syscalls.cc b/lib/asan/lit_tests/TestCases/Linux/syscalls.cc
deleted file mode 100644
index 4bcbe446113e..000000000000
--- a/lib/asan/lit_tests/TestCases/Linux/syscalls.cc
+++ /dev/null
@@ -1,22 +0,0 @@
-// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>&1 | FileCheck %s
-
-#include <assert.h>
-#include <errno.h>
-#include <glob.h>
-#include <stdio.h>
-#include <string.h>
-
-#include <sanitizer/linux_syscall_hooks.h>
-
-/* Test the presence of __sanitizer_syscall_ in the tool runtime, and general
- sanity of their behaviour. */
-
-int main(int argc, char *argv[]) {
- char buf[1000];
- __sanitizer_syscall_pre_recvmsg(0, buf - 1, 0);
- // CHECK: AddressSanitizer: stack-buffer-{{.*}}erflow
- // CHECK: READ of size {{.*}} at {{.*}} thread T0
- // CHECK: #0 {{.*}} in __sanitizer_syscall{{.*}}recvmsg
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/Linux/time_null_regtest.cc b/lib/asan/lit_tests/TestCases/Linux/time_null_regtest.cc
deleted file mode 100644
index 566409be6a19..000000000000
--- a/lib/asan/lit_tests/TestCases/Linux/time_null_regtest.cc
+++ /dev/null
@@ -1,20 +0,0 @@
-// RUN: %clangxx_asan -O0 %s -fsanitize-address-zero-base-shadow -pie -o %t && %t 2>&1 | FileCheck %s
-
-// Zero-base shadow only works on x86_64 and i386.
-// REQUIRES: x86_64-supported-target
-
-// A regression test for time(NULL), which caused ASan to crash in the
-// zero-based shadow mode on Linux.
-// FIXME: this test does not work on Darwin, because the code pages of the
-// executable interleave with the zero-based shadow.
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <time.h>
-
-int main() {
- time_t t = time(NULL);
- fprintf(stderr, "Time: %s\n", ctime(&t)); // NOLINT
- // CHECK: {{Time: .* .* .*}}
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/Linux/tsd_dtor_leak.cc b/lib/asan/lit_tests/TestCases/Linux/tsd_dtor_leak.cc
deleted file mode 100644
index a1d89ee437d4..000000000000
--- a/lib/asan/lit_tests/TestCases/Linux/tsd_dtor_leak.cc
+++ /dev/null
@@ -1,39 +0,0 @@
-// Regression test for a leak in tsd:
-// https://code.google.com/p/address-sanitizer/issues/detail?id=233
-// RUN: %clangxx_asan -O1 %s -o %t
-// RUN: ASAN_OPTIONS=quarantine_size=1 %t
-#include <pthread.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <assert.h>
-
-extern "C" size_t __asan_get_heap_size();
-static pthread_key_t tsd_key;
-
-void *Thread(void *) {
- pthread_setspecific(tsd_key, malloc(10));
- return 0;
-}
-
-static volatile void *v;
-
-void Dtor(void *tsd) {
- v = malloc(10000);
- free(tsd);
- free((void*)v); // The bug was that this was leaking.
-}
-
-int main() {
- assert(0 == pthread_key_create(&tsd_key, Dtor));
- size_t old_heap_size = 0;
- for (int i = 0; i < 10; i++) {
- pthread_t t;
- pthread_create(&t, 0, Thread, 0);
- pthread_join(t, 0);
- size_t new_heap_size = __asan_get_heap_size();
- fprintf(stderr, "heap size: new: %zd old: %zd\n", new_heap_size, old_heap_size);
- if (old_heap_size)
- assert(old_heap_size == new_heap_size);
- old_heap_size = new_heap_size;
- }
-}
diff --git a/lib/asan/lit_tests/TestCases/Linux/uar_signals.cc b/lib/asan/lit_tests/TestCases/Linux/uar_signals.cc
deleted file mode 100644
index 9663859dfefd..000000000000
--- a/lib/asan/lit_tests/TestCases/Linux/uar_signals.cc
+++ /dev/null
@@ -1,70 +0,0 @@
-// This test shows that the current implementation of use-after-return is
-// not signal-safe.
-// RUN: %clangxx_asan -O1 %s -o %t -lpthread && %t
-// RUN: %clangxx_asan -O1 %s -o %t -lpthread && %t
-#include <signal.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <sys/time.h>
-#include <pthread.h>
-
-int *g;
-int n_signals;
-
-typedef void (*Sigaction)(int, siginfo_t *, void *);
-
-void SignalHandler(int, siginfo_t*, void*) {
- int local;
- g = &local;
- n_signals++;
- // printf("s: %p\n", &local);
-}
-
-static void EnableSigprof(Sigaction SignalHandler) {
- struct sigaction sa;
- sa.sa_sigaction = SignalHandler;
- sa.sa_flags = SA_RESTART | SA_SIGINFO;
- sigemptyset(&sa.sa_mask);
- if (sigaction(SIGPROF, &sa, NULL) != 0) {
- perror("sigaction");
- abort();
- }
- struct itimerval timer;
- timer.it_interval.tv_sec = 0;
- timer.it_interval.tv_usec = 1;
- timer.it_value = timer.it_interval;
- if (setitimer(ITIMER_PROF, &timer, 0) != 0) {
- perror("setitimer");
- abort();
- }
-}
-
-void RecursiveFunction(int depth) {
- if (depth == 0) return;
- int local;
- g = &local;
- // printf("r: %p\n", &local);
- // printf("[%2d] n_signals: %d\n", depth, n_signals);
- RecursiveFunction(depth - 1);
- RecursiveFunction(depth - 1);
-}
-
-void *Thread(void *) {
- RecursiveFunction(18);
- return NULL;
-}
-
-int main(int argc, char **argv) {
- EnableSigprof(SignalHandler);
-
- for (int i = 0; i < 4; i++) {
- fprintf(stderr, ".");
- const int kNumThread = sizeof(void*) == 8 ? 16 : 8;
- pthread_t t[kNumThread];
- for (int i = 0; i < kNumThread; i++)
- pthread_create(&t[i], 0, Thread, 0);
- for (int i = 0; i < kNumThread; i++)
- pthread_join(t[i], 0);
- }
- fprintf(stderr, "\n");
-}
diff --git a/lib/asan/lit_tests/TestCases/Linux/unpoison_tls.cc b/lib/asan/lit_tests/TestCases/Linux/unpoison_tls.cc
deleted file mode 100644
index d67c4f954e43..000000000000
--- a/lib/asan/lit_tests/TestCases/Linux/unpoison_tls.cc
+++ /dev/null
@@ -1,35 +0,0 @@
-// Test that TLS is unpoisoned on thread death.
-// REQUIRES: x86_64-supported-target,i386-supported-target
-
-// RUN: %clangxx_asan -O1 %s -o %t && %t 2>&1
-
-#include <assert.h>
-#include <pthread.h>
-#include <stdio.h>
-
-#include <sanitizer/asan_interface.h>
-
-__thread int64_t tls_var[2];
-
-volatile int64_t *p_tls_var;
-
-void *first(void *arg) {
- ASAN_POISON_MEMORY_REGION(&tls_var, sizeof(tls_var));
- p_tls_var = tls_var;
- return 0;
-}
-
-void *second(void *arg) {
- assert(tls_var == p_tls_var);
- *p_tls_var = 1;
- return 0;
-}
-
-int main(int argc, char *argv[]) {
- pthread_t p;
- assert(0 == pthread_create(&p, 0, first, 0));
- assert(0 == pthread_join(p, 0));
- assert(0 == pthread_create(&p, 0, second, 0));
- assert(0 == pthread_join(p, 0));
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/Linux/zero-base-shadow32.cc b/lib/asan/lit_tests/TestCases/Linux/zero-base-shadow32.cc
deleted file mode 100644
index e6bcc5597471..000000000000
--- a/lib/asan/lit_tests/TestCases/Linux/zero-base-shadow32.cc
+++ /dev/null
@@ -1,24 +0,0 @@
-// RUN: %clangxx_asan -O0 -fsanitize-address-zero-base-shadow -fPIE -pie %s -o %t
-// RUN: not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O1 -fsanitize-address-zero-base-shadow -fPIE -pie %s -o %t
-// RUN: not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O2 -fsanitize-address-zero-base-shadow -fPIE -pie %s -o %t
-// RUN: not %t 2>&1 | FileCheck %s
-
-// Zero-base shadow only works on x86_64 and i386.
-// REQUIRES: i386-supported-target, asan-32-bits
-
-#include <string.h>
-int main(int argc, char **argv) {
- char x[10];
- memset(x, 0, 10);
- int res = x[argc * 10]; // BOOOM
- // CHECK: {{READ of size 1 at 0x.* thread T0}}
- // CHECK: {{ #0 0x.* in main .*zero-base-shadow32.cc:}}[[@LINE-2]]
- // CHECK: {{Address 0x.* is .* frame}}
- // CHECK: main
-
- // Check that shadow for stack memory occupies lower part of address space.
- // CHECK: =>0x1
- return res;
-}
diff --git a/lib/asan/lit_tests/TestCases/Linux/zero-base-shadow64.cc b/lib/asan/lit_tests/TestCases/Linux/zero-base-shadow64.cc
deleted file mode 100644
index 1db725c95752..000000000000
--- a/lib/asan/lit_tests/TestCases/Linux/zero-base-shadow64.cc
+++ /dev/null
@@ -1,24 +0,0 @@
-// RUN: %clangxx_asan -O0 -fsanitize-address-zero-base-shadow -fPIE -pie %s -o %t
-// RUN: not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O1 -fsanitize-address-zero-base-shadow -fPIE -pie %s -o %t
-// RUN: not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O2 -fsanitize-address-zero-base-shadow -fPIE -pie %s -o %t
-// RUN: not %t 2>&1 | FileCheck %s
-
-// Zero-base shadow only works on x86_64 and i386.
-// REQUIRES: x86_64-supported-target, asan-64-bits
-
-#include <string.h>
-int main(int argc, char **argv) {
- char x[10];
- memset(x, 0, 10);
- int res = x[argc * 10]; // BOOOM
- // CHECK: {{READ of size 1 at 0x.* thread T0}}
- // CHECK: {{ #0 0x.* in main .*zero-base-shadow64.cc:}}[[@LINE-2]]
- // CHECK: {{Address 0x.* is .* frame}}
- // CHECK: main
-
- // Check that shadow for stack memory occupies lower part of address space.
- // CHECK: =>0x0f
- return res;
-}
diff --git a/lib/asan/lit_tests/TestCases/SharedLibs/darwin-dummy-shared-lib-so.cc b/lib/asan/lit_tests/TestCases/SharedLibs/darwin-dummy-shared-lib-so.cc
deleted file mode 100644
index 5d939991476e..000000000000
--- a/lib/asan/lit_tests/TestCases/SharedLibs/darwin-dummy-shared-lib-so.cc
+++ /dev/null
@@ -1,13 +0,0 @@
-//===----------- darwin-dummy-shared-lib-so.cc ------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file is a part of AddressSanitizer, an address sanity checker.
-//
-//===----------------------------------------------------------------------===//
-void foo() {}
diff --git a/lib/asan/lit_tests/TestCases/SharedLibs/dlclose-test-so.cc b/lib/asan/lit_tests/TestCases/SharedLibs/dlclose-test-so.cc
deleted file mode 100644
index 73e00507358a..000000000000
--- a/lib/asan/lit_tests/TestCases/SharedLibs/dlclose-test-so.cc
+++ /dev/null
@@ -1,33 +0,0 @@
-//===----------- dlclose-test-so.cc -----------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file is a part of AddressSanitizer, an address sanity checker.
-//
-// Regression test for
-// http://code.google.com/p/address-sanitizer/issues/detail?id=19
-//===----------------------------------------------------------------------===//
-#include <stdio.h>
-
-static int pad1;
-static int static_var;
-static int pad2;
-
-extern "C"
-int *get_address_of_static_var() {
- return &static_var;
-}
-
-__attribute__((constructor))
-void at_dlopen() {
- printf("%s: I am being dlopened\n", __FILE__);
-}
-__attribute__((destructor))
-void at_dlclose() {
- printf("%s: I am being dlclosed\n", __FILE__);
-}
diff --git a/lib/asan/lit_tests/TestCases/SharedLibs/init-order-dlopen-so.cc b/lib/asan/lit_tests/TestCases/SharedLibs/init-order-dlopen-so.cc
deleted file mode 100644
index dc097a520d03..000000000000
--- a/lib/asan/lit_tests/TestCases/SharedLibs/init-order-dlopen-so.cc
+++ /dev/null
@@ -1,12 +0,0 @@
-#include <stdio.h>
-#include <unistd.h>
-
-extern "C" void inc_global();
-
-int slow_init() {
- sleep(1);
- inc_global();
- return 42;
-}
-
-int slowly_init_glob = slow_init();
diff --git a/lib/asan/lit_tests/TestCases/SharedLibs/lit.local.cfg b/lib/asan/lit_tests/TestCases/SharedLibs/lit.local.cfg
deleted file mode 100644
index b3677c17a0f2..000000000000
--- a/lib/asan/lit_tests/TestCases/SharedLibs/lit.local.cfg
+++ /dev/null
@@ -1,4 +0,0 @@
-# Sources in this directory are compiled as shared libraries and used by
-# tests in parent directory.
-
-config.suffixes = []
diff --git a/lib/asan/lit_tests/TestCases/SharedLibs/shared-lib-test-so.cc b/lib/asan/lit_tests/TestCases/SharedLibs/shared-lib-test-so.cc
deleted file mode 100644
index 6ef565ce47b3..000000000000
--- a/lib/asan/lit_tests/TestCases/SharedLibs/shared-lib-test-so.cc
+++ /dev/null
@@ -1,26 +0,0 @@
-//===----------- shared-lib-test-so.cc --------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file is a part of AddressSanitizer, an address sanity checker.
-//
-//===----------------------------------------------------------------------===//
-#include <stdio.h>
-
-int pad[10];
-int GLOB[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
-
-extern "C"
-void inc(int index) {
- GLOB[index]++;
-}
-
-extern "C"
-void inc2(int *a, int index) {
- a[index]++;
-}
diff --git a/lib/asan/lit_tests/TestCases/allocator_returns_null.cc b/lib/asan/lit_tests/TestCases/allocator_returns_null.cc
deleted file mode 100644
index 595c9e252f86..000000000000
--- a/lib/asan/lit_tests/TestCases/allocator_returns_null.cc
+++ /dev/null
@@ -1,81 +0,0 @@
-// Test the behavior of malloc/calloc/realloc when the allocation size is huge.
-// By default (allocator_may_return_null=0) the process should crash.
-// With allocator_may_return_null=1 the allocator should return 0.
-//
-// RUN: %clangxx_asan -O0 %s -o %t
-// RUN: not %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mCRASH
-// RUN: ASAN_OPTIONS=allocator_may_return_null=0 not %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mCRASH
-// RUN: ASAN_OPTIONS=allocator_may_return_null=1 %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mNULL
-// RUN: ASAN_OPTIONS=allocator_may_return_null=0 not %t calloc 2>&1 | FileCheck %s --check-prefix=CHECK-cCRASH
-// RUN: ASAN_OPTIONS=allocator_may_return_null=1 %t calloc 2>&1 | FileCheck %s --check-prefix=CHECK-cNULL
-// RUN: ASAN_OPTIONS=allocator_may_return_null=0 not %t calloc-overflow 2>&1 | FileCheck %s --check-prefix=CHECK-coCRASH
-// RUN: ASAN_OPTIONS=allocator_may_return_null=1 %t calloc-overflow 2>&1 | FileCheck %s --check-prefix=CHECK-coNULL
-// RUN: ASAN_OPTIONS=allocator_may_return_null=0 not %t realloc 2>&1 | FileCheck %s --check-prefix=CHECK-rCRASH
-// RUN: ASAN_OPTIONS=allocator_may_return_null=1 %t realloc 2>&1 | FileCheck %s --check-prefix=CHECK-rNULL
-// RUN: ASAN_OPTIONS=allocator_may_return_null=0 not %t realloc-after-malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mrCRASH
-// RUN: ASAN_OPTIONS=allocator_may_return_null=1 %t realloc-after-malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mrNULL
-
-#include <limits.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#include <assert.h>
-#include <limits>
-int main(int argc, char **argv) {
- volatile size_t size = std::numeric_limits<size_t>::max() - 10000;
- assert(argc == 2);
- char *x = 0;
- if (!strcmp(argv[1], "malloc")) {
- fprintf(stderr, "malloc:\n");
- x = (char*)malloc(size);
- }
- if (!strcmp(argv[1], "calloc")) {
- fprintf(stderr, "calloc:\n");
- x = (char*)calloc(size / 4, 4);
- }
-
- if (!strcmp(argv[1], "calloc-overflow")) {
- fprintf(stderr, "calloc-overflow:\n");
- volatile size_t kMaxSizeT = std::numeric_limits<size_t>::max();
- size_t kArraySize = 4096;
- volatile size_t kArraySize2 = kMaxSizeT / kArraySize + 10;
- x = (char*)calloc(kArraySize, kArraySize2);
- }
-
- if (!strcmp(argv[1], "realloc")) {
- fprintf(stderr, "realloc:\n");
- x = (char*)realloc(0, size);
- }
- if (!strcmp(argv[1], "realloc-after-malloc")) {
- fprintf(stderr, "realloc-after-malloc:\n");
- char *t = (char*)malloc(100);
- *t = 42;
- x = (char*)realloc(t, size);
- assert(*t == 42);
- }
- // The NULL pointer is printed differently on different systems, while (long)0
- // is always the same.
- fprintf(stderr, "x: %lx\n", (long)x);
- return x != 0;
-}
-// CHECK-mCRASH: malloc:
-// CHECK-mCRASH: AddressSanitizer's allocator is terminating the process
-// CHECK-cCRASH: calloc:
-// CHECK-cCRASH: AddressSanitizer's allocator is terminating the process
-// CHECK-coCRASH: calloc-overflow:
-// CHECK-coCRASH: AddressSanitizer's allocator is terminating the process
-// CHECK-rCRASH: realloc:
-// CHECK-rCRASH: AddressSanitizer's allocator is terminating the process
-// CHECK-mrCRASH: realloc-after-malloc:
-// CHECK-mrCRASH: AddressSanitizer's allocator is terminating the process
-
-// CHECK-mNULL: malloc:
-// CHECK-mNULL: x: 0
-// CHECK-cNULL: calloc:
-// CHECK-cNULL: x: 0
-// CHECK-coNULL: calloc-overflow:
-// CHECK-coNULL: x: 0
-// CHECK-rNULL: realloc:
-// CHECK-rNULL: x: 0
-// CHECK-mrNULL: realloc-after-malloc:
-// CHECK-mrNULL: x: 0
diff --git a/lib/asan/lit_tests/TestCases/allow_user_segv.cc b/lib/asan/lit_tests/TestCases/allow_user_segv.cc
deleted file mode 100644
index 55cf6044e7a0..000000000000
--- a/lib/asan/lit_tests/TestCases/allow_user_segv.cc
+++ /dev/null
@@ -1,48 +0,0 @@
-// Regression test for
-// https://code.google.com/p/address-sanitizer/issues/detail?id=180
-
-// RUN: %clangxx_asan -O0 %s -o %t && ASAN_OPTIONS=allow_user_segv_handler=true not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O2 %s -o %t && ASAN_OPTIONS=allow_user_segv_handler=true not %t 2>&1 | FileCheck %s
-
-#include <signal.h>
-#include <stdio.h>
-
-struct sigaction user_sigaction;
-struct sigaction original_sigaction;
-
-void User_OnSIGSEGV(int signum, siginfo_t *siginfo, void *context) {
- fprintf(stderr, "User sigaction called\n");
- if (original_sigaction.sa_flags | SA_SIGINFO)
- original_sigaction.sa_sigaction(signum, siginfo, context);
- else
- original_sigaction.sa_handler(signum);
-}
-
-int DoSEGV() {
- volatile int *x = 0;
- return *x;
-}
-
-int main() {
- user_sigaction.sa_sigaction = User_OnSIGSEGV;
- user_sigaction.sa_flags = SA_SIGINFO;
-#if defined(__APPLE__) && !defined(__LP64__)
- // On 32-bit Darwin KERN_PROTECTION_FAILURE (SIGBUS) is delivered.
- int signum = SIGBUS;
-#else
- // On 64-bit Darwin KERN_INVALID_ADDRESS (SIGSEGV) is delivered.
- // On Linux SIGSEGV is delivered as well.
- int signum = SIGSEGV;
-#endif
- if (sigaction(signum, &user_sigaction, &original_sigaction)) {
- perror("sigaction");
- return 1;
- }
- fprintf(stderr, "User sigaction installed\n");
- return DoSEGV();
-}
-
-// CHECK: User sigaction installed
-// CHECK-NEXT: User sigaction called
-// CHECK-NEXT: ASAN:SIGSEGV
-// CHECK: AddressSanitizer: SEGV on unknown address
diff --git a/lib/asan/lit_tests/TestCases/asan-symbolize-sanity-test.cc b/lib/asan/lit_tests/TestCases/asan-symbolize-sanity-test.cc
deleted file mode 100644
index 0efe245bb6b5..000000000000
--- a/lib/asan/lit_tests/TestCases/asan-symbolize-sanity-test.cc
+++ /dev/null
@@ -1,39 +0,0 @@
-// Check that asan_symbolize.py script works (for binaries, ASan RTL and
-// shared object files.
-
-// RUN: %clangxx_asan -O0 %p/SharedLibs/shared-lib-test-so.cc -fPIC -shared -o %t-so.so
-// RUN: %clangxx_asan -O0 %s -o %t
-// RUN: ASAN_SYMBOLIZER_PATH= not %t 2>&1 | %asan_symbolize | FileCheck %s
-#include <dlfcn.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include <string>
-
-using std::string;
-
-typedef void (fun_t)(int*, int);
-
-int main(int argc, char *argv[]) {
- string path = string(argv[0]) + "-so.so";
- printf("opening %s ... \n", path.c_str());
- void *lib = dlopen(path.c_str(), RTLD_NOW);
- if (!lib) {
- printf("error in dlopen(): %s\n", dlerror());
- return 1;
- }
- fun_t *inc2 = (fun_t*)dlsym(lib, "inc2");
- if (!inc2) return 1;
- printf("ok\n");
- int *array = (int*)malloc(40);
- inc2(array, 1);
- inc2(array, -1); // BOOM
- // CHECK: ERROR: AddressSanitizer: heap-buffer-overflow
- // CHECK: READ of size 4 at 0x{{.*}}
- // CHECK: #0 {{.*}} in inc2 {{.*}}shared-lib-test-so.cc:25
- // CHECK: #1 {{.*}} in main {{.*}}asan-symbolize-sanity-test.cc:[[@LINE-4]]
- // CHECK: allocated by thread T{{.*}} here:
- // CHECK: #{{.*}} in {{(wrap_|__interceptor_)?}}malloc
- // CHECK: #{{.*}} in main {{.*}}asan-symbolize-sanity-test.cc:[[@LINE-9]]
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/assign_large_valloc_to_global.cc b/lib/asan/lit_tests/TestCases/assign_large_valloc_to_global.cc
deleted file mode 100644
index b0a501576945..000000000000
--- a/lib/asan/lit_tests/TestCases/assign_large_valloc_to_global.cc
+++ /dev/null
@@ -1,8 +0,0 @@
-// Make sure we don't report a leak nor hang.
-// RUN: %clangxx_asan -O3 %s -o %t && %t
-#include <stdlib.h>
-#ifndef __APPLE__
-#include <malloc.h>
-#endif // __APPLE__
-int *p = (int*)valloc(1 << 20);
-int main() { }
diff --git a/lib/asan/lit_tests/TestCases/atexit_stats.cc b/lib/asan/lit_tests/TestCases/atexit_stats.cc
deleted file mode 100644
index e3b1269d25cc..000000000000
--- a/lib/asan/lit_tests/TestCases/atexit_stats.cc
+++ /dev/null
@@ -1,13 +0,0 @@
-// Make sure we report atexit stats.
-// RUN: %clangxx_asan -O3 %s -o %t
-// RUN: ASAN_OPTIONS=atexit=1:print_stats=1 %t 2>&1 | FileCheck %s
-#include <stdlib.h>
-#if !defined(__APPLE__)
-#include <malloc.h>
-#endif
-int *p1 = (int*)malloc(900);
-int *p2 = (int*)malloc(90000);
-int *p3 = (int*)malloc(9000000);
-int main() { }
-
-// CHECK: AddressSanitizer exit stats:
diff --git a/lib/asan/lit_tests/TestCases/blacklist.cc b/lib/asan/lit_tests/TestCases/blacklist.cc
deleted file mode 100644
index 46625ee7bdb5..000000000000
--- a/lib/asan/lit_tests/TestCases/blacklist.cc
+++ /dev/null
@@ -1,38 +0,0 @@
-// Test the blacklist functionality of ASan
-
-// RUN: echo "fun:*brokenFunction*" > %tmp
-// RUN: echo "global:*badGlobal*" >> %tmp
-// RUN: echo "src:*blacklist-extra.cc" >> %tmp
-// RUN: %clangxx_asan -fsanitize-blacklist=%tmp -O0 %s -o %t \
-// RUN: %p/Helpers/blacklist-extra.cc && %t 2>&1
-// RUN: %clangxx_asan -fsanitize-blacklist=%tmp -O1 %s -o %t \
-// RUN: %p/Helpers/blacklist-extra.cc && %t 2>&1
-// RUN: %clangxx_asan -fsanitize-blacklist=%tmp -O2 %s -o %t \
-// RUN: %p/Helpers/blacklist-extra.cc && %t 2>&1
-// RUN: %clangxx_asan -fsanitize-blacklist=%tmp -O3 %s -o %t \
-// RUN: %p/Helpers/blacklist-extra.cc && %t 2>&1
-
-// badGlobal is accessed improperly, but we blacklisted it. Align
-// it to make sure memory past the end of badGlobal will be in
-// the same page.
-__attribute__((aligned(16))) int badGlobal;
-int readBadGlobal() {
- return (&badGlobal)[1];
-}
-
-// A function which is broken, but excluded in the blacklist.
-int brokenFunction(int argc) {
- char x[10] = {0};
- return x[argc * 10]; // BOOM
-}
-
-// This function is defined in Helpers/blacklist-extra.cc, a source file which
-// is blacklisted by name
-int externalBrokenFunction(int x);
-
-int main(int argc, char **argv) {
- brokenFunction(argc);
- int x = readBadGlobal();
- externalBrokenFunction(argc);
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/contiguous_container.cc b/lib/asan/lit_tests/TestCases/contiguous_container.cc
deleted file mode 100644
index aa97592c7bb9..000000000000
--- a/lib/asan/lit_tests/TestCases/contiguous_container.cc
+++ /dev/null
@@ -1,47 +0,0 @@
-// RUN: %clangxx_asan -O %s -o %t && %t
-//
-// Test __sanitizer_annotate_contiguous_container.
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <assert.h>
-
-extern "C" {
-void __sanitizer_annotate_contiguous_container(void *beg, void *end,
- void *old_mid, void *new_mid);
-bool __asan_address_is_poisoned(void *addr);
-} // extern "C"
-
-void TestContainer(size_t capacity) {
- char *beg = new char[capacity];
- char *end = beg + capacity;
- char *mid = beg + capacity;
- char *old_mid = 0;
- unsigned seed = 0;
-
- for (int i = 0; i < 10000; i++) {
- size_t size = rand_r(&seed) % (capacity + 1);
- assert(size <= capacity);
- old_mid = mid;
- mid = beg + size;
- __sanitizer_annotate_contiguous_container(beg, end, old_mid, mid);
-
- for (size_t idx = 0; idx < size; idx++)
- assert(!__asan_address_is_poisoned(beg + idx));
- for (size_t idx = size; idx < capacity; idx++)
- assert(__asan_address_is_poisoned(beg + idx));
- }
-
- // Don't forget to unpoison the whole thing before destroing/reallocating.
- __sanitizer_annotate_contiguous_container(beg, end, mid, end);
- for (size_t idx = 0; idx < capacity; idx++)
- assert(!__asan_address_is_poisoned(beg + idx));
- delete[] beg;
-}
-
-int main(int argc, char **argv) {
- int n = argc == 1 ? 128 : atoi(argv[1]);
- for (int i = 0; i <= n; i++)
- TestContainer(i);
-}
diff --git a/lib/asan/lit_tests/TestCases/current_allocated_bytes.cc b/lib/asan/lit_tests/TestCases/current_allocated_bytes.cc
deleted file mode 100644
index 669cf150bdfb..000000000000
--- a/lib/asan/lit_tests/TestCases/current_allocated_bytes.cc
+++ /dev/null
@@ -1,43 +0,0 @@
-// RUN: %clangxx_asan -O0 %s -o %t && %t
-// RUN: %clangxx_asan -O2 %s -o %t && %t
-
-#include <assert.h>
-#include <pthread.h>
-#include <sanitizer/asan_interface.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-const size_t kLargeAlloc = 1UL << 20;
-
-void* allocate(void *arg) {
- volatile void *ptr = malloc(kLargeAlloc);
- free((void*)ptr);
- return 0;
-}
-
-void* check_stats(void *arg) {
- assert(__asan_get_current_allocated_bytes() > 0);
- return 0;
-}
-
-int main() {
- size_t used_mem = __asan_get_current_allocated_bytes();
- printf("Before: %zu\n", used_mem);
- const int kNumIterations = 1000;
- for (int iter = 0; iter < kNumIterations; iter++) {
- pthread_t thr[4];
- for (int j = 0; j < 4; j++) {
- assert(0 ==
- pthread_create(&thr[j], 0, (j < 2) ? allocate : check_stats, 0));
- }
- for (int j = 0; j < 4; j++)
- assert(0 == pthread_join(thr[j], 0));
- used_mem = __asan_get_current_allocated_bytes();
- if (used_mem > kLargeAlloc) {
- printf("After iteration %d: %zu\n", iter, used_mem);
- return 1;
- }
- }
- printf("Success after %d iterations\n", kNumIterations);
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/deep_call_stack.cc b/lib/asan/lit_tests/TestCases/deep_call_stack.cc
deleted file mode 100644
index e24704b9019e..000000000000
--- a/lib/asan/lit_tests/TestCases/deep_call_stack.cc
+++ /dev/null
@@ -1,25 +0,0 @@
-// Check that UAR mode can handle very deep recusrion.
-// export ASAN_OPTIONS=detect_stack_use_after_return=1
-// RUN: %clangxx_asan -O2 %s -o %t && \
-// RUN: %t 2>&1 | FileCheck %s
-// Also check that use_sigaltstack+verbosity doesn't crash.
-// RUN: ASAN_OPTIONS=verbosity=1:use_sigaltstack=1 %t | FileCheck %s
-#include <stdio.h>
-
-__attribute__((noinline))
-void RecursiveFunc(int depth, int *ptr) {
- if ((depth % 1000) == 0)
- printf("[%05d] ptr: %p\n", depth, ptr);
- if (depth == 0)
- return;
- int local;
- RecursiveFunc(depth - 1, &local);
-}
-
-int main(int argc, char **argv) {
- RecursiveFunc(40000, 0);
- return 0;
-}
-// CHECK: [40000] ptr:
-// CHECK: [20000] ptr:
-// CHECK: [00000] ptr
diff --git a/lib/asan/lit_tests/TestCases/deep_stack_uaf.cc b/lib/asan/lit_tests/TestCases/deep_stack_uaf.cc
deleted file mode 100644
index 920411c4ac52..000000000000
--- a/lib/asan/lit_tests/TestCases/deep_stack_uaf.cc
+++ /dev/null
@@ -1,31 +0,0 @@
-// Check that we can store lots of stack frames if asked to.
-
-// RUN: %clangxx_asan -O0 %s -o %t 2>&1
-// RUN: ASAN_OPTIONS=malloc_context_size=120:redzone=512 not %t 2>&1 | FileCheck %s
-#include <stdlib.h>
-#include <stdio.h>
-
-template <int depth>
-struct DeepFree {
- static void free(char *x) {
- DeepFree<depth - 1>::free(x);
- }
-};
-
-template<>
-struct DeepFree<0> {
- static void free(char *x) {
- ::free(x);
- }
-};
-
-int main() {
- char *x = (char*)malloc(10);
- // deep_free(x);
- DeepFree<200>::free(x);
- return x[5];
- // CHECK: {{.*ERROR: AddressSanitizer: heap-use-after-free on address}}
- // CHECK: DeepFree<36>
- // CHECK: DeepFree<98>
- // CHECK: DeepFree<115>
-}
diff --git a/lib/asan/lit_tests/TestCases/deep_tail_call.cc b/lib/asan/lit_tests/TestCases/deep_tail_call.cc
deleted file mode 100644
index 2e7aa8e0208f..000000000000
--- a/lib/asan/lit_tests/TestCases/deep_tail_call.cc
+++ /dev/null
@@ -1,20 +0,0 @@
-// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>&1 | FileCheck %s
-
-// CHECK: AddressSanitizer: global-buffer-overflow
-int global[10];
-// CHECK: {{#0.*call4}}
-void __attribute__((noinline)) call4(int i) { global[i+10]++; }
-// CHECK: {{#1.*call3}}
-void __attribute__((noinline)) call3(int i) { call4(i); }
-// CHECK: {{#2.*call2}}
-void __attribute__((noinline)) call2(int i) { call3(i); }
-// CHECK: {{#3.*call1}}
-void __attribute__((noinline)) call1(int i) { call2(i); }
-// CHECK: {{#4.*main}}
-int main(int argc, char **argv) {
- call1(argc);
- return global[0];
-}
diff --git a/lib/asan/lit_tests/TestCases/deep_thread_stack.cc b/lib/asan/lit_tests/TestCases/deep_thread_stack.cc
deleted file mode 100644
index 92e0d66c82eb..000000000000
--- a/lib/asan/lit_tests/TestCases/deep_thread_stack.cc
+++ /dev/null
@@ -1,57 +0,0 @@
-// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>&1 | FileCheck %s
-
-#include <pthread.h>
-
-int *x;
-
-void *AllocThread(void *arg) {
- x = new int;
- *x = 42;
- return NULL;
-}
-
-void *FreeThread(void *arg) {
- delete x;
- return NULL;
-}
-
-void *AccessThread(void *arg) {
- *x = 43; // BOOM
- return NULL;
-}
-
-typedef void* (*callback_type)(void* arg);
-
-void *RunnerThread(void *function) {
- pthread_t thread;
- pthread_create(&thread, NULL, (callback_type)function, NULL);
- pthread_join(thread, NULL);
- return NULL;
-}
-
-void RunThread(callback_type function) {
- pthread_t runner;
- pthread_create(&runner, NULL, RunnerThread, (void*)function);
- pthread_join(runner, NULL);
-}
-
-int main(int argc, char *argv[]) {
- RunThread(AllocThread);
- RunThread(FreeThread);
- RunThread(AccessThread);
- return (x != 0);
-}
-
-// CHECK: AddressSanitizer: heap-use-after-free
-// CHECK: WRITE of size 4 at 0x{{.*}} thread T[[ACCESS_THREAD:[0-9]+]]
-// CHECK: freed by thread T[[FREE_THREAD:[0-9]+]] here:
-// CHECK: previously allocated by thread T[[ALLOC_THREAD:[0-9]+]] here:
-// CHECK: Thread T[[ACCESS_THREAD]] created by T[[ACCESS_RUNNER:[0-9]+]] here:
-// CHECK: Thread T[[ACCESS_RUNNER]] created by T0 here:
-// CHECK: Thread T[[FREE_THREAD]] created by T[[FREE_RUNNER:[0-9]+]] here:
-// CHECK: Thread T[[FREE_RUNNER]] created by T0 here:
-// CHECK: Thread T[[ALLOC_THREAD]] created by T[[ALLOC_RUNNER:[0-9]+]] here:
-// CHECK: Thread T[[ALLOC_RUNNER]] created by T0 here:
diff --git a/lib/asan/lit_tests/TestCases/default_blacklist.cc b/lib/asan/lit_tests/TestCases/default_blacklist.cc
deleted file mode 100644
index 25a1ae1752b0..000000000000
--- a/lib/asan/lit_tests/TestCases/default_blacklist.cc
+++ /dev/null
@@ -1,3 +0,0 @@
-// Test that ASan uses the default blacklist from resource directory.
-// RUN: %clangxx_asan -### %s 2>&1 | FileCheck %s
-// CHECK: fsanitize-blacklist={{.*}}asan_blacklist.txt
diff --git a/lib/asan/lit_tests/TestCases/default_options.cc b/lib/asan/lit_tests/TestCases/default_options.cc
deleted file mode 100644
index 84b80557b852..000000000000
--- a/lib/asan/lit_tests/TestCases/default_options.cc
+++ /dev/null
@@ -1,15 +0,0 @@
-// RUN: %clangxx_asan -O2 %s -o %t
-// RUN: %t 2>&1 | FileCheck %s
-
-const char *kAsanDefaultOptions="verbosity=1 foo=bar";
-
-extern "C"
-__attribute__((no_sanitize_address))
-const char *__asan_default_options() {
- // CHECK: Using the defaults from __asan_default_options: {{.*}} foo=bar
- return kAsanDefaultOptions;
-}
-
-int main() {
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/dlclose-test.cc b/lib/asan/lit_tests/TestCases/dlclose-test.cc
deleted file mode 100644
index 03ed16016116..000000000000
--- a/lib/asan/lit_tests/TestCases/dlclose-test.cc
+++ /dev/null
@@ -1,81 +0,0 @@
-// Regression test for
-// http://code.google.com/p/address-sanitizer/issues/detail?id=19
-// Bug description:
-// 1. application dlopens foo.so
-// 2. asan registers all globals from foo.so
-// 3. application dlcloses foo.so
-// 4. application mmaps some memory to the location where foo.so was before
-// 5. application starts using this mmaped memory, but asan still thinks there
-// are globals.
-// 6. BOOM
-
-// This sublte test assumes that after a foo.so is dlclose-d
-// we can mmap the region of memory that has been occupied by the library.
-// It works on i368/x86_64 Linux, but not necessary anywhere else.
-// REQUIRES: x86_64-supported-target,i386-supported-target
-
-// RUN: %clangxx_asan -O0 %p/SharedLibs/dlclose-test-so.cc \
-// RUN: -fPIC -shared -o %t-so.so
-// RUN: %clangxx_asan -O0 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O1 %p/SharedLibs/dlclose-test-so.cc \
-// RUN: -fPIC -shared -o %t-so.so
-// RUN: %clangxx_asan -O1 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O2 %p/SharedLibs/dlclose-test-so.cc \
-// RUN: -fPIC -shared -o %t-so.so
-// RUN: %clangxx_asan -O2 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O3 %p/SharedLibs/dlclose-test-so.cc \
-// RUN: -fPIC -shared -o %t-so.so
-// RUN: %clangxx_asan -O3 %s -o %t && %t 2>&1 | FileCheck %s
-
-#include <assert.h>
-#include <dlfcn.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/mman.h>
-#include <unistd.h>
-
-#include <string>
-
-using std::string;
-
-typedef int *(fun_t)();
-
-int main(int argc, char *argv[]) {
- string path = string(argv[0]) + "-so.so";
- size_t PageSize = sysconf(_SC_PAGESIZE);
- printf("opening %s ... \n", path.c_str());
- void *lib = dlopen(path.c_str(), RTLD_NOW);
- if (!lib) {
- printf("error in dlopen(): %s\n", dlerror());
- return 1;
- }
- fun_t *get = (fun_t*)dlsym(lib, "get_address_of_static_var");
- if (!get) {
- printf("failed dlsym\n");
- return 1;
- }
- int *addr = get();
- assert(((size_t)addr % 32) == 0); // should be 32-byte aligned.
- printf("addr: %p\n", addr);
- addr[0] = 1; // make sure we can write there.
-
- // Now dlclose the shared library.
- printf("attempting to dlclose\n");
- if (dlclose(lib)) {
- printf("failed to dlclose\n");
- return 1;
- }
- // Now, the page where 'addr' is unmapped. Map it.
- size_t page_beg = ((size_t)addr) & ~(PageSize - 1);
- void *res = mmap((void*)(page_beg), PageSize,
- PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE, 0, 0);
- if (res == (char*)-1L) {
- printf("failed to mmap\n");
- return 1;
- }
- addr[1] = 2; // BOOM (if the bug is not fixed).
- printf("PASS\n");
- // CHECK: PASS
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/double-free.cc b/lib/asan/lit_tests/TestCases/double-free.cc
deleted file mode 100644
index 6bfd4fa2c7e5..000000000000
--- a/lib/asan/lit_tests/TestCases/double-free.cc
+++ /dev/null
@@ -1,25 +0,0 @@
-// RUN: %clangxx_asan -O0 %s -o %t 2>&1
-// RUN: not %t 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=MALLOC-CTX
-
-// Also works if no malloc context is available.
-// RUN: ASAN_OPTIONS=malloc_context_size=0:fast_unwind_on_malloc=0 not %t 2>&1 | FileCheck %s
-// RUN: ASAN_OPTIONS=malloc_context_size=0:fast_unwind_on_malloc=1 not %t 2>&1 | FileCheck %s
-
-#include <stdlib.h>
-#include <string.h>
-int main(int argc, char **argv) {
- char *x = (char*)malloc(10 * sizeof(char));
- memset(x, 0, 10);
- int res = x[argc];
- free(x);
- free(x + argc - 1); // BOOM
- // CHECK: AddressSanitizer: attempting double-free{{.*}}in thread T0
- // CHECK: #0 0x{{.*}} in {{.*}}free
- // CHECK: #1 0x{{.*}} in main {{.*}}double-free.cc:[[@LINE-3]]
- // CHECK: freed by thread T0 here:
- // MALLOC-CTX: #0 0x{{.*}} in {{.*}}free
- // MALLOC-CTX: #1 0x{{.*}} in main {{.*}}double-free.cc:[[@LINE-7]]
- // CHECK: allocated by thread T0 here:
- // MALLOC-CTX: double-free.cc:[[@LINE-12]]
- return res;
-}
diff --git a/lib/asan/lit_tests/TestCases/force_inline_opt0.cc b/lib/asan/lit_tests/TestCases/force_inline_opt0.cc
deleted file mode 100644
index 775a66dfe2fe..000000000000
--- a/lib/asan/lit_tests/TestCases/force_inline_opt0.cc
+++ /dev/null
@@ -1,14 +0,0 @@
-// This test checks that we are no instrumenting a memory access twice
-// (before and after inlining)
-// RUN: %clangxx_asan -O1 %s -o %t && %t
-// RUN: %clangxx_asan -O0 %s -o %t && %t
-__attribute__((always_inline))
-void foo(int *x) {
- *x = 0;
-}
-
-int main() {
- int x;
- foo(&x);
- return x;
-}
diff --git a/lib/asan/lit_tests/TestCases/free_hook_realloc.cc b/lib/asan/lit_tests/TestCases/free_hook_realloc.cc
deleted file mode 100644
index 7a71964b0032..000000000000
--- a/lib/asan/lit_tests/TestCases/free_hook_realloc.cc
+++ /dev/null
@@ -1,32 +0,0 @@
-// Check that free hook doesn't conflict with Realloc.
-// RUN: %clangxx_asan -O2 %s -o %t
-// RUN: %t 2>&1 | FileCheck %s
-#include <stdlib.h>
-#include <unistd.h>
-
-static void *glob_ptr;
-
-extern "C" {
-void __asan_free_hook(void *ptr) {
- if (ptr == glob_ptr) {
- *(int*)ptr = 0;
- write(1, "FreeHook\n", sizeof("FreeHook\n"));
- }
-}
-}
-
-int main() {
- int *x = (int*)malloc(100);
- x[0] = 42;
- glob_ptr = x;
- int *y = (int*)realloc(x, 200);
- // Verify that free hook was called and didn't spoil the memory.
- if (y[0] != 42) {
- _exit(1);
- }
- write(1, "Passed\n", sizeof("Passed\n"));
- free(y);
- // CHECK: FreeHook
- // CHECK: Passed
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/global-demangle.cc b/lib/asan/lit_tests/TestCases/global-demangle.cc
deleted file mode 100644
index d050b70f0fca..000000000000
--- a/lib/asan/lit_tests/TestCases/global-demangle.cc
+++ /dev/null
@@ -1,17 +0,0 @@
-// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s
-
-namespace XXX {
-class YYY {
- public:
- static char ZZZ[];
-};
-char YYY::ZZZ[] = "abc";
-}
-
-int main(int argc, char **argv) {
- return (int)XXX::YYY::ZZZ[argc + 5]; // BOOM
- // CHECK: {{READ of size 1 at 0x.*}}
- // CHECK: {{0x.* is located 2 bytes to the right of global variable}}
- // CHECK: 'XXX::YYY::ZZZ' {{.*}} of size 4
- // CHECK: 'XXX::YYY::ZZZ' is ascii string 'abc'
-}
diff --git a/lib/asan/lit_tests/TestCases/global-overflow.cc b/lib/asan/lit_tests/TestCases/global-overflow.cc
deleted file mode 100644
index 0f080f55f2f1..000000000000
--- a/lib/asan/lit_tests/TestCases/global-overflow.cc
+++ /dev/null
@@ -1,21 +0,0 @@
-// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>&1 | FileCheck %s
-
-#include <string.h>
-int main(int argc, char **argv) {
- static char XXX[10];
- static char YYY[10];
- static char ZZZ[10];
- memset(XXX, 0, 10);
- memset(YYY, 0, 10);
- memset(ZZZ, 0, 10);
- int res = YYY[argc * 10]; // BOOOM
- // CHECK: {{READ of size 1 at 0x.* thread T0}}
- // CHECK: {{ #0 0x.* in main .*global-overflow.cc:}}[[@LINE-2]]
- // CHECK: {{0x.* is located 0 bytes to the right of global variable}}
- // CHECK: {{.*YYY.* of size 10}}
- res += XXX[argc] + ZZZ[argc];
- return res;
-}
diff --git a/lib/asan/lit_tests/TestCases/heap-overflow.cc b/lib/asan/lit_tests/TestCases/heap-overflow.cc
deleted file mode 100644
index 2c943a36014f..000000000000
--- a/lib/asan/lit_tests/TestCases/heap-overflow.cc
+++ /dev/null
@@ -1,24 +0,0 @@
-// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
-// RUN: %clangxx_asan -O1 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
-// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
-// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
-
-#include <stdlib.h>
-#include <string.h>
-int main(int argc, char **argv) {
- char *x = (char*)malloc(10 * sizeof(char));
- memset(x, 0, 10);
- int res = x[argc * 10]; // BOOOM
- // CHECK: {{READ of size 1 at 0x.* thread T0}}
- // CHECK: {{ #0 0x.* in main .*heap-overflow.cc:}}[[@LINE-2]]
- // CHECK: {{0x.* is located 0 bytes to the right of 10-byte region}}
- // CHECK: {{allocated by thread T0 here:}}
-
- // CHECK-Linux: {{ #0 0x.* in .*malloc}}
- // CHECK-Linux: {{ #1 0x.* in main .*heap-overflow.cc:9}}
-
- // CHECK-Darwin: {{ #0 0x.* in wrap_malloc.*}}
- // CHECK-Darwin: {{ #1 0x.* in main .*heap-overflow.cc:9}}
- free(x);
- return res;
-}
diff --git a/lib/asan/lit_tests/TestCases/huge_negative_hea_oob.cc b/lib/asan/lit_tests/TestCases/huge_negative_hea_oob.cc
deleted file mode 100644
index 58a44c5fb68e..000000000000
--- a/lib/asan/lit_tests/TestCases/huge_negative_hea_oob.cc
+++ /dev/null
@@ -1,13 +0,0 @@
-// RUN: %clangxx_asan %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O %s -o %t && not %t 2>&1 | FileCheck %s
-// Check that we can find huge buffer overflows to the left.
-#include <stdlib.h>
-#include <string.h>
-int main(int argc, char **argv) {
- char *x = (char*)malloc(1 << 20);
- memset(x, 0, 10);
- int res = x[-argc * 4000]; // BOOOM
- // CHECK: is located 4000 bytes to the left of
- free(x);
- return res;
-}
diff --git a/lib/asan/lit_tests/TestCases/init-order-atexit.cc b/lib/asan/lit_tests/TestCases/init-order-atexit.cc
deleted file mode 100644
index e38cdd273d58..000000000000
--- a/lib/asan/lit_tests/TestCases/init-order-atexit.cc
+++ /dev/null
@@ -1,31 +0,0 @@
-// Test for the following situation:
-// (1) global A is constructed.
-// (2) exit() is called during construction of global B.
-// (3) destructor of A reads uninitialized global C from another module.
-// We do *not* want to report init-order bug in this case.
-
-// RUN: %clangxx_asan -O0 %s %p/Helpers/init-order-atexit-extra.cc -o %t
-// RUN: ASAN_OPTIONS=strict_init_order=true not %t 2>&1 | FileCheck %s
-
-#include <stdio.h>
-#include <stdlib.h>
-
-void AccessC();
-
-class A {
- public:
- A() { }
- ~A() { AccessC(); printf("PASSED\n"); }
- // CHECK-NOT: AddressSanitizer
- // CHECK: PASSED
-};
-
-A a;
-
-class B {
- public:
- B() { exit(1); }
- ~B() { }
-};
-
-B b;
diff --git a/lib/asan/lit_tests/TestCases/init-order-dlopen.cc b/lib/asan/lit_tests/TestCases/init-order-dlopen.cc
deleted file mode 100644
index d30d11999246..000000000000
--- a/lib/asan/lit_tests/TestCases/init-order-dlopen.cc
+++ /dev/null
@@ -1,57 +0,0 @@
-// Regression test for
-// https://code.google.com/p/address-sanitizer/issues/detail?id=178
-
-// Assume we're on Darwin and try to pass -U to the linker. If this flag is
-// unsupported, don't use it.
-// RUN: %clangxx_asan -O0 %p/SharedLibs/init-order-dlopen-so.cc \
-// RUN: -fPIC -shared -o %t-so.so -Wl,-U,_inc_global || \
-// RUN: %clangxx_asan -O0 %p/SharedLibs/init-order-dlopen-so.cc \
-// RUN: -fPIC -shared -o %t-so.so
-// If the linker doesn't support --export-dynamic (which is ELF-specific),
-// try to link without that option.
-// FIXME: find a better solution.
-// RUN: %clangxx_asan -O0 %s -o %t -Wl,--export-dynamic || \
-// RUN: %clangxx_asan -O0 %s -o %t
-// RUN: ASAN_OPTIONS=strict_init_order=true %t 2>&1 | FileCheck %s
-#include <dlfcn.h>
-#include <pthread.h>
-#include <stdio.h>
-#include <unistd.h>
-
-#include <string>
-
-using std::string;
-
-int foo() {
- return 42;
-}
-int global = foo();
-
-__attribute__((visibility("default")))
-extern "C"
-void inc_global() {
- global++;
-}
-
-void *global_poller(void *arg) {
- while (true) {
- if (global != 42)
- break;
- usleep(100);
- }
- return 0;
-}
-
-int main(int argc, char *argv[]) {
- pthread_t p;
- pthread_create(&p, 0, global_poller, 0);
- string path = string(argv[0]) + "-so.so";
- if (0 == dlopen(path.c_str(), RTLD_NOW)) {
- fprintf(stderr, "dlerror: %s\n", dlerror());
- return 1;
- }
- pthread_join(p, 0);
- printf("PASSED\n");
- // CHECK: PASSED
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/init-order-pthread-create.cc b/lib/asan/lit_tests/TestCases/init-order-pthread-create.cc
deleted file mode 100644
index 52031216d5bb..000000000000
--- a/lib/asan/lit_tests/TestCases/init-order-pthread-create.cc
+++ /dev/null
@@ -1,32 +0,0 @@
-// Check that init-order checking is properly disabled if pthread_create is
-// called.
-
-// RUN: %clangxx_asan %s %p/Helpers/init-order-pthread-create-extra.cc -o %t
-// RUN: ASAN_OPTIONS=strict_init_order=true %t
-
-#include <stdio.h>
-#include <pthread.h>
-
-void *run(void *arg) {
- return arg;
-}
-
-void *foo(void *input) {
- pthread_t t;
- pthread_create(&t, 0, run, input);
- void *res;
- pthread_join(t, &res);
- return res;
-}
-
-void *bar(void *input) {
- return input;
-}
-
-void *glob = foo((void*)0x1234);
-extern void *glob2;
-
-int main() {
- printf("%p %p\n", glob, glob2);
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/initialization-blacklist.cc b/lib/asan/lit_tests/TestCases/initialization-blacklist.cc
deleted file mode 100644
index f40fcc082f9a..000000000000
--- a/lib/asan/lit_tests/TestCases/initialization-blacklist.cc
+++ /dev/null
@@ -1,32 +0,0 @@
-// Test for blacklist functionality of initialization-order checker.
-
-// RUN: %clangxx_asan -O0 %s %p/Helpers/initialization-blacklist-extra.cc\
-// RUN: %p/Helpers/initialization-blacklist-extra2.cc \
-// RUN: -fsanitize-blacklist=%p/Helpers/initialization-blacklist.txt \
-// RUN: -fsanitize=init-order -o %t
-// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1
-// RUN: %clangxx_asan -O1 %s %p/Helpers/initialization-blacklist-extra.cc\
-// RUN: %p/Helpers/initialization-blacklist-extra2.cc \
-// RUN: -fsanitize-blacklist=%p/Helpers/initialization-blacklist.txt \
-// RUN: -fsanitize=init-order -o %t
-// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1
-// RUN: %clangxx_asan -O2 %s %p/Helpers/initialization-blacklist-extra.cc\
-// RUN: %p/Helpers/initialization-blacklist-extra2.cc \
-// RUN: -fsanitize-blacklist=%p/Helpers/initialization-blacklist.txt \
-// RUN: -fsanitize=init-order -o %t
-// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1
-
-// Function is defined in another TU.
-int readBadGlobal();
-int x = readBadGlobal(); // init-order bug.
-
-// Function is defined in another TU.
-int accessBadObject();
-int y = accessBadObject(); // init-order bug.
-
-int readBadSrcGlobal();
-int z = readBadSrcGlobal(); // init-order bug.
-
-int main(int argc, char **argv) {
- return argc + x + y + z - 1;
-}
diff --git a/lib/asan/lit_tests/TestCases/initialization-bug.cc b/lib/asan/lit_tests/TestCases/initialization-bug.cc
deleted file mode 100644
index fb289b1c7ebe..000000000000
--- a/lib/asan/lit_tests/TestCases/initialization-bug.cc
+++ /dev/null
@@ -1,45 +0,0 @@
-// Test to make sure basic initialization order errors are caught.
-
-// RUN: %clangxx_asan -O0 %s %p/Helpers/initialization-bug-extra2.cc -o %t
-// RUN: ASAN_OPTIONS=check_initialization_order=true not %t 2>&1 | FileCheck %s
-
-// Do not test with optimization -- the error may be optimized away.
-
-// FIXME: https://code.google.com/p/address-sanitizer/issues/detail?id=186
-// XFAIL: darwin
-
-#include <cstdio>
-
-// The structure of the test is:
-// "x", "y", "z" are dynamically initialized globals.
-// Value of "x" depends on "y", value of "y" depends on "z".
-// "x" and "z" are defined in this TU, "y" is defined in another one.
-// Thus we shoud stably report initialization order fiasco independently of
-// the translation unit order.
-
-int initZ() {
- return 5;
-}
-int z = initZ();
-
-// 'y' is a dynamically initialized global residing in a different TU. This
-// dynamic initializer will read the value of 'y' before main starts. The
-// result is undefined behavior, which should be caught by initialization order
-// checking.
-extern int y;
-int __attribute__((noinline)) initX() {
- return y + 1;
- // CHECK: {{AddressSanitizer: initialization-order-fiasco}}
- // CHECK: {{READ of size .* at 0x.* thread T0}}
- // CHECK: {{0x.* is located 0 bytes inside of global variable .*(y|z).*}}
-}
-
-// This initializer begins our initialization order problems.
-static int x = initX();
-
-int main() {
- // ASan should have caused an exit before main runs.
- printf("PASS\n");
- // CHECK-NOT: PASS
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/initialization-constexpr.cc b/lib/asan/lit_tests/TestCases/initialization-constexpr.cc
deleted file mode 100644
index 65c95edd5081..000000000000
--- a/lib/asan/lit_tests/TestCases/initialization-constexpr.cc
+++ /dev/null
@@ -1,31 +0,0 @@
-// Constexpr:
-// We need to check that a global variable initialized with a constexpr
-// constructor can be accessed during dynamic initialization (as a constexpr
-// constructor implies that it was initialized during constant initialization,
-// not dynamic initialization).
-
-// RUN: %clangxx_asan -O0 %s %p/Helpers/initialization-constexpr-extra.cc\
-// RUN: --std=c++11 -fsanitize=init-order -o %t
-// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1
-// RUN: %clangxx_asan -O1 %s %p/Helpers/initialization-constexpr-extra.cc\
-// RUN: --std=c++11 -fsanitize=init-order -o %t
-// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1
-// RUN: %clangxx_asan -O2 %s %p/Helpers/initialization-constexpr-extra.cc\
-// RUN: --std=c++11 -fsanitize=init-order -o %t
-// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1
-// RUN: %clangxx_asan -O3 %s %p/Helpers/initialization-constexpr-extra.cc\
-// RUN: --std=c++11 -fsanitize=init-order -o %t
-// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1
-
-class Integer {
- private:
- int value;
-
- public:
- constexpr Integer(int x = 0) : value(x) {}
- int getValue() {return value;}
-};
-Integer coolestInteger(42);
-int getCoolestInteger() { return coolestInteger.getValue(); }
-
-int main() { return 0; }
diff --git a/lib/asan/lit_tests/TestCases/initialization-nobug.cc b/lib/asan/lit_tests/TestCases/initialization-nobug.cc
deleted file mode 100644
index ed37d137f8cb..000000000000
--- a/lib/asan/lit_tests/TestCases/initialization-nobug.cc
+++ /dev/null
@@ -1,48 +0,0 @@
-// A collection of various initializers which shouldn't trip up initialization
-// order checking. If successful, this will just return 0.
-
-// RUN: %clangxx_asan -O0 %s %p/Helpers/initialization-nobug-extra.cc -fsanitize=init-order -o %t
-// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1
-// RUN: %clangxx_asan -O1 %s %p/Helpers/initialization-nobug-extra.cc -fsanitize=init-order -o %t
-// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1
-// RUN: %clangxx_asan -O2 %s %p/Helpers/initialization-nobug-extra.cc -fsanitize=init-order -o %t
-// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1
-// RUN: %clangxx_asan -O3 %s %p/Helpers/initialization-nobug-extra.cc -fsanitize=init-order -o %t
-// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1
-
-// Simple access:
-// Make sure that accessing a global in the same TU is safe
-
-bool condition = true;
-int initializeSameTU() {
- return condition ? 0x2a : 052;
-}
-int sameTU = initializeSameTU();
-
-// Linker initialized:
-// Check that access to linker initialized globals originating from a different
-// TU's initializer is safe.
-
-int A = (1 << 1) + (1 << 3) + (1 << 5), B;
-int getAB() {
- return A * B;
-}
-
-// Function local statics:
-// Check that access to function local statics originating from a different
-// TU's initializer is safe.
-
-int countCalls() {
- static int calls;
- return ++calls;
-}
-
-// Trivial constructor, non-trivial destructor.
-struct StructWithDtor {
- ~StructWithDtor() { }
- int value;
-};
-StructWithDtor struct_with_dtor;
-int getStructWithDtorValue() { return struct_with_dtor.value; }
-
-int main() { return 0; }
diff --git a/lib/asan/lit_tests/TestCases/inline.cc b/lib/asan/lit_tests/TestCases/inline.cc
deleted file mode 100644
index 792aff59f4ba..000000000000
--- a/lib/asan/lit_tests/TestCases/inline.cc
+++ /dev/null
@@ -1,19 +0,0 @@
-// RUN: %clangxx_asan -O3 %s -o %t && %t
-
-// Test that no_sanitize_address attribute applies even when the function would
-// be normally inlined.
-
-#include <stdlib.h>
-
-__attribute__((no_sanitize_address))
-int f(int *p) {
- return *p; // BOOOM?? Nope!
-}
-
-int main(int argc, char **argv) {
- int * volatile x = (int*)malloc(2*sizeof(int) + 2);
- int res = f(x + 2);
- if (res)
- exit(0);
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/interface_test.cc b/lib/asan/lit_tests/TestCases/interface_test.cc
deleted file mode 100644
index 297b5526e9d9..000000000000
--- a/lib/asan/lit_tests/TestCases/interface_test.cc
+++ /dev/null
@@ -1,8 +0,0 @@
-// Check that user may include ASan interface header.
-// RUN: %clang_asan %s -o %t && %t
-// RUN: %clang %s -o %t && %t
-#include <sanitizer/asan_interface.h>
-
-int main() {
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/invalid-free.cc b/lib/asan/lit_tests/TestCases/invalid-free.cc
deleted file mode 100644
index f940b501279a..000000000000
--- a/lib/asan/lit_tests/TestCases/invalid-free.cc
+++ /dev/null
@@ -1,21 +0,0 @@
-// RUN: %clangxx_asan -O0 %s -o %t
-// RUN: not %t 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=MALLOC-CTX
-
-// Also works if no malloc context is available.
-// RUN: ASAN_OPTIONS=malloc_context_size=0:fast_unwind_on_malloc=0 not %t 2>&1 | FileCheck %s
-// RUN: ASAN_OPTIONS=malloc_context_size=0:fast_unwind_on_malloc=1 not %t 2>&1 | FileCheck %s
-
-#include <stdlib.h>
-#include <string.h>
-int main(int argc, char **argv) {
- char *x = (char*)malloc(10 * sizeof(char));
- memset(x, 0, 10);
- int res = x[argc];
- free(x + 5); // BOOM
- // CHECK: AddressSanitizer: attempting free on address{{.*}}in thread T0
- // CHECK: invalid-free.cc:[[@LINE-2]]
- // CHECK: is located 5 bytes inside of 10-byte region
- // CHECK: allocated by thread T0 here:
- // MALLOC-CTX: invalid-free.cc:[[@LINE-8]]
- return res;
-}
diff --git a/lib/asan/lit_tests/TestCases/ioctl.cc b/lib/asan/lit_tests/TestCases/ioctl.cc
deleted file mode 100644
index 08ca688d3872..000000000000
--- a/lib/asan/lit_tests/TestCases/ioctl.cc
+++ /dev/null
@@ -1,24 +0,0 @@
-// RUN: %clangxx_asan -O0 -g %s -o %t && ASAN_OPTIONS=handle_ioctl=1 not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O3 -g %s -o %t && ASAN_OPTIONS=handle_ioctl=1 not %t 2>&1 | FileCheck %s
-
-// RUN: %clangxx_asan -O0 -g %s -o %t && %t
-// RUN: %clangxx_asan -O3 -g %s -o %t && %t
-
-#include <assert.h>
-#include <stdlib.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-#include <unistd.h>
-
-int main(int argc, char **argv) {
- int fd = socket(AF_INET, SOCK_DGRAM, 0);
-
- int nonblock;
- int res = ioctl(fd, FIONBIO, &nonblock + 1);
- // CHECK: AddressSanitizer: stack-buffer-overflow
- // CHECK: READ of size 4 at
- // CHECK: {{#.* in main .*ioctl.cc:}}[[@LINE-3]]
- assert(res == 0);
- close(fd);
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/large_func_test.cc b/lib/asan/lit_tests/TestCases/large_func_test.cc
deleted file mode 100644
index 0534bcd31142..000000000000
--- a/lib/asan/lit_tests/TestCases/large_func_test.cc
+++ /dev/null
@@ -1,51 +0,0 @@
-// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
-// RUN: %clangxx_asan -O1 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
-// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
-// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
-
-#include <stdlib.h>
-__attribute__((noinline))
-static void LargeFunction(int *x, int zero) {
- x[0]++;
- x[1]++;
- x[2]++;
- x[3]++;
- x[4]++;
- x[5]++;
- x[6]++;
- x[7]++;
- x[8]++;
- x[9]++;
-
- // CHECK: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
- // CHECK: {{0x.* at pc 0x.* bp 0x.* sp 0x.*}}
- // CHECK: {{READ of size 4 at 0x.* thread T0}}
- x[zero + 103]++; // we should report this exact line
- // atos incorrectly extracts the symbol name for the static functions on
- // Darwin.
- // CHECK-Linux: {{#0 0x.* in LargeFunction.*large_func_test.cc:}}[[@LINE-3]]
- // CHECK-Darwin: {{#0 0x.* in .*LargeFunction.*large_func_test.cc}}:[[@LINE-4]]
-
- x[10]++;
- x[11]++;
- x[12]++;
- x[13]++;
- x[14]++;
- x[15]++;
- x[16]++;
- x[17]++;
- x[18]++;
- x[19]++;
-}
-
-int main(int argc, char **argv) {
- int *x = new int[100];
- LargeFunction(x, argc - 1);
- // CHECK: {{ #1 0x.* in main .*large_func_test.cc:}}[[@LINE-1]]
- // CHECK: {{0x.* is located 12 bytes to the right of 400-byte region}}
- // CHECK: {{allocated by thread T0 here:}}
- // CHECK-Linux: {{ #0 0x.* in operator new.*}}
- // CHECK-Darwin: {{ #0 0x.* in .*_Zna.*}}
- // CHECK: {{ #1 0x.* in main .*large_func_test.cc:}}[[@LINE-7]]
- delete x;
-}
diff --git a/lib/asan/lit_tests/TestCases/log-path_test.cc b/lib/asan/lit_tests/TestCases/log-path_test.cc
deleted file mode 100644
index 1072670fbff4..000000000000
--- a/lib/asan/lit_tests/TestCases/log-path_test.cc
+++ /dev/null
@@ -1,39 +0,0 @@
-// RUN: %clangxx_asan %s -o %t
-
-// Regular run.
-// RUN: not %t 2> %t.out
-// RUN: FileCheck %s --check-prefix=CHECK-ERROR < %t.out
-
-// Good log_path.
-// RUN: rm -f %t.log.*
-// RUN: ASAN_OPTIONS=log_path=%t.log not %t 2> %t.out
-// RUN: FileCheck %s --check-prefix=CHECK-ERROR < %t.log.*
-
-// Invalid log_path.
-// RUN: ASAN_OPTIONS=log_path=/INVALID not %t 2> %t.out
-// RUN: FileCheck %s --check-prefix=CHECK-INVALID < %t.out
-
-// Too long log_path.
-// RUN: ASAN_OPTIONS=log_path=`for((i=0;i<10000;i++)); do echo -n $i; done` \
-// RUN: not %t 2> %t.out
-// RUN: FileCheck %s --check-prefix=CHECK-LONG < %t.out
-
-// Run w/o errors should not produce any log.
-// RUN: rm -f %t.log.*
-// RUN: ASAN_OPTIONS=log_path=%t.log %t ARG ARG ARG
-// RUN: not cat %t.log.*
-
-
-#include <stdlib.h>
-#include <string.h>
-int main(int argc, char **argv) {
- if (argc > 2) return 0;
- char *x = (char*)malloc(10);
- memset(x, 0, 10);
- int res = x[argc * 10]; // BOOOM
- free(x);
- return res;
-}
-// CHECK-ERROR: ERROR: AddressSanitizer
-// CHECK-INVALID: ERROR: Can't open file: /INVALID
-// CHECK-LONG: ERROR: Path is too long: 01234
diff --git a/lib/asan/lit_tests/TestCases/log_path_fork_test.cc.disabled b/lib/asan/lit_tests/TestCases/log_path_fork_test.cc.disabled
deleted file mode 100644
index c6c1b49e994d..000000000000
--- a/lib/asan/lit_tests/TestCases/log_path_fork_test.cc.disabled
+++ /dev/null
@@ -1,22 +0,0 @@
-// RUN: %clangxx_asan %s -o %t
-// RUN: rm -f %t.log.*
-// Set verbosity to 1 so that the log files are opened prior to fork().
-// RUN: ASAN_OPTIONS="log_path=%t.log verbosity=1" not %t 2> %t.out
-// RUN: for f in %t.log.* ; do FileCheck %s < $f; done
-// RUN: [ `ls %t.log.* | wc -l` == 2 ]
-
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-int main(int argc, char **argv) {
- void *x = malloc(10);
- free(x);
- if (fork() == -1) return 1;
- // There are two processes at this point, thus there should be two distinct
- // error logs.
- free(x);
- return 0;
-}
-
-// CHECK: ERROR: AddressSanitizer
diff --git a/lib/asan/lit_tests/TestCases/lsan_annotations.cc b/lib/asan/lit_tests/TestCases/lsan_annotations.cc
deleted file mode 100644
index c55ab8692eb5..000000000000
--- a/lib/asan/lit_tests/TestCases/lsan_annotations.cc
+++ /dev/null
@@ -1,16 +0,0 @@
-// Check that LSan annotations work fine.
-// RUN: %clangxx_asan -O0 %s -o %t && %t
-// RUN: %clangxx_asan -O3 %s -o %t && %t
-
-#include <sanitizer/lsan_interface.h>
-#include <stdlib.h>
-
-int main() {
- int *x = new int;
- __lsan_ignore_object(x);
- {
- __lsan::ScopedDisabler disabler;
- double *y = new double;
- }
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/malloc_context_size.cc b/lib/asan/lit_tests/TestCases/malloc_context_size.cc
deleted file mode 100644
index 266ce66f59e2..000000000000
--- a/lib/asan/lit_tests/TestCases/malloc_context_size.cc
+++ /dev/null
@@ -1,27 +0,0 @@
-// RUN: %clangxx_asan -O0 %s -o %t
-// RUN: ASAN_OPTIONS=malloc_context_size=0:fast_unwind_on_malloc=0 not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os
-// RUN: ASAN_OPTIONS=malloc_context_size=0:fast_unwind_on_malloc=1 not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os
-// RUN: ASAN_OPTIONS=malloc_context_size=1:fast_unwind_on_malloc=0 not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os
-// RUN: ASAN_OPTIONS=malloc_context_size=1:fast_unwind_on_malloc=1 not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os
-
-int main() {
- char *x = new char[20];
- delete[] x;
- return x[0];
- // We need to keep duplicate lines with different 'CHECK-%os' prefixes,
- // otherwise FileCheck barks on missing 'CHECK-%os' before 'CHECK-%os-NEXT'.
-
- // CHECK-Linux: freed by thread T{{.*}} here:
- // CHECK-Linux-NEXT: #0 0x{{.*}} in operator delete[]
- // CHECK-Darwin: freed by thread T{{.*}} here:
- // CHECK-Darwin-NEXT: #0 0x{{.*}} in wrap__ZdaPv
- // CHECK-NOT: #1 0x{{.*}}
-
- // CHECK-Linux: previously allocated by thread T{{.*}} here:
- // CHECK-Linux-NEXT: #0 0x{{.*}} in operator new[]
- // CHECK-Darwin: previously allocated by thread T{{.*}} here:
- // CHECK-Darwin-NEXT: #0 0x{{.*}} in wrap__Znam
- // CHECK-NOT: #1 0x{{.*}}
-
- // CHECK: SUMMARY: AddressSanitizer: heap-use-after-free
-}
diff --git a/lib/asan/lit_tests/TestCases/malloc_fill.cc b/lib/asan/lit_tests/TestCases/malloc_fill.cc
deleted file mode 100644
index 57f50d1438b7..000000000000
--- a/lib/asan/lit_tests/TestCases/malloc_fill.cc
+++ /dev/null
@@ -1,22 +0,0 @@
-// Check that we fill malloc-ed memory correctly.
-// RUN: %clangxx_asan %s -o %t
-// RUN: %t | FileCheck %s
-// RUN: ASAN_OPTIONS=max_malloc_fill_size=10:malloc_fill_byte=8 %t | FileCheck %s --check-prefix=CHECK-10-8
-// RUN: ASAN_OPTIONS=max_malloc_fill_size=20:malloc_fill_byte=171 %t | FileCheck %s --check-prefix=CHECK-20-ab
-
-#include <stdio.h>
-int main(int argc, char **argv) {
- // With asan allocator this makes sure we get memory from mmap.
- static const int kSize = 1 << 25;
- unsigned char *x = new unsigned char[kSize];
- printf("-");
- for (int i = 0; i <= 32; i++) {
- printf("%02x", x[i]);
- }
- printf("-\n");
- delete [] x;
-}
-
-// CHECK: -bebebebebebebebebebebebebebebebebebebebebebebebebebebebebebebebebe-
-// CHECK-10-8: -080808080808080808080000000000000000000000000000000000000000000000-
-// CHECK-20-ab: -abababababababababababababababababababab00000000000000000000000000-
diff --git a/lib/asan/lit_tests/TestCases/malloc_hook.cc b/lib/asan/lit_tests/TestCases/malloc_hook.cc
deleted file mode 100644
index 83be1020ea43..000000000000
--- a/lib/asan/lit_tests/TestCases/malloc_hook.cc
+++ /dev/null
@@ -1,36 +0,0 @@
-// RUN: %clangxx_asan -O2 %s -o %t
-// RUN: %t 2>&1 | FileCheck %s
-#include <stdlib.h>
-#include <unistd.h>
-
-extern "C" {
-bool __asan_get_ownership(const void *p);
-
-void *global_ptr;
-
-// Note: avoid calling functions that allocate memory in malloc/free
-// to avoid infinite recursion.
-void __asan_malloc_hook(void *ptr, size_t sz) {
- if (__asan_get_ownership(ptr)) {
- write(1, "MallocHook\n", sizeof("MallocHook\n"));
- global_ptr = ptr;
- }
-}
-void __asan_free_hook(void *ptr) {
- if (__asan_get_ownership(ptr) && ptr == global_ptr)
- write(1, "FreeHook\n", sizeof("FreeHook\n"));
-}
-} // extern "C"
-
-int main() {
- volatile int *x = new int;
- // CHECK: MallocHook
- // Check that malloc hook was called with correct argument.
- if (global_ptr != (void*)x) {
- _exit(1);
- }
- *x = 0;
- delete x;
- // CHECK: FreeHook
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/memcmp_strict_test.cc b/lib/asan/lit_tests/TestCases/memcmp_strict_test.cc
deleted file mode 100644
index e06a8c7e9e2f..000000000000
--- a/lib/asan/lit_tests/TestCases/memcmp_strict_test.cc
+++ /dev/null
@@ -1,15 +0,0 @@
-// RUN: %clangxx_asan -O0 %s -o %t && ASAN_OPTIONS=strict_memcmp=0 %t
-// RUN: %clangxx_asan -O0 %s -o %t && ASAN_OPTIONS=strict_memcmp=1 not %t 2>&1 | FileCheck %s
-// Default to strict_memcmp=1.
-// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s
-
-#include <stdio.h>
-#include <string.h>
-int main() {
- char kFoo[] = "foo";
- char kFubar[] = "fubar";
- int res = memcmp(kFoo, kFubar, strlen(kFubar));
- printf("res: %d\n", res);
- // CHECK: AddressSanitizer: stack-buffer-overflow
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/memcmp_test.cc b/lib/asan/lit_tests/TestCases/memcmp_test.cc
deleted file mode 100644
index 758311ddc476..000000000000
--- a/lib/asan/lit_tests/TestCases/memcmp_test.cc
+++ /dev/null
@@ -1,17 +0,0 @@
-// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>&1 | FileCheck %s
-
-// REQUIRES: compiler-rt-optimized
-
-#include <string.h>
-int main(int argc, char **argv) {
- char a1[] = {argc, 2, 3, 4};
- char a2[] = {1, 2*argc, 3, 4};
- int res = memcmp(a1, a2, 4 + argc); // BOOM
- // CHECK: AddressSanitizer: stack-buffer-overflow
- // CHECK: {{#0.*memcmp}}
- // CHECK: {{#1.*main}}
- return res;
-}
diff --git a/lib/asan/lit_tests/TestCases/null_deref.cc b/lib/asan/lit_tests/TestCases/null_deref.cc
deleted file mode 100644
index 476418324cc5..000000000000
--- a/lib/asan/lit_tests/TestCases/null_deref.cc
+++ /dev/null
@@ -1,19 +0,0 @@
-// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
-// RUN: %clangxx_asan -O1 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
-// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
-// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
-
-__attribute__((noinline))
-static void NullDeref(int *ptr) {
- // CHECK: ERROR: AddressSanitizer: SEGV on unknown address
- // CHECK: {{0x0*00028 .*pc 0x.*}}
- ptr[10]++; // BOOM
- // atos on Mac cannot extract the symbol name correctly.
- // CHECK-Linux: {{ #0 0x.* in NullDeref.*null_deref.cc:}}[[@LINE-2]]
- // CHECK-Darwin: {{ #0 0x.* in .*NullDeref.*null_deref.cc:}}[[@LINE-3]]
-}
-int main() {
- NullDeref((int*)0);
- // CHECK: {{ #1 0x.* in main.*null_deref.cc:}}[[@LINE-1]]
- // CHECK: {{AddressSanitizer can not provide additional info.}}
-}
diff --git a/lib/asan/lit_tests/TestCases/on_error_callback.cc b/lib/asan/lit_tests/TestCases/on_error_callback.cc
deleted file mode 100644
index d0cec2eb2703..000000000000
--- a/lib/asan/lit_tests/TestCases/on_error_callback.cc
+++ /dev/null
@@ -1,16 +0,0 @@
-// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s
-
-#include <stdio.h>
-#include <stdlib.h>
-
-extern "C"
-void __asan_on_error() {
- fprintf(stderr, "__asan_on_error called");
-}
-
-int main() {
- char *x = (char*)malloc(10 * sizeof(char));
- free(x);
- return x[5];
- // CHECK: __asan_on_error called
-}
diff --git a/lib/asan/lit_tests/TestCases/partial_right.cc b/lib/asan/lit_tests/TestCases/partial_right.cc
deleted file mode 100644
index a000a913d6be..000000000000
--- a/lib/asan/lit_tests/TestCases/partial_right.cc
+++ /dev/null
@@ -1,13 +0,0 @@
-// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>&1 | FileCheck %s
-
-#include <stdlib.h>
-int main(int argc, char **argv) {
- volatile int *x = (int*)malloc(2*sizeof(int) + 2);
- int res = x[2]; // BOOOM
- // CHECK: {{READ of size 4 at 0x.* thread T0}}
- // CHECK: [[ADDR:0x[01-9a-fa-f]+]] is located 0 bytes to the right of {{.*}}-byte region [{{.*}},{{.*}}[[ADDR]])
- return res;
-}
diff --git a/lib/asan/lit_tests/TestCases/poison_partial.cc b/lib/asan/lit_tests/TestCases/poison_partial.cc
deleted file mode 100644
index f7c48bf597b6..000000000000
--- a/lib/asan/lit_tests/TestCases/poison_partial.cc
+++ /dev/null
@@ -1,19 +0,0 @@
-// RUN: %clangxx_asan -O0 %s -o %t
-// RUN: not %t 2>&1 | FileCheck %s
-// RUN: not %t heap 2>&1 | FileCheck %s
-// RUN: ASAN_OPTIONS=poison_partial=0 %t
-// RUN: ASAN_OPTIONS=poison_partial=0 %t heap
-#include <string.h>
-char g[21];
-char *x;
-
-int main(int argc, char **argv) {
- if (argc >= 2)
- x = new char[21];
- else
- x = &g[0];
- memset(x, 0, 21);
- int *y = (int*)x;
- return y[5];
-}
-// CHECK: 0 bytes to the right
diff --git a/lib/asan/lit_tests/TestCases/print_summary.cc b/lib/asan/lit_tests/TestCases/print_summary.cc
deleted file mode 100644
index 949c9b54f8a3..000000000000
--- a/lib/asan/lit_tests/TestCases/print_summary.cc
+++ /dev/null
@@ -1,14 +0,0 @@
-// RUN: %clangxx_asan -O0 %s -o %t
-// RUN: not %t 2>&1 | FileCheck %s --check-prefix=YES
-// RUN: ASAN_OPTIONS=print_summary=false not %t 2>&1 | FileCheck %s --check-prefix=NO
-
-int main() {
- char *x = new char[20];
- delete[] x;
- return x[0];
- // YES: ERROR: AddressSanitizer: heap-use-after-free
- // YES: SUMMARY: AddressSanitizer: heap-use-after-free
- // NO: ERROR: AddressSanitizer: heap-use-after-free
- // NO-NOT: SUMMARY: AddressSanitizer: heap-use-after-free
-}
-
diff --git a/lib/asan/lit_tests/TestCases/readv.cc b/lib/asan/lit_tests/TestCases/readv.cc
deleted file mode 100644
index ba17505f37ac..000000000000
--- a/lib/asan/lit_tests/TestCases/readv.cc
+++ /dev/null
@@ -1,32 +0,0 @@
-// RUN: %clangxx_asan -O0 %s -o %t && %t
-// RUN: %clangxx_asan -O0 %s -DPOSITIVE -o %t && not %t 2>&1 | FileCheck %s
-
-// Test the readv() interceptor.
-
-#include <assert.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/uio.h>
-#include <time.h>
-
-int main() {
- char buf[2011];
- struct iovec iov[2];
-#ifdef POSITIVE
- char * volatile buf_ = buf;
- iov[0].iov_base = buf_ - 1;
-#else
- iov[0].iov_base = buf + 1;
-#endif
- iov[0].iov_len = 5;
- iov[1].iov_base = buf + 10;
- iov[1].iov_len = 2000;
- int fd = open("/etc/hosts", O_RDONLY);
- assert(fd > 0);
- readv(fd, iov, 2);
- // CHECK: WRITE of size 5 at
- close(fd);
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/sanity_check_pure_c.c b/lib/asan/lit_tests/TestCases/sanity_check_pure_c.c
deleted file mode 100644
index df150675bd97..000000000000
--- a/lib/asan/lit_tests/TestCases/sanity_check_pure_c.c
+++ /dev/null
@@ -1,19 +0,0 @@
-// Sanity checking a test in pure C.
-// RUN: %clang_asan -O2 %s -o %t
-// RUN: not %t 2>&1 | FileCheck %s
-
-// Sanity checking a test in pure C with -pie.
-// RUN: %clang_asan -O2 %s -pie -o %t
-// RUN: not %t 2>&1 | FileCheck %s
-
-#include <stdlib.h>
-int main() {
- char *x = (char*)malloc(10 * sizeof(char));
- free(x);
- return x[5];
- // CHECK: heap-use-after-free
- // CHECK: free
- // CHECK: main{{.*}}sanity_check_pure_c.c:[[@LINE-4]]
- // CHECK: malloc
- // CHECK: main{{.*}}sanity_check_pure_c.c:[[@LINE-7]]
-}
diff --git a/lib/asan/lit_tests/TestCases/shared-lib-test.cc b/lib/asan/lit_tests/TestCases/shared-lib-test.cc
deleted file mode 100644
index 126903a55866..000000000000
--- a/lib/asan/lit_tests/TestCases/shared-lib-test.cc
+++ /dev/null
@@ -1,42 +0,0 @@
-// RUN: %clangxx_asan -O0 %p/SharedLibs/shared-lib-test-so.cc \
-// RUN: -fPIC -shared -o %t-so.so
-// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O1 %p/SharedLibs/shared-lib-test-so.cc \
-// RUN: -fPIC -shared -o %t-so.so
-// RUN: %clangxx_asan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O2 %p/SharedLibs/shared-lib-test-so.cc \
-// RUN: -fPIC -shared -o %t-so.so
-// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O3 %p/SharedLibs/shared-lib-test-so.cc \
-// RUN: -fPIC -shared -o %t-so.so
-// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>&1 | FileCheck %s
-
-#include <dlfcn.h>
-#include <stdio.h>
-#include <string.h>
-
-#include <string>
-
-using std::string;
-
-typedef void (fun_t)(int x);
-
-int main(int argc, char *argv[]) {
- string path = string(argv[0]) + "-so.so";
- printf("opening %s ... \n", path.c_str());
- void *lib = dlopen(path.c_str(), RTLD_NOW);
- if (!lib) {
- printf("error in dlopen(): %s\n", dlerror());
- return 1;
- }
- fun_t *inc = (fun_t*)dlsym(lib, "inc");
- if (!inc) return 1;
- printf("ok\n");
- inc(1);
- inc(-1); // BOOM
- // CHECK: {{.*ERROR: AddressSanitizer: global-buffer-overflow}}
- // CHECK: {{READ of size 4 at 0x.* thread T0}}
- // CHECK: {{ #0 0x.*}}
- // CHECK: {{ #1 0x.* in main .*shared-lib-test.cc:}}[[@LINE-4]]
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/sleep_before_dying.c b/lib/asan/lit_tests/TestCases/sleep_before_dying.c
deleted file mode 100644
index 8dee9f2778ce..000000000000
--- a/lib/asan/lit_tests/TestCases/sleep_before_dying.c
+++ /dev/null
@@ -1,10 +0,0 @@
-// RUN: %clang_asan -O2 %s -o %t
-// RUN: ASAN_OPTIONS="sleep_before_dying=1" not %t 2>&1 | FileCheck %s
-
-#include <stdlib.h>
-int main() {
- char *x = (char*)malloc(10 * sizeof(char));
- free(x);
- return x[5];
- // CHECK: Sleeping for 1 second
-}
diff --git a/lib/asan/lit_tests/TestCases/stack-buffer-overflow-with-position.cc b/lib/asan/lit_tests/TestCases/stack-buffer-overflow-with-position.cc
deleted file mode 100644
index 91820db0142a..000000000000
--- a/lib/asan/lit_tests/TestCases/stack-buffer-overflow-with-position.cc
+++ /dev/null
@@ -1,45 +0,0 @@
-// RUN: %clangxx_asan -O2 %s -o %t
-// RUN: not %t -2 2>&1 | FileCheck --check-prefix=CHECK-m2 %s
-// RUN: not %t -1 2>&1 | FileCheck --check-prefix=CHECK-m1 %s
-// RUN: %t 0
-// RUN: %t 8
-// RUN: not %t 9 2>&1 | FileCheck --check-prefix=CHECK-9 %s
-// RUN: not %t 10 2>&1 | FileCheck --check-prefix=CHECK-10 %s
-// RUN: not %t 62 2>&1 | FileCheck --check-prefix=CHECK-62 %s
-// RUN: not %t 63 2>&1 | FileCheck --check-prefix=CHECK-63 %s
-// RUN: not %t 63 2>&1 | FileCheck --check-prefix=CHECK-63 %s
-// RUN: not %t 73 2>&1 | FileCheck --check-prefix=CHECK-73 %s
-// RUN: not %t 74 2>&1 | FileCheck --check-prefix=CHECK-74 %s
-// RUN: not %t 126 2>&1 | FileCheck --check-prefix=CHECK-126 %s
-// RUN: not %t 127 2>&1 | FileCheck --check-prefix=CHECK-127 %s
-// RUN: not %t 137 2>&1 | FileCheck --check-prefix=CHECK-137 %s
-// RUN: not %t 138 2>&1 | FileCheck --check-prefix=CHECK-138 %s
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <assert.h>
-int main(int argc, char **argv) {
- assert(argc >= 2);
- int idx = atoi(argv[1]);
- char AAA[10], BBB[10], CCC[10];
- memset(AAA, 0, sizeof(AAA));
- memset(BBB, 0, sizeof(BBB));
- memset(CCC, 0, sizeof(CCC));
- int res = 0;
- char *p = AAA + idx;
- printf("AAA: %p\ny: %p\nz: %p\np: %p\n", AAA, BBB, CCC, p);
- // make sure BBB and CCC are not removed;
- return *(short*)(p) + BBB[argc % 2] + CCC[argc % 2];
-}
-// CHECK-m2: 'AAA' <== Memory access at offset 30 underflows this variable
-// CHECK-m1: 'AAA' <== Memory access at offset 31 partially underflows this variable
-// CHECK-9: 'AAA' <== Memory access at offset 41 partially overflows this variable
-// CHECK-10: 'AAA' <== Memory access at offset 42 overflows this variable
-// CHECK-62: 'BBB' <== Memory access at offset 94 underflows this variable
-// CHECK-63: 'BBB' <== Memory access at offset 95 partially underflows this variable
-// CHECK-73: 'BBB' <== Memory access at offset 105 partially overflows this variable
-// CHECK-74: 'BBB' <== Memory access at offset 106 overflows this variable
-// CHECK-126: 'CCC' <== Memory access at offset 158 underflows this variable
-// CHECK-127: 'CCC' <== Memory access at offset 159 partially underflows this variable
-// CHECK-137: 'CCC' <== Memory access at offset 169 partially overflows this variable
-// CHECK-138: 'CCC' <== Memory access at offset 170 overflows this variable
diff --git a/lib/asan/lit_tests/TestCases/stack-frame-demangle.cc b/lib/asan/lit_tests/TestCases/stack-frame-demangle.cc
deleted file mode 100644
index 2b83ecc2923b..000000000000
--- a/lib/asan/lit_tests/TestCases/stack-frame-demangle.cc
+++ /dev/null
@@ -1,22 +0,0 @@
-// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s
-
-#include <string.h>
-
-namespace XXX {
-struct YYY {
- static int ZZZ(int x) {
- char array[10];
- memset(array, 0, 10);
- return array[x]; // BOOOM
- // CHECK: ERROR: AddressSanitizer: stack-buffer-overflow
- // CHECK: READ of size 1 at
- // CHECK: is located in stack of thread T0 at offset
- // CHECK: XXX::YYY::ZZZ
- }
-};
-} // namespace XXX
-
-int main(int argc, char **argv) {
- int res = XXX::YYY::ZZZ(argc + 10);
- return res;
-}
diff --git a/lib/asan/lit_tests/TestCases/stack-oob-frames.cc b/lib/asan/lit_tests/TestCases/stack-oob-frames.cc
deleted file mode 100644
index 909e700b3d00..000000000000
--- a/lib/asan/lit_tests/TestCases/stack-oob-frames.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-// RUN: %clangxx_asan -O1 %s -o %t
-// RUN: not %t 0 2>&1 | FileCheck %s --check-prefix=CHECK0
-// RUN: not %t 1 2>&1 | FileCheck %s --check-prefix=CHECK1
-// RUN: not %t 2 2>&1 | FileCheck %s --check-prefix=CHECK2
-// RUN: not %t 3 2>&1 | FileCheck %s --check-prefix=CHECK3
-
-#define NOINLINE __attribute__((noinline))
-inline void break_optimization(void *arg) {
- __asm__ __volatile__("" : : "r" (arg) : "memory");
-}
-
-NOINLINE static void Frame0(int frame, char *a, char *b, char *c) {
- char s[4] = {0};
- char *d = s;
- break_optimization(&d);
- switch (frame) {
- case 3: a[5]++; break;
- case 2: b[5]++; break;
- case 1: c[5]++; break;
- case 0: d[5]++; break;
- }
-}
-NOINLINE static void Frame1(int frame, char *a, char *b) {
- char c[4] = {0}; Frame0(frame, a, b, c);
- break_optimization(0);
-}
-NOINLINE static void Frame2(int frame, char *a) {
- char b[4] = {0}; Frame1(frame, a, b);
- break_optimization(0);
-}
-NOINLINE static void Frame3(int frame) {
- char a[4] = {0}; Frame2(frame, a);
- break_optimization(0);
-}
-
-int main(int argc, char **argv) {
- if (argc != 2) return 1;
- Frame3(argv[1][0] - '0');
-}
-
-// CHECK0: AddressSanitizer: stack-buffer-overflow
-// CHECK0: #0{{.*}}Frame0
-// CHECK0: #1{{.*}}Frame1
-// CHECK0: #2{{.*}}Frame2
-// CHECK0: #3{{.*}}Frame3
-// CHECK0: is located in stack of thread T0 at offset
-// CHECK0-NEXT: #0{{.*}}Frame0
-//
-// CHECK1: AddressSanitizer: stack-buffer-overflow
-// CHECK1: is located in stack of thread T0 at offset
-// CHECK1-NEXT: #0{{.*}}Frame1
-//
-// CHECK2: AddressSanitizer: stack-buffer-overflow
-// CHECK2: is located in stack of thread T0 at offset
-// CHECK2-NEXT: #0{{.*}}Frame2
-//
-// CHECK3: AddressSanitizer: stack-buffer-overflow
-// CHECK3: is located in stack of thread T0 at offset
-// CHECK3-NEXT: #0{{.*}}Frame3
diff --git a/lib/asan/lit_tests/TestCases/stack-overflow.cc b/lib/asan/lit_tests/TestCases/stack-overflow.cc
deleted file mode 100644
index adf1c0784f70..000000000000
--- a/lib/asan/lit_tests/TestCases/stack-overflow.cc
+++ /dev/null
@@ -1,16 +0,0 @@
-// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>&1 | FileCheck %s
-
-#include <string.h>
-int main(int argc, char **argv) {
- char x[10];
- memset(x, 0, 10);
- int res = x[argc * 10]; // BOOOM
- // CHECK: {{READ of size 1 at 0x.* thread T0}}
- // CHECK: {{ #0 0x.* in main .*stack-overflow.cc:}}[[@LINE-2]]
- // CHECK: {{Address 0x.* is located in stack of thread T0 at offset}}
- // CHECK-NEXT: in{{.*}}main{{.*}}stack-overflow.cc
- return res;
-}
diff --git a/lib/asan/lit_tests/TestCases/stack-use-after-return.cc b/lib/asan/lit_tests/TestCases/stack-use-after-return.cc
deleted file mode 100644
index 5ed42a8c0c97..000000000000
--- a/lib/asan/lit_tests/TestCases/stack-use-after-return.cc
+++ /dev/null
@@ -1,77 +0,0 @@
-// RUN: export ASAN_OPTIONS=detect_stack_use_after_return=1
-// RUN: %clangxx_asan -O0 %s -o %t && \
-// RUN: not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O1 %s -o %t && \
-// RUN: not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O2 %s -o %t && \
-// RUN: not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O3 %s -o %t && \
-// RUN: not %t 2>&1 | FileCheck %s
-// RUN: ASAN_OPTIONS=detect_stack_use_after_return=0 %t
-// Regression test for a CHECK failure with small stack size and large frame.
-// RUN: %clangxx_asan -O3 %s -o %t -DkSize=10000 && \
-// RUN: (ulimit -s 65; not %t) 2>&1 | FileCheck %s
-//
-// Test that we can find UAR in a thread other than main:
-// RUN: %clangxx_asan -DUseThread -O2 %s -o %t && \
-// RUN: not %t 2>&1 | FileCheck --check-prefix=THREAD %s
-//
-// Test the uar_stack_size_log flag.
-//
-// RUN: ASAN_OPTIONS=$ASAN_OPTIONS:uar_stack_size_log=20:verbosity=1 not %t 2>&1 | FileCheck --check-prefix=CHECK-20 %s
-// RUN: ASAN_OPTIONS=$ASAN_OPTIONS:uar_stack_size_log=24:verbosity=1 not %t 2>&1 | FileCheck --check-prefix=CHECK-24 %s
-
-#include <stdio.h>
-#include <pthread.h>
-
-#ifndef kSize
-# define kSize 1
-#endif
-
-#ifndef UseThread
-# define UseThread 0
-#endif
-
-__attribute__((noinline))
-char *Ident(char *x) {
- fprintf(stderr, "1: %p\n", x);
- return x;
-}
-
-__attribute__((noinline))
-char *Func1() {
- char local[kSize];
- return Ident(local);
-}
-
-__attribute__((noinline))
-void Func2(char *x) {
- fprintf(stderr, "2: %p\n", x);
- *x = 1;
- // CHECK: WRITE of size 1 {{.*}} thread T0
- // CHECK: #0{{.*}}Func2{{.*}}stack-use-after-return.cc:[[@LINE-2]]
- // CHECK: is located in stack of thread T0 at offset
- // CHECK: 'local' <== Memory access at offset 32 is inside this variable
- // THREAD: WRITE of size 1 {{.*}} thread T{{[1-9]}}
- // THREAD: #0{{.*}}Func2{{.*}}stack-use-after-return.cc:[[@LINE-6]]
- // THREAD: is located in stack of thread T{{[1-9]}} at offset
- // THREAD: 'local' <== Memory access at offset 32 is inside this variable
- // CHECK-20: T0: FakeStack created:{{.*}} stack_size_log: 20
- // CHECK-24: T0: FakeStack created:{{.*}} stack_size_log: 24
-}
-
-void *Thread(void *unused) {
- Func2(Func1());
- return NULL;
-}
-
-int main(int argc, char **argv) {
-#if UseThread
- pthread_t t;
- pthread_create(&t, 0, Thread, 0);
- pthread_join(t, 0);
-#else
- Func2(Func1());
-#endif
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/strdup_oob_test.cc b/lib/asan/lit_tests/TestCases/strdup_oob_test.cc
deleted file mode 100644
index e92afd3caaf9..000000000000
--- a/lib/asan/lit_tests/TestCases/strdup_oob_test.cc
+++ /dev/null
@@ -1,19 +0,0 @@
-// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>&1 | FileCheck %s
-
-#include <string.h>
-
-char kString[] = "foo";
-
-int main(int argc, char **argv) {
- char *copy = strdup(kString);
- int x = copy[4 + argc]; // BOOM
- // CHECK: AddressSanitizer: heap-buffer-overflow
- // CHECK: #0 {{.*}}main {{.*}}strdup_oob_test.cc:[[@LINE-2]]
- // CHECK: allocated by thread T{{.*}} here:
- // CHECK: #0 {{.*}}strdup
- // CHECK: strdup_oob_test.cc:[[@LINE-6]]
- return x;
-}
diff --git a/lib/asan/lit_tests/TestCases/strerror_r_test.cc b/lib/asan/lit_tests/TestCases/strerror_r_test.cc
deleted file mode 100644
index 0df009b83f9c..000000000000
--- a/lib/asan/lit_tests/TestCases/strerror_r_test.cc
+++ /dev/null
@@ -1,13 +0,0 @@
-// RUN: %clangxx_asan -O0 %s -o %t && %t
-
-// Regression test for PR17138.
-
-#include <assert.h>
-#include <string.h>
-
-int main() {
- char buf[1024];
- char *res = (char *)strerror_r(300, buf, sizeof(buf));
- assert(res != 0);
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/strip_path_prefix.c b/lib/asan/lit_tests/TestCases/strip_path_prefix.c
deleted file mode 100644
index c4d6ba49d5e3..000000000000
--- a/lib/asan/lit_tests/TestCases/strip_path_prefix.c
+++ /dev/null
@@ -1,12 +0,0 @@
-// RUN: %clang_asan -O2 %s -o %t
-// RUN: ASAN_OPTIONS="strip_path_prefix='/'" not %t 2>&1 | FileCheck %s
-
-#include <stdlib.h>
-int main() {
- char *x = (char*)malloc(10 * sizeof(char));
- free(x);
- return x[5];
- // Check that paths in error report don't start with slash.
- // CHECK: heap-use-after-free
- // CHECK-NOT: #0 0x{{.*}} ({{[/].*}})
-}
diff --git a/lib/asan/lit_tests/TestCases/strncpy-overflow.cc b/lib/asan/lit_tests/TestCases/strncpy-overflow.cc
deleted file mode 100644
index f91e191fde23..000000000000
--- a/lib/asan/lit_tests/TestCases/strncpy-overflow.cc
+++ /dev/null
@@ -1,28 +0,0 @@
-// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
-// RUN: %clangxx_asan -O1 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
-// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
-// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
-
-// REQUIRES: compiler-rt-optimized
-
-#include <string.h>
-#include <stdlib.h>
-int main(int argc, char **argv) {
- char *hello = (char*)malloc(6);
- strcpy(hello, "hello");
- char *short_buffer = (char*)malloc(9);
- strncpy(short_buffer, hello, 10); // BOOM
- // CHECK: {{WRITE of size 10 at 0x.* thread T0}}
- // CHECK-Linux: {{ #0 0x.* in .*strncpy}}
- // CHECK-Darwin: {{ #0 0x.* in wrap_strncpy}}
- // CHECK: {{ #1 0x.* in main .*strncpy-overflow.cc:}}[[@LINE-4]]
- // CHECK: {{0x.* is located 0 bytes to the right of 9-byte region}}
- // CHECK: {{allocated by thread T0 here:}}
-
- // CHECK-Linux: {{ #0 0x.* in .*malloc}}
- // CHECK-Linux: {{ #1 0x.* in main .*strncpy-overflow.cc:}}[[@LINE-10]]
-
- // CHECK-Darwin: {{ #0 0x.* in wrap_malloc.*}}
- // CHECK-Darwin: {{ #1 0x.* in main .*strncpy-overflow.cc:}}[[@LINE-13]]
- return short_buffer[8];
-}
diff --git a/lib/asan/lit_tests/TestCases/symbolize_callback.cc b/lib/asan/lit_tests/TestCases/symbolize_callback.cc
deleted file mode 100644
index 058b3150fbba..000000000000
--- a/lib/asan/lit_tests/TestCases/symbolize_callback.cc
+++ /dev/null
@@ -1,17 +0,0 @@
-// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s
-
-#include <stdio.h>
-#include <stdlib.h>
-
-extern "C"
-bool __asan_symbolize(const void *pc, char *out_buffer, int out_size) {
- snprintf(out_buffer, out_size, "MySymbolizer");
- return true;
-}
-
-int main() {
- char *x = (char*)malloc(10 * sizeof(char));
- free(x);
- return x[5];
- // CHECK: MySymbolizer
-}
diff --git a/lib/asan/lit_tests/TestCases/throw_call_test.cc b/lib/asan/lit_tests/TestCases/throw_call_test.cc
deleted file mode 100644
index 974bc51d97c5..000000000000
--- a/lib/asan/lit_tests/TestCases/throw_call_test.cc
+++ /dev/null
@@ -1,45 +0,0 @@
-// RUN: %clangxx_asan %s -o %t && %t
-// http://code.google.com/p/address-sanitizer/issues/detail?id=147 (not fixed).
-// BROKEN: %clangxx_asan %s -o %t -static-libstdc++ && %t
-#include <stdio.h>
-static volatile int zero = 0;
-inline void pretend_to_do_something(void *x) {
- __asm__ __volatile__("" : : "r" (x) : "memory");
-}
-
-__attribute__((noinline, no_sanitize_address))
-void ReallyThrow() {
- fprintf(stderr, "ReallyThrow\n");
- if (zero == 0)
- throw 42;
-}
-
-__attribute__((noinline))
-void Throw() {
- int a, b, c, d, e;
- pretend_to_do_something(&a);
- pretend_to_do_something(&b);
- pretend_to_do_something(&c);
- pretend_to_do_something(&d);
- pretend_to_do_something(&e);
- fprintf(stderr, "Throw stack = %p\n", &a);
- ReallyThrow();
-}
-
-__attribute__((noinline))
-void CheckStack() {
- int ar[100];
- pretend_to_do_something(ar);
- for (int i = 0; i < 100; i++)
- ar[i] = i;
- fprintf(stderr, "CheckStack stack = %p, %p\n", ar, ar + 100);
-}
-
-int main(int argc, char** argv) {
- try {
- Throw();
- } catch(int a) {
- fprintf(stderr, "a = %d\n", a);
- }
- CheckStack();
-}
diff --git a/lib/asan/lit_tests/TestCases/throw_invoke_test.cc b/lib/asan/lit_tests/TestCases/throw_invoke_test.cc
deleted file mode 100644
index 077a940e8d19..000000000000
--- a/lib/asan/lit_tests/TestCases/throw_invoke_test.cc
+++ /dev/null
@@ -1,50 +0,0 @@
-// RUN: %clangxx_asan %s -o %t && %t
-// RUN: %clangxx_asan %s -o %t -static-libstdc++ && %t
-#include <stdio.h>
-static volatile int zero = 0;
-inline void pretend_to_do_something(void *x) {
- __asm__ __volatile__("" : : "r" (x) : "memory");
-}
-
-__attribute__((noinline))
-void ReallyThrow() {
- fprintf(stderr, "ReallyThrow\n");
- try {
- if (zero == 0)
- throw 42;
- else if (zero == 1)
- throw 1.;
- } catch(double x) {
- }
-}
-
-__attribute__((noinline))
-void Throw() {
- int a, b, c, d, e;
- pretend_to_do_something(&a);
- pretend_to_do_something(&b);
- pretend_to_do_something(&c);
- pretend_to_do_something(&d);
- pretend_to_do_something(&e);
- fprintf(stderr, "Throw stack = %p\n", &a);
- ReallyThrow();
-}
-
-__attribute__((noinline))
-void CheckStack() {
- int ar[100];
- pretend_to_do_something(ar);
- for (int i = 0; i < 100; i++)
- ar[i] = i;
- fprintf(stderr, "CheckStack stack = %p, %p\n", ar, ar + 100);
-}
-
-int main(int argc, char** argv) {
- try {
- Throw();
- } catch(int a) {
- fprintf(stderr, "a = %d\n", a);
- }
- CheckStack();
-}
-
diff --git a/lib/asan/lit_tests/TestCases/time_interceptor.cc b/lib/asan/lit_tests/TestCases/time_interceptor.cc
deleted file mode 100644
index 3be00d60c01d..000000000000
--- a/lib/asan/lit_tests/TestCases/time_interceptor.cc
+++ /dev/null
@@ -1,16 +0,0 @@
-// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s
-
-// Test the time() interceptor.
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <time.h>
-
-int main() {
- time_t *tm = (time_t*)malloc(sizeof(time_t));
- free(tm);
- time_t t = time(tm);
- printf("Time: %s\n", ctime(&t)); // NOLINT
- // CHECK: use-after-free
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/uar_and_exceptions.cc b/lib/asan/lit_tests/TestCases/uar_and_exceptions.cc
deleted file mode 100644
index c967531c2c02..000000000000
--- a/lib/asan/lit_tests/TestCases/uar_and_exceptions.cc
+++ /dev/null
@@ -1,40 +0,0 @@
-// Test that use-after-return works with exceptions.
-// export ASAN_OPTIONS=detect_stack_use_after_return=1
-// RUN: %clangxx_asan -O0 %s -o %t && %t
-
-#include <stdio.h>
-
-volatile char *g;
-
-#ifndef FRAME_SIZE
-# define FRAME_SIZE 100
-#endif
-
-#ifndef NUM_ITER
-# define NUM_ITER 4000
-#endif
-
-#ifndef DO_THROW
-# define DO_THROW 1
-#endif
-
-void Func(int depth) {
- char frame[FRAME_SIZE];
- g = &frame[0];
- if (depth)
- Func(depth - 1);
- else if (DO_THROW)
- throw 1;
-}
-
-int main(int argc, char **argv) {
- for (int i = 0; i < NUM_ITER; i++) {
- try {
- Func(argc * 100);
- } catch(...) {
- }
- if ((i % (NUM_ITER / 10)) == 0)
- fprintf(stderr, "done [%d]\n", i);
- }
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/unaligned_loads_and_stores.cc b/lib/asan/lit_tests/TestCases/unaligned_loads_and_stores.cc
deleted file mode 100644
index d50566c44e9a..000000000000
--- a/lib/asan/lit_tests/TestCases/unaligned_loads_and_stores.cc
+++ /dev/null
@@ -1,52 +0,0 @@
-// RUN: %clangxx_asan -O0 %s -o %t
-// RUN: not %t A 2>&1 | FileCheck --check-prefix=CHECK-A %s
-// RUN: not %t B 2>&1 | FileCheck --check-prefix=CHECK-B %s
-// RUN: not %t C 2>&1 | FileCheck --check-prefix=CHECK-C %s
-// RUN: not %t D 2>&1 | FileCheck --check-prefix=CHECK-D %s
-// RUN: not %t E 2>&1 | FileCheck --check-prefix=CHECK-E %s
-
-// RUN: not %t K 2>&1 | FileCheck --check-prefix=CHECK-K %s
-// RUN: not %t L 2>&1 | FileCheck --check-prefix=CHECK-L %s
-// RUN: not %t M 2>&1 | FileCheck --check-prefix=CHECK-M %s
-// RUN: not %t N 2>&1 | FileCheck --check-prefix=CHECK-N %s
-// RUN: not %t O 2>&1 | FileCheck --check-prefix=CHECK-O %s
-
-#include <sanitizer/asan_interface.h>
-
-#include <stdlib.h>
-#include <string.h>
-int main(int argc, char **argv) {
- if (argc != 2) return 1;
- char *x = new char[16];
- memset(x, 0xab, 16);
- int res = 1;
- switch (argv[1][0]) {
- case 'A': res = __sanitizer_unaligned_load16(x + 15); break;
-// CHECK-A ERROR: AddressSanitizer: heap-buffer-overflow on address
-// CHECK-A: main{{.*}}unaligned_loads_and_stores.cc:[[@LINE-2]]
-// CHECK-A: is located 0 bytes to the right of 16-byte region
- case 'B': res = __sanitizer_unaligned_load32(x + 14); break;
-// CHECK-B: main{{.*}}unaligned_loads_and_stores.cc:[[@LINE-1]]
- case 'C': res = __sanitizer_unaligned_load32(x + 13); break;
-// CHECK-C: main{{.*}}unaligned_loads_and_stores.cc:[[@LINE-1]]
- case 'D': res = __sanitizer_unaligned_load64(x + 15); break;
-// CHECK-D: main{{.*}}unaligned_loads_and_stores.cc:[[@LINE-1]]
- case 'E': res = __sanitizer_unaligned_load64(x + 9); break;
-// CHECK-E: main{{.*}}unaligned_loads_and_stores.cc:[[@LINE-1]]
-
- case 'K': __sanitizer_unaligned_store16(x + 15, 0); break;
-// CHECK-K ERROR: AddressSanitizer: heap-buffer-overflow on address
-// CHECK-K: main{{.*}}unaligned_loads_and_stores.cc:[[@LINE-2]]
-// CHECK-K: is located 0 bytes to the right of 16-byte region
- case 'L': __sanitizer_unaligned_store32(x + 15, 0); break;
-// CHECK-L: main{{.*}}unaligned_loads_and_stores.cc:[[@LINE-1]]
- case 'M': __sanitizer_unaligned_store32(x + 13, 0); break;
-// CHECK-M: main{{.*}}unaligned_loads_and_stores.cc:[[@LINE-1]]
- case 'N': __sanitizer_unaligned_store64(x + 10, 0); break;
-// CHECK-N: main{{.*}}unaligned_loads_and_stores.cc:[[@LINE-1]]
- case 'O': __sanitizer_unaligned_store64(x + 14, 0); break;
-// CHECK-O: main{{.*}}unaligned_loads_and_stores.cc:[[@LINE-1]]
- }
- delete x;
- return res;
-}
diff --git a/lib/asan/lit_tests/TestCases/use-after-free-right.cc b/lib/asan/lit_tests/TestCases/use-after-free-right.cc
deleted file mode 100644
index 88d91f53d24e..000000000000
--- a/lib/asan/lit_tests/TestCases/use-after-free-right.cc
+++ /dev/null
@@ -1,34 +0,0 @@
-// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
-// RUN: %clangxx_asan -O1 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
-// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
-// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
-
-// Test use-after-free report in the case when access is at the right border of
-// the allocation.
-
-#include <stdlib.h>
-int main() {
- volatile char *x = (char*)malloc(sizeof(char));
- free((void*)x);
- *x = 42;
- // CHECK: {{.*ERROR: AddressSanitizer: heap-use-after-free on address}}
- // CHECK: {{0x.* at pc 0x.* bp 0x.* sp 0x.*}}
- // CHECK: {{WRITE of size 1 at 0x.* thread T0}}
- // CHECK: {{ #0 0x.* in main .*use-after-free-right.cc:13}}
- // CHECK: {{0x.* is located 0 bytes inside of 1-byte region .0x.*,0x.*}}
- // CHECK: {{freed by thread T0 here:}}
-
- // CHECK-Linux: {{ #0 0x.* in .*free}}
- // CHECK-Linux: {{ #1 0x.* in main .*use-after-free-right.cc:12}}
-
- // CHECK-Darwin: {{ #0 0x.* in wrap_free}}
- // CHECK-Darwin: {{ #1 0x.* in main .*use-after-free-right.cc:12}}
-
- // CHECK: {{previously allocated by thread T0 here:}}
-
- // CHECK-Linux: {{ #0 0x.* in .*malloc}}
- // CHECK-Linux: {{ #1 0x.* in main .*use-after-free-right.cc:11}}
-
- // CHECK-Darwin: {{ #0 0x.* in wrap_malloc.*}}
- // CHECK-Darwin: {{ #1 0x.* in main .*use-after-free-right.cc:11}}
-}
diff --git a/lib/asan/lit_tests/TestCases/use-after-free.cc b/lib/asan/lit_tests/TestCases/use-after-free.cc
deleted file mode 100644
index 84ba479c1393..000000000000
--- a/lib/asan/lit_tests/TestCases/use-after-free.cc
+++ /dev/null
@@ -1,31 +0,0 @@
-// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
-// RUN: %clangxx_asan -O1 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
-// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
-// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
-
-#include <stdlib.h>
-int main() {
- char *x = (char*)malloc(10 * sizeof(char));
- free(x);
- return x[5];
- // CHECK: {{.*ERROR: AddressSanitizer: heap-use-after-free on address}}
- // CHECK: {{0x.* at pc 0x.* bp 0x.* sp 0x.*}}
- // CHECK: {{READ of size 1 at 0x.* thread T0}}
- // CHECK: {{ #0 0x.* in main .*use-after-free.cc:10}}
- // CHECK: {{0x.* is located 5 bytes inside of 10-byte region .0x.*,0x.*}}
- // CHECK: {{freed by thread T0 here:}}
-
- // CHECK-Linux: {{ #0 0x.* in .*free}}
- // CHECK-Linux: {{ #1 0x.* in main .*use-after-free.cc:9}}
-
- // CHECK-Darwin: {{ #0 0x.* in wrap_free}}
- // CHECK-Darwin: {{ #1 0x.* in main .*use-after-free.cc:9}}
-
- // CHECK: {{previously allocated by thread T0 here:}}
-
- // CHECK-Linux: {{ #0 0x.* in .*malloc}}
- // CHECK-Linux: {{ #1 0x.* in main .*use-after-free.cc:8}}
-
- // CHECK-Darwin: {{ #0 0x.* in wrap_malloc.*}}
- // CHECK-Darwin: {{ #1 0x.* in main .*use-after-free.cc:8}}
-}
diff --git a/lib/asan/lit_tests/TestCases/use-after-poison.cc b/lib/asan/lit_tests/TestCases/use-after-poison.cc
deleted file mode 100644
index e3bc6ecee7f2..000000000000
--- a/lib/asan/lit_tests/TestCases/use-after-poison.cc
+++ /dev/null
@@ -1,20 +0,0 @@
-// Check that __asan_poison_memory_region works.
-// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s
-//
-// Check that we can disable it
-// RUN: ASAN_OPTIONS=allow_user_poisoning=0 %t
-
-#include <stdlib.h>
-
-extern "C" void __asan_poison_memory_region(void *, size_t);
-
-int main(int argc, char **argv) {
- char *x = new char[16];
- x[10] = 0;
- __asan_poison_memory_region(x, 16);
- int res = x[argc * 10]; // BOOOM
- // CHECK: ERROR: AddressSanitizer: use-after-poison
- // CHECK: main{{.*}}use-after-poison.cc:[[@LINE-2]]
- delete [] x;
- return res;
-}
diff --git a/lib/asan/lit_tests/TestCases/use-after-scope-dtor-order.cc b/lib/asan/lit_tests/TestCases/use-after-scope-dtor-order.cc
deleted file mode 100644
index 32fa6ad8a464..000000000000
--- a/lib/asan/lit_tests/TestCases/use-after-scope-dtor-order.cc
+++ /dev/null
@@ -1,25 +0,0 @@
-// RUN: %clangxx_asan -O0 -fsanitize=use-after-scope %s -o %t && \
-// RUN: not %t 2>&1 | FileCheck %s
-#include <stdio.h>
-
-struct IntHolder {
- explicit IntHolder(int *val = 0) : val_(val) { }
- ~IntHolder() {
- printf("Value: %d\n", *val_); // BOOM
- // CHECK: ERROR: AddressSanitizer: stack-use-after-scope
- // CHECK: #0 0x{{.*}} in IntHolder::~IntHolder{{.*}}use-after-scope-dtor-order.cc:[[@LINE-2]]
- }
- void set(int *val) { val_ = val; }
- int *get() { return val_; }
-
- int *val_;
-};
-
-int main(int argc, char *argv[]) {
- // It is incorrect to use "x" int IntHolder destructor, because "x" is
- // "destroyed" earlier as it's declared later.
- IntHolder holder;
- int x = argc;
- holder.set(&x);
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/use-after-scope-inlined.cc b/lib/asan/lit_tests/TestCases/use-after-scope-inlined.cc
deleted file mode 100644
index 0bad048e3b8f..000000000000
--- a/lib/asan/lit_tests/TestCases/use-after-scope-inlined.cc
+++ /dev/null
@@ -1,27 +0,0 @@
-// Test with "-O2" only to make sure inlining (leading to use-after-scope)
-// happens. "always_inline" is not enough, as Clang doesn't emit
-// llvm.lifetime intrinsics at -O0.
-//
-// RUN: %clangxx_asan -O2 -fsanitize=use-after-scope %s -o %t && not %t 2>&1 | FileCheck %s
-
-int *arr;
-
-__attribute__((always_inline))
-void inlined(int arg) {
- int x[5];
- for (int i = 0; i < arg; i++) x[i] = i;
- arr = x;
-}
-
-int main(int argc, char *argv[]) {
- inlined(argc);
- return arr[argc - 1]; // BOOM
- // CHECK: ERROR: AddressSanitizer: stack-use-after-scope
- // CHECK: READ of size 4 at 0x{{.*}} thread T0
- // CHECK: #0 0x{{.*}} in main
- // CHECK: {{.*}}use-after-scope-inlined.cc:[[@LINE-4]]
- // CHECK: Address 0x{{.*}} is located in stack of thread T0 at offset
- // CHECK: [[OFFSET:[^ ]*]] in frame
- // CHECK: main
- // CHECK: {{\[}}[[OFFSET]], {{.*}}) 'x.i'
-}
diff --git a/lib/asan/lit_tests/TestCases/use-after-scope-nobug.cc b/lib/asan/lit_tests/TestCases/use-after-scope-nobug.cc
deleted file mode 100644
index c23acf76eaee..000000000000
--- a/lib/asan/lit_tests/TestCases/use-after-scope-nobug.cc
+++ /dev/null
@@ -1,14 +0,0 @@
-// RUN: %clangxx_asan -O0 -fsanitize=use-after-scope %s -o %t && %t
-
-#include <stdio.h>
-
-int main() {
- int *p = 0;
- // Variable goes in and out of scope.
- for (int i = 0; i < 3; i++) {
- int x = 0;
- p = &x;
- }
- printf("PASSED\n");
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/use-after-scope-temp.cc b/lib/asan/lit_tests/TestCases/use-after-scope-temp.cc
deleted file mode 100644
index 13d714f9def7..000000000000
--- a/lib/asan/lit_tests/TestCases/use-after-scope-temp.cc
+++ /dev/null
@@ -1,29 +0,0 @@
-// RUN: %clangxx_asan -O0 -fsanitize=use-after-scope %s -o %t && \
-// RUN: %t 2>&1 | FileCheck %s
-//
-// Lifetime for temporaries is not emitted yet.
-// XFAIL: *
-
-#include <stdio.h>
-
-struct IntHolder {
- explicit IntHolder(int val) : val(val) {
- printf("IntHolder: %d\n", val);
- }
- int val;
-};
-
-const IntHolder *saved;
-
-void save(const IntHolder &holder) {
- saved = &holder;
-}
-
-int main(int argc, char *argv[]) {
- save(IntHolder(10));
- int x = saved->val; // BOOM
- // CHECK: ERROR: AddressSanitizer: stack-use-after-scope
- // CHECK: #0 0x{{.*}} in main {{.*}}use-after-scope-temp.cc:[[@LINE-2]]
- printf("saved value: %d\n", x);
- return 0;
-}
diff --git a/lib/asan/lit_tests/TestCases/use-after-scope.cc b/lib/asan/lit_tests/TestCases/use-after-scope.cc
deleted file mode 100644
index c46c9594c314..000000000000
--- a/lib/asan/lit_tests/TestCases/use-after-scope.cc
+++ /dev/null
@@ -1,16 +0,0 @@
-// RUN: %clangxx_asan -O0 -fsanitize=use-after-scope %s -o %t && \
-// RUN: not %t 2>&1 | FileCheck %s
-// RUN: ASAN_OPTIONS="detect_stack_use_after_return=1" not %t 2>&1 | FileCheck %s
-
-int main() {
- int *p = 0;
- {
- int x = 0;
- p = &x;
- }
- return *p; // BOOM
- // CHECK: ERROR: AddressSanitizer: stack-use-after-scope
- // CHECK: #0 0x{{.*}} in main {{.*}}use-after-scope.cc:[[@LINE-2]]
- // CHECK: Address 0x{{.*}} is located in stack of thread T{{.*}} at offset [[OFFSET:[^ ]+]] in frame
- // {{\[}}[[OFFSET]], {{[0-9]+}}) 'x'
-}
diff --git a/lib/asan/lit_tests/TestCases/wait.cc b/lib/asan/lit_tests/TestCases/wait.cc
deleted file mode 100644
index b5580dc88675..000000000000
--- a/lib/asan/lit_tests/TestCases/wait.cc
+++ /dev/null
@@ -1,63 +0,0 @@
-// RUN: %clangxx_asan -DWAIT -O0 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -DWAIT -O3 %s -o %t && not %t 2>&1 | FileCheck %s
-
-// RUN: %clangxx_asan -DWAITPID -O0 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -DWAITPID -O3 %s -o %t && not %t 2>&1 | FileCheck %s
-
-// RUN: %clangxx_asan -DWAITID -O0 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -DWAITID -O3 %s -o %t && not %t 2>&1 | FileCheck %s
-
-// RUN: %clangxx_asan -DWAIT3 -O0 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -DWAIT3 -O3 %s -o %t && not %t 2>&1 | FileCheck %s
-
-// RUN: %clangxx_asan -DWAIT4 -O0 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -DWAIT4 -O3 %s -o %t && not %t 2>&1 | FileCheck %s
-
-// RUN: %clangxx_asan -DWAIT3_RUSAGE -O0 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -DWAIT3_RUSAGE -O3 %s -o %t && not %t 2>&1 | FileCheck %s
-
-// RUN: %clangxx_asan -DWAIT4_RUSAGE -O0 %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -DWAIT4_RUSAGE -O3 %s -o %t && not %t 2>&1 | FileCheck %s
-
-
-#include <assert.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-int main(int argc, char **argv) {
- pid_t pid = fork();
- if (pid) { // parent
- int x[3];
- int *status = x + argc * 3;
- int res;
-#if defined(WAIT)
- res = wait(status);
-#elif defined(WAITPID)
- res = waitpid(pid, status, WNOHANG);
-#elif defined(WAITID)
- siginfo_t *si = (siginfo_t*)(x + argc * 3);
- res = waitid(P_ALL, 0, si, WEXITED | WNOHANG);
-#elif defined(WAIT3)
- res = wait3(status, WNOHANG, NULL);
-#elif defined(WAIT4)
- res = wait4(pid, status, WNOHANG, NULL);
-#elif defined(WAIT3_RUSAGE) || defined(WAIT4_RUSAGE)
- struct rusage *ru = (struct rusage*)(x + argc * 3);
- int good_status;
-# if defined(WAIT3_RUSAGE)
- res = wait3(&good_status, WNOHANG, ru);
-# elif defined(WAIT4_RUSAGE)
- res = wait4(pid, &good_status, WNOHANG, ru);
-# endif
-#endif
- // CHECK: stack-buffer-overflow
- // CHECK: {{WRITE of size .* at 0x.* thread T0}}
- // CHECK: {{in .*wait}}
- // CHECK: {{in main .*wait.cc:}}
- // CHECK: is located in stack of thread T0 at offset
- // CHECK: {{in main}}
- return res != -1;
- }
- // child
- return 0;
-}
diff --git a/lib/asan/lit_tests/Unit/lit.site.cfg.in b/lib/asan/lit_tests/Unit/lit.site.cfg.in
deleted file mode 100644
index a45870c9b0e1..000000000000
--- a/lib/asan/lit_tests/Unit/lit.site.cfg.in
+++ /dev/null
@@ -1,16 +0,0 @@
-## Autogenerated by LLVM/Clang configuration.
-# Do not edit!
-
-# Load common config for all compiler-rt unit tests.
-lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/lib/lit.common.unit.configured")
-
-# Setup config name.
-config.name = 'AddressSanitizer-Unit'
-
-# Setup test source and exec root. For unit tests, we define
-# it as build directory with ASan unit tests.
-config.test_exec_root = "@ASAN_BINARY_DIR@/tests"
-config.test_source_root = config.test_exec_root
-
-if config.host_os == 'Linux':
- config.environment['ASAN_OPTIONS'] = 'detect_leaks=1'
diff --git a/lib/asan/lit_tests/lit.cfg b/lib/asan/lit_tests/lit.cfg
deleted file mode 100644
index 71a700c6ac3b..000000000000
--- a/lib/asan/lit_tests/lit.cfg
+++ /dev/null
@@ -1,95 +0,0 @@
-# -*- Python -*-
-
-import os
-
-import lit.util
-
-def get_required_attr(config, attr_name):
- attr_value = getattr(config, attr_name, None)
- if not attr_value:
- lit_config.fatal(
- "No attribute %r in test configuration! You may need to run "
- "tests from your build directory or add this attribute "
- "to lit.site.cfg " % attr_name)
- return attr_value
-
-# Setup config name.
-config.name = 'AddressSanitizer' + config.bits
-
-# Setup source root.
-config.test_source_root = os.path.dirname(__file__)
-
-def DisplayNoConfigMessage():
- lit_config.fatal("No site specific configuration available! " +
- "Try running your test from the build tree or running " +
- "make check-asan")
-
-# Figure out LLVM source root.
-llvm_src_root = getattr(config, 'llvm_src_root', None)
-if llvm_src_root is None:
- # We probably haven't loaded the site-specific configuration: the user
- # is likely trying to run a test file directly, and the site configuration
- # wasn't created by the build system.
- asan_site_cfg = lit_config.params.get('asan_site_config', None)
- if (asan_site_cfg) and (os.path.exists(asan_site_cfg)):
- lit_config.load_config(config, asan_site_cfg)
- raise SystemExit
-
- # Try to guess the location of site-specific configuration using llvm-config
- # util that can point where the build tree is.
- llvm_config = lit.util.which("llvm-config", config.environment["PATH"])
- if not llvm_config:
- DisplayNoConfigMessage()
-
- # Find out the presumed location of generated site config.
- llvm_obj_root = lit.util.capture(["llvm-config", "--obj-root"]).strip()
- asan_site_cfg = os.path.join(llvm_obj_root, "projects", "compiler-rt",
- "lib", "asan", "lit_tests", "lit.site.cfg")
- if (not asan_site_cfg) or (not os.path.exists(asan_site_cfg)):
- DisplayNoConfigMessage()
-
- lit_config.load_config(config, asan_site_cfg)
- raise SystemExit
-
-# Setup default compiler flags used with -fsanitize=address option.
-# FIXME: Review the set of required flags and check if it can be reduced.
-bits_cflag = " -m" + config.bits
-clang_asan_cflags = (" -fsanitize=address"
- + " -mno-omit-leaf-frame-pointer"
- + " -fno-omit-frame-pointer"
- + " -fno-optimize-sibling-calls"
- + " -g"
- + bits_cflag)
-clang_asan_cxxflags = " --driver-mode=g++" + clang_asan_cflags
-config.substitutions.append( ("%clang ", " " + config.clang + bits_cflag + " "))
-config.substitutions.append( ("%clangxx ", (" " + config.clang +
- " --driver-mode=g++" +
- bits_cflag + " ")) )
-config.substitutions.append( ("%clang_asan ", (" " + config.clang + " " +
- clang_asan_cflags + " ")) )
-config.substitutions.append( ("%clangxx_asan ", (" " + config.clang + " " +
- clang_asan_cxxflags + " ")) )
-
-# Setup path to asan_symbolize.py script.
-asan_source_dir = get_required_attr(config, "asan_source_dir")
-asan_symbolize = os.path.join(asan_source_dir, "scripts", "asan_symbolize.py")
-if not os.path.exists(asan_symbolize):
- lit_config.fatal("Can't find script on path %r" % asan_symbolize)
-python_exec = get_required_attr(config, "python_executable")
-config.substitutions.append( ("%asan_symbolize", python_exec + " " + asan_symbolize + " ") )
-
-# Define CHECK-%os to check for OS-dependent output.
-config.substitutions.append( ('CHECK-%os', ("CHECK-" + config.host_os)))
-
-config.available_features.add("asan-" + config.bits + "-bits")
-
-# Turn on leak detection on 64-bit Linux.
-if config.host_os == 'Linux' and config.bits == '64':
- config.environment['ASAN_OPTIONS'] = 'detect_leaks=1'
-
-# Default test suffixes.
-config.suffixes = ['.c', '.cc', '.cpp']
-
-# AddressSanitizer tests are currently supported on Linux and Darwin only.
-if config.host_os not in ['Linux', 'Darwin']:
- config.unsupported = True
diff --git a/lib/asan/scripts/CMakeLists.txt b/lib/asan/scripts/CMakeLists.txt
new file mode 100644
index 000000000000..e5ab8ebed024
--- /dev/null
+++ b/lib/asan/scripts/CMakeLists.txt
@@ -0,0 +1,4 @@
+if(ANDROID)
+ add_compiler_rt_script(asan_device_setup)
+ add_dependencies(asan asan_device_setup)
+endif()
diff --git a/lib/asan/scripts/asan_device_setup b/lib/asan/scripts/asan_device_setup
new file mode 100755
index 000000000000..a620f51b0836
--- /dev/null
+++ b/lib/asan/scripts/asan_device_setup
@@ -0,0 +1,267 @@
+#!/bin/bash
+#===- lib/asan/scripts/asan_device_setup -----------------------------------===#
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+# Prepare Android device to run ASan applications.
+#
+#===------------------------------------------------------------------------===#
+
+set -e
+
+HERE="$(cd "$(dirname "$0")" && pwd)"
+
+revert=no
+extra_options=
+device=
+lib=
+
+function usage {
+ echo "usage: $0 [--revert] [--device device-id] [--lib path] [--extra-options options]"
+ echo " --revert: Uninstall ASan from the device."
+ echo " --lib: Path to ASan runtime library."
+ echo " --extra-options: Extra ASAN_OPTIONS."
+ echo " --device: Install to the given device. Use 'adb devices' to find"
+ echo " device-id."
+ echo
+ exit 1
+}
+
+function get_device_arch { # OUTVAR
+ local _outvar=$1
+ local _ABI=$($ADB shell getprop ro.product.cpu.abi)
+ local _ARCH=
+ if [[ $_ABI == x86* ]]; then
+ _ARCH=i686
+ elif [[ $_ABI == armeabi* ]]; then
+ _ARCH=arm
+ else
+ echo "Unrecognized device ABI: $_ABI"
+ exit 1
+ fi
+ eval $_outvar=\$_ARCH
+}
+
+while [[ $# > 0 ]]; do
+ case $1 in
+ --revert)
+ revert=yes
+ ;;
+ --extra-options)
+ shift
+ if [[ $# == 0 ]]; then
+ echo "--extra-options requires an argument."
+ exit 1
+ fi
+ extra_options="$1"
+ ;;
+ --lib)
+ shift
+ if [[ $# == 0 ]]; then
+ echo "--lib requires an argument."
+ exit 1
+ fi
+ lib="$1"
+ ;;
+ --device)
+ shift
+ if [[ $# == 0 ]]; then
+ echo "--device requires an argument."
+ exit 1
+ fi
+ device="$1"
+ ;;
+ *)
+ usage
+ ;;
+ esac
+ shift
+done
+
+ADB=${ADB:-adb}
+if [[ x$device != x ]]; then
+ ADB="$ADB -s $device"
+fi
+
+echo '>> Remounting /system rw'
+$ADB root
+$ADB wait-for-device
+$ADB remount
+$ADB wait-for-device
+
+get_device_arch ARCH
+echo "Target architecture: $ARCH"
+ASAN_RT="libclang_rt.asan-$ARCH-android.so"
+
+if [[ x$revert == xyes ]]; then
+ echo '>> Uninstalling ASan'
+
+ if ! $ADB shell readlink /system/bin/app_process | grep '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
+ $ADB shell rm /system/lib/$ASAN_RT
+ else
+ $ADB shell rm /system/bin/app_process.wrap
+ $ADB shell rm /system/bin/asanwrapper
+ $ADB shell rm /system/lib/$ASAN_RT
+ $ADB shell rm /system/bin/app_process
+ $ADB shell ln -s /system/bin/app_process32 /system/bin/app_process
+ fi
+
+ echo '>> Restarting shell'
+ $ADB shell stop
+ $ADB shell start
+
+ echo '>> Done'
+ exit 0
+fi
+
+if [[ -d "$lib" ]]; then
+ ASAN_RT_PATH="$lib"
+elif [[ -f "$lib" && "$lib" == *"$ASAN_RT" ]]; then
+ ASAN_RT_PATH=$(dirname "$lib")
+elif [[ -f "$HERE/$ASAN_RT" ]]; then
+ ASAN_RT_PATH="$HERE"
+elif [[ $(basename "$HERE") == "bin" ]]; then
+ # We could be in the toolchain's base directory.
+ # Consider ../lib, ../lib/asan, ../lib/linux and ../lib/clang/$VERSION/lib/linux.
+ P=$(ls "$HERE"/../lib/"$ASAN_RT" "$HERE"/../lib/asan/"$ASAN_RT" "$HERE"/../lib/linux/"$ASAN_RT" "$HERE"/../lib/clang/*/lib/linux/"$ASAN_RT" 2>/dev/null | sort | tail -1)
+ if [[ -n "$P" ]]; then
+ ASAN_RT_PATH="$(dirname "$P")"
+ fi
+fi
+
+if [[ -z "$ASAN_RT_PATH" || ! -f "$ASAN_RT_PATH/$ASAN_RT" ]]; then
+ echo ">> ASan runtime library not found"
+ exit 1
+fi
+
+TMPDIRBASE=$(mktemp -d)
+TMPDIROLD="$TMPDIRBASE/old"
+TMPDIR="$TMPDIRBASE/new"
+mkdir "$TMPDIROLD"
+
+RELEASE=$($ADB shell getprop ro.build.version.release)
+PRE_L=0
+if echo "$RELEASE" | grep '^4\.' >&/dev/null; then
+ PRE_L=1
+fi
+
+if ! $ADB shell readlink /system/bin/app_process | grep 'app_process' >&/dev/null; then
+
+ if $ADB pull /system/bin/app_process.real /dev/null >&/dev/null; then
+ echo '>> Old-style ASan installation detected. Reverting.'
+ $ADB shell mv /system/bin/app_process.real /system/bin/app_process
+ fi
+
+ echo '>> Pre-L device detected. Setting up app_process symlink.'
+ $ADB shell mv /system/bin/app_process /system/bin/app_process32
+ $ADB shell ln -s /system/bin/app_process32 /system/bin/app_process
+fi
+
+echo '>> Copying files from the device'
+$ADB pull /system/bin/app_process.wrap "$TMPDIROLD" || true
+$ADB pull /system/bin/asanwrapper "$TMPDIROLD" || true
+$ADB pull /system/lib/"$ASAN_RT" "$TMPDIROLD" || true
+cp -r "$TMPDIROLD" "$TMPDIR"
+
+if [[ -f "$TMPDIR/app_process.wrap" ]]; then
+ echo ">> Previous installation detected"
+else
+ echo ">> New installation"
+fi
+
+echo '>> Generating wrappers'
+
+cp "$ASAN_RT_PATH/$ASAN_RT" "$TMPDIR/"
+
+# FIXME: alloc_dealloc_mismatch=0 prevents a failure in libdvm startup,
+# which may or may not be a real bug (probably not).
+ASAN_OPTIONS=start_deactivated=1,alloc_dealloc_mismatch=0
+
+# On Android-L not allowing user segv handler breaks some applications.
+if $ADB shell 'echo $LD_PRELOAD' | grep libsigchain.so >&/dev/null; then
+ ASAN_OPTIONS="$ASAN_OPTIONS,allow_user_segv_handler=1"
+fi
+
+if [[ x$extra_options != x ]] ; then
+ ASAN_OPTIONS="$ASAN_OPTIONS,$extra_options"
+fi
+
+# Zygote wrapper.
+cat <<EOF >"$TMPDIR/app_process.wrap"
+#!/system/bin/sh-from-zygote
+ASAN_OPTIONS=$ASAN_OPTIONS \\
+LD_PRELOAD=\$LD_PRELOAD:$ASAN_RT \\
+exec /system/bin/app_process32 \$@
+
+EOF
+
+# General command-line tool wrapper (use for anything that's not started as
+# zygote).
+cat <<EOF >"$TMPDIR/asanwrapper"
+#!/system/bin/sh
+LD_PRELOAD=$ASAN_RT \\
+exec \$@
+
+EOF
+
+if ! ( cd "$TMPDIRBASE" && diff -qr old/ new/ ) ; then
+ echo '>> Pushing files to the device'
+ $ADB push "$TMPDIR/$ASAN_RT" /system/lib/
+ $ADB push "$TMPDIR/app_process.wrap" /system/bin/app_process.wrap
+ $ADB push "$TMPDIR/asanwrapper" /system/bin/asanwrapper
+
+ $ADB shell rm /system/bin/app_process
+ $ADB shell ln -s /system/bin/app_process.wrap /system/bin/app_process
+
+ $ADB shell chown root.shell \
+ /system/lib/"$ASAN_RT" \
+ /system/bin/app_process.wrap \
+ /system/bin/asanwrapper
+ $ADB shell chmod 644 \
+ /system/lib/"$ASAN_RT"
+ $ADB shell chmod 755 \
+ /system/bin/app_process.wrap \
+ /system/bin/asanwrapper
+
+ # Make SELinux happy by keeping app_process wrapper and the shell
+ # it runs on in zygote domain.
+ ENFORCING=0
+ if $ADB shell getenforce | grep Enforcing >/dev/null; then
+ # Sometimes shell is not allowed to change file contexts.
+ # Temporarily switch to permissive.
+ ENFORCING=1
+ $ADB shell setenforce 0
+ fi
+
+ $ADB shell cp /system/bin/sh /system/bin/sh-from-zygote
+
+ if [[ PRE_L -eq 1 ]]; then
+ CTX=u:object_r:system_file:s0
+ else
+ CTX=u:object_r:zygote_exec:s0
+ fi
+ $ADB shell chcon $CTX \
+ /system/bin/sh-from-zygote \
+ /system/bin/app_process.wrap \
+ /system/bin/app_process32
+
+ if [ $ENFORCING == 1 ]; then
+ $ADB shell setenforce 1
+ fi
+
+ echo '>> Restarting shell (asynchronous)'
+ $ADB shell stop
+ $ADB shell start
+
+ echo '>> Please wait until the device restarts'
+else
+ echo '>> Device is up to date'
+fi
+
+rm -r "$TMPDIRBASE"
diff --git a/lib/asan/scripts/asan_symbolize.py b/lib/asan/scripts/asan_symbolize.py
index a398fcf10361..5fca136b6950 100755
--- a/lib/asan/scripts/asan_symbolize.py
+++ b/lib/asan/scripts/asan_symbolize.py
@@ -7,6 +7,7 @@
# License. See LICENSE.TXT for details.
#
#===------------------------------------------------------------------------===#
+import argparse
import bisect
import getopt
import os
@@ -16,20 +17,33 @@ import subprocess
import sys
import termios
-llvm_symbolizer = None
symbolizers = {}
DEBUG = False
-demangle = False;
-
+demangle = False
+binutils_prefix = None
+sysroot_path = None
+binary_name_filter = None
+fix_filename_patterns = None
+logfile = sys.stdin
# FIXME: merge the code that calls fix_filename().
def fix_filename(file_name):
- for path_to_cut in sys.argv[1:]:
- file_name = re.sub('.*' + path_to_cut, '', file_name)
+ if fix_filename_patterns:
+ for path_to_cut in fix_filename_patterns:
+ file_name = re.sub('.*' + path_to_cut, '', file_name)
file_name = re.sub('.*asan_[a-z_]*.cc:[0-9]*', '_asan_rtl_', file_name)
file_name = re.sub('.*crtstuff.c:0', '???:0', file_name)
return file_name
+def sysroot_path_filter(binary_name):
+ return sysroot_path + binary_name
+
+def guess_arch(addr):
+ # Guess which arch we're running. 10 = len('0x') + 8 hex digits.
+ if len(addr) > 10:
+ return 'x86_64'
+ else:
+ return 'i386'
class Symbolizer(object):
def __init__(self):
@@ -52,23 +66,32 @@ class Symbolizer(object):
class LLVMSymbolizer(Symbolizer):
- def __init__(self, symbolizer_path):
+ def __init__(self, symbolizer_path, default_arch, system, dsym_hints=[]):
super(LLVMSymbolizer, self).__init__()
self.symbolizer_path = symbolizer_path
+ self.default_arch = default_arch
+ self.system = system
+ self.dsym_hints = dsym_hints
self.pipe = self.open_llvm_symbolizer()
def open_llvm_symbolizer(self):
- if not os.path.exists(self.symbolizer_path):
- return None
cmd = [self.symbolizer_path,
'--use-symbol-table=true',
'--demangle=%s' % demangle,
- '--functions=true',
- '--inlining=true']
+ '--functions=short',
+ '--inlining=true',
+ '--default-arch=%s' % self.default_arch]
+ if self.system == 'Darwin':
+ for hint in self.dsym_hints:
+ cmd.append('--dsym-hint=%s' % hint)
if DEBUG:
print ' '.join(cmd)
- return subprocess.Popen(cmd, stdin=subprocess.PIPE,
- stdout=subprocess.PIPE)
+ try:
+ result = subprocess.Popen(cmd, stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE)
+ except OSError:
+ result = None
+ return result
def symbolize(self, addr, binary, offset):
"""Overrides Symbolizer.symbolize."""
@@ -76,7 +99,7 @@ class LLVMSymbolizer(Symbolizer):
return None
result = []
try:
- symbolizer_input = '%s %s' % (binary, offset)
+ symbolizer_input = '"%s" %s' % (binary, offset)
if DEBUG:
print symbolizer_input
print >> self.pipe.stdin, symbolizer_input
@@ -86,9 +109,9 @@ class LLVMSymbolizer(Symbolizer):
break
file_name = self.pipe.stdout.readline().rstrip()
file_name = fix_filename(file_name)
- if (not function_name.startswith('??') and
+ if (not function_name.startswith('??') or
not file_name.startswith('??')):
- # Append only valid frames.
+ # Append only non-trivial frames.
result.append('%s in %s %s' % (addr, function_name,
file_name))
except Exception:
@@ -98,14 +121,14 @@ class LLVMSymbolizer(Symbolizer):
return result
-def LLVMSymbolizerFactory(system):
+def LLVMSymbolizerFactory(system, default_arch, dsym_hints=[]):
symbolizer_path = os.getenv('LLVM_SYMBOLIZER_PATH')
if not symbolizer_path:
symbolizer_path = os.getenv('ASAN_SYMBOLIZER_PATH')
if not symbolizer_path:
# Assume llvm-symbolizer is in PATH.
symbolizer_path = 'llvm-symbolizer'
- return LLVMSymbolizer(symbolizer_path)
+ return LLVMSymbolizer(symbolizer_path, default_arch, system, dsym_hints)
class Addr2LineSymbolizer(Symbolizer):
@@ -115,7 +138,10 @@ class Addr2LineSymbolizer(Symbolizer):
self.pipe = self.open_addr2line()
def open_addr2line(self):
- cmd = ['addr2line', '-f']
+ addr2line_tool = 'addr2line'
+ if binutils_prefix:
+ addr2line_tool = binutils_prefix + addr2line_tool
+ cmd = [addr2line_tool, '-f']
if demangle:
cmd += ['--demangle']
cmd += ['-e', self.binary]
@@ -173,11 +199,7 @@ class DarwinSymbolizer(Symbolizer):
def __init__(self, addr, binary):
super(DarwinSymbolizer, self).__init__()
self.binary = binary
- # Guess which arch we're running. 10 = len('0x') + 8 hex digits.
- if len(addr) > 10:
- self.arch = 'x86_64'
- else:
- self.arch = 'i386'
+ self.arch = guess_arch(addr)
self.open_atos()
def open_atos(self):
@@ -318,23 +340,49 @@ class BreakpadSymbolizer(Symbolizer):
class SymbolizationLoop(object):
- def __init__(self, binary_name_filter=None):
+ def __init__(self, binary_name_filter=None, dsym_hint_producer=None):
# Used by clients who may want to supply a different binary name.
# E.g. in Chrome several binaries may share a single .dSYM.
self.binary_name_filter = binary_name_filter
+ self.dsym_hint_producer = dsym_hint_producer
self.system = os.uname()[0]
- if self.system in ['Linux', 'Darwin']:
- self.llvm_symbolizer = LLVMSymbolizerFactory(self.system)
- else:
+ if self.system not in ['Linux', 'Darwin', 'FreeBSD']:
raise Exception('Unknown system')
+ self.llvm_symbolizers = {}
+ self.last_llvm_symbolizer = None
+ self.dsym_hints = set([])
+ self.frame_no = 0
def symbolize_address(self, addr, binary, offset):
+ # On non-Darwin (i.e. on platforms without .dSYM debug info) always use
+ # a single symbolizer binary.
+ # On Darwin, if the dsym hint producer is present:
+ # 1. check whether we've seen this binary already; if so,
+ # use |llvm_symbolizers[binary]|, which has already loaded the debug
+ # info for this binary (might not be the case for
+ # |last_llvm_symbolizer|);
+ # 2. otherwise check if we've seen all the hints for this binary already;
+ # if so, reuse |last_llvm_symbolizer| which has the full set of hints;
+ # 3. otherwise create a new symbolizer and pass all currently known
+ # .dSYM hints to it.
+ if not binary in self.llvm_symbolizers:
+ use_last_symbolizer = True
+ if self.system == 'Darwin' and self.dsym_hint_producer:
+ dsym_hints_for_binary = set(self.dsym_hint_producer(binary))
+ use_last_symbolizer = bool(dsym_hints_for_binary - self.dsym_hints)
+ self.dsym_hints |= dsym_hints_for_binary
+ if self.last_llvm_symbolizer and use_last_symbolizer:
+ self.llvm_symbolizers[binary] = self.last_llvm_symbolizer
+ else:
+ self.last_llvm_symbolizer = LLVMSymbolizerFactory(
+ self.system, guess_arch(addr), self.dsym_hints)
+ self.llvm_symbolizers[binary] = self.last_llvm_symbolizer
# Use the chain of symbolizers:
# Breakpad symbolizer -> LLVM symbolizer -> addr2line/atos
# (fall back to next symbolizer if the previous one fails).
if not binary in symbolizers:
symbolizers[binary] = ChainSymbolizer(
- [BreakpadSymbolizerFactory(binary), self.llvm_symbolizer])
+ [BreakpadSymbolizerFactory(binary), self.llvm_symbolizers[binary]])
result = symbolizers[binary].symbolize(addr, binary, offset)
if result is None:
# Initialize system symbolizer only if other symbolizers failed.
@@ -345,48 +393,77 @@ class SymbolizationLoop(object):
assert result
return result
- def print_symbolized_lines(self, symbolized_lines):
+ def get_symbolized_lines(self, symbolized_lines):
if not symbolized_lines:
- print self.current_line
+ return [self.current_line]
else:
+ result = []
for symbolized_frame in symbolized_lines:
- print ' #' + str(self.frame_no) + ' ' + symbolized_frame.rstrip()
+ result.append(' #%s %s' % (str(self.frame_no), symbolized_frame.rstrip()))
self.frame_no += 1
+ return result
- def process_stdin(self):
+ def process_logfile(self):
self.frame_no = 0
while True:
- line = sys.stdin.readline()
+ line = logfile.readline()
if not line:
break
- self.current_line = line.rstrip()
- #0 0x7f6e35cf2e45 (/blah/foo.so+0x11fe45)
- stack_trace_line_format = (
- '^( *#([0-9]+) *)(0x[0-9a-f]+) *\((.*)\+(0x[0-9a-f]+)\)')
- match = re.match(stack_trace_line_format, line)
- if not match:
- print self.current_line
- continue
- if DEBUG:
- print line
- _, frameno_str, addr, binary, offset = match.groups()
- if frameno_str == '0':
- # Assume that frame #0 is the first frame of new stack trace.
- self.frame_no = 0
- original_binary = binary
- if self.binary_name_filter:
- binary = self.binary_name_filter(binary)
- symbolized_line = self.symbolize_address(addr, binary, offset)
- if not symbolized_line:
- if original_binary != binary:
- symbolized_line = self.symbolize_address(addr, binary, offset)
- self.print_symbolized_lines(symbolized_line)
+ processed = self.process_line(line)
+ print '\n'.join(processed)
+
+ def process_line(self, line):
+ self.current_line = line.rstrip()
+ #0 0x7f6e35cf2e45 (/blah/foo.so+0x11fe45)
+ stack_trace_line_format = (
+ '^( *#([0-9]+) *)(0x[0-9a-f]+) *\((.*)\+(0x[0-9a-f]+)\)')
+ match = re.match(stack_trace_line_format, line)
+ if not match:
+ return [self.current_line]
+ if DEBUG:
+ print line
+ _, frameno_str, addr, binary, offset = match.groups()
+ if frameno_str == '0':
+ # Assume that frame #0 is the first frame of new stack trace.
+ self.frame_no = 0
+ original_binary = binary
+ if self.binary_name_filter:
+ binary = self.binary_name_filter(binary)
+ symbolized_line = self.symbolize_address(addr, binary, offset)
+ if not symbolized_line:
+ if original_binary != binary:
+ symbolized_line = self.symbolize_address(addr, binary, offset)
+ return self.get_symbolized_lines(symbolized_line)
if __name__ == '__main__':
- opts, args = getopt.getopt(sys.argv[1:], "d", ["demangle"])
- for o, a in opts:
- if o in ("-d", "--demangle"):
- demangle = True;
- loop = SymbolizationLoop()
- loop.process_stdin()
+ parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter,
+ description='ASan symbolization script',
+ epilog='''Example of use:
+ asan_symbolize.py -c "$HOME/opt/cross/bin/arm-linux-gnueabi-" -s "$HOME/SymbolFiles" < asan.log''')
+ parser.add_argument('path_to_cut', nargs='*',
+ help='pattern to be cut from the result file path ')
+ parser.add_argument('-d','--demangle', action='store_true',
+ help='demangle function names')
+ parser.add_argument('-s', metavar='SYSROOT',
+ help='set path to sysroot for sanitized binaries')
+ parser.add_argument('-c', metavar='CROSS_COMPILE',
+ help='set prefix for binutils')
+ parser.add_argument('-l','--logfile', default=sys.stdin, type=argparse.FileType('r'),
+ help='set log file name to parse, default is stdin')
+ args = parser.parse_args()
+ if args.path_to_cut:
+ fix_filename_patterns = args.path_to_cut
+ if args.demangle:
+ demangle = True
+ if args.s:
+ binary_name_filter = sysroot_path_filter
+ sysroot_path = args.s
+ if args.c:
+ binutils_prefix = args.c
+ if args.logfile:
+ logfile = args.logfile
+ else:
+ logfile = sys.stdin
+ loop = SymbolizationLoop(binary_name_filter)
+ loop.process_logfile()
diff --git a/lib/asan/tests/CMakeLists.txt b/lib/asan/tests/CMakeLists.txt
index fc0f1788bd35..7b363714e8a5 100644
--- a/lib/asan/tests/CMakeLists.txt
+++ b/lib/asan/tests/CMakeLists.txt
@@ -15,32 +15,29 @@ include(CompilerRTCompile)
include_directories(..)
include_directories(../..)
-# Use zero-based shadow on Android.
-if(ANDROID)
- set(ASAN_TESTS_USE_ZERO_BASE_SHADOW TRUE)
-else()
- set(ASAN_TESTS_USE_ZERO_BASE_SHADOW FALSE)
-endif()
-
set(ASAN_UNITTEST_HEADERS
asan_mac_test.h
asan_test_config.h
asan_test_utils.h)
set(ASAN_UNITTEST_COMMON_CFLAGS
- ${COMPILER_RT_GTEST_INCLUDE_CFLAGS}
+ ${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/asan
-I${COMPILER_RT_SOURCE_DIR}/lib/sanitizer_common/tests
- -Wall
+ -fno-rtti
+ -O2
-Wno-format
- -Werror
- -Werror=sign-compare
- -g
- -O2)
-if(SUPPORTS_NO_VARIADIC_MACROS_FLAG)
- list(APPEND ASAN_UNITTEST_COMMON_CFLAGS -Wno-variadic-macros)
+ -Werror=sign-compare)
+append_list_if(COMPILER_RT_HAS_WVARIADIC_MACROS_FLAG -Wno-variadic-macros ASAN_UNITTEST_COMMON_CFLAGS)
+
+# -gline-tables-only must be enough for ASan, so use it if possible.
+if(COMPILER_RT_TEST_COMPILER_ID MATCHES "Clang")
+ list(APPEND ASAN_UNITTEST_COMMON_CFLAGS -gline-tables-only)
+else()
+ list(APPEND ASAN_UNITTEST_COMMON_CFLAGS -g)
endif()
# Use -D instead of definitions to please custom compile command.
@@ -48,79 +45,91 @@ list(APPEND ASAN_UNITTEST_COMMON_CFLAGS
-DASAN_HAS_BLACKLIST=1
-DASAN_HAS_EXCEPTIONS=1
-DASAN_UAR=0)
-if(ANDROID)
- list(APPEND ASAN_UNITTEST_COMMON_CFLAGS
- -DASAN_FLEXIBLE_MAPPING_AND_OFFSET=0
- -DASAN_NEEDS_SEGV=0)
-else()
- list(APPEND ASAN_UNITTEST_COMMON_CFLAGS
- -DASAN_FLEXIBLE_MAPPING_AND_OFFSET=1
- -DASAN_NEEDS_SEGV=1)
-endif()
set(ASAN_BLACKLIST_FILE "${CMAKE_CURRENT_SOURCE_DIR}/asan_test.ignore")
set(ASAN_UNITTEST_INSTRUMENTED_CFLAGS
${ASAN_UNITTEST_COMMON_CFLAGS}
-fsanitize=address
"-fsanitize-blacklist=${ASAN_BLACKLIST_FILE}"
- -mllvm -asan-stack=1
- -mllvm -asan-globals=1
- -mllvm -asan-mapping-scale=0 # default will be used
- -mllvm -asan-mapping-offset-log=-1 # default will be used
)
-if(ASAN_TESTS_USE_ZERO_BASE_SHADOW)
- list(APPEND ASAN_UNITTEST_INSTRUMENTED_CFLAGS
- -fsanitize-address-zero-base-shadow)
+if(CAN_TARGET_x86_64 OR CAN_TARGET_i386)
+ list(APPEND ASAN_UNITTEST_INSTRUMENTED_CFLAGS -mllvm -asan-instrument-assembly)
+endif()
+
+if(NOT MSVC)
+ list(APPEND ASAN_UNITTEST_COMMON_LINKFLAGS --driver-mode=g++)
+endif()
+
+# x86_64 FreeBSD 9.2 additionally requires libc++ to build the tests.
+if(CMAKE_SYSTEM MATCHES "FreeBSD-9.2-RELEASE")
+ list(APPEND ASAN_UNITTEST_COMMON_LINKFLAGS "-lc++")
endif()
-# Unit tests require libstdc++.
-set(ASAN_UNITTEST_COMMON_LINKFLAGS -lstdc++)
# Unit tests on Mac depend on Foundation.
if(APPLE)
list(APPEND ASAN_UNITTEST_COMMON_LINKFLAGS -framework Foundation)
endif()
-if(ASAN_TESTS_USE_ZERO_BASE_SHADOW)
+if(ANDROID)
list(APPEND ASAN_UNITTEST_COMMON_LINKFLAGS -pie)
endif()
set(ASAN_UNITTEST_INSTRUMENTED_LINKFLAGS
${ASAN_UNITTEST_COMMON_LINKFLAGS})
-# On Android, we link with ASan runtime manually. On other platforms we depend
-# on Clang driver behavior, passing -fsanitize=address flag.
-if(NOT ANDROID)
- list(APPEND ASAN_UNITTEST_INSTRUMENTED_LINKFLAGS -fsanitize=address)
-endif()
+list(APPEND ASAN_UNITTEST_INSTRUMENTED_LINKFLAGS -fsanitize=address)
-set(ASAN_UNITTEST_NOINST_LINKFLAGS
- ${ASAN_UNITTEST_COMMON_LINKFLAGS}
- -ldl -lm)
-if(NOT ANDROID)
- list(APPEND ASAN_UNITTEST_NOINST_LINKFLAGS -lpthread)
-endif()
+set(ASAN_DYNAMIC_UNITTEST_INSTRUMENTED_LINKFLAGS
+ ${ASAN_UNITTEST_INSTRUMENTED_LINKFLAGS}
+ -shared-libasan)
+
+set(ASAN_UNITTEST_INSTRUMENTED_LIBS)
+# NDK r10 requires -latomic almost always.
+append_list_if(ANDROID atomic ASAN_UNITTEST_INSTRUMENTED_LIBS)
+
+set(ASAN_UNITTEST_NOINST_LINKFLAGS ${ASAN_UNITTEST_COMMON_LINKFLAGS})
+append_list_if(COMPILER_RT_HAS_LIBM -lm ASAN_UNITTEST_NOINST_LINKFLAGS)
+append_list_if(COMPILER_RT_HAS_LIBDL -ldl ASAN_UNITTEST_NOINST_LINKFLAGS)
+append_list_if(COMPILER_RT_HAS_LIBPTHREAD -pthread ASAN_UNITTEST_NOINST_LINKFLAGS)
+append_list_if(COMPILER_RT_HAS_LIBPTHREAD -pthread
+ ASAN_DYNAMIC_UNITTEST_INSTRUMENTED_LINKFLAGS)
+
+# TODO(eugenis): move all -l flags above to _LIBS?
+set(ASAN_UNITTEST_NOINST_LIBS)
+append_list_if(ANDROID log ASAN_UNITTEST_NOINST_LIBS)
+# NDK r10 requires -latomic almost always.
+append_list_if(ANDROID atomic ASAN_UNITTEST_NOINST_LIBS)
# Compile source for the given architecture, using compiler
# options in ${ARGN}, and add it to the object list.
-macro(asan_compile obj_list source arch)
+macro(asan_compile obj_list source arch kind)
get_filename_component(basename ${source} NAME)
- set(output_obj "${obj_list}.${basename}.${arch}.o")
+ set(output_obj "${obj_list}.${basename}.${arch}${kind}.o")
get_target_flags_for_arch(${arch} TARGET_CFLAGS)
+ set(COMPILE_DEPS ${ASAN_UNITTEST_HEADERS} ${ASAN_BLACKLIST_FILE})
+ if(NOT COMPILER_RT_STANDALONE_BUILD)
+ list(APPEND COMPILE_DEPS gtest asan)
+ endif()
clang_compile(${output_obj} ${source}
CFLAGS ${ARGN} ${TARGET_CFLAGS}
- DEPS gtest asan_runtime_libraries
- ${ASAN_UNITTEST_HEADERS}
- ${ASAN_BLACKLIST_FILE})
+ DEPS ${COMPILE_DEPS})
list(APPEND ${obj_list} ${output_obj})
endmacro()
# Link ASan unit test for a given architecture from a set
# of objects in with given linker flags.
-macro(add_asan_test test_suite test_name arch)
+macro(add_asan_test test_suite test_name arch kind)
parse_arguments(TEST "OBJECTS;LINKFLAGS" "WITH_TEST_RUNTIME" ${ARGN})
get_target_flags_for_arch(${arch} TARGET_LINK_FLAGS)
- set(TEST_DEPS asan_runtime_libraries ${TEST_OBJECTS})
+ set(TEST_DEPS ${TEST_OBJECTS})
+ if(NOT COMPILER_RT_STANDALONE_BUILD)
+ list(APPEND TEST_DEPS asan)
+ endif()
if(TEST_WITH_TEST_RUNTIME)
list(APPEND TEST_DEPS ${ASAN_TEST_RUNTIME})
- list(APPEND TEST_OBJECTS lib${ASAN_TEST_RUNTIME}.a)
+ if(NOT MSVC)
+ list(APPEND TEST_OBJECTS lib${ASAN_TEST_RUNTIME}.a)
+ else()
+ list(APPEND TEST_OBJECTS ${ASAN_TEST_RUNTIME}.lib)
+ endif()
endif()
add_compiler_rt_test(${test_suite} ${test_name}
OBJECTS ${TEST_OBJECTS}
@@ -144,6 +153,7 @@ set(ASAN_NOINST_TEST_SOURCES
set(ASAN_INST_TEST_SOURCES
${COMPILER_RT_GTEST_SOURCE}
+ asan_asm_test.cc
asan_globals_test.cc
asan_interface_test.cc
asan_test.cc
@@ -157,27 +167,32 @@ endif()
set(ASAN_BENCHMARKS_SOURCES
${COMPILER_RT_GTEST_SOURCE}
- asan_benchmarks_test.cc)
+ asan_benchmarks_test.cc)
# Adds ASan unit tests and benchmarks for architecture.
-macro(add_asan_tests_for_arch arch)
+macro(add_asan_tests_for_arch_and_kind arch kind)
# Instrumented tests.
set(ASAN_INST_TEST_OBJECTS)
foreach(src ${ASAN_INST_TEST_SOURCES})
- asan_compile(ASAN_INST_TEST_OBJECTS ${src} ${arch}
- ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS})
+ asan_compile(ASAN_INST_TEST_OBJECTS ${src} ${arch} ${kind}
+ ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS} ${ARGN})
endforeach()
if (APPLE)
# Add Mac-specific helper.
- asan_compile(ASAN_INST_TEST_OBJECTS asan_mac_test_helpers.mm ${arch}
- ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS} -ObjC)
+ asan_compile(ASAN_INST_TEST_OBJECTS asan_mac_test_helpers.mm ${arch} ${kind}
+ ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS} -ObjC ${ARGN})
endif()
- add_asan_test(AsanUnitTests "Asan-${arch}-Test" ${arch}
+ add_asan_test(AsanUnitTests "Asan-${arch}${kind}-Test" ${arch} ${kind}
OBJECTS ${ASAN_INST_TEST_OBJECTS}
LINKFLAGS ${ASAN_UNITTEST_INSTRUMENTED_LINKFLAGS})
+ if(COMPILER_RT_BUILD_SHARED_ASAN)
+ add_asan_test(AsanUnitTests "Asan-${arch}${kind}-Dynamic-Test" ${arch} ${kind}
+ OBJECTS ${ASAN_INST_TEST_OBJECTS}
+ LINKFLAGS ${ASAN_DYNAMIC_UNITTEST_INSTRUMENTED_LINKFLAGS})
+ endif()
# Add static ASan runtime that will be linked with uninstrumented tests.
- set(ASAN_TEST_RUNTIME RTAsanTest.${arch})
+ set(ASAN_TEST_RUNTIME RTAsanTest.${arch}${kind})
if(APPLE)
set(ASAN_TEST_RUNTIME_OBJECTS
$<TARGET_OBJECTS:RTAsan.osx>
@@ -187,10 +202,14 @@ macro(add_asan_tests_for_arch arch)
else()
set(ASAN_TEST_RUNTIME_OBJECTS
$<TARGET_OBJECTS:RTAsan.${arch}>
+ $<TARGET_OBJECTS:RTAsan_cxx.${arch}>
$<TARGET_OBJECTS:RTInterception.${arch}>
- $<TARGET_OBJECTS:RTLSanCommon.${arch}>
$<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
$<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>)
+ if(NOT WIN32)
+ list(APPEND ASAN_TEST_RUNTIME_OBJECTS
+ $<TARGET_OBJECTS:RTLSanCommon.${arch}>)
+ endif()
endif()
add_library(${ASAN_TEST_RUNTIME} STATIC ${ASAN_TEST_RUNTIME_OBJECTS})
set_target_properties(${ASAN_TEST_RUNTIME} PROPERTIES
@@ -198,10 +217,10 @@ macro(add_asan_tests_for_arch arch)
# Uninstrumented tests.
set(ASAN_NOINST_TEST_OBJECTS)
foreach(src ${ASAN_NOINST_TEST_SOURCES})
- asan_compile(ASAN_NOINST_TEST_OBJECTS ${src} ${arch}
- ${ASAN_UNITTEST_COMMON_CFLAGS})
+ asan_compile(ASAN_NOINST_TEST_OBJECTS ${src} ${arch} ${kind}
+ ${ASAN_UNITTEST_COMMON_CFLAGS} ${ARGN})
endforeach()
- add_asan_test(AsanUnitTests "Asan-${arch}-Noinst-Test" ${arch}
+ add_asan_test(AsanUnitTests "Asan-${arch}${kind}-Noinst-Test" ${arch} ${kind}
OBJECTS ${ASAN_NOINST_TEST_OBJECTS}
LINKFLAGS ${ASAN_UNITTEST_NOINST_LINKFLAGS}
WITH_TEST_RUNTIME)
@@ -209,45 +228,53 @@ macro(add_asan_tests_for_arch arch)
# Benchmarks.
set(ASAN_BENCHMARKS_OBJECTS)
foreach(src ${ASAN_BENCHMARKS_SOURCES})
- asan_compile(ASAN_BENCHMARKS_OBJECTS ${src} ${arch}
- ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS})
+ asan_compile(ASAN_BENCHMARKS_OBJECTS ${src} ${arch} ${kind}
+ ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS} ${ARGN})
endforeach()
- add_asan_test(AsanBenchmarks "Asan-${arch}-Benchmark" ${arch}
+ add_asan_test(AsanBenchmarks "Asan-${arch}${kind}-Benchmark" ${arch} ${kind}
OBJECTS ${ASAN_BENCHMARKS_OBJECTS}
LINKFLAGS ${ASAN_UNITTEST_INSTRUMENTED_LINKFLAGS})
+ if(COMPILER_RT_BUILD_SHARED_ASAN)
+ add_asan_test(AsanBenchmarks "Asan-${arch}${kind}-Dynamic-Benchmark" ${arch} ${kind}
+ OBJECTS ${ASAN_BENCHMARKS_OBJECTS}
+ LINKFLAGS ${ASAN_DYNAMIC_UNITTEST_INSTRUMENTED_LINKFLAGS})
+ endif()
endmacro()
-if(COMPILER_RT_CAN_EXECUTE_TESTS)
+if(COMPILER_RT_CAN_EXECUTE_TESTS AND NOT ANDROID)
foreach(arch ${ASAN_SUPPORTED_ARCH})
- add_asan_tests_for_arch(${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)
endforeach()
endif()
if(ANDROID)
- # We assume that unit tests on Android are built in a build
- # tree with fresh Clang as a host compiler.
-
- # Test w/o ASan instrumentation. Link it with ASan statically.
- add_executable(AsanNoinstTest
- $<TARGET_OBJECTS:RTAsan.arm.android>
- $<TARGET_OBJECTS:RTInterception.arm.android>
- $<TARGET_OBJECTS:RTSanitizerCommon.arm.android>
- ${COMPILER_RT_GTEST_SOURCE}
- ${ASAN_NOINST_TEST_SOURCES})
- set_target_compile_flags(AsanNoinstTest ${ASAN_UNITTEST_COMMON_CFLAGS})
- set_target_link_flags(AsanNoinstTest ${ASAN_UNITTEST_NOINST_LINKFLAGS})
-
- # Test with ASan instrumentation. Link with ASan dynamic runtime.
- add_executable(AsanTest
- ${COMPILER_RT_GTEST_SOURCE}
- ${ASAN_INST_TEST_SOURCES})
- set_target_compile_flags(AsanTest ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS})
- set_target_link_flags(AsanTest ${ASAN_UNITTEST_INSTRUMENTED_LINKFLAGS})
- target_link_libraries(AsanTest clang_rt.asan-arm-android)
-
- # Setup correct output directory and link flags.
- set_target_properties(AsanNoinstTest AsanTest PROPERTIES
- RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
- # Add unit test to test suite.
- add_dependencies(AsanUnitTests AsanNoinstTest AsanTest)
+ foreach(arch ${ASAN_SUPPORTED_ARCH})
+ # Test w/o ASan instrumentation. Link it with ASan statically.
+ add_executable(AsanNoinstTest # FIXME: .arch?
+ $<TARGET_OBJECTS:RTAsan.${arch}>
+ $<TARGET_OBJECTS:RTInterception.${arch}>
+ $<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
+ $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>
+ ${COMPILER_RT_GTEST_SOURCE}
+ ${ASAN_NOINST_TEST_SOURCES})
+ set_target_compile_flags(AsanNoinstTest ${ASAN_UNITTEST_COMMON_CFLAGS})
+ set_target_link_flags(AsanNoinstTest ${ASAN_UNITTEST_NOINST_LINKFLAGS})
+ target_link_libraries(AsanNoinstTest ${ASAN_UNITTEST_NOINST_LIBS})
+
+ # Test with ASan instrumentation. Link with ASan dynamic runtime.
+ add_executable(AsanTest
+ ${COMPILER_RT_GTEST_SOURCE}
+ ${ASAN_INST_TEST_SOURCES})
+ set_target_compile_flags(AsanTest ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS})
+ set_target_link_flags(AsanTest ${ASAN_UNITTEST_INSTRUMENTED_LINKFLAGS})
+ target_link_libraries(AsanTest ${ASAN_UNITTEST_INSTRUMENTED_LIBS})
+
+ # Setup correct output directory and link flags.
+ set_target_properties(AsanNoinstTest AsanTest PROPERTIES
+ RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
+ # Add unit tests to the test suite.
+ add_dependencies(AsanUnitTests AsanNoinstTest AsanTest)
+ endforeach()
endif()
diff --git a/lib/asan/tests/asan_asm_test.cc b/lib/asan/tests/asan_asm_test.cc
new file mode 100644
index 000000000000..1d8b04d611bd
--- /dev/null
+++ b/lib/asan/tests/asan_asm_test.cc
@@ -0,0 +1,267 @@
+//===-- asan_asm_test.cc --------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+//===----------------------------------------------------------------------===//
+#include "asan_test_utils.h"
+
+#if defined(__linux__)
+
+#if defined(__x86_64__) || (defined(__i386__) && defined(__SSE2__))
+
+#include <emmintrin.h>
+
+namespace {
+
+template<typename T> void asm_write(T *ptr, T val);
+template<typename T> T asm_read(T *ptr);
+template<typename T> void asm_rep_movs(T *dst, T *src, size_t n);
+
+} // End of anonymous namespace
+
+#endif // defined(__x86_64__) || (defined(__i386__) && defined(__SSE2__))
+
+#if defined(__x86_64__)
+
+namespace {
+
+#define DECLARE_ASM_WRITE(Type, Size, Mov, Reg) \
+template<> void asm_write<Type>(Type *ptr, Type val) { \
+ __asm__( \
+ Mov " %[val], (%[ptr]) \n\t" \
+ : \
+ : [ptr] "r" (ptr), [val] Reg (val) \
+ : "memory" \
+ ); \
+}
+
+#define DECLARE_ASM_READ(Type, Size, Mov, Reg) \
+template<> Type asm_read<Type>(Type *ptr) { \
+ Type res; \
+ __asm__( \
+ Mov " (%[ptr]), %[res] \n\t" \
+ : [res] Reg (res) \
+ : [ptr] "r" (ptr) \
+ : "memory" \
+ ); \
+ return res; \
+}
+
+#define DECLARE_ASM_REP_MOVS(Type, Movs) \
+ template <> void asm_rep_movs<Type>(Type * dst, Type * src, size_t size) { \
+ __asm__("rep " Movs " \n\t" \
+ : \
+ : "D"(dst), "S"(src), "c"(size) \
+ : "rsi", "rdi", "rcx", "memory"); \
+ }
+
+DECLARE_ASM_WRITE(U8, "8", "movq", "r");
+DECLARE_ASM_READ(U8, "8", "movq", "=r");
+DECLARE_ASM_REP_MOVS(U8, "movsq");
+
+} // End of anonymous namespace
+
+#endif // defined(__x86_64__)
+
+#if defined(__i386__) && defined(__SSE2__)
+
+namespace {
+
+#define DECLARE_ASM_WRITE(Type, Size, Mov, Reg) \
+template<> void asm_write<Type>(Type *ptr, Type val) { \
+ __asm__( \
+ Mov " %[val], (%[ptr]) \n\t" \
+ : \
+ : [ptr] "r" (ptr), [val] Reg (val) \
+ : "memory" \
+ ); \
+}
+
+#define DECLARE_ASM_READ(Type, Size, Mov, Reg) \
+template<> Type asm_read<Type>(Type *ptr) { \
+ Type res; \
+ __asm__( \
+ Mov " (%[ptr]), %[res] \n\t" \
+ : [res] Reg (res) \
+ : [ptr] "r" (ptr) \
+ : "memory" \
+ ); \
+ return res; \
+}
+
+#define DECLARE_ASM_REP_MOVS(Type, Movs) \
+ template <> void asm_rep_movs<Type>(Type * dst, Type * src, size_t size) { \
+ __asm__("rep " Movs " \n\t" \
+ : \
+ : "D"(dst), "S"(src), "c"(size) \
+ : "esi", "edi", "ecx", "memory"); \
+ }
+
+} // End of anonymous namespace
+
+#endif // defined(__i386__) && defined(__SSE2__)
+
+#if defined(__x86_64__) || (defined(__i386__) && defined(__SSE2__))
+
+namespace {
+
+DECLARE_ASM_WRITE(U1, "1", "movb", "r");
+DECLARE_ASM_WRITE(U2, "2", "movw", "r");
+DECLARE_ASM_WRITE(U4, "4", "movl", "r");
+DECLARE_ASM_WRITE(__m128i, "16", "movaps", "x");
+
+DECLARE_ASM_READ(U1, "1", "movb", "=r");
+DECLARE_ASM_READ(U2, "2", "movw", "=r");
+DECLARE_ASM_READ(U4, "4", "movl", "=r");
+DECLARE_ASM_READ(__m128i, "16", "movaps", "=x");
+
+DECLARE_ASM_REP_MOVS(U1, "movsb");
+DECLARE_ASM_REP_MOVS(U2, "movsw");
+DECLARE_ASM_REP_MOVS(U4, "movsl");
+
+template<typename T> void TestAsmWrite(const char *DeathPattern) {
+ T *buf = new T;
+ EXPECT_DEATH(asm_write(&buf[1], static_cast<T>(0)), DeathPattern);
+ T var = 0x12;
+ asm_write(&var, static_cast<T>(0x21));
+ ASSERT_EQ(static_cast<T>(0x21), var);
+ delete buf;
+}
+
+template<> void TestAsmWrite<__m128i>(const char *DeathPattern) {
+ char *buf = new char[16];
+ char *p = buf + 16;
+ if (((uintptr_t) p % 16) != 0)
+ p = buf + 8;
+ assert(((uintptr_t) p % 16) == 0);
+ __m128i val = _mm_set1_epi16(0x1234);
+ EXPECT_DEATH(asm_write<__m128i>((__m128i*) p, val), DeathPattern);
+ __m128i var = _mm_set1_epi16(0x4321);
+ asm_write(&var, val);
+ ASSERT_EQ(0x1234, _mm_extract_epi16(var, 0));
+ delete [] buf;
+}
+
+template<typename T> void TestAsmRead(const char *DeathPattern) {
+ T *buf = new T;
+ EXPECT_DEATH(asm_read(&buf[1]), DeathPattern);
+ T var = 0x12;
+ ASSERT_EQ(static_cast<T>(0x12), asm_read(&var));
+ delete buf;
+}
+
+template<> void TestAsmRead<__m128i>(const char *DeathPattern) {
+ char *buf = new char[16];
+ char *p = buf + 16;
+ if (((uintptr_t) p % 16) != 0)
+ p = buf + 8;
+ assert(((uintptr_t) p % 16) == 0);
+ EXPECT_DEATH(asm_read<__m128i>((__m128i*) p), DeathPattern);
+ __m128i val = _mm_set1_epi16(0x1234);
+ ASSERT_EQ(0x1234, _mm_extract_epi16(asm_read(&val), 0));
+ delete [] buf;
+}
+
+U4 AsmLoad(U4 *a) {
+ U4 r;
+ __asm__("movl (%[a]), %[r] \n\t" : [r] "=r" (r) : [a] "r" (a) : "memory");
+ return r;
+}
+
+void AsmStore(U4 r, U4 *a) {
+ __asm__("movl %[r], (%[a]) \n\t" : : [a] "r" (a), [r] "r" (r) : "memory");
+}
+
+template <typename T>
+void TestAsmRepMovs(const char *DeathPatternRead,
+ const char *DeathPatternWrite) {
+ T src_good[4] = { 0x0, 0x1, 0x2, 0x3 };
+ T dst_good[4] = {};
+ asm_rep_movs(dst_good, src_good, 4);
+ ASSERT_EQ(static_cast<T>(0x0), dst_good[0]);
+ ASSERT_EQ(static_cast<T>(0x1), dst_good[1]);
+ ASSERT_EQ(static_cast<T>(0x2), dst_good[2]);
+ ASSERT_EQ(static_cast<T>(0x3), dst_good[3]);
+
+ T dst_bad[3];
+ EXPECT_DEATH(asm_rep_movs(dst_bad, src_good, 4), DeathPatternWrite);
+
+ T src_bad[3] = { 0x0, 0x1, 0x2 };
+ EXPECT_DEATH(asm_rep_movs(dst_good, src_bad, 4), DeathPatternRead);
+
+ T* dp = dst_bad + 4;
+ T* sp = src_bad + 4;
+ asm_rep_movs(dp, sp, 0);
+}
+
+} // End of anonymous namespace
+
+TEST(AddressSanitizer, asm_load_store) {
+ U4* buf = new U4[2];
+ EXPECT_DEATH(AsmLoad(&buf[3]), "READ of size 4");
+ EXPECT_DEATH(AsmStore(0x1234, &buf[3]), "WRITE of size 4");
+ delete [] buf;
+}
+
+TEST(AddressSanitizer, asm_rw) {
+ TestAsmWrite<U1>("WRITE of size 1");
+ TestAsmWrite<U2>("WRITE of size 2");
+ TestAsmWrite<U4>("WRITE of size 4");
+#if defined(__x86_64__)
+ TestAsmWrite<U8>("WRITE of size 8");
+#endif // defined(__x86_64__)
+ TestAsmWrite<__m128i>("WRITE of size 16");
+
+ TestAsmRead<U1>("READ of size 1");
+ TestAsmRead<U2>("READ of size 2");
+ TestAsmRead<U4>("READ of size 4");
+#if defined(__x86_64__)
+ TestAsmRead<U8>("READ of size 8");
+#endif // defined(__x86_64__)
+ TestAsmRead<__m128i>("READ of size 16");
+}
+
+TEST(AddressSanitizer, asm_flags) {
+ long magic = 0x1234;
+ long r = 0x0;
+
+#if defined(__x86_64__)
+ __asm__("xorq %%rax, %%rax \n\t"
+ "movq (%[p]), %%rax \n\t"
+ "sete %%al \n\t"
+ "movzbq %%al, %[r] \n\t"
+ : [r] "=r"(r)
+ : [p] "r"(&magic)
+ : "rax", "memory");
+#else
+ __asm__("xorl %%eax, %%eax \n\t"
+ "movl (%[p]), %%eax \n\t"
+ "sete %%al \n\t"
+ "movzbl %%al, %[r] \n\t"
+ : [r] "=r"(r)
+ : [p] "r"(&magic)
+ : "eax", "memory");
+#endif // defined(__x86_64__)
+
+ ASSERT_EQ(0x1, r);
+}
+
+TEST(AddressSanitizer, asm_rep_movs) {
+ TestAsmRepMovs<U1>("READ of size 1", "WRITE of size 1");
+ TestAsmRepMovs<U2>("READ of size 2", "WRITE of size 2");
+ TestAsmRepMovs<U4>("READ of size 4", "WRITE of size 4");
+#if defined(__x86_64__)
+ TestAsmRepMovs<U8>("READ of size 8", "WRITE of size 8");
+#endif // defined(__x86_64__)
+}
+
+#endif // defined(__x86_64__) || (defined(__i386__) && defined(__SSE2__))
+
+#endif // defined(__linux__)
diff --git a/lib/asan/tests/asan_fake_stack_test.cc b/lib/asan/tests/asan_fake_stack_test.cc
index 1c98125eb45e..516142f0c3b7 100644
--- a/lib/asan/tests/asan_fake_stack_test.cc
+++ b/lib/asan/tests/asan_fake_stack_test.cc
@@ -59,14 +59,16 @@ TEST(FakeStack, FlagsOffset) {
}
}
+#if !defined(_WIN32) // FIXME: Fails due to OOM on Windows.
TEST(FakeStack, CreateDestroy) {
for (int i = 0; i < 1000; i++) {
for (uptr stack_size_log = 20; stack_size_log <= 22; stack_size_log++) {
FakeStack *fake_stack = FakeStack::Create(stack_size_log);
- fake_stack->Destroy();
+ fake_stack->Destroy(0);
}
}
}
+#endif
TEST(FakeStack, ModuloNumberOfFrames) {
EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 0, 0), 0U);
@@ -98,7 +100,7 @@ TEST(FakeStack, GetFrame) {
EXPECT_EQ(base + 0*stack_size + 64 * 7, fs->GetFrame(stack_size_log, 0, 7U));
EXPECT_EQ(base + 1*stack_size + 128 * 3, fs->GetFrame(stack_size_log, 1, 3U));
EXPECT_EQ(base + 2*stack_size + 256 * 5, fs->GetFrame(stack_size_log, 2, 5U));
- fs->Destroy();
+ fs->Destroy(0);
}
TEST(FakeStack, Allocate) {
@@ -127,7 +129,7 @@ TEST(FakeStack, Allocate) {
fs->Deallocate(reinterpret_cast<uptr>(it->first), it->second);
}
}
- fs->Destroy();
+ fs->Destroy(0);
}
static void RecursiveFunction(FakeStack *fs, int depth) {
@@ -144,7 +146,7 @@ TEST(FakeStack, RecursiveStressTest) {
const uptr stack_size_log = 16;
FakeStack *fs = FakeStack::Create(stack_size_log);
RecursiveFunction(fs, 22); // with 26 runs for 2-3 seconds.
- fs->Destroy();
+ fs->Destroy(0);
}
} // namespace __asan
diff --git a/lib/asan/tests/asan_interface_test.cc b/lib/asan/tests/asan_interface_test.cc
index f36679012f27..50fdf1119f0b 100644
--- a/lib/asan/tests/asan_interface_test.cc
+++ b/lib/asan/tests/asan_interface_test.cc
@@ -11,18 +11,19 @@
//
//===----------------------------------------------------------------------===//
#include "asan_test_utils.h"
-#include "sanitizer/asan_interface.h"
+#include <sanitizer/allocator_interface.h>
+#include <sanitizer/asan_interface.h>
TEST(AddressSanitizerInterface, GetEstimatedAllocatedSize) {
- EXPECT_EQ(0U, __asan_get_estimated_allocated_size(0));
+ EXPECT_EQ(0U, __sanitizer_get_estimated_allocated_size(0));
const size_t sizes[] = { 1, 30, 1<<30 };
for (size_t i = 0; i < 3; i++) {
- EXPECT_EQ(sizes[i], __asan_get_estimated_allocated_size(sizes[i]));
+ EXPECT_EQ(sizes[i], __sanitizer_get_estimated_allocated_size(sizes[i]));
}
}
static const char* kGetAllocatedSizeErrorMsg =
- "attempting to call __asan_get_allocated_size()";
+ "attempting to call __sanitizer_get_allocated_size";
TEST(AddressSanitizerInterface, GetAllocatedSizeAndOwnershipTest) {
const size_t kArraySize = 100;
@@ -31,38 +32,41 @@ TEST(AddressSanitizerInterface, GetAllocatedSizeAndOwnershipTest) {
// Allocated memory is owned by allocator. Allocated size should be
// equal to requested size.
- EXPECT_EQ(true, __asan_get_ownership(array));
- EXPECT_EQ(kArraySize, __asan_get_allocated_size(array));
- EXPECT_EQ(true, __asan_get_ownership(int_ptr));
- EXPECT_EQ(sizeof(int), __asan_get_allocated_size(int_ptr));
+ EXPECT_EQ(true, __sanitizer_get_ownership(array));
+ EXPECT_EQ(kArraySize, __sanitizer_get_allocated_size(array));
+ EXPECT_EQ(true, __sanitizer_get_ownership(int_ptr));
+ EXPECT_EQ(sizeof(int), __sanitizer_get_allocated_size(int_ptr));
// We cannot call GetAllocatedSize from the memory we didn't map,
// and from the interior pointers (not returned by previous malloc).
void *wild_addr = (void*)0x1;
- EXPECT_FALSE(__asan_get_ownership(wild_addr));
- EXPECT_DEATH(__asan_get_allocated_size(wild_addr), kGetAllocatedSizeErrorMsg);
- EXPECT_FALSE(__asan_get_ownership(array + kArraySize / 2));
- EXPECT_DEATH(__asan_get_allocated_size(array + kArraySize / 2),
+ EXPECT_FALSE(__sanitizer_get_ownership(wild_addr));
+ EXPECT_DEATH(__sanitizer_get_allocated_size(wild_addr),
+ kGetAllocatedSizeErrorMsg);
+ EXPECT_FALSE(__sanitizer_get_ownership(array + kArraySize / 2));
+ EXPECT_DEATH(__sanitizer_get_allocated_size(array + kArraySize / 2),
kGetAllocatedSizeErrorMsg);
- // NULL is not owned, but is a valid argument for __asan_get_allocated_size().
- EXPECT_FALSE(__asan_get_ownership(NULL));
- EXPECT_EQ(0U, __asan_get_allocated_size(NULL));
+ // NULL is not owned, but is a valid argument for
+ // __sanitizer_get_allocated_size().
+ EXPECT_FALSE(__sanitizer_get_ownership(NULL));
+ EXPECT_EQ(0U, __sanitizer_get_allocated_size(NULL));
// When memory is freed, it's not owned, and call to GetAllocatedSize
// is forbidden.
free(array);
- EXPECT_FALSE(__asan_get_ownership(array));
- EXPECT_DEATH(__asan_get_allocated_size(array), kGetAllocatedSizeErrorMsg);
+ EXPECT_FALSE(__sanitizer_get_ownership(array));
+ EXPECT_DEATH(__sanitizer_get_allocated_size(array),
+ kGetAllocatedSizeErrorMsg);
delete int_ptr;
void *zero_alloc = Ident(malloc(0));
if (zero_alloc != 0) {
// If malloc(0) is not null, this pointer is owned and should have valid
// allocated size.
- EXPECT_TRUE(__asan_get_ownership(zero_alloc));
+ EXPECT_TRUE(__sanitizer_get_ownership(zero_alloc));
// Allocated size is 0 or 1 depending on the allocator used.
- EXPECT_LT(__asan_get_allocated_size(zero_alloc), 2U);
+ EXPECT_LT(__sanitizer_get_allocated_size(zero_alloc), 2U);
}
free(zero_alloc);
}
@@ -71,14 +75,14 @@ TEST(AddressSanitizerInterface, GetCurrentAllocatedBytesTest) {
size_t before_malloc, after_malloc, after_free;
char *array;
const size_t kMallocSize = 100;
- before_malloc = __asan_get_current_allocated_bytes();
+ before_malloc = __sanitizer_get_current_allocated_bytes();
array = Ident((char*)malloc(kMallocSize));
- after_malloc = __asan_get_current_allocated_bytes();
+ after_malloc = __sanitizer_get_current_allocated_bytes();
EXPECT_EQ(before_malloc + kMallocSize, after_malloc);
free(array);
- after_free = __asan_get_current_allocated_bytes();
+ after_free = __sanitizer_get_current_allocated_bytes();
EXPECT_EQ(before_malloc, after_free);
}
@@ -88,11 +92,11 @@ TEST(AddressSanitizerInterface, GetHeapSizeTest) {
// otherwise it will be stuck in quarantine instead of being unmaped.
static const size_t kLargeMallocSize = (1 << 28) + 1; // 256M
free(Ident(malloc(kLargeMallocSize))); // Drain quarantine.
- size_t old_heap_size = __asan_get_heap_size();
+ size_t old_heap_size = __sanitizer_get_heap_size();
for (int i = 0; i < 3; i++) {
// fprintf(stderr, "allocating %zu bytes:\n", kLargeMallocSize);
free(Ident(malloc(kLargeMallocSize)));
- EXPECT_EQ(old_heap_size, __asan_get_heap_size());
+ EXPECT_EQ(old_heap_size, __sanitizer_get_heap_size());
}
}
@@ -116,7 +120,7 @@ static void *ManyThreadsWithStatsWorker(void *arg) {
TEST(AddressSanitizerInterface, ManyThreadsWithStatsStressTest) {
size_t before_test, after_test, i;
pthread_t threads[kManyThreadsNumThreads];
- before_test = __asan_get_current_allocated_bytes();
+ before_test = __sanitizer_get_current_allocated_bytes();
for (i = 0; i < kManyThreadsNumThreads; i++) {
PTHREAD_CREATE(&threads[i], 0,
(void* (*)(void *x))ManyThreadsWithStatsWorker, (void*)i);
@@ -124,7 +128,7 @@ TEST(AddressSanitizerInterface, ManyThreadsWithStatsStressTest) {
for (i = 0; i < kManyThreadsNumThreads; i++) {
PTHREAD_JOIN(threads[i], 0);
}
- after_test = __asan_get_current_allocated_bytes();
+ after_test = __sanitizer_get_current_allocated_bytes();
// ASan stats also reflect memory usage of internal ASan RTL structs,
// so we can't check for equality here.
EXPECT_LT(after_test, before_test + (1UL<<20));
@@ -148,6 +152,7 @@ TEST(AddressSanitizerInterface, ExitCode) {
static void MyDeathCallback() {
fprintf(stderr, "MyDeathCallback\n");
+ fflush(0); // On Windows, stderr doesn't flush on crash.
}
TEST(AddressSanitizerInterface, DeathCallbackTest) {
@@ -389,6 +394,7 @@ TEST(AddressSanitizerInterface, DISABLED_InvalidPoisonAndUnpoisonCallsTest) {
free(array);
}
+#if !defined(_WIN32) // FIXME: This should really be a lit test.
static void ErrorReportCallbackOneToZ(const char *report) {
int report_len = strlen(report);
ASSERT_EQ(6, write(2, "ABCDEF", 6));
@@ -403,6 +409,7 @@ TEST(AddressSanitizerInterface, SetErrorReportCallbackTest) {
ASAN_PCRE_DOTALL "ABCDEF.*AddressSanitizer.*WRITE.*ABCDEF");
__asan_set_error_report_callback(NULL);
}
+#endif
TEST(AddressSanitizerInterface, GetOwnershipStressTest) {
std::vector<char *> pointers;
@@ -414,11 +421,11 @@ TEST(AddressSanitizerInterface, GetOwnershipStressTest) {
sizes.push_back(size);
}
for (size_t i = 0; i < 4000000; i++) {
- EXPECT_FALSE(__asan_get_ownership(&pointers));
- EXPECT_FALSE(__asan_get_ownership((void*)0x1234));
+ EXPECT_FALSE(__sanitizer_get_ownership(&pointers));
+ EXPECT_FALSE(__sanitizer_get_ownership((void*)0x1234));
size_t idx = i % kNumMallocs;
- EXPECT_TRUE(__asan_get_ownership(pointers[idx]));
- EXPECT_EQ(sizes[idx], __asan_get_allocated_size(pointers[idx]));
+ EXPECT_TRUE(__sanitizer_get_ownership(pointers[idx]));
+ EXPECT_EQ(sizes[idx], __sanitizer_get_allocated_size(pointers[idx]));
}
for (size_t i = 0, n = pointers.size(); i < n; i++)
free(pointers[i]);
diff --git a/lib/asan/tests/asan_mem_test.cc b/lib/asan/tests/asan_mem_test.cc
index 60f5cd4cf760..4a941faa0430 100644
--- a/lib/asan/tests/asan_mem_test.cc
+++ b/lib/asan/tests/asan_mem_test.cc
@@ -76,17 +76,17 @@ TEST(AddressSanitizer, MemSetOOBTest) {
// Strictly speaking we are not guaranteed to find such two pointers,
// but given the structure of asan's allocator we will.
static bool AllocateTwoAdjacentArrays(char **x1, char **x2, size_t size) {
- vector<char *> v;
+ vector<uintptr_t> v;
bool res = false;
for (size_t i = 0; i < 1000U && !res; i++) {
- v.push_back(new char[size]);
+ v.push_back(reinterpret_cast<uintptr_t>(new char[size]));
if (i == 0) continue;
sort(v.begin(), v.end());
for (size_t j = 1; j < v.size(); j++) {
assert(v[j] > v[j-1]);
if ((size_t)(v[j] - v[j-1]) < size * 2) {
- *x2 = v[j];
- *x1 = v[j-1];
+ *x2 = reinterpret_cast<char*>(v[j]);
+ *x1 = reinterpret_cast<char*>(v[j-1]);
res = true;
break;
}
@@ -94,9 +94,10 @@ static bool AllocateTwoAdjacentArrays(char **x1, char **x2, size_t size) {
}
for (size_t i = 0; i < v.size(); i++) {
- if (res && v[i] == *x1) continue;
- if (res && v[i] == *x2) continue;
- delete [] v[i];
+ char *p = reinterpret_cast<char *>(v[i]);
+ if (res && p == *x1) continue;
+ if (res && p == *x2) continue;
+ delete [] p;
}
return res;
}
diff --git a/lib/asan/tests/asan_noinst_test.cc b/lib/asan/tests/asan_noinst_test.cc
index cb6223c09a46..bb6af45bddf9 100644
--- a/lib/asan/tests/asan_noinst_test.cc
+++ b/lib/asan/tests/asan_noinst_test.cc
@@ -16,6 +16,7 @@
#include "asan_internal.h"
#include "asan_mapping.h"
#include "asan_test_utils.h"
+#include <sanitizer/allocator_interface.h>
#include <assert.h>
#include <stdio.h>
@@ -25,40 +26,19 @@
#include <vector>
#include <limits>
-#if ASAN_FLEXIBLE_MAPPING_AND_OFFSET == 1
-// Manually set correct ASan mapping scale and offset, as they won't be
-// exported from instrumented sources (there are none).
-# define FLEXIBLE_SHADOW_SCALE kDefaultShadowScale
-# if SANITIZER_ANDROID
-# define FLEXIBLE_SHADOW_OFFSET (0)
-# else
-# if SANITIZER_WORDSIZE == 32
-# if defined(__mips__)
-# define FLEXIBLE_SHADOW_OFFSET kMIPS32_ShadowOffset32
-# else
-# define FLEXIBLE_SHADOW_OFFSET kDefaultShadowOffset32
-# endif
-# else
-# if defined(__powerpc64__)
-# define FLEXIBLE_SHADOW_OFFSET kPPC64_ShadowOffset64
-# elif SANITIZER_MAC
-# define FLEXIBLE_SHADOW_OFFSET kDefaultShadowOffset64
-# else
-# define FLEXIBLE_SHADOW_OFFSET kDefaultShort64bitShadowOffset
-# endif
-# endif
-# endif
-SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_mapping_scale = FLEXIBLE_SHADOW_SCALE;
-SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_mapping_offset =
- FLEXIBLE_SHADOW_OFFSET;
-#endif // ASAN_FLEXIBLE_MAPPING_AND_OFFSET
+// ATTENTION!
+// Please don't call intercepted functions (including malloc() and friends)
+// in this test. The static runtime library is linked explicitly (without
+// -fsanitize=address), thus the interceptors do not work correctly on OS X.
+#if !defined(_WIN32)
extern "C" {
// Set specific ASan options for uninstrumented unittest.
const char* __asan_default_options() {
return "allow_reexec=0";
}
} // extern "C"
+#endif
// Make sure __asan_init is called before any test case is run.
struct AsanInitCaller {
@@ -72,19 +52,19 @@ TEST(AddressSanitizer, InternalSimpleDeathTest) {
static void MallocStress(size_t n) {
u32 seed = my_rand();
- StackTrace stack1;
- stack1.trace[0] = 0xa123;
- stack1.trace[1] = 0xa456;
+ BufferedStackTrace stack1;
+ stack1.trace_buffer[0] = 0xa123;
+ stack1.trace_buffer[1] = 0xa456;
stack1.size = 2;
- StackTrace stack2;
- stack2.trace[0] = 0xb123;
- stack2.trace[1] = 0xb456;
+ BufferedStackTrace stack2;
+ stack2.trace_buffer[0] = 0xb123;
+ stack2.trace_buffer[1] = 0xb456;
stack2.size = 2;
- StackTrace stack3;
- stack3.trace[0] = 0xc123;
- stack3.trace[1] = 0xc456;
+ BufferedStackTrace stack3;
+ stack3.trace_buffer[0] = 0xc123;
+ stack3.trace_buffer[1] = 0xc456;
stack3.size = 2;
std::vector<void *> vec;
@@ -160,8 +140,8 @@ TEST(AddressSanitizer, DISABLED_InternalPrintShadow) {
}
TEST(AddressSanitizer, QuarantineTest) {
- StackTrace stack;
- stack.trace[0] = 0x890;
+ BufferedStackTrace stack;
+ stack.trace_buffer[0] = 0x890;
stack.size = 1;
const int size = 1024;
@@ -181,8 +161,8 @@ TEST(AddressSanitizer, QuarantineTest) {
void *ThreadedQuarantineTestWorker(void *unused) {
(void)unused;
u32 seed = my_rand();
- StackTrace stack;
- stack.trace[0] = 0x890;
+ BufferedStackTrace stack;
+ stack.trace_buffer[0] = 0x890;
stack.size = 1;
for (size_t i = 0; i < 1000; i++) {
@@ -196,20 +176,20 @@ void *ThreadedQuarantineTestWorker(void *unused) {
// destroyed.
TEST(AddressSanitizer, ThreadedQuarantineTest) {
const int n_threads = 3000;
- size_t mmaped1 = __asan_get_heap_size();
+ size_t mmaped1 = __sanitizer_get_heap_size();
for (int i = 0; i < n_threads; i++) {
pthread_t t;
PTHREAD_CREATE(&t, NULL, ThreadedQuarantineTestWorker, 0);
PTHREAD_JOIN(t, 0);
- size_t mmaped2 = __asan_get_heap_size();
+ size_t mmaped2 = __sanitizer_get_heap_size();
EXPECT_LT(mmaped2 - mmaped1, 320U * (1 << 20));
}
}
void *ThreadedOneSizeMallocStress(void *unused) {
(void)unused;
- StackTrace stack;
- stack.trace[0] = 0x890;
+ BufferedStackTrace stack;
+ stack.trace_buffer[0] = 0x890;
stack.size = 1;
const size_t kNumMallocs = 1000;
for (int iter = 0; iter < 1000; iter++) {
@@ -245,3 +225,45 @@ TEST(AddressSanitizer, ShadowRegionIsPoisonedTest) {
ptr = kHighShadowBeg + 200;
EXPECT_EQ(ptr, __asan_region_is_poisoned(ptr, 100));
}
+
+// Test __asan_load1 & friends.
+TEST(AddressSanitizer, LoadStoreCallbacks) {
+ typedef void (*CB)(uptr p);
+ CB cb[2][5] = {
+ {
+ __asan_load1, __asan_load2, __asan_load4, __asan_load8, __asan_load16,
+ }, {
+ __asan_store1, __asan_store2, __asan_store4, __asan_store8,
+ __asan_store16,
+ }
+ };
+
+ uptr buggy_ptr;
+
+ __asan_test_only_reported_buggy_pointer = &buggy_ptr;
+ BufferedStackTrace stack;
+ stack.trace_buffer[0] = 0x890;
+ stack.size = 1;
+
+ for (uptr len = 16; len <= 32; len++) {
+ char *ptr = (char*) __asan::asan_malloc(len, &stack);
+ uptr p = reinterpret_cast<uptr>(ptr);
+ for (uptr is_write = 0; is_write <= 1; is_write++) {
+ for (uptr size_log = 0; size_log <= 4; size_log++) {
+ uptr size = 1 << size_log;
+ CB call = cb[is_write][size_log];
+ // Iterate only size-aligned offsets.
+ for (uptr offset = 0; offset <= len; offset += size) {
+ buggy_ptr = 0;
+ call(p + offset);
+ if (offset + size <= len)
+ EXPECT_EQ(buggy_ptr, 0U);
+ else
+ EXPECT_EQ(buggy_ptr, p + offset);
+ }
+ }
+ }
+ __asan::asan_free(ptr, &stack, __asan::FROM_MALLOC);
+ }
+ __asan_test_only_reported_buggy_pointer = 0;
+}
diff --git a/lib/asan/tests/asan_oob_test.cc b/lib/asan/tests/asan_oob_test.cc
index f8343f19cfcb..0c6bea285864 100644
--- a/lib/asan/tests/asan_oob_test.cc
+++ b/lib/asan/tests/asan_oob_test.cc
@@ -75,7 +75,9 @@ TEST(AddressSanitizer, OOB_int) {
}
TEST(AddressSanitizer, OOBRightTest) {
- for (size_t access_size = 1; access_size <= 8; access_size *= 2) {
+ size_t max_access_size = SANITIZER_WORDSIZE == 64 ? 8 : 4;
+ for (size_t access_size = 1; access_size <= max_access_size;
+ access_size *= 2) {
for (size_t alloc_size = 1; alloc_size <= 8; alloc_size++) {
for (size_t offset = 0; offset <= 8; offset += access_size) {
void *p = malloc(alloc_size);
diff --git a/lib/asan/tests/asan_racy_double_free_test.cc b/lib/asan/tests/asan_racy_double_free_test.cc
index deeeb4f45e2f..23240e714d56 100644
--- a/lib/asan/tests/asan_racy_double_free_test.cc
+++ b/lib/asan/tests/asan_racy_double_free_test.cc
@@ -7,7 +7,7 @@ void *x[N];
void *Thread1(void *unused) {
for (int i = 0; i < N; i++) {
- fprintf(stderr, "%s %d\n", __FUNCTION__, i);
+ fprintf(stderr, "%s %d\n", __func__, i);
free(x[i]);
}
return NULL;
@@ -15,7 +15,7 @@ void *Thread1(void *unused) {
void *Thread2(void *unused) {
for (int i = 0; i < N; i++) {
- fprintf(stderr, "%s %d\n", __FUNCTION__, i);
+ fprintf(stderr, "%s %d\n", __func__, i);
free(x[i]);
}
return NULL;
diff --git a/lib/asan/tests/asan_str_test.cc b/lib/asan/tests/asan_str_test.cc
index 178d00d4da86..1cd2a08b9021 100644
--- a/lib/asan/tests/asan_str_test.cc
+++ b/lib/asan/tests/asan_str_test.cc
@@ -77,7 +77,7 @@ TEST(AddressSanitizer, WcsLenTest) {
free(heap_string);
}
-#ifndef __APPLE__
+#if SANITIZER_TEST_HAS_STRNLEN
TEST(AddressSanitizer, StrNLenOOBTest) {
size_t size = Ident(123);
char *str = MallocAndMemsetString(size);
@@ -95,7 +95,7 @@ TEST(AddressSanitizer, StrNLenOOBTest) {
EXPECT_DEATH(Ident(strnlen(str, size + 1)), RightOOBReadMessage(0));
free(str);
}
-#endif
+#endif // SANITIZER_TEST_HAS_STRNLEN
TEST(AddressSanitizer, StrDupOOBTest) {
size_t size = Ident(42);
@@ -186,7 +186,7 @@ TEST(AddressSanitizer, StrNCpyOOBTest) {
typedef char*(*PointerToStrChr1)(const char*, int);
typedef char*(*PointerToStrChr2)(char*, int);
-USED static void RunStrChrTest(PointerToStrChr1 StrChr) {
+UNUSED static void RunStrChrTest(PointerToStrChr1 StrChr) {
size_t size = Ident(100);
char *str = MallocAndMemsetString(size);
str[10] = 'q';
@@ -202,7 +202,7 @@ USED static void RunStrChrTest(PointerToStrChr1 StrChr) {
EXPECT_DEATH(Ident(StrChr(str, 'a')), RightOOBReadMessage(0));
free(str);
}
-USED static void RunStrChrTest(PointerToStrChr2 StrChr) {
+UNUSED static void RunStrChrTest(PointerToStrChr2 StrChr) {
size_t size = Ident(100);
char *str = MallocAndMemsetString(size);
str[10] = 'q';
@@ -221,7 +221,10 @@ USED static void RunStrChrTest(PointerToStrChr2 StrChr) {
TEST(AddressSanitizer, StrChrAndIndexOOBTest) {
RunStrChrTest(&strchr);
+// No index() on Windows and on Android L.
+#if !defined(_WIN32) && !defined(__ANDROID__)
RunStrChrTest(&index);
+#endif
}
TEST(AddressSanitizer, StrCmpAndFriendsLogicTest) {
@@ -244,6 +247,7 @@ TEST(AddressSanitizer, StrCmpAndFriendsLogicTest) {
EXPECT_LT(0, strncmp("baa", "aaa", 1));
EXPECT_LT(0, strncmp("zyx", "", 2));
+#if !defined(_WIN32) // no str[n]casecmp on Windows.
// strcasecmp
EXPECT_EQ(0, strcasecmp("", ""));
EXPECT_EQ(0, strcasecmp("zzz", "zzz"));
@@ -263,6 +267,7 @@ TEST(AddressSanitizer, StrCmpAndFriendsLogicTest) {
EXPECT_LT(0, strncasecmp("xyz", "xyy", 10));
EXPECT_LT(0, strncasecmp("Baa", "aaa", 1));
EXPECT_LT(0, strncasecmp("zyx", "", 2));
+#endif
// memcmp
EXPECT_EQ(0, memcmp("a", "b", 0));
@@ -305,9 +310,11 @@ TEST(AddressSanitizer, StrCmpOOBTest) {
RunStrCmpTest(&strcmp);
}
+#if !defined(_WIN32) // no str[n]casecmp on Windows.
TEST(AddressSanitizer, StrCaseCmpOOBTest) {
RunStrCmpTest(&strcasecmp);
}
+#endif
typedef int(*PointerToStrNCmp)(const char*, const char*, size_t);
void RunStrNCmpTest(PointerToStrNCmp StrNCmp) {
@@ -340,9 +347,12 @@ TEST(AddressSanitizer, StrNCmpOOBTest) {
RunStrNCmpTest(&strncmp);
}
+#if !defined(_WIN32) // no str[n]casecmp on Windows.
TEST(AddressSanitizer, StrNCaseCmpOOBTest) {
RunStrNCmpTest(&strncasecmp);
}
+#endif
+
TEST(AddressSanitizer, StrCatOOBTest) {
// strcat() reads strlen(to) bytes from |to| before concatenating.
size_t to_size = Ident(100);
@@ -489,15 +499,6 @@ TEST(AddressSanitizer, StrArgsOverlapTest) {
free(str);
}
-void CallAtoi(const char *nptr) {
- Ident(atoi(nptr));
-}
-void CallAtol(const char *nptr) {
- Ident(atol(nptr));
-}
-void CallAtoll(const char *nptr) {
- Ident(atoll(nptr));
-}
typedef void(*PointerToCallAtoi)(const char*);
void RunAtoiOOBTest(PointerToCallAtoi Atoi) {
@@ -524,18 +525,23 @@ void RunAtoiOOBTest(PointerToCallAtoi Atoi) {
free(array);
}
+#if !defined(_WIN32) // FIXME: Fix and enable on Windows.
+void CallAtoi(const char *nptr) {
+ Ident(atoi(nptr));
+}
+void CallAtol(const char *nptr) {
+ Ident(atol(nptr));
+}
+void CallAtoll(const char *nptr) {
+ Ident(atoll(nptr));
+}
TEST(AddressSanitizer, AtoiAndFriendsOOBTest) {
RunAtoiOOBTest(&CallAtoi);
RunAtoiOOBTest(&CallAtol);
RunAtoiOOBTest(&CallAtoll);
}
+#endif
-void CallStrtol(const char *nptr, char **endptr, int base) {
- Ident(strtol(nptr, endptr, base));
-}
-void CallStrtoll(const char *nptr, char **endptr, int base) {
- Ident(strtoll(nptr, endptr, base));
-}
typedef void(*PointerToCallStrtol)(const char*, char**, int);
void RunStrtolOOBTest(PointerToCallStrtol Strtol) {
@@ -578,11 +584,19 @@ void RunStrtolOOBTest(PointerToCallStrtol Strtol) {
free(array);
}
+#if !defined(_WIN32) // FIXME: Fix and enable on Windows.
+void CallStrtol(const char *nptr, char **endptr, int base) {
+ Ident(strtol(nptr, endptr, base));
+}
+void CallStrtoll(const char *nptr, char **endptr, int base) {
+ Ident(strtoll(nptr, endptr, base));
+}
TEST(AddressSanitizer, StrtollOOBTest) {
RunStrtolOOBTest(&CallStrtoll);
}
TEST(AddressSanitizer, StrtolOOBTest) {
RunStrtolOOBTest(&CallStrtol);
}
+#endif
diff --git a/lib/asan/tests/asan_test.cc b/lib/asan/tests/asan_test.cc
index 6539ae8af4ea..67bcbaca1e40 100644
--- a/lib/asan/tests/asan_test.cc
+++ b/lib/asan/tests/asan_test.cc
@@ -25,27 +25,10 @@ NOINLINE void *malloc_bbb(size_t size) {
NOINLINE void *malloc_aaa(size_t size) {
void *res = malloc_bbb(size); break_optimization(0); return res;}
-#ifndef __APPLE__
-NOINLINE void *memalign_fff(size_t alignment, size_t size) {
- void *res = memalign/**/(alignment, size); break_optimization(0); return res;}
-NOINLINE void *memalign_eee(size_t alignment, size_t size) {
- void *res = memalign_fff(alignment, size); break_optimization(0); return res;}
-NOINLINE void *memalign_ddd(size_t alignment, size_t size) {
- void *res = memalign_eee(alignment, size); break_optimization(0); return res;}
-NOINLINE void *memalign_ccc(size_t alignment, size_t size) {
- void *res = memalign_ddd(alignment, size); break_optimization(0); return res;}
-NOINLINE void *memalign_bbb(size_t alignment, size_t size) {
- void *res = memalign_ccc(alignment, size); break_optimization(0); return res;}
-NOINLINE void *memalign_aaa(size_t alignment, size_t size) {
- void *res = memalign_bbb(alignment, size); break_optimization(0); return res;}
-#endif // __APPLE__
-
-
NOINLINE void free_ccc(void *p) { free(p); break_optimization(0);}
NOINLINE void free_bbb(void *p) { free_ccc(p); break_optimization(0);}
NOINLINE void free_aaa(void *p) { free_bbb(p); break_optimization(0);}
-
template<typename T>
NOINLINE void uaf_test(int size, int off) {
char *p = (char *)malloc_aaa(size);
@@ -90,19 +73,19 @@ TEST(AddressSanitizer, VariousMallocsTest) {
*c = 0;
delete c;
-#if !defined(__APPLE__) && !defined(ANDROID) && !defined(__ANDROID__)
+#if SANITIZER_TEST_HAS_POSIX_MEMALIGN
int *pm;
int pm_res = posix_memalign((void**)&pm, kPageSize, kPageSize);
EXPECT_EQ(0, pm_res);
free(pm);
-#endif
+#endif // SANITIZER_TEST_HAS_POSIX_MEMALIGN
-#if !defined(__APPLE__)
+#if SANITIZER_TEST_HAS_MEMALIGN
int *ma = (int*)memalign(kPageSize, kPageSize);
EXPECT_EQ(0U, (uintptr_t)ma % kPageSize);
ma[123] = 0;
free(ma);
-#endif // __APPLE__
+#endif // SANITIZER_TEST_HAS_MEMALIGN
}
TEST(AddressSanitizer, CallocTest) {
@@ -124,18 +107,25 @@ TEST(AddressSanitizer, CallocReturnsZeroMem) {
EXPECT_EQ(x[size / 4], 0);
memset(x, 0x42, size);
free(Ident(x));
+#if !defined(_WIN32)
+ // FIXME: OOM on Windows. We should just make this a lit test
+ // with quarantine size set to 1.
free(Ident(malloc(Ident(1 << 27)))); // Try to drain the quarantine.
+#endif
}
}
}
+// No valloc on Windows or Android.
+#if !defined(_WIN32) && !defined(__ANDROID__)
TEST(AddressSanitizer, VallocTest) {
void *a = valloc(100);
EXPECT_EQ(0U, (uintptr_t)a % kPageSize);
free(a);
}
+#endif
-#ifndef __APPLE__
+#if SANITIZER_TEST_HAS_PVALLOC
TEST(AddressSanitizer, PvallocTest) {
char *a = (char*)pvalloc(kPageSize + 100);
EXPECT_EQ(0U, (uintptr_t)a % kPageSize);
@@ -147,8 +137,10 @@ TEST(AddressSanitizer, PvallocTest) {
a[101] = 1; // we should not report an error here.
free(a);
}
-#endif // __APPLE__
+#endif // SANITIZER_TEST_HAS_PVALLOC
+#if !defined(_WIN32)
+// FIXME: Use an equivalent of pthread_setspecific on Windows.
void *TSDWorker(void *test_key) {
if (test_key) {
pthread_setspecific(*(pthread_key_t*)test_key, (void*)0xfeedface);
@@ -178,6 +170,7 @@ TEST(AddressSanitizer, DISABLED_TSDTest) {
PTHREAD_JOIN(th, NULL);
pthread_key_delete(test_key);
}
+#endif
TEST(AddressSanitizer, UAF_char) {
const char *uaf_string = "AddressSanitizer:.*heap-use-after-free";
@@ -191,18 +184,27 @@ TEST(AddressSanitizer, UAF_char) {
TEST(AddressSanitizer, UAF_long_double) {
if (sizeof(long double) == sizeof(double)) return;
long double *p = Ident(new long double[10]);
- EXPECT_DEATH(Ident(p)[12] = 0, "WRITE of size 1[06]");
- EXPECT_DEATH(Ident(p)[0] = Ident(p)[12], "READ of size 1[06]");
+ EXPECT_DEATH(Ident(p)[12] = 0, "WRITE of size 1[026]");
+ EXPECT_DEATH(Ident(p)[0] = Ident(p)[12], "READ of size 1[026]");
delete [] Ident(p);
}
+#if !defined(_WIN32)
struct Packed5 {
int x;
char c;
} __attribute__((packed));
-
+#else
+# pragma pack(push, 1)
+struct Packed5 {
+ int x;
+ char c;
+};
+# pragma pack(pop)
+#endif
TEST(AddressSanitizer, UAF_Packed5) {
+ static_assert(sizeof(Packed5) == 5, "Please check the keywords used");
Packed5 *p = Ident(new Packed5[2]);
EXPECT_DEATH(p[0] = p[3], "READ of size 5");
EXPECT_DEATH(p[3] = p[0], "WRITE of size 5");
@@ -299,12 +301,14 @@ TEST(AddressSanitizer, LargeMallocTest) {
}
TEST(AddressSanitizer, HugeMallocTest) {
- if (SANITIZER_WORDSIZE != 64) return;
+ if (SANITIZER_WORDSIZE != 64 || ASAN_AVOID_EXPENSIVE_TESTS) return;
size_t n_megs = 4100;
- TestLargeMalloc(n_megs << 20);
+ EXPECT_DEATH(Ident((char*)malloc(n_megs << 20))[-1] = 0,
+ "is located 1 bytes to the left|"
+ "AddressSanitizer failed to allocate");
}
-#ifndef __APPLE__
+#if SANITIZER_TEST_HAS_MEMALIGN
void MemalignRun(size_t align, size_t size, int idx) {
char *p = (char *)memalign(align, size);
Ident(p)[idx] = 0;
@@ -320,7 +324,7 @@ TEST(AddressSanitizer, memalign) {
"is located 1 bytes to the right");
}
}
-#endif
+#endif // SANITIZER_TEST_HAS_MEMALIGN
void *ManyThreadsWorker(void *a) {
for (int iter = 0; iter < 100; iter++) {
@@ -379,12 +383,12 @@ TEST(AddressSanitizer, ZeroSizeMallocTest) {
void *ptr = Ident(malloc(0));
EXPECT_TRUE(NULL != ptr);
free(ptr);
-#if !defined(__APPLE__) && !defined(ANDROID) && !defined(__ANDROID__)
+#if SANITIZER_TEST_HAS_POSIX_MEMALIGN
int pm_res = posix_memalign(&ptr, 1<<20, 0);
EXPECT_EQ(0, pm_res);
EXPECT_TRUE(NULL != ptr);
free(ptr);
-#endif
+#endif // SANITIZER_TEST_HAS_POSIX_MEMALIGN
int *int_ptr = new int[0];
int *int_ptr2 = new int[0];
EXPECT_TRUE(NULL != int_ptr);
@@ -394,7 +398,7 @@ TEST(AddressSanitizer, ZeroSizeMallocTest) {
delete[] int_ptr2;
}
-#ifndef __APPLE__
+#if SANITIZER_TEST_HAS_MALLOC_USABLE_SIZE
static const char *kMallocUsableSizeErrorMsg =
"AddressSanitizer: attempting to call malloc_usable_size()";
@@ -412,7 +416,7 @@ TEST(AddressSanitizer, MallocUsableSizeTest) {
EXPECT_DEATH(malloc_usable_size(array), kMallocUsableSizeErrorMsg);
delete int_ptr;
}
-#endif
+#endif // SANITIZER_TEST_HAS_MALLOC_USABLE_SIZE
void WrongFree() {
int *x = (int*)malloc(100 * sizeof(int));
@@ -421,12 +425,14 @@ void WrongFree() {
free(x + 1);
}
+#if !defined(_WIN32) // FIXME: This should be a lit test.
TEST(AddressSanitizer, WrongFreeTest) {
EXPECT_DEATH(WrongFree(), ASAN_PCRE_DOTALL
"ERROR: AddressSanitizer: attempting free.*not malloc"
".*is located 4 bytes inside of 400-byte region"
".*allocated by thread");
}
+#endif
void DoubleFree() {
int *x = (int*)malloc(100 * sizeof(int));
@@ -437,6 +443,7 @@ void DoubleFree() {
abort();
}
+#if !defined(_WIN32) // FIXME: This should be a lit test.
TEST(AddressSanitizer, DoubleFreeTest) {
EXPECT_DEATH(DoubleFree(), ASAN_PCRE_DOTALL
"ERROR: AddressSanitizer: attempting double-free"
@@ -444,20 +451,22 @@ TEST(AddressSanitizer, DoubleFreeTest) {
".*freed by thread T0 here"
".*previously allocated by thread T0 here");
}
+#endif
template<int kSize>
NOINLINE void SizedStackTest() {
char a[kSize];
char *A = Ident((char*)&a);
+ const char *expected_death = "AddressSanitizer: stack-buffer-";
for (size_t i = 0; i < kSize; i++)
A[i] = i;
- EXPECT_DEATH(A[-1] = 0, "");
- EXPECT_DEATH(A[-20] = 0, "");
- EXPECT_DEATH(A[-31] = 0, "");
- EXPECT_DEATH(A[kSize] = 0, "");
- EXPECT_DEATH(A[kSize + 1] = 0, "");
- EXPECT_DEATH(A[kSize + 10] = 0, "");
- EXPECT_DEATH(A[kSize + 31] = 0, "");
+ EXPECT_DEATH(A[-1] = 0, expected_death);
+ EXPECT_DEATH(A[-5] = 0, expected_death);
+ EXPECT_DEATH(A[kSize] = 0, expected_death);
+ EXPECT_DEATH(A[kSize + 1] = 0, expected_death);
+ EXPECT_DEATH(A[kSize + 5] = 0, expected_death);
+ if (kSize > 16)
+ EXPECT_DEATH(A[kSize + 31] = 0, expected_death);
}
TEST(AddressSanitizer, SimpleStackTest) {
@@ -478,6 +487,9 @@ TEST(AddressSanitizer, SimpleStackTest) {
SizedStackTest<128>();
}
+#if !defined(_WIN32)
+// FIXME: It's a bit hard to write multi-line death test expectations
+// in a portable way. Anyways, this should just be turned into a lit test.
TEST(AddressSanitizer, ManyStackObjectsTest) {
char XXX[10];
char YYY[20];
@@ -486,6 +498,7 @@ TEST(AddressSanitizer, ManyStackObjectsTest) {
Ident(YYY);
EXPECT_DEATH(Ident(ZZZ)[-1] = 0, ASAN_PCRE_DOTALL "XXX.*YYY.*ZZZ");
}
+#endif
#if 0 // This test requires online symbolizer.
// Moved to lit_tests/stack-oob-frames.cc.
@@ -538,6 +551,24 @@ NOINLINE void LongJmpFunc1(jmp_buf buf) {
longjmp(buf, 1);
}
+NOINLINE void TouchStackFunc() {
+ int a[100]; // long array will intersect with redzones from LongJmpFunc1.
+ int *A = Ident(a);
+ for (int i = 0; i < 100; i++)
+ A[i] = i*i;
+}
+
+// Test that we handle longjmp and do not report false positives on stack.
+TEST(AddressSanitizer, LongJmpTest) {
+ static jmp_buf buf;
+ if (!setjmp(buf)) {
+ LongJmpFunc1(buf);
+ } else {
+ TouchStackFunc();
+ }
+}
+
+#if !defined(_WIN32) // Only basic longjmp is available on Windows.
NOINLINE void BuiltinLongJmpFunc1(jmp_buf buf) {
// create three red zones for these two stack objects.
int a;
@@ -571,27 +602,9 @@ NOINLINE void SigLongJmpFunc1(sigjmp_buf buf) {
siglongjmp(buf, 1);
}
-
-NOINLINE void TouchStackFunc() {
- int a[100]; // long array will intersect with redzones from LongJmpFunc1.
- int *A = Ident(a);
- for (int i = 0; i < 100; i++)
- A[i] = i*i;
-}
-
-// Test that we handle longjmp and do not report fals positives on stack.
-TEST(AddressSanitizer, LongJmpTest) {
- static jmp_buf buf;
- if (!setjmp(buf)) {
- LongJmpFunc1(buf);
- } else {
- TouchStackFunc();
- }
-}
-
-#if !defined(__ANDROID__) && \
+#if !defined(__ANDROID__) && !defined(__arm__) && \
!defined(__powerpc64__) && !defined(__powerpc__)
-// Does not work on Power:
+// Does not work on Power and ARM:
// https://code.google.com/p/address-sanitizer/issues/detail?id=185
TEST(AddressSanitizer, BuiltinLongJmpTest) {
static jmp_buf buf;
@@ -601,7 +614,8 @@ TEST(AddressSanitizer, BuiltinLongJmpTest) {
TouchStackFunc();
}
}
-#endif // not defined(__ANDROID__)
+#endif // !defined(__ANDROID__) && !defined(__powerpc64__) &&
+ // !defined(__powerpc__) && !defined(__arm__)
TEST(AddressSanitizer, UnderscopeLongJmpTest) {
static jmp_buf buf;
@@ -620,8 +634,10 @@ TEST(AddressSanitizer, SigLongJmpTest) {
TouchStackFunc();
}
}
+#endif
-#ifdef __EXCEPTIONS
+// FIXME: Why does clang-cl define __EXCEPTIONS?
+#if defined(__EXCEPTIONS) && !defined(_WIN32)
NOINLINE void ThrowFunc() {
// create three red zones for these two stack objects.
int a;
@@ -688,12 +704,19 @@ TEST(AddressSanitizer, Store128Test) {
}
#endif
+// FIXME: All tests that use this function should be turned into lit tests.
string RightOOBErrorMessage(int oob_distance, bool is_write) {
assert(oob_distance >= 0);
char expected_str[100];
sprintf(expected_str, ASAN_PCRE_DOTALL
- "buffer-overflow.*%s.*located %d bytes to the right",
- is_write ? "WRITE" : "READ", oob_distance);
+#if !GTEST_USES_SIMPLE_RE
+ "buffer-overflow.*%s.*"
+#endif
+ "located %d bytes to the right",
+#if !GTEST_USES_SIMPLE_RE
+ is_write ? "WRITE" : "READ",
+#endif
+ oob_distance);
return string(expected_str);
}
@@ -705,11 +728,19 @@ string RightOOBReadMessage(int oob_distance) {
return RightOOBErrorMessage(oob_distance, /*is_write*/false);
}
+// FIXME: All tests that use this function should be turned into lit tests.
string LeftOOBErrorMessage(int oob_distance, bool is_write) {
assert(oob_distance > 0);
char expected_str[100];
- sprintf(expected_str, ASAN_PCRE_DOTALL "%s.*located %d bytes to the left",
- is_write ? "WRITE" : "READ", oob_distance);
+ sprintf(expected_str,
+#if !GTEST_USES_SIMPLE_RE
+ ASAN_PCRE_DOTALL "%s.*"
+#endif
+ "located %d bytes to the left",
+#if !GTEST_USES_SIMPLE_RE
+ is_write ? "WRITE" : "READ",
+#endif
+ oob_distance);
return string(expected_str);
}
@@ -738,7 +769,7 @@ char* MallocAndMemsetString(size_t size) {
return MallocAndMemsetString(size, 'z');
}
-#if defined(__linux__) && !defined(ANDROID) && !defined(__ANDROID__)
+#if defined(__linux__) && !defined(__ANDROID__)
#define READ_TEST(READ_N_BYTES) \
char *x = new char[10]; \
int fd = open("/proc/self/stat", O_RDONLY); \
@@ -761,7 +792,7 @@ TEST(AddressSanitizer, pread64) {
TEST(AddressSanitizer, read) {
READ_TEST(read(fd, x, 15));
}
-#endif // defined(__linux__) && !defined(ANDROID) && !defined(__ANDROID__)
+#endif // defined(__linux__) && !defined(__ANDROID__)
// This test case fails
// Clang optimizes memcpy/memset calls which lead to unaligned access
@@ -801,7 +832,7 @@ NOINLINE static int LargeFunction(bool do_bad_access) {
x[18]++;
x[19]++;
- delete x;
+ delete[] x;
return res;
}
@@ -863,6 +894,7 @@ void ThreadedTestSpawn() {
PTHREAD_JOIN(t, 0);
}
+#if !defined(_WIN32) // FIXME: This should be a lit test.
TEST(AddressSanitizer, ThreadedTest) {
EXPECT_DEATH(ThreadedTestSpawn(),
ASAN_PCRE_DOTALL
@@ -870,6 +902,7 @@ TEST(AddressSanitizer, ThreadedTest) {
".*Thread T.*created"
".*Thread T.*created");
}
+#endif
void *ThreadedTestFunc(void *unused) {
// Check if prctl(PR_SET_NAME) is supported. Return if not.
@@ -1064,7 +1097,8 @@ TEST(AddressSanitizer, PthreadExitTest) {
}
}
-#ifdef __EXCEPTIONS
+// FIXME: Why does clang-cl define __EXCEPTIONS?
+#if defined(__EXCEPTIONS) && !defined(_WIN32)
NOINLINE static void StackReuseAndException() {
int large_stack[1000];
Ident(large_stack);
@@ -1082,12 +1116,14 @@ TEST(AddressSanitizer, DISABLED_StressStackReuseAndExceptionsTest) {
}
#endif
+#if !defined(_WIN32)
TEST(AddressSanitizer, MlockTest) {
EXPECT_EQ(0, mlockall(MCL_CURRENT));
EXPECT_EQ(0, mlock((void*)0x12345, 0x5678));
EXPECT_EQ(0, munlockall());
EXPECT_EQ(0, munlock((void*)0x987, 0x654));
}
+#endif
struct LargeStruct {
int foo[100];
@@ -1111,10 +1147,15 @@ TEST(AddressSanitizer, AttributeNoSanitizeAddressTest) {
Ident(NoSanitizeAddress)();
}
-// It doesn't work on Android, as calls to new/delete go through malloc/free.
-// Neither it does on OS X, see
-// https://code.google.com/p/address-sanitizer/issues/detail?id=131.
-#if !defined(ANDROID) && !defined(__ANDROID__) && !defined(__APPLE__)
+// The new/delete/etc mismatch checks don't work on Android,
+// as calls to new/delete go through malloc/free.
+// OS X support is tracked here:
+// https://code.google.com/p/address-sanitizer/issues/detail?id=131
+// Windows support is tracked here:
+// https://code.google.com/p/address-sanitizer/issues/detail?id=309
+#if !defined(__ANDROID__) && \
+ !defined(__APPLE__) && \
+ !defined(_WIN32)
static string MismatchStr(const string &str) {
return string("AddressSanitizer: alloc-dealloc-mismatch \\(") + str;
}
@@ -1229,6 +1270,7 @@ TEST(AddressSanitizer, LongDoubleNegativeTest) {
memcpy(Ident(&c), Ident(&b), sizeof(long double));
}
+#if !defined(_WIN32)
TEST(AddressSanitizer, pthread_getschedparam) {
int policy;
struct sched_param param;
@@ -1241,3 +1283,4 @@ TEST(AddressSanitizer, pthread_getschedparam) {
int res = pthread_getschedparam(pthread_self(), &policy, &param);
ASSERT_EQ(0, res);
}
+#endif
diff --git a/lib/asan/tests/asan_test_config.h b/lib/asan/tests/asan_test_config.h
index 6eb33ce4431b..92f276307481 100644
--- a/lib/asan/tests/asan_test_config.h
+++ b/lib/asan/tests/asan_test_config.h
@@ -21,12 +21,6 @@
#include <string>
#include <map>
-#if ASAN_USE_DEJAGNU_GTEST
-# include "dejagnu-gtest.h"
-#else
-# include "gtest/gtest.h"
-#endif
-
using std::string;
using std::vector;
using std::map;
@@ -44,7 +38,11 @@ using std::map;
#endif
#ifndef ASAN_NEEDS_SEGV
-# error "please define ASAN_NEEDS_SEGV"
+# if defined(_WIN32)
+# define ASAN_NEEDS_SEGV 0
+# else
+# define ASAN_NEEDS_SEGV 1
+# endif
#endif
#ifndef ASAN_AVOID_EXPENSIVE_TESTS
diff --git a/lib/asan/tests/asan_test_utils.h b/lib/asan/tests/asan_test_utils.h
index b6bf6b82066d..03d17cfb26a7 100644
--- a/lib/asan/tests/asan_test_utils.h
+++ b/lib/asan/tests/asan_test_utils.h
@@ -14,24 +14,28 @@
#ifndef ASAN_TEST_UTILS_H
#define ASAN_TEST_UTILS_H
-#if !defined(ASAN_EXTERNAL_TEST_CONFIG)
+#if !defined(SANITIZER_EXTERNAL_TEST_CONFIG)
# define INCLUDED_FROM_ASAN_TEST_UTILS_H
# include "asan_test_config.h"
# undef INCLUDED_FROM_ASAN_TEST_UTILS_H
#endif
#include "sanitizer_test_utils.h"
+#include "sanitizer_pthread_wrappers.h"
+
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
-#include <strings.h>
-#include <pthread.h>
#include <stdint.h>
-#include <setjmp.h>
#include <assert.h>
#include <algorithm>
-#include <sys/mman.h>
+
+#if !defined(_WIN32)
+# include <strings.h>
+# include <sys/mman.h>
+# include <setjmp.h>
+#endif
#ifdef __linux__
# include <sys/prctl.h>
@@ -41,14 +45,10 @@
#include <unistd.h>
#endif
-#ifndef __APPLE__
+#if !defined(__APPLE__) && !defined(__FreeBSD__)
#include <malloc.h>
#endif
-// Check that pthread_create/pthread_join return success.
-#define PTHREAD_CREATE(a, b, c, d) ASSERT_EQ(0, pthread_create(a, b, c, d))
-#define PTHREAD_JOIN(a, b) ASSERT_EQ(0, pthread_join(a, b))
-
#if ASAN_HAS_EXCEPTIONS
# define ASAN_THROW(x) throw (x)
#else
diff --git a/lib/ashlti3.c b/lib/ashlti3.c
deleted file mode 100644
index 4bd8219b5278..000000000000
--- a/lib/ashlti3.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/* ===-- ashlti3.c - Implement __ashlti3 -----------------------------------===
- *
- * 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 __ashlti3 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-#if __x86_64
-
-/* Returns: a << b */
-
-/* Precondition: 0 <= b < bits_in_tword */
-
-ti_int
-__ashlti3(ti_int a, si_int b)
-{
- const int bits_in_dword = (int)(sizeof(di_int) * CHAR_BIT);
- twords input;
- twords result;
- input.all = a;
- if (b & bits_in_dword) /* bits_in_dword <= b < bits_in_tword */
- {
- result.s.low = 0;
- result.s.high = input.s.low << (b - bits_in_dword);
- }
- else /* 0 <= b < bits_in_dword */
- {
- if (b == 0)
- return a;
- result.s.low = input.s.low << b;
- result.s.high = (input.s.high << b) | (input.s.low >> (bits_in_dword - b));
- }
- return result.all;
-}
-
-#endif /* __x86_64 */
diff --git a/lib/ashrti3.c b/lib/ashrti3.c
deleted file mode 100644
index ed43641c7ef7..000000000000
--- a/lib/ashrti3.c
+++ /dev/null
@@ -1,46 +0,0 @@
-/* ===-- ashrti3.c - Implement __ashrti3 -----------------------------------===
- *
- * 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 __ashrti3 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-#if __x86_64
-
-/* Returns: arithmetic a >> b */
-
-/* Precondition: 0 <= b < bits_in_tword */
-
-ti_int
-__ashrti3(ti_int a, si_int b)
-{
- const int bits_in_dword = (int)(sizeof(di_int) * CHAR_BIT);
- twords input;
- twords result;
- input.all = a;
- if (b & bits_in_dword) /* bits_in_dword <= b < bits_in_tword */
- {
- /* result.s.high = input.s.high < 0 ? -1 : 0 */
- result.s.high = input.s.high >> (bits_in_dword - 1);
- result.s.low = input.s.high >> (b - bits_in_dword);
- }
- else /* 0 <= b < bits_in_dword */
- {
- if (b == 0)
- return a;
- result.s.high = input.s.high >> b;
- result.s.low = (input.s.high << (bits_in_dword - b)) | (input.s.low >> b);
- }
- return result.all;
-}
-
-#endif /* __x86_64 */
diff --git a/lib/assembly.h b/lib/assembly.h
deleted file mode 100644
index 3d8e50dc8ad9..000000000000
--- a/lib/assembly.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/* ===-- assembly.h - compiler-rt assembler support macros -----------------===
- *
- * 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 defines macros for use in compiler-rt assembler source.
- * This file is not part of the interface of this library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#ifndef COMPILERRT_ASSEMBLY_H
-#define COMPILERRT_ASSEMBLY_H
-
-#if defined(__POWERPC__) || defined(__powerpc__) || defined(__ppc__)
-#define SEPARATOR @
-#else
-#define SEPARATOR ;
-#endif
-
-#if defined(__APPLE__)
-#define HIDDEN_DIRECTIVE .private_extern
-#define LOCAL_LABEL(name) L_##name
-#define FILE_LEVEL_DIRECTIVE .subsections_via_symbols
-#else
-#define HIDDEN_DIRECTIVE .hidden
-#define LOCAL_LABEL(name) .L_##name
-#define FILE_LEVEL_DIRECTIVE
-#endif
-
-#define GLUE2(a, b) a ## b
-#define GLUE(a, b) GLUE2(a, b)
-#define SYMBOL_NAME(name) GLUE(__USER_LABEL_PREFIX__, name)
-
-#ifdef VISIBILITY_HIDDEN
-#define DECLARE_SYMBOL_VISIBILITY(name) \
- HIDDEN_DIRECTIVE SYMBOL_NAME(name) SEPARATOR
-#else
-#define DECLARE_SYMBOL_VISIBILITY(name)
-#endif
-
-#define DEFINE_COMPILERRT_FUNCTION(name) \
- FILE_LEVEL_DIRECTIVE SEPARATOR \
- .globl SYMBOL_NAME(name) SEPARATOR \
- DECLARE_SYMBOL_VISIBILITY(name) \
- SYMBOL_NAME(name):
-
-#define DEFINE_COMPILERRT_PRIVATE_FUNCTION(name) \
- .globl SYMBOL_NAME(name) SEPARATOR \
- HIDDEN_DIRECTIVE SYMBOL_NAME(name) SEPARATOR \
- SYMBOL_NAME(name):
-
-#define DEFINE_COMPILERRT_PRIVATE_FUNCTION_UNMANGLED(name) \
- .globl name SEPARATOR \
- HIDDEN_DIRECTIVE name SEPARATOR \
- name:
-
-#define DEFINE_COMPILERRT_FUNCTION_ALIAS(name, target) \
- .globl SYMBOL_NAME(name) SEPARATOR \
- .set SYMBOL_NAME(name), SYMBOL_NAME(target) SEPARATOR
-
-#if defined (__ARM_EABI__)
-# define DEFINE_AEABI_FUNCTION_ALIAS(aeabi_name, name) \
- DEFINE_COMPILERRT_FUNCTION_ALIAS(aeabi_name, name)
-#else
-# define DEFINE_AEABI_FUNCTION_ALIAS(aeabi_name, name)
-#endif
-
-#endif /* COMPILERRT_ASSEMBLY_H */
diff --git a/lib/builtins/CMakeLists.txt b/lib/builtins/CMakeLists.txt
new file mode 100644
index 000000000000..999faa86739d
--- /dev/null
+++ b/lib/builtins/CMakeLists.txt
@@ -0,0 +1,278 @@
+# This directory contains a large amount of C code which provides
+# generic implementations of the core runtime library along with optimized
+# architecture-specific code in various subdirectories.
+
+set(GENERIC_SOURCES
+ absvdi2.c
+ absvsi2.c
+ absvti2.c
+ adddf3.c
+ addsf3.c
+ addtf3.c
+ addvdi3.c
+ addvsi3.c
+ addvti3.c
+ apple_versioning.c
+ ashldi3.c
+ ashlti3.c
+ ashrdi3.c
+ ashrti3.c
+ # FIXME: atomic.c may only be compiled if host compiler understands _Atomic
+ # atomic.c
+ clear_cache.c
+ clzdi2.c
+ clzsi2.c
+ clzti2.c
+ cmpdi2.c
+ cmpti2.c
+ comparedf2.c
+ comparesf2.c
+ ctzdi2.c
+ ctzsi2.c
+ ctzti2.c
+ divdc3.c
+ divdf3.c
+ divdi3.c
+ divmoddi4.c
+ divmodsi4.c
+ divsc3.c
+ divsf3.c
+ divsi3.c
+ divti3.c
+ divtf3.c
+ divxc3.c
+ enable_execute_stack.c
+ eprintf.c
+ extendsfdf2.c
+ ffsdi2.c
+ ffsti2.c
+ fixdfdi.c
+ fixdfsi.c
+ fixdfti.c
+ fixsfdi.c
+ fixsfsi.c
+ fixsfti.c
+ fixunsdfdi.c
+ fixunsdfsi.c
+ fixunsdfti.c
+ fixunssfdi.c
+ fixunssfsi.c
+ fixunssfti.c
+ fixunsxfdi.c
+ fixunsxfsi.c
+ fixunsxfti.c
+ fixxfdi.c
+ fixxfti.c
+ floatdidf.c
+ floatdisf.c
+ floatdixf.c
+ floatsidf.c
+ floatsisf.c
+ floattidf.c
+ floattisf.c
+ floattixf.c
+ floatundidf.c
+ floatundisf.c
+ floatundixf.c
+ floatunsidf.c
+ floatunsisf.c
+ floatuntidf.c
+ floatuntisf.c
+ floatuntixf.c
+ gcc_personality_v0.c
+ int_util.c
+ lshrdi3.c
+ lshrti3.c
+ moddi3.c
+ modsi3.c
+ modti3.c
+ muldc3.c
+ muldf3.c
+ muldi3.c
+ mulodi4.c
+ mulosi4.c
+ muloti4.c
+ mulsc3.c
+ mulsf3.c
+ multi3.c
+ multf3.c
+ mulvdi3.c
+ mulvsi3.c
+ mulvti3.c
+ mulxc3.c
+ negdf2.c
+ negdi2.c
+ negsf2.c
+ negti2.c
+ negvdi2.c
+ negvsi2.c
+ negvti2.c
+ paritydi2.c
+ paritysi2.c
+ parityti2.c
+ popcountdi2.c
+ popcountsi2.c
+ popcountti2.c
+ powidf2.c
+ powisf2.c
+ powitf2.c
+ powixf2.c
+ subdf3.c
+ subsf3.c
+ subvdi3.c
+ subvsi3.c
+ subvti3.c
+ subtf3.c
+ trampoline_setup.c
+ truncdfsf2.c
+ ucmpdi2.c
+ ucmpti2.c
+ udivdi3.c
+ udivmoddi4.c
+ udivmodsi4.c
+ udivmodti4.c
+ udivsi3.c
+ udivti3.c
+ umoddi3.c
+ umodsi3.c
+ umodti3.c)
+
+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})
+
+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})
+
+set(i686_SOURCES
+ ${i386_SOURCES})
+
+set(arm_SOURCES
+ arm/adddf3vfp.S
+ arm/addsf3vfp.S
+ arm/aeabi_dcmp.S
+ arm/aeabi_div0.c
+ arm/aeabi_fcmp.S
+ arm/aeabi_idivmod.S
+ arm/aeabi_ldivmod.S
+ arm/aeabi_memcmp.S
+ arm/aeabi_memcpy.S
+ arm/aeabi_memmove.S
+ arm/aeabi_memset.S
+ arm/aeabi_uidivmod.S
+ arm/aeabi_uldivmod.S
+ arm/bswapdi2.S
+ arm/bswapsi2.S
+ arm/comparesf2.S
+ arm/divdf3vfp.S
+ arm/divmodsi4.S
+ arm/divsf3vfp.S
+ arm/divsi3.S
+ arm/eqdf2vfp.S
+ arm/eqsf2vfp.S
+ arm/extendsfdf2vfp.S
+ arm/fixdfsivfp.S
+ arm/fixsfsivfp.S
+ arm/fixunsdfsivfp.S
+ arm/fixunssfsivfp.S
+ arm/floatsidfvfp.S
+ arm/floatsisfvfp.S
+ arm/floatunssidfvfp.S
+ arm/floatunssisfvfp.S
+ arm/gedf2vfp.S
+ arm/gesf2vfp.S
+ arm/gtdf2vfp.S
+ arm/gtsf2vfp.S
+ arm/ledf2vfp.S
+ arm/lesf2vfp.S
+ arm/ltdf2vfp.S
+ arm/ltsf2vfp.S
+ arm/modsi3.S
+ arm/muldf3vfp.S
+ arm/mulsf3vfp.S
+ arm/nedf2vfp.S
+ arm/negdf2vfp.S
+ arm/negsf2vfp.S
+ arm/nesf2vfp.S
+ arm/restore_vfp_d8_d15_regs.S
+ arm/save_vfp_d8_d15_regs.S
+ arm/subdf3vfp.S
+ arm/subsf3vfp.S
+ arm/switch16.S
+ arm/switch32.S
+ arm/switch8.S
+ arm/switchu8.S
+ arm/sync_fetch_and_add_4.S
+ arm/sync_fetch_and_add_8.S
+ arm/sync_fetch_and_and_4.S
+ arm/sync_fetch_and_and_8.S
+ arm/sync_fetch_and_max_4.S
+ arm/sync_fetch_and_max_8.S
+ arm/sync_fetch_and_min_4.S
+ arm/sync_fetch_and_min_8.S
+ arm/sync_fetch_and_nand_4.S
+ arm/sync_fetch_and_nand_8.S
+ arm/sync_fetch_and_or_4.S
+ arm/sync_fetch_and_or_8.S
+ arm/sync_fetch_and_sub_4.S
+ arm/sync_fetch_and_sub_8.S
+ arm/sync_fetch_and_umax_4.S
+ arm/sync_fetch_and_umax_8.S
+ arm/sync_fetch_and_umin_4.S
+ arm/sync_fetch_and_umin_8.S
+ arm/sync_fetch_and_xor_4.S
+ arm/sync_fetch_and_xor_8.S
+ arm/sync_synchronize.S
+ arm/truncdfsf2vfp.S
+ arm/udivmodsi4.S
+ arm/udivsi3.S
+ arm/umodsi3.S
+ arm/unorddf2vfp.S
+ arm/unordsf2vfp.S
+ ${GENERIC_SOURCES})
+
+add_custom_target(builtins)
+
+if (NOT WIN32)
+ foreach (arch x86_64 i386 i686 arm)
+ if (CAN_TARGET_${arch})
+ # Filter out generic versions of routines that are re-implemented in
+ # architecture specific manner. This prevents multiple definitions of the
+ # same symbols, making the symbol selection non-deterministic.
+ foreach (_file ${${arch}_SOURCES})
+ if (${_file} MATCHES ${arch}/*)
+ get_filename_component(_name ${_file} NAME)
+ string(REPLACE ".S" ".c" _cname "${_name}")
+ list(REMOVE_ITEM ${arch}_SOURCES ${_cname})
+ endif ()
+ endforeach ()
+
+ set_source_files_properties(${${arch}_SOURCES} PROPERTIES LANGUAGE C)
+ add_compiler_rt_runtime(clang_rt.builtins-${arch} ${arch} STATIC
+ SOURCES ${${arch}_SOURCES}
+ CFLAGS "-std=c99")
+ add_dependencies(builtins clang_rt.builtins-${arch})
+ endif ()
+ endforeach ()
+endif ()
+
+add_dependencies(compiler-rt builtins)
diff --git a/lib/builtins/Makefile.mk b/lib/builtins/Makefile.mk
new file mode 100644
index 000000000000..00e2f53fc401
--- /dev/null
+++ b/lib/builtins/Makefile.mk
@@ -0,0 +1,25 @@
+#===- lib/builtins/Makefile.mk -----------------------------*- Makefile -*--===#
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+
+ModuleName := builtins
+SubDirs :=
+
+# Add arch specific optimized implementations.
+SubDirs += i386 ppc x86_64 arm armv6m
+
+# Add ARM64 dir.
+SubDirs += arm64
+
+# Define the variables for this specific directory.
+Sources := $(foreach file,$(wildcard $(Dir)/*.c),$(notdir $(file)))
+ObjNames := $(Sources:%.c=%.o)
+Implementation := Generic
+
+# FIXME: use automatic dependencies?
+Dependencies := $(wildcard $(Dir)/*.h)
diff --git a/lib/builtins/README.txt b/lib/builtins/README.txt
new file mode 100644
index 000000000000..1c08e7415e64
--- /dev/null
+++ b/lib/builtins/README.txt
@@ -0,0 +1,343 @@
+Compiler-RT
+================================
+
+This directory and its subdirectories contain source code for the compiler
+support routines.
+
+Compiler-RT is open source software. You may freely distribute it under the
+terms of the license agreement found in LICENSE.txt.
+
+================================
+
+This is a replacement library for libgcc. Each function is contained
+in its own file. Each function has a corresponding unit test under
+test/Unit.
+
+A rudimentary script to test each file is in the file called
+test/Unit/test.
+
+Here is the specification for this library:
+
+http://gcc.gnu.org/onlinedocs/gccint/Libgcc.html#Libgcc
+
+Here is a synopsis of the contents of this library:
+
+typedef int si_int;
+typedef unsigned su_int;
+
+typedef long long di_int;
+typedef unsigned long long du_int;
+
+// Integral bit manipulation
+
+di_int __ashldi3(di_int a, si_int b); // a << b
+ti_int __ashlti3(ti_int a, si_int b); // a << b
+
+di_int __ashrdi3(di_int a, si_int b); // a >> b arithmetic (sign fill)
+ti_int __ashrti3(ti_int a, si_int b); // a >> b arithmetic (sign fill)
+di_int __lshrdi3(di_int a, si_int b); // a >> b logical (zero fill)
+ti_int __lshrti3(ti_int a, si_int b); // a >> b logical (zero fill)
+
+si_int __clzsi2(si_int a); // count leading zeros
+si_int __clzdi2(di_int a); // count leading zeros
+si_int __clzti2(ti_int a); // count leading zeros
+si_int __ctzsi2(si_int a); // count trailing zeros
+si_int __ctzdi2(di_int a); // count trailing zeros
+si_int __ctzti2(ti_int a); // count trailing zeros
+
+si_int __ffsdi2(di_int a); // find least significant 1 bit
+si_int __ffsti2(ti_int a); // find least significant 1 bit
+
+si_int __paritysi2(si_int a); // bit parity
+si_int __paritydi2(di_int a); // bit parity
+si_int __parityti2(ti_int a); // bit parity
+
+si_int __popcountsi2(si_int a); // bit population
+si_int __popcountdi2(di_int a); // bit population
+si_int __popcountti2(ti_int a); // bit population
+
+uint32_t __bswapsi2(uint32_t a); // a byteswapped, arm only
+uint64_t __bswapdi2(uint64_t a); // a byteswapped, arm only
+
+// Integral arithmetic
+
+di_int __negdi2 (di_int a); // -a
+ti_int __negti2 (ti_int a); // -a
+di_int __muldi3 (di_int a, di_int b); // a * b
+ti_int __multi3 (ti_int a, ti_int b); // a * b
+si_int __divsi3 (si_int a, si_int b); // a / b signed
+di_int __divdi3 (di_int a, di_int b); // a / b signed
+ti_int __divti3 (ti_int a, ti_int b); // a / b signed
+su_int __udivsi3 (su_int n, su_int d); // a / b unsigned
+du_int __udivdi3 (du_int a, du_int b); // a / b unsigned
+tu_int __udivti3 (tu_int a, tu_int b); // a / b unsigned
+si_int __modsi3 (si_int a, si_int b); // a % b signed
+di_int __moddi3 (di_int a, di_int b); // a % b signed
+ti_int __modti3 (ti_int a, ti_int b); // a % b signed
+su_int __umodsi3 (su_int a, su_int b); // a % b unsigned
+du_int __umoddi3 (du_int a, du_int b); // a % b unsigned
+tu_int __umodti3 (tu_int a, tu_int b); // a % b unsigned
+du_int __udivmoddi4(du_int a, du_int b, du_int* rem); // a / b, *rem = a % b unsigned
+tu_int __udivmodti4(tu_int a, tu_int b, tu_int* rem); // a / b, *rem = a % b unsigned
+su_int __udivmodsi4(su_int a, su_int b, su_int* rem); // a / b, *rem = a % b unsigned
+si_int __divmodsi4(si_int a, si_int b, si_int* rem); // a / b, *rem = a % b signed
+
+
+
+// Integral arithmetic with trapping overflow
+
+si_int __absvsi2(si_int a); // abs(a)
+di_int __absvdi2(di_int a); // abs(a)
+ti_int __absvti2(ti_int a); // abs(a)
+
+si_int __negvsi2(si_int a); // -a
+di_int __negvdi2(di_int a); // -a
+ti_int __negvti2(ti_int a); // -a
+
+si_int __addvsi3(si_int a, si_int b); // a + b
+di_int __addvdi3(di_int a, di_int b); // a + b
+ti_int __addvti3(ti_int a, ti_int b); // a + b
+
+si_int __subvsi3(si_int a, si_int b); // a - b
+di_int __subvdi3(di_int a, di_int b); // a - b
+ti_int __subvti3(ti_int a, ti_int b); // a - b
+
+si_int __mulvsi3(si_int a, si_int b); // a * b
+di_int __mulvdi3(di_int a, di_int b); // a * b
+ti_int __mulvti3(ti_int a, ti_int b); // a * b
+
+
+// Integral arithmetic which returns if overflow
+
+si_int __mulosi4(si_int a, si_int b, int* overflow); // a * b, overflow set to one if result not in signed range
+di_int __mulodi4(di_int a, di_int b, int* overflow); // a * b, overflow set to one if result not in signed range
+ti_int __muloti4(ti_int a, ti_int b, int* overflow); // a * b, overflow set to
+ one if result not in signed range
+
+
+// Integral comparison: a < b -> 0
+// a == b -> 1
+// a > b -> 2
+
+si_int __cmpdi2 (di_int a, di_int b);
+si_int __cmpti2 (ti_int a, ti_int b);
+si_int __ucmpdi2(du_int a, du_int b);
+si_int __ucmpti2(tu_int a, tu_int b);
+
+// Integral / floating point conversion
+
+di_int __fixsfdi( float a);
+di_int __fixdfdi( double a);
+di_int __fixxfdi(long double a);
+
+ti_int __fixsfti( float a);
+ti_int __fixdfti( double a);
+ti_int __fixxfti(long double a);
+uint64_t __fixtfdi(long double input); // ppc only, doesn't match documentation
+
+su_int __fixunssfsi( float a);
+su_int __fixunsdfsi( double a);
+su_int __fixunsxfsi(long double a);
+
+du_int __fixunssfdi( float a);
+du_int __fixunsdfdi( double a);
+du_int __fixunsxfdi(long double a);
+
+tu_int __fixunssfti( float a);
+tu_int __fixunsdfti( double a);
+tu_int __fixunsxfti(long double a);
+uint64_t __fixunstfdi(long double input); // ppc only
+
+float __floatdisf(di_int a);
+double __floatdidf(di_int a);
+long double __floatdixf(di_int a);
+long double __floatditf(int64_t a); // ppc only
+
+float __floattisf(ti_int a);
+double __floattidf(ti_int a);
+long double __floattixf(ti_int a);
+
+float __floatundisf(du_int a);
+double __floatundidf(du_int a);
+long double __floatundixf(du_int a);
+long double __floatunditf(uint64_t a); // ppc only
+
+float __floatuntisf(tu_int a);
+double __floatuntidf(tu_int a);
+long double __floatuntixf(tu_int a);
+
+// Floating point raised to integer power
+
+float __powisf2( float a, si_int b); // a ^ b
+double __powidf2( double a, si_int b); // a ^ b
+long double __powixf2(long double a, si_int b); // a ^ b
+long double __powitf2(long double a, si_int b); // ppc only, a ^ b
+
+// Complex arithmetic
+
+// (a + ib) * (c + id)
+
+ float _Complex __mulsc3( float a, float b, float c, float d);
+ double _Complex __muldc3(double a, double b, double c, double d);
+long double _Complex __mulxc3(long double a, long double b,
+ long double c, long double d);
+long double _Complex __multc3(long double a, long double b,
+ long double c, long double d); // ppc only
+
+// (a + ib) / (c + id)
+
+ float _Complex __divsc3( float a, float b, float c, float d);
+ double _Complex __divdc3(double a, double b, double c, double d);
+long double _Complex __divxc3(long double a, long double b,
+ long double c, long double d);
+long double _Complex __divtc3(long double a, long double b,
+ long double c, long double d); // ppc only
+
+
+// Runtime support
+
+// __clear_cache() is used to tell process that new instructions have been
+// written to an address range. Necessary on processors that do not have
+// a unified instruction and data cache.
+void __clear_cache(void* start, void* end);
+
+// __enable_execute_stack() is used with nested functions when a trampoline
+// function is written onto the stack and that page range needs to be made
+// executable.
+void __enable_execute_stack(void* addr);
+
+// __gcc_personality_v0() is normally only called by the system unwinder.
+// C code (as opposed to C++) normally does not need a personality function
+// because there are no catch clauses or destructors to be run. But there
+// is a C language extension __attribute__((cleanup(func))) which marks local
+// variables as needing the cleanup function "func" to be run when the
+// variable goes out of scope. That includes when an exception is thrown,
+// so a personality handler is needed.
+_Unwind_Reason_Code __gcc_personality_v0(int version, _Unwind_Action actions,
+ uint64_t exceptionClass, struct _Unwind_Exception* exceptionObject,
+ _Unwind_Context_t context);
+
+// 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);
+
+
+
+// Power PC specific functions
+
+// There is no C interface to the saveFP/restFP functions. They are helper
+// functions called by the prolog and epilog of functions that need to save
+// a number of non-volatile float point registers.
+saveFP
+restFP
+
+// PowerPC has a standard template for trampoline functions. This function
+// generates a custom trampoline function with the specific realFunc
+// and localsPtr values.
+void __trampoline_setup(uint32_t* trampOnStack, int trampSizeAllocated,
+ const void* realFunc, void* localsPtr);
+
+// adds two 128-bit double-double precision values ( x + y )
+long double __gcc_qadd(long double x, long double y);
+
+// subtracts two 128-bit double-double precision values ( x - y )
+long double __gcc_qsub(long double x, long double y);
+
+// multiples two 128-bit double-double precision values ( x * y )
+long double __gcc_qmul(long double x, long double y);
+
+// divides two 128-bit double-double precision values ( x / y )
+long double __gcc_qdiv(long double a, long double b);
+
+
+// ARM specific functions
+
+// There is no C interface to the switch* functions. These helper functions
+// are only needed by Thumb1 code for efficient switch table generation.
+switch16
+switch32
+switch8
+switchu8
+
+// There is no C interface to the *_vfp_d8_d15_regs functions. There are
+// called in the prolog and epilog of Thumb1 functions. When the C++ ABI use
+// SJLJ for exceptions, each function with a catch clause or destuctors needs
+// to save and restore all registers in it prolog and epliog. But there is
+// no way to access vector and high float registers from thumb1 code, so the
+// compiler must add call outs to these helper functions in the prolog and
+// epilog.
+restore_vfp_d8_d15_regs
+save_vfp_d8_d15_regs
+
+
+// Note: long ago ARM processors did not have floating point hardware support.
+// Floating point was done in software and floating point parameters were
+// passed in integer registers. When hardware support was added for floating
+// point, new *vfp functions were added to do the same operations but with
+// floating point parameters in floating point registers.
+
+// Undocumented functions
+
+float __addsf3vfp(float a, float b); // Appears to return a + b
+double __adddf3vfp(double a, double b); // Appears to return a + b
+float __divsf3vfp(float a, float b); // Appears to return a / b
+double __divdf3vfp(double a, double b); // Appears to return a / b
+int __eqsf2vfp(float a, float b); // Appears to return one
+ // iff a == b and neither is NaN.
+int __eqdf2vfp(double a, double b); // Appears to return one
+ // iff a == b and neither is NaN.
+double __extendsfdf2vfp(float a); // Appears to convert from
+ // float to double.
+int __fixdfsivfp(double a); // Appears to convert from
+ // double to int.
+int __fixsfsivfp(float a); // Appears to convert from
+ // float to int.
+unsigned int __fixunssfsivfp(float a); // Appears to convert from
+ // float to unsigned int.
+unsigned int __fixunsdfsivfp(double a); // Appears to convert from
+ // double to unsigned int.
+double __floatsidfvfp(int a); // Appears to convert from
+ // int to double.
+float __floatsisfvfp(int a); // Appears to convert from
+ // int to float.
+double __floatunssidfvfp(unsigned int a); // Appears to convert from
+ // unisgned int to double.
+float __floatunssisfvfp(unsigned int a); // Appears to convert from
+ // unisgned int to float.
+int __gedf2vfp(double a, double b); // Appears to return __gedf2
+ // (a >= b)
+int __gesf2vfp(float a, float b); // Appears to return __gesf2
+ // (a >= b)
+int __gtdf2vfp(double a, double b); // Appears to return __gtdf2
+ // (a > b)
+int __gtsf2vfp(float a, float b); // Appears to return __gtsf2
+ // (a > b)
+int __ledf2vfp(double a, double b); // Appears to return __ledf2
+ // (a <= b)
+int __lesf2vfp(float a, float b); // Appears to return __lesf2
+ // (a <= b)
+int __ltdf2vfp(double a, double b); // Appears to return __ltdf2
+ // (a < b)
+int __ltsf2vfp(float a, float b); // Appears to return __ltsf2
+ // (a < b)
+double __muldf3vfp(double a, double b); // Appears to return a * b
+float __mulsf3vfp(float a, float b); // Appears to return a * b
+int __nedf2vfp(double a, double b); // Appears to return __nedf2
+ // (a != b)
+double __negdf2vfp(double a); // Appears to return -a
+float __negsf2vfp(float a); // Appears to return -a
+float __negsf2vfp(float a); // Appears to return -a
+double __subdf3vfp(double a, double b); // Appears to return a - b
+float __subsf3vfp(float a, float b); // Appears to return a - b
+float __truncdfsf2vfp(double a); // Appears to convert from
+ // double to float.
+int __unorddf2vfp(double a, double b); // Appears to return __unorddf2
+int __unordsf2vfp(float a, float b); // Appears to return __unordsf2
+
+
+Preconditions are listed for each function at the definition when there are any.
+Any preconditions reflect the specification at
+http://gcc.gnu.org/onlinedocs/gccint/Libgcc.html#Libgcc.
+
+Assumptions are listed in "int_lib.h", and in individual files. Where possible
+assumptions are checked at compile time.
diff --git a/lib/absvdi2.c b/lib/builtins/absvdi2.c
index 682c2355d2ac..682c2355d2ac 100644
--- a/lib/absvdi2.c
+++ b/lib/builtins/absvdi2.c
diff --git a/lib/absvsi2.c b/lib/builtins/absvsi2.c
index 4812af815982..4812af815982 100644
--- a/lib/absvsi2.c
+++ b/lib/builtins/absvsi2.c
diff --git a/lib/builtins/absvti2.c b/lib/builtins/absvti2.c
new file mode 100644
index 000000000000..7927770c9ab3
--- /dev/null
+++ b/lib/builtins/absvti2.c
@@ -0,0 +1,34 @@
+/* ===-- absvti2.c - Implement __absvdi2 -----------------------------------===
+ *
+ * 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 __absvti2 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+/* Returns: absolute value */
+
+/* Effects: aborts if abs(x) < 0 */
+
+COMPILER_RT_ABI ti_int
+__absvti2(ti_int a)
+{
+ const int N = (int)(sizeof(ti_int) * CHAR_BIT);
+ if (a == ((ti_int)1 << (N-1)))
+ compilerrt_abort();
+ const ti_int s = a >> (N - 1);
+ return (a ^ s) - s;
+}
+
+#endif /* CRT_HAS_128BIT */
+
diff --git a/lib/builtins/adddf3.c b/lib/builtins/adddf3.c
new file mode 100644
index 000000000000..8b7aae0a6f87
--- /dev/null
+++ b/lib/builtins/adddf3.c
@@ -0,0 +1,22 @@
+//===-- lib/adddf3.c - Double-precision addition ------------------*- 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 double-precision soft-float addition with the IEEE-754
+// default rounding (to nearest, ties to even).
+//
+//===----------------------------------------------------------------------===//
+
+#define DOUBLE_PRECISION
+#include "fp_add_impl.inc"
+
+ARM_EABI_FNALIAS(dadd, adddf3)
+
+COMPILER_RT_ABI double __adddf3(double a, double b){
+ return __addXf3__(a, b);
+}
diff --git a/lib/builtins/addsf3.c b/lib/builtins/addsf3.c
new file mode 100644
index 000000000000..0f5d6ea4097a
--- /dev/null
+++ b/lib/builtins/addsf3.c
@@ -0,0 +1,22 @@
+//===-- lib/addsf3.c - Single-precision addition ------------------*- 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 single-precision soft-float addition with the IEEE-754
+// default rounding (to nearest, ties to even).
+//
+//===----------------------------------------------------------------------===//
+
+#define SINGLE_PRECISION
+#include "fp_add_impl.inc"
+
+ARM_EABI_FNALIAS(fadd, addsf3)
+
+COMPILER_RT_ABI float __addsf3(float a, float b) {
+ return __addXf3__(a, b);
+}
diff --git a/lib/builtins/addtf3.c b/lib/builtins/addtf3.c
new file mode 100644
index 000000000000..e4bbe0227ae6
--- /dev/null
+++ b/lib/builtins/addtf3.c
@@ -0,0 +1,25 @@
+//===-- lib/addtf3.c - Quad-precision addition --------------------*- 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 quad-precision soft-float addition with the IEEE-754
+// default rounding (to nearest, ties to even).
+//
+//===----------------------------------------------------------------------===//
+
+#define QUAD_PRECISION
+#include "fp_lib.h"
+
+#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
+#include "fp_add_impl.inc"
+
+COMPILER_RT_ABI long double __addtf3(long double a, long double b){
+ return __addXf3__(a, b);
+}
+
+#endif
diff --git a/lib/builtins/addvdi3.c b/lib/builtins/addvdi3.c
new file mode 100644
index 000000000000..0da38945679d
--- /dev/null
+++ b/lib/builtins/addvdi3.c
@@ -0,0 +1,36 @@
+/* ===-- addvdi3.c - Implement __addvdi3 -----------------------------------===
+ *
+ * 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 __addvdi3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: a + b */
+
+/* Effects: aborts if a + b overflows */
+
+COMPILER_RT_ABI di_int
+__addvdi3(di_int a, di_int b)
+{
+ di_int s = (du_int) a + (du_int) b;
+ if (b >= 0)
+ {
+ if (s < a)
+ compilerrt_abort();
+ }
+ else
+ {
+ if (s >= a)
+ compilerrt_abort();
+ }
+ return s;
+}
diff --git a/lib/builtins/addvsi3.c b/lib/builtins/addvsi3.c
new file mode 100644
index 000000000000..94ca726f42b9
--- /dev/null
+++ b/lib/builtins/addvsi3.c
@@ -0,0 +1,36 @@
+/* ===-- addvsi3.c - Implement __addvsi3 -----------------------------------===
+ *
+ * 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 __addvsi3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: a + b */
+
+/* Effects: aborts if a + b overflows */
+
+COMPILER_RT_ABI si_int
+__addvsi3(si_int a, si_int b)
+{
+ si_int s = (su_int) a + (su_int) b;
+ if (b >= 0)
+ {
+ if (s < a)
+ compilerrt_abort();
+ }
+ else
+ {
+ if (s >= a)
+ compilerrt_abort();
+ }
+ return s;
+}
diff --git a/lib/builtins/addvti3.c b/lib/builtins/addvti3.c
new file mode 100644
index 000000000000..c224de60aab0
--- /dev/null
+++ b/lib/builtins/addvti3.c
@@ -0,0 +1,40 @@
+/* ===-- addvti3.c - Implement __addvti3 -----------------------------------===
+ *
+ * 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 __addvti3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+/* Returns: a + b */
+
+/* Effects: aborts if a + b overflows */
+
+COMPILER_RT_ABI ti_int
+__addvti3(ti_int a, ti_int b)
+{
+ ti_int s = (tu_int) a + (tu_int) b;
+ if (b >= 0)
+ {
+ if (s < a)
+ compilerrt_abort();
+ }
+ else
+ {
+ if (s >= a)
+ compilerrt_abort();
+ }
+ return s;
+}
+
+#endif /* CRT_HAS_128BIT */
diff --git a/lib/apple_versioning.c b/lib/builtins/apple_versioning.c
index 3797a1ab02da..3797a1ab02da 100644
--- a/lib/apple_versioning.c
+++ b/lib/builtins/apple_versioning.c
diff --git a/lib/builtins/arm/Makefile.mk b/lib/builtins/arm/Makefile.mk
new file mode 100644
index 000000000000..ed2e8323e391
--- /dev/null
+++ b/lib/builtins/arm/Makefile.mk
@@ -0,0 +1,20 @@
+#===- lib/builtins/arm/Makefile.mk -------------------------*- Makefile -*--===#
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+
+ModuleName := builtins
+SubDirs :=
+OnlyArchs := armv5 armv6 armv7 armv7k armv7m armv7em armv7s
+
+AsmSources := $(foreach file,$(wildcard $(Dir)/*.S),$(notdir $(file)))
+Sources := $(foreach file,$(wildcard $(Dir)/*.c),$(notdir $(file)))
+ObjNames := $(Sources:%.c=%.o) $(AsmSources:%.S=%.o)
+Implementation := Optimized
+
+# FIXME: use automatic dependencies?
+Dependencies := $(wildcard lib/*.h $(Dir)/*.h)
diff --git a/lib/builtins/arm/adddf3vfp.S b/lib/builtins/arm/adddf3vfp.S
new file mode 100644
index 000000000000..2825ae92cd5a
--- /dev/null
+++ b/lib/builtins/arm/adddf3vfp.S
@@ -0,0 +1,26 @@
+//===-- adddf3vfp.S - Implement adddf3vfp ---------------------------------===//
+//
+// 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"
+
+//
+// double __adddf3vfp(double a, double b) { return a + b; }
+//
+// Adds two double precision floating point numbers using the Darwin
+// calling convention where double arguments are passsed in GPR pairs
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__adddf3vfp)
+ vmov d6, r0, r1 // move first param from r0/r1 pair into d6
+ vmov d7, r2, r3 // move second param from r2/r3 pair into d7
+ vadd.f64 d6, d6, d7
+ vmov r0, r1, d6 // move result back to r0/r1 pair
+ bx lr
+END_COMPILERRT_FUNCTION(__adddf3vfp)
diff --git a/lib/builtins/arm/addsf3vfp.S b/lib/builtins/arm/addsf3vfp.S
new file mode 100644
index 000000000000..bff5a7e0fbe8
--- /dev/null
+++ b/lib/builtins/arm/addsf3vfp.S
@@ -0,0 +1,26 @@
+//===-- addsf3vfp.S - Implement addsf3vfp ---------------------------------===//
+//
+// 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"
+
+//
+// extern float __addsf3vfp(float a, float b);
+//
+// Adds two single precision floating point numbers using the Darwin
+// calling convention where single arguments are passsed in GPRs
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__addsf3vfp)
+ vmov s14, r0 // move first param from r0 into float register
+ vmov s15, r1 // move second param from r1 into float register
+ vadd.f32 s14, s14, s15
+ vmov r0, s14 // move result back to r0
+ bx lr
+END_COMPILERRT_FUNCTION(__addsf3vfp)
diff --git a/lib/builtins/arm/aeabi_dcmp.S b/lib/builtins/arm/aeabi_dcmp.S
new file mode 100644
index 000000000000..310c35b74932
--- /dev/null
+++ b/lib/builtins/arm/aeabi_dcmp.S
@@ -0,0 +1,40 @@
+//===-- aeabi_dcmp.S - EABI dcmp* 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"
+
+// int __aeabi_dcmp{eq,lt,le,ge,gt}(double a, double b) {
+// int result = __{eq,lt,le,ge,gt}df2(a, b);
+// if (result {==,<,<=,>=,>} 0) {
+// return 1;
+// } else {
+// return 0;
+// }
+// }
+
+#define DEFINE_AEABI_DCMP(cond) \
+ .syntax unified SEPARATOR \
+ .p2align 2 SEPARATOR \
+DEFINE_COMPILERRT_FUNCTION(__aeabi_dcmp ## cond) \
+ push { r4, lr } SEPARATOR \
+ bl SYMBOL_NAME(__ ## cond ## df2) SEPARATOR \
+ cmp r0, #0 SEPARATOR \
+ b ## cond 1f SEPARATOR \
+ mov r0, #0 SEPARATOR \
+ pop { r4, pc } SEPARATOR \
+1: SEPARATOR \
+ mov r0, #1 SEPARATOR \
+ pop { r4, pc } SEPARATOR \
+END_COMPILERRT_FUNCTION(__aeabi_dcmp ## cond)
+
+DEFINE_AEABI_DCMP(eq)
+DEFINE_AEABI_DCMP(lt)
+DEFINE_AEABI_DCMP(le)
+DEFINE_AEABI_DCMP(ge)
+DEFINE_AEABI_DCMP(gt)
diff --git a/lib/builtins/arm/aeabi_div0.c b/lib/builtins/arm/aeabi_div0.c
new file mode 100644
index 000000000000..ccc95fa5c12e
--- /dev/null
+++ b/lib/builtins/arm/aeabi_div0.c
@@ -0,0 +1,43 @@
+/* ===-- aeabi_div0.c - ARM Runtime ABI support routines for compiler-rt ---===
+ *
+ * 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 the division by zero helper routines as specified by the
+ * Run-time ABI for the ARM Architecture.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+/*
+ * RTABI 4.3.2 - Division by zero
+ *
+ * The *div0 functions:
+ * - Return the value passed to them as a parameter
+ * - Or, return a fixed value defined by the execution environment (such as 0)
+ * - Or, raise a signal (often SIGFPE) or throw an exception, and do not return
+ *
+ * An application may provide its own implementations of the *div0 functions to
+ * for a particular behaviour from the *div and *divmod functions called out of
+ * line.
+ */
+
+/* provide an unused declaration to pacify pendantic compilation */
+extern unsigned char declaration;
+
+#if defined(__ARM_EABI__)
+int __attribute__((weak)) __attribute__((visibility("hidden")))
+__aeabi_idiv0(int return_value) {
+ return return_value;
+}
+
+long long __attribute__((weak)) __attribute__((visibility("hidden")))
+__aeabi_ldiv0(long long return_value) {
+ return return_value;
+}
+#endif
+
diff --git a/lib/builtins/arm/aeabi_fcmp.S b/lib/builtins/arm/aeabi_fcmp.S
new file mode 100644
index 000000000000..55f49a2b5af6
--- /dev/null
+++ b/lib/builtins/arm/aeabi_fcmp.S
@@ -0,0 +1,40 @@
+//===-- aeabi_fcmp.S - EABI fcmp* 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"
+
+// int __aeabi_fcmp{eq,lt,le,ge,gt}(float a, float b) {
+// int result = __{eq,lt,le,ge,gt}sf2(a, b);
+// if (result {==,<,<=,>=,>} 0) {
+// return 1;
+// } else {
+// return 0;
+// }
+// }
+
+#define DEFINE_AEABI_FCMP(cond) \
+ .syntax unified SEPARATOR \
+ .p2align 2 SEPARATOR \
+DEFINE_COMPILERRT_FUNCTION(__aeabi_fcmp ## cond) \
+ push { r4, lr } SEPARATOR \
+ bl SYMBOL_NAME(__ ## cond ## sf2) SEPARATOR \
+ cmp r0, #0 SEPARATOR \
+ b ## cond 1f SEPARATOR \
+ mov r0, #0 SEPARATOR \
+ pop { r4, pc } SEPARATOR \
+1: SEPARATOR \
+ mov r0, #1 SEPARATOR \
+ pop { r4, pc } SEPARATOR \
+END_COMPILERRT_FUNCTION(__aeabi_fcmp ## cond)
+
+DEFINE_AEABI_FCMP(eq)
+DEFINE_AEABI_FCMP(lt)
+DEFINE_AEABI_FCMP(le)
+DEFINE_AEABI_FCMP(ge)
+DEFINE_AEABI_FCMP(gt)
diff --git a/lib/builtins/arm/aeabi_idivmod.S b/lib/builtins/arm/aeabi_idivmod.S
new file mode 100644
index 000000000000..384add38279e
--- /dev/null
+++ b/lib/builtins/arm/aeabi_idivmod.S
@@ -0,0 +1,28 @@
+//===-- aeabi_idivmod.S - EABI idivmod 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"
+
+// struct { int quot, int rem} __aeabi_idivmod(int numerator, int denominator) {
+// int rem, quot;
+// quot = __divmodsi4(numerator, denominator, &rem);
+// return {quot, rem};
+// }
+
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__aeabi_idivmod)
+ push { lr }
+ sub sp, sp, #4
+ mov r2, sp
+ bl SYMBOL_NAME(__divmodsi4)
+ ldr r1, [sp]
+ add sp, sp, #4
+ pop { pc }
+END_COMPILERRT_FUNCTION(__aeabi_idivmod)
diff --git a/lib/builtins/arm/aeabi_ldivmod.S b/lib/builtins/arm/aeabi_ldivmod.S
new file mode 100644
index 000000000000..ad06f1de2af4
--- /dev/null
+++ b/lib/builtins/arm/aeabi_ldivmod.S
@@ -0,0 +1,31 @@
+//===-- aeabi_ldivmod.S - EABI ldivmod 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"
+
+// struct { int64_t quot, int64_t rem}
+// __aeabi_ldivmod(int64_t numerator, int64_t denominator) {
+// int64_t rem, quot;
+// quot = __divmoddi4(numerator, denominator, &rem);
+// return {quot, rem};
+// }
+
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__aeabi_ldivmod)
+ push {r11, lr}
+ sub sp, sp, #16
+ add r12, sp, #8
+ str r12, [sp]
+ bl SYMBOL_NAME(__divmoddi4)
+ ldr r2, [sp, #8]
+ ldr r3, [sp, #12]
+ add sp, sp, #16
+ pop {r11, pc}
+END_COMPILERRT_FUNCTION(__aeabi_ldivmod)
diff --git a/lib/builtins/arm/aeabi_memcmp.S b/lib/builtins/arm/aeabi_memcmp.S
new file mode 100644
index 000000000000..051ce435bab9
--- /dev/null
+++ b/lib/builtins/arm/aeabi_memcmp.S
@@ -0,0 +1,20 @@
+//===-- aeabi_memcmp.S - EABI memcmp 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"
+
+// void __aeabi_memcmp(void *dest, void *src, size_t n) { memcmp(dest, src, n); }
+
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__aeabi_memcmp)
+ b memcmp
+END_COMPILERRT_FUNCTION(__aeabi_memcmp)
+
+DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memcmp4, __aeabi_memcmp)
+DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memcmp8, __aeabi_memcmp)
diff --git a/lib/builtins/arm/aeabi_memcpy.S b/lib/builtins/arm/aeabi_memcpy.S
new file mode 100644
index 000000000000..cf02332490a1
--- /dev/null
+++ b/lib/builtins/arm/aeabi_memcpy.S
@@ -0,0 +1,20 @@
+//===-- aeabi_memcpy.S - EABI memcpy 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"
+
+// void __aeabi_memcpy(void *dest, void *src, size_t n) { memcpy(dest, src, n); }
+
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__aeabi_memcpy)
+ b memcpy
+END_COMPILERRT_FUNCTION(__aeabi_memcpy)
+
+DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memcpy4, __aeabi_memcpy)
+DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memcpy8, __aeabi_memcpy)
diff --git a/lib/builtins/arm/aeabi_memmove.S b/lib/builtins/arm/aeabi_memmove.S
new file mode 100644
index 000000000000..4dda06f75d04
--- /dev/null
+++ b/lib/builtins/arm/aeabi_memmove.S
@@ -0,0 +1,20 @@
+//===-- aeabi_memmove.S - EABI memmove 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"
+
+// void __aeabi_memmove(void *dest, void *src, size_t n) { memmove(dest, src, n); }
+
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__aeabi_memmove)
+ b memmove
+END_COMPILERRT_FUNCTION(__aeabi_memmove)
+
+DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memmove4, __aeabi_memmove)
+DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memmove8, __aeabi_memmove)
diff --git a/lib/builtins/arm/aeabi_memset.S b/lib/builtins/arm/aeabi_memset.S
new file mode 100644
index 000000000000..c8b49c7809a6
--- /dev/null
+++ b/lib/builtins/arm/aeabi_memset.S
@@ -0,0 +1,34 @@
+//===-- aeabi_memset.S - EABI memset 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"
+
+// void __aeabi_memset(void *dest, size_t n, int c) { memset(dest, c, n); }
+// void __aeabi_memclr(void *dest, size_t n) { __aeabi_memset(dest, n, 0); }
+
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__aeabi_memset)
+ mov r3, r1
+ mov r1, r2
+ mov r2, r3
+ b memset
+END_COMPILERRT_FUNCTION(__aeabi_memset)
+
+DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memset4, __aeabi_memset)
+DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memset8, __aeabi_memset)
+
+DEFINE_COMPILERRT_FUNCTION(__aeabi_memclr)
+ mov r2, r1
+ mov r1, #0
+ b memset
+END_COMPILERRT_FUNCTION(__aeabi_memclr)
+
+DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memclr4, __aeabi_memclr)
+DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memclr8, __aeabi_memclr)
+
diff --git a/lib/builtins/arm/aeabi_uidivmod.S b/lib/builtins/arm/aeabi_uidivmod.S
new file mode 100644
index 000000000000..8ea474d91c6b
--- /dev/null
+++ b/lib/builtins/arm/aeabi_uidivmod.S
@@ -0,0 +1,29 @@
+//===-- aeabi_uidivmod.S - EABI uidivmod 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"
+
+// struct { unsigned quot, unsigned rem}
+// __aeabi_uidivmod(unsigned numerator, unsigned denominator) {
+// unsigned rem, quot;
+// quot = __udivmodsi4(numerator, denominator, &rem);
+// return {quot, rem};
+// }
+
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__aeabi_uidivmod)
+ push { lr }
+ sub sp, sp, #4
+ mov r2, sp
+ bl SYMBOL_NAME(__udivmodsi4)
+ ldr r1, [sp]
+ add sp, sp, #4
+ pop { pc }
+END_COMPILERRT_FUNCTION(__aeabi_uidivmod)
diff --git a/lib/builtins/arm/aeabi_uldivmod.S b/lib/builtins/arm/aeabi_uldivmod.S
new file mode 100644
index 000000000000..4e1f8e2a6736
--- /dev/null
+++ b/lib/builtins/arm/aeabi_uldivmod.S
@@ -0,0 +1,31 @@
+//===-- aeabi_uldivmod.S - EABI uldivmod 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"
+
+// struct { uint64_t quot, uint64_t rem}
+// __aeabi_uldivmod(uint64_t numerator, uint64_t denominator) {
+// uint64_t rem, quot;
+// quot = __udivmoddi4(numerator, denominator, &rem);
+// return {quot, rem};
+// }
+
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__aeabi_uldivmod)
+ push {r11, lr}
+ sub sp, sp, #16
+ add r12, sp, #8
+ str r12, [sp]
+ bl SYMBOL_NAME(__udivmoddi4)
+ ldr r2, [sp, #8]
+ ldr r3, [sp, #12]
+ add sp, sp, #16
+ pop {r11, pc}
+END_COMPILERRT_FUNCTION(__aeabi_uldivmod)
diff --git a/lib/builtins/arm/bswapdi2.S b/lib/builtins/arm/bswapdi2.S
new file mode 100644
index 000000000000..86f3bba8c290
--- /dev/null
+++ b/lib/builtins/arm/bswapdi2.S
@@ -0,0 +1,47 @@
+//===------- bswapdi2 - Implement bswapdi2 --------------------------------===//
+//
+// 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"
+
+ .syntax unified
+ .text
+#if __ARM_ARCH_ISA_THUMB == 2
+ .thumb
+#endif
+
+//
+// extern uint64_t __bswapdi2(uint64_t);
+//
+// Reverse all the bytes in a 64-bit integer.
+//
+ .p2align 2
+#if __ARM_ARCH_ISA_THUMB == 2
+DEFINE_COMPILERRT_THUMB_FUNCTION(__bswapdi2)
+#else
+DEFINE_COMPILERRT_FUNCTION(__bswapdi2)
+#endif
+#if __ARM_ARCH < 6
+ // before armv6 does not have "rev" instruction
+ // r2 = rev(r0)
+ eor r2, r0, r0, ror #16
+ bic r2, r2, #0xff0000
+ mov r2, r2, lsr #8
+ eor r2, r2, r0, ror #8
+ // r0 = rev(r1)
+ eor r0, r1, r1, ror #16
+ bic r0, r0, #0xff0000
+ mov r0, r0, lsr #8
+ eor r0, r0, r1, ror #8
+#else
+ rev r2, r0 // r2 = rev(r0)
+ rev r0, r1 // r0 = rev(r1)
+#endif
+ mov r1, r2 // r1 = r2 = rev(r0)
+ JMP(lr)
+END_COMPILERRT_FUNCTION(__bswapdi2)
diff --git a/lib/builtins/arm/bswapsi2.S b/lib/builtins/arm/bswapsi2.S
new file mode 100644
index 000000000000..59ba8158fd57
--- /dev/null
+++ b/lib/builtins/arm/bswapsi2.S
@@ -0,0 +1,39 @@
+//===------- bswapsi2 - Implement bswapsi2 --------------------------------===//
+//
+// 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"
+
+ .syntax unified
+ .text
+#if __ARM_ARCH_ISA_THUMB == 2
+ .thumb
+#endif
+
+//
+// extern uint32_t __bswapsi2(uint32_t);
+//
+// Reverse all the bytes in a 32-bit integer.
+//
+ .p2align 2
+#if __ARM_ARCH_ISA_THUMB == 2
+DEFINE_COMPILERRT_THUMB_FUNCTION(__bswapsi2)
+#else
+DEFINE_COMPILERRT_FUNCTION(__bswapsi2)
+#endif
+#if __ARM_ARCH < 6
+ // before armv6 does not have "rev" instruction
+ eor r1, r0, r0, ror #16
+ bic r1, r1, #0xff0000
+ mov r1, r1, lsr #8
+ eor r0, r1, r0, ror #8
+#else
+ rev r0, r0
+#endif
+ JMP(lr)
+END_COMPILERRT_FUNCTION(__bswapsi2)
diff --git a/lib/builtins/arm/clzdi2.S b/lib/builtins/arm/clzdi2.S
new file mode 100644
index 000000000000..a55abac0469b
--- /dev/null
+++ b/lib/builtins/arm/clzdi2.S
@@ -0,0 +1,97 @@
+/* ===-- clzdi2.c - Implement __clzdi2 -------------------------------------===
+ *
+ * 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 count leading zeros for 64bit arguments.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+#include "../assembly.h"
+
+ .syntax unified
+ .text
+#if __ARM_ARCH_ISA_THUMB == 2
+ .thumb
+#endif
+
+
+ .p2align 2
+#if __ARM_ARCH_ISA_THUMB == 2
+DEFINE_COMPILERRT_THUMB_FUNCTION(__clzdi2)
+#else
+DEFINE_COMPILERRT_FUNCTION(__clzdi2)
+#endif
+#ifdef __ARM_FEATURE_CLZ
+#ifdef __ARMEB__
+ cmp r0, 0
+ itee ne
+ clzne r0, r0
+ clzeq r0, r1
+ addeq r0, r0, 32
+#else
+ cmp r1, 0
+ itee ne
+ clzne r0, r1
+ clzeq r0, r0
+ addeq r0, r0, 32
+#endif
+ JMP(lr)
+#else
+ /* Assumption: n != 0 */
+
+ /*
+ * r0: n
+ * r1: upper half of n, overwritten after check
+ * r1: count of leading zeros in n + 1
+ * r2: scratch register for shifted r0
+ */
+#ifdef __ARMEB__
+ cmp r0, 0
+ moveq r0, r1
+#else
+ cmp r1, 0
+ movne r0, r1
+#endif
+ movne r1, 1
+ moveq r1, 33
+
+ /*
+ * Basic block:
+ * if ((r0 >> SHIFT) == 0)
+ * r1 += SHIFT;
+ * else
+ * r0 >>= SHIFT;
+ * for descending powers of two as SHIFT.
+ */
+#define BLOCK(shift) \
+ lsrs r2, r0, shift; \
+ movne r0, r2; \
+ addeq r1, shift \
+
+ BLOCK(16)
+ BLOCK(8)
+ BLOCK(4)
+ BLOCK(2)
+
+ /*
+ * The basic block invariants at this point are (r0 >> 2) == 0 and
+ * r0 != 0. This means 1 <= r0 <= 3 and 0 <= (r0 >> 1) <= 1.
+ *
+ * r0 | (r0 >> 1) == 0 | (r0 >> 1) == 1 | -(r0 >> 1) | 1 - (r0 >> 1)
+ * ---+----------------+----------------+------------+--------------
+ * 1 | 1 | 0 | 0 | 1
+ * 2 | 0 | 1 | -1 | 0
+ * 3 | 0 | 1 | -1 | 0
+ *
+ * The r1's initial value of 1 compensates for the 1 here.
+ */
+ sub r0, r1, r0, lsr #1
+
+ JMP(lr)
+#endif // __ARM_FEATURE_CLZ
+END_COMPILERRT_FUNCTION(__clzdi2)
diff --git a/lib/builtins/arm/clzsi2.S b/lib/builtins/arm/clzsi2.S
new file mode 100644
index 000000000000..1cd379bfb0a9
--- /dev/null
+++ b/lib/builtins/arm/clzsi2.S
@@ -0,0 +1,76 @@
+/* ===-- clzsi2.c - Implement __clzsi2 -------------------------------------===
+ *
+ * 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 count leading zeros for 32bit arguments.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+#include "../assembly.h"
+
+ .syntax unified
+ .text
+#if __ARM_ARCH_ISA_THUMB == 2
+ .thumb
+#endif
+
+ .p2align 2
+#if __ARM_ARCH_ISA_THUMB == 2
+DEFINE_COMPILERRT_THUMB_FUNCTION(__clzsi2)
+#else
+DEFINE_COMPILERRT_FUNCTION(__clzsi2)
+#endif
+#ifdef __ARM_FEATURE_CLZ
+ clz r0, r0
+ JMP(lr)
+#else
+ /* Assumption: n != 0 */
+
+ /*
+ * r0: n
+ * r1: count of leading zeros in n + 1
+ * r2: scratch register for shifted r0
+ */
+ mov r1, 1
+
+ /*
+ * Basic block:
+ * if ((r0 >> SHIFT) == 0)
+ * r1 += SHIFT;
+ * else
+ * r0 >>= SHIFT;
+ * for descending powers of two as SHIFT.
+ */
+
+#define BLOCK(shift) \
+ lsrs r2, r0, shift; \
+ movne r0, r2; \
+ addeq r1, shift \
+
+ BLOCK(16)
+ BLOCK(8)
+ BLOCK(4)
+ BLOCK(2)
+
+ /*
+ * The basic block invariants at this point are (r0 >> 2) == 0 and
+ * r0 != 0. This means 1 <= r0 <= 3 and 0 <= (r0 >> 1) <= 1.
+ *
+ * r0 | (r0 >> 1) == 0 | (r0 >> 1) == 1 | -(r0 >> 1) | 1 - (r0 >> 1)
+ * ---+----------------+----------------+------------+--------------
+ * 1 | 1 | 0 | 0 | 1
+ * 2 | 0 | 1 | -1 | 0
+ * 3 | 0 | 1 | -1 | 0
+ *
+ * The r1's initial value of 1 compensates for the 1 here.
+ */
+ sub r0, r1, r0, lsr #1
+
+ JMP(lr)
+#endif // __ARM_FEATURE_CLZ
+END_COMPILERRT_FUNCTION(__clzsi2)
diff --git a/lib/builtins/arm/comparesf2.S b/lib/builtins/arm/comparesf2.S
new file mode 100644
index 000000000000..cf71d36e0517
--- /dev/null
+++ b/lib/builtins/arm/comparesf2.S
@@ -0,0 +1,148 @@
+//===-- comparesf2.S - Implement single-precision soft-float comparisons --===//
+//
+// 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 the following soft-fp_t comparison routines:
+//
+// __eqsf2 __gesf2 __unordsf2
+// __lesf2 __gtsf2
+// __ltsf2
+// __nesf2
+//
+// The semantics of the routines grouped in each column are identical, so there
+// is a single implementation for each, with multiple names.
+//
+// The routines behave as follows:
+//
+// __lesf2(a,b) returns -1 if a < b
+// 0 if a == b
+// 1 if a > b
+// 1 if either a or b is NaN
+//
+// __gesf2(a,b) returns -1 if a < b
+// 0 if a == b
+// 1 if a > b
+// -1 if either a or b is NaN
+//
+// __unordsf2(a,b) returns 0 if both a and b are numbers
+// 1 if either a or b is NaN
+//
+// Note that __lesf2( ) and __gesf2( ) are identical except in their handling of
+// NaN values.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+.syntax unified
+
+.p2align 2
+DEFINE_COMPILERRT_FUNCTION(__eqsf2)
+ // Make copies of a and b with the sign bit shifted off the top. These will
+ // be used to detect zeros and NaNs.
+ mov r2, r0, lsl #1
+ mov r3, r1, lsl #1
+
+ // We do the comparison in three stages (ignoring NaN values for the time
+ // being). First, we orr the absolute values of a and b; this sets the Z
+ // flag if both a and b are zero (of either sign). The shift of r3 doesn't
+ // effect this at all, but it *does* make sure that the C flag is clear for
+ // the subsequent operations.
+ orrs r12, r2, r3, lsr #1
+
+ // Next, we check if a and b have the same or different signs. If they have
+ // opposite signs, this eor will set the N flag.
+ it ne
+ eorsne r12, r0, r1
+
+ // If a and b are equal (either both zeros or bit identical; again, we're
+ // ignoring NaNs for now), this subtract will zero out r0. If they have the
+ // same sign, the flags are updated as they would be for a comparison of the
+ // absolute values of a and b.
+ it pl
+ subspl r0, r2, r3
+
+ // If a is smaller in magnitude than b and both have the same sign, place
+ // the negation of the sign of b in r0. Thus, if both are negative and
+ // a > b, this sets r0 to 0; if both are positive and a < b, this sets
+ // r0 to -1.
+ //
+ // This is also done if a and b have opposite signs and are not both zero,
+ // because in that case the subtract was not performed and the C flag is
+ // still clear from the shift argument in orrs; if a is positive and b
+ // negative, this places 0 in r0; if a is negative and b positive, -1 is
+ // placed in r0.
+ it lo
+ mvnlo r0, r1, asr #31
+
+ // If a is greater in magnitude than b and both have the same sign, place
+ // the sign of b in r0. Thus, if both are negative and a < b, -1 is placed
+ // in r0, which is the desired result. Conversely, if both are positive
+ // and a > b, zero is placed in r0.
+ it hi
+ movhi r0, r1, asr #31
+
+ // If you've been keeping track, at this point r0 contains -1 if a < b and
+ // 0 if a >= b. All that remains to be done is to set it to 1 if a > b.
+ // If a == b, then the Z flag is set, so we can get the correct final value
+ // into r0 by simply or'ing with 1 if Z is clear.
+ it ne
+ orrne r0, r0, #1
+
+ // Finally, we need to deal with NaNs. If either argument is NaN, replace
+ // the value in r0 with 1.
+ cmp r2, #0xff000000
+ ite ls
+ cmpls r3, #0xff000000
+ movhi r0, #1
+ JMP(lr)
+END_COMPILERRT_FUNCTION(__eqsf2)
+DEFINE_COMPILERRT_FUNCTION_ALIAS(__lesf2, __eqsf2)
+DEFINE_COMPILERRT_FUNCTION_ALIAS(__ltsf2, __eqsf2)
+DEFINE_COMPILERRT_FUNCTION_ALIAS(__nesf2, __eqsf2)
+
+.p2align 2
+DEFINE_COMPILERRT_FUNCTION(__gtsf2)
+ // Identical to the preceding except in that we return -1 for NaN values.
+ // Given that the two paths share so much code, one might be tempted to
+ // unify them; however, the extra code needed to do so makes the code size
+ // to performance tradeoff very hard to justify for such small functions.
+ mov r2, r0, lsl #1
+ mov r3, r1, lsl #1
+ orrs r12, r2, r3, lsr #1
+ it ne
+ eorsne r12, r0, r1
+ it pl
+ subspl r0, r2, r3
+ it lo
+ mvnlo r0, r1, asr #31
+ it hi
+ movhi r0, r1, asr #31
+ it ne
+ orrne r0, r0, #1
+ cmp r2, #0xff000000
+ ite ls
+ cmpls r3, #0xff000000
+ movhi r0, #-1
+ JMP(lr)
+END_COMPILERRT_FUNCTION(__gtsf2)
+DEFINE_COMPILERRT_FUNCTION_ALIAS(__gesf2, __gtsf2)
+
+.p2align 2
+DEFINE_COMPILERRT_FUNCTION(__unordsf2)
+ // Return 1 for NaN values, 0 otherwise.
+ mov r2, r0, lsl #1
+ mov r3, r1, lsl #1
+ mov r0, #0
+ cmp r2, #0xff000000
+ ite ls
+ cmpls r3, #0xff000000
+ movhi r0, #1
+ JMP(lr)
+END_COMPILERRT_FUNCTION(__unordsf2)
+
+DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_fcmpun, __unordsf2)
diff --git a/lib/builtins/arm/divdf3vfp.S b/lib/builtins/arm/divdf3vfp.S
new file mode 100644
index 000000000000..6eebef167a2c
--- /dev/null
+++ b/lib/builtins/arm/divdf3vfp.S
@@ -0,0 +1,26 @@
+//===-- divdf3vfp.S - Implement divdf3vfp ---------------------------------===//
+//
+// 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"
+
+//
+// extern double __divdf3vfp(double a, double b);
+//
+// Divides two double precision floating point numbers using the Darwin
+// calling convention where double arguments are passsed in GPR pairs
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__divdf3vfp)
+ vmov d6, r0, r1 // move first param from r0/r1 pair into d6
+ vmov d7, r2, r3 // move second param from r2/r3 pair into d7
+ vdiv.f64 d5, d6, d7
+ vmov r0, r1, d5 // move result back to r0/r1 pair
+ bx lr
+END_COMPILERRT_FUNCTION(__divdf3vfp)
diff --git a/lib/builtins/arm/divmodsi4.S b/lib/builtins/arm/divmodsi4.S
new file mode 100644
index 000000000000..646b9ab78fb6
--- /dev/null
+++ b/lib/builtins/arm/divmodsi4.S
@@ -0,0 +1,74 @@
+/*===-- divmodsi4.S - 32-bit signed integer divide and modulus ------------===//
+ *
+ * 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 the __divmodsi4 (32-bit signed integer divide and
+ * modulus) function for the ARM architecture. A naive digit-by-digit
+ * computation is employed for simplicity.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "../assembly.h"
+
+#define ESTABLISH_FRAME \
+ push {r4-r7, lr} ;\
+ add r7, sp, #12
+#define CLEAR_FRAME_AND_RETURN \
+ pop {r4-r7, pc}
+
+ .syntax unified
+ .text
+#if __ARM_ARCH_ISA_THUMB == 2
+ .thumb
+#endif
+
+@ int __divmodsi4(int divident, int divisor, int *remainder)
+@ Calculate the quotient and remainder of the (signed) division. The return
+@ value is the quotient, the remainder is placed in the variable.
+
+ .p2align 3
+#if __ARM_ARCH_ISA_THUMB == 2
+DEFINE_COMPILERRT_THUMB_FUNCTION(__divmodsi4)
+#else
+DEFINE_COMPILERRT_FUNCTION(__divmodsi4)
+#endif
+#if __ARM_ARCH_EXT_IDIV__
+ tst r1, r1
+ beq LOCAL_LABEL(divzero)
+ mov r3, r0
+ sdiv r0, r3, r1
+ mls r1, r0, r1, r3
+ str r1, [r2]
+ bx lr
+LOCAL_LABEL(divzero):
+ mov r0, #0
+ bx lr
+#else
+ ESTABLISH_FRAME
+// Set aside the sign of the quotient and modulus, and the address for the
+// modulus.
+ eor r4, r0, r1
+ mov r5, r0
+ mov r6, r2
+// Take the absolute value of a and b via abs(x) = (x^(x >> 31)) - (x >> 31).
+ eor ip, r0, r0, asr #31
+ eor lr, r1, r1, asr #31
+ sub r0, ip, r0, asr #31
+ sub r1, lr, r1, asr #31
+// Unsigned divmod:
+ bl SYMBOL_NAME(__udivmodsi4)
+// Apply the sign of quotient and modulus
+ ldr r1, [r6]
+ eor r0, r0, r4, asr #31
+ eor r1, r1, r5, asr #31
+ sub r0, r0, r4, asr #31
+ sub r1, r1, r5, asr #31
+ str r1, [r6]
+ CLEAR_FRAME_AND_RETURN
+#endif
+END_COMPILERRT_FUNCTION(__divmodsi4)
diff --git a/lib/builtins/arm/divsf3vfp.S b/lib/builtins/arm/divsf3vfp.S
new file mode 100644
index 000000000000..fdbaebc88371
--- /dev/null
+++ b/lib/builtins/arm/divsf3vfp.S
@@ -0,0 +1,26 @@
+//===-- divsf3vfp.S - Implement divsf3vfp ---------------------------------===//
+//
+// 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"
+
+//
+// extern float __divsf3vfp(float a, float b);
+//
+// Divides two single precision floating point numbers using the Darwin
+// calling convention where single arguments are passsed like 32-bit ints.
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__divsf3vfp)
+ vmov s14, r0 // move first param from r0 into float register
+ vmov s15, r1 // move second param from r1 into float register
+ vdiv.f32 s13, s14, s15
+ vmov r0, s13 // move result back to r0
+ bx lr
+END_COMPILERRT_FUNCTION(__divsf3vfp)
diff --git a/lib/builtins/arm/divsi3.S b/lib/builtins/arm/divsi3.S
new file mode 100644
index 000000000000..adf8f94fc7b8
--- /dev/null
+++ b/lib/builtins/arm/divsi3.S
@@ -0,0 +1,65 @@
+/*===-- divsi3.S - 32-bit signed integer divide ---------------------------===//
+ *
+ * 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 the __divsi3 (32-bit signed integer divide) function
+ * for the ARM architecture as a wrapper around the unsigned routine.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "../assembly.h"
+
+#define ESTABLISH_FRAME \
+ push {r4, r7, lr} ;\
+ add r7, sp, #4
+#define CLEAR_FRAME_AND_RETURN \
+ pop {r4, r7, pc}
+
+ .syntax unified
+ .text
+#if __ARM_ARCH_ISA_THUMB == 2
+ .thumb
+#endif
+
+ .p2align 3
+// Ok, APCS and AAPCS agree on 32 bit args, so it's safe to use the same routine.
+DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_idiv, __divsi3)
+
+@ int __divsi3(int divident, int divisor)
+@ Calculate and return the quotient of the (signed) division.
+
+#if __ARM_ARCH_ISA_THUMB == 2
+DEFINE_COMPILERRT_THUMB_FUNCTION(__divsi3)
+#else
+DEFINE_COMPILERRT_FUNCTION(__divsi3)
+#endif
+#if __ARM_ARCH_EXT_IDIV__
+ tst r1,r1
+ beq LOCAL_LABEL(divzero)
+ sdiv r0, r0, r1
+ bx lr
+LOCAL_LABEL(divzero):
+ mov r0,#0
+ bx lr
+#else
+ESTABLISH_FRAME
+// Set aside the sign of the quotient.
+ eor r4, r0, r1
+// Take absolute value of a and b via abs(x) = (x^(x >> 31)) - (x >> 31).
+ eor r2, r0, r0, asr #31
+ eor r3, r1, r1, asr #31
+ sub r0, r2, r0, asr #31
+ sub r1, r3, r1, asr #31
+// abs(a) / abs(b)
+ bl SYMBOL_NAME(__udivsi3)
+// Apply sign of quotient to result and return.
+ eor r0, r0, r4, asr #31
+ sub r0, r0, r4, asr #31
+ CLEAR_FRAME_AND_RETURN
+#endif
+END_COMPILERRT_FUNCTION(__divsi3)
diff --git a/lib/builtins/arm/eqdf2vfp.S b/lib/builtins/arm/eqdf2vfp.S
new file mode 100644
index 000000000000..7f2fbc3072d4
--- /dev/null
+++ b/lib/builtins/arm/eqdf2vfp.S
@@ -0,0 +1,29 @@
+//===-- eqdf2vfp.S - Implement eqdf2vfp -----------------------------------===//
+//
+// 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"
+
+//
+// extern int __eqdf2vfp(double a, double b);
+//
+// Returns one iff a == b and neither is NaN.
+// Uses Darwin calling convention where double precision arguments are passsed
+// like in GPR pairs.
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__eqdf2vfp)
+ vmov d6, r0, r1 // load r0/r1 pair in double register
+ vmov d7, r2, r3 // load r2/r3 pair in double register
+ vcmp.f64 d6, d7
+ vmrs apsr_nzcv, fpscr
+ moveq r0, #1 // set result register to 1 if equal
+ movne r0, #0
+ bx lr
+END_COMPILERRT_FUNCTION(__eqdf2vfp)
diff --git a/lib/builtins/arm/eqsf2vfp.S b/lib/builtins/arm/eqsf2vfp.S
new file mode 100644
index 000000000000..a318b336ae9e
--- /dev/null
+++ b/lib/builtins/arm/eqsf2vfp.S
@@ -0,0 +1,29 @@
+//===-- eqsf2vfp.S - Implement eqsf2vfp -----------------------------------===//
+//
+// 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"
+
+//
+// extern int __eqsf2vfp(float a, float b);
+//
+// Returns one iff a == b and neither is NaN.
+// Uses Darwin calling convention where single precision arguments are passsed
+// like 32-bit ints
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__eqsf2vfp)
+ vmov s14, r0 // move from GPR 0 to float register
+ vmov s15, r1 // move from GPR 1 to float register
+ vcmp.f32 s14, s15
+ vmrs apsr_nzcv, fpscr
+ moveq r0, #1 // set result register to 1 if equal
+ movne r0, #0
+ bx lr
+END_COMPILERRT_FUNCTION(__eqsf2vfp)
diff --git a/lib/builtins/arm/extendsfdf2vfp.S b/lib/builtins/arm/extendsfdf2vfp.S
new file mode 100644
index 000000000000..b998e589459e
--- /dev/null
+++ b/lib/builtins/arm/extendsfdf2vfp.S
@@ -0,0 +1,26 @@
+//===-- extendsfdf2vfp.S - Implement extendsfdf2vfp -----------------------===//
+//
+// 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"
+
+//
+// extern double __extendsfdf2vfp(float a);
+//
+// Converts single precision float to double precision result.
+// Uses Darwin calling convention where a single precision parameter is
+// passed in a GPR and a double precision result is returned in R0/R1 pair.
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__extendsfdf2vfp)
+ vmov s15, r0 // load float register from R0
+ vcvt.f64.f32 d7, s15 // convert single to double
+ vmov r0, r1, d7 // return result in r0/r1 pair
+ bx lr
+END_COMPILERRT_FUNCTION(__extendsfdf2vfp)
diff --git a/lib/builtins/arm/fixdfsivfp.S b/lib/builtins/arm/fixdfsivfp.S
new file mode 100644
index 000000000000..e3bd8e05e01f
--- /dev/null
+++ b/lib/builtins/arm/fixdfsivfp.S
@@ -0,0 +1,26 @@
+//===-- fixdfsivfp.S - Implement fixdfsivfp -----------------------===//
+//
+// 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"
+
+//
+// extern int __fixdfsivfp(double a);
+//
+// Converts double precision float to a 32-bit int rounding towards zero.
+// Uses Darwin calling convention where a double precision parameter is
+// passed in GPR register pair.
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__fixdfsivfp)
+ vmov d7, r0, r1 // load double register from R0/R1
+ vcvt.s32.f64 s15, d7 // convert double to 32-bit int into s15
+ vmov r0, s15 // move s15 to result register
+ bx lr
+END_COMPILERRT_FUNCTION(__fixdfsivfp)
diff --git a/lib/builtins/arm/fixsfsivfp.S b/lib/builtins/arm/fixsfsivfp.S
new file mode 100644
index 000000000000..3d0d0f56d235
--- /dev/null
+++ b/lib/builtins/arm/fixsfsivfp.S
@@ -0,0 +1,26 @@
+//===-- fixsfsivfp.S - Implement fixsfsivfp -----------------------===//
+//
+// 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"
+
+//
+// extern int __fixsfsivfp(float a);
+//
+// Converts single precision float to a 32-bit int rounding towards zero.
+// Uses Darwin calling convention where a single precision parameter is
+// passed in a GPR..
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__fixsfsivfp)
+ vmov s15, r0 // load float register from R0
+ vcvt.s32.f32 s15, s15 // convert single to 32-bit int into s15
+ vmov r0, s15 // move s15 to result register
+ bx lr
+END_COMPILERRT_FUNCTION(__fixsfsivfp)
diff --git a/lib/builtins/arm/fixunsdfsivfp.S b/lib/builtins/arm/fixunsdfsivfp.S
new file mode 100644
index 000000000000..35dda5b9b034
--- /dev/null
+++ b/lib/builtins/arm/fixunsdfsivfp.S
@@ -0,0 +1,27 @@
+//===-- fixunsdfsivfp.S - Implement fixunsdfsivfp -------------------------===//
+//
+// 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"
+
+//
+// extern unsigned int __fixunsdfsivfp(double a);
+//
+// Converts double precision float to a 32-bit unsigned int rounding towards
+// zero. All negative values become zero.
+// Uses Darwin calling convention where a double precision parameter is
+// passed in GPR register pair.
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__fixunsdfsivfp)
+ vmov d7, r0, r1 // load double register from R0/R1
+ vcvt.u32.f64 s15, d7 // convert double to 32-bit int into s15
+ vmov r0, s15 // move s15 to result register
+ bx lr
+END_COMPILERRT_FUNCTION(__fixunsdfsivfp)
diff --git a/lib/builtins/arm/fixunssfsivfp.S b/lib/builtins/arm/fixunssfsivfp.S
new file mode 100644
index 000000000000..5c3a7d926fcc
--- /dev/null
+++ b/lib/builtins/arm/fixunssfsivfp.S
@@ -0,0 +1,27 @@
+//===-- fixunssfsivfp.S - Implement fixunssfsivfp -------------------------===//
+//
+// 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"
+
+//
+// extern unsigned int __fixunssfsivfp(float a);
+//
+// Converts single precision float to a 32-bit unsigned int rounding towards
+// zero. All negative values become zero.
+// Uses Darwin calling convention where a single precision parameter is
+// passed in a GPR..
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__fixunssfsivfp)
+ vmov s15, r0 // load float register from R0
+ vcvt.u32.f32 s15, s15 // convert single to 32-bit unsigned into s15
+ vmov r0, s15 // move s15 to result register
+ bx lr
+END_COMPILERRT_FUNCTION(__fixunssfsivfp)
diff --git a/lib/builtins/arm/floatsidfvfp.S b/lib/builtins/arm/floatsidfvfp.S
new file mode 100644
index 000000000000..d69184914ccd
--- /dev/null
+++ b/lib/builtins/arm/floatsidfvfp.S
@@ -0,0 +1,26 @@
+//===-- floatsidfvfp.S - Implement floatsidfvfp ---------------------------===//
+//
+// 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"
+
+//
+// extern double __floatsidfvfp(int a);
+//
+// Converts a 32-bit int to a double precision float.
+// Uses Darwin calling convention where a double precision result is
+// return in GPR register pair.
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__floatsidfvfp)
+ vmov s15, r0 // move int to float register s15
+ vcvt.f64.s32 d7, s15 // convert 32-bit int in s15 to double in d7
+ vmov r0, r1, d7 // move d7 to result register pair r0/r1
+ bx lr
+END_COMPILERRT_FUNCTION(__floatsidfvfp)
diff --git a/lib/builtins/arm/floatsisfvfp.S b/lib/builtins/arm/floatsisfvfp.S
new file mode 100644
index 000000000000..4a0cb39d0eb0
--- /dev/null
+++ b/lib/builtins/arm/floatsisfvfp.S
@@ -0,0 +1,26 @@
+//===-- floatsisfvfp.S - Implement floatsisfvfp ---------------------------===//
+//
+// 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"
+
+//
+// extern float __floatsisfvfp(int a);
+//
+// Converts single precision float to a 32-bit int rounding towards zero.
+// Uses Darwin calling convention where a single precision result is
+// return in a GPR..
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__floatsisfvfp)
+ vmov s15, r0 // move int to float register s15
+ vcvt.f32.s32 s15, s15 // convert 32-bit int in s15 to float in s15
+ vmov r0, s15 // move s15 to result register
+ bx lr
+END_COMPILERRT_FUNCTION(__floatsisfvfp)
diff --git a/lib/builtins/arm/floatunssidfvfp.S b/lib/builtins/arm/floatunssidfvfp.S
new file mode 100644
index 000000000000..d92969ea3453
--- /dev/null
+++ b/lib/builtins/arm/floatunssidfvfp.S
@@ -0,0 +1,26 @@
+//===-- floatunssidfvfp.S - Implement floatunssidfvfp ---------------------===//
+//
+// 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"
+
+//
+// extern double __floatunssidfvfp(unsigned int a);
+//
+// Converts a 32-bit int to a double precision float.
+// Uses Darwin calling convention where a double precision result is
+// return in GPR register pair.
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__floatunssidfvfp)
+ vmov s15, r0 // move int to float register s15
+ vcvt.f64.u32 d7, s15 // convert 32-bit int in s15 to double in d7
+ vmov r0, r1, d7 // move d7 to result register pair r0/r1
+ bx lr
+END_COMPILERRT_FUNCTION(__floatunssidfvfp)
diff --git a/lib/builtins/arm/floatunssisfvfp.S b/lib/builtins/arm/floatunssisfvfp.S
new file mode 100644
index 000000000000..f6aeba56ae15
--- /dev/null
+++ b/lib/builtins/arm/floatunssisfvfp.S
@@ -0,0 +1,26 @@
+//===-- floatunssisfvfp.S - Implement floatunssisfvfp ---------------------===//
+//
+// 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"
+
+//
+// extern float __floatunssisfvfp(unsigned int a);
+//
+// Converts single precision float to a 32-bit int rounding towards zero.
+// Uses Darwin calling convention where a single precision result is
+// return in a GPR..
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__floatunssisfvfp)
+ vmov s15, r0 // move int to float register s15
+ vcvt.f32.u32 s15, s15 // convert 32-bit int in s15 to float in s15
+ vmov r0, s15 // move s15 to result register
+ bx lr
+END_COMPILERRT_FUNCTION(__floatunssisfvfp)
diff --git a/lib/builtins/arm/gedf2vfp.S b/lib/builtins/arm/gedf2vfp.S
new file mode 100644
index 000000000000..9e235270175c
--- /dev/null
+++ b/lib/builtins/arm/gedf2vfp.S
@@ -0,0 +1,29 @@
+//===-- gedf2vfp.S - Implement gedf2vfp -----------------------------------===//
+//
+// 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"
+
+//
+// extern int __gedf2vfp(double a, double b);
+//
+// Returns one iff a >= b and neither is NaN.
+// Uses Darwin calling convention where double precision arguments are passsed
+// like in GPR pairs.
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__gedf2vfp)
+ vmov d6, r0, r1 // load r0/r1 pair in double register
+ vmov d7, r2, r3 // load r2/r3 pair in double register
+ vcmp.f64 d6, d7
+ vmrs apsr_nzcv, fpscr
+ movge r0, #1 // set result register to 1 if greater than or equal
+ movlt r0, #0
+ bx lr
+END_COMPILERRT_FUNCTION(__gedf2vfp)
diff --git a/lib/builtins/arm/gesf2vfp.S b/lib/builtins/arm/gesf2vfp.S
new file mode 100644
index 000000000000..0ff608477882
--- /dev/null
+++ b/lib/builtins/arm/gesf2vfp.S
@@ -0,0 +1,29 @@
+//===-- gesf2vfp.S - Implement gesf2vfp -----------------------------------===//
+//
+// 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"
+
+//
+// extern int __gesf2vfp(float a, float b);
+//
+// Returns one iff a >= b and neither is NaN.
+// Uses Darwin calling convention where single precision arguments are passsed
+// like 32-bit ints
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__gesf2vfp)
+ vmov s14, r0 // move from GPR 0 to float register
+ vmov s15, r1 // move from GPR 1 to float register
+ vcmp.f32 s14, s15
+ vmrs apsr_nzcv, fpscr
+ movge r0, #1 // set result register to 1 if greater than or equal
+ movlt r0, #0
+ bx lr
+END_COMPILERRT_FUNCTION(__gesf2vfp)
diff --git a/lib/builtins/arm/gtdf2vfp.S b/lib/builtins/arm/gtdf2vfp.S
new file mode 100644
index 000000000000..3dc5d5b59225
--- /dev/null
+++ b/lib/builtins/arm/gtdf2vfp.S
@@ -0,0 +1,29 @@
+//===-- gtdf2vfp.S - Implement gtdf2vfp -----------------------------------===//
+//
+// 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"
+
+//
+// extern double __gtdf2vfp(double a, double b);
+//
+// Returns one iff a > b and neither is NaN.
+// Uses Darwin calling convention where double precision arguments are passsed
+// like in GPR pairs.
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__gtdf2vfp)
+ vmov d6, r0, r1 // load r0/r1 pair in double register
+ vmov d7, r2, r3 // load r2/r3 pair in double register
+ vcmp.f64 d6, d7
+ vmrs apsr_nzcv, fpscr
+ movgt r0, #1 // set result register to 1 if equal
+ movle r0, #0
+ bx lr
+END_COMPILERRT_FUNCTION(__gtdf2vfp)
diff --git a/lib/builtins/arm/gtsf2vfp.S b/lib/builtins/arm/gtsf2vfp.S
new file mode 100644
index 000000000000..ddd843acf592
--- /dev/null
+++ b/lib/builtins/arm/gtsf2vfp.S
@@ -0,0 +1,29 @@
+//===-- gtsf2vfp.S - Implement gtsf2vfp -----------------------------------===//
+//
+// 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"
+
+//
+// extern int __gtsf2vfp(float a, float b);
+//
+// Returns one iff a > b and neither is NaN.
+// Uses Darwin calling convention where single precision arguments are passsed
+// like 32-bit ints
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__gtsf2vfp)
+ vmov s14, r0 // move from GPR 0 to float register
+ vmov s15, r1 // move from GPR 1 to float register
+ vcmp.f32 s14, s15
+ vmrs apsr_nzcv, fpscr
+ movgt r0, #1 // set result register to 1 if equal
+ movle r0, #0
+ bx lr
+END_COMPILERRT_FUNCTION(__gtsf2vfp)
diff --git a/lib/builtins/arm/ledf2vfp.S b/lib/builtins/arm/ledf2vfp.S
new file mode 100644
index 000000000000..b06ff6db5a33
--- /dev/null
+++ b/lib/builtins/arm/ledf2vfp.S
@@ -0,0 +1,29 @@
+//===-- ledf2vfp.S - Implement ledf2vfp -----------------------------------===//
+//
+// 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"
+
+//
+// extern double __ledf2vfp(double a, double b);
+//
+// Returns one iff a <= b and neither is NaN.
+// Uses Darwin calling convention where double precision arguments are passsed
+// like in GPR pairs.
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__ledf2vfp)
+ vmov d6, r0, r1 // load r0/r1 pair in double register
+ vmov d7, r2, r3 // load r2/r3 pair in double register
+ vcmp.f64 d6, d7
+ vmrs apsr_nzcv, fpscr
+ movls r0, #1 // set result register to 1 if equal
+ movhi r0, #0
+ bx lr
+END_COMPILERRT_FUNCTION(__ledf2vfp)
diff --git a/lib/builtins/arm/lesf2vfp.S b/lib/builtins/arm/lesf2vfp.S
new file mode 100644
index 000000000000..9b33c0c53697
--- /dev/null
+++ b/lib/builtins/arm/lesf2vfp.S
@@ -0,0 +1,29 @@
+//===-- lesf2vfp.S - Implement lesf2vfp -----------------------------------===//
+//
+// 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"
+
+//
+// extern int __lesf2vfp(float a, float b);
+//
+// Returns one iff a <= b and neither is NaN.
+// Uses Darwin calling convention where single precision arguments are passsed
+// like 32-bit ints
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__lesf2vfp)
+ vmov s14, r0 // move from GPR 0 to float register
+ vmov s15, r1 // move from GPR 1 to float register
+ vcmp.f32 s14, s15
+ vmrs apsr_nzcv, fpscr
+ movls r0, #1 // set result register to 1 if equal
+ movhi r0, #0
+ bx lr
+END_COMPILERRT_FUNCTION(__lesf2vfp)
diff --git a/lib/builtins/arm/ltdf2vfp.S b/lib/builtins/arm/ltdf2vfp.S
new file mode 100644
index 000000000000..9f794b026a4a
--- /dev/null
+++ b/lib/builtins/arm/ltdf2vfp.S
@@ -0,0 +1,29 @@
+//===-- ltdf2vfp.S - Implement ltdf2vfp -----------------------------------===//
+//
+// 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"
+
+//
+// extern double __ltdf2vfp(double a, double b);
+//
+// Returns one iff a < b and neither is NaN.
+// Uses Darwin calling convention where double precision arguments are passsed
+// like in GPR pairs.
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__ltdf2vfp)
+ vmov d6, r0, r1 // load r0/r1 pair in double register
+ vmov d7, r2, r3 // load r2/r3 pair in double register
+ vcmp.f64 d6, d7
+ vmrs apsr_nzcv, fpscr
+ movmi r0, #1 // set result register to 1 if equal
+ movpl r0, #0
+ bx lr
+END_COMPILERRT_FUNCTION(__ltdf2vfp)
diff --git a/lib/builtins/arm/ltsf2vfp.S b/lib/builtins/arm/ltsf2vfp.S
new file mode 100644
index 000000000000..ba190d9d8dc2
--- /dev/null
+++ b/lib/builtins/arm/ltsf2vfp.S
@@ -0,0 +1,29 @@
+//===-- ltsf2vfp.S - Implement ltsf2vfp -----------------------------------===//
+//
+// 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"
+
+//
+// extern int __ltsf2vfp(float a, float b);
+//
+// Returns one iff a < b and neither is NaN.
+// Uses Darwin calling convention where single precision arguments are passsed
+// like 32-bit ints
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__ltsf2vfp)
+ vmov s14, r0 // move from GPR 0 to float register
+ vmov s15, r1 // move from GPR 1 to float register
+ vcmp.f32 s14, s15
+ vmrs apsr_nzcv, fpscr
+ movmi r0, #1 // set result register to 1 if equal
+ movpl r0, #0
+ bx lr
+END_COMPILERRT_FUNCTION(__ltsf2vfp)
diff --git a/lib/builtins/arm/modsi3.S b/lib/builtins/arm/modsi3.S
new file mode 100644
index 000000000000..295a227d862e
--- /dev/null
+++ b/lib/builtins/arm/modsi3.S
@@ -0,0 +1,63 @@
+/*===-- modsi3.S - 32-bit signed integer modulus --------------------------===//
+ *
+ * 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 the __modsi3 (32-bit signed integer modulus) function
+ * for the ARM architecture as a wrapper around the unsigned routine.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "../assembly.h"
+
+#define ESTABLISH_FRAME \
+ push {r4, r7, lr} ;\
+ add r7, sp, #4
+#define CLEAR_FRAME_AND_RETURN \
+ pop {r4, r7, pc}
+
+ .syntax unified
+ .text
+#if __ARM_ARCH_ISA_THUMB == 2
+ .thumb
+#endif
+
+@ int __modsi3(int divident, int divisor)
+@ Calculate and return the remainder of the (signed) division.
+
+ .p2align 3
+#if __ARM_ARCH_ISA_THUMB == 2
+DEFINE_COMPILERRT_THUMB_FUNCTION(__modsi3)
+#else
+DEFINE_COMPILERRT_FUNCTION(__modsi3)
+#endif
+#if __ARM_ARCH_EXT_IDIV__
+ tst r1, r1
+ beq LOCAL_LABEL(divzero)
+ sdiv r2, r0, r1
+ mls r0, r2, r1, r0
+ bx lr
+LOCAL_LABEL(divzero):
+ mov r0, #0
+ bx lr
+#else
+ ESTABLISH_FRAME
+ // Set aside the sign of the dividend.
+ mov r4, r0
+ // Take absolute value of a and b via abs(x) = (x^(x >> 31)) - (x >> 31).
+ eor r2, r0, r0, asr #31
+ eor r3, r1, r1, asr #31
+ sub r0, r2, r0, asr #31
+ sub r1, r3, r1, asr #31
+ // abs(a) % abs(b)
+ bl SYMBOL_NAME(__umodsi3)
+ // Apply sign of dividend to result and return.
+ eor r0, r0, r4, asr #31
+ sub r0, r0, r4, asr #31
+ CLEAR_FRAME_AND_RETURN
+#endif
+END_COMPILERRT_FUNCTION(__modsi3)
diff --git a/lib/builtins/arm/muldf3vfp.S b/lib/builtins/arm/muldf3vfp.S
new file mode 100644
index 000000000000..636cc711ac1a
--- /dev/null
+++ b/lib/builtins/arm/muldf3vfp.S
@@ -0,0 +1,26 @@
+//===-- muldf3vfp.S - Implement muldf3vfp ---------------------------------===//
+//
+// 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"
+
+//
+// extern double __muldf3vfp(double a, double b);
+//
+// Multiplies two double precision floating point numbers using the Darwin
+// calling convention where double arguments are passsed in GPR pairs
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__muldf3vfp)
+ vmov d6, r0, r1 // move first param from r0/r1 pair into d6
+ vmov d7, r2, r3 // move second param from r2/r3 pair into d7
+ vmul.f64 d6, d6, d7
+ vmov r0, r1, d6 // move result back to r0/r1 pair
+ bx lr
+END_COMPILERRT_FUNCTION(__muldf3vfp)
diff --git a/lib/builtins/arm/mulsf3vfp.S b/lib/builtins/arm/mulsf3vfp.S
new file mode 100644
index 000000000000..7f4008266bff
--- /dev/null
+++ b/lib/builtins/arm/mulsf3vfp.S
@@ -0,0 +1,26 @@
+//===-- mulsf3vfp.S - Implement mulsf3vfp ---------------------------------===//
+//
+// 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"
+
+//
+// extern float __mulsf3vfp(float a, float b);
+//
+// Multiplies two single precision floating point numbers using the Darwin
+// calling convention where single arguments are passsed like 32-bit ints.
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__mulsf3vfp)
+ vmov s14, r0 // move first param from r0 into float register
+ vmov s15, r1 // move second param from r1 into float register
+ vmul.f32 s13, s14, s15
+ vmov r0, s13 // move result back to r0
+ bx lr
+END_COMPILERRT_FUNCTION(__mulsf3vfp)
diff --git a/lib/builtins/arm/nedf2vfp.S b/lib/builtins/arm/nedf2vfp.S
new file mode 100644
index 000000000000..7ab2f5501ce0
--- /dev/null
+++ b/lib/builtins/arm/nedf2vfp.S
@@ -0,0 +1,29 @@
+//===-- nedf2vfp.S - Implement nedf2vfp -----------------------------------===//
+//
+// 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"
+
+//
+// extern double __nedf2vfp(double a, double b);
+//
+// Returns zero if a and b are unequal and neither is NaN.
+// Uses Darwin calling convention where double precision arguments are passsed
+// like in GPR pairs.
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__nedf2vfp)
+ vmov d6, r0, r1 // load r0/r1 pair in double register
+ vmov d7, r2, r3 // load r2/r3 pair in double register
+ vcmp.f64 d6, d7
+ vmrs apsr_nzcv, fpscr
+ movne r0, #1 // set result register to 0 if unequal
+ moveq r0, #0
+ bx lr
+END_COMPILERRT_FUNCTION(__nedf2vfp)
diff --git a/lib/builtins/arm/negdf2vfp.S b/lib/builtins/arm/negdf2vfp.S
new file mode 100644
index 000000000000..56d73c676176
--- /dev/null
+++ b/lib/builtins/arm/negdf2vfp.S
@@ -0,0 +1,23 @@
+//===-- negdf2vfp.S - Implement negdf2vfp ---------------------------------===//
+//
+// 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"
+
+//
+// extern double __negdf2vfp(double a, double b);
+//
+// Returns the negation a double precision floating point numbers using the
+// Darwin calling convention where double arguments are passsed in GPR pairs.
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__negdf2vfp)
+ eor r1, r1, #-2147483648 // flip sign bit on double in r0/r1 pair
+ bx lr
+END_COMPILERRT_FUNCTION(__negdf2vfp)
diff --git a/lib/builtins/arm/negsf2vfp.S b/lib/builtins/arm/negsf2vfp.S
new file mode 100644
index 000000000000..a6e32e1ff89c
--- /dev/null
+++ b/lib/builtins/arm/negsf2vfp.S
@@ -0,0 +1,23 @@
+//===-- negsf2vfp.S - Implement negsf2vfp ---------------------------------===//
+//
+// 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"
+
+//
+// extern float __negsf2vfp(float a);
+//
+// Returns the negation of a single precision floating point numbers using the
+// Darwin calling convention where single arguments are passsed like 32-bit ints
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__negsf2vfp)
+ eor r0, r0, #-2147483648 // flip sign bit on float in r0
+ bx lr
+END_COMPILERRT_FUNCTION(__negsf2vfp)
diff --git a/lib/builtins/arm/nesf2vfp.S b/lib/builtins/arm/nesf2vfp.S
new file mode 100644
index 000000000000..9fe8ecdefb37
--- /dev/null
+++ b/lib/builtins/arm/nesf2vfp.S
@@ -0,0 +1,29 @@
+//===-- nesf2vfp.S - Implement nesf2vfp -----------------------------------===//
+//
+// 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"
+
+//
+// extern int __nesf2vfp(float a, float b);
+//
+// Returns one iff a != b and neither is NaN.
+// Uses Darwin calling convention where single precision arguments are passsed
+// like 32-bit ints
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__nesf2vfp)
+ vmov s14, r0 // move from GPR 0 to float register
+ vmov s15, r1 // move from GPR 1 to float register
+ vcmp.f32 s14, s15
+ vmrs apsr_nzcv, fpscr
+ movne r0, #1 // set result register to 1 if unequal
+ moveq r0, #0
+ bx lr
+END_COMPILERRT_FUNCTION(__nesf2vfp)
diff --git a/lib/builtins/arm/restore_vfp_d8_d15_regs.S b/lib/builtins/arm/restore_vfp_d8_d15_regs.S
new file mode 100644
index 000000000000..0f6ea5136166
--- /dev/null
+++ b/lib/builtins/arm/restore_vfp_d8_d15_regs.S
@@ -0,0 +1,33 @@
+//===-- save_restore_regs.S - Implement save/restore* ---------------------===//
+//
+// 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"
+
+//
+// When compiling C++ functions that need to handle thrown exceptions the
+// compiler is required to save all registers and call __Unwind_SjLj_Register
+// in the function prolog. But when compiling for thumb1, there are
+// no instructions to access the floating point registers, so the
+// compiler needs to add a call to the helper function _save_vfp_d8_d15_regs
+// written in ARM to save the float registers. In the epilog, the compiler
+// must also add a call to __restore_vfp_d8_d15_regs to restore those registers.
+//
+
+ .text
+ .syntax unified
+
+//
+// Restore registers d8-d15 from stack
+//
+ .p2align 2
+DEFINE_COMPILERRT_PRIVATE_FUNCTION(__restore_vfp_d8_d15_regs)
+ vldmia sp!, {d8-d15} // pop registers d8-d15 off stack
+ bx lr // return to prolog
+END_COMPILERRT_FUNCTION(__restore_vfp_d8_d15_regs)
+
diff --git a/lib/builtins/arm/save_vfp_d8_d15_regs.S b/lib/builtins/arm/save_vfp_d8_d15_regs.S
new file mode 100644
index 000000000000..f1d90e75808c
--- /dev/null
+++ b/lib/builtins/arm/save_vfp_d8_d15_regs.S
@@ -0,0 +1,33 @@
+//===-- save_restore_regs.S - Implement save/restore* ---------------------===//
+//
+// 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"
+
+//
+// When compiling C++ functions that need to handle thrown exceptions the
+// compiler is required to save all registers and call __Unwind_SjLj_Register
+// in the function prolog. But when compiling for thumb1, there are
+// no instructions to access the floating point registers, so the
+// compiler needs to add a call to the helper function _save_vfp_d8_d15_regs
+// written in ARM to save the float registers. In the epilog, the compiler
+// must also add a call to __restore_vfp_d8_d15_regs to restore those registers.
+//
+
+ .text
+ .syntax unified
+
+//
+// Save registers d8-d15 onto stack
+//
+ .p2align 2
+DEFINE_COMPILERRT_PRIVATE_FUNCTION(__save_vfp_d8_d15_regs)
+ vstmdb sp!, {d8-d15} // push registers d8-d15 onto stack
+ bx lr // return to prolog
+END_COMPILERRT_FUNCTION(__save_vfp_d8_d15_regs)
+
diff --git a/lib/arm/softfloat-alias.list b/lib/builtins/arm/softfloat-alias.list
index cc6a4b3cdd2e..cc6a4b3cdd2e 100644
--- a/lib/arm/softfloat-alias.list
+++ b/lib/builtins/arm/softfloat-alias.list
diff --git a/lib/builtins/arm/subdf3vfp.S b/lib/builtins/arm/subdf3vfp.S
new file mode 100644
index 000000000000..5f3c0f70dbc4
--- /dev/null
+++ b/lib/builtins/arm/subdf3vfp.S
@@ -0,0 +1,26 @@
+//===-- subdf3vfp.S - Implement subdf3vfp ---------------------------------===//
+//
+// 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"
+
+//
+// extern double __subdf3vfp(double a, double b);
+//
+// Returns difference between two double precision floating point numbers using
+// the Darwin calling convention where double arguments are passsed in GPR pairs
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__subdf3vfp)
+ vmov d6, r0, r1 // move first param from r0/r1 pair into d6
+ vmov d7, r2, r3 // move second param from r2/r3 pair into d7
+ vsub.f64 d6, d6, d7
+ vmov r0, r1, d6 // move result back to r0/r1 pair
+ bx lr
+END_COMPILERRT_FUNCTION(__subdf3vfp)
diff --git a/lib/builtins/arm/subsf3vfp.S b/lib/builtins/arm/subsf3vfp.S
new file mode 100644
index 000000000000..d6e06df51920
--- /dev/null
+++ b/lib/builtins/arm/subsf3vfp.S
@@ -0,0 +1,27 @@
+//===-- subsf3vfp.S - Implement subsf3vfp ---------------------------------===//
+//
+// 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"
+
+//
+// extern float __subsf3vfp(float a, float b);
+//
+// Returns the difference between two single precision floating point numbers
+// using the Darwin calling convention where single arguments are passsed
+// like 32-bit ints.
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__subsf3vfp)
+ vmov s14, r0 // move first param from r0 into float register
+ vmov s15, r1 // move second param from r1 into float register
+ vsub.f32 s14, s14, s15
+ vmov r0, s14 // move result back to r0
+ bx lr
+END_COMPILERRT_FUNCTION(__subsf3vfp)
diff --git a/lib/builtins/arm/switch16.S b/lib/builtins/arm/switch16.S
new file mode 100644
index 000000000000..3c3a6b106124
--- /dev/null
+++ b/lib/builtins/arm/switch16.S
@@ -0,0 +1,44 @@
+//===-- switch.S - Implement switch* --------------------------------------===//
+//
+// 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"
+
+//
+// When compiling switch statements in thumb mode, the compiler
+// can use these __switch* helper functions The compiler emits a blx to
+// the __switch* function followed by a table of displacements for each
+// case statement. On entry, R0 is the index into the table. The __switch*
+// function uses the return address in lr to find the start of the table.
+// The first entry in the table is the count of the entries in the table.
+// It then uses R0 to index into the table and get the displacement of the
+// address to jump to. If R0 is greater than the size of the table, it jumps
+// to the last entry in the table. Each displacement in the table is actually
+// the distance from lr to the label, thus making the tables PIC.
+
+
+ .text
+ .syntax unified
+
+//
+// The table contains signed 2-byte sized elements which are 1/2 the distance
+// from lr to the target label.
+//
+ .p2align 2
+DEFINE_COMPILERRT_PRIVATE_FUNCTION(__switch16)
+ ldrh ip, [lr, #-1] // get first 16-bit word in table
+ cmp r0, ip // compare with index
+ add r0, lr, r0, lsl #1 // compute address of element in table
+ add ip, lr, ip, lsl #1 // compute address of last element in table
+ ite lo
+ ldrshlo r0, [r0, #1] // load 16-bit element if r0 is in range
+ ldrshhs r0, [ip, #1] // load 16-bit element if r0 out of range
+ add ip, lr, r0, lsl #1 // compute label = lr + element*2
+ bx ip // jump to computed label
+END_COMPILERRT_FUNCTION(__switch16)
+
diff --git a/lib/builtins/arm/switch32.S b/lib/builtins/arm/switch32.S
new file mode 100644
index 000000000000..b38cd2b764a4
--- /dev/null
+++ b/lib/builtins/arm/switch32.S
@@ -0,0 +1,44 @@
+//===-- switch.S - Implement switch* --------------------------------------===//
+//
+// 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"
+
+//
+// When compiling switch statements in thumb mode, the compiler
+// can use these __switch* helper functions The compiler emits a blx to
+// the __switch* function followed by a table of displacements for each
+// case statement. On entry, R0 is the index into the table. The __switch*
+// function uses the return address in lr to find the start of the table.
+// The first entry in the table is the count of the entries in the table.
+// It then uses R0 to index into the table and get the displacement of the
+// address to jump to. If R0 is greater than the size of the table, it jumps
+// to the last entry in the table. Each displacement in the table is actually
+// the distance from lr to the label, thus making the tables PIC.
+
+
+ .text
+ .syntax unified
+
+//
+// The table contains signed 4-byte sized elements which are the distance
+// from lr to the target label.
+//
+ .p2align 2
+DEFINE_COMPILERRT_PRIVATE_FUNCTION(__switch32)
+ ldr ip, [lr, #-1] // get first 32-bit word in table
+ cmp r0, ip // compare with index
+ add r0, lr, r0, lsl #2 // compute address of element in table
+ add ip, lr, ip, lsl #2 // compute address of last element in table
+ ite lo
+ ldrlo r0, [r0, #3] // load 32-bit element if r0 is in range
+ ldrhs r0, [ip, #3] // load 32-bit element if r0 out of range
+ add ip, lr, r0 // compute label = lr + element
+ bx ip // jump to computed label
+END_COMPILERRT_FUNCTION(__switch32)
+
diff --git a/lib/builtins/arm/switch8.S b/lib/builtins/arm/switch8.S
new file mode 100644
index 000000000000..d7c20423def2
--- /dev/null
+++ b/lib/builtins/arm/switch8.S
@@ -0,0 +1,42 @@
+//===-- switch.S - Implement switch* --------------------------------------===//
+//
+// 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"
+
+//
+// When compiling switch statements in thumb mode, the compiler
+// can use these __switch* helper functions The compiler emits a blx to
+// the __switch* function followed by a table of displacements for each
+// case statement. On entry, R0 is the index into the table. The __switch*
+// function uses the return address in lr to find the start of the table.
+// The first entry in the table is the count of the entries in the table.
+// It then uses R0 to index into the table and get the displacement of the
+// address to jump to. If R0 is greater than the size of the table, it jumps
+// to the last entry in the table. Each displacement in the table is actually
+// the distance from lr to the label, thus making the tables PIC.
+
+
+ .text
+ .syntax unified
+
+//
+// The table contains signed byte sized elements which are 1/2 the distance
+// from lr to the target label.
+//
+ .p2align 2
+DEFINE_COMPILERRT_PRIVATE_FUNCTION(__switch8)
+ ldrb ip, [lr, #-1] // get first byte in table
+ cmp r0, ip // signed compare with index
+ ite lo
+ ldrsblo r0, [lr, r0] // get indexed byte out of table
+ ldrsbhs r0, [lr, ip] // if out of range, use last entry in table
+ add ip, lr, r0, lsl #1 // compute label = lr + element*2
+ bx ip // jump to computed label
+END_COMPILERRT_FUNCTION(__switch8)
+
diff --git a/lib/builtins/arm/switchu8.S b/lib/builtins/arm/switchu8.S
new file mode 100644
index 000000000000..1844f11c604e
--- /dev/null
+++ b/lib/builtins/arm/switchu8.S
@@ -0,0 +1,42 @@
+//===-- switch.S - Implement switch* --------------------------------------===//
+//
+// 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"
+
+//
+// When compiling switch statements in thumb mode, the compiler
+// can use these __switch* helper functions The compiler emits a blx to
+// the __switch* function followed by a table of displacements for each
+// case statement. On entry, R0 is the index into the table. The __switch*
+// function uses the return address in lr to find the start of the table.
+// The first entry in the table is the count of the entries in the table.
+// It then uses R0 to index into the table and get the displacement of the
+// address to jump to. If R0 is greater than the size of the table, it jumps
+// to the last entry in the table. Each displacement in the table is actually
+// the distance from lr to the label, thus making the tables PIC.
+
+
+ .text
+ .syntax unified
+
+//
+// The table contains unsigned byte sized elements which are 1/2 the distance
+// from lr to the target label.
+//
+ .p2align 2
+DEFINE_COMPILERRT_PRIVATE_FUNCTION(__switchu8)
+ ldrb ip, [lr, #-1] // get first byte in table
+ cmp r0, ip // compare with index
+ ite lo
+ ldrblo r0, [lr, r0] // get indexed byte out of table
+ ldrbhs r0, [lr, ip] // if out of range, use last entry in table
+ add ip, lr, r0, lsl #1 // compute label = lr + element*2
+ bx ip // jump to computed label
+END_COMPILERRT_FUNCTION(__switchu8)
+
diff --git a/lib/builtins/arm/sync-ops.h b/lib/builtins/arm/sync-ops.h
new file mode 100644
index 000000000000..ee02c30c6eaa
--- /dev/null
+++ b/lib/builtins/arm/sync-ops.h
@@ -0,0 +1,64 @@
+/*===-- sync-ops.h - --===//
+ *
+ * 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 outline macros for the __sync_fetch_and_*
+ * operations. Different instantiations will generate appropriate assembly for
+ * ARM and Thumb-2 versions of the functions.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "../assembly.h"
+
+#define SYNC_OP_4(op) \
+ .p2align 2 ; \
+ .thumb ; \
+ .syntax unified ; \
+ DEFINE_COMPILERRT_THUMB_FUNCTION(__sync_fetch_and_ ## op) \
+ dmb ; \
+ mov r12, r0 ; \
+ LOCAL_LABEL(tryatomic_ ## op): \
+ ldrex r0, [r12] ; \
+ op(r2, r0, r1) ; \
+ strex r3, r2, [r12] ; \
+ cmp r3, #0 ; \
+ bne LOCAL_LABEL(tryatomic_ ## op) ; \
+ dmb ; \
+ bx lr
+
+#define SYNC_OP_8(op) \
+ .p2align 2 ; \
+ .thumb ; \
+ .syntax unified ; \
+ DEFINE_COMPILERRT_THUMB_FUNCTION(__sync_fetch_and_ ## op) \
+ push {r4, r5, r6, lr} ; \
+ dmb ; \
+ mov r12, r0 ; \
+ LOCAL_LABEL(tryatomic_ ## op): \
+ ldrexd r0, r1, [r12] ; \
+ op(r4, r5, r0, r1, r2, r3) ; \
+ strexd r6, r4, r5, [r12] ; \
+ cmp r6, #0 ; \
+ bne LOCAL_LABEL(tryatomic_ ## op) ; \
+ dmb ; \
+ pop {r4, r5, r6, pc}
+
+#define MINMAX_4(rD, rN, rM, cmp_kind) \
+ cmp rN, rM ; \
+ mov rD, rM ; \
+ it cmp_kind ; \
+ mov##cmp_kind rD, rN
+
+#define MINMAX_8(rD_LO, rD_HI, rN_LO, rN_HI, rM_LO, rM_HI, cmp_kind) \
+ cmp rN_LO, rM_LO ; \
+ sbcs rN_HI, rM_HI ; \
+ mov rD_LO, rM_LO ; \
+ mov rD_HI, rM_HI ; \
+ itt cmp_kind ; \
+ mov##cmp_kind rD_LO, rN_LO ; \
+ mov##cmp_kind rD_HI, rN_HI
diff --git a/lib/builtins/arm/sync_fetch_and_add_4.S b/lib/builtins/arm/sync_fetch_and_add_4.S
new file mode 100644
index 000000000000..54c33e2d26b7
--- /dev/null
+++ b/lib/builtins/arm/sync_fetch_and_add_4.S
@@ -0,0 +1,21 @@
+/*===-- sync_fetch_and_add_4.S - ------------------------------------------===//
+ *
+ * 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 the __sync_fetch_and_add_4 function for the ARM
+ * architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "sync-ops.h"
+
+/* "adds" is 2 bytes shorter than "add". */
+#define add_4(rD, rN, rM) add rD, rN, rM
+
+SYNC_OP_4(add_4)
+
diff --git a/lib/builtins/arm/sync_fetch_and_add_8.S b/lib/builtins/arm/sync_fetch_and_add_8.S
new file mode 100644
index 000000000000..5724bb148ba7
--- /dev/null
+++ b/lib/builtins/arm/sync_fetch_and_add_8.S
@@ -0,0 +1,24 @@
+/*===-- sync_fetch_and_add_8.S - ------------------------------------------===//
+ *
+ * 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 the __sync_fetch_and_add_8 function for the ARM
+ * architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "sync-ops.h"
+
+#if __ARM_ARCH_PROFILE != 'M'
+#define add_8(rD_LO, rD_HI, rN_LO, rN_HI, rM_LO, rM_HI) \
+ adds rD_LO, rN_LO, rM_LO ; \
+ adc rD_HI, rN_HI, rM_HI
+
+SYNC_OP_8(add_8)
+#endif
+
diff --git a/lib/builtins/arm/sync_fetch_and_and_4.S b/lib/builtins/arm/sync_fetch_and_and_4.S
new file mode 100644
index 000000000000..e2b77a1a87d4
--- /dev/null
+++ b/lib/builtins/arm/sync_fetch_and_and_4.S
@@ -0,0 +1,19 @@
+/*===-- sync_fetch_and_and_4.S - ------------------------------------------===//
+ *
+ * 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 the __sync_fetch_and_and_4 function for the ARM
+ * architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "sync-ops.h"
+
+#define and_4(rD, rN, rM) and rD, rN, rM
+
+SYNC_OP_4(and_4)
diff --git a/lib/builtins/arm/sync_fetch_and_and_8.S b/lib/builtins/arm/sync_fetch_and_and_8.S
new file mode 100644
index 000000000000..a74163a8600b
--- /dev/null
+++ b/lib/builtins/arm/sync_fetch_and_and_8.S
@@ -0,0 +1,23 @@
+/*===-- sync_fetch_and_and_8.S - ------------------------------------------===//
+ *
+ * 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 the __sync_fetch_and_and_8 function for the ARM
+ * architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "sync-ops.h"
+
+#if __ARM_ARCH_PROFILE != 'M'
+#define and_8(rD_LO, rD_HI, rN_LO, rN_HI, rM_LO, rM_HI) \
+ and rD_LO, rN_LO, rM_LO ; \
+ and rD_HI, rN_HI, rM_HI
+
+SYNC_OP_8(and_8)
+#endif
diff --git a/lib/builtins/arm/sync_fetch_and_max_4.S b/lib/builtins/arm/sync_fetch_and_max_4.S
new file mode 100644
index 000000000000..01e4f444c2f7
--- /dev/null
+++ b/lib/builtins/arm/sync_fetch_and_max_4.S
@@ -0,0 +1,20 @@
+/*===-- sync_fetch_and_max_4.S - ------------------------------------------===//
+ *
+ * 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 the __sync_fetch_and_max_4 function for the ARM
+ * architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "sync-ops.h"
+
+#define max_4(rD, rN, rM) MINMAX_4(rD, rN, rM, gt)
+
+SYNC_OP_4(max_4)
+
diff --git a/lib/builtins/arm/sync_fetch_and_max_8.S b/lib/builtins/arm/sync_fetch_and_max_8.S
new file mode 100644
index 000000000000..1eef2b223668
--- /dev/null
+++ b/lib/builtins/arm/sync_fetch_and_max_8.S
@@ -0,0 +1,21 @@
+/*===-- sync_fetch_and_max_8.S - ------------------------------------------===//
+ *
+ * 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 the __sync_fetch_and_max_8 function for the ARM
+ * architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "sync-ops.h"
+
+#if __ARM_ARCH_PROFILE != 'M'
+#define max_8(rD_LO, rD_HI, rN_LO, rN_HI, rM_LO, rM_HI) MINMAX_8(rD_LO, rD_HI, rN_LO, rN_HI, rM_LO, rM_HI, gt)
+
+SYNC_OP_8(max_8)
+#endif
diff --git a/lib/builtins/arm/sync_fetch_and_min_4.S b/lib/builtins/arm/sync_fetch_and_min_4.S
new file mode 100644
index 000000000000..015626b63da5
--- /dev/null
+++ b/lib/builtins/arm/sync_fetch_and_min_4.S
@@ -0,0 +1,20 @@
+/*===-- sync_fetch_and_min_4.S - ------------------------------------------===//
+ *
+ * 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 the __sync_fetch_and_min_4 function for the ARM
+ * architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "sync-ops.h"
+
+#define min_4(rD, rN, rM) MINMAX_4(rD, rN, rM, lt)
+
+SYNC_OP_4(min_4)
+
diff --git a/lib/builtins/arm/sync_fetch_and_min_8.S b/lib/builtins/arm/sync_fetch_and_min_8.S
new file mode 100644
index 000000000000..ad5cce07544c
--- /dev/null
+++ b/lib/builtins/arm/sync_fetch_and_min_8.S
@@ -0,0 +1,21 @@
+/*===-- sync_fetch_and_min_8.S - ------------------------------------------===//
+ *
+ * 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 the __sync_fetch_and_min_8 function for the ARM
+ * architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "sync-ops.h"
+
+#if __ARM_ARCH_PROFILE != 'M'
+#define min_8(rD_LO, rD_HI, rN_LO, rN_HI, rM_LO, rM_HI) MINMAX_8(rD_LO, rD_HI, rN_LO, rN_HI, rM_LO, rM_HI, lt)
+
+SYNC_OP_8(min_8)
+#endif
diff --git a/lib/builtins/arm/sync_fetch_and_nand_4.S b/lib/builtins/arm/sync_fetch_and_nand_4.S
new file mode 100644
index 000000000000..b32a314b3974
--- /dev/null
+++ b/lib/builtins/arm/sync_fetch_and_nand_4.S
@@ -0,0 +1,20 @@
+/*===-- sync_fetch_and_nand_4.S - -----------------------------------------===//
+ *
+ * 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 the __sync_fetch_and_nand_4 function for the ARM
+ * architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "sync-ops.h"
+
+#define nand_4(rD, rN, rM) bic rD, rN, rM
+
+SYNC_OP_4(nand_4)
+
diff --git a/lib/builtins/arm/sync_fetch_and_nand_8.S b/lib/builtins/arm/sync_fetch_and_nand_8.S
new file mode 100644
index 000000000000..a2c17c09c08f
--- /dev/null
+++ b/lib/builtins/arm/sync_fetch_and_nand_8.S
@@ -0,0 +1,24 @@
+/*===-- sync_fetch_and_nand_8.S - ------------------------------------------===//
+ *
+ * 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 the __sync_fetch_and_nand_8 function for the ARM
+ * architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "sync-ops.h"
+
+#if __ARM_ARCH_PROFILE != 'M'
+#define nand_8(rD_LO, rD_HI, rN_LO, rN_HI, rM_LO, rM_HI) \
+ bic rD_LO, rN_LO, rM_LO ; \
+ bic rD_HI, rN_HI, rM_HI
+
+SYNC_OP_8(nand_8)
+#endif
+
diff --git a/lib/builtins/arm/sync_fetch_and_or_4.S b/lib/builtins/arm/sync_fetch_and_or_4.S
new file mode 100644
index 000000000000..f2e08576aaab
--- /dev/null
+++ b/lib/builtins/arm/sync_fetch_and_or_4.S
@@ -0,0 +1,20 @@
+/*===-- sync_fetch_and_or_4.S - -------------------------------------------===//
+ *
+ * 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 the __sync_fetch_and_or_4 function for the ARM
+ * architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "sync-ops.h"
+
+#define or_4(rD, rN, rM) orr rD, rN, rM
+
+SYNC_OP_4(or_4)
+
diff --git a/lib/builtins/arm/sync_fetch_and_or_8.S b/lib/builtins/arm/sync_fetch_and_or_8.S
new file mode 100644
index 000000000000..87b940bf620d
--- /dev/null
+++ b/lib/builtins/arm/sync_fetch_and_or_8.S
@@ -0,0 +1,24 @@
+/*===-- sync_fetch_and_or_8.S - -------------------------------------------===//
+ *
+ * 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 the __sync_fetch_and_or_8 function for the ARM
+ * architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "sync-ops.h"
+
+#if __ARM_ARCH_PROFILE != 'M'
+#define or_8(rD_LO, rD_HI, rN_LO, rN_HI, rM_LO, rM_HI) \
+ orr rD_LO, rN_LO, rM_LO ; \
+ orr rD_HI, rN_HI, rM_HI
+
+SYNC_OP_8(or_8)
+#endif
+
diff --git a/lib/builtins/arm/sync_fetch_and_sub_4.S b/lib/builtins/arm/sync_fetch_and_sub_4.S
new file mode 100644
index 000000000000..460b2bc1ed62
--- /dev/null
+++ b/lib/builtins/arm/sync_fetch_and_sub_4.S
@@ -0,0 +1,21 @@
+/*===-- sync_fetch_and_sub_4.S - ------------------------------------------===//
+ *
+ * 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 the __sync_fetch_and_sub_4 function for the ARM
+ * architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "sync-ops.h"
+
+/* "subs" is 2 bytes shorter than "sub". */
+#define sub_4(rD, rN, rM) sub rD, rN, rM
+
+SYNC_OP_4(sub_4)
+
diff --git a/lib/builtins/arm/sync_fetch_and_sub_8.S b/lib/builtins/arm/sync_fetch_and_sub_8.S
new file mode 100644
index 000000000000..a8035a276853
--- /dev/null
+++ b/lib/builtins/arm/sync_fetch_and_sub_8.S
@@ -0,0 +1,24 @@
+/*===-- sync_fetch_and_sub_8.S - ------------------------------------------===//
+ *
+ * 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 the __sync_fetch_and_sub_8 function for the ARM
+ * architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "sync-ops.h"
+
+#if __ARM_ARCH_PROFILE != 'M'
+#define sub_8(rD_LO, rD_HI, rN_LO, rN_HI, rM_LO, rM_HI) \
+ subs rD_LO, rN_LO, rM_LO ; \
+ sbc rD_HI, rN_HI, rM_HI
+
+SYNC_OP_8(sub_8)
+#endif
+
diff --git a/lib/builtins/arm/sync_fetch_and_umax_4.S b/lib/builtins/arm/sync_fetch_and_umax_4.S
new file mode 100644
index 000000000000..c59153031931
--- /dev/null
+++ b/lib/builtins/arm/sync_fetch_and_umax_4.S
@@ -0,0 +1,20 @@
+/*===-- sync_fetch_and_umax_4.S - ------------------------------------------===//
+ *
+ * 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 the __sync_fetch_and_umax_4 function for the ARM
+ * architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "sync-ops.h"
+
+#define umax_4(rD, rN, rM) MINMAX_4(rD, rN, rM, hi)
+
+SYNC_OP_4(umax_4)
+
diff --git a/lib/builtins/arm/sync_fetch_and_umax_8.S b/lib/builtins/arm/sync_fetch_and_umax_8.S
new file mode 100644
index 000000000000..d9b7965e52ba
--- /dev/null
+++ b/lib/builtins/arm/sync_fetch_and_umax_8.S
@@ -0,0 +1,21 @@
+/*===-- sync_fetch_and_umax_8.S - ------------------------------------------===//
+ *
+ * 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 the __sync_fetch_and_umax_8 function for the ARM
+ * architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "sync-ops.h"
+
+#if __ARM_ARCH_PROFILE != 'M'
+#define umax_8(rD_LO, rD_HI, rN_LO, rN_HI, rM_LO, rM_HI) MINMAX_8(rD_LO, rD_HI, rN_LO, rN_HI, rM_LO, rM_HI, hi)
+
+SYNC_OP_8(umax_8)
+#endif
diff --git a/lib/builtins/arm/sync_fetch_and_umin_4.S b/lib/builtins/arm/sync_fetch_and_umin_4.S
new file mode 100644
index 000000000000..9f3896fca80e
--- /dev/null
+++ b/lib/builtins/arm/sync_fetch_and_umin_4.S
@@ -0,0 +1,20 @@
+/*===-- sync_fetch_and_umin_4.S - ------------------------------------------===//
+ *
+ * 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 the __sync_fetch_and_umin_4 function for the ARM
+ * architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "sync-ops.h"
+
+#define umin_4(rD, rN, rM) MINMAX_4(rD, rN, rM, lo)
+
+SYNC_OP_4(umin_4)
+
diff --git a/lib/builtins/arm/sync_fetch_and_umin_8.S b/lib/builtins/arm/sync_fetch_and_umin_8.S
new file mode 100644
index 000000000000..7bf5e235653c
--- /dev/null
+++ b/lib/builtins/arm/sync_fetch_and_umin_8.S
@@ -0,0 +1,21 @@
+/*===-- sync_fetch_and_umin_8.S - ------------------------------------------===//
+ *
+ * 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 the __sync_fetch_and_umin_8 function for the ARM
+ * architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "sync-ops.h"
+
+#if __ARM_ARCH_PROFILE != 'M'
+#define umin_8(rD_LO, rD_HI, rN_LO, rN_HI, rM_LO, rM_HI) MINMAX_8(rD_LO, rD_HI, rN_LO, rN_HI, rM_LO, rM_HI, lo)
+
+SYNC_OP_8(umin_8)
+#endif
diff --git a/lib/builtins/arm/sync_fetch_and_xor_4.S b/lib/builtins/arm/sync_fetch_and_xor_4.S
new file mode 100644
index 000000000000..7e7c90c96277
--- /dev/null
+++ b/lib/builtins/arm/sync_fetch_and_xor_4.S
@@ -0,0 +1,20 @@
+/*===-- sync_fetch_and_xor_4.S - ------------------------------------------===//
+ *
+ * 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 the __sync_fetch_and_xor_4 function for the ARM
+ * architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "sync-ops.h"
+
+#define xor_4(rD, rN, rM) eor rD, rN, rM
+
+SYNC_OP_4(xor_4)
+
diff --git a/lib/builtins/arm/sync_fetch_and_xor_8.S b/lib/builtins/arm/sync_fetch_and_xor_8.S
new file mode 100644
index 000000000000..ea9aa6d4b0e2
--- /dev/null
+++ b/lib/builtins/arm/sync_fetch_and_xor_8.S
@@ -0,0 +1,24 @@
+/*===-- sync_fetch_and_xor_8.S - ------------------------------------------===//
+ *
+ * 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 the __sync_fetch_and_xor_8 function for the ARM
+ * architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "sync-ops.h"
+
+#if __ARM_ARCH_PROFILE != 'M'
+#define xor_8(rD_LO, rD_HI, rN_LO, rN_HI, rM_LO, rM_HI) \
+ eor rD_LO, rN_LO, rM_LO ; \
+ eor rD_HI, rN_HI, rM_HI
+
+SYNC_OP_8(xor_8)
+#endif
+
diff --git a/lib/builtins/arm/sync_synchronize.S b/lib/builtins/arm/sync_synchronize.S
new file mode 100644
index 000000000000..178f24534c71
--- /dev/null
+++ b/lib/builtins/arm/sync_synchronize.S
@@ -0,0 +1,35 @@
+//===-- sync_synchronize - Implement memory barrier * ----------------------===//
+//
+// 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"
+
+//
+// When compiling a use of the gcc built-in __sync_synchronize() in thumb1 mode
+// the compiler may emit a call to __sync_synchronize.
+// On Darwin the implementation jumps to an OS supplied function named
+// OSMemoryBarrier
+//
+
+ .text
+ .syntax unified
+
+#if __APPLE__
+
+ .p2align 2
+DEFINE_COMPILERRT_PRIVATE_FUNCTION(__sync_synchronize)
+ stmfd sp!, {r7, lr}
+ add r7, sp, #0
+ bl _OSMemoryBarrier
+ ldmfd sp!, {r7, pc}
+END_COMPILERRT_FUNCTION(__sync_synchronize)
+
+ // tell linker it can break up file at label boundaries
+ .subsections_via_symbols
+
+#endif
diff --git a/lib/builtins/arm/truncdfsf2vfp.S b/lib/builtins/arm/truncdfsf2vfp.S
new file mode 100644
index 000000000000..fa4362c45e77
--- /dev/null
+++ b/lib/builtins/arm/truncdfsf2vfp.S
@@ -0,0 +1,26 @@
+//===-- truncdfsf2vfp.S - Implement truncdfsf2vfp -------------------------===//
+//
+// 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"
+
+//
+// extern float __truncdfsf2vfp(double a);
+//
+// Converts double precision float to signle precision result.
+// Uses Darwin calling convention where a double precision parameter is
+// passed in a R0/R1 pair and a signle precision result is returned in R0.
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__truncdfsf2vfp)
+ vmov d7, r0, r1 // load double from r0/r1 pair
+ vcvt.f32.f64 s15, d7 // convert double to single (trucate precision)
+ vmov r0, s15 // return result in r0
+ bx lr
+END_COMPILERRT_FUNCTION(__truncdfsf2vfp)
diff --git a/lib/builtins/arm/udivmodsi4.S b/lib/builtins/arm/udivmodsi4.S
new file mode 100644
index 000000000000..85b84936c4b3
--- /dev/null
+++ b/lib/builtins/arm/udivmodsi4.S
@@ -0,0 +1,184 @@
+/*===-- udivmodsi4.S - 32-bit unsigned integer divide and modulus ---------===//
+ *
+ * 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 the __udivmodsi4 (32-bit unsigned integer divide and
+ * modulus) function for the ARM 32-bit architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "../assembly.h"
+
+ .syntax unified
+ .text
+
+#if __ARM_ARCH_ISA_THUMB == 2
+ .thumb
+#endif
+
+@ unsigned int __udivmodsi4(unsigned int divident, unsigned int divisor,
+@ unsigned int *remainder)
+@ Calculate the quotient and remainder of the (unsigned) division. The return
+@ value is the quotient, the remainder is placed in the variable.
+
+ .p2align 2
+#if __ARM_ARCH_ISA_THUMB == 2
+DEFINE_COMPILERRT_THUMB_FUNCTION(__udivmodsi4)
+#else
+DEFINE_COMPILERRT_FUNCTION(__udivmodsi4)
+#endif
+#if __ARM_ARCH_EXT_IDIV__
+ tst r1, r1
+ beq LOCAL_LABEL(divby0)
+ mov r3, r0
+ udiv r0, r3, r1
+ mls r1, r0, r1, r3
+ str r1, [r2]
+ bx lr
+#else
+ cmp r1, #1
+ bcc LOCAL_LABEL(divby0)
+ beq LOCAL_LABEL(divby1)
+ cmp r0, r1
+ bcc LOCAL_LABEL(quotient0)
+ /*
+ * Implement division using binary long division algorithm.
+ *
+ * r0 is the numerator, r1 the denominator.
+ *
+ * The code before JMP computes the correct shift I, so that
+ * r0 and (r1 << I) have the highest bit set in the same position.
+ * At the time of JMP, ip := .Ldiv0block - 12 * I.
+ * This depends on the fixed instruction size of block.
+ * For ARM mode, this is 12 Bytes, for THUMB mode 14 Bytes.
+ *
+ * block(shift) implements the test-and-update-quotient core.
+ * It assumes (r0 << shift) can be computed without overflow and
+ * that (r0 << shift) < 2 * r1. The quotient is stored in r3.
+ */
+
+# ifdef __ARM_FEATURE_CLZ
+ clz ip, r0
+ clz r3, r1
+ /* r0 >= r1 implies clz(r0) <= clz(r1), so ip <= r3. */
+ sub r3, r3, ip
+# if __ARM_ARCH_ISA_THUMB == 2
+ adr ip, LOCAL_LABEL(div0block) + 1
+ sub ip, ip, r3, lsl #1
+# else
+ adr ip, LOCAL_LABEL(div0block)
+# endif
+ sub ip, ip, r3, lsl #2
+ sub ip, ip, r3, lsl #3
+ mov r3, #0
+ bx ip
+# else
+# if __ARM_ARCH_ISA_THUMB == 2
+# error THUMB mode requires CLZ or UDIV
+# endif
+ str r4, [sp, #-8]!
+
+ mov r4, r0
+ adr ip, LOCAL_LABEL(div0block)
+
+ lsr r3, r4, #16
+ cmp r3, r1
+ movhs r4, r3
+ subhs ip, ip, #(16 * 12)
+
+ lsr r3, r4, #8
+ cmp r3, r1
+ movhs r4, r3
+ subhs ip, ip, #(8 * 12)
+
+ lsr r3, r4, #4
+ cmp r3, r1
+ movhs r4, r3
+ subhs ip, #(4 * 12)
+
+ lsr r3, r4, #2
+ cmp r3, r1
+ movhs r4, r3
+ subhs ip, ip, #(2 * 12)
+
+ /* Last block, no need to update r3 or r4. */
+ cmp r1, r4, lsr #1
+ subls ip, ip, #(1 * 12)
+
+ ldr r4, [sp], #8 /* restore r4, we are done with it. */
+ mov r3, #0
+
+ JMP(ip)
+# endif
+
+#define IMM #
+
+#define block(shift) \
+ cmp r0, r1, lsl IMM shift; \
+ ITT(hs); \
+ WIDE(addhs) r3, r3, IMM (1 << shift); \
+ WIDE(subhs) r0, r0, r1, lsl IMM shift
+
+ block(31)
+ block(30)
+ block(29)
+ block(28)
+ block(27)
+ block(26)
+ block(25)
+ block(24)
+ block(23)
+ block(22)
+ block(21)
+ block(20)
+ block(19)
+ block(18)
+ block(17)
+ block(16)
+ block(15)
+ block(14)
+ block(13)
+ block(12)
+ block(11)
+ block(10)
+ block(9)
+ block(8)
+ block(7)
+ block(6)
+ block(5)
+ block(4)
+ block(3)
+ block(2)
+ block(1)
+LOCAL_LABEL(div0block):
+ block(0)
+
+ str r0, [r2]
+ mov r0, r3
+ JMP(lr)
+
+LOCAL_LABEL(quotient0):
+ str r0, [r2]
+ mov r0, #0
+ JMP(lr)
+
+LOCAL_LABEL(divby1):
+ mov r3, #0
+ str r3, [r2]
+ JMP(lr)
+#endif /* __ARM_ARCH_EXT_IDIV__ */
+
+LOCAL_LABEL(divby0):
+ mov r0, #0
+#ifdef __ARM_EABI__
+ b __aeabi_idiv0
+#else
+ JMP(lr)
+#endif
+
+END_COMPILERRT_FUNCTION(__udivmodsi4)
diff --git a/lib/builtins/arm/udivsi3.S b/lib/builtins/arm/udivsi3.S
new file mode 100644
index 000000000000..165b2b58acb4
--- /dev/null
+++ b/lib/builtins/arm/udivsi3.S
@@ -0,0 +1,170 @@
+/*===-- udivsi3.S - 32-bit unsigned integer divide ------------------------===//
+ *
+ * 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 the __udivsi3 (32-bit unsigned integer divide)
+ * function for the ARM 32-bit architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "../assembly.h"
+
+ .syntax unified
+ .text
+
+#if __ARM_ARCH_ISA_THUMB == 2
+ .thumb
+#endif
+
+ .p2align 2
+DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_uidiv, __udivsi3)
+
+@ unsigned int __udivsi3(unsigned int divident, unsigned int divisor)
+@ Calculate and return the quotient of the (unsigned) division.
+
+#if __ARM_ARCH_ISA_THUMB == 2
+DEFINE_COMPILERRT_THUMB_FUNCTION(__udivsi3)
+#else
+DEFINE_COMPILERRT_FUNCTION(__udivsi3)
+#endif
+#if __ARM_ARCH_EXT_IDIV__
+ tst r1, r1
+ beq LOCAL_LABEL(divby0)
+ udiv r0, r0, r1
+ bx lr
+#else
+ cmp r1, #1
+ bcc LOCAL_LABEL(divby0)
+ IT(eq)
+ JMPc(lr, eq)
+ cmp r0, r1
+ ITT(cc)
+ movcc r0, #0
+ JMPc(lr, cc)
+ /*
+ * Implement division using binary long division algorithm.
+ *
+ * r0 is the numerator, r1 the denominator.
+ *
+ * The code before JMP computes the correct shift I, so that
+ * r0 and (r1 << I) have the highest bit set in the same position.
+ * At the time of JMP, ip := .Ldiv0block - 12 * I.
+ * This depends on the fixed instruction size of block.
+ * For ARM mode, this is 12 Bytes, for THUMB mode 14 Bytes.
+ *
+ * block(shift) implements the test-and-update-quotient core.
+ * It assumes (r0 << shift) can be computed without overflow and
+ * that (r0 << shift) < 2 * r1. The quotient is stored in r3.
+ */
+
+# ifdef __ARM_FEATURE_CLZ
+ clz ip, r0
+ clz r3, r1
+ /* r0 >= r1 implies clz(r0) <= clz(r1), so ip <= r3. */
+ sub r3, r3, ip
+# if __ARM_ARCH_ISA_THUMB == 2
+ adr ip, LOCAL_LABEL(div0block) + 1
+ sub ip, ip, r3, lsl #1
+# else
+ adr ip, LOCAL_LABEL(div0block)
+# endif
+ sub ip, ip, r3, lsl #2
+ sub ip, ip, r3, lsl #3
+ mov r3, #0
+ bx ip
+# else
+# if __ARM_ARCH_ISA_THUMB == 2
+# error THUMB mode requires CLZ or UDIV
+# endif
+ mov r2, r0
+ adr ip, LOCAL_LABEL(div0block)
+
+ lsr r3, r2, #16
+ cmp r3, r1
+ movhs r2, r3
+ subhs ip, ip, #(16 * 12)
+
+ lsr r3, r2, #8
+ cmp r3, r1
+ movhs r2, r3
+ subhs ip, ip, #(8 * 12)
+
+ lsr r3, r2, #4
+ cmp r3, r1
+ movhs r2, r3
+ subhs ip, #(4 * 12)
+
+ lsr r3, r2, #2
+ cmp r3, r1
+ movhs r2, r3
+ subhs ip, ip, #(2 * 12)
+
+ /* Last block, no need to update r2 or r3. */
+ cmp r1, r2, lsr #1
+ subls ip, ip, #(1 * 12)
+
+ mov r3, #0
+
+ JMP(ip)
+# endif
+
+#define IMM #
+
+#define block(shift) \
+ cmp r0, r1, lsl IMM shift; \
+ ITT(hs); \
+ WIDE(addhs) r3, r3, IMM (1 << shift); \
+ WIDE(subhs) r0, r0, r1, lsl IMM shift
+
+ block(31)
+ block(30)
+ block(29)
+ block(28)
+ block(27)
+ block(26)
+ block(25)
+ block(24)
+ block(23)
+ block(22)
+ block(21)
+ block(20)
+ block(19)
+ block(18)
+ block(17)
+ block(16)
+ block(15)
+ block(14)
+ block(13)
+ block(12)
+ block(11)
+ block(10)
+ block(9)
+ block(8)
+ block(7)
+ block(6)
+ block(5)
+ block(4)
+ block(3)
+ block(2)
+ block(1)
+LOCAL_LABEL(div0block):
+ block(0)
+
+ mov r0, r3
+ JMP(lr)
+#endif /* __ARM_ARCH_EXT_IDIV__ */
+
+LOCAL_LABEL(divby0):
+ mov r0, #0
+#ifdef __ARM_EABI__
+ b __aeabi_idiv0
+#else
+ JMP(lr)
+#endif
+
+END_COMPILERRT_FUNCTION(__udivsi3)
diff --git a/lib/builtins/arm/umodsi3.S b/lib/builtins/arm/umodsi3.S
new file mode 100644
index 000000000000..9e7a148ce46f
--- /dev/null
+++ b/lib/builtins/arm/umodsi3.S
@@ -0,0 +1,161 @@
+/*===-- umodsi3.S - 32-bit unsigned integer modulus -----------------------===//
+ *
+ * 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 the __umodsi3 (32-bit unsigned integer modulus)
+ * function for the ARM 32-bit architecture.
+ *
+ *===----------------------------------------------------------------------===*/
+
+#include "../assembly.h"
+
+ .syntax unified
+ .text
+#if __ARM_ARCH_ISA_THUMB == 2
+ .thumb
+#endif
+
+@ unsigned int __umodsi3(unsigned int divident, unsigned int divisor)
+@ Calculate and return the remainder of the (unsigned) division.
+
+ .p2align 2
+#if __ARM_ARCH_ISA_THUMB == 2
+DEFINE_COMPILERRT_THUMB_FUNCTION(__umodsi3)
+#else
+DEFINE_COMPILERRT_FUNCTION(__umodsi3)
+#endif
+#if __ARM_ARCH_EXT_IDIV__
+ tst r1, r1
+ beq LOCAL_LABEL(divby0)
+ udiv r2, r0, r1
+ mls r0, r2, r1, r0
+ bx lr
+#else
+ cmp r1, #1
+ bcc LOCAL_LABEL(divby0)
+ ITT(eq)
+ moveq r0, #0
+ JMPc(lr, eq)
+ cmp r0, r1
+ IT(cc)
+ JMPc(lr, cc)
+ /*
+ * Implement division using binary long division algorithm.
+ *
+ * r0 is the numerator, r1 the denominator.
+ *
+ * The code before JMP computes the correct shift I, so that
+ * r0 and (r1 << I) have the highest bit set in the same position.
+ * At the time of JMP, ip := .Ldiv0block - 8 * I.
+ * This depends on the fixed instruction size of block.
+ * For ARM mode, this is 8 Bytes, for THUMB mode 10 Bytes.
+ *
+ * block(shift) implements the test-and-update-quotient core.
+ * It assumes (r0 << shift) can be computed without overflow and
+ * that (r0 << shift) < 2 * r1. The quotient is stored in r3.
+ */
+
+# ifdef __ARM_FEATURE_CLZ
+ clz ip, r0
+ clz r3, r1
+ /* r0 >= r1 implies clz(r0) <= clz(r1), so ip <= r3. */
+ sub r3, r3, ip
+# if __ARM_ARCH_ISA_THUMB == 2
+ adr ip, LOCAL_LABEL(div0block) + 1
+ sub ip, ip, r3, lsl #1
+# else
+ adr ip, LOCAL_LABEL(div0block)
+# endif
+ sub ip, ip, r3, lsl #3
+ bx ip
+# else
+# if __ARM_ARCH_ISA_THUMB == 2
+# error THUMB mode requires CLZ or UDIV
+# endif
+ mov r2, r0
+ adr ip, LOCAL_LABEL(div0block)
+
+ lsr r3, r2, #16
+ cmp r3, r1
+ movhs r2, r3
+ subhs ip, ip, #(16 * 8)
+
+ lsr r3, r2, #8
+ cmp r3, r1
+ movhs r2, r3
+ subhs ip, ip, #(8 * 8)
+
+ lsr r3, r2, #4
+ cmp r3, r1
+ movhs r2, r3
+ subhs ip, #(4 * 8)
+
+ lsr r3, r2, #2
+ cmp r3, r1
+ movhs r2, r3
+ subhs ip, ip, #(2 * 8)
+
+ /* Last block, no need to update r2 or r3. */
+ cmp r1, r2, lsr #1
+ subls ip, ip, #(1 * 8)
+
+ JMP(ip)
+# endif
+
+#define IMM #
+
+#define block(shift) \
+ cmp r0, r1, lsl IMM shift; \
+ IT(hs); \
+ WIDE(subhs) r0, r0, r1, lsl IMM shift
+
+ block(31)
+ block(30)
+ block(29)
+ block(28)
+ block(27)
+ block(26)
+ block(25)
+ block(24)
+ block(23)
+ block(22)
+ block(21)
+ block(20)
+ block(19)
+ block(18)
+ block(17)
+ block(16)
+ block(15)
+ block(14)
+ block(13)
+ block(12)
+ block(11)
+ block(10)
+ block(9)
+ block(8)
+ block(7)
+ block(6)
+ block(5)
+ block(4)
+ block(3)
+ block(2)
+ block(1)
+LOCAL_LABEL(div0block):
+ block(0)
+ JMP(lr)
+#endif /* __ARM_ARCH_EXT_IDIV__ */
+
+LOCAL_LABEL(divby0):
+ mov r0, #0
+#ifdef __ARM_EABI__
+ b __aeabi_idiv0
+#else
+ JMP(lr)
+#endif
+
+END_COMPILERRT_FUNCTION(__umodsi3)
diff --git a/lib/builtins/arm/unorddf2vfp.S b/lib/builtins/arm/unorddf2vfp.S
new file mode 100644
index 000000000000..c4bea2d5eebd
--- /dev/null
+++ b/lib/builtins/arm/unorddf2vfp.S
@@ -0,0 +1,29 @@
+//===-- unorddf2vfp.S - Implement unorddf2vfp ------------------------------===//
+//
+// 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"
+
+//
+// extern int __unorddf2vfp(double a, double b);
+//
+// Returns one iff a or b is NaN
+// Uses Darwin calling convention where double precision arguments are passsed
+// like in GPR pairs.
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__unorddf2vfp)
+ vmov d6, r0, r1 // load r0/r1 pair in double register
+ vmov d7, r2, r3 // load r2/r3 pair in double register
+ vcmp.f64 d6, d7
+ vmrs apsr_nzcv, fpscr
+ movvs r0, #1 // set result register to 1 if "overflow" (any NaNs)
+ movvc r0, #0
+ bx lr
+END_COMPILERRT_FUNCTION(__unorddf2vfp)
diff --git a/lib/builtins/arm/unordsf2vfp.S b/lib/builtins/arm/unordsf2vfp.S
new file mode 100644
index 000000000000..886e96568103
--- /dev/null
+++ b/lib/builtins/arm/unordsf2vfp.S
@@ -0,0 +1,29 @@
+//===-- unordsf2vfp.S - Implement unordsf2vfp -----------------------------===//
+//
+// 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"
+
+//
+// extern int __unordsf2vfp(float a, float b);
+//
+// Returns one iff a or b is NaN
+// Uses Darwin calling convention where single precision arguments are passsed
+// like 32-bit ints
+//
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__unordsf2vfp)
+ vmov s14, r0 // move from GPR 0 to float register
+ vmov s15, r1 // move from GPR 1 to float register
+ vcmp.f32 s14, s15
+ vmrs apsr_nzcv, fpscr
+ movvs r0, #1 // set result register to 1 if "overflow" (any NaNs)
+ movvc r0, #0
+ bx lr
+END_COMPILERRT_FUNCTION(__unordsf2vfp)
diff --git a/lib/builtins/arm64/Makefile.mk b/lib/builtins/arm64/Makefile.mk
new file mode 100644
index 000000000000..7f7e38661303
--- /dev/null
+++ b/lib/builtins/arm64/Makefile.mk
@@ -0,0 +1,20 @@
+#===- lib/builtins/arm64/Makefile.mk -----------------------*- Makefile -*--===#
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+
+ModuleName := builtins
+SubDirs :=
+OnlyArchs := arm64
+
+AsmSources := $(foreach file,$(wildcard $(Dir)/*.S),$(notdir $(file)))
+Sources := $(foreach file,$(wildcard $(Dir)/*.c),$(notdir $(file)))
+ObjNames := $(Sources:%.c=%.o) $(AsmSources:%.S=%.o)
+Implementation := Optimized
+
+# FIXME: use automatic dependencies?
+Dependencies := $(wildcard lib/*.h $(Dir)/*.h)
diff --git a/lib/builtins/armv6m/Makefile.mk b/lib/builtins/armv6m/Makefile.mk
new file mode 100644
index 000000000000..f3c1807f01b8
--- /dev/null
+++ b/lib/builtins/armv6m/Makefile.mk
@@ -0,0 +1,20 @@
+#===- lib/builtins/arm/Makefile.mk -------------------------*- Makefile -*--===#
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+
+ModuleName := builtins
+SubDirs :=
+OnlyArchs := armv6m
+
+AsmSources := $(foreach file,$(wildcard $(Dir)/*.S),$(notdir $(file)))
+Sources := $(foreach file,$(wildcard $(Dir)/*.c),$(notdir $(file)))
+ObjNames := $(Sources:%.c=%.o) $(AsmSources:%.S=%.o)
+Implementation := Optimized
+
+# FIXME: use automatic dependencies?
+Dependencies := $(wildcard lib/*.h $(Dir)/*.h)
diff --git a/lib/ashldi3.c b/lib/builtins/ashldi3.c
index eb4698ac517c..eb4698ac517c 100644
--- a/lib/ashldi3.c
+++ b/lib/builtins/ashldi3.c
diff --git a/lib/builtins/ashlti3.c b/lib/builtins/ashlti3.c
new file mode 100644
index 000000000000..638ae845ff04
--- /dev/null
+++ b/lib/builtins/ashlti3.c
@@ -0,0 +1,45 @@
+/* ===-- ashlti3.c - Implement __ashlti3 -----------------------------------===
+ *
+ * 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 __ashlti3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+/* Returns: a << b */
+
+/* Precondition: 0 <= b < bits_in_tword */
+
+COMPILER_RT_ABI ti_int
+__ashlti3(ti_int a, si_int b)
+{
+ const int bits_in_dword = (int)(sizeof(di_int) * CHAR_BIT);
+ twords input;
+ twords result;
+ input.all = a;
+ if (b & bits_in_dword) /* bits_in_dword <= b < bits_in_tword */
+ {
+ result.s.low = 0;
+ result.s.high = input.s.low << (b - bits_in_dword);
+ }
+ else /* 0 <= b < bits_in_dword */
+ {
+ if (b == 0)
+ return a;
+ result.s.low = input.s.low << b;
+ result.s.high = (input.s.high << b) | (input.s.low >> (bits_in_dword - b));
+ }
+ return result.all;
+}
+
+#endif /* CRT_HAS_128BIT */
diff --git a/lib/ashrdi3.c b/lib/builtins/ashrdi3.c
index 14c878bb7793..14c878bb7793 100644
--- a/lib/ashrdi3.c
+++ b/lib/builtins/ashrdi3.c
diff --git a/lib/builtins/ashrti3.c b/lib/builtins/ashrti3.c
new file mode 100644
index 000000000000..f78205d961e4
--- /dev/null
+++ b/lib/builtins/ashrti3.c
@@ -0,0 +1,46 @@
+/* ===-- ashrti3.c - Implement __ashrti3 -----------------------------------===
+ *
+ * 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 __ashrti3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+/* Returns: arithmetic a >> b */
+
+/* Precondition: 0 <= b < bits_in_tword */
+
+COMPILER_RT_ABI ti_int
+__ashrti3(ti_int a, si_int b)
+{
+ const int bits_in_dword = (int)(sizeof(di_int) * CHAR_BIT);
+ twords input;
+ twords result;
+ input.all = a;
+ if (b & bits_in_dword) /* bits_in_dword <= b < bits_in_tword */
+ {
+ /* result.s.high = input.s.high < 0 ? -1 : 0 */
+ result.s.high = input.s.high >> (bits_in_dword - 1);
+ result.s.low = input.s.high >> (b - bits_in_dword);
+ }
+ else /* 0 <= b < bits_in_dword */
+ {
+ if (b == 0)
+ return a;
+ result.s.high = input.s.high >> b;
+ result.s.low = (input.s.high << (bits_in_dword - b)) | (input.s.low >> b);
+ }
+ return result.all;
+}
+
+#endif /* CRT_HAS_128BIT */
diff --git a/lib/builtins/assembly.h b/lib/builtins/assembly.h
new file mode 100644
index 000000000000..8bb0ddc106bd
--- /dev/null
+++ b/lib/builtins/assembly.h
@@ -0,0 +1,149 @@
+/* ===-- assembly.h - compiler-rt assembler support macros -----------------===
+ *
+ * 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 defines macros for use in compiler-rt assembler source.
+ * This file is not part of the interface of this library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#ifndef COMPILERRT_ASSEMBLY_H
+#define COMPILERRT_ASSEMBLY_H
+
+#if defined(__POWERPC__) || defined(__powerpc__) || defined(__ppc__)
+#define SEPARATOR @
+#else
+#define SEPARATOR ;
+#endif
+
+#if defined(__APPLE__)
+#define HIDDEN(name) .private_extern name
+#define LOCAL_LABEL(name) L_##name
+// tell linker it can break up file at label boundaries
+#define FILE_LEVEL_DIRECTIVE .subsections_via_symbols
+#define SYMBOL_IS_FUNC(name)
+#define CONST_SECTION .const
+
+#elif defined(__ELF__)
+
+#define HIDDEN(name) .hidden name
+#define LOCAL_LABEL(name) .L_##name
+#define FILE_LEVEL_DIRECTIVE
+#if defined(__arm__)
+#define SYMBOL_IS_FUNC(name) .type name,%function
+#else
+#define SYMBOL_IS_FUNC(name) .type name,@function
+#endif
+#define CONST_SECTION .section .rodata
+
+#else // !__APPLE__ && !__ELF__
+
+#define HIDDEN(name)
+#define LOCAL_LABEL(name) .L ## name
+#define FILE_LEVEL_DIRECTIVE
+#define SYMBOL_IS_FUNC(name) \
+ .def name SEPARATOR \
+ .scl 2 SEPARATOR \
+ .type 32 SEPARATOR \
+ .endef
+#define CONST_SECTION .section .rdata,"rd"
+
+#endif
+
+#if defined(__arm__)
+#if defined(__ARM_ARCH_4T__) || __ARM_ARCH >= 5
+#define ARM_HAS_BX
+#endif
+#if !defined(__ARM_FEATURE_CLZ) && \
+ (__ARM_ARCH >= 6 || (__ARM_ARCH == 5 && !defined(__ARM_ARCH_5__)))
+#define __ARM_FEATURE_CLZ
+#endif
+
+#ifdef ARM_HAS_BX
+#define JMP(r) bx r
+#define JMPc(r, c) bx##c r
+#else
+#define JMP(r) mov pc, r
+#define JMPc(r, c) mov##c pc, r
+#endif
+
+#if __ARM_ARCH_ISA_THUMB == 2
+#define IT(cond) it cond
+#define ITT(cond) itt cond
+#else
+#define IT(cond)
+#define ITT(cond)
+#endif
+
+#if __ARM_ARCH_ISA_THUMB == 2
+#define WIDE(op) op.w
+#else
+#define WIDE(op) op
+#endif
+#endif
+
+#define GLUE2(a, b) a##b
+#define GLUE(a, b) GLUE2(a, b)
+#define SYMBOL_NAME(name) GLUE(__USER_LABEL_PREFIX__, name)
+
+#ifdef VISIBILITY_HIDDEN
+#define DECLARE_SYMBOL_VISIBILITY(name) \
+ HIDDEN(SYMBOL_NAME(name)) SEPARATOR
+#else
+#define DECLARE_SYMBOL_VISIBILITY(name)
+#endif
+
+#define DEFINE_COMPILERRT_FUNCTION(name) \
+ FILE_LEVEL_DIRECTIVE SEPARATOR \
+ .globl SYMBOL_NAME(name) SEPARATOR \
+ SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \
+ DECLARE_SYMBOL_VISIBILITY(name) \
+ SYMBOL_NAME(name):
+
+#define DEFINE_COMPILERRT_THUMB_FUNCTION(name) \
+ FILE_LEVEL_DIRECTIVE SEPARATOR \
+ .globl SYMBOL_NAME(name) SEPARATOR \
+ SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \
+ DECLARE_SYMBOL_VISIBILITY(name) SEPARATOR \
+ .thumb_func SEPARATOR \
+ SYMBOL_NAME(name):
+
+#define DEFINE_COMPILERRT_PRIVATE_FUNCTION(name) \
+ FILE_LEVEL_DIRECTIVE SEPARATOR \
+ .globl SYMBOL_NAME(name) SEPARATOR \
+ SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \
+ HIDDEN(SYMBOL_NAME(name)) SEPARATOR \
+ SYMBOL_NAME(name):
+
+#define DEFINE_COMPILERRT_PRIVATE_FUNCTION_UNMANGLED(name) \
+ .globl name SEPARATOR \
+ SYMBOL_IS_FUNC(name) SEPARATOR \
+ HIDDEN(name) SEPARATOR \
+ name:
+
+#define DEFINE_COMPILERRT_FUNCTION_ALIAS(name, target) \
+ .globl SYMBOL_NAME(name) SEPARATOR \
+ SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \
+ .set SYMBOL_NAME(name), SYMBOL_NAME(target) SEPARATOR
+
+#if defined(__ARM_EABI__)
+#define DEFINE_AEABI_FUNCTION_ALIAS(aeabi_name, name) \
+ DEFINE_COMPILERRT_FUNCTION_ALIAS(aeabi_name, name)
+#else
+#define DEFINE_AEABI_FUNCTION_ALIAS(aeabi_name, name)
+#endif
+
+#ifdef __ELF__
+#define END_COMPILERRT_FUNCTION(name) \
+ .size SYMBOL_NAME(name), . - SYMBOL_NAME(name)
+#else
+#define END_COMPILERRT_FUNCTION(name)
+#endif
+
+#endif /* COMPILERRT_ASSEMBLY_H */
diff --git a/lib/atomic.c b/lib/builtins/atomic.c
index 02429a653d2b..02429a653d2b 100644
--- a/lib/atomic.c
+++ b/lib/builtins/atomic.c
diff --git a/lib/builtins/clear_cache.c b/lib/builtins/clear_cache.c
new file mode 100644
index 000000000000..86e68afad3b7
--- /dev/null
+++ b/lib/builtins/clear_cache.c
@@ -0,0 +1,96 @@
+/* ===-- clear_cache.c - Implement __clear_cache ---------------------------===
+ *
+ * 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 "int_lib.h"
+
+#if __APPLE__
+ #include <libkern/OSCacheControl.h>
+#endif
+#if defined(__NetBSD__) && defined(__arm__)
+ #include <machine/sysarch.h>
+#endif
+
+#if defined(__ANDROID__) && defined(__mips__)
+ #include <sys/cachectl.h>
+#endif
+
+#if defined(__ANDROID__) && defined(__arm__)
+ #include <asm/unistd.h>
+#endif
+
+/*
+ * The compiler generates calls to __clear_cache() when creating
+ * trampoline functions on the stack for use with nested functions.
+ * It is expected to invalidate the instruction cache for the
+ * specified range.
+ */
+
+void __clear_cache(void *start, void *end) {
+#if __i386__ || __x86_64__
+/*
+ * Intel processors have a unified instruction and data cache
+ * so there is nothing to do
+ */
+#elif defined(__arm__) && !defined(__APPLE__)
+ #if defined(__NetBSD__)
+ struct arm_sync_icache_args arg;
+
+ arg.addr = (uintptr_t)start;
+ arg.len = (uintptr_t)end - (uintptr_t)start;
+
+ sysarch(ARM_SYNC_ICACHE, &arg);
+ #elif defined(__ANDROID__)
+ const register int start_reg __asm("r0") = (int) (intptr_t) start;
+ const register int end_reg __asm("r1") = (int) (intptr_t) end;
+ const register int flags __asm("r2") = 0;
+ const register int syscall_nr __asm("r7") = __ARM_NR_cacheflush;
+ __asm __volatile("svc 0x0" : "=r"(start_reg)
+ : "r"(syscall_nr), "r"(start_reg), "r"(end_reg), "r"(flags) : "r0");
+ if (start_reg != 0) {
+ compilerrt_abort();
+ }
+ #else
+ compilerrt_abort();
+ #endif
+#elif defined(__ANDROID__) && defined(__mips__)
+ const uintptr_t start_int = (uintptr_t) start;
+ const uintptr_t end_int = (uintptr_t) end;
+ _flush_cache(start, (end_int - start_int), BCACHE);
+#elif defined(__aarch64__) && !defined(__APPLE__)
+ uint64_t xstart = (uint64_t)(uintptr_t) start;
+ uint64_t xend = (uint64_t)(uintptr_t) end;
+
+ // Get Cache Type Info
+ uint64_t ctr_el0;
+ __asm __volatile("mrs %0, ctr_el0" : "=r"(ctr_el0));
+
+ /*
+ * dc & ic instructions must use 64bit registers so we don't use
+ * uintptr_t in case this runs in an IPL32 environment.
+ */
+ const size_t dcache_line_size = 4 << ((ctr_el0 >> 16) & 15);
+ for (uint64_t addr = xstart; addr < xend; addr += dcache_line_size)
+ __asm __volatile("dc cvau, %0" :: "r"(addr));
+ __asm __volatile("dsb ish");
+
+ const size_t icache_line_size = 4 << ((ctr_el0 >> 0) & 15);
+ for (uint64_t addr = xstart; addr < xend; addr += icache_line_size)
+ __asm __volatile("ic ivau, %0" :: "r"(addr));
+ __asm __volatile("isb sy");
+#else
+ #if __APPLE__
+ /* On Darwin, sys_icache_invalidate() provides this functionality */
+ sys_icache_invalidate(start, end-start);
+ #else
+ compilerrt_abort();
+ #endif
+#endif
+}
+
diff --git a/lib/clzdi2.c b/lib/builtins/clzdi2.c
index b9e64da492bd..b9e64da492bd 100644
--- a/lib/clzdi2.c
+++ b/lib/builtins/clzdi2.c
diff --git a/lib/clzsi2.c b/lib/builtins/clzsi2.c
index 25b8ed2c4c24..25b8ed2c4c24 100644
--- a/lib/clzsi2.c
+++ b/lib/builtins/clzsi2.c
diff --git a/lib/builtins/clzti2.c b/lib/builtins/clzti2.c
new file mode 100644
index 000000000000..15a7b3c90004
--- /dev/null
+++ b/lib/builtins/clzti2.c
@@ -0,0 +1,33 @@
+/* ===-- clzti2.c - Implement __clzti2 -------------------------------------===
+ *
+ * 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 __clzti2 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+/* Returns: the number of leading 0-bits */
+
+/* Precondition: a != 0 */
+
+COMPILER_RT_ABI si_int
+__clzti2(ti_int a)
+{
+ twords x;
+ x.all = a;
+ const di_int f = -(x.s.high == 0);
+ return __builtin_clzll((x.s.high & ~f) | (x.s.low & f)) +
+ ((si_int)f & ((si_int)(sizeof(di_int) * CHAR_BIT)));
+}
+
+#endif /* CRT_HAS_128BIT */
diff --git a/lib/cmpdi2.c b/lib/builtins/cmpdi2.c
index 52634d9c3362..52634d9c3362 100644
--- a/lib/cmpdi2.c
+++ b/lib/builtins/cmpdi2.c
diff --git a/lib/builtins/cmpti2.c b/lib/builtins/cmpti2.c
new file mode 100644
index 000000000000..2c8b56e29a06
--- /dev/null
+++ b/lib/builtins/cmpti2.c
@@ -0,0 +1,42 @@
+/* ===-- cmpti2.c - Implement __cmpti2 -------------------------------------===
+ *
+ * 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 __cmpti2 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+/* Returns: if (a < b) returns 0
+ * if (a == b) returns 1
+ * if (a > b) returns 2
+ */
+
+COMPILER_RT_ABI si_int
+__cmpti2(ti_int a, ti_int b)
+{
+ twords x;
+ x.all = a;
+ twords y;
+ y.all = b;
+ if (x.s.high < y.s.high)
+ return 0;
+ if (x.s.high > y.s.high)
+ return 2;
+ if (x.s.low < y.s.low)
+ return 0;
+ if (x.s.low > y.s.low)
+ return 2;
+ return 1;
+}
+
+#endif /* CRT_HAS_128BIT */
diff --git a/lib/builtins/comparedf2.c b/lib/builtins/comparedf2.c
new file mode 100644
index 000000000000..64eea1249055
--- /dev/null
+++ b/lib/builtins/comparedf2.c
@@ -0,0 +1,141 @@
+//===-- lib/comparedf2.c - Double-precision comparisons -----------*- 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 the following soft-float comparison routines:
+//
+// __eqdf2 __gedf2 __unorddf2
+// __ledf2 __gtdf2
+// __ltdf2
+// __nedf2
+//
+// The semantics of the routines grouped in each column are identical, so there
+// is a single implementation for each, and wrappers to provide the other names.
+//
+// The main routines behave as follows:
+//
+// __ledf2(a,b) returns -1 if a < b
+// 0 if a == b
+// 1 if a > b
+// 1 if either a or b is NaN
+//
+// __gedf2(a,b) returns -1 if a < b
+// 0 if a == b
+// 1 if a > b
+// -1 if either a or b is NaN
+//
+// __unorddf2(a,b) returns 0 if both a and b are numbers
+// 1 if either a or b is NaN
+//
+// Note that __ledf2( ) and __gedf2( ) are identical except in their handling of
+// NaN values.
+//
+//===----------------------------------------------------------------------===//
+
+#define DOUBLE_PRECISION
+#include "fp_lib.h"
+
+enum LE_RESULT {
+ LE_LESS = -1,
+ LE_EQUAL = 0,
+ LE_GREATER = 1,
+ LE_UNORDERED = 1
+};
+
+COMPILER_RT_ABI enum LE_RESULT
+__ledf2(fp_t a, fp_t b) {
+
+ const srep_t aInt = toRep(a);
+ const srep_t bInt = toRep(b);
+ const rep_t aAbs = aInt & absMask;
+ const rep_t bAbs = bInt & absMask;
+
+ // If either a or b is NaN, they are unordered.
+ if (aAbs > infRep || bAbs > infRep) return LE_UNORDERED;
+
+ // If a and b are both zeros, they are equal.
+ if ((aAbs | bAbs) == 0) return LE_EQUAL;
+
+ // If at least one of a and b is positive, we get the same result comparing
+ // a and b as signed integers as we would with a floating-point compare.
+ if ((aInt & bInt) >= 0) {
+ if (aInt < bInt) return LE_LESS;
+ else if (aInt == bInt) return LE_EQUAL;
+ else return LE_GREATER;
+ }
+
+ // Otherwise, both are negative, so we need to flip the sense of the
+ // comparison to get the correct result. (This assumes a twos- or ones-
+ // complement integer representation; if integers are represented in a
+ // sign-magnitude representation, then this flip is incorrect).
+ else {
+ if (aInt > bInt) return LE_LESS;
+ else if (aInt == bInt) return LE_EQUAL;
+ else return LE_GREATER;
+ }
+}
+
+enum GE_RESULT {
+ GE_LESS = -1,
+ GE_EQUAL = 0,
+ GE_GREATER = 1,
+ GE_UNORDERED = -1 // Note: different from LE_UNORDERED
+};
+
+COMPILER_RT_ABI enum GE_RESULT
+__gedf2(fp_t a, fp_t b) {
+
+ const srep_t aInt = toRep(a);
+ const srep_t bInt = toRep(b);
+ const rep_t aAbs = aInt & absMask;
+ const rep_t bAbs = bInt & absMask;
+
+ if (aAbs > infRep || bAbs > infRep) return GE_UNORDERED;
+ if ((aAbs | bAbs) == 0) return GE_EQUAL;
+ if ((aInt & bInt) >= 0) {
+ if (aInt < bInt) return GE_LESS;
+ else if (aInt == bInt) return GE_EQUAL;
+ else return GE_GREATER;
+ } else {
+ if (aInt > bInt) return GE_LESS;
+ else if (aInt == bInt) return GE_EQUAL;
+ else return GE_GREATER;
+ }
+}
+
+ARM_EABI_FNALIAS(dcmpun, unorddf2)
+
+COMPILER_RT_ABI int
+__unorddf2(fp_t a, fp_t b) {
+ const rep_t aAbs = toRep(a) & absMask;
+ const rep_t bAbs = toRep(b) & absMask;
+ return aAbs > infRep || bAbs > infRep;
+}
+
+// The following are alternative names for the preceding routines.
+
+COMPILER_RT_ABI enum LE_RESULT
+__eqdf2(fp_t a, fp_t b) {
+ return __ledf2(a, b);
+}
+
+COMPILER_RT_ABI enum LE_RESULT
+__ltdf2(fp_t a, fp_t b) {
+ return __ledf2(a, b);
+}
+
+COMPILER_RT_ABI enum LE_RESULT
+__nedf2(fp_t a, fp_t b) {
+ return __ledf2(a, b);
+}
+
+COMPILER_RT_ABI enum GE_RESULT
+__gtdf2(fp_t a, fp_t b) {
+ return __gedf2(a, b);
+}
+
diff --git a/lib/builtins/comparesf2.c b/lib/builtins/comparesf2.c
new file mode 100644
index 000000000000..442289c1004e
--- /dev/null
+++ b/lib/builtins/comparesf2.c
@@ -0,0 +1,140 @@
+//===-- lib/comparesf2.c - Single-precision comparisons -----------*- 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 the following soft-fp_t comparison routines:
+//
+// __eqsf2 __gesf2 __unordsf2
+// __lesf2 __gtsf2
+// __ltsf2
+// __nesf2
+//
+// The semantics of the routines grouped in each column are identical, so there
+// is a single implementation for each, and wrappers to provide the other names.
+//
+// The main routines behave as follows:
+//
+// __lesf2(a,b) returns -1 if a < b
+// 0 if a == b
+// 1 if a > b
+// 1 if either a or b is NaN
+//
+// __gesf2(a,b) returns -1 if a < b
+// 0 if a == b
+// 1 if a > b
+// -1 if either a or b is NaN
+//
+// __unordsf2(a,b) returns 0 if both a and b are numbers
+// 1 if either a or b is NaN
+//
+// Note that __lesf2( ) and __gesf2( ) are identical except in their handling of
+// NaN values.
+//
+//===----------------------------------------------------------------------===//
+
+#define SINGLE_PRECISION
+#include "fp_lib.h"
+
+enum LE_RESULT {
+ LE_LESS = -1,
+ LE_EQUAL = 0,
+ LE_GREATER = 1,
+ LE_UNORDERED = 1
+};
+
+COMPILER_RT_ABI enum LE_RESULT
+__lesf2(fp_t a, fp_t b) {
+
+ const srep_t aInt = toRep(a);
+ const srep_t bInt = toRep(b);
+ const rep_t aAbs = aInt & absMask;
+ const rep_t bAbs = bInt & absMask;
+
+ // If either a or b is NaN, they are unordered.
+ if (aAbs > infRep || bAbs > infRep) return LE_UNORDERED;
+
+ // If a and b are both zeros, they are equal.
+ if ((aAbs | bAbs) == 0) return LE_EQUAL;
+
+ // If at least one of a and b is positive, we get the same result comparing
+ // a and b as signed integers as we would with a fp_ting-point compare.
+ if ((aInt & bInt) >= 0) {
+ if (aInt < bInt) return LE_LESS;
+ else if (aInt == bInt) return LE_EQUAL;
+ else return LE_GREATER;
+ }
+
+ // Otherwise, both are negative, so we need to flip the sense of the
+ // comparison to get the correct result. (This assumes a twos- or ones-
+ // complement integer representation; if integers are represented in a
+ // sign-magnitude representation, then this flip is incorrect).
+ else {
+ if (aInt > bInt) return LE_LESS;
+ else if (aInt == bInt) return LE_EQUAL;
+ else return LE_GREATER;
+ }
+}
+
+enum GE_RESULT {
+ GE_LESS = -1,
+ GE_EQUAL = 0,
+ GE_GREATER = 1,
+ GE_UNORDERED = -1 // Note: different from LE_UNORDERED
+};
+
+COMPILER_RT_ABI enum GE_RESULT
+__gesf2(fp_t a, fp_t b) {
+
+ const srep_t aInt = toRep(a);
+ const srep_t bInt = toRep(b);
+ const rep_t aAbs = aInt & absMask;
+ const rep_t bAbs = bInt & absMask;
+
+ if (aAbs > infRep || bAbs > infRep) return GE_UNORDERED;
+ if ((aAbs | bAbs) == 0) return GE_EQUAL;
+ if ((aInt & bInt) >= 0) {
+ if (aInt < bInt) return GE_LESS;
+ else if (aInt == bInt) return GE_EQUAL;
+ else return GE_GREATER;
+ } else {
+ if (aInt > bInt) return GE_LESS;
+ else if (aInt == bInt) return GE_EQUAL;
+ else return GE_GREATER;
+ }
+}
+
+ARM_EABI_FNALIAS(fcmpun, unordsf2)
+
+COMPILER_RT_ABI int
+__unordsf2(fp_t a, fp_t b) {
+ const rep_t aAbs = toRep(a) & absMask;
+ const rep_t bAbs = toRep(b) & absMask;
+ return aAbs > infRep || bAbs > infRep;
+}
+
+// The following are alternative names for the preceding routines.
+
+COMPILER_RT_ABI enum LE_RESULT
+__eqsf2(fp_t a, fp_t b) {
+ return __lesf2(a, b);
+}
+
+COMPILER_RT_ABI enum LE_RESULT
+__ltsf2(fp_t a, fp_t b) {
+ return __lesf2(a, b);
+}
+
+COMPILER_RT_ABI enum LE_RESULT
+__nesf2(fp_t a, fp_t b) {
+ return __lesf2(a, b);
+}
+
+COMPILER_RT_ABI enum GE_RESULT
+__gtsf2(fp_t a, fp_t b) {
+ return __gesf2(a, b);
+}
diff --git a/lib/builtins/comparetf2.c b/lib/builtins/comparetf2.c
new file mode 100644
index 000000000000..a6436de89e76
--- /dev/null
+++ b/lib/builtins/comparetf2.c
@@ -0,0 +1,133 @@
+//===-- lib/comparetf2.c - Quad-precision comparisons -------------*- 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 the following soft-float comparison routines:
+//
+// __eqtf2 __getf2 __unordtf2
+// __letf2 __gttf2
+// __lttf2
+// __netf2
+//
+// The semantics of the routines grouped in each column are identical, so there
+// is a single implementation for each, and wrappers to provide the other names.
+//
+// The main routines behave as follows:
+//
+// __letf2(a,b) returns -1 if a < b
+// 0 if a == b
+// 1 if a > b
+// 1 if either a or b is NaN
+//
+// __getf2(a,b) returns -1 if a < b
+// 0 if a == b
+// 1 if a > b
+// -1 if either a or b is NaN
+//
+// __unordtf2(a,b) returns 0 if both a and b are numbers
+// 1 if either a or b is NaN
+//
+// Note that __letf2( ) and __getf2( ) are identical except in their handling of
+// NaN values.
+//
+//===----------------------------------------------------------------------===//
+
+#define QUAD_PRECISION
+#include "fp_lib.h"
+
+#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
+enum LE_RESULT {
+ LE_LESS = -1,
+ LE_EQUAL = 0,
+ LE_GREATER = 1,
+ LE_UNORDERED = 1
+};
+
+COMPILER_RT_ABI enum LE_RESULT __letf2(fp_t a, fp_t b) {
+
+ const srep_t aInt = toRep(a);
+ const srep_t bInt = toRep(b);
+ const rep_t aAbs = aInt & absMask;
+ const rep_t bAbs = bInt & absMask;
+
+ // If either a or b is NaN, they are unordered.
+ if (aAbs > infRep || bAbs > infRep) return LE_UNORDERED;
+
+ // If a and b are both zeros, they are equal.
+ if ((aAbs | bAbs) == 0) return LE_EQUAL;
+
+ // If at least one of a and b is positive, we get the same result comparing
+ // a and b as signed integers as we would with a floating-point compare.
+ if ((aInt & bInt) >= 0) {
+ if (aInt < bInt) return LE_LESS;
+ else if (aInt == bInt) return LE_EQUAL;
+ else return LE_GREATER;
+ }
+ else {
+ // Otherwise, both are negative, so we need to flip the sense of the
+ // comparison to get the correct result. (This assumes a twos- or ones-
+ // complement integer representation; if integers are represented in a
+ // sign-magnitude representation, then this flip is incorrect).
+ if (aInt > bInt) return LE_LESS;
+ else if (aInt == bInt) return LE_EQUAL;
+ else return LE_GREATER;
+ }
+}
+
+enum GE_RESULT {
+ GE_LESS = -1,
+ GE_EQUAL = 0,
+ GE_GREATER = 1,
+ GE_UNORDERED = -1 // Note: different from LE_UNORDERED
+};
+
+COMPILER_RT_ABI enum GE_RESULT __getf2(fp_t a, fp_t b) {
+
+ const srep_t aInt = toRep(a);
+ const srep_t bInt = toRep(b);
+ const rep_t aAbs = aInt & absMask;
+ const rep_t bAbs = bInt & absMask;
+
+ if (aAbs > infRep || bAbs > infRep) return GE_UNORDERED;
+ if ((aAbs | bAbs) == 0) return GE_EQUAL;
+ if ((aInt & bInt) >= 0) {
+ if (aInt < bInt) return GE_LESS;
+ else if (aInt == bInt) return GE_EQUAL;
+ else return GE_GREATER;
+ } else {
+ if (aInt > bInt) return GE_LESS;
+ else if (aInt == bInt) return GE_EQUAL;
+ else return GE_GREATER;
+ }
+}
+
+COMPILER_RT_ABI int __unordtf2(fp_t a, fp_t b) {
+ const rep_t aAbs = toRep(a) & absMask;
+ const rep_t bAbs = toRep(b) & absMask;
+ return aAbs > infRep || bAbs > infRep;
+}
+
+// The following are alternative names for the preceding routines.
+
+COMPILER_RT_ABI enum LE_RESULT __eqtf2(fp_t a, fp_t b) {
+ return __letf2(a, b);
+}
+
+COMPILER_RT_ABI enum LE_RESULT __lttf2(fp_t a, fp_t b) {
+ return __letf2(a, b);
+}
+
+COMPILER_RT_ABI enum LE_RESULT __netf2(fp_t a, fp_t b) {
+ return __letf2(a, b);
+}
+
+COMPILER_RT_ABI enum GE_RESULT __gttf2(fp_t a, fp_t b) {
+ return __getf2(a, b);
+}
+
+#endif
diff --git a/lib/ctzdi2.c b/lib/builtins/ctzdi2.c
index db3c6fdc08f1..db3c6fdc08f1 100644
--- a/lib/ctzdi2.c
+++ b/lib/builtins/ctzdi2.c
diff --git a/lib/ctzsi2.c b/lib/builtins/ctzsi2.c
index c69486ea445f..c69486ea445f 100644
--- a/lib/ctzsi2.c
+++ b/lib/builtins/ctzsi2.c
diff --git a/lib/builtins/ctzti2.c b/lib/builtins/ctzti2.c
new file mode 100644
index 000000000000..45de682700cc
--- /dev/null
+++ b/lib/builtins/ctzti2.c
@@ -0,0 +1,33 @@
+/* ===-- ctzti2.c - Implement __ctzti2 -------------------------------------===
+ *
+ * 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 __ctzti2 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+/* Returns: the number of trailing 0-bits */
+
+/* Precondition: a != 0 */
+
+COMPILER_RT_ABI si_int
+__ctzti2(ti_int a)
+{
+ twords x;
+ x.all = a;
+ const di_int f = -(x.s.low == 0);
+ return __builtin_ctzll((x.s.high & f) | (x.s.low & ~f)) +
+ ((si_int)f & ((si_int)(sizeof(di_int) * CHAR_BIT)));
+}
+
+#endif /* CRT_HAS_128BIT */
diff --git a/lib/builtins/divdc3.c b/lib/builtins/divdc3.c
new file mode 100644
index 000000000000..7de78c8711e1
--- /dev/null
+++ b/lib/builtins/divdc3.c
@@ -0,0 +1,60 @@
+/* ===-- divdc3.c - Implement __divdc3 -------------------------------------===
+ *
+ * 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 __divdc3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+#include "int_math.h"
+
+/* Returns: the quotient of (a + ib) / (c + id) */
+
+COMPILER_RT_ABI double _Complex
+__divdc3(double __a, double __b, double __c, double __d)
+{
+ int __ilogbw = 0;
+ double __logbw = crt_logb(crt_fmax(crt_fabs(__c), crt_fabs(__d)));
+ if (crt_isfinite(__logbw))
+ {
+ __ilogbw = (int)__logbw;
+ __c = crt_scalbn(__c, -__ilogbw);
+ __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))
+ {
+ 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;
+ }
+ 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);
+ }
+ 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);
+ }
+ }
+ return z;
+}
diff --git a/lib/builtins/divdf3.c b/lib/builtins/divdf3.c
new file mode 100644
index 000000000000..ab44c2b25fe5
--- /dev/null
+++ b/lib/builtins/divdf3.c
@@ -0,0 +1,185 @@
+//===-- lib/divdf3.c - Double-precision division ------------------*- 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 double-precision soft-float division
+// with the IEEE-754 default rounding (to nearest, ties to even).
+//
+// For simplicity, this implementation currently flushes denormals to zero.
+// It should be a fairly straightforward exercise to implement gradual
+// underflow with correct rounding.
+//
+//===----------------------------------------------------------------------===//
+
+#define DOUBLE_PRECISION
+#include "fp_lib.h"
+
+ARM_EABI_FNALIAS(ddiv, divdf3)
+
+COMPILER_RT_ABI fp_t
+__divdf3(fp_t a, fp_t b) {
+
+ const unsigned int aExponent = toRep(a) >> significandBits & maxExponent;
+ const unsigned int bExponent = toRep(b) >> significandBits & maxExponent;
+ const rep_t quotientSign = (toRep(a) ^ toRep(b)) & signBit;
+
+ rep_t aSignificand = toRep(a) & significandMask;
+ rep_t bSignificand = toRep(b) & significandMask;
+ int scale = 0;
+
+ // Detect if a or b is zero, denormal, infinity, or NaN.
+ if (aExponent-1U >= maxExponent-1U || bExponent-1U >= maxExponent-1U) {
+
+ const rep_t aAbs = toRep(a) & absMask;
+ const rep_t bAbs = toRep(b) & absMask;
+
+ // NaN / anything = qNaN
+ if (aAbs > infRep) return fromRep(toRep(a) | quietBit);
+ // anything / NaN = qNaN
+ if (bAbs > infRep) return fromRep(toRep(b) | quietBit);
+
+ if (aAbs == infRep) {
+ // infinity / infinity = NaN
+ if (bAbs == infRep) return fromRep(qnanRep);
+ // infinity / anything else = +/- infinity
+ else return fromRep(aAbs | quotientSign);
+ }
+
+ // anything else / infinity = +/- 0
+ if (bAbs == infRep) return fromRep(quotientSign);
+
+ if (!aAbs) {
+ // zero / zero = NaN
+ if (!bAbs) return fromRep(qnanRep);
+ // zero / anything else = +/- zero
+ else return fromRep(quotientSign);
+ }
+ // anything else / zero = +/- infinity
+ if (!bAbs) return fromRep(infRep | quotientSign);
+
+ // one or both of a or b is denormal, the other (if applicable) is a
+ // normal number. Renormalize one or both of a and b, and set scale to
+ // include the necessary exponent adjustment.
+ if (aAbs < implicitBit) scale += normalize(&aSignificand);
+ if (bAbs < implicitBit) scale -= normalize(&bSignificand);
+ }
+
+ // Or in the implicit significand bit. (If we fell through from the
+ // denormal path it was already set by normalize( ), but setting it twice
+ // won't hurt anything.)
+ aSignificand |= implicitBit;
+ bSignificand |= implicitBit;
+ int quotientExponent = aExponent - bExponent + scale;
+
+ // Align the significand of b as a Q31 fixed-point number in the range
+ // [1, 2.0) and get a Q32 approximate reciprocal using a small minimax
+ // polynomial approximation: reciprocal = 3/4 + 1/sqrt(2) - b/2. This
+ // is accurate to about 3.5 binary digits.
+ const uint32_t q31b = bSignificand >> 21;
+ uint32_t recip32 = UINT32_C(0x7504f333) - q31b;
+
+ // Now refine the reciprocal estimate using a Newton-Raphson iteration:
+ //
+ // x1 = x0 * (2 - x0 * b)
+ //
+ // This doubles the number of correct binary digits in the approximation
+ // with each iteration, so after three iterations, we have about 28 binary
+ // digits of accuracy.
+ uint32_t correction32;
+ correction32 = -((uint64_t)recip32 * q31b >> 32);
+ recip32 = (uint64_t)recip32 * correction32 >> 31;
+ correction32 = -((uint64_t)recip32 * q31b >> 32);
+ recip32 = (uint64_t)recip32 * correction32 >> 31;
+ correction32 = -((uint64_t)recip32 * q31b >> 32);
+ recip32 = (uint64_t)recip32 * correction32 >> 31;
+
+ // recip32 might have overflowed to exactly zero in the preceding
+ // computation if the high word of b is exactly 1.0. This would sabotage
+ // the full-width final stage of the computation that follows, so we adjust
+ // recip32 downward by one bit.
+ recip32--;
+
+ // We need to perform one more iteration to get us to 56 binary digits;
+ // The last iteration needs to happen with extra precision.
+ const uint32_t q63blo = bSignificand << 11;
+ uint64_t correction, reciprocal;
+ correction = -((uint64_t)recip32*q31b + ((uint64_t)recip32*q63blo >> 32));
+ uint32_t cHi = correction >> 32;
+ uint32_t cLo = correction;
+ reciprocal = (uint64_t)recip32*cHi + ((uint64_t)recip32*cLo >> 32);
+
+ // We already adjusted the 32-bit estimate, now we need to adjust the final
+ // 64-bit reciprocal estimate downward to ensure that it is strictly smaller
+ // than the infinitely precise exact reciprocal. Because the computation
+ // of the Newton-Raphson step is truncating at every step, this adjustment
+ // is small; most of the work is already done.
+ reciprocal -= 2;
+
+ // The numerical reciprocal is accurate to within 2^-56, lies in the
+ // interval [0.5, 1.0), and is strictly smaller than the true reciprocal
+ // of b. Multiplying a by this reciprocal thus gives a numerical q = a/b
+ // in Q53 with the following properties:
+ //
+ // 1. q < a/b
+ // 2. q is in the interval [0.5, 2.0)
+ // 3. the error in q is bounded away from 2^-53 (actually, we have a
+ // couple of bits to spare, but this is all we need).
+
+ // We need a 64 x 64 multiply high to compute q, which isn't a basic
+ // operation in C, so we need to be a little bit fussy.
+ rep_t quotient, quotientLo;
+ wideMultiply(aSignificand << 2, reciprocal, &quotient, &quotientLo);
+
+ // Two cases: quotient is in [0.5, 1.0) or quotient is in [1.0, 2.0).
+ // In either case, we are going to compute a residual of the form
+ //
+ // r = a - q*b
+ //
+ // We know from the construction of q that r satisfies:
+ //
+ // 0 <= r < ulp(q)*b
+ //
+ // if r is greater than 1/2 ulp(q)*b, then q rounds up. Otherwise, we
+ // already have the correct result. The exact halfway case cannot occur.
+ // We also take this time to right shift quotient if it falls in the [1,2)
+ // range and adjust the exponent accordingly.
+ rep_t residual;
+ if (quotient < (implicitBit << 1)) {
+ residual = (aSignificand << 53) - quotient * bSignificand;
+ quotientExponent--;
+ } else {
+ quotient >>= 1;
+ residual = (aSignificand << 52) - quotient * bSignificand;
+ }
+
+ const int writtenExponent = quotientExponent + exponentBias;
+
+ if (writtenExponent >= maxExponent) {
+ // If we have overflowed the exponent, return infinity.
+ return fromRep(infRep | quotientSign);
+ }
+
+ else if (writtenExponent < 1) {
+ // Flush denormals to zero. In the future, it would be nice to add
+ // code to round them correctly.
+ return fromRep(quotientSign);
+ }
+
+ else {
+ const bool round = (residual << 1) > bSignificand;
+ // Clear the implicit bit
+ rep_t absResult = quotient & significandMask;
+ // Insert the exponent
+ absResult |= (rep_t)writtenExponent << significandBits;
+ // Round
+ absResult += round;
+ // Insert the sign and return
+ const double result = fromRep(absResult | quotientSign);
+ return result;
+ }
+}
diff --git a/lib/builtins/divdi3.c b/lib/builtins/divdi3.c
new file mode 100644
index 000000000000..b8eebcb20465
--- /dev/null
+++ b/lib/builtins/divdi3.c
@@ -0,0 +1,29 @@
+/* ===-- divdi3.c - Implement __divdi3 -------------------------------------===
+ *
+ * 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 __divdi3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: a / b */
+
+COMPILER_RT_ABI di_int
+__divdi3(di_int a, di_int b)
+{
+ const int bits_in_dword_m1 = (int)(sizeof(di_int) * CHAR_BIT) - 1;
+ di_int s_a = a >> bits_in_dword_m1; /* s_a = a < 0 ? -1 : 0 */
+ di_int s_b = b >> bits_in_dword_m1; /* s_b = b < 0 ? -1 : 0 */
+ a = (a ^ s_a) - s_a; /* negate if s_a == -1 */
+ b = (b ^ s_b) - s_b; /* negate if s_b == -1 */
+ s_a ^= s_b; /*sign of quotient */
+ return (__udivmoddi4(a, b, (du_int*)0) ^ s_a) - s_a; /* negate if s_a == -1 */
+}
diff --git a/lib/builtins/divmoddi4.c b/lib/builtins/divmoddi4.c
new file mode 100644
index 000000000000..0d4df67a63e0
--- /dev/null
+++ b/lib/builtins/divmoddi4.c
@@ -0,0 +1,25 @@
+/*===-- divmoddi4.c - Implement __divmoddi4 --------------------------------===
+ *
+ * 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 __divmoddi4 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: a / b, *rem = a % b */
+
+COMPILER_RT_ABI di_int
+__divmoddi4(di_int a, di_int b, di_int* rem)
+{
+ di_int d = __divdi3(a,b);
+ *rem = a - (d*b);
+ return d;
+}
diff --git a/lib/builtins/divmodsi4.c b/lib/builtins/divmodsi4.c
new file mode 100644
index 000000000000..dabe2874397c
--- /dev/null
+++ b/lib/builtins/divmodsi4.c
@@ -0,0 +1,27 @@
+/*===-- divmodsi4.c - Implement __divmodsi4 --------------------------------===
+ *
+ * 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 __divmodsi4 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: a / b, *rem = a % b */
+
+COMPILER_RT_ABI si_int
+__divmodsi4(si_int a, si_int b, si_int* rem)
+{
+ si_int d = __divsi3(a,b);
+ *rem = a - (d*b);
+ return d;
+}
+
+
diff --git a/lib/builtins/divsc3.c b/lib/builtins/divsc3.c
new file mode 100644
index 000000000000..710d5320803f
--- /dev/null
+++ b/lib/builtins/divsc3.c
@@ -0,0 +1,60 @@
+/*===-- divsc3.c - Implement __divsc3 -------------------------------------===
+ *
+ * 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 __divsc3 for the compiler_rt library.
+ *
+ *===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+#include "int_math.h"
+
+/* Returns: the quotient of (a + ib) / (c + id) */
+
+COMPILER_RT_ABI float _Complex
+__divsc3(float __a, float __b, float __c, float __d)
+{
+ int __ilogbw = 0;
+ float __logbw = crt_logbf(crt_fmaxf(crt_fabsf(__c), crt_fabsf(__d)));
+ if (crt_isfinite(__logbw))
+ {
+ __ilogbw = (int)__logbw;
+ __c = crt_scalbnf(__c, -__ilogbw);
+ __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))
+ {
+ 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;
+ }
+ 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);
+ }
+ 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);
+ }
+ }
+ return z;
+}
diff --git a/lib/builtins/divsf3.c b/lib/builtins/divsf3.c
new file mode 100644
index 000000000000..de2e376125b6
--- /dev/null
+++ b/lib/builtins/divsf3.c
@@ -0,0 +1,169 @@
+//===-- lib/divsf3.c - Single-precision division ------------------*- 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 single-precision soft-float division
+// with the IEEE-754 default rounding (to nearest, ties to even).
+//
+// For simplicity, this implementation currently flushes denormals to zero.
+// It should be a fairly straightforward exercise to implement gradual
+// underflow with correct rounding.
+//
+//===----------------------------------------------------------------------===//
+
+#define SINGLE_PRECISION
+#include "fp_lib.h"
+
+ARM_EABI_FNALIAS(fdiv, divsf3)
+
+COMPILER_RT_ABI fp_t
+__divsf3(fp_t a, fp_t b) {
+
+ const unsigned int aExponent = toRep(a) >> significandBits & maxExponent;
+ const unsigned int bExponent = toRep(b) >> significandBits & maxExponent;
+ const rep_t quotientSign = (toRep(a) ^ toRep(b)) & signBit;
+
+ rep_t aSignificand = toRep(a) & significandMask;
+ rep_t bSignificand = toRep(b) & significandMask;
+ int scale = 0;
+
+ // Detect if a or b is zero, denormal, infinity, or NaN.
+ if (aExponent-1U >= maxExponent-1U || bExponent-1U >= maxExponent-1U) {
+
+ const rep_t aAbs = toRep(a) & absMask;
+ const rep_t bAbs = toRep(b) & absMask;
+
+ // NaN / anything = qNaN
+ if (aAbs > infRep) return fromRep(toRep(a) | quietBit);
+ // anything / NaN = qNaN
+ if (bAbs > infRep) return fromRep(toRep(b) | quietBit);
+
+ if (aAbs == infRep) {
+ // infinity / infinity = NaN
+ if (bAbs == infRep) return fromRep(qnanRep);
+ // infinity / anything else = +/- infinity
+ else return fromRep(aAbs | quotientSign);
+ }
+
+ // anything else / infinity = +/- 0
+ if (bAbs == infRep) return fromRep(quotientSign);
+
+ if (!aAbs) {
+ // zero / zero = NaN
+ if (!bAbs) return fromRep(qnanRep);
+ // zero / anything else = +/- zero
+ else return fromRep(quotientSign);
+ }
+ // anything else / zero = +/- infinity
+ if (!bAbs) return fromRep(infRep | quotientSign);
+
+ // one or both of a or b is denormal, the other (if applicable) is a
+ // normal number. Renormalize one or both of a and b, and set scale to
+ // include the necessary exponent adjustment.
+ if (aAbs < implicitBit) scale += normalize(&aSignificand);
+ if (bAbs < implicitBit) scale -= normalize(&bSignificand);
+ }
+
+ // Or in the implicit significand bit. (If we fell through from the
+ // denormal path it was already set by normalize( ), but setting it twice
+ // won't hurt anything.)
+ aSignificand |= implicitBit;
+ bSignificand |= implicitBit;
+ int quotientExponent = aExponent - bExponent + scale;
+
+ // Align the significand of b as a Q31 fixed-point number in the range
+ // [1, 2.0) and get a Q32 approximate reciprocal using a small minimax
+ // polynomial approximation: reciprocal = 3/4 + 1/sqrt(2) - b/2. This
+ // is accurate to about 3.5 binary digits.
+ uint32_t q31b = bSignificand << 8;
+ uint32_t reciprocal = UINT32_C(0x7504f333) - q31b;
+
+ // Now refine the reciprocal estimate using a Newton-Raphson iteration:
+ //
+ // x1 = x0 * (2 - x0 * b)
+ //
+ // This doubles the number of correct binary digits in the approximation
+ // with each iteration, so after three iterations, we have about 28 binary
+ // digits of accuracy.
+ uint32_t correction;
+ correction = -((uint64_t)reciprocal * q31b >> 32);
+ reciprocal = (uint64_t)reciprocal * correction >> 31;
+ correction = -((uint64_t)reciprocal * q31b >> 32);
+ reciprocal = (uint64_t)reciprocal * correction >> 31;
+ correction = -((uint64_t)reciprocal * q31b >> 32);
+ reciprocal = (uint64_t)reciprocal * correction >> 31;
+
+ // Exhaustive testing shows that the error in reciprocal after three steps
+ // is in the interval [-0x1.f58108p-31, 0x1.d0e48cp-29], in line with our
+ // expectations. We bump the reciprocal by a tiny value to force the error
+ // to be strictly positive (in the range [0x1.4fdfp-37,0x1.287246p-29], to
+ // be specific). This also causes 1/1 to give a sensible approximation
+ // instead of zero (due to overflow).
+ reciprocal -= 2;
+
+ // The numerical reciprocal is accurate to within 2^-28, lies in the
+ // interval [0x1.000000eep-1, 0x1.fffffffcp-1], and is strictly smaller
+ // than the true reciprocal of b. Multiplying a by this reciprocal thus
+ // gives a numerical q = a/b in Q24 with the following properties:
+ //
+ // 1. q < a/b
+ // 2. q is in the interval [0x1.000000eep-1, 0x1.fffffffcp0)
+ // 3. the error in q is at most 2^-24 + 2^-27 -- the 2^24 term comes
+ // from the fact that we truncate the product, and the 2^27 term
+ // is the error in the reciprocal of b scaled by the maximum
+ // possible value of a. As a consequence of this error bound,
+ // either q or nextafter(q) is the correctly rounded
+ rep_t quotient = (uint64_t)reciprocal*(aSignificand << 1) >> 32;
+
+ // Two cases: quotient is in [0.5, 1.0) or quotient is in [1.0, 2.0).
+ // In either case, we are going to compute a residual of the form
+ //
+ // r = a - q*b
+ //
+ // We know from the construction of q that r satisfies:
+ //
+ // 0 <= r < ulp(q)*b
+ //
+ // if r is greater than 1/2 ulp(q)*b, then q rounds up. Otherwise, we
+ // already have the correct result. The exact halfway case cannot occur.
+ // We also take this time to right shift quotient if it falls in the [1,2)
+ // range and adjust the exponent accordingly.
+ rep_t residual;
+ if (quotient < (implicitBit << 1)) {
+ residual = (aSignificand << 24) - quotient * bSignificand;
+ quotientExponent--;
+ } else {
+ quotient >>= 1;
+ residual = (aSignificand << 23) - quotient * bSignificand;
+ }
+
+ const int writtenExponent = quotientExponent + exponentBias;
+
+ if (writtenExponent >= maxExponent) {
+ // If we have overflowed the exponent, return infinity.
+ return fromRep(infRep | quotientSign);
+ }
+
+ else if (writtenExponent < 1) {
+ // Flush denormals to zero. In the future, it would be nice to add
+ // code to round them correctly.
+ return fromRep(quotientSign);
+ }
+
+ else {
+ const bool round = (residual << 1) > bSignificand;
+ // Clear the implicit bit
+ rep_t absResult = quotient & significandMask;
+ // Insert the exponent
+ absResult |= (rep_t)writtenExponent << significandBits;
+ // Round
+ absResult += round;
+ // Insert the sign and return
+ return fromRep(absResult | quotientSign);
+ }
+}
diff --git a/lib/builtins/divsi3.c b/lib/builtins/divsi3.c
new file mode 100644
index 000000000000..bab4aefda30a
--- /dev/null
+++ b/lib/builtins/divsi3.c
@@ -0,0 +1,37 @@
+/* ===-- divsi3.c - Implement __divsi3 -------------------------------------===
+ *
+ * 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 __divsi3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: a / b */
+
+ARM_EABI_FNALIAS(idiv, divsi3)
+
+COMPILER_RT_ABI si_int
+__divsi3(si_int a, si_int b)
+{
+ const int bits_in_word_m1 = (int)(sizeof(si_int) * CHAR_BIT) - 1;
+ si_int s_a = a >> bits_in_word_m1; /* s_a = a < 0 ? -1 : 0 */
+ si_int s_b = b >> bits_in_word_m1; /* s_b = b < 0 ? -1 : 0 */
+ a = (a ^ s_a) - s_a; /* negate if s_a == -1 */
+ b = (b ^ s_b) - s_b; /* negate if s_b == -1 */
+ s_a ^= s_b; /* sign of quotient */
+ /*
+ * On CPUs without unsigned hardware division support,
+ * this calls __udivsi3 (notice the cast to su_int).
+ * On CPUs with unsigned hardware division support,
+ * this uses the unsigned division instruction.
+ */
+ return ((su_int)a/(su_int)b ^ s_a) - s_a; /* negate if s_a == -1 */
+}
diff --git a/lib/builtins/divtf3.c b/lib/builtins/divtf3.c
new file mode 100644
index 000000000000..e81dab826bdd
--- /dev/null
+++ b/lib/builtins/divtf3.c
@@ -0,0 +1,203 @@
+//===-- lib/divtf3.c - Quad-precision division --------------------*- 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 quad-precision soft-float division
+// with the IEEE-754 default rounding (to nearest, ties to even).
+//
+// For simplicity, this implementation currently flushes denormals to zero.
+// It should be a fairly straightforward exercise to implement gradual
+// underflow with correct rounding.
+//
+//===----------------------------------------------------------------------===//
+
+#define QUAD_PRECISION
+#include "fp_lib.h"
+
+#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
+COMPILER_RT_ABI fp_t __divtf3(fp_t a, fp_t b) {
+
+ const unsigned int aExponent = toRep(a) >> significandBits & maxExponent;
+ const unsigned int bExponent = toRep(b) >> significandBits & maxExponent;
+ const rep_t quotientSign = (toRep(a) ^ toRep(b)) & signBit;
+
+ rep_t aSignificand = toRep(a) & significandMask;
+ rep_t bSignificand = toRep(b) & significandMask;
+ int scale = 0;
+
+ // Detect if a or b is zero, denormal, infinity, or NaN.
+ if (aExponent-1U >= maxExponent-1U || bExponent-1U >= maxExponent-1U) {
+
+ const rep_t aAbs = toRep(a) & absMask;
+ const rep_t bAbs = toRep(b) & absMask;
+
+ // NaN / anything = qNaN
+ if (aAbs > infRep) return fromRep(toRep(a) | quietBit);
+ // anything / NaN = qNaN
+ if (bAbs > infRep) return fromRep(toRep(b) | quietBit);
+
+ if (aAbs == infRep) {
+ // infinity / infinity = NaN
+ if (bAbs == infRep) return fromRep(qnanRep);
+ // infinity / anything else = +/- infinity
+ else return fromRep(aAbs | quotientSign);
+ }
+
+ // anything else / infinity = +/- 0
+ if (bAbs == infRep) return fromRep(quotientSign);
+
+ if (!aAbs) {
+ // zero / zero = NaN
+ if (!bAbs) return fromRep(qnanRep);
+ // zero / anything else = +/- zero
+ else return fromRep(quotientSign);
+ }
+ // anything else / zero = +/- infinity
+ if (!bAbs) return fromRep(infRep | quotientSign);
+
+ // one or both of a or b is denormal, the other (if applicable) is a
+ // normal number. Renormalize one or both of a and b, and set scale to
+ // include the necessary exponent adjustment.
+ if (aAbs < implicitBit) scale += normalize(&aSignificand);
+ if (bAbs < implicitBit) scale -= normalize(&bSignificand);
+ }
+
+ // Or in the implicit significand bit. (If we fell through from the
+ // denormal path it was already set by normalize( ), but setting it twice
+ // won't hurt anything.)
+ aSignificand |= implicitBit;
+ bSignificand |= implicitBit;
+ int quotientExponent = aExponent - bExponent + scale;
+
+ // Align the significand of b as a Q63 fixed-point number in the range
+ // [1, 2.0) and get a Q64 approximate reciprocal using a small minimax
+ // polynomial approximation: reciprocal = 3/4 + 1/sqrt(2) - b/2. This
+ // is accurate to about 3.5 binary digits.
+ const uint64_t q63b = bSignificand >> 49;
+ uint64_t recip64 = UINT64_C(0x7504f333F9DE6484) - q63b;
+ // 0x7504f333F9DE6484 / 2^64 + 1 = 3/4 + 1/sqrt(2)
+
+ // Now refine the reciprocal estimate using a Newton-Raphson iteration:
+ //
+ // x1 = x0 * (2 - x0 * b)
+ //
+ // This doubles the number of correct binary digits in the approximation
+ // with each iteration.
+ uint64_t correction64;
+ correction64 = -((rep_t)recip64 * q63b >> 64);
+ recip64 = (rep_t)recip64 * correction64 >> 63;
+ correction64 = -((rep_t)recip64 * q63b >> 64);
+ recip64 = (rep_t)recip64 * correction64 >> 63;
+ correction64 = -((rep_t)recip64 * q63b >> 64);
+ recip64 = (rep_t)recip64 * correction64 >> 63;
+ correction64 = -((rep_t)recip64 * q63b >> 64);
+ recip64 = (rep_t)recip64 * correction64 >> 63;
+ correction64 = -((rep_t)recip64 * q63b >> 64);
+ recip64 = (rep_t)recip64 * correction64 >> 63;
+
+ // recip64 might have overflowed to exactly zero in the preceeding
+ // computation if the high word of b is exactly 1.0. This would sabotage
+ // the full-width final stage of the computation that follows, so we adjust
+ // recip64 downward by one bit.
+ recip64--;
+
+ // We need to perform one more iteration to get us to 112 binary digits;
+ // The last iteration needs to happen with extra precision.
+ const uint64_t q127blo = bSignificand << 15;
+ rep_t correction, reciprocal;
+
+ // NOTE: This operation is equivalent to __multi3, which is not implemented
+ // in some architechure
+ rep_t r64q63, r64q127, r64cH, r64cL, dummy;
+ wideMultiply((rep_t)recip64, (rep_t)q63b, &dummy, &r64q63);
+ wideMultiply((rep_t)recip64, (rep_t)q127blo, &dummy, &r64q127);
+
+ correction = -(r64q63 + (r64q127 >> 64));
+
+ uint64_t cHi = correction >> 64;
+ uint64_t cLo = correction;
+
+ wideMultiply((rep_t)recip64, (rep_t)cHi, &dummy, &r64cH);
+ wideMultiply((rep_t)recip64, (rep_t)cLo, &dummy, &r64cL);
+
+ reciprocal = r64cH + (r64cL >> 64);
+
+ // We already adjusted the 64-bit estimate, now we need to adjust the final
+ // 128-bit reciprocal estimate downward to ensure that it is strictly smaller
+ // than the infinitely precise exact reciprocal. Because the computation
+ // of the Newton-Raphson step is truncating at every step, this adjustment
+ // is small; most of the work is already done.
+ reciprocal -= 2;
+
+ // The numerical reciprocal is accurate to within 2^-112, lies in the
+ // interval [0.5, 1.0), and is strictly smaller than the true reciprocal
+ // of b. Multiplying a by this reciprocal thus gives a numerical q = a/b
+ // in Q127 with the following properties:
+ //
+ // 1. q < a/b
+ // 2. q is in the interval [0.5, 2.0)
+ // 3. the error in q is bounded away from 2^-113 (actually, we have a
+ // couple of bits to spare, but this is all we need).
+
+ // We need a 128 x 128 multiply high to compute q, which isn't a basic
+ // operation in C, so we need to be a little bit fussy.
+ rep_t quotient, quotientLo;
+ wideMultiply(aSignificand << 2, reciprocal, &quotient, &quotientLo);
+
+ // Two cases: quotient is in [0.5, 1.0) or quotient is in [1.0, 2.0).
+ // In either case, we are going to compute a residual of the form
+ //
+ // r = a - q*b
+ //
+ // We know from the construction of q that r satisfies:
+ //
+ // 0 <= r < ulp(q)*b
+ //
+ // if r is greater than 1/2 ulp(q)*b, then q rounds up. Otherwise, we
+ // already have the correct result. The exact halfway case cannot occur.
+ // We also take this time to right shift quotient if it falls in the [1,2)
+ // range and adjust the exponent accordingly.
+ rep_t residual;
+ rep_t qb;
+
+ if (quotient < (implicitBit << 1)) {
+ wideMultiply(quotient, bSignificand, &dummy, &qb);
+ residual = (aSignificand << 113) - qb;
+ quotientExponent--;
+ } else {
+ quotient >>= 1;
+ wideMultiply(quotient, bSignificand, &dummy, &qb);
+ residual = (aSignificand << 112) - qb;
+ }
+
+ const int writtenExponent = quotientExponent + exponentBias;
+
+ if (writtenExponent >= maxExponent) {
+ // If we have overflowed the exponent, return infinity.
+ return fromRep(infRep | quotientSign);
+ }
+ else if (writtenExponent < 1) {
+ // Flush denormals to zero. In the future, it would be nice to add
+ // code to round them correctly.
+ return fromRep(quotientSign);
+ }
+ else {
+ const bool round = (residual << 1) >= bSignificand;
+ // Clear the implicit bit
+ rep_t absResult = quotient & significandMask;
+ // Insert the exponent
+ absResult |= (rep_t)writtenExponent << significandBits;
+ // Round
+ absResult += round;
+ // Insert the sign and return
+ const long double result = fromRep(absResult | quotientSign);
+ return result;
+ }
+}
+
+#endif
diff --git a/lib/builtins/divti3.c b/lib/builtins/divti3.c
new file mode 100644
index 000000000000..c73eae28fe08
--- /dev/null
+++ b/lib/builtins/divti3.c
@@ -0,0 +1,33 @@
+/* ===-- divti3.c - Implement __divti3 -------------------------------------===
+ *
+ * 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 __divti3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+/* Returns: a / b */
+
+COMPILER_RT_ABI ti_int
+__divti3(ti_int a, ti_int b)
+{
+ const int bits_in_tword_m1 = (int)(sizeof(ti_int) * CHAR_BIT) - 1;
+ ti_int s_a = a >> bits_in_tword_m1; /* s_a = a < 0 ? -1 : 0 */
+ ti_int s_b = b >> bits_in_tword_m1; /* s_b = b < 0 ? -1 : 0 */
+ a = (a ^ s_a) - s_a; /* negate if s_a == -1 */
+ b = (b ^ s_b) - s_b; /* negate if s_b == -1 */
+ s_a ^= s_b; /* sign of quotient */
+ return (__udivmodti4(a, b, (tu_int*)0) ^ s_a) - s_a; /* negate if s_a == -1 */
+}
+
+#endif /* CRT_HAS_128BIT */
diff --git a/lib/builtins/divxc3.c b/lib/builtins/divxc3.c
new file mode 100644
index 000000000000..175ae3cf4aee
--- /dev/null
+++ b/lib/builtins/divxc3.c
@@ -0,0 +1,63 @@
+/* ===-- divxc3.c - Implement __divxc3 -------------------------------------===
+ *
+ * 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 __divxc3 for the compiler_rt library.
+ *
+ */
+
+#if !_ARCH_PPC
+
+#include "int_lib.h"
+#include "int_math.h"
+
+/* Returns: the quotient of (a + ib) / (c + id) */
+
+COMPILER_RT_ABI long double _Complex
+__divxc3(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) && (!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, __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);
+ }
+ 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);
+ }
+ }
+ return z;
+}
+
+#endif
diff --git a/lib/builtins/enable_execute_stack.c b/lib/builtins/enable_execute_stack.c
new file mode 100644
index 000000000000..63d836b31d17
--- /dev/null
+++ b/lib/builtins/enable_execute_stack.c
@@ -0,0 +1,58 @@
+/* ===-- enable_execute_stack.c - Implement __enable_execute_stack ---------===
+ *
+ * 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 "int_lib.h"
+
+#include <sys/mman.h>
+
+/* #include "config.h"
+ * FIXME: CMake - include when cmake system is ready.
+ * Remove #define HAVE_SYSCONF 1 line.
+ */
+#define HAVE_SYSCONF 1
+
+#ifndef __APPLE__
+#include <unistd.h>
+#endif /* __APPLE__ */
+
+#if __LP64__
+ #define TRAMPOLINE_SIZE 48
+#else
+ #define TRAMPOLINE_SIZE 40
+#endif
+
+/*
+ * The compiler generates calls to __enable_execute_stack() when creating
+ * trampoline functions on the stack for use with nested functions.
+ * It is expected to mark the page(s) containing the address
+ * and the next 48 bytes as executable. Since the stack is normally rw-
+ * that means changing the protection on those page(s) to rwx.
+ */
+
+COMPILER_RT_ABI void
+__enable_execute_stack(void* addr)
+{
+
+#if __APPLE__
+ /* On Darwin, pagesize is always 4096 bytes */
+ const uintptr_t pageSize = 4096;
+#elif !defined(HAVE_SYSCONF)
+#error "HAVE_SYSCONF not defined! See enable_execute_stack.c"
+#else
+ const uintptr_t pageSize = sysconf(_SC_PAGESIZE);
+#endif /* __APPLE__ */
+
+ const uintptr_t pageAlignMask = ~(pageSize-1);
+ uintptr_t p = (uintptr_t)addr;
+ unsigned char* startPage = (unsigned char*)(p & pageAlignMask);
+ unsigned char* endPage = (unsigned char*)((p+TRAMPOLINE_SIZE+pageSize) & pageAlignMask);
+ size_t length = endPage - startPage;
+ (void) mprotect((void *)startPage, length, PROT_READ | PROT_WRITE | PROT_EXEC);
+}
diff --git a/lib/builtins/eprintf.c b/lib/builtins/eprintf.c
new file mode 100644
index 000000000000..89f34b154577
--- /dev/null
+++ b/lib/builtins/eprintf.c
@@ -0,0 +1,35 @@
+/* ===---------- eprintf.c - Implements __eprintf --------------------------===
+ *
+ * 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 "int_lib.h"
+#include <stdio.h>
+
+
+/*
+ * __eprintf() was used in an old version of <assert.h>.
+ * It can eventually go away, but it is needed when linking
+ * .o files built with the old <assert.h>.
+ *
+ * It should never be exported from a dylib, so it is marked
+ * visibility hidden.
+ */
+#ifndef _WIN32
+__attribute__((visibility("hidden")))
+#endif
+COMPILER_RT_ABI void
+__eprintf(const char* format, const char* assertion_expression,
+ const char* line, const char* file)
+{
+ fprintf(stderr, format, assertion_expression, line, file);
+ fflush(stderr);
+ compilerrt_abort();
+}
diff --git a/lib/builtins/extenddftf2.c b/lib/builtins/extenddftf2.c
new file mode 100644
index 000000000000..86dab8f03a8f
--- /dev/null
+++ b/lib/builtins/extenddftf2.c
@@ -0,0 +1,23 @@
+//===-- lib/extenddftf2.c - double -> quad 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.
+//
+//===----------------------------------------------------------------------===//
+//
+
+#define QUAD_PRECISION
+#include "fp_lib.h"
+
+#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
+#define SRC_DOUBLE
+#define DST_QUAD
+#include "fp_extend_impl.inc"
+
+COMPILER_RT_ABI long double __extenddftf2(double a) {
+ return __extendXfYf2__(a);
+}
+
+#endif
diff --git a/lib/builtins/extendsfdf2.c b/lib/builtins/extendsfdf2.c
new file mode 100644
index 000000000000..7a267c2f47ad
--- /dev/null
+++ b/lib/builtins/extendsfdf2.c
@@ -0,0 +1,19 @@
+//===-- lib/extendsfdf2.c - single -> double 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.
+//
+//===----------------------------------------------------------------------===//
+//
+
+#define SRC_SINGLE
+#define DST_DOUBLE
+#include "fp_extend_impl.inc"
+
+ARM_EABI_FNALIAS(f2d, extendsfdf2)
+
+COMPILER_RT_ABI double __extendsfdf2(float a) {
+ return __extendXfYf2__(a);
+}
diff --git a/lib/builtins/extendsftf2.c b/lib/builtins/extendsftf2.c
new file mode 100644
index 000000000000..2eeeba284845
--- /dev/null
+++ b/lib/builtins/extendsftf2.c
@@ -0,0 +1,23 @@
+//===-- lib/extendsftf2.c - single -> quad 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.
+//
+//===----------------------------------------------------------------------===//
+//
+
+#define QUAD_PRECISION
+#include "fp_lib.h"
+
+#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
+#define SRC_SINGLE
+#define DST_QUAD
+#include "fp_extend_impl.inc"
+
+COMPILER_RT_ABI long double __extendsftf2(float a) {
+ return __extendXfYf2__(a);
+}
+
+#endif
diff --git a/lib/ffsdi2.c b/lib/builtins/ffsdi2.c
index a5ac9900ff10..a5ac9900ff10 100644
--- a/lib/ffsdi2.c
+++ b/lib/builtins/ffsdi2.c
diff --git a/lib/builtins/ffsti2.c b/lib/builtins/ffsti2.c
new file mode 100644
index 000000000000..dcdb3bd7f807
--- /dev/null
+++ b/lib/builtins/ffsti2.c
@@ -0,0 +1,37 @@
+/* ===-- ffsti2.c - Implement __ffsti2 -------------------------------------===
+ *
+ * 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 __ffsti2 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+/* Returns: the index of the least significant 1-bit in a, or
+ * the value zero if a is zero. The least significant bit is index one.
+ */
+
+COMPILER_RT_ABI si_int
+__ffsti2(ti_int a)
+{
+ twords x;
+ x.all = a;
+ if (x.s.low == 0)
+ {
+ if (x.s.high == 0)
+ return 0;
+ return __builtin_ctzll(x.s.high) + (1 + sizeof(di_int) * CHAR_BIT);
+ }
+ return __builtin_ctzll(x.s.low) + 1;
+}
+
+#endif /* CRT_HAS_128BIT */
diff --git a/lib/builtins/fixdfdi.c b/lib/builtins/fixdfdi.c
new file mode 100644
index 000000000000..86f9f6ce8db3
--- /dev/null
+++ b/lib/builtins/fixdfdi.c
@@ -0,0 +1,45 @@
+/* ===-- fixdfdi.c - Implement __fixdfdi -----------------------------------===
+ *
+ * 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 __fixdfdi for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: convert a to a signed long long, rounding toward zero. */
+
+/* Assumption: double is a IEEE 64 bit floating point type
+ * su_int is a 32 bit integral type
+ * value in double is representable in di_int (no range checking performed)
+ */
+
+/* seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm */
+
+ARM_EABI_FNALIAS(d2lz, fixdfdi)
+
+COMPILER_RT_ABI di_int
+__fixdfdi(double a)
+{
+ double_bits fb;
+ fb.f = a;
+ int e = ((fb.u.s.high & 0x7FF00000) >> 20) - 1023;
+ if (e < 0)
+ return 0;
+ di_int s = (si_int)(fb.u.s.high & 0x80000000) >> 31;
+ dwords r;
+ r.s.high = (fb.u.s.high & 0x000FFFFF) | 0x00100000;
+ r.s.low = fb.u.s.low;
+ if (e > 52)
+ r.all <<= (e - 52);
+ else
+ r.all >>= (52 - e);
+ return (r.all ^ s) - s;
+}
diff --git a/lib/builtins/fixdfsi.c b/lib/builtins/fixdfsi.c
new file mode 100644
index 000000000000..88b2ff5e74a0
--- /dev/null
+++ b/lib/builtins/fixdfsi.c
@@ -0,0 +1,50 @@
+//===-- lib/fixdfsi.c - Double-precision -> integer 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 double-precision to integer conversion for the
+// compiler-rt library. No range checking is performed; the behavior of this
+// conversion is undefined for out of range values in the C standard.
+//
+//===----------------------------------------------------------------------===//
+
+#define DOUBLE_PRECISION
+#include "fp_lib.h"
+
+#include "int_lib.h"
+
+ARM_EABI_FNALIAS(d2iz, fixdfsi)
+
+COMPILER_RT_ABI int
+__fixdfsi(fp_t a) {
+
+ // Break a into sign, exponent, significand
+ const rep_t aRep = toRep(a);
+ const rep_t aAbs = aRep & absMask;
+ const int sign = aRep & signBit ? -1 : 1;
+ const int exponent = (aAbs >> significandBits) - exponentBias;
+ const rep_t significand = (aAbs & significandMask) | implicitBit;
+
+ // If 0 < exponent < significandBits, right shift to get the result.
+ if ((unsigned int)exponent < significandBits) {
+ return sign * (significand >> (significandBits - exponent));
+ }
+
+ // If exponent is negative, the result is zero.
+ else if (exponent < 0) {
+ return 0;
+ }
+
+ // If significandBits < exponent, left shift to get the result. This shift
+ // may end up being larger than the type width, which incurs undefined
+ // behavior, but the conversion itself is undefined in that case, so
+ // whatever the compiler decides to do is fine.
+ else {
+ return sign * (significand << (exponent - significandBits));
+ }
+}
diff --git a/lib/builtins/fixdfti.c b/lib/builtins/fixdfti.c
new file mode 100644
index 000000000000..2c27f4bae3b9
--- /dev/null
+++ b/lib/builtins/fixdfti.c
@@ -0,0 +1,45 @@
+/* ===-- fixdfti.c - Implement __fixdfti -----------------------------------===
+ *
+ * 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 __fixdfti for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+/* Returns: convert a to a signed long long, rounding toward zero. */
+
+/* Assumption: double is a IEEE 64 bit floating point type
+ * su_int is a 32 bit integral type
+ * value in double is representable in ti_int (no range checking performed)
+ */
+
+/* seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm */
+
+COMPILER_RT_ABI ti_int
+__fixdfti(double a)
+{
+ double_bits fb;
+ fb.f = a;
+ int e = ((fb.u.s.high & 0x7FF00000) >> 20) - 1023;
+ if (e < 0)
+ return 0;
+ ti_int s = (si_int)(fb.u.s.high & 0x80000000) >> 31;
+ ti_int r = 0x0010000000000000uLL | (0x000FFFFFFFFFFFFFuLL & fb.u.all);
+ if (e > 52)
+ r <<= (e - 52);
+ else
+ r >>= (52 - e);
+ return (r ^ s) - s;
+}
+
+#endif /* CRT_HAS_128BIT */
diff --git a/lib/fixsfdi.c b/lib/builtins/fixsfdi.c
index 4f6cfdd7a5c6..4f6cfdd7a5c6 100644
--- a/lib/fixsfdi.c
+++ b/lib/builtins/fixsfdi.c
diff --git a/lib/fixsfsi.c b/lib/builtins/fixsfsi.c
index e3cc42d5255a..e3cc42d5255a 100644
--- a/lib/fixsfsi.c
+++ b/lib/builtins/fixsfsi.c
diff --git a/lib/builtins/fixsfti.c b/lib/builtins/fixsfti.c
new file mode 100644
index 000000000000..6a1a1c6d5465
--- /dev/null
+++ b/lib/builtins/fixsfti.c
@@ -0,0 +1,45 @@
+/* ===-- fixsfti.c - Implement __fixsfti -----------------------------------===
+ *
+ * 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 __fixsfti for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+/* Returns: convert a to a signed long long, rounding toward zero. */
+
+/* Assumption: float is a IEEE 32 bit floating point type
+ * su_int is a 32 bit integral type
+ * value in float is representable in ti_int (no range checking performed)
+ */
+
+/* seee eeee emmm mmmm mmmm mmmm mmmm mmmm */
+
+COMPILER_RT_ABI ti_int
+__fixsfti(float a)
+{
+ float_bits fb;
+ fb.f = a;
+ int e = ((fb.u & 0x7F800000) >> 23) - 127;
+ if (e < 0)
+ return 0;
+ ti_int s = (si_int)(fb.u & 0x80000000) >> 31;
+ ti_int r = (fb.u & 0x007FFFFF) | 0x00800000;
+ if (e > 23)
+ r <<= (e - 23);
+ else
+ r >>= (23 - e);
+ return (r ^ s) - s;
+}
+
+#endif /* CRT_HAS_128BIT */
diff --git a/lib/fixunsdfdi.c b/lib/builtins/fixunsdfdi.c
index 9e6371390d5c..9e6371390d5c 100644
--- a/lib/fixunsdfdi.c
+++ b/lib/builtins/fixunsdfdi.c
diff --git a/lib/fixunsdfsi.c b/lib/builtins/fixunsdfsi.c
index c6a3c755e90f..c6a3c755e90f 100644
--- a/lib/fixunsdfsi.c
+++ b/lib/builtins/fixunsdfsi.c
diff --git a/lib/builtins/fixunsdfti.c b/lib/builtins/fixunsdfti.c
new file mode 100644
index 000000000000..cc6c84ff5cb5
--- /dev/null
+++ b/lib/builtins/fixunsdfti.c
@@ -0,0 +1,47 @@
+/* ===-- fixunsdfti.c - Implement __fixunsdfti -----------------------------===
+ *
+ * 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 __fixunsdfti for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+/* Returns: convert a to a unsigned long long, rounding toward zero.
+ * Negative values all become zero.
+ */
+
+/* Assumption: double is a IEEE 64 bit floating point type
+ * tu_int is a 64 bit integral type
+ * value in double is representable in tu_int or is negative
+ * (no range checking performed)
+ */
+
+/* seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm */
+
+COMPILER_RT_ABI tu_int
+__fixunsdfti(double a)
+{
+ double_bits fb;
+ fb.f = a;
+ int e = ((fb.u.s.high & 0x7FF00000) >> 20) - 1023;
+ if (e < 0 || (fb.u.s.high & 0x80000000))
+ return 0;
+ tu_int r = 0x0010000000000000uLL | (fb.u.all & 0x000FFFFFFFFFFFFFuLL);
+ if (e > 52)
+ r <<= (e - 52);
+ else
+ r >>= (52 - e);
+ return r;
+}
+
+#endif /* CRT_HAS_128BIT */
diff --git a/lib/fixunssfdi.c b/lib/builtins/fixunssfdi.c
index 69d5952e9607..69d5952e9607 100644
--- a/lib/fixunssfdi.c
+++ b/lib/builtins/fixunssfdi.c
diff --git a/lib/fixunssfsi.c b/lib/builtins/fixunssfsi.c
index e034139ea277..e034139ea277 100644
--- a/lib/fixunssfsi.c
+++ b/lib/builtins/fixunssfsi.c
diff --git a/lib/builtins/fixunssfti.c b/lib/builtins/fixunssfti.c
new file mode 100644
index 000000000000..4da9e242ad05
--- /dev/null
+++ b/lib/builtins/fixunssfti.c
@@ -0,0 +1,47 @@
+/* ===-- fixunssfti.c - Implement __fixunssfti -----------------------------===
+ *
+ * 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 __fixunssfti for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+/* Returns: convert a to a unsigned long long, rounding toward zero.
+ * Negative values all become zero.
+ */
+
+/* Assumption: float is a IEEE 32 bit floating point type
+ * tu_int is a 64 bit integral type
+ * value in float is representable in tu_int or is negative
+ * (no range checking performed)
+ */
+
+/* seee eeee emmm mmmm mmmm mmmm mmmm mmmm */
+
+COMPILER_RT_ABI tu_int
+__fixunssfti(float a)
+{
+ float_bits fb;
+ fb.f = a;
+ int e = ((fb.u & 0x7F800000) >> 23) - 127;
+ if (e < 0 || (fb.u & 0x80000000))
+ return 0;
+ tu_int r = (fb.u & 0x007FFFFF) | 0x00800000;
+ if (e > 23)
+ r <<= (e - 23);
+ else
+ r >>= (23 - e);
+ return r;
+}
+
+#endif /* CRT_HAS_128BIT */
diff --git a/lib/builtins/fixunsxfdi.c b/lib/builtins/fixunsxfdi.c
new file mode 100644
index 000000000000..7224d467e7c9
--- /dev/null
+++ b/lib/builtins/fixunsxfdi.c
@@ -0,0 +1,44 @@
+/* ===-- fixunsxfdi.c - Implement __fixunsxfdi -----------------------------===
+ *
+ * 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 __fixunsxfdi for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#if !_ARCH_PPC
+
+#include "int_lib.h"
+
+/* Returns: convert a to a unsigned long long, rounding toward zero.
+ * Negative values all become zero.
+ */
+
+/* Assumption: long double is an intel 80 bit floating point type padded with 6 bytes
+ * du_int is a 64 bit integral type
+ * value in long double is representable in du_int or is negative
+ * (no range checking performed)
+ */
+
+/* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee |
+ * 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm
+ */
+
+COMPILER_RT_ABI du_int
+__fixunsxfdi(long double a)
+{
+ long_double_bits fb;
+ fb.f = a;
+ int e = (fb.u.high.s.low & 0x00007FFF) - 16383;
+ if (e < 0 || (fb.u.high.s.low & 0x00008000))
+ return 0;
+ return fb.u.low.all >> (63 - e);
+}
+
+#endif
diff --git a/lib/builtins/fixunsxfsi.c b/lib/builtins/fixunsxfsi.c
new file mode 100644
index 000000000000..df0a18e2c1ab
--- /dev/null
+++ b/lib/builtins/fixunsxfsi.c
@@ -0,0 +1,44 @@
+/* ===-- fixunsxfsi.c - Implement __fixunsxfsi -----------------------------===
+ *
+ * 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 __fixunsxfsi for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#if !_ARCH_PPC
+
+#include "int_lib.h"
+
+/* Returns: convert a to a unsigned int, rounding toward zero.
+ * Negative values all become zero.
+ */
+
+/* Assumption: long double is an intel 80 bit floating point type padded with 6 bytes
+ * su_int is a 32 bit integral type
+ * value in long double is representable in su_int or is negative
+ * (no range checking performed)
+ */
+
+/* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee |
+ * 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm
+ */
+
+COMPILER_RT_ABI su_int
+__fixunsxfsi(long double a)
+{
+ long_double_bits fb;
+ fb.f = a;
+ int e = (fb.u.high.s.low & 0x00007FFF) - 16383;
+ if (e < 0 || (fb.u.high.s.low & 0x00008000))
+ return 0;
+ return fb.u.low.s.high >> (31 - e);
+}
+
+#endif /* !_ARCH_PPC */
diff --git a/lib/builtins/fixunsxfti.c b/lib/builtins/fixunsxfti.c
new file mode 100644
index 000000000000..42e507304718
--- /dev/null
+++ b/lib/builtins/fixunsxfti.c
@@ -0,0 +1,49 @@
+/* ===-- fixunsxfti.c - Implement __fixunsxfti -----------------------------===
+ *
+ * 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 __fixunsxfti for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+/* Returns: convert a to a unsigned long long, rounding toward zero.
+ * Negative values all become zero.
+ */
+
+/* Assumption: long double is an intel 80 bit floating point type padded with 6 bytes
+ * tu_int is a 64 bit integral type
+ * value in long double is representable in tu_int or is negative
+ * (no range checking performed)
+ */
+
+/* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee |
+ * 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm
+ */
+
+COMPILER_RT_ABI tu_int
+__fixunsxfti(long double a)
+{
+ long_double_bits fb;
+ fb.f = a;
+ int e = (fb.u.high.s.low & 0x00007FFF) - 16383;
+ if (e < 0 || (fb.u.high.s.low & 0x00008000))
+ return 0;
+ tu_int r = fb.u.low.all;
+ if (e > 63)
+ r <<= (e - 63);
+ else
+ r >>= (63 - e);
+ return r;
+}
+
+#endif /* CRT_HAS_128BIT */
diff --git a/lib/builtins/fixxfdi.c b/lib/builtins/fixxfdi.c
new file mode 100644
index 000000000000..afc79d8664d8
--- /dev/null
+++ b/lib/builtins/fixxfdi.c
@@ -0,0 +1,44 @@
+/* ===-- fixxfdi.c - Implement __fixxfdi -----------------------------------===
+ *
+ * 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 __fixxfdi for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#if !_ARCH_PPC
+
+#include "int_lib.h"
+
+/* Returns: convert a to a signed long long, rounding toward zero. */
+
+/* Assumption: long double is an intel 80 bit floating point type padded with 6 bytes
+ * su_int is a 32 bit integral type
+ * value in long double is representable in di_int (no range checking performed)
+ */
+
+/* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee |
+ * 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm
+ */
+
+COMPILER_RT_ABI di_int
+__fixxfdi(long double a)
+{
+ long_double_bits fb;
+ fb.f = a;
+ int e = (fb.u.high.s.low & 0x00007FFF) - 16383;
+ if (e < 0)
+ return 0;
+ di_int s = -(si_int)((fb.u.high.s.low & 0x00008000) >> 15);
+ di_int r = fb.u.low.all;
+ r = (du_int)r >> (63 - e);
+ return (r ^ s) - s;
+}
+
+#endif /* !_ARCH_PPC */
diff --git a/lib/builtins/fixxfti.c b/lib/builtins/fixxfti.c
new file mode 100644
index 000000000000..3d0a279b3842
--- /dev/null
+++ b/lib/builtins/fixxfti.c
@@ -0,0 +1,47 @@
+/* ===-- fixxfti.c - Implement __fixxfti -----------------------------------===
+ *
+ * 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 __fixxfti for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+/* Returns: convert a to a signed long long, rounding toward zero. */
+
+/* Assumption: long double is an intel 80 bit floating point type padded with 6 bytes
+ * su_int is a 32 bit integral type
+ * value in long double is representable in ti_int (no range checking performed)
+ */
+
+/* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee |
+ * 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm
+ */
+
+COMPILER_RT_ABI ti_int
+__fixxfti(long double a)
+{
+ long_double_bits fb;
+ fb.f = a;
+ int e = (fb.u.high.s.low & 0x00007FFF) - 16383;
+ if (e < 0)
+ return 0;
+ ti_int s = -(si_int)((fb.u.high.s.low & 0x00008000) >> 15);
+ ti_int r = fb.u.low.all;
+ if (e > 63)
+ r <<= (e - 63);
+ else
+ r >>= (63 - e);
+ return (r ^ s) - s;
+}
+
+#endif /* CRT_HAS_128BIT */
diff --git a/lib/floatdidf.c b/lib/builtins/floatdidf.c
index e53fa2580f6e..e53fa2580f6e 100644
--- a/lib/floatdidf.c
+++ b/lib/builtins/floatdidf.c
diff --git a/lib/floatdisf.c b/lib/builtins/floatdisf.c
index 3e47580ef576..3e47580ef576 100644
--- a/lib/floatdisf.c
+++ b/lib/builtins/floatdisf.c
diff --git a/lib/builtins/floatdixf.c b/lib/builtins/floatdixf.c
new file mode 100644
index 000000000000..d39e81d7ca75
--- /dev/null
+++ b/lib/builtins/floatdixf.c
@@ -0,0 +1,46 @@
+/* ===-- floatdixf.c - Implement __floatdixf -------------------------------===
+ *
+ * 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 __floatdixf for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#if !_ARCH_PPC
+
+#include "int_lib.h"
+
+/* Returns: convert a to a long double, rounding toward even. */
+
+/* Assumption: long double is a IEEE 80 bit floating point type padded to 128 bits
+ * di_int is a 64 bit integral type
+ */
+
+/* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee |
+ * 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm
+ */
+
+COMPILER_RT_ABI long double
+__floatdixf(di_int a)
+{
+ if (a == 0)
+ return 0.0;
+ const unsigned N = sizeof(di_int) * CHAR_BIT;
+ const di_int s = a >> (N-1);
+ a = (a ^ s) - s;
+ int clz = __builtin_clzll(a);
+ int e = (N - 1) - clz ; /* exponent */
+ long_double_bits fb;
+ fb.u.high.s.low = ((su_int)s & 0x00008000) | /* sign */
+ (e + 16383); /* exponent */
+ fb.u.low.all = a << clz; /* mantissa */
+ return fb.f;
+}
+
+#endif /* !_ARCH_PPC */
diff --git a/lib/builtins/floatsidf.c b/lib/builtins/floatsidf.c
new file mode 100644
index 000000000000..1cf99b782a60
--- /dev/null
+++ b/lib/builtins/floatsidf.c
@@ -0,0 +1,53 @@
+//===-- lib/floatsidf.c - integer -> double-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 integer to double-precision conversion for the
+// compiler-rt library in the IEEE-754 default round-to-nearest, ties-to-even
+// mode.
+//
+//===----------------------------------------------------------------------===//
+
+#define DOUBLE_PRECISION
+#include "fp_lib.h"
+
+#include "int_lib.h"
+
+ARM_EABI_FNALIAS(i2d, floatsidf)
+
+COMPILER_RT_ABI fp_t
+__floatsidf(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;
+ if (a < 0) {
+ sign = signBit;
+ a = -a;
+ }
+
+ // Exponent of (fp_t)a is the width of abs(a).
+ const int exponent = (aWidth - 1) - __builtin_clz(a);
+ 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.
+ const int shift = significandBits - exponent;
+ result = (rep_t)(unsigned int)a << shift ^ implicitBit;
+
+ // Insert the exponent
+ result += (rep_t)(exponent + exponentBias) << significandBits;
+ // Insert the sign bit and return
+ return fromRep(result | sign);
+}
diff --git a/lib/builtins/floatsisf.c b/lib/builtins/floatsisf.c
new file mode 100644
index 000000000000..467dd1d1eaf1
--- /dev/null
+++ b/lib/builtins/floatsisf.c
@@ -0,0 +1,59 @@
+//===-- lib/floatsisf.c - integer -> single-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 integer to single-precision conversion for the
+// compiler-rt library in the IEEE-754 default round-to-nearest, ties-to-even
+// mode.
+//
+//===----------------------------------------------------------------------===//
+
+#define SINGLE_PRECISION
+#include "fp_lib.h"
+
+#include "int_lib.h"
+
+ARM_EABI_FNALIAS(i2f, floatsisf)
+
+COMPILER_RT_ABI fp_t
+__floatsisf(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;
+ if (a < 0) {
+ sign = signBit;
+ a = -a;
+ }
+
+ // Exponent of (fp_t)a is the width of abs(a).
+ const int exponent = (aWidth - 1) - __builtin_clz(a);
+ rep_t result;
+
+ // Shift a into the significand field, rounding if it is a right-shift
+ if (exponent <= significandBits) {
+ const int shift = significandBits - exponent;
+ result = (rep_t)a << shift ^ implicitBit;
+ } else {
+ const int shift = exponent - significandBits;
+ result = (rep_t)a >> shift ^ implicitBit;
+ rep_t round = (rep_t)a << (typeWidth - shift);
+ if (round > signBit) result++;
+ if (round == signBit) result += result & 1;
+ }
+
+ // Insert the exponent
+ result += (rep_t)(exponent + exponentBias) << significandBits;
+ // Insert the sign bit and return
+ return fromRep(result | sign);
+}
diff --git a/lib/builtins/floatsitf.c b/lib/builtins/floatsitf.c
new file mode 100644
index 000000000000..85346933f81e
--- /dev/null
+++ b/lib/builtins/floatsitf.c
@@ -0,0 +1,52 @@
+//===-- lib/floatsitf.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 integer 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 __floatsitf(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;
+ unsigned aAbs = (unsigned)a;
+ if (a < 0) {
+ sign = signBit;
+ aAbs += 0x80000000;
+ }
+
+ // Exponent of (fp_t)a is the width of abs(a).
+ const int exponent = (aWidth - 1) - __builtin_clz(a);
+ 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.
+ 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/floattidf.c b/lib/builtins/floattidf.c
new file mode 100644
index 000000000000..6331ba57376f
--- /dev/null
+++ b/lib/builtins/floattidf.c
@@ -0,0 +1,83 @@
+/* ===-- floattidf.c - Implement __floattidf -------------------------------===
+ *
+ * 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 __floattidf for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+/* Returns: convert a to a double, rounding toward even.*/
+
+/* Assumption: double is a IEEE 64 bit floating point type
+ * ti_int is a 128 bit integral type
+ */
+
+/* seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm */
+
+COMPILER_RT_ABI double
+__floattidf(ti_int a)
+{
+ if (a == 0)
+ return 0.0;
+ const unsigned N = sizeof(ti_int) * CHAR_BIT;
+ const ti_int s = a >> (N-1);
+ a = (a ^ s) - s;
+ int sd = N - __clzti2(a); /* number of significant digits */
+ int e = sd - 1; /* exponent */
+ if (sd > DBL_MANT_DIG)
+ {
+ /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
+ * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
+ * 12345678901234567890123456
+ * 1 = msb 1 bit
+ * P = bit DBL_MANT_DIG-1 bits to the right of 1
+ * Q = bit DBL_MANT_DIG bits to the right of 1
+ * R = "or" of all bits to the right of Q
+ */
+ switch (sd)
+ {
+ case DBL_MANT_DIG + 1:
+ a <<= 1;
+ break;
+ case DBL_MANT_DIG + 2:
+ break;
+ default:
+ a = ((tu_int)a >> (sd - (DBL_MANT_DIG+2))) |
+ ((a & ((tu_int)(-1) >> ((N + DBL_MANT_DIG+2) - sd))) != 0);
+ };
+ /* finish: */
+ a |= (a & 4) != 0; /* Or P into R */
+ ++a; /* round - this step may add a significant bit */
+ a >>= 2; /* dump Q and R */
+ /* a is now rounded to DBL_MANT_DIG or DBL_MANT_DIG+1 bits */
+ if (a & ((tu_int)1 << DBL_MANT_DIG))
+ {
+ a >>= 1;
+ ++e;
+ }
+ /* a is now rounded to DBL_MANT_DIG bits */
+ }
+ else
+ {
+ a <<= (DBL_MANT_DIG - sd);
+ /* a is now rounded to DBL_MANT_DIG bits */
+ }
+ double_bits fb;
+ fb.u.s.high = ((su_int)s & 0x80000000) | /* sign */
+ ((e + 1023) << 20) | /* exponent */
+ ((su_int)(a >> 32) & 0x000FFFFF); /* mantissa-high */
+ fb.u.s.low = (su_int)a; /* mantissa-low */
+ return fb.f;
+}
+
+#endif /* CRT_HAS_128BIT */
diff --git a/lib/builtins/floattisf.c b/lib/builtins/floattisf.c
new file mode 100644
index 000000000000..f1b585f2c326
--- /dev/null
+++ b/lib/builtins/floattisf.c
@@ -0,0 +1,82 @@
+/* ===-- floattisf.c - Implement __floattisf -------------------------------===
+ *
+ * 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 __floattisf for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+/* Returns: convert a to a float, rounding toward even. */
+
+/* Assumption: float is a IEEE 32 bit floating point type
+ * ti_int is a 128 bit integral type
+ */
+
+/* seee eeee emmm mmmm mmmm mmmm mmmm mmmm */
+
+COMPILER_RT_ABI float
+__floattisf(ti_int a)
+{
+ if (a == 0)
+ return 0.0F;
+ const unsigned N = sizeof(ti_int) * CHAR_BIT;
+ const ti_int s = a >> (N-1);
+ a = (a ^ s) - s;
+ int sd = N - __clzti2(a); /* number of significant digits */
+ int e = sd - 1; /* exponent */
+ if (sd > FLT_MANT_DIG)
+ {
+ /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
+ * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
+ * 12345678901234567890123456
+ * 1 = msb 1 bit
+ * P = bit FLT_MANT_DIG-1 bits to the right of 1
+ * Q = bit FLT_MANT_DIG bits to the right of 1
+ * R = "or" of all bits to the right of Q
+ */
+ switch (sd)
+ {
+ case FLT_MANT_DIG + 1:
+ a <<= 1;
+ break;
+ case FLT_MANT_DIG + 2:
+ break;
+ default:
+ a = ((tu_int)a >> (sd - (FLT_MANT_DIG+2))) |
+ ((a & ((tu_int)(-1) >> ((N + FLT_MANT_DIG+2) - sd))) != 0);
+ };
+ /* finish: */
+ a |= (a & 4) != 0; /* Or P into R */
+ ++a; /* round - this step may add a significant bit */
+ a >>= 2; /* dump Q and R */
+ /* a is now rounded to FLT_MANT_DIG or FLT_MANT_DIG+1 bits */
+ if (a & ((tu_int)1 << FLT_MANT_DIG))
+ {
+ a >>= 1;
+ ++e;
+ }
+ /* a is now rounded to FLT_MANT_DIG bits */
+ }
+ else
+ {
+ a <<= (FLT_MANT_DIG - sd);
+ /* a is now rounded to FLT_MANT_DIG bits */
+ }
+ float_bits fb;
+ fb.u = ((su_int)s & 0x80000000) | /* sign */
+ ((e + 127) << 23) | /* exponent */
+ ((su_int)a & 0x007FFFFF); /* mantissa */
+ return fb.f;
+}
+
+#endif /* CRT_HAS_128BIT */
diff --git a/lib/builtins/floattixf.c b/lib/builtins/floattixf.c
new file mode 100644
index 000000000000..1203b3a96e75
--- /dev/null
+++ b/lib/builtins/floattixf.c
@@ -0,0 +1,84 @@
+/* ===-- floattixf.c - Implement __floattixf -------------------------------===
+ *
+ * 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 __floattixf for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+/* Returns: convert a to a long double, rounding toward even. */
+
+/* Assumption: long double is a IEEE 80 bit floating point type padded to 128 bits
+ * ti_int is a 128 bit integral type
+ */
+
+/* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee |
+ * 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm
+ */
+
+COMPILER_RT_ABI long double
+__floattixf(ti_int a)
+{
+ if (a == 0)
+ return 0.0;
+ const unsigned N = sizeof(ti_int) * CHAR_BIT;
+ const ti_int s = a >> (N-1);
+ a = (a ^ s) - s;
+ int sd = N - __clzti2(a); /* number of significant digits */
+ int e = sd - 1; /* exponent */
+ if (sd > LDBL_MANT_DIG)
+ {
+ /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
+ * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
+ * 12345678901234567890123456
+ * 1 = msb 1 bit
+ * P = bit LDBL_MANT_DIG-1 bits to the right of 1
+ * Q = bit LDBL_MANT_DIG bits to the right of 1
+ * R = "or" of all bits to the right of Q
+ */
+ switch (sd)
+ {
+ case LDBL_MANT_DIG + 1:
+ a <<= 1;
+ break;
+ case LDBL_MANT_DIG + 2:
+ break;
+ default:
+ a = ((tu_int)a >> (sd - (LDBL_MANT_DIG+2))) |
+ ((a & ((tu_int)(-1) >> ((N + LDBL_MANT_DIG+2) - sd))) != 0);
+ };
+ /* finish: */
+ a |= (a & 4) != 0; /* Or P into R */
+ ++a; /* round - this step may add a significant bit */
+ a >>= 2; /* dump Q and R */
+ /* a is now rounded to LDBL_MANT_DIG or LDBL_MANT_DIG+1 bits */
+ if (a & ((tu_int)1 << LDBL_MANT_DIG))
+ {
+ a >>= 1;
+ ++e;
+ }
+ /* a is now rounded to LDBL_MANT_DIG bits */
+ }
+ else
+ {
+ a <<= (LDBL_MANT_DIG - sd);
+ /* a is now rounded to LDBL_MANT_DIG bits */
+ }
+ long_double_bits fb;
+ fb.u.high.s.low = ((su_int)s & 0x8000) | /* sign */
+ (e + 16383); /* exponent */
+ fb.u.low.all = (du_int)a; /* mantissa */
+ return fb.f;
+}
+
+#endif /* CRT_HAS_128BIT */
diff --git a/lib/builtins/floatundidf.c b/lib/builtins/floatundidf.c
new file mode 100644
index 000000000000..73b8bac1c1a1
--- /dev/null
+++ b/lib/builtins/floatundidf.c
@@ -0,0 +1,106 @@
+/* ===-- floatundidf.c - Implement __floatundidf ---------------------------===
+ *
+ * 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 __floatundidf for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+/* Returns: convert a to a double, rounding toward even. */
+
+/* Assumption: double is a IEEE 64 bit floating point type
+ * du_int is a 64 bit integral type
+ */
+
+/* seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm */
+
+#include "int_lib.h"
+
+ARM_EABI_FNALIAS(ul2d, floatundidf)
+
+#ifndef __SOFT_FP__
+/* Support for systems that have hardware floating-point; we'll set the inexact flag
+ * as a side-effect of this computation.
+ */
+
+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;
+
+ union { uint64_t x; double d; } high = { .d = twop84 };
+ union { uint64_t x; double d; } low = { .d = twop52 };
+
+ high.x |= a >> 32;
+ low.x |= a & UINT64_C(0x00000000ffffffff);
+
+ const double result = (high.d - twop84_plus_twop52) + low.d;
+ return result;
+}
+
+#else
+/* Support for systems that don't have hardware floating-point; there are no flags to
+ * set, and we don't want to code-gen to an unknown soft-float implementation.
+ */
+
+COMPILER_RT_ABI double
+__floatundidf(du_int a)
+{
+ if (a == 0)
+ return 0.0;
+ const unsigned N = sizeof(du_int) * CHAR_BIT;
+ int sd = N - __builtin_clzll(a); /* number of significant digits */
+ int e = sd - 1; /* exponent */
+ if (sd > DBL_MANT_DIG)
+ {
+ /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
+ * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
+ * 12345678901234567890123456
+ * 1 = msb 1 bit
+ * P = bit DBL_MANT_DIG-1 bits to the right of 1
+ * Q = bit DBL_MANT_DIG bits to the right of 1
+ * R = "or" of all bits to the right of Q
+ */
+ switch (sd)
+ {
+ case DBL_MANT_DIG + 1:
+ a <<= 1;
+ break;
+ case DBL_MANT_DIG + 2:
+ break;
+ default:
+ a = (a >> (sd - (DBL_MANT_DIG+2))) |
+ ((a & ((du_int)(-1) >> ((N + DBL_MANT_DIG+2) - sd))) != 0);
+ };
+ /* finish: */
+ a |= (a & 4) != 0; /* Or P into R */
+ ++a; /* round - this step may add a significant bit */
+ a >>= 2; /* dump Q and R */
+ /* a is now rounded to DBL_MANT_DIG or DBL_MANT_DIG+1 bits */
+ if (a & ((du_int)1 << DBL_MANT_DIG))
+ {
+ a >>= 1;
+ ++e;
+ }
+ /* a is now rounded to DBL_MANT_DIG bits */
+ }
+ else
+ {
+ a <<= (DBL_MANT_DIG - sd);
+ /* a is now rounded to DBL_MANT_DIG bits */
+ }
+ double_bits fb;
+ fb.u.high = ((e + 1023) << 20) | /* exponent */
+ ((su_int)(a >> 32) & 0x000FFFFF); /* mantissa-high */
+ fb.u.low = (su_int)a; /* mantissa-low */
+ return fb.f;
+}
+#endif
diff --git a/lib/floatundisf.c b/lib/builtins/floatundisf.c
index 713a44abc8bd..713a44abc8bd 100644
--- a/lib/floatundisf.c
+++ b/lib/builtins/floatundisf.c
diff --git a/lib/builtins/floatundixf.c b/lib/builtins/floatundixf.c
new file mode 100644
index 000000000000..ca5e06d64dcd
--- /dev/null
+++ b/lib/builtins/floatundixf.c
@@ -0,0 +1,42 @@
+/* ===-- floatundixf.c - Implement __floatundixf ---------------------------===
+ *
+ * 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 __floatundixf for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#if !_ARCH_PPC
+
+#include "int_lib.h"
+
+/* Returns: convert a to a long double, rounding toward even. */
+
+/* Assumption: long double is a IEEE 80 bit floating point type padded to 128 bits
+ * du_int is a 64 bit integral type
+ */
+
+/* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee |
+ * 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm
+ */
+COMPILER_RT_ABI long double
+__floatundixf(du_int a)
+{
+ if (a == 0)
+ return 0.0;
+ const unsigned N = sizeof(du_int) * CHAR_BIT;
+ int clz = __builtin_clzll(a);
+ int e = (N - 1) - clz ; /* exponent */
+ long_double_bits fb;
+ fb.u.high.s.low = (e + 16383); /* exponent */
+ fb.u.low.all = a << clz; /* mantissa */
+ return fb.f;
+}
+
+#endif /* _ARCH_PPC */
diff --git a/lib/builtins/floatunsidf.c b/lib/builtins/floatunsidf.c
new file mode 100644
index 000000000000..445e18041c48
--- /dev/null
+++ b/lib/builtins/floatunsidf.c
@@ -0,0 +1,42 @@
+//===-- lib/floatunsidf.c - uint -> double-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 unsigned integer to double-precision conversion for the
+// compiler-rt library in the IEEE-754 default round-to-nearest, ties-to-even
+// mode.
+//
+//===----------------------------------------------------------------------===//
+
+#define DOUBLE_PRECISION
+#include "fp_lib.h"
+
+#include "int_lib.h"
+
+ARM_EABI_FNALIAS(ui2d, floatunsidf)
+
+COMPILER_RT_ABI fp_t
+__floatunsidf(unsigned 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_clz(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);
+}
diff --git a/lib/builtins/floatunsisf.c b/lib/builtins/floatunsisf.c
new file mode 100644
index 000000000000..ea6f161adc02
--- /dev/null
+++ b/lib/builtins/floatunsisf.c
@@ -0,0 +1,50 @@
+//===-- lib/floatunsisf.c - uint -> single-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 unsigned integer to single-precision conversion for the
+// compiler-rt library in the IEEE-754 default round-to-nearest, ties-to-even
+// mode.
+//
+//===----------------------------------------------------------------------===//
+
+#define SINGLE_PRECISION
+#include "fp_lib.h"
+
+#include "int_lib.h"
+
+ARM_EABI_FNALIAS(ui2f, floatunsisf)
+
+COMPILER_RT_ABI fp_t
+__floatunsisf(unsigned 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_clz(a);
+ rep_t result;
+
+ // Shift a into the significand field, rounding if it is a right-shift
+ if (exponent <= significandBits) {
+ const int shift = significandBits - exponent;
+ result = (rep_t)a << shift ^ implicitBit;
+ } else {
+ const int shift = exponent - significandBits;
+ result = (rep_t)a >> shift ^ implicitBit;
+ rep_t round = (rep_t)a << (typeWidth - shift);
+ if (round > signBit) result++;
+ if (round == signBit) result += result & 1;
+ }
+
+ // Insert the exponent
+ result += (rep_t)(exponent + exponentBias) << significandBits;
+ return fromRep(result);
+}
diff --git a/lib/builtins/floatunsitf.c b/lib/builtins/floatunsitf.c
new file mode 100644
index 000000000000..1cd1842e709a
--- /dev/null
+++ b/lib/builtins/floatunsitf.c
@@ -0,0 +1,40 @@
+//===-- lib/floatunsitf.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 unsigned integer 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 __floatunsitf(unsigned 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_clz(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/floatuntidf.c b/lib/builtins/floatuntidf.c
new file mode 100644
index 000000000000..06202d9679ee
--- /dev/null
+++ b/lib/builtins/floatuntidf.c
@@ -0,0 +1,80 @@
+/* ===-- floatuntidf.c - Implement __floatuntidf ---------------------------===
+ *
+ * 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 __floatuntidf for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+/* Returns: convert a to a double, rounding toward even. */
+
+/* Assumption: double is a IEEE 64 bit floating point type
+ * tu_int is a 128 bit integral type
+ */
+
+/* seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm */
+
+COMPILER_RT_ABI double
+__floatuntidf(tu_int a)
+{
+ if (a == 0)
+ return 0.0;
+ const unsigned N = sizeof(tu_int) * CHAR_BIT;
+ int sd = N - __clzti2(a); /* number of significant digits */
+ int e = sd - 1; /* exponent */
+ if (sd > DBL_MANT_DIG)
+ {
+ /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
+ * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
+ * 12345678901234567890123456
+ * 1 = msb 1 bit
+ * P = bit DBL_MANT_DIG-1 bits to the right of 1
+ * Q = bit DBL_MANT_DIG bits to the right of 1
+ * R = "or" of all bits to the right of Q
+ */
+ switch (sd)
+ {
+ case DBL_MANT_DIG + 1:
+ a <<= 1;
+ break;
+ case DBL_MANT_DIG + 2:
+ break;
+ default:
+ a = (a >> (sd - (DBL_MANT_DIG+2))) |
+ ((a & ((tu_int)(-1) >> ((N + DBL_MANT_DIG+2) - sd))) != 0);
+ };
+ /* finish: */
+ a |= (a & 4) != 0; /* Or P into R */
+ ++a; /* round - this step may add a significant bit */
+ a >>= 2; /* dump Q and R */
+ /* a is now rounded to DBL_MANT_DIG or DBL_MANT_DIG+1 bits */
+ if (a & ((tu_int)1 << DBL_MANT_DIG))
+ {
+ a >>= 1;
+ ++e;
+ }
+ /* a is now rounded to DBL_MANT_DIG bits */
+ }
+ else
+ {
+ a <<= (DBL_MANT_DIG - sd);
+ /* a is now rounded to DBL_MANT_DIG bits */
+ }
+ double_bits fb;
+ fb.u.s.high = ((e + 1023) << 20) | /* exponent */
+ ((su_int)(a >> 32) & 0x000FFFFF); /* mantissa-high */
+ fb.u.s.low = (su_int)a; /* mantissa-low */
+ return fb.f;
+}
+
+#endif /* CRT_HAS_128BIT */
diff --git a/lib/builtins/floatuntisf.c b/lib/builtins/floatuntisf.c
new file mode 100644
index 000000000000..c0dd0275ddba
--- /dev/null
+++ b/lib/builtins/floatuntisf.c
@@ -0,0 +1,79 @@
+/* ===-- floatuntisf.c - Implement __floatuntisf ---------------------------===
+ *
+ * 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 __floatuntisf for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+/* Returns: convert a to a float, rounding toward even. */
+
+/* Assumption: float is a IEEE 32 bit floating point type
+ * tu_int is a 128 bit integral type
+ */
+
+/* seee eeee emmm mmmm mmmm mmmm mmmm mmmm */
+
+COMPILER_RT_ABI float
+__floatuntisf(tu_int a)
+{
+ if (a == 0)
+ return 0.0F;
+ const unsigned N = sizeof(tu_int) * CHAR_BIT;
+ int sd = N - __clzti2(a); /* number of significant digits */
+ int e = sd - 1; /* exponent */
+ if (sd > FLT_MANT_DIG)
+ {
+ /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
+ * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
+ * 12345678901234567890123456
+ * 1 = msb 1 bit
+ * P = bit FLT_MANT_DIG-1 bits to the right of 1
+ * Q = bit FLT_MANT_DIG bits to the right of 1
+ * R = "or" of all bits to the right of Q
+ */
+ switch (sd)
+ {
+ case FLT_MANT_DIG + 1:
+ a <<= 1;
+ break;
+ case FLT_MANT_DIG + 2:
+ break;
+ default:
+ a = (a >> (sd - (FLT_MANT_DIG+2))) |
+ ((a & ((tu_int)(-1) >> ((N + FLT_MANT_DIG+2) - sd))) != 0);
+ };
+ /* finish: */
+ a |= (a & 4) != 0; /* Or P into R */
+ ++a; /* round - this step may add a significant bit */
+ a >>= 2; /* dump Q and R */
+ /* a is now rounded to FLT_MANT_DIG or FLT_MANT_DIG+1 bits */
+ if (a & ((tu_int)1 << FLT_MANT_DIG))
+ {
+ a >>= 1;
+ ++e;
+ }
+ /* a is now rounded to FLT_MANT_DIG bits */
+ }
+ else
+ {
+ a <<= (FLT_MANT_DIG - sd);
+ /* a is now rounded to FLT_MANT_DIG bits */
+ }
+ float_bits fb;
+ fb.u = ((e + 127) << 23) | /* exponent */
+ ((su_int)a & 0x007FFFFF); /* mantissa */
+ return fb.f;
+}
+
+#endif /* CRT_HAS_128BIT */
diff --git a/lib/builtins/floatuntixf.c b/lib/builtins/floatuntixf.c
new file mode 100644
index 000000000000..ea81cb1bcdae
--- /dev/null
+++ b/lib/builtins/floatuntixf.c
@@ -0,0 +1,81 @@
+/* ===-- floatuntixf.c - Implement __floatuntixf ---------------------------===
+ *
+ * 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 __floatuntixf for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+/* Returns: convert a to a long double, rounding toward even. */
+
+/* Assumption: long double is a IEEE 80 bit floating point type padded to 128 bits
+ * tu_int is a 128 bit integral type
+ */
+
+/* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee |
+ * 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm
+ */
+
+COMPILER_RT_ABI long double
+__floatuntixf(tu_int a)
+{
+ if (a == 0)
+ return 0.0;
+ const unsigned N = sizeof(tu_int) * CHAR_BIT;
+ int sd = N - __clzti2(a); /* number of significant digits */
+ int e = sd - 1; /* exponent */
+ if (sd > LDBL_MANT_DIG)
+ {
+ /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
+ * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
+ * 12345678901234567890123456
+ * 1 = msb 1 bit
+ * P = bit LDBL_MANT_DIG-1 bits to the right of 1
+ * Q = bit LDBL_MANT_DIG bits to the right of 1
+ * R = "or" of all bits to the right of Q
+ */
+ switch (sd)
+ {
+ case LDBL_MANT_DIG + 1:
+ a <<= 1;
+ break;
+ case LDBL_MANT_DIG + 2:
+ break;
+ default:
+ a = (a >> (sd - (LDBL_MANT_DIG+2))) |
+ ((a & ((tu_int)(-1) >> ((N + LDBL_MANT_DIG+2) - sd))) != 0);
+ };
+ /* finish: */
+ a |= (a & 4) != 0; /* Or P into R */
+ ++a; /* round - this step may add a significant bit */
+ a >>= 2; /* dump Q and R */
+ /* a is now rounded to LDBL_MANT_DIG or LDBL_MANT_DIG+1 bits */
+ if (a & ((tu_int)1 << LDBL_MANT_DIG))
+ {
+ a >>= 1;
+ ++e;
+ }
+ /* a is now rounded to LDBL_MANT_DIG bits */
+ }
+ else
+ {
+ a <<= (LDBL_MANT_DIG - sd);
+ /* a is now rounded to LDBL_MANT_DIG bits */
+ }
+ long_double_bits fb;
+ fb.u.high.s.low = (e + 16383); /* exponent */
+ fb.u.low.all = (du_int)a; /* mantissa */
+ return fb.f;
+}
+
+#endif
diff --git a/lib/builtins/fp_add_impl.inc b/lib/builtins/fp_add_impl.inc
new file mode 100644
index 000000000000..5741889728cd
--- /dev/null
+++ b/lib/builtins/fp_add_impl.inc
@@ -0,0 +1,144 @@
+//===----- lib/fp_add_impl.inc - floaing point addition -----------*- 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 soft-float addition with the IEEE-754 default rounding
+// (to nearest, ties to even).
+//
+//===----------------------------------------------------------------------===//
+
+#include "fp_lib.h"
+
+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;
+ const rep_t bAbs = bRep & absMask;
+
+ // Detect if a or b is zero, infinity, or NaN.
+ if (aAbs - REP_C(1) >= infRep - REP_C(1) ||
+ bAbs - REP_C(1) >= infRep - REP_C(1)) {
+ // NaN + anything = qNaN
+ if (aAbs > infRep) return fromRep(toRep(a) | quietBit);
+ // anything + NaN = qNaN
+ if (bAbs > infRep) return fromRep(toRep(b) | quietBit);
+
+ if (aAbs == infRep) {
+ // +/-infinity + -/+infinity = qNaN
+ if ((toRep(a) ^ toRep(b)) == signBit) return fromRep(qnanRep);
+ // +/-infinity + anything remaining = +/- infinity
+ else return a;
+ }
+
+ // anything remaining + +/-infinity = +/-infinity
+ if (bAbs == infRep) return b;
+
+ // zero + anything = anything
+ if (!aAbs) {
+ // but we need to get the sign right for zero + zero
+ if (!bAbs) return fromRep(toRep(a) & toRep(b));
+ else return b;
+ }
+
+ // anything + zero = anything
+ if (!bAbs) return a;
+ }
+
+ // Swap a and b if necessary so that a has the larger absolute value.
+ if (bAbs > aAbs) {
+ const rep_t temp = aRep;
+ aRep = bRep;
+ bRep = temp;
+ }
+
+ // Extract the exponent and significand from the (possibly swapped) a and b.
+ int aExponent = aRep >> significandBits & maxExponent;
+ int bExponent = bRep >> significandBits & maxExponent;
+ rep_t aSignificand = aRep & significandMask;
+ rep_t bSignificand = bRep & significandMask;
+
+ // Normalize any denormals, and adjust the exponent accordingly.
+ if (aExponent == 0) aExponent = normalize(&aSignificand);
+ if (bExponent == 0) bExponent = normalize(&bSignificand);
+
+ // The sign of the result is the sign of the larger operand, a. If they
+ // have opposite signs, we are performing a subtraction; otherwise addition.
+ const rep_t resultSign = aRep & signBit;
+ const bool subtraction = (aRep ^ bRep) & signBit;
+
+ // Shift the significands to give us round, guard and sticky, and or in the
+ // implicit significand bit. (If we fell through from the denormal path it
+ // was already set by normalize( ), but setting it twice won't hurt
+ // anything.)
+ aSignificand = (aSignificand | implicitBit) << 3;
+ bSignificand = (bSignificand | implicitBit) << 3;
+
+ // Shift the significand of b by the difference in exponents, with a sticky
+ // bottom bit to get rounding correct.
+ const unsigned int align = aExponent - bExponent;
+ if (align) {
+ if (align < typeWidth) {
+ const bool sticky = bSignificand << (typeWidth - align);
+ bSignificand = bSignificand >> align | sticky;
+ } else {
+ bSignificand = 1; // sticky; b is known to be non-zero.
+ }
+ }
+ if (subtraction) {
+ aSignificand -= bSignificand;
+ // If a == -b, return +zero.
+ if (aSignificand == 0) return fromRep(0);
+
+ // If partial cancellation occured, we need to left-shift the result
+ // and adjust the exponent:
+ if (aSignificand < implicitBit << 3) {
+ const int shift = rep_clz(aSignificand) - rep_clz(implicitBit << 3);
+ aSignificand <<= shift;
+ aExponent -= shift;
+ }
+ }
+ else /* addition */ {
+ aSignificand += bSignificand;
+
+ // If the addition carried up, we need to right-shift the result and
+ // adjust the exponent:
+ if (aSignificand & implicitBit << 4) {
+ const bool sticky = aSignificand & 1;
+ aSignificand = aSignificand >> 1 | sticky;
+ aExponent += 1;
+ }
+ }
+
+ // If we have overflowed the type, return +/- infinity:
+ if (aExponent >= maxExponent) return fromRep(infRep | resultSign);
+
+ if (aExponent <= 0) {
+ // Result is denormal before rounding; the exponent is zero and we
+ // need to shift the significand.
+ const int shift = 1 - aExponent;
+ const bool sticky = aSignificand << (typeWidth - shift);
+ aSignificand = aSignificand >> shift | sticky;
+ aExponent = 0;
+ }
+
+ // Low three bits are round, guard, and sticky.
+ const int roundGuardSticky = aSignificand & 0x7;
+
+ // Shift the significand into place, and mask off the implicit bit.
+ rep_t result = aSignificand >> 3 & significandMask;
+
+ // Insert the exponent and sign.
+ result |= (rep_t)aExponent << significandBits;
+ result |= resultSign;
+
+ // Final rounding. The result may overflow to infinity, but that is the
+ // correct result in that case.
+ if (roundGuardSticky > 0x4) result++;
+ if (roundGuardSticky == 0x4) result += result & 1;
+ return fromRep(result);
+}
diff --git a/lib/builtins/fp_extend.h b/lib/builtins/fp_extend.h
new file mode 100644
index 000000000000..fff676eeca8c
--- /dev/null
+++ b/lib/builtins/fp_extend.h
@@ -0,0 +1,76 @@
+//===-lib/fp_extend.h - low precision -> high 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.
+//
+//===----------------------------------------------------------------------===//
+//
+// Set source and destination setting
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef FP_EXTEND_HEADER
+#define FP_EXTEND_HEADER
+
+#include "int_lib.h"
+
+#if defined SRC_SINGLE
+typedef float src_t;
+typedef uint32_t src_rep_t;
+#define SRC_REP_C UINT32_C
+static const int srcSigBits = 23;
+#define src_rep_t_clz __builtin_clz
+
+#elif defined SRC_DOUBLE
+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) {
+#if defined __LP64__
+ return __builtin_clzl(a);
+#else
+ if (a & REP_C(0xffffffff00000000))
+ return __builtin_clz(a >> 32);
+ else
+ return 32 + __builtin_clz(a & REP_C(0xffffffff));
+#endif
+}
+
+#else
+#error Source should be single precision or double precision!
+#endif //end source precision
+
+#if defined DST_DOUBLE
+typedef double dst_t;
+typedef uint64_t dst_rep_t;
+#define DST_REP_C UINT64_C
+static const int dstSigBits = 52;
+
+#elif defined DST_QUAD
+typedef long double dst_t;
+typedef __uint128_t dst_rep_t;
+#define DST_REP_C (__uint128_t)
+static const int dstSigBits = 112;
+
+#else
+#error Destination should be double precision or quad precision!
+#endif //end destination precision
+
+// 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) {
+ const union { src_t f; src_rep_t i; } rep = {.f = x};
+ return rep.i;
+}
+
+static inline dst_t dstFromRep(dst_rep_t x) {
+ const union { dst_t f; dst_rep_t i; } rep = {.i = x};
+ return rep.f;
+}
+// End helper routines. Conversion implementation follows.
+
+#endif //FP_EXTEND_HEADER
diff --git a/lib/builtins/fp_extend_impl.inc b/lib/builtins/fp_extend_impl.inc
new file mode 100644
index 000000000000..f6953ff4bfae
--- /dev/null
+++ b/lib/builtins/fp_extend_impl.inc
@@ -0,0 +1,106 @@
+//=-lib/fp_extend_impl.inc - low precision -> high precision conversion -*-- -//
+//
+// 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 a fairly generic conversion from a narrower to a wider
+// IEEE-754 floating-point type. The constants and types defined following the
+// includes below parameterize the conversion.
+//
+// It does not support types that don't use the usual IEEE-754 interchange
+// formats; specifically, some work would be needed to adapt it to
+// (for example) the Intel 80-bit format or PowerPC double-double format.
+//
+// Note please, however, that this implementation is only intended to support
+// *widening* operations; if you need to convert to a *narrower* floating-point
+// type (e.g. double -> float), then this routine will not do what you want it
+// to.
+//
+// It also requires that integer types at least as large as both formats
+// are available on the target platform; this may pose a problem when trying
+// to add support for quad on some 32-bit systems, for example. You also may
+// run into trouble finding an appropriate CLZ function for wide source types;
+// you will likely need to roll your own on some platforms.
+//
+// Finally, the following assumptions are made:
+//
+// 1. floating-point types and integer types have the same endianness on the
+// target platform
+//
+// 2. quiet NaNs, if supported, are indicated by the leading bit of the
+// significand field being set
+//
+//===----------------------------------------------------------------------===//
+
+#include "fp_extend.h"
+
+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;
+ const int srcExpBits = srcBits - srcSigBits - 1;
+ const int srcInfExp = (1 << srcExpBits) - 1;
+ const int srcExpBias = srcInfExp >> 1;
+
+ const src_rep_t srcMinNormal = SRC_REP_C(1) << srcSigBits;
+ const src_rep_t srcInfinity = (src_rep_t)srcInfExp << srcSigBits;
+ const src_rep_t srcSignMask = SRC_REP_C(1) << (srcSigBits + srcExpBits);
+ const src_rep_t srcAbsMask = srcSignMask - 1;
+ const src_rep_t srcQNaN = SRC_REP_C(1) << (srcSigBits - 1);
+ const src_rep_t srcNaNCode = srcQNaN - 1;
+
+ const int dstBits = sizeof(dst_t)*CHAR_BIT;
+ const int dstExpBits = dstBits - dstSigBits - 1;
+ const int dstInfExp = (1 << dstExpBits) - 1;
+ const int dstExpBias = dstInfExp >> 1;
+
+ const dst_rep_t dstMinNormal = DST_REP_C(1) << dstSigBits;
+
+ // Break a into a sign and representation of the absolute value
+ const src_rep_t aRep = srcToRep(a);
+ const src_rep_t aAbs = aRep & srcAbsMask;
+ const src_rep_t sign = aRep & srcSignMask;
+ dst_rep_t absResult;
+
+ if (aAbs - srcMinNormal < srcInfinity - srcMinNormal) {
+ // a is a normal number.
+ // Extend to the destination type by shifting the significand and
+ // exponent into the proper position and rebiasing the exponent.
+ absResult = (dst_rep_t)aAbs << (dstSigBits - srcSigBits);
+ absResult += (dst_rep_t)(dstExpBias - srcExpBias) << dstSigBits;
+ }
+
+ else if (aAbs >= srcInfinity) {
+ // a is NaN or infinity.
+ // Conjure the result by beginning with infinity, then setting the qNaN
+ // bit (if needed) and right-aligning the rest of the trailing NaN
+ // payload field.
+ absResult = (dst_rep_t)dstInfExp << dstSigBits;
+ absResult |= (dst_rep_t)(aAbs & srcQNaN) << (dstSigBits - srcSigBits);
+ absResult |= (dst_rep_t)(aAbs & srcNaNCode) << (dstSigBits - srcSigBits);
+ }
+
+ else if (aAbs) {
+ // a is denormal.
+ // renormalize the significand and clear the leading bit, then insert
+ // the correct adjusted exponent in the destination type.
+ const int scale = src_rep_t_clz(aAbs) - src_rep_t_clz(srcMinNormal);
+ absResult = (dst_rep_t)aAbs << (dstSigBits - srcSigBits + scale);
+ absResult ^= dstMinNormal;
+ const int resultExponent = dstExpBias - srcExpBias - scale + 1;
+ absResult |= (dst_rep_t)resultExponent << dstSigBits;
+ }
+
+ else {
+ // a is zero.
+ absResult = 0;
+ }
+
+ // Apply the signbit to (dst_t)abs(a).
+ const dst_rep_t result = absResult | (dst_rep_t)sign << (dstBits - srcBits);
+ return dstFromRep(result);
+}
diff --git a/lib/builtins/fp_lib.h b/lib/builtins/fp_lib.h
new file mode 100644
index 000000000000..faebb99ecd5e
--- /dev/null
+++ b/lib/builtins/fp_lib.h
@@ -0,0 +1,270 @@
+//===-- lib/fp_lib.h - Floating-point utilities -------------------*- 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 is a configuration header for soft-float routines in compiler-rt.
+// This file does not provide any part of the compiler-rt interface, but defines
+// many useful constants and utility routines that are used in the
+// implementation of the soft-float routines in compiler-rt.
+//
+// Assumes that float, double and long double correspond to the IEEE-754
+// binary32, binary64 and binary 128 types, respectively, and that integer
+// endianness matches floating point endianness on the target platform.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef FP_LIB_HEADER
+#define FP_LIB_HEADER
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <limits.h>
+#include "int_lib.h"
+
+// x86_64 FreeBSD prior v9.3 define fixed-width types incorrectly in
+// 32-bit mode.
+#if defined(__FreeBSD__) && defined(__i386__)
+# include <sys/param.h>
+# if __FreeBSD_version < 903000 // v9.3
+# define uint64_t unsigned long long
+# define int64_t long long
+# undef UINT64_C
+# define UINT64_C(c) (c ## ULL)
+# endif
+#endif
+
+#if defined SINGLE_PRECISION
+
+typedef uint32_t rep_t;
+typedef int32_t srep_t;
+typedef float fp_t;
+#define REP_C UINT32_C
+#define significandBits 23
+
+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) {
+ const uint64_t product = (uint64_t)a*b;
+ *hi = product >> 32;
+ *lo = product;
+}
+COMPILER_RT_ABI fp_t __addsf3(fp_t a, fp_t b);
+
+#elif defined DOUBLE_PRECISION
+
+typedef uint64_t rep_t;
+typedef int64_t srep_t;
+typedef double fp_t;
+#define REP_C UINT64_C
+#define significandBits 52
+
+static inline int rep_clz(rep_t a) {
+#if defined __LP64__
+ return __builtin_clzl(a);
+#else
+ if (a & REP_C(0xffffffff00000000))
+ return __builtin_clz(a >> 32);
+ else
+ return 32 + __builtin_clz(a & REP_C(0xffffffff));
+#endif
+}
+
+#define loWord(a) (a & 0xffffffffU)
+#define hiWord(a) (a >> 32)
+
+// 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) {
+ // Each of the component 32x32 -> 64 products
+ const uint64_t plolo = loWord(a) * loWord(b);
+ const uint64_t plohi = loWord(a) * hiWord(b);
+ const uint64_t philo = hiWord(a) * loWord(b);
+ const uint64_t phihi = hiWord(a) * hiWord(b);
+ // Sum terms that contribute to lo in a way that allows us to get the carry
+ const uint64_t r0 = loWord(plolo);
+ const uint64_t r1 = hiWord(plolo) + loWord(plohi) + loWord(philo);
+ *lo = r0 + (r1 << 32);
+ // Sum terms contributing to hi with the carry from lo
+ *hi = hiWord(plohi) + hiWord(philo) + hiWord(r1) + phihi;
+}
+#undef loWord
+#undef hiWord
+
+COMPILER_RT_ABI fp_t __adddf3(fp_t a, fp_t b);
+
+#elif defined QUAD_PRECISION
+#if __LDBL_MANT_DIG__ == 113
+#define CRT_LDBL_128BIT
+typedef __uint128_t rep_t;
+typedef __int128_t srep_t;
+typedef long double fp_t;
+#define REP_C (__uint128_t)
+// Note: Since there is no explicit way to tell compiler the constant is a
+// 128-bit integer, we let the constant be casted to 128-bit integer
+#define significandBits 112
+
+static inline int rep_clz(rep_t a) {
+ const union
+ {
+ __uint128_t ll;
+#if _YUGA_BIG_ENDIAN
+ struct { uint64_t high, low; } s;
+#else
+ struct { uint64_t low, high; } s;
+#endif
+ } uu = { .ll = a };
+
+ uint64_t word;
+ uint64_t add;
+
+ if (uu.s.high){
+ word = uu.s.high;
+ add = 0;
+ }
+ else{
+ word = uu.s.low;
+ add = 64;
+ }
+ return __builtin_clzll(word) + add;
+}
+
+#define Word_LoMask UINT64_C(0x00000000ffffffff)
+#define Word_HiMask UINT64_C(0xffffffff00000000)
+#define Word_FullMask UINT64_C(0xffffffffffffffff)
+#define Word_1(a) (uint64_t)((a >> 96) & Word_LoMask)
+#define Word_2(a) (uint64_t)((a >> 64) & Word_LoMask)
+#define Word_3(a) (uint64_t)((a >> 32) & Word_LoMask)
+#define Word_4(a) (uint64_t)(a & Word_LoMask)
+
+// 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) {
+
+ const uint64_t product11 = Word_1(a) * Word_1(b);
+ const uint64_t product12 = Word_1(a) * Word_2(b);
+ const uint64_t product13 = Word_1(a) * Word_3(b);
+ const uint64_t product14 = Word_1(a) * Word_4(b);
+ const uint64_t product21 = Word_2(a) * Word_1(b);
+ const uint64_t product22 = Word_2(a) * Word_2(b);
+ const uint64_t product23 = Word_2(a) * Word_3(b);
+ const uint64_t product24 = Word_2(a) * Word_4(b);
+ const uint64_t product31 = Word_3(a) * Word_1(b);
+ const uint64_t product32 = Word_3(a) * Word_2(b);
+ const uint64_t product33 = Word_3(a) * Word_3(b);
+ const uint64_t product34 = Word_3(a) * Word_4(b);
+ const uint64_t product41 = Word_4(a) * Word_1(b);
+ const uint64_t product42 = Word_4(a) * Word_2(b);
+ const uint64_t product43 = Word_4(a) * Word_3(b);
+ const uint64_t product44 = Word_4(a) * Word_4(b);
+
+ const __uint128_t sum0 = (__uint128_t)product44;
+ const __uint128_t sum1 = (__uint128_t)product34 +
+ (__uint128_t)product43;
+ const __uint128_t sum2 = (__uint128_t)product24 +
+ (__uint128_t)product33 +
+ (__uint128_t)product42;
+ const __uint128_t sum3 = (__uint128_t)product14 +
+ (__uint128_t)product23 +
+ (__uint128_t)product32 +
+ (__uint128_t)product41;
+ const __uint128_t sum4 = (__uint128_t)product13 +
+ (__uint128_t)product22 +
+ (__uint128_t)product31;
+ const __uint128_t sum5 = (__uint128_t)product12 +
+ (__uint128_t)product21;
+ const __uint128_t sum6 = (__uint128_t)product11;
+
+ const __uint128_t r0 = (sum0 & Word_FullMask) +
+ ((sum1 & Word_LoMask) << 32);
+ const __uint128_t r1 = (sum0 >> 64) +
+ ((sum1 >> 32) & Word_FullMask) +
+ (sum2 & Word_FullMask) +
+ ((sum3 << 32) & Word_HiMask);
+
+ *lo = r0 + (r1 << 64);
+ *hi = (r1 >> 64) +
+ (sum1 >> 96) +
+ (sum2 >> 64) +
+ (sum3 >> 32) +
+ sum4 +
+ (sum5 << 32) +
+ (sum6 << 64);
+}
+#undef Word_1
+#undef Word_2
+#undef Word_3
+#undef Word_4
+#undef Word_HiMask
+#undef Word_LoMask
+#undef Word_FullMask
+#endif // __LDBL_MANT_DIG__ == 113
+#else
+#error SINGLE_PRECISION, DOUBLE_PRECISION or QUAD_PRECISION must be defined.
+#endif
+
+#if defined(SINGLE_PRECISION) || defined(DOUBLE_PRECISION) || defined(CRT_LDBL_128BIT)
+#define typeWidth (sizeof(rep_t)*CHAR_BIT)
+#define exponentBits (typeWidth - significandBits - 1)
+#define maxExponent ((1 << exponentBits) - 1)
+#define exponentBias (maxExponent >> 1)
+
+#define implicitBit (REP_C(1) << significandBits)
+#define significandMask (implicitBit - 1U)
+#define signBit (REP_C(1) << (significandBits + exponentBits))
+#define absMask (signBit - 1U)
+#define exponentMask (absMask ^ significandMask)
+#define oneRep ((rep_t)exponentBias << significandBits)
+#define infRep exponentMask
+#define quietBit (implicitBit >> 1)
+#define qnanRep (exponentMask | quietBit)
+
+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) {
+ const union { fp_t f; rep_t i; } rep = {.i = x};
+ return rep.f;
+}
+
+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) {
+ *hi = *hi << count | *lo >> (typeWidth - count);
+ *lo = *lo << 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;
+ *hi = *hi >> count;
+ }
+ else if (count < 2*typeWidth) {
+ const bool sticky = *hi << (2*typeWidth - count) | *lo;
+ *lo = *hi >> (count - typeWidth) | sticky;
+ *hi = 0;
+ } else {
+ const bool sticky = *hi | *lo;
+ *lo = sticky;
+ *hi = 0;
+ }
+}
+#endif
+
+#endif // FP_LIB_HEADER
diff --git a/lib/builtins/fp_mul_impl.inc b/lib/builtins/fp_mul_impl.inc
new file mode 100644
index 000000000000..ca8a0bb98b10
--- /dev/null
+++ b/lib/builtins/fp_mul_impl.inc
@@ -0,0 +1,116 @@
+//===---- lib/fp_mul_impl.inc - floating point multiplication -----*- 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 soft-float multiplication with the IEEE-754 default
+// rounding (to nearest, ties to even).
+//
+//===----------------------------------------------------------------------===//
+
+#include "fp_lib.h"
+
+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;
+
+ rep_t aSignificand = toRep(a) & significandMask;
+ rep_t bSignificand = toRep(b) & significandMask;
+ int scale = 0;
+
+ // Detect if a or b is zero, denormal, infinity, or NaN.
+ if (aExponent-1U >= maxExponent-1U || bExponent-1U >= maxExponent-1U) {
+
+ const rep_t aAbs = toRep(a) & absMask;
+ const rep_t bAbs = toRep(b) & absMask;
+
+ // NaN * anything = qNaN
+ if (aAbs > infRep) return fromRep(toRep(a) | quietBit);
+ // anything * NaN = qNaN
+ if (bAbs > infRep) return fromRep(toRep(b) | quietBit);
+
+ if (aAbs == infRep) {
+ // infinity * non-zero = +/- infinity
+ if (bAbs) return fromRep(aAbs | productSign);
+ // infinity * zero = NaN
+ else return fromRep(qnanRep);
+ }
+
+ if (bAbs == infRep) {
+ //? non-zero * infinity = +/- infinity
+ if (aAbs) return fromRep(bAbs | productSign);
+ // zero * infinity = NaN
+ else return fromRep(qnanRep);
+ }
+
+ // zero * anything = +/- zero
+ if (!aAbs) return fromRep(productSign);
+ // anything * zero = +/- zero
+ if (!bAbs) return fromRep(productSign);
+
+ // one or both of a or b is denormal, the other (if applicable) is a
+ // normal number. Renormalize one or both of a and b, and set scale to
+ // include the necessary exponent adjustment.
+ if (aAbs < implicitBit) scale += normalize(&aSignificand);
+ if (bAbs < implicitBit) scale += normalize(&bSignificand);
+ }
+
+ // Or in the implicit significand bit. (If we fell through from the
+ // denormal path it was already set by normalize( ), but setting it twice
+ // won't hurt anything.)
+ aSignificand |= implicitBit;
+ bSignificand |= implicitBit;
+
+ // Get the significand of a*b. Before multiplying the significands, shift
+ // one of them left to left-align it in the field. Thus, the product will
+ // have (exponentBits + 2) integral digits, all but two of which must be
+ // zero. Normalizing this result is just a conditional left-shift by one
+ // and bumping the exponent accordingly.
+ rep_t productHi, productLo;
+ wideMultiply(aSignificand, bSignificand << exponentBits,
+ &productHi, &productLo);
+
+ int productExponent = aExponent + bExponent - exponentBias + scale;
+
+ // Normalize the significand, adjust exponent if needed.
+ if (productHi & implicitBit) productExponent++;
+ else wideLeftShift(&productHi, &productLo, 1);
+
+ // If we have overflowed the type, return +/- infinity.
+ if (productExponent >= maxExponent) return fromRep(infRep | productSign);
+
+ if (productExponent <= 0) {
+ // Result is denormal before rounding
+ //
+ // If the result is so small that it just underflows to zero, return
+ // a zero of the appropriate sign. Mathematically there is no need to
+ // handle this case separately, but we make it a special case to
+ // simplify the shift logic.
+ const unsigned int shift = REP_C(1) - (unsigned int)productExponent;
+ if (shift >= typeWidth) return fromRep(productSign);
+
+ // Otherwise, shift the significand of the result so that the round
+ // bit is the high bit of productLo.
+ wideRightShiftWithSticky(&productHi, &productLo, shift);
+ }
+ else {
+ // Result is normal before rounding; insert the exponent.
+ productHi &= significandMask;
+ productHi |= (rep_t)productExponent << significandBits;
+ }
+
+ // Insert the sign of the result:
+ productHi |= productSign;
+
+ // Final rounding. The final result may overflow to infinity, or underflow
+ // to zero, but those are the correct results in those cases. We use the
+ // default IEEE-754 round-to-nearest, ties-to-even rounding mode.
+ if (productLo > signBit) productHi++;
+ if (productLo == signBit) productHi += productHi & 1;
+ return fromRep(productHi);
+}
diff --git a/lib/builtins/fp_trunc.h b/lib/builtins/fp_trunc.h
new file mode 100644
index 000000000000..49a9aebbc67d
--- /dev/null
+++ b/lib/builtins/fp_trunc.h
@@ -0,0 +1,64 @@
+//=== lib/fp_trunc.h - high precision -> low 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.
+//
+//===----------------------------------------------------------------------===//
+//
+// Set source and destination precision setting
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef FP_TRUNC_HEADER
+#define FP_TRUNC_HEADER
+
+#include "int_lib.h"
+
+#if defined SRC_DOUBLE
+typedef double src_t;
+typedef uint64_t src_rep_t;
+#define SRC_REP_C UINT64_C
+static const int srcSigBits = 52;
+
+#elif defined SRC_QUAD
+typedef long double src_t;
+typedef __uint128_t src_rep_t;
+#define SRC_REP_C (__uint128_t)
+static const int srcSigBits = 112;
+
+#else
+#error Source should be double precision or quad precision!
+#endif //end source precision
+
+#if defined DST_DOUBLE
+typedef double dst_t;
+typedef uint64_t dst_rep_t;
+#define DST_REP_C UINT64_C
+static const int dstSigBits = 52;
+
+#elif defined DST_SINGLE
+typedef float dst_t;
+typedef uint32_t dst_rep_t;
+#define DST_REP_C UINT32_C
+static const int dstSigBits = 23;
+
+#else
+#error Destination should be single precision or double precision!
+#endif //end destination precision
+
+// 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) {
+ const union { src_t f; src_rep_t i; } rep = {.f = x};
+ return rep.i;
+}
+
+static inline dst_t dstFromRep(dst_rep_t x) {
+ const union { dst_t f; dst_rep_t i; } rep = {.i = x};
+ return rep.f;
+}
+
+#endif // FP_TRUNC_HEADER
diff --git a/lib/builtins/fp_trunc_impl.inc b/lib/builtins/fp_trunc_impl.inc
new file mode 100644
index 000000000000..21bffae02bf4
--- /dev/null
+++ b/lib/builtins/fp_trunc_impl.inc
@@ -0,0 +1,135 @@
+//= lib/fp_trunc_impl.inc - high precision -> low precision conversion *-*-===//
+//
+// 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 a fairly generic conversion from a wider to a narrower
+// IEEE-754 floating-point type in the default (round to nearest, ties to even)
+// rounding mode. The constants and types defined following the includes below
+// parameterize the conversion.
+//
+// This routine can be trivially adapted to support conversions to
+// half-precision or from quad-precision. It does not support types that don't
+// use the usual IEEE-754 interchange formats; specifically, some work would be
+// needed to adapt it to (for example) the Intel 80-bit format or PowerPC
+// double-double format.
+//
+// Note please, however, that this implementation is only intended to support
+// *narrowing* operations; if you need to convert to a *wider* floating-point
+// type (e.g. float -> double), then this routine will not do what you want it
+// to.
+//
+// It also requires that integer types at least as large as both formats
+// are available on the target platform; this may pose a problem when trying
+// to add support for quad on some 32-bit systems, for example.
+//
+// Finally, the following assumptions are made:
+//
+// 1. floating-point types and integer types have the same endianness on the
+// target platform
+//
+// 2. quiet NaNs, if supported, are indicated by the leading bit of the
+// significand field being set
+//
+//===----------------------------------------------------------------------===//
+
+#include "fp_trunc.h"
+
+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;
+ const int srcExpBits = srcBits - srcSigBits - 1;
+ const int srcInfExp = (1 << srcExpBits) - 1;
+ const int srcExpBias = srcInfExp >> 1;
+
+ const src_rep_t srcMinNormal = SRC_REP_C(1) << srcSigBits;
+ const src_rep_t srcSignificandMask = srcMinNormal - 1;
+ const src_rep_t srcInfinity = (src_rep_t)srcInfExp << srcSigBits;
+ const src_rep_t srcSignMask = SRC_REP_C(1) << (srcSigBits + srcExpBits);
+ const src_rep_t srcAbsMask = srcSignMask - 1;
+ const src_rep_t roundMask = (SRC_REP_C(1) << (srcSigBits - dstSigBits)) - 1;
+ const src_rep_t halfway = SRC_REP_C(1) << (srcSigBits - dstSigBits - 1);
+ const src_rep_t srcQNaN = SRC_REP_C(1) << (srcSigBits - 1);
+ const src_rep_t srcNaNCode = srcQNaN - 1;
+
+ const int dstBits = sizeof(dst_t)*CHAR_BIT;
+ const int dstExpBits = dstBits - dstSigBits - 1;
+ const int dstInfExp = (1 << dstExpBits) - 1;
+ const int dstExpBias = dstInfExp >> 1;
+
+ const int underflowExponent = srcExpBias + 1 - dstExpBias;
+ const int overflowExponent = srcExpBias + dstInfExp - dstExpBias;
+ const src_rep_t underflow = (src_rep_t)underflowExponent << srcSigBits;
+ const src_rep_t overflow = (src_rep_t)overflowExponent << srcSigBits;
+
+ const dst_rep_t dstQNaN = DST_REP_C(1) << (dstSigBits - 1);
+ const dst_rep_t dstNaNCode = dstQNaN - 1;
+
+ // Break a into a sign and representation of the absolute value
+ const src_rep_t aRep = srcToRep(a);
+ const src_rep_t aAbs = aRep & srcAbsMask;
+ const src_rep_t sign = aRep & srcSignMask;
+ dst_rep_t absResult;
+
+ if (aAbs - underflow < aAbs - overflow) {
+ // The exponent of a is within the range of normal numbers in the
+ // destination format. We can convert by simply right-shifting with
+ // rounding and adjusting the exponent.
+ absResult = aAbs >> (srcSigBits - dstSigBits);
+ absResult -= (dst_rep_t)(srcExpBias - dstExpBias) << dstSigBits;
+
+ const src_rep_t roundBits = aAbs & roundMask;
+ // Round to nearest
+ if (roundBits > halfway)
+ absResult++;
+ // Ties to even
+ else if (roundBits == halfway)
+ absResult += absResult & 1;
+ }
+ else if (aAbs > srcInfinity) {
+ // a is NaN.
+ // Conjure the result by beginning with infinity, setting the qNaN
+ // bit and inserting the (truncated) trailing NaN field.
+ absResult = (dst_rep_t)dstInfExp << dstSigBits;
+ absResult |= dstQNaN;
+ absResult |= ((aAbs & srcNaNCode) >> (srcSigBits - dstSigBits)) & dstNaNCode;
+ }
+ else if (aAbs > overflow) {
+ // a overflows to infinity.
+ absResult = (dst_rep_t)dstInfExp << dstSigBits;
+ }
+ else {
+ // a underflows on conversion to the destination type or is an exact
+ // zero. The result may be a denormal or zero. Extract the exponent
+ // to get the shift amount for the denormalization.
+ const int aExp = aAbs >> srcSigBits;
+ const int shift = srcExpBias - dstExpBias - aExp + 1;
+
+ const src_rep_t significand = (aRep & srcSignificandMask) | srcMinNormal;
+
+ // Right shift by the denormalization amount with sticky.
+ if (shift > srcSigBits) {
+ absResult = 0;
+ } else {
+ const bool sticky = significand << (srcBits - shift);
+ src_rep_t denormalizedSignificand = significand >> shift | sticky;
+ absResult = denormalizedSignificand >> (srcSigBits - dstSigBits);
+ const src_rep_t roundBits = denormalizedSignificand & roundMask;
+ // Round to nearest
+ if (roundBits > halfway)
+ absResult++;
+ // Ties to even
+ else if (roundBits == halfway)
+ absResult += absResult & 1;
+ }
+ }
+
+ // Apply the signbit to (dst_t)abs(a).
+ const dst_rep_t result = absResult | sign >> (srcBits - dstBits);
+ return dstFromRep(result);
+}
diff --git a/lib/builtins/gcc_personality_v0.c b/lib/builtins/gcc_personality_v0.c
new file mode 100644
index 000000000000..869f4178e853
--- /dev/null
+++ b/lib/builtins/gcc_personality_v0.c
@@ -0,0 +1,249 @@
+/* ===-- gcc_personality_v0.c - Implement __gcc_personality_v0 -------------===
+ *
+ * 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 "int_lib.h"
+
+/*
+ * _Unwind_* stuff based on C++ ABI public documentation
+ * http://refspecs.freestandards.org/abi-eh-1.21.html
+ */
+
+typedef enum {
+ _URC_NO_REASON = 0,
+ _URC_FOREIGN_EXCEPTION_CAUGHT = 1,
+ _URC_FATAL_PHASE2_ERROR = 2,
+ _URC_FATAL_PHASE1_ERROR = 3,
+ _URC_NORMAL_STOP = 4,
+ _URC_END_OF_STACK = 5,
+ _URC_HANDLER_FOUND = 6,
+ _URC_INSTALL_CONTEXT = 7,
+ _URC_CONTINUE_UNWIND = 8
+} _Unwind_Reason_Code;
+
+typedef enum {
+ _UA_SEARCH_PHASE = 1,
+ _UA_CLEANUP_PHASE = 2,
+ _UA_HANDLER_FRAME = 4,
+ _UA_FORCE_UNWIND = 8,
+ _UA_END_OF_STACK = 16
+} _Unwind_Action;
+
+typedef struct _Unwind_Context* _Unwind_Context_t;
+
+struct _Unwind_Exception {
+ uint64_t exception_class;
+ void (*exception_cleanup)(_Unwind_Reason_Code reason,
+ struct _Unwind_Exception* exc);
+ uintptr_t private_1;
+ uintptr_t private_2;
+};
+
+COMPILER_RT_ABI const uint8_t* _Unwind_GetLanguageSpecificData(_Unwind_Context_t c);
+COMPILER_RT_ABI void _Unwind_SetGR(_Unwind_Context_t c, int i, uintptr_t n);
+COMPILER_RT_ABI void _Unwind_SetIP(_Unwind_Context_t, uintptr_t new_value);
+COMPILER_RT_ABI uintptr_t _Unwind_GetIP(_Unwind_Context_t context);
+COMPILER_RT_ABI uintptr_t _Unwind_GetRegionStart(_Unwind_Context_t context);
+
+
+/*
+ * Pointer encodings documented at:
+ * http://refspecs.freestandards.org/LSB_1.3.0/gLSB/gLSB/ehframehdr.html
+ */
+
+#define DW_EH_PE_omit 0xff /* no data follows */
+
+#define DW_EH_PE_absptr 0x00
+#define DW_EH_PE_uleb128 0x01
+#define DW_EH_PE_udata2 0x02
+#define DW_EH_PE_udata4 0x03
+#define DW_EH_PE_udata8 0x04
+#define DW_EH_PE_sleb128 0x09
+#define DW_EH_PE_sdata2 0x0A
+#define DW_EH_PE_sdata4 0x0B
+#define DW_EH_PE_sdata8 0x0C
+
+#define DW_EH_PE_pcrel 0x10
+#define DW_EH_PE_textrel 0x20
+#define DW_EH_PE_datarel 0x30
+#define DW_EH_PE_funcrel 0x40
+#define DW_EH_PE_aligned 0x50
+#define DW_EH_PE_indirect 0x80 /* gcc extension */
+
+
+
+/* read a uleb128 encoded value and advance pointer */
+static uintptr_t readULEB128(const uint8_t** data)
+{
+ uintptr_t result = 0;
+ uintptr_t shift = 0;
+ unsigned char byte;
+ const uint8_t* p = *data;
+ do {
+ byte = *p++;
+ result |= (byte & 0x7f) << shift;
+ shift += 7;
+ } while (byte & 0x80);
+ *data = p;
+ return result;
+}
+
+/* read a pointer encoded value and advance pointer */
+static uintptr_t readEncodedPointer(const uint8_t** data, uint8_t encoding)
+{
+ const uint8_t* p = *data;
+ uintptr_t result = 0;
+
+ if ( encoding == DW_EH_PE_omit )
+ return 0;
+
+ /* first get value */
+ switch (encoding & 0x0F) {
+ case DW_EH_PE_absptr:
+ result = *((const uintptr_t*)p);
+ p += sizeof(uintptr_t);
+ break;
+ case DW_EH_PE_uleb128:
+ result = readULEB128(&p);
+ break;
+ case DW_EH_PE_udata2:
+ result = *((const uint16_t*)p);
+ p += sizeof(uint16_t);
+ break;
+ case DW_EH_PE_udata4:
+ result = *((const uint32_t*)p);
+ p += sizeof(uint32_t);
+ break;
+ case DW_EH_PE_udata8:
+ result = *((const uint64_t*)p);
+ p += sizeof(uint64_t);
+ break;
+ case DW_EH_PE_sdata2:
+ result = *((const int16_t*)p);
+ p += sizeof(int16_t);
+ break;
+ case DW_EH_PE_sdata4:
+ result = *((const int32_t*)p);
+ p += sizeof(int32_t);
+ break;
+ case DW_EH_PE_sdata8:
+ result = *((const int64_t*)p);
+ p += sizeof(int64_t);
+ break;
+ case DW_EH_PE_sleb128:
+ default:
+ /* not supported */
+ compilerrt_abort();
+ break;
+ }
+
+ /* then add relative offset */
+ switch ( encoding & 0x70 ) {
+ case DW_EH_PE_absptr:
+ /* do nothing */
+ break;
+ case DW_EH_PE_pcrel:
+ result += (uintptr_t)(*data);
+ break;
+ case DW_EH_PE_textrel:
+ case DW_EH_PE_datarel:
+ case DW_EH_PE_funcrel:
+ case DW_EH_PE_aligned:
+ default:
+ /* not supported */
+ compilerrt_abort();
+ break;
+ }
+
+ /* then apply indirection */
+ if (encoding & DW_EH_PE_indirect) {
+ result = *((const uintptr_t*)result);
+ }
+
+ *data = p;
+ return result;
+}
+
+
+/*
+ * The C compiler makes references to __gcc_personality_v0 in
+ * the dwarf unwind information for translation units that use
+ * __attribute__((cleanup(xx))) on local variables.
+ * This personality routine is called by the system unwinder
+ * on each frame as the stack is unwound during a C++ exception
+ * throw through a C function compiled with -fexceptions.
+ */
+#if __USING_SJLJ_EXCEPTIONS__
+// 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,
+ _Unwind_Context_t context)
+#else
+COMPILER_RT_ABI _Unwind_Reason_Code
+__gcc_personality_v0(int version, _Unwind_Action actions,
+ uint64_t exceptionClass, struct _Unwind_Exception* exceptionObject,
+ _Unwind_Context_t context)
+#endif
+{
+ /* Since C does not have catch clauses, there is nothing to do during */
+ /* phase 1 (the search phase). */
+ if ( actions & _UA_SEARCH_PHASE )
+ return _URC_CONTINUE_UNWIND;
+
+ /* There is nothing to do if there is no LSDA for this frame. */
+ const uint8_t* lsda = _Unwind_GetLanguageSpecificData(context);
+ if ( lsda == (uint8_t*) 0 )
+ return _URC_CONTINUE_UNWIND;
+
+ uintptr_t pc = _Unwind_GetIP(context)-1;
+ uintptr_t funcStart = _Unwind_GetRegionStart(context);
+ uintptr_t pcOffset = pc - funcStart;
+
+ /* Parse LSDA header. */
+ uint8_t lpStartEncoding = *lsda++;
+ if (lpStartEncoding != DW_EH_PE_omit) {
+ readEncodedPointer(&lsda, lpStartEncoding);
+ }
+ uint8_t ttypeEncoding = *lsda++;
+ if (ttypeEncoding != DW_EH_PE_omit) {
+ readULEB128(&lsda);
+ }
+ /* Walk call-site table looking for range that includes current PC. */
+ uint8_t callSiteEncoding = *lsda++;
+ uint32_t callSiteTableLength = readULEB128(&lsda);
+ const uint8_t* callSiteTableStart = lsda;
+ const uint8_t* callSiteTableEnd = callSiteTableStart + callSiteTableLength;
+ const uint8_t* p=callSiteTableStart;
+ while (p < callSiteTableEnd) {
+ uintptr_t start = readEncodedPointer(&p, callSiteEncoding);
+ uintptr_t length = readEncodedPointer(&p, callSiteEncoding);
+ uintptr_t landingPad = readEncodedPointer(&p, callSiteEncoding);
+ readULEB128(&p); /* action value not used for C code */
+ if ( landingPad == 0 )
+ continue; /* no landing pad for this entry */
+ if ( (start <= pcOffset) && (pcOffset < (start+length)) ) {
+ /* Found landing pad for the PC.
+ * 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(1), 0);
+ _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/Makefile.mk b/lib/builtins/i386/Makefile.mk
new file mode 100644
index 000000000000..f3776a02c0de
--- /dev/null
+++ b/lib/builtins/i386/Makefile.mk
@@ -0,0 +1,20 @@
+#===- lib/builtins/i386/Makefile.mk ------------------------*- Makefile -*--===#
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+
+ModuleName := builtins
+SubDirs :=
+OnlyArchs := i386
+
+AsmSources := $(foreach file,$(wildcard $(Dir)/*.S),$(notdir $(file)))
+Sources := $(foreach file,$(wildcard $(Dir)/*.c),$(notdir $(file)))
+ObjNames := $(Sources:%.c=%.o) $(AsmSources:%.S=%.o)
+Implementation := Optimized
+
+# FIXME: use automatic dependencies?
+Dependencies := $(wildcard lib/*.h $(Dir)/*.h)
diff --git a/lib/builtins/i386/ashldi3.S b/lib/builtins/i386/ashldi3.S
new file mode 100644
index 000000000000..3fbd73903842
--- /dev/null
+++ b/lib/builtins/i386/ashldi3.S
@@ -0,0 +1,58 @@
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+
+#include "../assembly.h"
+
+// di_int __ashldi3(di_int input, int count);
+
+// This routine has some extra memory traffic, loading the 64-bit input via two
+// 32-bit loads, then immediately storing it back to the stack via a single 64-bit
+// store. This is to avoid a write-small, read-large stall.
+// However, if callers of this routine can be safely assumed to store the argument
+// via a 64-bt store, this is unnecessary memory traffic, and should be avoided.
+// It can be turned off by defining the TRUST_CALLERS_USE_64_BIT_STORES macro.
+
+#ifdef __i386__
+#ifdef __SSE2__
+
+.text
+.balign 4
+DEFINE_COMPILERRT_FUNCTION(__ashldi3)
+ movd 12(%esp), %xmm2 // Load count
+#ifndef TRUST_CALLERS_USE_64_BIT_STORES
+ movd 4(%esp), %xmm0
+ movd 8(%esp), %xmm1
+ punpckldq %xmm1, %xmm0 // Load input
+#else
+ movq 4(%esp), %xmm0 // Load input
+#endif
+ psllq %xmm2, %xmm0 // shift input by count
+ movd %xmm0, %eax
+ psrlq $32, %xmm0
+ movd %xmm0, %edx
+ ret
+END_COMPILERRT_FUNCTION(__ashldi3)
+
+#else // Use GPRs instead of SSE2 instructions, if they aren't available.
+
+.text
+.balign 4
+DEFINE_COMPILERRT_FUNCTION(__ashldi3)
+ movl 12(%esp), %ecx // Load count
+ movl 8(%esp), %edx // Load high
+ movl 4(%esp), %eax // Load low
+
+ testl $0x20, %ecx // If count >= 32
+ jnz 1f // goto 1
+ shldl %cl, %eax, %edx // left shift high by count
+ shll %cl, %eax // left shift low by count
+ ret
+
+1: movl %eax, %edx // Move low to high
+ xorl %eax, %eax // clear low
+ shll %cl, %edx // shift high by count - 32
+ ret
+END_COMPILERRT_FUNCTION(__ashldi3)
+
+#endif // __SSE2__
+#endif // __i386__
diff --git a/lib/builtins/i386/ashrdi3.S b/lib/builtins/i386/ashrdi3.S
new file mode 100644
index 000000000000..8f4742481b42
--- /dev/null
+++ b/lib/builtins/i386/ashrdi3.S
@@ -0,0 +1,69 @@
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+
+#include "../assembly.h"
+
+// di_int __ashrdi3(di_int input, int count);
+
+#ifdef __i386__
+#ifdef __SSE2__
+
+.text
+.balign 4
+DEFINE_COMPILERRT_FUNCTION(__ashrdi3)
+ movd 12(%esp), %xmm2 // Load count
+ movl 8(%esp), %eax
+#ifndef TRUST_CALLERS_USE_64_BIT_STORES
+ movd 4(%esp), %xmm0
+ movd 8(%esp), %xmm1
+ punpckldq %xmm1, %xmm0 // Load input
+#else
+ movq 4(%esp), %xmm0 // Load input
+#endif
+
+ psrlq %xmm2, %xmm0 // unsigned shift input by count
+
+ testl %eax, %eax // check the sign-bit of the input
+ jns 1f // early out for positive inputs
+
+ // If the input is negative, we need to construct the shifted sign bit
+ // to or into the result, as xmm does not have a signed right shift.
+ pcmpeqb %xmm1, %xmm1 // -1ULL
+ psrlq $58, %xmm1 // 0x3f
+ pandn %xmm1, %xmm2 // 63 - count
+ pcmpeqb %xmm1, %xmm1 // -1ULL
+ psubq %xmm1, %xmm2 // 64 - count
+ psllq %xmm2, %xmm1 // -1 << (64 - count) = leading sign bits
+ por %xmm1, %xmm0
+
+ // Move the result back to the general purpose registers and return
+1: movd %xmm0, %eax
+ psrlq $32, %xmm0
+ movd %xmm0, %edx
+ ret
+END_COMPILERRT_FUNCTION(__ashrdi3)
+
+#else // Use GPRs instead of SSE2 instructions, if they aren't available.
+
+.text
+.balign 4
+DEFINE_COMPILERRT_FUNCTION(__ashrdi3)
+ movl 12(%esp), %ecx // Load count
+ movl 8(%esp), %edx // Load high
+ movl 4(%esp), %eax // Load low
+
+ testl $0x20, %ecx // If count >= 32
+ jnz 1f // goto 1
+
+ shrdl %cl, %edx, %eax // right shift low by count
+ sarl %cl, %edx // right shift high by count
+ ret
+
+1: movl %edx, %eax // Move high to low
+ sarl $31, %edx // clear high
+ sarl %cl, %eax // shift low by count - 32
+ ret
+END_COMPILERRT_FUNCTION(__ashrdi3)
+
+#endif // __SSE2__
+#endif // __i386__
diff --git a/lib/builtins/i386/divdi3.S b/lib/builtins/i386/divdi3.S
new file mode 100644
index 000000000000..2cb0ddd4c29f
--- /dev/null
+++ b/lib/builtins/i386/divdi3.S
@@ -0,0 +1,162 @@
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+
+#include "../assembly.h"
+
+// di_int __divdi3(di_int a, di_int b);
+
+// result = a / b.
+// both inputs and the output are 64-bit signed integers.
+// This will do whatever the underlying hardware is set to do on division by zero.
+// No other exceptions are generated, as the divide cannot overflow.
+//
+// This is targeted at 32-bit x86 *only*, as this can be done directly in hardware
+// on x86_64. The performance goal is ~40 cycles per divide, which is faster than
+// currently possible via simulation of integer divides on the x87 unit.
+//
+// Stephen Canon, December 2008
+
+#ifdef __i386__
+
+.text
+.balign 4
+DEFINE_COMPILERRT_FUNCTION(__divdi3)
+
+/* This is currently implemented by wrapping the unsigned divide up in an absolute
+ value, then restoring the correct sign at the end of the computation. This could
+ certainly be improved upon. */
+
+ pushl %esi
+ movl 20(%esp), %edx // high word of b
+ movl 16(%esp), %eax // low word of b
+ movl %edx, %ecx
+ sarl $31, %ecx // (b < 0) ? -1 : 0
+ xorl %ecx, %eax
+ xorl %ecx, %edx // EDX:EAX = (b < 0) ? not(b) : b
+ subl %ecx, %eax
+ sbbl %ecx, %edx // EDX:EAX = abs(b)
+ movl %edx, 20(%esp)
+ movl %eax, 16(%esp) // store abs(b) back to stack
+ movl %ecx, %esi // set aside sign of b
+
+ movl 12(%esp), %edx // high word of b
+ movl 8(%esp), %eax // low word of b
+ movl %edx, %ecx
+ sarl $31, %ecx // (a < 0) ? -1 : 0
+ xorl %ecx, %eax
+ xorl %ecx, %edx // EDX:EAX = (a < 0) ? not(a) : a
+ subl %ecx, %eax
+ sbbl %ecx, %edx // EDX:EAX = abs(a)
+ movl %edx, 12(%esp)
+ movl %eax, 8(%esp) // store abs(a) back to stack
+ xorl %ecx, %esi // sign of result = (sign of a) ^ (sign of b)
+
+ pushl %ebx
+ movl 24(%esp), %ebx // Find the index i of the leading bit in b.
+ bsrl %ebx, %ecx // If the high word of b is zero, jump to
+ jz 9f // the code to handle that special case [9].
+
+ /* High word of b is known to be non-zero on this branch */
+
+ movl 20(%esp), %eax // Construct bhi, containing bits [1+i:32+i] of b
+
+ shrl %cl, %eax // Practically, this means that bhi is given by:
+ shrl %eax //
+ notl %ecx // bhi = (high word of b) << (31 - i) |
+ shll %cl, %ebx // (low word of b) >> (1 + i)
+ orl %eax, %ebx //
+ movl 16(%esp), %edx // Load the high and low words of a, and jump
+ movl 12(%esp), %eax // to [1] if the high word is larger than bhi
+ cmpl %ebx, %edx // to avoid overflowing the upcoming divide.
+ jae 1f
+
+ /* High word of a is greater than or equal to (b >> (1 + i)) on this branch */
+
+ divl %ebx // eax <-- qs, edx <-- r such that ahi:alo = bs*qs + r
+
+ pushl %edi
+ notl %ecx
+ shrl %eax
+ shrl %cl, %eax // q = qs >> (1 + i)
+ movl %eax, %edi
+ mull 24(%esp) // q*blo
+ movl 16(%esp), %ebx
+ movl 20(%esp), %ecx // ECX:EBX = a
+ subl %eax, %ebx
+ sbbl %edx, %ecx // ECX:EBX = a - q*blo
+ movl 28(%esp), %eax
+ imull %edi, %eax // q*bhi
+ subl %eax, %ecx // ECX:EBX = a - q*b
+ sbbl $0, %edi // decrement q if remainder is negative
+ xorl %edx, %edx
+ movl %edi, %eax
+
+ addl %esi, %eax // Restore correct sign to result
+ adcl %esi, %edx
+ xorl %esi, %eax
+ xorl %esi, %edx
+ popl %edi // Restore callee-save registers
+ popl %ebx
+ popl %esi
+ retl // Return
+
+
+1: /* High word of a is greater than or equal to (b >> (1 + i)) on this branch */
+
+ subl %ebx, %edx // subtract bhi from ahi so that divide will not
+ divl %ebx // overflow, and find q and r such that
+ //
+ // ahi:alo = (1:q)*bhi + r
+ //
+ // Note that q is a number in (31-i).(1+i)
+ // fix point.
+
+ pushl %edi
+ notl %ecx
+ shrl %eax
+ orl $0x80000000, %eax
+ shrl %cl, %eax // q = (1:qs) >> (1 + i)
+ movl %eax, %edi
+ mull 24(%esp) // q*blo
+ movl 16(%esp), %ebx
+ movl 20(%esp), %ecx // ECX:EBX = a
+ subl %eax, %ebx
+ sbbl %edx, %ecx // ECX:EBX = a - q*blo
+ movl 28(%esp), %eax
+ imull %edi, %eax // q*bhi
+ subl %eax, %ecx // ECX:EBX = a - q*b
+ sbbl $0, %edi // decrement q if remainder is negative
+ xorl %edx, %edx
+ movl %edi, %eax
+
+ addl %esi, %eax // Restore correct sign to result
+ adcl %esi, %edx
+ xorl %esi, %eax
+ xorl %esi, %edx
+ popl %edi // Restore callee-save registers
+ popl %ebx
+ popl %esi
+ retl // Return
+
+
+9: /* High word of b is zero on this branch */
+
+ movl 16(%esp), %eax // Find qhi and rhi such that
+ movl 20(%esp), %ecx //
+ xorl %edx, %edx // ahi = qhi*b + rhi with 0 ≤ rhi < b
+ divl %ecx //
+ movl %eax, %ebx //
+ movl 12(%esp), %eax // Find qlo such that
+ divl %ecx //
+ movl %ebx, %edx // rhi:alo = qlo*b + rlo with 0 ≤ rlo < b
+
+ addl %esi, %eax // Restore correct sign to result
+ adcl %esi, %edx
+ xorl %esi, %eax
+ xorl %esi, %edx
+ popl %ebx // Restore callee-save registers
+ popl %esi
+ retl // Return
+END_COMPILERRT_FUNCTION(__divdi3)
+
+#endif // __i386__
diff --git a/lib/builtins/i386/floatdidf.S b/lib/builtins/i386/floatdidf.S
new file mode 100644
index 000000000000..dcc32f8ed85d
--- /dev/null
+++ b/lib/builtins/i386/floatdidf.S
@@ -0,0 +1,39 @@
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+
+#include "../assembly.h"
+
+// double __floatundidf(du_int a);
+
+#ifdef __i386__
+
+CONST_SECTION
+
+ .balign 16
+twop52:
+ .quad 0x4330000000000000
+
+ .balign 16
+twop32:
+ .quad 0x41f0000000000000
+
+#define REL_ADDR(_a) (_a)-0b(%eax)
+
+.text
+.balign 4
+DEFINE_COMPILERRT_FUNCTION(__floatdidf)
+ cvtsi2sd 8(%esp), %xmm1
+ movss 4(%esp), %xmm0 // low 32 bits of a
+ calll 0f
+0: popl %eax
+ mulsd REL_ADDR(twop32), %xmm1 // a_hi as a double (without rounding)
+ movsd REL_ADDR(twop52), %xmm2 // 0x1.0p52
+ subsd %xmm2, %xmm1 // a_hi - 0x1p52 (no rounding occurs)
+ orpd %xmm2, %xmm0 // 0x1p52 + a_lo (no rounding occurs)
+ addsd %xmm1, %xmm0 // a_hi + a_lo (round happens here)
+ movsd %xmm0, 4(%esp)
+ fldl 4(%esp)
+ ret
+END_COMPILERRT_FUNCTION(__floatdidf)
+
+#endif // __i386__
diff --git a/lib/builtins/i386/floatdisf.S b/lib/builtins/i386/floatdisf.S
new file mode 100644
index 000000000000..f64276703607
--- /dev/null
+++ b/lib/builtins/i386/floatdisf.S
@@ -0,0 +1,32 @@
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+
+#include "../assembly.h"
+
+// float __floatdisf(di_int a);
+
+// This routine has some extra memory traffic, loading the 64-bit input via two
+// 32-bit loads, then immediately storing it back to the stack via a single 64-bit
+// store. This is to avoid a write-small, read-large stall.
+// However, if callers of this routine can be safely assumed to store the argument
+// via a 64-bt store, this is unnecessary memory traffic, and should be avoided.
+// It can be turned off by defining the TRUST_CALLERS_USE_64_BIT_STORES macro.
+
+#ifdef __i386__
+
+.text
+.balign 4
+DEFINE_COMPILERRT_FUNCTION(__floatdisf)
+#ifndef TRUST_CALLERS_USE_64_BIT_STORES
+ movd 4(%esp), %xmm0
+ movd 8(%esp), %xmm1
+ punpckldq %xmm1, %xmm0
+ movq %xmm0, 4(%esp)
+#endif
+ fildll 4(%esp)
+ fstps 4(%esp)
+ flds 4(%esp)
+ ret
+END_COMPILERRT_FUNCTION(__floatdisf)
+
+#endif // __i386__
diff --git a/lib/builtins/i386/floatdixf.S b/lib/builtins/i386/floatdixf.S
new file mode 100644
index 000000000000..839b0434c0c6
--- /dev/null
+++ b/lib/builtins/i386/floatdixf.S
@@ -0,0 +1,30 @@
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+
+#include "../assembly.h"
+
+// float __floatdixf(di_int a);
+
+#ifdef __i386__
+
+// This routine has some extra memory traffic, loading the 64-bit input via two
+// 32-bit loads, then immediately storing it back to the stack via a single 64-bit
+// store. This is to avoid a write-small, read-large stall.
+// However, if callers of this routine can be safely assumed to store the argument
+// via a 64-bt store, this is unnecessary memory traffic, and should be avoided.
+// It can be turned off by defining the TRUST_CALLERS_USE_64_BIT_STORES macro.
+
+.text
+.balign 4
+DEFINE_COMPILERRT_FUNCTION(__floatdixf)
+#ifndef TRUST_CALLERS_USE_64_BIT_STORES
+ movd 4(%esp), %xmm0
+ movd 8(%esp), %xmm1
+ punpckldq %xmm1, %xmm0
+ movq %xmm0, 4(%esp)
+#endif
+ fildll 4(%esp)
+ ret
+END_COMPILERRT_FUNCTION(__floatdixf)
+
+#endif // __i386__
diff --git a/lib/builtins/i386/floatundidf.S b/lib/builtins/i386/floatundidf.S
new file mode 100644
index 000000000000..8058c2ac0aed
--- /dev/null
+++ b/lib/builtins/i386/floatundidf.S
@@ -0,0 +1,52 @@
+//===-- floatundidf.S - Implement __floatundidf for i386 ------------------===//
+//
+// 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 __floatundidf for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+// double __floatundidf(du_int a);
+
+#ifdef __i386__
+
+CONST_SECTION
+
+ .balign 16
+twop52:
+ .quad 0x4330000000000000
+
+ .balign 16
+twop84_plus_twop52:
+ .quad 0x4530000000100000
+
+ .balign 16
+twop84:
+ .quad 0x4530000000000000
+
+#define REL_ADDR(_a) (_a)-0b(%eax)
+
+.text
+.balign 4
+DEFINE_COMPILERRT_FUNCTION(__floatundidf)
+ movss 8(%esp), %xmm1 // high 32 bits of a
+ movss 4(%esp), %xmm0 // low 32 bits of a
+ calll 0f
+0: popl %eax
+ orpd REL_ADDR(twop84), %xmm1 // 0x1p84 + a_hi (no rounding occurs)
+ subsd REL_ADDR(twop84_plus_twop52), %xmm1 // a_hi - 0x1p52 (no rounding occurs)
+ orpd REL_ADDR(twop52), %xmm0 // 0x1p52 + a_lo (no rounding occurs)
+ addsd %xmm1, %xmm0 // a_hi + a_lo (round happens here)
+ movsd %xmm0, 4(%esp)
+ fldl 4(%esp)
+ ret
+END_COMPILERRT_FUNCTION(__floatundidf)
+
+#endif // __i386__
diff --git a/lib/builtins/i386/floatundisf.S b/lib/builtins/i386/floatundisf.S
new file mode 100644
index 000000000000..94c97e25aa8c
--- /dev/null
+++ b/lib/builtins/i386/floatundisf.S
@@ -0,0 +1,105 @@
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+
+#include "../assembly.h"
+
+// float __floatundisf(du_int a);
+
+// Note that there is a hardware instruction, fildll, that does most of what
+// this function needs to do. However, because of our ia32 ABI, it will take
+// a write-small read-large stall, so the software implementation here is
+// actually several cycles faster.
+
+// This is a branch-free implementation. A branchy implementation might be
+// faster for the common case if you know something a priori about the input
+// distribution.
+
+/* branch-free x87 implementation - one cycle slower than without x87.
+
+#ifdef __i386__
+
+CONST_SECTION
+.balign 3
+
+ .quad 0x43f0000000000000
+twop64: .quad 0x0000000000000000
+
+#define TWOp64 twop64-0b(%ecx,%eax,8)
+
+.text
+.balign 4
+DEFINE_COMPILERRT_FUNCTION(__floatundisf)
+ movl 8(%esp), %eax
+ movd 8(%esp), %xmm1
+ movd 4(%esp), %xmm0
+ punpckldq %xmm1, %xmm0
+ calll 0f
+0: popl %ecx
+ sarl $31, %eax
+ movq %xmm0, 4(%esp)
+ fildll 4(%esp)
+ faddl TWOp64
+ fstps 4(%esp)
+ flds 4(%esp)
+ ret
+END_COMPILERRT_FUNCTION(__floatundisf)
+
+#endif // __i386__
+
+*/
+
+/* branch-free, x87-free implementation - faster at the expense of code size */
+
+#ifdef __i386__
+
+CONST_SECTION
+
+ .balign 16
+twop52:
+ .quad 0x4330000000000000
+ .quad 0x0000000000000fff
+
+ .balign 16
+sticky:
+ .quad 0x0000000000000000
+ .long 0x00000012
+
+ .balign 16
+twelve:
+ .long 0x00000000
+
+#define TWOp52 twop52-0b(%ecx)
+#define STICKY sticky-0b(%ecx,%eax,8)
+
+.text
+.balign 4
+DEFINE_COMPILERRT_FUNCTION(__floatundisf)
+ movl 8(%esp), %eax
+ movd 8(%esp), %xmm1
+ movd 4(%esp), %xmm0
+ punpckldq %xmm1, %xmm0
+
+ calll 0f
+0: popl %ecx
+ shrl %eax // high 31 bits of input as sint32
+ addl $0x7ff80000, %eax
+ sarl $31, %eax // (big input) ? -1 : 0
+ movsd STICKY, %xmm1 // (big input) ? 0xfff : 0
+ movl $12, %edx
+ andl %eax, %edx // (big input) ? 12 : 0
+ movd %edx, %xmm3
+ andpd %xmm0, %xmm1 // (big input) ? input & 0xfff : 0
+ movsd TWOp52, %xmm2 // 0x1.0p52
+ psrlq %xmm3, %xmm0 // (big input) ? input >> 12 : input
+ orpd %xmm2, %xmm1 // 0x1.0p52 + ((big input) ? input & 0xfff : input)
+ orpd %xmm1, %xmm0 // 0x1.0p52 + ((big input) ? (input >> 12 | input & 0xfff) : input)
+ subsd %xmm2, %xmm0 // (double)((big input) ? (input >> 12 | input & 0xfff) : input)
+ cvtsd2ss %xmm0, %xmm0 // (float)((big input) ? (input >> 12 | input & 0xfff) : input)
+ pslld $23, %xmm3
+ paddd %xmm3, %xmm0 // (float)input
+ movd %xmm0, 4(%esp)
+ flds 4(%esp)
+ ret
+END_COMPILERRT_FUNCTION(__floatundisf)
+
+#endif // __i386__
diff --git a/lib/builtins/i386/floatundixf.S b/lib/builtins/i386/floatundixf.S
new file mode 100644
index 000000000000..814b52f941d8
--- /dev/null
+++ b/lib/builtins/i386/floatundixf.S
@@ -0,0 +1,43 @@
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+
+#include "../assembly.h"
+
+// long double __floatundixf(du_int a);16
+
+#ifdef __i386__
+
+CONST_SECTION
+
+ .balign 16
+twop52:
+ .quad 0x4330000000000000
+
+ .balign 16
+twop84_plus_twop52_neg:
+ .quad 0xc530000000100000
+
+ .balign 16
+twop84:
+ .quad 0x4530000000000000
+
+#define REL_ADDR(_a) (_a)-0b(%eax)
+
+.text
+.balign 4
+DEFINE_COMPILERRT_FUNCTION(__floatundixf)
+ calll 0f
+0: popl %eax
+ movss 8(%esp), %xmm0 // hi 32 bits of input
+ movss 4(%esp), %xmm1 // lo 32 bits of input
+ orpd REL_ADDR(twop84), %xmm0 // 2^84 + hi (as a double)
+ orpd REL_ADDR(twop52), %xmm1 // 2^52 + lo (as a double)
+ addsd REL_ADDR(twop84_plus_twop52_neg), %xmm0 // hi - 2^52 (no rounding occurs)
+ movsd %xmm1, 4(%esp)
+ fldl 4(%esp)
+ movsd %xmm0, 4(%esp)
+ faddl 4(%esp)
+ ret
+END_COMPILERRT_FUNCTION(__floatundixf)
+
+#endif // __i386__
diff --git a/lib/builtins/i386/lshrdi3.S b/lib/builtins/i386/lshrdi3.S
new file mode 100644
index 000000000000..b80f11a3806b
--- /dev/null
+++ b/lib/builtins/i386/lshrdi3.S
@@ -0,0 +1,59 @@
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+
+#include "../assembly.h"
+
+// di_int __lshrdi3(di_int input, int count);
+
+// This routine has some extra memory traffic, loading the 64-bit input via two
+// 32-bit loads, then immediately storing it back to the stack via a single 64-bit
+// store. This is to avoid a write-small, read-large stall.
+// However, if callers of this routine can be safely assumed to store the argument
+// via a 64-bt store, this is unnecessary memory traffic, and should be avoided.
+// It can be turned off by defining the TRUST_CALLERS_USE_64_BIT_STORES macro.
+
+#ifdef __i386__
+#ifdef __SSE2__
+
+.text
+.balign 4
+DEFINE_COMPILERRT_FUNCTION(__lshrdi3)
+ movd 12(%esp), %xmm2 // Load count
+#ifndef TRUST_CALLERS_USE_64_BIT_STORES
+ movd 4(%esp), %xmm0
+ movd 8(%esp), %xmm1
+ punpckldq %xmm1, %xmm0 // Load input
+#else
+ movq 4(%esp), %xmm0 // Load input
+#endif
+ psrlq %xmm2, %xmm0 // shift input by count
+ movd %xmm0, %eax
+ psrlq $32, %xmm0
+ movd %xmm0, %edx
+ ret
+END_COMPILERRT_FUNCTION(__lshrdi3)
+
+#else // Use GPRs instead of SSE2 instructions, if they aren't available.
+
+.text
+.balign 4
+DEFINE_COMPILERRT_FUNCTION(__lshrdi3)
+ movl 12(%esp), %ecx // Load count
+ movl 8(%esp), %edx // Load high
+ movl 4(%esp), %eax // Load low
+
+ testl $0x20, %ecx // If count >= 32
+ jnz 1f // goto 1
+
+ shrdl %cl, %edx, %eax // right shift low by count
+ shrl %cl, %edx // right shift high by count
+ ret
+
+1: movl %edx, %eax // Move high to low
+ xorl %edx, %edx // clear high
+ shrl %cl, %eax // shift low by count - 32
+ ret
+END_COMPILERRT_FUNCTION(__lshrdi3)
+
+#endif // __SSE2__
+#endif // __i386__
diff --git a/lib/builtins/i386/moddi3.S b/lib/builtins/i386/moddi3.S
new file mode 100644
index 000000000000..b9cee9d7aa70
--- /dev/null
+++ b/lib/builtins/i386/moddi3.S
@@ -0,0 +1,166 @@
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+
+#include "../assembly.h"
+
+// di_int __moddi3(di_int a, di_int b);
+
+// result = remainder of a / b.
+// both inputs and the output are 64-bit signed integers.
+// This will do whatever the underlying hardware is set to do on division by zero.
+// No other exceptions are generated, as the divide cannot overflow.
+//
+// This is targeted at 32-bit x86 *only*, as this can be done directly in hardware
+// on x86_64. The performance goal is ~40 cycles per divide, which is faster than
+// currently possible via simulation of integer divides on the x87 unit.
+//
+
+// Stephen Canon, December 2008
+
+#ifdef __i386__
+
+.text
+.balign 4
+DEFINE_COMPILERRT_FUNCTION(__moddi3)
+
+/* This is currently implemented by wrapping the unsigned modulus up in an absolute
+ value. This could certainly be improved upon. */
+
+ pushl %esi
+ movl 20(%esp), %edx // high word of b
+ movl 16(%esp), %eax // low word of b
+ movl %edx, %ecx
+ sarl $31, %ecx // (b < 0) ? -1 : 0
+ xorl %ecx, %eax
+ xorl %ecx, %edx // EDX:EAX = (b < 0) ? not(b) : b
+ subl %ecx, %eax
+ sbbl %ecx, %edx // EDX:EAX = abs(b)
+ movl %edx, 20(%esp)
+ movl %eax, 16(%esp) // store abs(b) back to stack
+
+ movl 12(%esp), %edx // high word of b
+ movl 8(%esp), %eax // low word of b
+ movl %edx, %ecx
+ sarl $31, %ecx // (a < 0) ? -1 : 0
+ xorl %ecx, %eax
+ xorl %ecx, %edx // EDX:EAX = (a < 0) ? not(a) : a
+ subl %ecx, %eax
+ sbbl %ecx, %edx // EDX:EAX = abs(a)
+ movl %edx, 12(%esp)
+ movl %eax, 8(%esp) // store abs(a) back to stack
+ movl %ecx, %esi // set aside sign of a
+
+ pushl %ebx
+ movl 24(%esp), %ebx // Find the index i of the leading bit in b.
+ bsrl %ebx, %ecx // If the high word of b is zero, jump to
+ jz 9f // the code to handle that special case [9].
+
+ /* High word of b is known to be non-zero on this branch */
+
+ movl 20(%esp), %eax // Construct bhi, containing bits [1+i:32+i] of b
+
+ shrl %cl, %eax // Practically, this means that bhi is given by:
+ shrl %eax //
+ notl %ecx // bhi = (high word of b) << (31 - i) |
+ shll %cl, %ebx // (low word of b) >> (1 + i)
+ orl %eax, %ebx //
+ movl 16(%esp), %edx // Load the high and low words of a, and jump
+ movl 12(%esp), %eax // to [2] if the high word is larger than bhi
+ cmpl %ebx, %edx // to avoid overflowing the upcoming divide.
+ jae 2f
+
+ /* High word of a is greater than or equal to (b >> (1 + i)) on this branch */
+
+ divl %ebx // eax <-- qs, edx <-- r such that ahi:alo = bs*qs + r
+
+ pushl %edi
+ notl %ecx
+ shrl %eax
+ shrl %cl, %eax // q = qs >> (1 + i)
+ movl %eax, %edi
+ mull 24(%esp) // q*blo
+ movl 16(%esp), %ebx
+ movl 20(%esp), %ecx // ECX:EBX = a
+ subl %eax, %ebx
+ sbbl %edx, %ecx // ECX:EBX = a - q*blo
+ movl 28(%esp), %eax
+ imull %edi, %eax // q*bhi
+ subl %eax, %ecx // ECX:EBX = a - q*b
+
+ jnc 1f // if positive, this is the result.
+ addl 24(%esp), %ebx // otherwise
+ adcl 28(%esp), %ecx // ECX:EBX = a - (q-1)*b = result
+1: movl %ebx, %eax
+ movl %ecx, %edx
+
+ addl %esi, %eax // Restore correct sign to result
+ adcl %esi, %edx
+ xorl %esi, %eax
+ xorl %esi, %edx
+ popl %edi // Restore callee-save registers
+ popl %ebx
+ popl %esi
+ retl // Return
+
+2: /* High word of a is greater than or equal to (b >> (1 + i)) on this branch */
+
+ subl %ebx, %edx // subtract bhi from ahi so that divide will not
+ divl %ebx // overflow, and find q and r such that
+ //
+ // ahi:alo = (1:q)*bhi + r
+ //
+ // Note that q is a number in (31-i).(1+i)
+ // fix point.
+
+ pushl %edi
+ notl %ecx
+ shrl %eax
+ orl $0x80000000, %eax
+ shrl %cl, %eax // q = (1:qs) >> (1 + i)
+ movl %eax, %edi
+ mull 24(%esp) // q*blo
+ movl 16(%esp), %ebx
+ movl 20(%esp), %ecx // ECX:EBX = a
+ subl %eax, %ebx
+ sbbl %edx, %ecx // ECX:EBX = a - q*blo
+ movl 28(%esp), %eax
+ imull %edi, %eax // q*bhi
+ subl %eax, %ecx // ECX:EBX = a - q*b
+
+ jnc 3f // if positive, this is the result.
+ addl 24(%esp), %ebx // otherwise
+ adcl 28(%esp), %ecx // ECX:EBX = a - (q-1)*b = result
+3: movl %ebx, %eax
+ movl %ecx, %edx
+
+ addl %esi, %eax // Restore correct sign to result
+ adcl %esi, %edx
+ xorl %esi, %eax
+ xorl %esi, %edx
+ popl %edi // Restore callee-save registers
+ popl %ebx
+ popl %esi
+ retl // Return
+
+9: /* High word of b is zero on this branch */
+
+ movl 16(%esp), %eax // Find qhi and rhi such that
+ movl 20(%esp), %ecx //
+ xorl %edx, %edx // ahi = qhi*b + rhi with 0 ≤ rhi < b
+ divl %ecx //
+ movl %eax, %ebx //
+ movl 12(%esp), %eax // Find rlo such that
+ divl %ecx //
+ movl %edx, %eax // rhi:alo = qlo*b + rlo with 0 ≤ rlo < b
+ popl %ebx //
+ xorl %edx, %edx // and return 0:rlo
+
+ addl %esi, %eax // Restore correct sign to result
+ adcl %esi, %edx
+ xorl %esi, %eax
+ xorl %esi, %edx
+ popl %esi
+ retl // Return
+END_COMPILERRT_FUNCTION(__moddi3)
+
+#endif // __i386__
diff --git a/lib/builtins/i386/muldi3.S b/lib/builtins/i386/muldi3.S
new file mode 100644
index 000000000000..15b6b4998456
--- /dev/null
+++ b/lib/builtins/i386/muldi3.S
@@ -0,0 +1,30 @@
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+
+#include "../assembly.h"
+
+// di_int __muldi3(di_int a, di_int b);
+
+#ifdef __i386__
+
+.text
+.balign 4
+DEFINE_COMPILERRT_FUNCTION(__muldi3)
+ pushl %ebx
+ movl 16(%esp), %eax // b.lo
+ movl 12(%esp), %ecx // a.hi
+ imull %eax, %ecx // b.lo * a.hi
+
+ movl 8(%esp), %edx // a.lo
+ movl 20(%esp), %ebx // b.hi
+ imull %edx, %ebx // a.lo * b.hi
+
+ mull %edx // EDX:EAX = a.lo * b.lo
+ addl %ecx, %ebx // EBX = (a.lo*b.hi + a.hi*b.lo)
+ addl %ebx, %edx
+
+ popl %ebx
+ retl
+END_COMPILERRT_FUNCTION(__muldi3)
+
+#endif // __i386__
diff --git a/lib/builtins/i386/udivdi3.S b/lib/builtins/i386/udivdi3.S
new file mode 100644
index 000000000000..41b2edf03e34
--- /dev/null
+++ b/lib/builtins/i386/udivdi3.S
@@ -0,0 +1,115 @@
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+
+#include "../assembly.h"
+
+// du_int __udivdi3(du_int a, du_int b);
+
+// result = a / b.
+// both inputs and the output are 64-bit unsigned integers.
+// This will do whatever the underlying hardware is set to do on division by zero.
+// No other exceptions are generated, as the divide cannot overflow.
+//
+// This is targeted at 32-bit x86 *only*, as this can be done directly in hardware
+// on x86_64. The performance goal is ~40 cycles per divide, which is faster than
+// currently possible via simulation of integer divides on the x87 unit.
+//
+// Stephen Canon, December 2008
+
+#ifdef __i386__
+
+.text
+.balign 4
+DEFINE_COMPILERRT_FUNCTION(__udivdi3)
+
+ pushl %ebx
+ movl 20(%esp), %ebx // Find the index i of the leading bit in b.
+ bsrl %ebx, %ecx // If the high word of b is zero, jump to
+ jz 9f // the code to handle that special case [9].
+
+ /* High word of b is known to be non-zero on this branch */
+
+ movl 16(%esp), %eax // Construct bhi, containing bits [1+i:32+i] of b
+
+ shrl %cl, %eax // Practically, this means that bhi is given by:
+ shrl %eax //
+ notl %ecx // bhi = (high word of b) << (31 - i) |
+ shll %cl, %ebx // (low word of b) >> (1 + i)
+ orl %eax, %ebx //
+ movl 12(%esp), %edx // Load the high and low words of a, and jump
+ movl 8(%esp), %eax // to [1] if the high word is larger than bhi
+ cmpl %ebx, %edx // to avoid overflowing the upcoming divide.
+ jae 1f
+
+ /* High word of a is greater than or equal to (b >> (1 + i)) on this branch */
+
+ divl %ebx // eax <-- qs, edx <-- r such that ahi:alo = bs*qs + r
+
+ pushl %edi
+ notl %ecx
+ shrl %eax
+ shrl %cl, %eax // q = qs >> (1 + i)
+ movl %eax, %edi
+ mull 20(%esp) // q*blo
+ movl 12(%esp), %ebx
+ movl 16(%esp), %ecx // ECX:EBX = a
+ subl %eax, %ebx
+ sbbl %edx, %ecx // ECX:EBX = a - q*blo
+ movl 24(%esp), %eax
+ imull %edi, %eax // q*bhi
+ subl %eax, %ecx // ECX:EBX = a - q*b
+ sbbl $0, %edi // decrement q if remainder is negative
+ xorl %edx, %edx
+ movl %edi, %eax
+ popl %edi
+ popl %ebx
+ retl
+
+
+1: /* High word of a is greater than or equal to (b >> (1 + i)) on this branch */
+
+ subl %ebx, %edx // subtract bhi from ahi so that divide will not
+ divl %ebx // overflow, and find q and r such that
+ //
+ // ahi:alo = (1:q)*bhi + r
+ //
+ // Note that q is a number in (31-i).(1+i)
+ // fix point.
+
+ pushl %edi
+ notl %ecx
+ shrl %eax
+ orl $0x80000000, %eax
+ shrl %cl, %eax // q = (1:qs) >> (1 + i)
+ movl %eax, %edi
+ mull 20(%esp) // q*blo
+ movl 12(%esp), %ebx
+ movl 16(%esp), %ecx // ECX:EBX = a
+ subl %eax, %ebx
+ sbbl %edx, %ecx // ECX:EBX = a - q*blo
+ movl 24(%esp), %eax
+ imull %edi, %eax // q*bhi
+ subl %eax, %ecx // ECX:EBX = a - q*b
+ sbbl $0, %edi // decrement q if remainder is negative
+ xorl %edx, %edx
+ movl %edi, %eax
+ popl %edi
+ popl %ebx
+ retl
+
+
+9: /* High word of b is zero on this branch */
+
+ movl 12(%esp), %eax // Find qhi and rhi such that
+ movl 16(%esp), %ecx //
+ xorl %edx, %edx // ahi = qhi*b + rhi with 0 ≤ rhi < b
+ divl %ecx //
+ movl %eax, %ebx //
+ movl 8(%esp), %eax // Find qlo such that
+ divl %ecx //
+ movl %ebx, %edx // rhi:alo = qlo*b + rlo with 0 ≤ rlo < b
+ popl %ebx //
+ retl // and return qhi:qlo
+END_COMPILERRT_FUNCTION(__udivdi3)
+
+#endif // __i386__
diff --git a/lib/builtins/i386/umoddi3.S b/lib/builtins/i386/umoddi3.S
new file mode 100644
index 000000000000..a190a7d397d2
--- /dev/null
+++ b/lib/builtins/i386/umoddi3.S
@@ -0,0 +1,126 @@
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+
+#include "../assembly.h"
+
+// du_int __umoddi3(du_int a, du_int b);
+
+// result = remainder of a / b.
+// both inputs and the output are 64-bit unsigned integers.
+// This will do whatever the underlying hardware is set to do on division by zero.
+// No other exceptions are generated, as the divide cannot overflow.
+//
+// This is targeted at 32-bit x86 *only*, as this can be done directly in hardware
+// on x86_64. The performance goal is ~40 cycles per divide, which is faster than
+// currently possible via simulation of integer divides on the x87 unit.
+//
+
+// Stephen Canon, December 2008
+
+#ifdef __i386__
+
+.text
+.balign 4
+DEFINE_COMPILERRT_FUNCTION(__umoddi3)
+
+ pushl %ebx
+ movl 20(%esp), %ebx // Find the index i of the leading bit in b.
+ bsrl %ebx, %ecx // If the high word of b is zero, jump to
+ jz 9f // the code to handle that special case [9].
+
+ /* High word of b is known to be non-zero on this branch */
+
+ movl 16(%esp), %eax // Construct bhi, containing bits [1+i:32+i] of b
+
+ shrl %cl, %eax // Practically, this means that bhi is given by:
+ shrl %eax //
+ notl %ecx // bhi = (high word of b) << (31 - i) |
+ shll %cl, %ebx // (low word of b) >> (1 + i)
+ orl %eax, %ebx //
+ movl 12(%esp), %edx // Load the high and low words of a, and jump
+ movl 8(%esp), %eax // to [2] if the high word is larger than bhi
+ cmpl %ebx, %edx // to avoid overflowing the upcoming divide.
+ jae 2f
+
+ /* High word of a is greater than or equal to (b >> (1 + i)) on this branch */
+
+ divl %ebx // eax <-- qs, edx <-- r such that ahi:alo = bs*qs + r
+
+ pushl %edi
+ notl %ecx
+ shrl %eax
+ shrl %cl, %eax // q = qs >> (1 + i)
+ movl %eax, %edi
+ mull 20(%esp) // q*blo
+ movl 12(%esp), %ebx
+ movl 16(%esp), %ecx // ECX:EBX = a
+ subl %eax, %ebx
+ sbbl %edx, %ecx // ECX:EBX = a - q*blo
+ movl 24(%esp), %eax
+ imull %edi, %eax // q*bhi
+ subl %eax, %ecx // ECX:EBX = a - q*b
+
+ jnc 1f // if positive, this is the result.
+ addl 20(%esp), %ebx // otherwise
+ adcl 24(%esp), %ecx // ECX:EBX = a - (q-1)*b = result
+1: movl %ebx, %eax
+ movl %ecx, %edx
+
+ popl %edi
+ popl %ebx
+ retl
+
+
+2: /* High word of a is greater than or equal to (b >> (1 + i)) on this branch */
+
+ subl %ebx, %edx // subtract bhi from ahi so that divide will not
+ divl %ebx // overflow, and find q and r such that
+ //
+ // ahi:alo = (1:q)*bhi + r
+ //
+ // Note that q is a number in (31-i).(1+i)
+ // fix point.
+
+ pushl %edi
+ notl %ecx
+ shrl %eax
+ orl $0x80000000, %eax
+ shrl %cl, %eax // q = (1:qs) >> (1 + i)
+ movl %eax, %edi
+ mull 20(%esp) // q*blo
+ movl 12(%esp), %ebx
+ movl 16(%esp), %ecx // ECX:EBX = a
+ subl %eax, %ebx
+ sbbl %edx, %ecx // ECX:EBX = a - q*blo
+ movl 24(%esp), %eax
+ imull %edi, %eax // q*bhi
+ subl %eax, %ecx // ECX:EBX = a - q*b
+
+ jnc 3f // if positive, this is the result.
+ addl 20(%esp), %ebx // otherwise
+ adcl 24(%esp), %ecx // ECX:EBX = a - (q-1)*b = result
+3: movl %ebx, %eax
+ movl %ecx, %edx
+
+ popl %edi
+ popl %ebx
+ retl
+
+
+
+9: /* High word of b is zero on this branch */
+
+ movl 12(%esp), %eax // Find qhi and rhi such that
+ movl 16(%esp), %ecx //
+ xorl %edx, %edx // ahi = qhi*b + rhi with 0 ≤ rhi < b
+ divl %ecx //
+ movl %eax, %ebx //
+ movl 8(%esp), %eax // Find rlo such that
+ divl %ecx //
+ movl %edx, %eax // rhi:alo = qlo*b + rlo with 0 ≤ rlo < b
+ popl %ebx //
+ xorl %edx, %edx // and return 0:rlo
+ retl //
+END_COMPILERRT_FUNCTION(__umoddi3)
+
+#endif // __i386__
diff --git a/lib/builtins/int_endianness.h b/lib/builtins/int_endianness.h
new file mode 100644
index 000000000000..4b35bde079e8
--- /dev/null
+++ b/lib/builtins/int_endianness.h
@@ -0,0 +1,112 @@
+/* ===-- int_endianness.h - configuration header for compiler-rt ------------===
+ *
+ * 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 is a configuration header for compiler-rt.
+ * This file is not part of the interface of this library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#ifndef INT_ENDIANNESS_H
+#define INT_ENDIANNESS_H
+
+#if defined(__SVR4) && defined(__sun)
+#include <sys/byteorder.h>
+
+#if defined(_BIG_ENDIAN)
+#define _YUGA_LITTLE_ENDIAN 0
+#define _YUGA_BIG_ENDIAN 1
+#elif defined(_LITTLE_ENDIAN)
+#define _YUGA_LITTLE_ENDIAN 1
+#define _YUGA_BIG_ENDIAN 0
+#else /* !_LITTLE_ENDIAN */
+#error "unknown endianness"
+#endif /* !_LITTLE_ENDIAN */
+
+#endif /* Solaris and AuroraUX. */
+
+/* .. */
+
+#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || \
+ defined(__minix)
+#include <sys/endian.h>
+
+#if _BYTE_ORDER == _BIG_ENDIAN
+#define _YUGA_LITTLE_ENDIAN 0
+#define _YUGA_BIG_ENDIAN 1
+#elif _BYTE_ORDER == _LITTLE_ENDIAN
+#define _YUGA_LITTLE_ENDIAN 1
+#define _YUGA_BIG_ENDIAN 0
+#endif /* _BYTE_ORDER */
+
+#endif /* *BSD */
+
+#if defined(__OpenBSD__) || defined(__Bitrig__)
+#include <machine/endian.h>
+
+#if _BYTE_ORDER == _BIG_ENDIAN
+#define _YUGA_LITTLE_ENDIAN 0
+#define _YUGA_BIG_ENDIAN 1
+#elif _BYTE_ORDER == _LITTLE_ENDIAN
+#define _YUGA_LITTLE_ENDIAN 1
+#define _YUGA_BIG_ENDIAN 0
+#endif /* _BYTE_ORDER */
+
+#endif /* OpenBSD and Bitrig. */
+
+/* .. */
+
+/* Mac OSX has __BIG_ENDIAN__ or __LITTLE_ENDIAN__ automatically set by the
+ * compiler (at least with GCC) */
+#if defined(__APPLE__) || defined(__ellcc__ )
+
+#ifdef __BIG_ENDIAN__
+#if __BIG_ENDIAN__
+#define _YUGA_LITTLE_ENDIAN 0
+#define _YUGA_BIG_ENDIAN 1
+#endif
+#endif /* __BIG_ENDIAN__ */
+
+#ifdef __LITTLE_ENDIAN__
+#if __LITTLE_ENDIAN__
+#define _YUGA_LITTLE_ENDIAN 1
+#define _YUGA_BIG_ENDIAN 0
+#endif
+#endif /* __LITTLE_ENDIAN__ */
+
+#endif /* Mac OSX */
+
+/* .. */
+
+#if defined(__linux__)
+
+#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+#define _YUGA_LITTLE_ENDIAN 0
+#define _YUGA_BIG_ENDIAN 1
+#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+#define _YUGA_LITTLE_ENDIAN 1
+#define _YUGA_BIG_ENDIAN 0
+#endif /* __BYTE_ORDER__ */
+
+#endif /* GNU/Linux */
+
+#if defined(_WIN32)
+
+#define _YUGA_LITTLE_ENDIAN 1
+#define _YUGA_BIG_ENDIAN 0
+
+#endif /* Windows */
+
+/* . */
+
+#if !defined(_YUGA_LITTLE_ENDIAN) || !defined(_YUGA_BIG_ENDIAN)
+#error Unable to determine endian
+#endif /* Check we found an endianness correctly. */
+
+#endif /* INT_ENDIANNESS_H */
diff --git a/lib/builtins/int_lib.h b/lib/builtins/int_lib.h
new file mode 100644
index 000000000000..ff314da986f1
--- /dev/null
+++ b/lib/builtins/int_lib.h
@@ -0,0 +1,70 @@
+/* ===-- int_lib.h - configuration header for compiler-rt -----------------===
+ *
+ * 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 is a configuration header for compiler-rt.
+ * This file is not part of the interface of this library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#ifndef INT_LIB_H
+#define INT_LIB_H
+
+/* Assumption: Signed integral is 2's complement. */
+/* Assumption: Right shift of signed negative is arithmetic shift. */
+/* Assumption: Endianness is little or big (not mixed). */
+
+/* ABI macro definitions */
+
+#if __ARM_EABI__
+# define ARM_EABI_FNALIAS(aeabi_name, name) \
+ void __aeabi_##aeabi_name() __attribute__((alias("__" #name)));
+# define COMPILER_RT_ABI __attribute__((pcs("aapcs")))
+#else
+# define ARM_EABI_FNALIAS(aeabi_name, name)
+# define COMPILER_RT_ABI
+#endif
+
+#if defined(__NetBSD__) && (defined(_KERNEL) || defined(_STANDALONE))
+/*
+ * Kernel and boot environment can't use normal headers,
+ * so use the equivalent system headers.
+ */
+# include <machine/limits.h>
+# include <sys/stdint.h>
+# include <sys/types.h>
+#else
+/* Include the standard compiler builtin headers we use functionality from. */
+# include <limits.h>
+# include <stdint.h>
+# include <stdbool.h>
+# include <float.h>
+#endif
+
+/* Include the commonly used internal type definitions. */
+#include "int_types.h"
+
+/* Include internal utility function declarations. */
+#include "int_util.h"
+
+COMPILER_RT_ABI si_int __paritysi2(si_int a);
+COMPILER_RT_ABI si_int __paritydi2(di_int a);
+
+COMPILER_RT_ABI di_int __divdi3(di_int a, di_int b);
+COMPILER_RT_ABI si_int __divsi3(si_int a, si_int b);
+COMPILER_RT_ABI su_int __udivsi3(su_int n, su_int d);
+
+COMPILER_RT_ABI su_int __udivmodsi4(su_int a, su_int b, su_int* rem);
+COMPILER_RT_ABI du_int __udivmoddi4(du_int a, du_int b, du_int* rem);
+#ifdef CRT_HAS_128BIT
+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
+
+#endif /* INT_LIB_H */
diff --git a/lib/int_math.h b/lib/builtins/int_math.h
index d6b4bdae162b..d6b4bdae162b 100644
--- a/lib/int_math.h
+++ b/lib/builtins/int_math.h
diff --git a/lib/builtins/int_types.h b/lib/builtins/int_types.h
new file mode 100644
index 000000000000..5107f71550ac
--- /dev/null
+++ b/lib/builtins/int_types.h
@@ -0,0 +1,143 @@
+/* ===-- int_lib.h - configuration header for compiler-rt -----------------===
+ *
+ * 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 is not part of the interface of this library.
+ *
+ * This file defines various standard types, most importantly a number of unions
+ * used to access parts of larger types.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#ifndef INT_TYPES_H
+#define INT_TYPES_H
+
+#include "int_endianness.h"
+
+typedef int si_int;
+typedef unsigned su_int;
+
+typedef long long di_int;
+typedef unsigned long long du_int;
+
+typedef union
+{
+ di_int all;
+ struct
+ {
+#if _YUGA_LITTLE_ENDIAN
+ su_int low;
+ si_int high;
+#else
+ si_int high;
+ su_int low;
+#endif /* _YUGA_LITTLE_ENDIAN */
+ }s;
+} dwords;
+
+typedef union
+{
+ du_int all;
+ struct
+ {
+#if _YUGA_LITTLE_ENDIAN
+ su_int low;
+ su_int high;
+#else
+ su_int high;
+ su_int low;
+#endif /* _YUGA_LITTLE_ENDIAN */
+ }s;
+} udwords;
+
+#if __LP64__
+#define CRT_HAS_128BIT
+#endif
+
+#ifdef CRT_HAS_128BIT
+typedef int ti_int __attribute__ ((mode (TI)));
+typedef unsigned tu_int __attribute__ ((mode (TI)));
+
+typedef union
+{
+ ti_int all;
+ struct
+ {
+#if _YUGA_LITTLE_ENDIAN
+ du_int low;
+ di_int high;
+#else
+ di_int high;
+ du_int low;
+#endif /* _YUGA_LITTLE_ENDIAN */
+ }s;
+} twords;
+
+typedef union
+{
+ tu_int all;
+ struct
+ {
+#if _YUGA_LITTLE_ENDIAN
+ du_int low;
+ du_int high;
+#else
+ du_int high;
+ du_int low;
+#endif /* _YUGA_LITTLE_ENDIAN */
+ }s;
+} utwords;
+
+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) {
+ utwords r;
+ r.s.high = h;
+ r.s.low = l;
+ return r.all;
+}
+
+#endif /* CRT_HAS_128BIT */
+
+typedef union
+{
+ su_int u;
+ float f;
+} float_bits;
+
+typedef union
+{
+ udwords u;
+ double f;
+} double_bits;
+
+typedef struct
+{
+#if _YUGA_LITTLE_ENDIAN
+ udwords low;
+ udwords high;
+#else
+ udwords high;
+ udwords low;
+#endif /* _YUGA_LITTLE_ENDIAN */
+} uqwords;
+
+typedef union
+{
+ uqwords u;
+ long double f;
+} long_double_bits;
+
+#endif /* INT_TYPES_H */
+
diff --git a/lib/int_util.c b/lib/builtins/int_util.c
index 323e46179e6c..323e46179e6c 100644
--- a/lib/int_util.c
+++ b/lib/builtins/int_util.c
diff --git a/lib/builtins/int_util.h b/lib/builtins/int_util.h
new file mode 100644
index 000000000000..a9b595db8d0f
--- /dev/null
+++ b/lib/builtins/int_util.h
@@ -0,0 +1,29 @@
+/* ===-- int_util.h - internal utility functions ----------------------------===
+ *
+ * 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 is not part of the interface of this library.
+ *
+ * This file defines non-inline utilities which are available for use in the
+ * library. The function definitions themselves are all contained in int_util.c
+ * which will always be compiled into any compiler-rt library.
+ *
+ * ===-----------------------------------------------------------------------===
+ */
+
+#ifndef INT_UTIL_H
+#define INT_UTIL_H
+
+/** \brief Trigger a program abort (or panic for kernel code). */
+#define compilerrt_abort() compilerrt_abort_impl(__FILE__, __LINE__, \
+ __func__)
+
+void compilerrt_abort_impl(const char *file, int line,
+ const char *function) __attribute__((noreturn));
+
+#endif /* INT_UTIL_H */
diff --git a/lib/lshrdi3.c b/lib/builtins/lshrdi3.c
index 6b1ea923b778..6b1ea923b778 100644
--- a/lib/lshrdi3.c
+++ b/lib/builtins/lshrdi3.c
diff --git a/lib/builtins/lshrti3.c b/lib/builtins/lshrti3.c
new file mode 100644
index 000000000000..e4170ff84a5a
--- /dev/null
+++ b/lib/builtins/lshrti3.c
@@ -0,0 +1,45 @@
+/* ===-- lshrti3.c - Implement __lshrti3 -----------------------------------===
+ *
+ * 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 __lshrti3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+/* Returns: logical a >> b */
+
+/* Precondition: 0 <= b < bits_in_tword */
+
+COMPILER_RT_ABI ti_int
+__lshrti3(ti_int a, si_int b)
+{
+ const int bits_in_dword = (int)(sizeof(di_int) * CHAR_BIT);
+ utwords input;
+ utwords result;
+ input.all = a;
+ if (b & bits_in_dword) /* bits_in_dword <= b < bits_in_tword */
+ {
+ result.s.high = 0;
+ result.s.low = input.s.high >> (b - bits_in_dword);
+ }
+ else /* 0 <= b < bits_in_dword */
+ {
+ if (b == 0)
+ return a;
+ result.s.high = input.s.high >> b;
+ result.s.low = (input.s.high << (bits_in_dword - b)) | (input.s.low >> b);
+ }
+ return result.all;
+}
+
+#endif /* CRT_HAS_128BIT */
diff --git a/lib/builtins/moddi3.c b/lib/builtins/moddi3.c
new file mode 100644
index 000000000000..a04279e3875f
--- /dev/null
+++ b/lib/builtins/moddi3.c
@@ -0,0 +1,30 @@
+/*===-- moddi3.c - Implement __moddi3 -------------------------------------===
+ *
+ * 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 __moddi3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: a % b */
+
+COMPILER_RT_ABI di_int
+__moddi3(di_int a, di_int b)
+{
+ const int bits_in_dword_m1 = (int)(sizeof(di_int) * CHAR_BIT) - 1;
+ di_int s = b >> bits_in_dword_m1; /* s = b < 0 ? -1 : 0 */
+ b = (b ^ s) - s; /* negate if s == -1 */
+ s = a >> bits_in_dword_m1; /* s = a < 0 ? -1 : 0 */
+ a = (a ^ s) - s; /* negate if s == -1 */
+ du_int r;
+ __udivmoddi4(a, b, &r);
+ return ((di_int)r ^ s) - s; /* negate if s == -1 */
+}
diff --git a/lib/builtins/modsi3.c b/lib/builtins/modsi3.c
new file mode 100644
index 000000000000..86c73ce13777
--- /dev/null
+++ b/lib/builtins/modsi3.c
@@ -0,0 +1,23 @@
+/* ===-- modsi3.c - Implement __modsi3 -------------------------------------===
+ *
+ * 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 __modsi3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: a % b */
+
+COMPILER_RT_ABI si_int
+__modsi3(si_int a, si_int b)
+{
+ return a - __divsi3(a, b) * b;
+}
diff --git a/lib/builtins/modti3.c b/lib/builtins/modti3.c
new file mode 100644
index 000000000000..d505c07ac162
--- /dev/null
+++ b/lib/builtins/modti3.c
@@ -0,0 +1,34 @@
+/* ===-- modti3.c - Implement __modti3 -------------------------------------===
+ *
+ * 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 __modti3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+/*Returns: a % b */
+
+COMPILER_RT_ABI ti_int
+__modti3(ti_int a, ti_int b)
+{
+ const int bits_in_tword_m1 = (int)(sizeof(ti_int) * CHAR_BIT) - 1;
+ ti_int s = b >> bits_in_tword_m1; /* s = b < 0 ? -1 : 0 */
+ b = (b ^ s) - s; /* negate if s == -1 */
+ s = a >> bits_in_tword_m1; /* s = a < 0 ? -1 : 0 */
+ a = (a ^ s) - s; /* negate if s == -1 */
+ tu_int r;
+ __udivmodti4(a, b, &r);
+ return ((ti_int)r ^ s) - s; /* negate if s == -1 */
+}
+
+#endif /* CRT_HAS_128BIT */
diff --git a/lib/builtins/muldc3.c b/lib/builtins/muldc3.c
new file mode 100644
index 000000000000..3bfae2c52224
--- /dev/null
+++ b/lib/builtins/muldc3.c
@@ -0,0 +1,73 @@
+/* ===-- muldc3.c - Implement __muldc3 -------------------------------------===
+ *
+ * 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 __muldc3 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 double _Complex
+__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))
+ {
+ int __recalc = 0;
+ if (crt_isinf(__a) || crt_isinf(__b))
+ {
+ __a = crt_copysign(crt_isinf(__a) ? 1 : 0, __a);
+ __b = crt_copysign(crt_isinf(__b) ? 1 : 0, __b);
+ if (crt_isnan(__c))
+ __c = crt_copysign(0, __c);
+ if (crt_isnan(__d))
+ __d = crt_copysign(0, __d);
+ __recalc = 1;
+ }
+ if (crt_isinf(__c) || crt_isinf(__d))
+ {
+ __c = crt_copysign(crt_isinf(__c) ? 1 : 0, __c);
+ __d = crt_copysign(crt_isinf(__d) ? 1 : 0, __d);
+ if (crt_isnan(__a))
+ __a = crt_copysign(0, __a);
+ if (crt_isnan(__b))
+ __b = crt_copysign(0, __b);
+ __recalc = 1;
+ }
+ if (!__recalc && (crt_isinf(__ac) || crt_isinf(__bd) ||
+ crt_isinf(__ad) || crt_isinf(__bc)))
+ {
+ if (crt_isnan(__a))
+ __a = crt_copysign(0, __a);
+ if (crt_isnan(__b))
+ __b = crt_copysign(0, __b);
+ if (crt_isnan(__c))
+ __c = crt_copysign(0, __c);
+ if (crt_isnan(__d))
+ __d = crt_copysign(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/muldf3.c b/lib/builtins/muldf3.c
new file mode 100644
index 000000000000..1eb733849e5a
--- /dev/null
+++ b/lib/builtins/muldf3.c
@@ -0,0 +1,22 @@
+//===-- lib/muldf3.c - Double-precision multiplication ------------*- 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 double-precision soft-float multiplication
+// with the IEEE-754 default rounding (to nearest, ties to even).
+//
+//===----------------------------------------------------------------------===//
+
+#define DOUBLE_PRECISION
+#include "fp_mul_impl.inc"
+
+ARM_EABI_FNALIAS(dmul, muldf3)
+
+COMPILER_RT_ABI fp_t __muldf3(fp_t a, fp_t b) {
+ return __mulXf3__(a, b);
+}
diff --git a/lib/muldi3.c b/lib/builtins/muldi3.c
index 2dae44c11b95..2dae44c11b95 100644
--- a/lib/muldi3.c
+++ b/lib/builtins/muldi3.c
diff --git a/lib/builtins/mulodi4.c b/lib/builtins/mulodi4.c
new file mode 100644
index 000000000000..d2fd7db2bcd3
--- /dev/null
+++ b/lib/builtins/mulodi4.c
@@ -0,0 +1,58 @@
+/*===-- mulodi4.c - Implement __mulodi4 -----------------------------------===
+ *
+ * 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 __mulodi4 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: a * b */
+
+/* Effects: sets *overflow to 1 if a * b overflows */
+
+COMPILER_RT_ABI di_int
+__mulodi4(di_int a, di_int b, int* overflow)
+{
+ const int N = (int)(sizeof(di_int) * CHAR_BIT);
+ const di_int MIN = (di_int)1 << (N-1);
+ const di_int MAX = ~MIN;
+ *overflow = 0;
+ di_int result = a * b;
+ if (a == MIN)
+ {
+ if (b != 0 && b != 1)
+ *overflow = 1;
+ return result;
+ }
+ if (b == MIN)
+ {
+ if (a != 0 && a != 1)
+ *overflow = 1;
+ return result;
+ }
+ di_int sa = a >> (N - 1);
+ di_int abs_a = (a ^ sa) - sa;
+ di_int sb = b >> (N - 1);
+ di_int abs_b = (b ^ sb) - sb;
+ if (abs_a < 2 || abs_b < 2)
+ return result;
+ if (sa == sb)
+ {
+ if (abs_a > MAX / abs_b)
+ *overflow = 1;
+ }
+ else
+ {
+ if (abs_a > MIN / -abs_b)
+ *overflow = 1;
+ }
+ return result;
+}
diff --git a/lib/builtins/mulosi4.c b/lib/builtins/mulosi4.c
new file mode 100644
index 000000000000..422528085c44
--- /dev/null
+++ b/lib/builtins/mulosi4.c
@@ -0,0 +1,58 @@
+/*===-- mulosi4.c - Implement __mulosi4 -----------------------------------===
+ *
+ * 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 __mulosi4 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: a * b */
+
+/* Effects: sets *overflow to 1 if a * b overflows */
+
+COMPILER_RT_ABI si_int
+__mulosi4(si_int a, si_int b, int* overflow)
+{
+ const int N = (int)(sizeof(si_int) * CHAR_BIT);
+ const si_int MIN = (si_int)1 << (N-1);
+ const si_int MAX = ~MIN;
+ *overflow = 0;
+ si_int result = a * b;
+ if (a == MIN)
+ {
+ if (b != 0 && b != 1)
+ *overflow = 1;
+ return result;
+ }
+ if (b == MIN)
+ {
+ if (a != 0 && a != 1)
+ *overflow = 1;
+ return result;
+ }
+ si_int sa = a >> (N - 1);
+ si_int abs_a = (a ^ sa) - sa;
+ si_int sb = b >> (N - 1);
+ si_int abs_b = (b ^ sb) - sb;
+ if (abs_a < 2 || abs_b < 2)
+ return result;
+ if (sa == sb)
+ {
+ if (abs_a > MAX / abs_b)
+ *overflow = 1;
+ }
+ else
+ {
+ if (abs_a > MIN / -abs_b)
+ *overflow = 1;
+ }
+ return result;
+}
diff --git a/lib/builtins/muloti4.c b/lib/builtins/muloti4.c
new file mode 100644
index 000000000000..16b218920321
--- /dev/null
+++ b/lib/builtins/muloti4.c
@@ -0,0 +1,62 @@
+/*===-- muloti4.c - Implement __muloti4 -----------------------------------===
+ *
+ * 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 __muloti4 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+/* Returns: a * b */
+
+/* Effects: sets *overflow to 1 if a * b overflows */
+
+COMPILER_RT_ABI ti_int
+__muloti4(ti_int a, ti_int b, int* overflow)
+{
+ const int N = (int)(sizeof(ti_int) * CHAR_BIT);
+ const ti_int MIN = (ti_int)1 << (N-1);
+ const ti_int MAX = ~MIN;
+ *overflow = 0;
+ ti_int result = a * b;
+ if (a == MIN)
+ {
+ if (b != 0 && b != 1)
+ *overflow = 1;
+ return result;
+ }
+ if (b == MIN)
+ {
+ if (a != 0 && a != 1)
+ *overflow = 1;
+ return result;
+ }
+ ti_int sa = a >> (N - 1);
+ ti_int abs_a = (a ^ sa) - sa;
+ ti_int sb = b >> (N - 1);
+ ti_int abs_b = (b ^ sb) - sb;
+ if (abs_a < 2 || abs_b < 2)
+ return result;
+ if (sa == sb)
+ {
+ if (abs_a > MAX / abs_b)
+ *overflow = 1;
+ }
+ else
+ {
+ if (abs_a > MIN / -abs_b)
+ *overflow = 1;
+ }
+ return result;
+}
+
+#endif /* CRT_HAS_128BIT */
diff --git a/lib/builtins/mulsc3.c b/lib/builtins/mulsc3.c
new file mode 100644
index 000000000000..29d46c63a799
--- /dev/null
+++ b/lib/builtins/mulsc3.c
@@ -0,0 +1,73 @@
+/* ===-- mulsc3.c - Implement __mulsc3 -------------------------------------===
+ *
+ * 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 __mulsc3 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 float _Complex
+__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))
+ {
+ int __recalc = 0;
+ if (crt_isinf(__a) || crt_isinf(__b))
+ {
+ __a = crt_copysignf(crt_isinf(__a) ? 1 : 0, __a);
+ __b = crt_copysignf(crt_isinf(__b) ? 1 : 0, __b);
+ if (crt_isnan(__c))
+ __c = crt_copysignf(0, __c);
+ if (crt_isnan(__d))
+ __d = crt_copysignf(0, __d);
+ __recalc = 1;
+ }
+ if (crt_isinf(__c) || crt_isinf(__d))
+ {
+ __c = crt_copysignf(crt_isinf(__c) ? 1 : 0, __c);
+ __d = crt_copysignf(crt_isinf(__d) ? 1 : 0, __d);
+ if (crt_isnan(__a))
+ __a = crt_copysignf(0, __a);
+ if (crt_isnan(__b))
+ __b = crt_copysignf(0, __b);
+ __recalc = 1;
+ }
+ if (!__recalc && (crt_isinf(__ac) || crt_isinf(__bd) ||
+ crt_isinf(__ad) || crt_isinf(__bc)))
+ {
+ if (crt_isnan(__a))
+ __a = crt_copysignf(0, __a);
+ if (crt_isnan(__b))
+ __b = crt_copysignf(0, __b);
+ if (crt_isnan(__c))
+ __c = crt_copysignf(0, __c);
+ if (crt_isnan(__d))
+ __d = crt_copysignf(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/mulsf3.c b/lib/builtins/mulsf3.c
new file mode 100644
index 000000000000..478b3bc0e0e0
--- /dev/null
+++ b/lib/builtins/mulsf3.c
@@ -0,0 +1,22 @@
+//===-- lib/mulsf3.c - Single-precision multiplication ------------*- 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 single-precision soft-float multiplication
+// with the IEEE-754 default rounding (to nearest, ties to even).
+//
+//===----------------------------------------------------------------------===//
+
+#define SINGLE_PRECISION
+#include "fp_mul_impl.inc"
+
+ARM_EABI_FNALIAS(fmul, mulsf3)
+
+COMPILER_RT_ABI fp_t __mulsf3(fp_t a, fp_t b) {
+ return __mulXf3__(a, b);
+}
diff --git a/lib/builtins/multf3.c b/lib/builtins/multf3.c
new file mode 100644
index 000000000000..0b915923ea09
--- /dev/null
+++ b/lib/builtins/multf3.c
@@ -0,0 +1,25 @@
+//===-- lib/multf3.c - Quad-precision multiplication --------------*- 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 quad-precision soft-float multiplication
+// with the IEEE-754 default rounding (to nearest, ties to even).
+//
+//===----------------------------------------------------------------------===//
+
+#define QUAD_PRECISION
+#include "fp_lib.h"
+
+#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
+#include "fp_mul_impl.inc"
+
+COMPILER_RT_ABI fp_t __multf3(fp_t a, fp_t b) {
+ return __mulXf3__(a, b);
+}
+
+#endif
diff --git a/lib/builtins/multi3.c b/lib/builtins/multi3.c
new file mode 100644
index 000000000000..e0d52d430b66
--- /dev/null
+++ b/lib/builtins/multi3.c
@@ -0,0 +1,58 @@
+/* ===-- multi3.c - Implement __multi3 -------------------------------------===
+ *
+ * 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 __multi3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+/* Returns: a * b */
+
+static
+ti_int
+__mulddi3(du_int a, du_int b)
+{
+ twords r;
+ const int bits_in_dword_2 = (int)(sizeof(di_int) * CHAR_BIT) / 2;
+ const du_int lower_mask = (du_int)~0 >> bits_in_dword_2;
+ r.s.low = (a & lower_mask) * (b & lower_mask);
+ du_int t = r.s.low >> bits_in_dword_2;
+ r.s.low &= lower_mask;
+ t += (a >> bits_in_dword_2) * (b & lower_mask);
+ r.s.low += (t & lower_mask) << bits_in_dword_2;
+ r.s.high = t >> bits_in_dword_2;
+ t = r.s.low >> bits_in_dword_2;
+ r.s.low &= lower_mask;
+ t += (b >> bits_in_dword_2) * (a & lower_mask);
+ r.s.low += (t & lower_mask) << bits_in_dword_2;
+ r.s.high += t >> bits_in_dword_2;
+ r.s.high += (a >> bits_in_dword_2) * (b >> bits_in_dword_2);
+ return r.all;
+}
+
+/* Returns: a * b */
+
+COMPILER_RT_ABI ti_int
+__multi3(ti_int a, ti_int b)
+{
+ twords x;
+ x.all = a;
+ twords y;
+ y.all = b;
+ twords r;
+ r.all = __mulddi3(x.s.low, y.s.low);
+ r.s.high += x.s.high * y.s.low + x.s.low * y.s.high;
+ return r.all;
+}
+
+#endif /* CRT_HAS_128BIT */
diff --git a/lib/builtins/mulvdi3.c b/lib/builtins/mulvdi3.c
new file mode 100644
index 000000000000..e63249e0a04c
--- /dev/null
+++ b/lib/builtins/mulvdi3.c
@@ -0,0 +1,56 @@
+/*===-- mulvdi3.c - Implement __mulvdi3 -----------------------------------===
+ *
+ * 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 __mulvdi3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: a * b */
+
+/* Effects: aborts if a * b overflows */
+
+COMPILER_RT_ABI di_int
+__mulvdi3(di_int a, di_int b)
+{
+ const int N = (int)(sizeof(di_int) * CHAR_BIT);
+ const di_int MIN = (di_int)1 << (N-1);
+ const di_int MAX = ~MIN;
+ if (a == MIN)
+ {
+ if (b == 0 || b == 1)
+ return a * b;
+ compilerrt_abort();
+ }
+ if (b == MIN)
+ {
+ if (a == 0 || a == 1)
+ return a * b;
+ compilerrt_abort();
+ }
+ di_int sa = a >> (N - 1);
+ di_int abs_a = (a ^ sa) - sa;
+ di_int sb = b >> (N - 1);
+ di_int abs_b = (b ^ sb) - sb;
+ if (abs_a < 2 || abs_b < 2)
+ return a * b;
+ if (sa == sb)
+ {
+ if (abs_a > MAX / abs_b)
+ compilerrt_abort();
+ }
+ else
+ {
+ if (abs_a > MIN / -abs_b)
+ compilerrt_abort();
+ }
+ return a * b;
+}
diff --git a/lib/builtins/mulvsi3.c b/lib/builtins/mulvsi3.c
new file mode 100644
index 000000000000..74ea4f2da226
--- /dev/null
+++ b/lib/builtins/mulvsi3.c
@@ -0,0 +1,56 @@
+/* ===-- mulvsi3.c - Implement __mulvsi3 -----------------------------------===
+ *
+ * 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 __mulvsi3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: a * b */
+
+/* Effects: aborts if a * b overflows */
+
+COMPILER_RT_ABI si_int
+__mulvsi3(si_int a, si_int b)
+{
+ const int N = (int)(sizeof(si_int) * CHAR_BIT);
+ const si_int MIN = (si_int)1 << (N-1);
+ const si_int MAX = ~MIN;
+ if (a == MIN)
+ {
+ if (b == 0 || b == 1)
+ return a * b;
+ compilerrt_abort();
+ }
+ if (b == MIN)
+ {
+ if (a == 0 || a == 1)
+ return a * b;
+ compilerrt_abort();
+ }
+ si_int sa = a >> (N - 1);
+ si_int abs_a = (a ^ sa) - sa;
+ si_int sb = b >> (N - 1);
+ si_int abs_b = (b ^ sb) - sb;
+ if (abs_a < 2 || abs_b < 2)
+ return a * b;
+ if (sa == sb)
+ {
+ if (abs_a > MAX / abs_b)
+ compilerrt_abort();
+ }
+ else
+ {
+ if (abs_a > MIN / -abs_b)
+ compilerrt_abort();
+ }
+ return a * b;
+}
diff --git a/lib/builtins/mulvti3.c b/lib/builtins/mulvti3.c
new file mode 100644
index 000000000000..f4c7d1612ba9
--- /dev/null
+++ b/lib/builtins/mulvti3.c
@@ -0,0 +1,60 @@
+/* ===-- mulvti3.c - Implement __mulvti3 -----------------------------------===
+ *
+ * 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 __mulvti3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+/* Returns: a * b */
+
+/* Effects: aborts if a * b overflows */
+
+COMPILER_RT_ABI ti_int
+__mulvti3(ti_int a, ti_int b)
+{
+ const int N = (int)(sizeof(ti_int) * CHAR_BIT);
+ const ti_int MIN = (ti_int)1 << (N-1);
+ const ti_int MAX = ~MIN;
+ if (a == MIN)
+ {
+ if (b == 0 || b == 1)
+ return a * b;
+ compilerrt_abort();
+ }
+ if (b == MIN)
+ {
+ if (a == 0 || a == 1)
+ return a * b;
+ compilerrt_abort();
+ }
+ ti_int sa = a >> (N - 1);
+ ti_int abs_a = (a ^ sa) - sa;
+ ti_int sb = b >> (N - 1);
+ ti_int abs_b = (b ^ sb) - sb;
+ if (abs_a < 2 || abs_b < 2)
+ return a * b;
+ if (sa == sb)
+ {
+ if (abs_a > MAX / abs_b)
+ compilerrt_abort();
+ }
+ else
+ {
+ if (abs_a > MIN / -abs_b)
+ compilerrt_abort();
+ }
+ return a * b;
+}
+
+#endif /* CRT_HAS_128BIT */
diff --git a/lib/builtins/mulxc3.c b/lib/builtins/mulxc3.c
new file mode 100644
index 000000000000..161fd0ce0dd4
--- /dev/null
+++ b/lib/builtins/mulxc3.c
@@ -0,0 +1,77 @@
+/* ===-- mulxc3.c - Implement __mulxc3 -------------------------------------===
+ *
+ * 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 __mulxc3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#if !_ARCH_PPC
+
+#include "int_lib.h"
+#include "int_math.h"
+
+/* Returns: the product of a + ib and c + id */
+
+COMPILER_RT_ABI long double _Complex
+__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))
+ {
+ 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;
+}
+
+#endif
diff --git a/lib/builtins/negdf2.c b/lib/builtins/negdf2.c
new file mode 100644
index 000000000000..d634b421cb79
--- /dev/null
+++ b/lib/builtins/negdf2.c
@@ -0,0 +1,22 @@
+//===-- lib/negdf2.c - double-precision negation ------------------*- 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 double-precision soft-float negation.
+//
+//===----------------------------------------------------------------------===//
+
+#define DOUBLE_PRECISION
+#include "fp_lib.h"
+
+ARM_EABI_FNALIAS(dneg, negdf2)
+
+COMPILER_RT_ABI fp_t
+__negdf2(fp_t a) {
+ return fromRep(toRep(a) ^ signBit);
+}
diff --git a/lib/builtins/negdi2.c b/lib/builtins/negdi2.c
new file mode 100644
index 000000000000..3d49ba2899d2
--- /dev/null
+++ b/lib/builtins/negdi2.c
@@ -0,0 +1,26 @@
+/* ===-- negdi2.c - Implement __negdi2 -------------------------------------===
+ *
+ * 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 __negdi2 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: -a */
+
+COMPILER_RT_ABI di_int
+__negdi2(di_int a)
+{
+ /* Note: this routine is here for API compatibility; any sane compiler
+ * should expand it inline.
+ */
+ return -a;
+}
diff --git a/lib/negsf2.c b/lib/builtins/negsf2.c
index 29c17be4145f..29c17be4145f 100644
--- a/lib/negsf2.c
+++ b/lib/builtins/negsf2.c
diff --git a/lib/builtins/negti2.c b/lib/builtins/negti2.c
new file mode 100644
index 000000000000..9b00b303f856
--- /dev/null
+++ b/lib/builtins/negti2.c
@@ -0,0 +1,30 @@
+/* ===-- negti2.c - Implement __negti2 -------------------------------------===
+ *
+ * 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 __negti2 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+/* Returns: -a */
+
+COMPILER_RT_ABI ti_int
+__negti2(ti_int a)
+{
+ /* Note: this routine is here for API compatibility; any sane compiler
+ * should expand it inline.
+ */
+ return -a;
+}
+
+#endif /* CRT_HAS_128BIT */
diff --git a/lib/negvdi2.c b/lib/builtins/negvdi2.c
index e336ecf28f0d..e336ecf28f0d 100644
--- a/lib/negvdi2.c
+++ b/lib/builtins/negvdi2.c
diff --git a/lib/negvsi2.c b/lib/builtins/negvsi2.c
index b9e93fef06c5..b9e93fef06c5 100644
--- a/lib/negvsi2.c
+++ b/lib/builtins/negvsi2.c
diff --git a/lib/builtins/negvti2.c b/lib/builtins/negvti2.c
new file mode 100644
index 000000000000..85f9f7d19d9d
--- /dev/null
+++ b/lib/builtins/negvti2.c
@@ -0,0 +1,32 @@
+/*===-- negvti2.c - Implement __negvti2 -----------------------------------===
+ *
+ * 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 __negvti2 for the compiler_rt library.
+ *
+ *===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+/* Returns: -a */
+
+/* Effects: aborts if -a overflows */
+
+COMPILER_RT_ABI ti_int
+__negvti2(ti_int a)
+{
+ const ti_int MIN = (ti_int)1 << ((int)(sizeof(ti_int) * CHAR_BIT)-1);
+ if (a == MIN)
+ compilerrt_abort();
+ return -a;
+}
+
+#endif /* CRT_HAS_128BIT */
diff --git a/lib/builtins/paritydi2.c b/lib/builtins/paritydi2.c
new file mode 100644
index 000000000000..8ea5ab4214e9
--- /dev/null
+++ b/lib/builtins/paritydi2.c
@@ -0,0 +1,25 @@
+/* ===-- paritydi2.c - Implement __paritydi2 -------------------------------===
+ *
+ * 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 __paritydi2 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: 1 if number of bits is odd else returns 0 */
+
+COMPILER_RT_ABI si_int
+__paritydi2(di_int a)
+{
+ dwords x;
+ x.all = a;
+ return __paritysi2(x.s.high ^ x.s.low);
+}
diff --git a/lib/paritysi2.c b/lib/builtins/paritysi2.c
index 599984663849..599984663849 100644
--- a/lib/paritysi2.c
+++ b/lib/builtins/paritysi2.c
diff --git a/lib/builtins/parityti2.c b/lib/builtins/parityti2.c
new file mode 100644
index 000000000000..5a4fe492486f
--- /dev/null
+++ b/lib/builtins/parityti2.c
@@ -0,0 +1,29 @@
+/* ===-- parityti2.c - Implement __parityti2 -------------------------------===
+ *
+ * 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 __parityti2 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+/* Returns: 1 if number of bits is odd else returns 0 */
+
+COMPILER_RT_ABI si_int
+__parityti2(ti_int a)
+{
+ twords x;
+ x.all = a;
+ return __paritydi2(x.s.high ^ x.s.low);
+}
+
+#endif /* CRT_HAS_128BIT */
diff --git a/lib/popcountdi2.c b/lib/builtins/popcountdi2.c
index 5e8a62f075eb..5e8a62f075eb 100644
--- a/lib/popcountdi2.c
+++ b/lib/builtins/popcountdi2.c
diff --git a/lib/popcountsi2.c b/lib/builtins/popcountsi2.c
index 44544ff49890..44544ff49890 100644
--- a/lib/popcountsi2.c
+++ b/lib/builtins/popcountsi2.c
diff --git a/lib/builtins/popcountti2.c b/lib/builtins/popcountti2.c
new file mode 100644
index 000000000000..7451bbb286b7
--- /dev/null
+++ b/lib/builtins/popcountti2.c
@@ -0,0 +1,44 @@
+/* ===-- popcountti2.c - Implement __popcountti2 ----------------------------===
+ *
+ * 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 __popcountti2 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+/* Returns: count of 1 bits */
+
+COMPILER_RT_ABI si_int
+__popcountti2(ti_int a)
+{
+ tu_int x3 = (tu_int)a;
+ x3 = x3 - ((x3 >> 1) & (((tu_int)0x5555555555555555uLL << 64) |
+ 0x5555555555555555uLL));
+ /* Every 2 bits holds the sum of every pair of bits (64) */
+ x3 = ((x3 >> 2) & (((tu_int)0x3333333333333333uLL << 64) | 0x3333333333333333uLL))
+ + (x3 & (((tu_int)0x3333333333333333uLL << 64) | 0x3333333333333333uLL));
+ /* Every 4 bits holds the sum of every 4-set of bits (3 significant bits) (32) */
+ x3 = (x3 + (x3 >> 4))
+ & (((tu_int)0x0F0F0F0F0F0F0F0FuLL << 64) | 0x0F0F0F0F0F0F0F0FuLL);
+ /* Every 8 bits holds the sum of every 8-set of bits (4 significant bits) (16) */
+ du_int x2 = (du_int)(x3 + (x3 >> 64));
+ /* Every 8 bits holds the sum of every 8-set of bits (5 significant bits) (8) */
+ su_int x = (su_int)(x2 + (x2 >> 32));
+ /* Every 8 bits holds the sum of every 8-set of bits (6 significant bits) (4) */
+ x = x + (x >> 16);
+ /* Every 8 bits holds the sum of every 8-set of bits (7 significant bits) (2) */
+ /* Upper 16 bits are garbage */
+ return (x + (x >> 8)) & 0xFF; /* (8 significant bits) */
+}
+
+#endif /* CRT_HAS_128BIT */
diff --git a/lib/powidf2.c b/lib/builtins/powidf2.c
index ac13b172b043..ac13b172b043 100644
--- a/lib/powidf2.c
+++ b/lib/builtins/powidf2.c
diff --git a/lib/powisf2.c b/lib/builtins/powisf2.c
index 0c400ec6dd6a..0c400ec6dd6a 100644
--- a/lib/powisf2.c
+++ b/lib/builtins/powisf2.c
diff --git a/lib/builtins/powitf2.c b/lib/builtins/powitf2.c
new file mode 100644
index 000000000000..172f29f58f25
--- /dev/null
+++ b/lib/builtins/powitf2.c
@@ -0,0 +1,38 @@
+/* ===-- powitf2.cpp - Implement __powitf2 ---------------------------------===
+ *
+ * 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 __powitf2 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#if _ARCH_PPC
+
+/* Returns: a ^ b */
+
+COMPILER_RT_ABI long double
+__powitf2(long double a, si_int b)
+{
+ const int recip = b < 0;
+ long double r = 1;
+ while (1)
+ {
+ if (b & 1)
+ r *= a;
+ b /= 2;
+ if (b == 0)
+ break;
+ a *= a;
+ }
+ return recip ? 1/r : r;
+}
+
+#endif
diff --git a/lib/builtins/powixf2.c b/lib/builtins/powixf2.c
new file mode 100644
index 000000000000..0fd96e503e7b
--- /dev/null
+++ b/lib/builtins/powixf2.c
@@ -0,0 +1,38 @@
+/* ===-- powixf2.cpp - Implement __powixf2 ---------------------------------===
+ *
+ * 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 __powixf2 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#if !_ARCH_PPC
+
+#include "int_lib.h"
+
+/* Returns: a ^ b */
+
+COMPILER_RT_ABI long double
+__powixf2(long double a, si_int b)
+{
+ const int recip = b < 0;
+ long double r = 1;
+ while (1)
+ {
+ if (b & 1)
+ r *= a;
+ b /= 2;
+ if (b == 0)
+ break;
+ a *= a;
+ }
+ return recip ? 1/r : r;
+}
+
+#endif
diff --git a/lib/builtins/ppc/DD.h b/lib/builtins/ppc/DD.h
new file mode 100644
index 000000000000..fc3e41cbe07e
--- /dev/null
+++ b/lib/builtins/ppc/DD.h
@@ -0,0 +1,46 @@
+#ifndef __DD_HEADER
+#define __DD_HEADER
+
+#include "../int_lib.h"
+
+typedef union {
+ long double ld;
+ struct {
+ double hi;
+ double lo;
+ }s;
+}DD;
+
+typedef union {
+ double d;
+ uint64_t x;
+} doublebits;
+
+#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 double __attribute__((always_inline))
+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;
+}
+
+#endif /* __DD_HEADER */
diff --git a/lib/builtins/ppc/Makefile.mk b/lib/builtins/ppc/Makefile.mk
new file mode 100644
index 000000000000..0adc623aa041
--- /dev/null
+++ b/lib/builtins/ppc/Makefile.mk
@@ -0,0 +1,20 @@
+#===- lib/builtins/ppc/Makefile.mk -------------------------*- Makefile -*--===#
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+
+ModuleName := builtins
+SubDirs :=
+OnlyArchs := ppc
+
+AsmSources := $(foreach file,$(wildcard $(Dir)/*.S),$(notdir $(file)))
+Sources := $(foreach file,$(wildcard $(Dir)/*.c),$(notdir $(file)))
+ObjNames := $(Sources:%.c=%.o) $(AsmSources:%.S=%.o)
+Implementation := Optimized
+
+# FIXME: use automatic dependencies?
+Dependencies := $(wildcard lib/*.h $(Dir)/*.h)
diff --git a/lib/ppc/divtc3.c b/lib/builtins/ppc/divtc3.c
index 299128186312..299128186312 100644
--- a/lib/ppc/divtc3.c
+++ b/lib/builtins/ppc/divtc3.c
diff --git a/lib/builtins/ppc/fixtfdi.c b/lib/builtins/ppc/fixtfdi.c
new file mode 100644
index 000000000000..2c7c0f8e279f
--- /dev/null
+++ b/lib/builtins/ppc/fixtfdi.c
@@ -0,0 +1,104 @@
+/* This file is distributed under the University of Illinois Open Source
+ * License. See LICENSE.TXT for details.
+ */
+
+/* int64_t __fixunstfdi(long double x);
+ * This file implements the PowerPC 128-bit double-double -> int64_t conversion
+ */
+
+#include "DD.h"
+#include "../int_math.h"
+
+uint64_t __fixtfdi(long double input)
+{
+ const DD x = { .ld = input };
+ const doublebits hibits = { .d = x.s.hi };
+
+ const uint32_t absHighWord = (uint32_t)(hibits.x >> 32) & UINT32_C(0x7fffffff);
+ const uint32_t absHighWordMinusOne = absHighWord - UINT32_C(0x3ff00000);
+
+ /* If (1.0 - tiny) <= input < 0x1.0p63: */
+ if (UINT32_C(0x03f00000) > absHighWordMinusOne)
+ {
+ /* Do an unsigned conversion of the absolute value, then restore the sign. */
+ const int unbiasedHeadExponent = absHighWordMinusOne >> 20;
+
+ int64_t result = hibits.x & INT64_C(0x000fffffffffffff); /* mantissa(hi) */
+ result |= INT64_C(0x0010000000000000); /* matissa(hi) with implicit bit */
+ result <<= 10; /* mantissa(hi) with one zero preceding bit. */
+
+ const int64_t hiNegationMask = ((int64_t)(hibits.x)) >> 63;
+
+ /* If the tail is non-zero, we need to patch in the tail bits. */
+ if (0.0 != x.s.lo)
+ {
+ const doublebits lobits = { .d = x.s.lo };
+ int64_t tailMantissa = lobits.x & INT64_C(0x000fffffffffffff);
+ tailMantissa |= INT64_C(0x0010000000000000);
+
+ /* At this point we have the mantissa of |tail| */
+ /* We need to negate it if head and tail have different signs. */
+ const int64_t loNegationMask = ((int64_t)(lobits.x)) >> 63;
+ const int64_t negationMask = loNegationMask ^ hiNegationMask;
+ tailMantissa = (tailMantissa ^ negationMask) - negationMask;
+
+ /* Now we have the mantissa of tail as a signed 2s-complement integer */
+
+ const int biasedTailExponent = (int)(lobits.x >> 52) & 0x7ff;
+
+ /* Shift the tail mantissa into the right position, accounting for the
+ * bias of 10 that we shifted the head mantissa by.
+ */
+ tailMantissa >>= (unbiasedHeadExponent - (biasedTailExponent - (1023 - 10)));
+
+ result += tailMantissa;
+ }
+
+ result >>= (62 - unbiasedHeadExponent);
+
+ /* Restore the sign of the result and return */
+ result = (result ^ hiNegationMask) - hiNegationMask;
+ return result;
+
+ }
+
+ /* Edge cases handled here: */
+
+ /* |x| < 1, result is zero. */
+ if (1.0 > crt_fabs(x.s.hi))
+ return INT64_C(0);
+
+ /* x very close to INT64_MIN, care must be taken to see which side we are on. */
+ if (x.s.hi == -0x1.0p63) {
+
+ int64_t result = INT64_MIN;
+
+ if (0.0 < x.s.lo)
+ {
+ /* If the tail is positive, the correct result is something other than INT64_MIN.
+ * we'll need to figure out what it is.
+ */
+
+ const doublebits lobits = { .d = x.s.lo };
+ int64_t tailMantissa = lobits.x & INT64_C(0x000fffffffffffff);
+ tailMantissa |= INT64_C(0x0010000000000000);
+
+ /* Now we negate the tailMantissa */
+ tailMantissa = (tailMantissa ^ INT64_C(-1)) + INT64_C(1);
+
+ /* And shift it by the appropriate amount */
+ const int biasedTailExponent = (int)(lobits.x >> 52) & 0x7ff;
+ tailMantissa >>= 1075 - biasedTailExponent;
+
+ result -= tailMantissa;
+ }
+
+ return result;
+ }
+
+ /* Signed overflows, infinities, and NaNs */
+ if (x.s.hi > 0.0)
+ return INT64_MAX;
+ else
+ return INT64_MIN;
+}
diff --git a/lib/ppc/fixunstfdi.c b/lib/builtins/ppc/fixunstfdi.c
index 5e6e2cedf6ac..5e6e2cedf6ac 100644
--- a/lib/ppc/fixunstfdi.c
+++ b/lib/builtins/ppc/fixunstfdi.c
diff --git a/lib/ppc/floatditf.c b/lib/builtins/ppc/floatditf.c
index beabdd017422..beabdd017422 100644
--- a/lib/ppc/floatditf.c
+++ b/lib/builtins/ppc/floatditf.c
diff --git a/lib/ppc/floatunditf.c b/lib/builtins/ppc/floatunditf.c
index b12e1e738fd0..b12e1e738fd0 100644
--- a/lib/ppc/floatunditf.c
+++ b/lib/builtins/ppc/floatunditf.c
diff --git a/lib/builtins/ppc/gcc_qadd.c b/lib/builtins/ppc/gcc_qadd.c
new file mode 100644
index 000000000000..32e16e9d1d11
--- /dev/null
+++ b/lib/builtins/ppc/gcc_qadd.c
@@ -0,0 +1,76 @@
+/* This file is distributed under the University of Illinois Open Source
+ * License. See LICENSE.TXT for details.
+ */
+
+/* long double __gcc_qadd(long double x, long double y);
+ * This file implements the PowerPC 128-bit double-double add operation.
+ * This implementation is shamelessly cribbed from Apple's DDRT, circa 1993(!)
+ */
+
+#include "DD.h"
+
+long double __gcc_qadd(long double x, long double y)
+{
+ static const uint32_t infinityHi = UINT32_C(0x7ff00000);
+
+ DD dst = { .ld = x }, src = { .ld = y };
+
+ register double A = dst.s.hi, a = dst.s.lo,
+ B = src.s.hi, b = src.s.lo;
+
+ /* If both operands are zero: */
+ if ((A == 0.0) && (B == 0.0)) {
+ dst.s.hi = A + B;
+ dst.s.lo = 0.0;
+ return dst.ld;
+ }
+
+ /* If either operand is NaN or infinity: */
+ const doublebits abits = { .d = A };
+ const doublebits bbits = { .d = B };
+ if ((((uint32_t)(abits.x >> 32) & infinityHi) == infinityHi) ||
+ (((uint32_t)(bbits.x >> 32) & infinityHi) == infinityHi)) {
+ dst.s.hi = A + B;
+ dst.s.lo = 0.0;
+ return dst.ld;
+ }
+
+ /* If the computation overflows: */
+ /* This may be playing things a little bit fast and loose, but it will do for a start. */
+ const double testForOverflow = A + (B + (a + b));
+ const doublebits testbits = { .d = testForOverflow };
+ if (((uint32_t)(testbits.x >> 32) & infinityHi) == infinityHi) {
+ dst.s.hi = testForOverflow;
+ dst.s.lo = 0.0;
+ return dst.ld;
+ }
+
+ double H, h;
+ double T, t;
+ double W, w;
+ double Y;
+
+ H = B + (A - (A + B));
+ T = b + (a - (a + b));
+ h = A + (B - (A + B));
+ t = a + (b - (a + b));
+
+ if (local_fabs(A) <= local_fabs(B))
+ w = (a + b) + h;
+ else
+ w = (a + b) + H;
+
+ W = (A + B) + w;
+ Y = (A + B) - W;
+ Y += w;
+
+ if (local_fabs(a) <= local_fabs(b))
+ w = t + Y;
+ else
+ w = T + Y;
+
+ dst.s.hi = Y = W + w;
+ dst.s.lo = (W - Y) + w;
+
+ return dst.ld;
+}
diff --git a/lib/ppc/gcc_qdiv.c b/lib/builtins/ppc/gcc_qdiv.c
index 70aa00b64400..70aa00b64400 100644
--- a/lib/ppc/gcc_qdiv.c
+++ b/lib/builtins/ppc/gcc_qdiv.c
diff --git a/lib/ppc/gcc_qmul.c b/lib/builtins/ppc/gcc_qmul.c
index fb4c5164ccb5..fb4c5164ccb5 100644
--- a/lib/ppc/gcc_qmul.c
+++ b/lib/builtins/ppc/gcc_qmul.c
diff --git a/lib/builtins/ppc/gcc_qsub.c b/lib/builtins/ppc/gcc_qsub.c
new file mode 100644
index 000000000000..c092e24dbda1
--- /dev/null
+++ b/lib/builtins/ppc/gcc_qsub.c
@@ -0,0 +1,76 @@
+/* This file is distributed under the University of Illinois Open Source
+ * License. See LICENSE.TXT for details.
+ */
+
+/* long double __gcc_qsub(long double x, long double y);
+ * This file implements the PowerPC 128-bit double-double add operation.
+ * This implementation is shamelessly cribbed from Apple's DDRT, circa 1993(!)
+ */
+
+#include "DD.h"
+
+long double __gcc_qsub(long double x, long double y)
+{
+ static const uint32_t infinityHi = UINT32_C(0x7ff00000);
+
+ DD dst = { .ld = x }, src = { .ld = y };
+
+ register double A = dst.s.hi, a = dst.s.lo,
+ B = -src.s.hi, b = -src.s.lo;
+
+ /* If both operands are zero: */
+ if ((A == 0.0) && (B == 0.0)) {
+ dst.s.hi = A + B;
+ dst.s.lo = 0.0;
+ return dst.ld;
+ }
+
+ /* If either operand is NaN or infinity: */
+ const doublebits abits = { .d = A };
+ const doublebits bbits = { .d = B };
+ if ((((uint32_t)(abits.x >> 32) & infinityHi) == infinityHi) ||
+ (((uint32_t)(bbits.x >> 32) & infinityHi) == infinityHi)) {
+ dst.s.hi = A + B;
+ dst.s.lo = 0.0;
+ return dst.ld;
+ }
+
+ /* If the computation overflows: */
+ /* This may be playing things a little bit fast and loose, but it will do for a start. */
+ const double testForOverflow = A + (B + (a + b));
+ const doublebits testbits = { .d = testForOverflow };
+ if (((uint32_t)(testbits.x >> 32) & infinityHi) == infinityHi) {
+ dst.s.hi = testForOverflow;
+ dst.s.lo = 0.0;
+ return dst.ld;
+ }
+
+ double H, h;
+ double T, t;
+ double W, w;
+ double Y;
+
+ H = B + (A - (A + B));
+ T = b + (a - (a + b));
+ h = A + (B - (A + B));
+ t = a + (b - (a + b));
+
+ if (local_fabs(A) <= local_fabs(B))
+ w = (a + b) + h;
+ else
+ w = (a + b) + H;
+
+ W = (A + B) + w;
+ Y = (A + B) - W;
+ Y += w;
+
+ if (local_fabs(a) <= local_fabs(b))
+ w = t + Y;
+ else
+ w = T + Y;
+
+ dst.s.hi = Y = W + w;
+ dst.s.lo = (W - Y) + w;
+
+ return dst.ld;
+}
diff --git a/lib/ppc/multc3.c b/lib/builtins/ppc/multc3.c
index 738b65a83b03..738b65a83b03 100644
--- a/lib/ppc/multc3.c
+++ b/lib/builtins/ppc/multc3.c
diff --git a/lib/ppc/restFP.S b/lib/builtins/ppc/restFP.S
index 95032897c0da..95032897c0da 100644
--- a/lib/ppc/restFP.S
+++ b/lib/builtins/ppc/restFP.S
diff --git a/lib/ppc/saveFP.S b/lib/builtins/ppc/saveFP.S
index 72bd459f4cc0..72bd459f4cc0 100644
--- a/lib/ppc/saveFP.S
+++ b/lib/builtins/ppc/saveFP.S
diff --git a/lib/builtins/subdf3.c b/lib/builtins/subdf3.c
new file mode 100644
index 000000000000..089e062415b7
--- /dev/null
+++ b/lib/builtins/subdf3.c
@@ -0,0 +1,26 @@
+//===-- lib/adddf3.c - Double-precision subtraction ---------------*- 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 double-precision soft-float subtraction with the
+// IEEE-754 default rounding (to nearest, ties to even).
+//
+//===----------------------------------------------------------------------===//
+
+#define DOUBLE_PRECISION
+#include "fp_lib.h"
+
+ARM_EABI_FNALIAS(dsub, subdf3)
+
+// Subtraction; flip the sign bit of b and add.
+COMPILER_RT_ABI fp_t
+__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
new file mode 100644
index 000000000000..47f5e5e46ea8
--- /dev/null
+++ b/lib/builtins/subsf3.c
@@ -0,0 +1,26 @@
+//===-- lib/subsf3.c - Single-precision subtraction ---------------*- 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 single-precision soft-float subtraction with the
+// IEEE-754 default rounding (to nearest, ties to even).
+//
+//===----------------------------------------------------------------------===//
+
+#define SINGLE_PRECISION
+#include "fp_lib.h"
+
+ARM_EABI_FNALIAS(fsub, subsf3)
+
+// Subtraction; flip the sign bit of b and add.
+COMPILER_RT_ABI fp_t
+__subsf3(fp_t a, fp_t b) {
+ return __addsf3(a, fromRep(toRep(b) ^ signBit));
+}
+
+/* FIXME: rsub for ARM EABI */
diff --git a/lib/builtins/subtf3.c b/lib/builtins/subtf3.c
new file mode 100644
index 000000000000..609b816f41e3
--- /dev/null
+++ b/lib/builtins/subtf3.c
@@ -0,0 +1,27 @@
+//===-- lib/subtf3.c - Quad-precision subtraction -----------------*- 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 quad-precision soft-float subtraction with the
+// IEEE-754 default rounding (to nearest, ties to even).
+//
+//===----------------------------------------------------------------------===//
+
+#define QUAD_PRECISION
+#include "fp_lib.h"
+
+#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
+COMPILER_RT_ABI fp_t __addtf3(fp_t a, fp_t b);
+
+// Subtraction; flip the sign bit of b and add.
+COMPILER_RT_ABI fp_t
+__subtf3(fp_t a, fp_t b) {
+ return __addtf3(a, fromRep(toRep(b) ^ signBit));
+}
+
+#endif
diff --git a/lib/builtins/subvdi3.c b/lib/builtins/subvdi3.c
new file mode 100644
index 000000000000..71fc70ffa92d
--- /dev/null
+++ b/lib/builtins/subvdi3.c
@@ -0,0 +1,36 @@
+/* ===-- subvdi3.c - Implement __subvdi3 -----------------------------------===
+ *
+ * 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 __subvdi3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: a - b */
+
+/* Effects: aborts if a - b overflows */
+
+COMPILER_RT_ABI di_int
+__subvdi3(di_int a, di_int b)
+{
+ di_int s = (du_int) a - (du_int) b;
+ if (b >= 0)
+ {
+ if (s > a)
+ compilerrt_abort();
+ }
+ else
+ {
+ if (s <= a)
+ compilerrt_abort();
+ }
+ return s;
+}
diff --git a/lib/builtins/subvsi3.c b/lib/builtins/subvsi3.c
new file mode 100644
index 000000000000..e6c0fb688c97
--- /dev/null
+++ b/lib/builtins/subvsi3.c
@@ -0,0 +1,36 @@
+/* ===-- subvsi3.c - Implement __subvsi3 -----------------------------------===
+ *
+ * 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 __subvsi3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: a - b */
+
+/* Effects: aborts if a - b overflows */
+
+COMPILER_RT_ABI si_int
+__subvsi3(si_int a, si_int b)
+{
+ si_int s = (su_int) a - (su_int) b;
+ if (b >= 0)
+ {
+ if (s > a)
+ compilerrt_abort();
+ }
+ else
+ {
+ if (s <= a)
+ compilerrt_abort();
+ }
+ return s;
+}
diff --git a/lib/builtins/subvti3.c b/lib/builtins/subvti3.c
new file mode 100644
index 000000000000..a6804d2d7b95
--- /dev/null
+++ b/lib/builtins/subvti3.c
@@ -0,0 +1,40 @@
+/* ===-- subvti3.c - Implement __subvti3 -----------------------------------===
+ *
+ * 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 __subvti3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+/* Returns: a - b */
+
+/* Effects: aborts if a - b overflows */
+
+COMPILER_RT_ABI ti_int
+__subvti3(ti_int a, ti_int b)
+{
+ ti_int s = (tu_int) a - (tu_int) b;
+ if (b >= 0)
+ {
+ if (s > a)
+ compilerrt_abort();
+ }
+ else
+ {
+ if (s <= a)
+ compilerrt_abort();
+ }
+ return s;
+}
+
+#endif /* CRT_HAS_128BIT */
diff --git a/lib/builtins/trampoline_setup.c b/lib/builtins/trampoline_setup.c
new file mode 100644
index 000000000000..25b627ab7658
--- /dev/null
+++ b/lib/builtins/trampoline_setup.c
@@ -0,0 +1,48 @@
+/* ===----- trampoline_setup.c - Implement __trampoline_setup -------------===
+ *
+ * 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 "int_lib.h"
+
+extern void __clear_cache(void* start, void* end);
+
+/*
+ * The ppc compiler generates calls to __trampoline_setup() when creating
+ * trampoline functions on the stack for use with nested functions.
+ * This function creates a custom 40-byte trampoline function on the stack
+ * which loads r11 with a pointer to the outer function's locals
+ * and then jumps to the target nested function.
+ */
+
+#if __ppc__ && !defined(__powerpc64__)
+COMPILER_RT_ABI void
+__trampoline_setup(uint32_t* trampOnStack, int trampSizeAllocated,
+ const void* realFunc, void* localsPtr)
+{
+ /* should never happen, but if compiler did not allocate */
+ /* enough space on stack for the trampoline, abort */
+ if ( trampSizeAllocated < 40 )
+ compilerrt_abort();
+
+ /* create trampoline */
+ trampOnStack[0] = 0x7c0802a6; /* mflr r0 */
+ trampOnStack[1] = 0x4800000d; /* bl Lbase */
+ trampOnStack[2] = (uint32_t)realFunc;
+ trampOnStack[3] = (uint32_t)localsPtr;
+ trampOnStack[4] = 0x7d6802a6; /* Lbase: mflr r11 */
+ trampOnStack[5] = 0x818b0000; /* lwz r12,0(r11) */
+ trampOnStack[6] = 0x7c0803a6; /* mtlr r0 */
+ trampOnStack[7] = 0x7d8903a6; /* mtctr r12 */
+ trampOnStack[8] = 0x816b0004; /* lwz r11,4(r11) */
+ trampOnStack[9] = 0x4e800420; /* bctr */
+
+ /* clear instruction cache */
+ __clear_cache(trampOnStack, &trampOnStack[10]);
+}
+#endif /* __ppc__ && !defined(__powerpc64__) */
diff --git a/lib/builtins/truncdfsf2.c b/lib/builtins/truncdfsf2.c
new file mode 100644
index 000000000000..46ec11dccd79
--- /dev/null
+++ b/lib/builtins/truncdfsf2.c
@@ -0,0 +1,18 @@
+//===-- lib/truncdfsf2.c - double -> single 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.
+//
+//===----------------------------------------------------------------------===//
+
+#define SRC_DOUBLE
+#define DST_SINGLE
+#include "fp_trunc_impl.inc"
+
+ARM_EABI_FNALIAS(d2f, truncdfsf2)
+
+COMPILER_RT_ABI float __truncdfsf2(double a) {
+ return __truncXfYf2__(a);
+}
diff --git a/lib/builtins/trunctfdf2.c b/lib/builtins/trunctfdf2.c
new file mode 100644
index 000000000000..741a71b33c5a
--- /dev/null
+++ b/lib/builtins/trunctfdf2.c
@@ -0,0 +1,22 @@
+//===-- lib/truncdfsf2.c - quad -> double 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.
+//
+//===----------------------------------------------------------------------===//
+
+#define QUAD_PRECISION
+#include "fp_lib.h"
+
+#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
+#define SRC_QUAD
+#define DST_DOUBLE
+#include "fp_trunc_impl.inc"
+
+COMPILER_RT_ABI double __trunctfdf2(long double a) {
+ return __truncXfYf2__(a);
+}
+
+#endif
diff --git a/lib/builtins/trunctfsf2.c b/lib/builtins/trunctfsf2.c
new file mode 100644
index 000000000000..de96c1decf63
--- /dev/null
+++ b/lib/builtins/trunctfsf2.c
@@ -0,0 +1,22 @@
+//===-- lib/trunctfsf2.c - quad -> single 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.
+//
+//===----------------------------------------------------------------------===//
+
+#define QUAD_PRECISION
+#include "fp_lib.h"
+
+#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
+#define SRC_QUAD
+#define DST_SINGLE
+#include "fp_trunc_impl.inc"
+
+COMPILER_RT_ABI float __trunctfsf2(long double a) {
+ return __truncXfYf2__(a);
+}
+
+#endif
diff --git a/lib/ucmpdi2.c b/lib/builtins/ucmpdi2.c
index 40af23613b1f..40af23613b1f 100644
--- a/lib/ucmpdi2.c
+++ b/lib/builtins/ucmpdi2.c
diff --git a/lib/builtins/ucmpti2.c b/lib/builtins/ucmpti2.c
new file mode 100644
index 000000000000..bda8083bb2a1
--- /dev/null
+++ b/lib/builtins/ucmpti2.c
@@ -0,0 +1,42 @@
+/* ===-- ucmpti2.c - Implement __ucmpti2 -----------------------------------===
+ *
+ * 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 __ucmpti2 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+/* Returns: if (a < b) returns 0
+ * if (a == b) returns 1
+ * if (a > b) returns 2
+ */
+
+COMPILER_RT_ABI si_int
+__ucmpti2(tu_int a, tu_int b)
+{
+ utwords x;
+ x.all = a;
+ utwords y;
+ y.all = b;
+ if (x.s.high < y.s.high)
+ return 0;
+ if (x.s.high > y.s.high)
+ return 2;
+ if (x.s.low < y.s.low)
+ return 0;
+ if (x.s.low > y.s.low)
+ return 2;
+ return 1;
+}
+
+#endif /* CRT_HAS_128BIT */
diff --git a/lib/builtins/udivdi3.c b/lib/builtins/udivdi3.c
new file mode 100644
index 000000000000..dc68e154b109
--- /dev/null
+++ b/lib/builtins/udivdi3.c
@@ -0,0 +1,23 @@
+/* ===-- udivdi3.c - Implement __udivdi3 -----------------------------------===
+ *
+ * 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 __udivdi3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: a / b */
+
+COMPILER_RT_ABI du_int
+__udivdi3(du_int a, du_int b)
+{
+ return __udivmoddi4(a, b, 0);
+}
diff --git a/lib/builtins/udivmoddi4.c b/lib/builtins/udivmoddi4.c
new file mode 100644
index 000000000000..0c8b4ff46474
--- /dev/null
+++ b/lib/builtins/udivmoddi4.c
@@ -0,0 +1,231 @@
+/* ===-- udivmoddi4.c - Implement __udivmoddi4 -----------------------------===
+ *
+ * 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 __udivmoddi4 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Effects: if rem != 0, *rem = a % b
+ * Returns: a / b
+ */
+
+/* Translated from Figure 3-40 of The PowerPC Compiler Writer's Guide */
+
+COMPILER_RT_ABI du_int
+__udivmoddi4(du_int a, du_int b, du_int* rem)
+{
+ const unsigned n_uword_bits = sizeof(su_int) * CHAR_BIT;
+ const unsigned n_udword_bits = sizeof(du_int) * CHAR_BIT;
+ udwords n;
+ n.all = a;
+ udwords d;
+ d.all = b;
+ udwords q;
+ udwords r;
+ unsigned sr;
+ /* special cases, X is unknown, K != 0 */
+ if (n.s.high == 0)
+ {
+ if (d.s.high == 0)
+ {
+ /* 0 X
+ * ---
+ * 0 X
+ */
+ if (rem)
+ *rem = n.s.low % d.s.low;
+ return n.s.low / d.s.low;
+ }
+ /* 0 X
+ * ---
+ * K X
+ */
+ if (rem)
+ *rem = n.s.low;
+ return 0;
+ }
+ /* n.s.high != 0 */
+ if (d.s.low == 0)
+ {
+ if (d.s.high == 0)
+ {
+ /* K X
+ * ---
+ * 0 0
+ */
+ if (rem)
+ *rem = n.s.high % d.s.low;
+ return n.s.high / d.s.low;
+ }
+ /* d.s.high != 0 */
+ if (n.s.low == 0)
+ {
+ /* K 0
+ * ---
+ * K 0
+ */
+ if (rem)
+ {
+ r.s.high = n.s.high % d.s.high;
+ r.s.low = 0;
+ *rem = r.all;
+ }
+ return n.s.high / d.s.high;
+ }
+ /* K K
+ * ---
+ * K 0
+ */
+ if ((d.s.high & (d.s.high - 1)) == 0) /* if d is a power of 2 */
+ {
+ if (rem)
+ {
+ r.s.low = n.s.low;
+ r.s.high = n.s.high & (d.s.high - 1);
+ *rem = r.all;
+ }
+ return n.s.high >> __builtin_ctz(d.s.high);
+ }
+ /* K K
+ * ---
+ * K 0
+ */
+ sr = __builtin_clz(d.s.high) - __builtin_clz(n.s.high);
+ /* 0 <= sr <= n_uword_bits - 2 or sr large */
+ if (sr > n_uword_bits - 2)
+ {
+ if (rem)
+ *rem = n.all;
+ return 0;
+ }
+ ++sr;
+ /* 1 <= sr <= n_uword_bits - 1 */
+ /* q.all = n.all << (n_udword_bits - sr); */
+ q.s.low = 0;
+ q.s.high = n.s.low << (n_uword_bits - sr);
+ /* r.all = n.all >> sr; */
+ r.s.high = n.s.high >> sr;
+ r.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr);
+ }
+ else /* d.s.low != 0 */
+ {
+ if (d.s.high == 0)
+ {
+ /* K X
+ * ---
+ * 0 K
+ */
+ if ((d.s.low & (d.s.low - 1)) == 0) /* if d is a power of 2 */
+ {
+ if (rem)
+ *rem = n.s.low & (d.s.low - 1);
+ if (d.s.low == 1)
+ return n.all;
+ sr = __builtin_ctz(d.s.low);
+ q.s.high = n.s.high >> sr;
+ q.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr);
+ return q.all;
+ }
+ /* K X
+ * ---
+ * 0 K
+ */
+ sr = 1 + n_uword_bits + __builtin_clz(d.s.low) - __builtin_clz(n.s.high);
+ /* 2 <= sr <= n_udword_bits - 1
+ * q.all = n.all << (n_udword_bits - sr);
+ * r.all = n.all >> sr;
+ */
+ if (sr == n_uword_bits)
+ {
+ q.s.low = 0;
+ q.s.high = n.s.low;
+ r.s.high = 0;
+ r.s.low = n.s.high;
+ }
+ else if (sr < n_uword_bits) // 2 <= sr <= n_uword_bits - 1
+ {
+ q.s.low = 0;
+ q.s.high = n.s.low << (n_uword_bits - sr);
+ r.s.high = n.s.high >> sr;
+ r.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr);
+ }
+ else // n_uword_bits + 1 <= sr <= n_udword_bits - 1
+ {
+ q.s.low = n.s.low << (n_udword_bits - sr);
+ q.s.high = (n.s.high << (n_udword_bits - sr)) |
+ (n.s.low >> (sr - n_uword_bits));
+ r.s.high = 0;
+ r.s.low = n.s.high >> (sr - n_uword_bits);
+ }
+ }
+ else
+ {
+ /* K X
+ * ---
+ * K K
+ */
+ sr = __builtin_clz(d.s.high) - __builtin_clz(n.s.high);
+ /* 0 <= sr <= n_uword_bits - 1 or sr large */
+ if (sr > n_uword_bits - 1)
+ {
+ if (rem)
+ *rem = n.all;
+ return 0;
+ }
+ ++sr;
+ /* 1 <= sr <= n_uword_bits */
+ /* q.all = n.all << (n_udword_bits - sr); */
+ q.s.low = 0;
+ if (sr == n_uword_bits)
+ {
+ q.s.high = n.s.low;
+ r.s.high = 0;
+ r.s.low = n.s.high;
+ }
+ else
+ {
+ q.s.high = n.s.low << (n_uword_bits - sr);
+ r.s.high = n.s.high >> sr;
+ r.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr);
+ }
+ }
+ }
+ /* Not a special case
+ * q and r are initialized with:
+ * q.all = n.all << (n_udword_bits - sr);
+ * r.all = n.all >> sr;
+ * 1 <= sr <= n_udword_bits - 1
+ */
+ su_int carry = 0;
+ for (; sr > 0; --sr)
+ {
+ /* r:q = ((r:q) << 1) | carry */
+ r.s.high = (r.s.high << 1) | (r.s.low >> (n_uword_bits - 1));
+ r.s.low = (r.s.low << 1) | (q.s.high >> (n_uword_bits - 1));
+ q.s.high = (q.s.high << 1) | (q.s.low >> (n_uword_bits - 1));
+ q.s.low = (q.s.low << 1) | carry;
+ /* carry = 0;
+ * if (r.all >= d.all)
+ * {
+ * r.all -= d.all;
+ * carry = 1;
+ * }
+ */
+ const di_int s = (di_int)(d.all - r.all - 1) >> (n_udword_bits - 1);
+ carry = s & 1;
+ r.all -= d.all & s;
+ }
+ q.all = (q.all << 1) | carry;
+ if (rem)
+ *rem = r.all;
+ return q.all;
+}
diff --git a/lib/builtins/udivmodsi4.c b/lib/builtins/udivmodsi4.c
new file mode 100644
index 000000000000..789c4b5061e4
--- /dev/null
+++ b/lib/builtins/udivmodsi4.c
@@ -0,0 +1,27 @@
+/*===-- udivmodsi4.c - Implement __udivmodsi4 ------------------------------===
+ *
+ * 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 __udivmodsi4 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: a / b, *rem = a % b */
+
+COMPILER_RT_ABI su_int
+__udivmodsi4(su_int a, su_int b, su_int* rem)
+{
+ si_int d = __udivsi3(a,b);
+ *rem = a - (d*b);
+ return d;
+}
+
+
diff --git a/lib/builtins/udivmodti4.c b/lib/builtins/udivmodti4.c
new file mode 100644
index 000000000000..803168849c6c
--- /dev/null
+++ b/lib/builtins/udivmodti4.c
@@ -0,0 +1,238 @@
+/* ===-- udivmodti4.c - Implement __udivmodti4 -----------------------------===
+ *
+ * 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 __udivmodti4 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+/* Effects: if rem != 0, *rem = a % b
+ * Returns: a / b
+ */
+
+/* Translated from Figure 3-40 of The PowerPC Compiler Writer's Guide */
+
+COMPILER_RT_ABI tu_int
+__udivmodti4(tu_int a, tu_int b, tu_int* rem)
+{
+ const unsigned n_udword_bits = sizeof(du_int) * CHAR_BIT;
+ const unsigned n_utword_bits = sizeof(tu_int) * CHAR_BIT;
+ utwords n;
+ n.all = a;
+ utwords d;
+ d.all = b;
+ utwords q;
+ utwords r;
+ unsigned sr;
+ /* special cases, X is unknown, K != 0 */
+ if (n.s.high == 0)
+ {
+ if (d.s.high == 0)
+ {
+ /* 0 X
+ * ---
+ * 0 X
+ */
+ if (rem)
+ *rem = n.s.low % d.s.low;
+ return n.s.low / d.s.low;
+ }
+ /* 0 X
+ * ---
+ * K X
+ */
+ if (rem)
+ *rem = n.s.low;
+ return 0;
+ }
+ /* n.s.high != 0 */
+ if (d.s.low == 0)
+ {
+ if (d.s.high == 0)
+ {
+ /* K X
+ * ---
+ * 0 0
+ */
+ if (rem)
+ *rem = n.s.high % d.s.low;
+ return n.s.high / d.s.low;
+ }
+ /* d.s.high != 0 */
+ if (n.s.low == 0)
+ {
+ /* K 0
+ * ---
+ * K 0
+ */
+ if (rem)
+ {
+ r.s.high = n.s.high % d.s.high;
+ r.s.low = 0;
+ *rem = r.all;
+ }
+ return n.s.high / d.s.high;
+ }
+ /* K K
+ * ---
+ * K 0
+ */
+ if ((d.s.high & (d.s.high - 1)) == 0) /* if d is a power of 2 */
+ {
+ if (rem)
+ {
+ r.s.low = n.s.low;
+ r.s.high = n.s.high & (d.s.high - 1);
+ *rem = r.all;
+ }
+ return n.s.high >> __builtin_ctzll(d.s.high);
+ }
+ /* K K
+ * ---
+ * K 0
+ */
+ sr = __builtin_clzll(d.s.high) - __builtin_clzll(n.s.high);
+ /* 0 <= sr <= n_udword_bits - 2 or sr large */
+ if (sr > n_udword_bits - 2)
+ {
+ if (rem)
+ *rem = n.all;
+ return 0;
+ }
+ ++sr;
+ /* 1 <= sr <= n_udword_bits - 1 */
+ /* q.all = n.all << (n_utword_bits - sr); */
+ q.s.low = 0;
+ q.s.high = n.s.low << (n_udword_bits - sr);
+ /* r.all = n.all >> sr; */
+ r.s.high = n.s.high >> sr;
+ r.s.low = (n.s.high << (n_udword_bits - sr)) | (n.s.low >> sr);
+ }
+ else /* d.s.low != 0 */
+ {
+ if (d.s.high == 0)
+ {
+ /* K X
+ * ---
+ * 0 K
+ */
+ if ((d.s.low & (d.s.low - 1)) == 0) /* if d is a power of 2 */
+ {
+ if (rem)
+ *rem = n.s.low & (d.s.low - 1);
+ if (d.s.low == 1)
+ return n.all;
+ sr = __builtin_ctzll(d.s.low);
+ q.s.high = n.s.high >> sr;
+ q.s.low = (n.s.high << (n_udword_bits - sr)) | (n.s.low >> sr);
+ return q.all;
+ }
+ /* K X
+ * ---
+ * 0 K
+ */
+ sr = 1 + n_udword_bits + __builtin_clzll(d.s.low)
+ - __builtin_clzll(n.s.high);
+ /* 2 <= sr <= n_utword_bits - 1
+ * q.all = n.all << (n_utword_bits - sr);
+ * r.all = n.all >> sr;
+ */
+ if (sr == n_udword_bits)
+ {
+ q.s.low = 0;
+ q.s.high = n.s.low;
+ r.s.high = 0;
+ r.s.low = n.s.high;
+ }
+ else if (sr < n_udword_bits) // 2 <= sr <= n_udword_bits - 1
+ {
+ q.s.low = 0;
+ q.s.high = n.s.low << (n_udword_bits - sr);
+ r.s.high = n.s.high >> sr;
+ r.s.low = (n.s.high << (n_udword_bits - sr)) | (n.s.low >> sr);
+ }
+ else // n_udword_bits + 1 <= sr <= n_utword_bits - 1
+ {
+ q.s.low = n.s.low << (n_utword_bits - sr);
+ q.s.high = (n.s.high << (n_utword_bits - sr)) |
+ (n.s.low >> (sr - n_udword_bits));
+ r.s.high = 0;
+ r.s.low = n.s.high >> (sr - n_udword_bits);
+ }
+ }
+ else
+ {
+ /* K X
+ * ---
+ * K K
+ */
+ sr = __builtin_clzll(d.s.high) - __builtin_clzll(n.s.high);
+ /*0 <= sr <= n_udword_bits - 1 or sr large */
+ if (sr > n_udword_bits - 1)
+ {
+ if (rem)
+ *rem = n.all;
+ return 0;
+ }
+ ++sr;
+ /* 1 <= sr <= n_udword_bits
+ * q.all = n.all << (n_utword_bits - sr);
+ * r.all = n.all >> sr;
+ */
+ q.s.low = 0;
+ if (sr == n_udword_bits)
+ {
+ q.s.high = n.s.low;
+ r.s.high = 0;
+ r.s.low = n.s.high;
+ }
+ else
+ {
+ r.s.high = n.s.high >> sr;
+ r.s.low = (n.s.high << (n_udword_bits - sr)) | (n.s.low >> sr);
+ q.s.high = n.s.low << (n_udword_bits - sr);
+ }
+ }
+ }
+ /* Not a special case
+ * q and r are initialized with:
+ * q.all = n.all << (n_utword_bits - sr);
+ * r.all = n.all >> sr;
+ * 1 <= sr <= n_utword_bits - 1
+ */
+ su_int carry = 0;
+ for (; sr > 0; --sr)
+ {
+ /* r:q = ((r:q) << 1) | carry */
+ r.s.high = (r.s.high << 1) | (r.s.low >> (n_udword_bits - 1));
+ r.s.low = (r.s.low << 1) | (q.s.high >> (n_udword_bits - 1));
+ q.s.high = (q.s.high << 1) | (q.s.low >> (n_udword_bits - 1));
+ q.s.low = (q.s.low << 1) | carry;
+ /* carry = 0;
+ * if (r.all >= d.all)
+ * {
+ * r.all -= d.all;
+ * carry = 1;
+ * }
+ */
+ const ti_int s = (ti_int)(d.all - r.all - 1) >> (n_utword_bits - 1);
+ carry = s & 1;
+ r.all -= d.all & s;
+ }
+ q.all = (q.all << 1) | carry;
+ if (rem)
+ *rem = r.all;
+ return q.all;
+}
+
+#endif /* CRT_HAS_128BIT */
diff --git a/lib/udivsi3.c b/lib/builtins/udivsi3.c
index 5d0140cc3e75..5d0140cc3e75 100644
--- a/lib/udivsi3.c
+++ b/lib/builtins/udivsi3.c
diff --git a/lib/builtins/udivti3.c b/lib/builtins/udivti3.c
new file mode 100644
index 000000000000..ec94673e25b0
--- /dev/null
+++ b/lib/builtins/udivti3.c
@@ -0,0 +1,27 @@
+/* ===-- udivti3.c - Implement __udivti3 -----------------------------------===
+ *
+ * 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 __udivti3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+/* Returns: a / b */
+
+COMPILER_RT_ABI tu_int
+__udivti3(tu_int a, tu_int b)
+{
+ return __udivmodti4(a, b, 0);
+}
+
+#endif /* CRT_HAS_128BIT */
diff --git a/lib/builtins/umoddi3.c b/lib/builtins/umoddi3.c
new file mode 100644
index 000000000000..d513f080a1e9
--- /dev/null
+++ b/lib/builtins/umoddi3.c
@@ -0,0 +1,25 @@
+/* ===-- umoddi3.c - Implement __umoddi3 -----------------------------------===
+ *
+ * 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 __umoddi3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: a % b */
+
+COMPILER_RT_ABI du_int
+__umoddi3(du_int a, du_int b)
+{
+ du_int r;
+ __udivmoddi4(a, b, &r);
+ return r;
+}
diff --git a/lib/builtins/umodsi3.c b/lib/builtins/umodsi3.c
new file mode 100644
index 000000000000..d5fda4a6af1f
--- /dev/null
+++ b/lib/builtins/umodsi3.c
@@ -0,0 +1,23 @@
+/* ===-- umodsi3.c - Implement __umodsi3 -----------------------------------===
+ *
+ * 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 __umodsi3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: a % b */
+
+COMPILER_RT_ABI su_int
+__umodsi3(su_int a, su_int b)
+{
+ return a - __udivsi3(a, b) * b;
+}
diff --git a/lib/builtins/umodti3.c b/lib/builtins/umodti3.c
new file mode 100644
index 000000000000..6d1ca7a8cf6f
--- /dev/null
+++ b/lib/builtins/umodti3.c
@@ -0,0 +1,29 @@
+/* ===-- umodti3.c - Implement __umodti3 -----------------------------------===
+ *
+ * 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 __umodti3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+/* Returns: a % b */
+
+COMPILER_RT_ABI tu_int
+__umodti3(tu_int a, tu_int b)
+{
+ tu_int r;
+ __udivmodti4(a, b, &r);
+ return r;
+}
+
+#endif /* CRT_HAS_128BIT */
diff --git a/lib/builtins/x86_64/Makefile.mk b/lib/builtins/x86_64/Makefile.mk
new file mode 100644
index 000000000000..83848dddd964
--- /dev/null
+++ b/lib/builtins/x86_64/Makefile.mk
@@ -0,0 +1,20 @@
+#===- lib/builtins/x86_64/Makefile.mk ----------------------*- Makefile -*--===#
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+
+ModuleName := builtins
+SubDirs :=
+OnlyArchs := x86_64 x86_64h
+
+AsmSources := $(foreach file,$(wildcard $(Dir)/*.S),$(notdir $(file)))
+Sources := $(foreach file,$(wildcard $(Dir)/*.c),$(notdir $(file)))
+ObjNames := $(Sources:%.c=%.o) $(AsmSources:%.S=%.o)
+Implementation := Optimized
+
+# FIXME: use automatic dependencies?
+Dependencies := $(wildcard lib/*.h $(Dir)/*.h)
diff --git a/lib/x86_64/floatdidf.c b/lib/builtins/x86_64/floatdidf.c
index 388404e5e089..388404e5e089 100644
--- a/lib/x86_64/floatdidf.c
+++ b/lib/builtins/x86_64/floatdidf.c
diff --git a/lib/x86_64/floatdisf.c b/lib/builtins/x86_64/floatdisf.c
index 96c3728e92c3..96c3728e92c3 100644
--- a/lib/x86_64/floatdisf.c
+++ b/lib/builtins/x86_64/floatdisf.c
diff --git a/lib/x86_64/floatdixf.c b/lib/builtins/x86_64/floatdixf.c
index c01193a82b5e..c01193a82b5e 100644
--- a/lib/x86_64/floatdixf.c
+++ b/lib/builtins/x86_64/floatdixf.c
diff --git a/lib/builtins/x86_64/floatundidf.S b/lib/builtins/x86_64/floatundidf.S
new file mode 100644
index 000000000000..3cd5d02a743a
--- /dev/null
+++ b/lib/builtins/x86_64/floatundidf.S
@@ -0,0 +1,49 @@
+//===-- floatundidf.S - Implement __floatundidf for x86_64 ----------------===//
+//
+// 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 __floatundidf for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+// double __floatundidf(du_int a);
+
+#ifdef __x86_64__
+
+CONST_SECTION
+
+ .balign 16
+twop52:
+ .quad 0x4330000000000000
+
+ .balign 16
+twop84_plus_twop52:
+ .quad 0x4530000000100000
+
+ .balign 16
+twop84:
+ .quad 0x4530000000000000
+
+#define REL_ADDR(_a) (_a)(%rip)
+
+.text
+.balign 4
+DEFINE_COMPILERRT_FUNCTION(__floatundidf)
+ movd %edi, %xmm0 // low 32 bits of a
+ shrq $32, %rdi // high 32 bits of a
+ orq REL_ADDR(twop84), %rdi // 0x1p84 + a_hi (no rounding occurs)
+ orpd REL_ADDR(twop52), %xmm0 // 0x1p52 + a_lo (no rounding occurs)
+ movd %rdi, %xmm1
+ subsd REL_ADDR(twop84_plus_twop52), %xmm1 // a_hi - 0x1p52 (no rounding occurs)
+ addsd %xmm1, %xmm0 // a_hi + a_lo (round happens here)
+ ret
+END_COMPILERRT_FUNCTION(__floatundidf)
+
+#endif // __x86_64__
diff --git a/lib/builtins/x86_64/floatundisf.S b/lib/builtins/x86_64/floatundisf.S
new file mode 100644
index 000000000000..61952f40470c
--- /dev/null
+++ b/lib/builtins/x86_64/floatundisf.S
@@ -0,0 +1,35 @@
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+
+#include "../assembly.h"
+
+// float __floatundisf(du_int a);
+
+#ifdef __x86_64__
+
+CONST_SECTION
+
+ .balign 16
+two:
+ .single 2.0
+
+#define REL_ADDR(_a) (_a)(%rip)
+
+.text
+.balign 4
+DEFINE_COMPILERRT_FUNCTION(__floatundisf)
+ movq $1, %rsi
+ testq %rdi, %rdi
+ js 1f
+ cvtsi2ssq %rdi, %xmm0
+ ret
+
+1: andq %rdi, %rsi
+ shrq %rdi
+ orq %rsi, %rdi
+ cvtsi2ssq %rdi, %xmm0
+ mulss REL_ADDR(two), %xmm0
+ ret
+END_COMPILERRT_FUNCTION(__floatundisf)
+
+#endif // __x86_64__
diff --git a/lib/builtins/x86_64/floatundixf.S b/lib/builtins/x86_64/floatundixf.S
new file mode 100644
index 000000000000..92961c89115d
--- /dev/null
+++ b/lib/builtins/x86_64/floatundixf.S
@@ -0,0 +1,68 @@
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+
+#include "../assembly.h"
+
+// long double __floatundixf(du_int a);
+
+#ifdef __x86_64__
+
+CONST_SECTION
+
+ .balign 16
+twop64:
+ .quad 0x43f0000000000000
+
+#define REL_ADDR(_a) (_a)(%rip)
+
+ .text
+
+ .balign 4
+DEFINE_COMPILERRT_FUNCTION(__floatundixf)
+ movq %rdi, -8(%rsp)
+ fildq -8(%rsp)
+ test %rdi, %rdi
+ js 1f
+ ret
+1: faddl REL_ADDR(twop64)
+ ret
+END_COMPILERRT_FUNCTION(__floatundixf)
+
+#endif // __x86_64__
+
+
+/* Branch-free implementation is ever so slightly slower, but more beautiful.
+ It is likely superior for inlining, so I kept it around for future reference.
+
+#ifdef __x86_64__
+
+CONST_SECTION
+
+ .balign 4
+twop52:
+ .quad 0x4330000000000000
+twop84_plus_twop52_neg:
+ .quad 0xc530000000100000
+twop84:
+ .quad 0x4530000000000000
+
+#define REL_ADDR(_a) (_a)(%rip)
+
+.text
+.balign 4
+DEFINE_COMPILERRT_FUNCTION(__floatundixf)
+ movl %edi, %esi // low 32 bits of input
+ shrq $32, %rdi // hi 32 bits of input
+ orq REL_ADDR(twop84), %rdi // 2^84 + hi (as a double)
+ orq REL_ADDR(twop52), %rsi // 2^52 + lo (as a double)
+ movq %rdi, -8(%rsp)
+ movq %rsi, -16(%rsp)
+ fldl REL_ADDR(twop84_plus_twop52_neg)
+ faddl -8(%rsp) // hi - 2^52 (as double extended, no rounding occurs)
+ faddl -16(%rsp) // hi + lo (as double extended)
+ ret
+END_COMPILERRT_FUNCTION(__floatundixf)
+
+#endif // __x86_64__
+
+*/
diff --git a/lib/clear_cache.c b/lib/clear_cache.c
deleted file mode 100644
index b934fd4bdf69..000000000000
--- a/lib/clear_cache.c
+++ /dev/null
@@ -1,40 +0,0 @@
-/* ===-- clear_cache.c - Implement __clear_cache ---------------------------===
- *
- * 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 "int_lib.h"
-
-#if __APPLE__
- #include <libkern/OSCacheControl.h>
-#endif
-
-/*
- * The compiler generates calls to __clear_cache() when creating
- * trampoline functions on the stack for use with nested functions.
- * It is expected to invalidate the instruction cache for the
- * specified range.
- */
-
-void __clear_cache(void* start, void* end)
-{
-#if __i386__ || __x86_64__
-/*
- * Intel processors have a unified instruction and data cache
- * so there is nothing to do
- */
-#else
- #if __APPLE__
- /* On Darwin, sys_icache_invalidate() provides this functionality */
- sys_icache_invalidate(start, end-start);
- #else
- compilerrt_abort();
- #endif
-#endif
-}
-
diff --git a/lib/clzti2.c b/lib/clzti2.c
deleted file mode 100644
index 355c20e4239c..000000000000
--- a/lib/clzti2.c
+++ /dev/null
@@ -1,33 +0,0 @@
-/* ===-- clzti2.c - Implement __clzti2 -------------------------------------===
- *
- * 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 __clzti2 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-#if __x86_64
-
-/* Returns: the number of leading 0-bits */
-
-/* Precondition: a != 0 */
-
-si_int
-__clzti2(ti_int a)
-{
- twords x;
- x.all = a;
- const di_int f = -(x.s.high == 0);
- return __builtin_clzll((x.s.high & ~f) | (x.s.low & f)) +
- ((si_int)f & ((si_int)(sizeof(di_int) * CHAR_BIT)));
-}
-
-#endif /* __x86_64 */
diff --git a/lib/cmpti2.c b/lib/cmpti2.c
deleted file mode 100644
index d0aec452a466..000000000000
--- a/lib/cmpti2.c
+++ /dev/null
@@ -1,42 +0,0 @@
-/* ===-- cmpti2.c - Implement __cmpti2 -------------------------------------===
- *
- * 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 __cmpti2 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-#if __x86_64
-
-/* Returns: if (a < b) returns 0
- * if (a == b) returns 1
- * if (a > b) returns 2
- */
-
-si_int
-__cmpti2(ti_int a, ti_int b)
-{
- twords x;
- x.all = a;
- twords y;
- y.all = b;
- if (x.s.high < y.s.high)
- return 0;
- if (x.s.high > y.s.high)
- return 2;
- if (x.s.low < y.s.low)
- return 0;
- if (x.s.low > y.s.low)
- return 2;
- return 1;
-}
-
-#endif
diff --git a/lib/comparedf2.c b/lib/comparedf2.c
deleted file mode 100644
index de67784dc85d..000000000000
--- a/lib/comparedf2.c
+++ /dev/null
@@ -1,134 +0,0 @@
-//===-- lib/comparedf2.c - Double-precision comparisons -----------*- 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 the following soft-float comparison routines:
-//
-// __eqdf2 __gedf2 __unorddf2
-// __ledf2 __gtdf2
-// __ltdf2
-// __nedf2
-//
-// The semantics of the routines grouped in each column are identical, so there
-// is a single implementation for each, and wrappers to provide the other names.
-//
-// The main routines behave as follows:
-//
-// __ledf2(a,b) returns -1 if a < b
-// 0 if a == b
-// 1 if a > b
-// 1 if either a or b is NaN
-//
-// __gedf2(a,b) returns -1 if a < b
-// 0 if a == b
-// 1 if a > b
-// -1 if either a or b is NaN
-//
-// __unorddf2(a,b) returns 0 if both a and b are numbers
-// 1 if either a or b is NaN
-//
-// Note that __ledf2( ) and __gedf2( ) are identical except in their handling of
-// NaN values.
-//
-//===----------------------------------------------------------------------===//
-
-#define DOUBLE_PRECISION
-#include "fp_lib.h"
-
-enum LE_RESULT {
- LE_LESS = -1,
- LE_EQUAL = 0,
- LE_GREATER = 1,
- LE_UNORDERED = 1
-};
-
-enum LE_RESULT __ledf2(fp_t a, fp_t b) {
-
- const srep_t aInt = toRep(a);
- const srep_t bInt = toRep(b);
- const rep_t aAbs = aInt & absMask;
- const rep_t bAbs = bInt & absMask;
-
- // If either a or b is NaN, they are unordered.
- if (aAbs > infRep || bAbs > infRep) return LE_UNORDERED;
-
- // If a and b are both zeros, they are equal.
- if ((aAbs | bAbs) == 0) return LE_EQUAL;
-
- // If at least one of a and b is positive, we get the same result comparing
- // a and b as signed integers as we would with a floating-point compare.
- if ((aInt & bInt) >= 0) {
- if (aInt < bInt) return LE_LESS;
- else if (aInt == bInt) return LE_EQUAL;
- else return LE_GREATER;
- }
-
- // Otherwise, both are negative, so we need to flip the sense of the
- // comparison to get the correct result. (This assumes a twos- or ones-
- // complement integer representation; if integers are represented in a
- // sign-magnitude representation, then this flip is incorrect).
- else {
- if (aInt > bInt) return LE_LESS;
- else if (aInt == bInt) return LE_EQUAL;
- else return LE_GREATER;
- }
-}
-
-enum GE_RESULT {
- GE_LESS = -1,
- GE_EQUAL = 0,
- GE_GREATER = 1,
- GE_UNORDERED = -1 // Note: different from LE_UNORDERED
-};
-
-enum GE_RESULT __gedf2(fp_t a, fp_t b) {
-
- const srep_t aInt = toRep(a);
- const srep_t bInt = toRep(b);
- const rep_t aAbs = aInt & absMask;
- const rep_t bAbs = bInt & absMask;
-
- if (aAbs > infRep || bAbs > infRep) return GE_UNORDERED;
- if ((aAbs | bAbs) == 0) return GE_EQUAL;
- if ((aInt & bInt) >= 0) {
- if (aInt < bInt) return GE_LESS;
- else if (aInt == bInt) return GE_EQUAL;
- else return GE_GREATER;
- } else {
- if (aInt > bInt) return GE_LESS;
- else if (aInt == bInt) return GE_EQUAL;
- else return GE_GREATER;
- }
-}
-
-ARM_EABI_FNALIAS(dcmpun, unorddf2)
-
-int __unorddf2(fp_t a, fp_t b) {
- const rep_t aAbs = toRep(a) & absMask;
- const rep_t bAbs = toRep(b) & absMask;
- return aAbs > infRep || bAbs > infRep;
-}
-
-// The following are alternative names for the preceeding routines.
-
-enum LE_RESULT __eqdf2(fp_t a, fp_t b) {
- return __ledf2(a, b);
-}
-
-enum LE_RESULT __ltdf2(fp_t a, fp_t b) {
- return __ledf2(a, b);
-}
-
-enum LE_RESULT __nedf2(fp_t a, fp_t b) {
- return __ledf2(a, b);
-}
-
-enum GE_RESULT __gtdf2(fp_t a, fp_t b) {
- return __gedf2(a, b);
-}
-
diff --git a/lib/comparesf2.c b/lib/comparesf2.c
deleted file mode 100644
index c1c3a479c8ec..000000000000
--- a/lib/comparesf2.c
+++ /dev/null
@@ -1,133 +0,0 @@
-//===-- lib/comparesf2.c - Single-precision comparisons -----------*- 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 the following soft-fp_t comparison routines:
-//
-// __eqsf2 __gesf2 __unordsf2
-// __lesf2 __gtsf2
-// __ltsf2
-// __nesf2
-//
-// The semantics of the routines grouped in each column are identical, so there
-// is a single implementation for each, and wrappers to provide the other names.
-//
-// The main routines behave as follows:
-//
-// __lesf2(a,b) returns -1 if a < b
-// 0 if a == b
-// 1 if a > b
-// 1 if either a or b is NaN
-//
-// __gesf2(a,b) returns -1 if a < b
-// 0 if a == b
-// 1 if a > b
-// -1 if either a or b is NaN
-//
-// __unordsf2(a,b) returns 0 if both a and b are numbers
-// 1 if either a or b is NaN
-//
-// Note that __lesf2( ) and __gesf2( ) are identical except in their handling of
-// NaN values.
-//
-//===----------------------------------------------------------------------===//
-
-#define SINGLE_PRECISION
-#include "fp_lib.h"
-
-enum LE_RESULT {
- LE_LESS = -1,
- LE_EQUAL = 0,
- LE_GREATER = 1,
- LE_UNORDERED = 1
-};
-
-enum LE_RESULT __lesf2(fp_t a, fp_t b) {
-
- const srep_t aInt = toRep(a);
- const srep_t bInt = toRep(b);
- const rep_t aAbs = aInt & absMask;
- const rep_t bAbs = bInt & absMask;
-
- // If either a or b is NaN, they are unordered.
- if (aAbs > infRep || bAbs > infRep) return LE_UNORDERED;
-
- // If a and b are both zeros, they are equal.
- if ((aAbs | bAbs) == 0) return LE_EQUAL;
-
- // If at least one of a and b is positive, we get the same result comparing
- // a and b as signed integers as we would with a fp_ting-point compare.
- if ((aInt & bInt) >= 0) {
- if (aInt < bInt) return LE_LESS;
- else if (aInt == bInt) return LE_EQUAL;
- else return LE_GREATER;
- }
-
- // Otherwise, both are negative, so we need to flip the sense of the
- // comparison to get the correct result. (This assumes a twos- or ones-
- // complement integer representation; if integers are represented in a
- // sign-magnitude representation, then this flip is incorrect).
- else {
- if (aInt > bInt) return LE_LESS;
- else if (aInt == bInt) return LE_EQUAL;
- else return LE_GREATER;
- }
-}
-
-enum GE_RESULT {
- GE_LESS = -1,
- GE_EQUAL = 0,
- GE_GREATER = 1,
- GE_UNORDERED = -1 // Note: different from LE_UNORDERED
-};
-
-enum GE_RESULT __gesf2(fp_t a, fp_t b) {
-
- const srep_t aInt = toRep(a);
- const srep_t bInt = toRep(b);
- const rep_t aAbs = aInt & absMask;
- const rep_t bAbs = bInt & absMask;
-
- if (aAbs > infRep || bAbs > infRep) return GE_UNORDERED;
- if ((aAbs | bAbs) == 0) return GE_EQUAL;
- if ((aInt & bInt) >= 0) {
- if (aInt < bInt) return GE_LESS;
- else if (aInt == bInt) return GE_EQUAL;
- else return GE_GREATER;
- } else {
- if (aInt > bInt) return GE_LESS;
- else if (aInt == bInt) return GE_EQUAL;
- else return GE_GREATER;
- }
-}
-
-ARM_EABI_FNALIAS(fcmpun, unordsf2)
-
-int __unordsf2(fp_t a, fp_t b) {
- const rep_t aAbs = toRep(a) & absMask;
- const rep_t bAbs = toRep(b) & absMask;
- return aAbs > infRep || bAbs > infRep;
-}
-
-// The following are alternative names for the preceeding routines.
-
-enum LE_RESULT __eqsf2(fp_t a, fp_t b) {
- return __lesf2(a, b);
-}
-
-enum LE_RESULT __ltsf2(fp_t a, fp_t b) {
- return __lesf2(a, b);
-}
-
-enum LE_RESULT __nesf2(fp_t a, fp_t b) {
- return __lesf2(a, b);
-}
-
-enum GE_RESULT __gtsf2(fp_t a, fp_t b) {
- return __gesf2(a, b);
-}
diff --git a/lib/ctzti2.c b/lib/ctzti2.c
deleted file mode 100644
index 66dc01b7ad3e..000000000000
--- a/lib/ctzti2.c
+++ /dev/null
@@ -1,33 +0,0 @@
-/* ===-- ctzti2.c - Implement __ctzti2 -------------------------------------===
- *
- * 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 __ctzti2 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-#if __x86_64
-
-/* Returns: the number of trailing 0-bits */
-
-/* Precondition: a != 0 */
-
-si_int
-__ctzti2(ti_int a)
-{
- twords x;
- x.all = a;
- const di_int f = -(x.s.low == 0);
- return __builtin_ctzll((x.s.high & f) | (x.s.low & ~f)) +
- ((si_int)f & ((si_int)(sizeof(di_int) * CHAR_BIT)));
-}
-
-#endif
diff --git a/lib/dfsan/CMakeLists.txt b/lib/dfsan/CMakeLists.txt
index b952799ffb5b..257a15a93301 100644
--- a/lib/dfsan/CMakeLists.txt
+++ b/lib/dfsan/CMakeLists.txt
@@ -5,40 +5,44 @@ set(DFSAN_RTL_SOURCES
dfsan.cc
dfsan_custom.cc
dfsan_interceptors.cc)
-set(DFSAN_RTL_CFLAGS
- ${SANITIZER_COMMON_CFLAGS}
- # Prevent clang from generating libc calls.
- -ffreestanding)
+set(DFSAN_COMMON_CFLAGS ${SANITIZER_COMMON_CFLAGS})
+# Prevent clang from generating libc calls.
+append_list_if(COMPILER_RT_HAS_FFREESTANDING_FLAG -ffreestanding DFSAN_COMMON_CFLAGS)
# Static runtime library.
-set(DFSAN_RUNTIME_LIBRARIES)
-set(arch "x86_64")
-if(CAN_TARGET_${arch})
- add_compiler_rt_static_runtime(clang_rt.dfsan-${arch} ${arch}
+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
SOURCES ${DFSAN_RTL_SOURCES}
$<TARGET_OBJECTS:RTInterception.${arch}>
$<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
$<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>
- CFLAGS ${DFSAN_RTL_CFLAGS} -fPIE)
- add_compiler_rt_static_runtime(clang_rt.dfsan-libc-${arch} ${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_RTL_CFLAGS} -fPIC -DDFSAN_NOLIBC)
+ CFLAGS ${DFSAN_NOLIBC_CFLAGS})
add_sanitizer_rt_symbols(clang_rt.dfsan-${arch} dfsan.syms.extra)
- list(APPEND DFSAN_RUNTIME_LIBRARIES clang_rt.dfsan-${arch}
- clang_rt.dfsan-${arch}-symbols)
-endif()
+ add_dependencies(dfsan
+ clang_rt.dfsan-${arch}
+ clang_rt.dfsan-${arch}-symbols)
+endforeach()
+set(dfsan_abilist_filename ${COMPILER_RT_OUTPUT_DIR}/dfsan_abilist.txt)
add_custom_target(dfsan_abilist ALL
- SOURCES ${CLANG_RESOURCE_DIR}/dfsan_abilist.txt)
-add_custom_command(OUTPUT ${CLANG_RESOURCE_DIR}/dfsan_abilist.txt
+ DEPENDS ${dfsan_abilist_filename})
+add_custom_command(OUTPUT ${dfsan_abilist_filename}
VERBATIM
COMMAND
cat ${CMAKE_CURRENT_SOURCE_DIR}/done_abilist.txt
- ${CMAKE_CURRENT_SOURCE_DIR}/libc_ubuntu1204_abilist.txt
- > ${CLANG_RESOURCE_DIR}/dfsan_abilist.txt
- DEPENDS done_abilist.txt libc_ubuntu1204_abilist.txt)
-install(FILES ${CLANG_RESOURCE_DIR}/dfsan_abilist.txt
- DESTINATION ${LIBCLANG_INSTALL_PATH})
+ ${CMAKE_CURRENT_SOURCE_DIR}/libc_ubuntu1404_abilist.txt
+ > ${dfsan_abilist_filename}
+ DEPENDS done_abilist.txt libc_ubuntu1404_abilist.txt)
+add_dependencies(dfsan dfsan_abilist)
+install(FILES ${dfsan_abilist_filename}
+ DESTINATION ${COMPILER_RT_INSTALL_PATH})
-add_subdirectory(lit_tests)
+add_dependencies(compiler-rt dfsan)
diff --git a/lib/dfsan/dfsan.cc b/lib/dfsan/dfsan.cc
index 72d05c68604b..941edc5eba7a 100644
--- a/lib/dfsan/dfsan.cc
+++ b/lib/dfsan/dfsan.cc
@@ -63,17 +63,50 @@ SANITIZER_INTERFACE_ATTRIBUTE THREADLOCAL dfsan_label __dfsan_arg_tls[64];
// account for the double byte representation of shadow labels and move the
// address into the shadow memory range. See the function shadow_for below.
+// On Linux/MIPS64, memory is laid out as follows:
+//
+// +--------------------+ 0x10000000000 (top of memory)
+// | application memory |
+// +--------------------+ 0xF000008000 (kAppAddr)
+// | |
+// | unused |
+// | |
+// +--------------------+ 0x2200000000 (kUnusedAddr)
+// | union table |
+// +--------------------+ 0x2000000000 (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!"
+#endif
static atomic_dfsan_label *union_table(dfsan_label l1, dfsan_label l2) {
return &(*(dfsan_union_table_t *) kUnionTableAddr)[l1][l2];
}
+// Checks we do not run out of labels.
+static void dfsan_check_label(dfsan_label label) {
+ if (label == kInitializingLabel) {
+ Report("FATAL: DataFlowSanitizer: out of labels\n");
+ Die();
+ }
+}
+
// Resolves the union of two unequal labels. Nonequality is a precondition for
// this function (the instrumentation pass inlines the equality test).
extern "C" SANITIZER_INTERFACE_ATTRIBUTE
@@ -106,7 +139,7 @@ dfsan_label __dfsan_union(dfsan_label l1, dfsan_label l2) {
} else {
label =
atomic_fetch_add(&__dfsan_last_label, 1, memory_order_relaxed) + 1;
- CHECK_NE(label, kInitializingLabel);
+ dfsan_check_label(label);
__dfsan_label_info[label].l1 = l1;
__dfsan_label_info[label].l2 = l2;
}
@@ -147,6 +180,15 @@ extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __dfsan_nonzero_label() {
Report("WARNING: DataFlowSanitizer: saw nonzero label\n");
}
+// Indirect call to an uninstrumented vararg function. We don't have a way of
+// handling these at the moment.
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
+__dfsan_vararg_wrapper(const char *fname) {
+ Report("FATAL: DataFlowSanitizer: unsupported indirect call to vararg "
+ "function %s\n", fname);
+ Die();
+}
+
// Like __dfsan_union, but for use from the client or custom functions. Hence
// the equality comparison is done here before calling __dfsan_union.
SANITIZER_INTERFACE_ATTRIBUTE dfsan_label
@@ -160,7 +202,7 @@ extern "C" SANITIZER_INTERFACE_ATTRIBUTE
dfsan_label dfsan_create_label(const char *desc, void *userdata) {
dfsan_label label =
atomic_fetch_add(&__dfsan_last_label, 1, memory_order_relaxed) + 1;
- CHECK_NE(label, kInitializingLabel);
+ dfsan_check_label(label);
__dfsan_label_info[label].l1 = __dfsan_label_info[label].l2 = 0;
__dfsan_label_info[label].desc = desc;
__dfsan_label_info[label].userdata = userdata;
@@ -169,8 +211,20 @@ dfsan_label dfsan_create_label(const char *desc, void *userdata) {
extern "C" SANITIZER_INTERFACE_ATTRIBUTE
void __dfsan_set_label(dfsan_label label, void *addr, uptr size) {
- for (dfsan_label *labelp = shadow_for(addr); size != 0; --size, ++labelp)
+ for (dfsan_label *labelp = shadow_for(addr); size != 0; --size, ++labelp) {
+ // Don't write the label if it is already the value we need it to be.
+ // In a program where most addresses are not labeled, it is common that
+ // a page of shadow memory is entirely zeroed. The Linux copy-on-write
+ // implementation will share all of the zeroed pages, making a copy of a
+ // page when any value is written. The un-sharing will happen even if
+ // the value written does not change the value in memory. Avoiding the
+ // write when both |label| and |*labelp| are zero dramatically reduces
+ // the amount of real memory used by large programs.
+ if (label == *labelp)
+ continue;
+
*labelp = label;
+ }
}
SANITIZER_INTERFACE_ATTRIBUTE
@@ -230,12 +284,58 @@ dfsan_has_label_with_desc(dfsan_label label, const char *desc) {
}
}
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE uptr
+dfsan_get_label_count(void) {
+ dfsan_label max_label_allocated =
+ atomic_load(&__dfsan_last_label, memory_order_relaxed);
+
+ return static_cast<uptr>(max_label_allocated);
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
+dfsan_dump_labels(int fd) {
+ dfsan_label last_label =
+ atomic_load(&__dfsan_last_label, memory_order_relaxed);
+
+ for (uptr l = 1; l <= last_label; ++l) {
+ char buf[64];
+ internal_snprintf(buf, sizeof(buf), "%u %u %u ", l,
+ __dfsan_label_info[l].l1, __dfsan_label_info[l].l2);
+ internal_write(fd, buf, internal_strlen(buf));
+ if (__dfsan_label_info[l].l1 == 0 && __dfsan_label_info[l].desc) {
+ internal_write(fd, __dfsan_label_info[l].desc,
+ internal_strlen(__dfsan_label_info[l].desc));
+ }
+ internal_write(fd, "\n", 1);
+ }
+}
+
static void InitializeFlags(Flags &f, const char *env) {
f.warn_unimplemented = true;
f.warn_nonzero_labels = false;
+ f.strict_data_dependencies = true;
+ f.dump_labels_at_exit = "";
+
+ ParseFlag(env, &f.warn_unimplemented, "warn_unimplemented", "");
+ ParseFlag(env, &f.warn_nonzero_labels, "warn_nonzero_labels", "");
+ ParseFlag(env, &f.strict_data_dependencies, "strict_data_dependencies", "");
+ ParseFlag(env, &f.dump_labels_at_exit, "dump_labels_at_exit", "");
+}
+
+static void dfsan_fini() {
+ if (internal_strcmp(flags().dump_labels_at_exit, "") != 0) {
+ fd_t fd = OpenFile(flags().dump_labels_at_exit, true /* write */);
+ if (fd == kInvalidFd) {
+ Report("WARNING: DataFlowSanitizer: unable to open output file %s\n",
+ flags().dump_labels_at_exit);
+ return;
+ }
- ParseFlag(env, &f.warn_unimplemented, "warn_unimplemented");
- ParseFlag(env, &f.warn_nonzero_labels, "warn_nonzero_labels");
+ Report("INFO: DataFlowSanitizer: dumping labels to %s\n",
+ flags().dump_labels_at_exit);
+ dfsan_dump_labels(fd);
+ internal_close(fd);
+ }
}
#ifdef DFSAN_NOLIBC
@@ -257,9 +357,16 @@ static void dfsan_init(int argc, char **argv, char **envp) {
InitializeFlags(flags(), GetEnv("DFSAN_OPTIONS"));
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);
+
+ __dfsan_label_info[kInitializingLabel].desc = "<init label>";
}
-#ifndef DFSAN_NOLIBC
+#if !defined(DFSAN_NOLIBC) && 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 693e0c5efe04..bc38be08c9cd 100644
--- a/lib/dfsan/dfsan.h
+++ b/lib/dfsan/dfsan.h
@@ -28,6 +28,7 @@ struct dfsan_label_info {
};
extern "C" {
+void dfsan_add_label(dfsan_label label, void *addr, uptr size);
void dfsan_set_label(dfsan_label label, void *addr, uptr size);
dfsan_label dfsan_read_label(const void *addr, uptr size);
dfsan_label dfsan_union(dfsan_label l1, dfsan_label l2);
@@ -43,7 +44,11 @@ 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
}
inline const dfsan_label *shadow_for(const void *ptr) {
@@ -55,6 +60,13 @@ struct Flags {
bool warn_unimplemented;
// Whether to warn on non-zero labels.
bool warn_nonzero_labels;
+ // Whether to propagate labels only when there is an obvious data dependency
+ // (e.g., when comparing strings, ignore the fact that the output of the
+ // comparison might be data-dependent on the content of the strings). This
+ // applies only to the custom functions defined in 'custom.c'.
+ bool strict_data_dependencies;
+ // The path of the file where to dump the labels when the program terminates.
+ const char* dump_labels_at_exit;
};
extern Flags flags_data;
diff --git a/lib/dfsan/dfsan_custom.cc b/lib/dfsan/dfsan_custom.cc
index 6a132db062b3..839a399faae0 100644
--- a/lib/dfsan/dfsan_custom.cc
+++ b/lib/dfsan/dfsan_custom.cc
@@ -11,26 +11,39 @@
//
// This file defines the custom functions listed in done_abilist.txt.
//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_internal_defs.h"
#include "sanitizer_common/sanitizer_linux.h"
#include "dfsan/dfsan.h"
+#include <arpa/inet.h>
+#include <assert.h>
#include <ctype.h>
#include <dlfcn.h>
#include <link.h>
+#include <poll.h>
#include <pthread.h>
+#include <pwd.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <sys/types.h>
+#include <sys/resource.h>
+#include <sys/select.h>
#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
#include <time.h>
#include <unistd.h>
using namespace __dfsan;
extern "C" {
-
SANITIZER_INTERFACE_ATTRIBUTE int
__dfsw_stat(const char *path, struct stat *buf, dfsan_label path_label,
dfsan_label buf_label, dfsan_label *ret_label) {
@@ -58,7 +71,12 @@ SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strchr(const char *s, int c,
dfsan_label *ret_label) {
for (size_t i = 0;; ++i) {
if (s[i] == c || s[i] == 0) {
- *ret_label = dfsan_union(dfsan_read_label(s, i+1), c_label);
+ if (flags().strict_data_dependencies) {
+ *ret_label = s_label;
+ } else {
+ *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);
}
}
@@ -72,13 +90,22 @@ SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_memcmp(const void *s1, const void *s2,
const char *cs1 = (const char *) s1, *cs2 = (const char *) s2;
for (size_t i = 0; i != n; ++i) {
if (cs1[i] != cs2[i]) {
- *ret_label = dfsan_union(dfsan_read_label(cs1, i+1),
- dfsan_read_label(cs2, i+1));
+ if (flags().strict_data_dependencies) {
+ *ret_label = 0;
+ } else {
+ *ret_label = dfsan_union(dfsan_read_label(cs1, i + 1),
+ dfsan_read_label(cs2, i + 1));
+ }
return cs1[i] - cs2[i];
}
}
- *ret_label = dfsan_union(dfsan_read_label(cs1, n),
- dfsan_read_label(cs2, n));
+
+ if (flags().strict_data_dependencies) {
+ *ret_label = 0;
+ } else {
+ *ret_label = dfsan_union(dfsan_read_label(cs1, n),
+ dfsan_read_label(cs2, n));
+ }
return 0;
}
@@ -88,8 +115,12 @@ SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_strcmp(const char *s1, const char *s2,
dfsan_label *ret_label) {
for (size_t i = 0;; ++i) {
if (s1[i] != s2[i] || s1[i] == 0 || s2[i] == 0) {
- *ret_label = dfsan_union(dfsan_read_label(s1, i+1),
- dfsan_read_label(s2, i+1));
+ if (flags().strict_data_dependencies) {
+ *ret_label = 0;
+ } else {
+ *ret_label = dfsan_union(dfsan_read_label(s1, i + 1),
+ dfsan_read_label(s2, i + 1));
+ }
return s1[i] - s2[i];
}
}
@@ -101,8 +132,12 @@ __dfsw_strcasecmp(const char *s1, const char *s2, dfsan_label s1_label,
dfsan_label s2_label, dfsan_label *ret_label) {
for (size_t i = 0;; ++i) {
if (tolower(s1[i]) != tolower(s2[i]) || s1[i] == 0 || s2[i] == 0) {
- *ret_label = dfsan_union(dfsan_read_label(s1, i+1),
- dfsan_read_label(s2, i+1));
+ if (flags().strict_data_dependencies) {
+ *ret_label = 0;
+ } else {
+ *ret_label = dfsan_union(dfsan_read_label(s1, i + 1),
+ dfsan_read_label(s2, i + 1));
+ }
return s1[i] - s2[i];
}
}
@@ -120,9 +155,13 @@ SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_strncmp(const char *s1, const char *s2,
}
for (size_t i = 0;; ++i) {
- if (s1[i] != s2[i] || s1[i] == 0 || s2[i] == 0 || i == n-1) {
- *ret_label = dfsan_union(dfsan_read_label(s1, i+1),
- dfsan_read_label(s2, i+1));
+ if (s1[i] != s2[i] || s1[i] == 0 || s2[i] == 0 || i == n - 1) {
+ if (flags().strict_data_dependencies) {
+ *ret_label = 0;
+ } else {
+ *ret_label = dfsan_union(dfsan_read_label(s1, i + 1),
+ dfsan_read_label(s2, i + 1));
+ }
return s1[i] - s2[i];
}
}
@@ -141,8 +180,12 @@ __dfsw_strncasecmp(const char *s1, const char *s2, size_t n,
for (size_t i = 0;; ++i) {
if (tolower(s1[i]) != tolower(s2[i]) || s1[i] == 0 || s2[i] == 0 ||
i == n - 1) {
- *ret_label = dfsan_union(dfsan_read_label(s1, i+1),
- dfsan_read_label(s2, i+1));
+ if (flags().strict_data_dependencies) {
+ *ret_label = 0;
+ } else {
+ *ret_label = dfsan_union(dfsan_read_label(s1, i + 1),
+ dfsan_read_label(s2, i + 1));
+ }
return s1[i] - s2[i];
}
}
@@ -162,14 +205,19 @@ SANITIZER_INTERFACE_ATTRIBUTE void *__dfsw_calloc(size_t nmemb, size_t size,
SANITIZER_INTERFACE_ATTRIBUTE size_t
__dfsw_strlen(const char *s, dfsan_label s_label, dfsan_label *ret_label) {
size_t ret = strlen(s);
- *ret_label = dfsan_read_label(s, ret+1);
+ if (flags().strict_data_dependencies) {
+ *ret_label = 0;
+ } else {
+ *ret_label = dfsan_read_label(s, ret + 1);
+ }
return ret;
}
static void *dfsan_memcpy(void *dest, const void *src, size_t n) {
- dfsan_label *sdest = shadow_for(dest), *ssrc = shadow_for((void *)src);
- internal_memcpy((void *)sdest, (void *)ssrc, n * sizeof(dfsan_label));
+ dfsan_label *sdest = shadow_for(dest);
+ const dfsan_label *ssrc = shadow_for(src);
+ internal_memcpy((void *)sdest, (const void *)ssrc, n * sizeof(dfsan_label));
return internal_memcpy(dest, src, n);
}
@@ -182,7 +230,7 @@ SANITIZER_INTERFACE_ATTRIBUTE
void *__dfsw_memcpy(void *dest, const void *src, size_t n,
dfsan_label dest_label, dfsan_label src_label,
dfsan_label n_label, dfsan_label *ret_label) {
- *ret_label = 0;
+ *ret_label = dest_label;
return dfsan_memcpy(dest, src, n);
}
@@ -191,7 +239,7 @@ void *__dfsw_memset(void *s, int c, size_t n,
dfsan_label s_label, dfsan_label c_label,
dfsan_label n_label, dfsan_label *ret_label) {
dfsan_memset(s, c, c_label, n);
- *ret_label = 0;
+ *ret_label = s_label;
return s;
}
@@ -216,7 +264,7 @@ __dfsw_strncpy(char *s1, const char *s2, size_t n, dfsan_label s1_label,
dfsan_memcpy(s1, s2, n);
}
- *ret_label = 0;
+ *ret_label = s1_label;
return s1;
}
@@ -318,9 +366,11 @@ struct dl_iterate_phdr_info {
int dl_iterate_phdr_cb(struct dl_phdr_info *info, size_t size, void *data) {
dl_iterate_phdr_info *dipi = (dl_iterate_phdr_info *)data;
dfsan_set_label(0, *info);
- dfsan_set_label(0, (void *)info->dlpi_name, strlen(info->dlpi_name) + 1);
- dfsan_set_label(0, (void *)info->dlpi_phdr,
- sizeof(*info->dlpi_phdr) * info->dlpi_phnum);
+ dfsan_set_label(0, const_cast<char *>(info->dlpi_name),
+ strlen(info->dlpi_name) + 1);
+ dfsan_set_label(
+ 0, const_cast<char *>(reinterpret_cast<const char *>(info->dlpi_phdr)),
+ sizeof(*info->dlpi_phdr) * info->dlpi_phnum);
dfsan_label ret_label;
return dipi->callback_trampoline(dipi->callback, info, size, dipi->data, 0, 0,
0, &ret_label);
@@ -338,4 +388,737 @@ SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_dl_iterate_phdr(
return dl_iterate_phdr(dl_iterate_phdr_cb, &dipi);
}
+SANITIZER_INTERFACE_ATTRIBUTE
+char *__dfsw_ctime_r(const time_t *timep, char *buf, dfsan_label timep_label,
+ dfsan_label buf_label, dfsan_label *ret_label) {
+ char *ret = ctime_r(timep, buf);
+ if (ret) {
+ dfsan_set_label(dfsan_read_label(timep, sizeof(time_t)), buf,
+ strlen(buf) + 1);
+ *ret_label = buf_label;
+ } else {
+ *ret_label = 0;
+ }
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+char *__dfsw_fgets(char *s, int size, FILE *stream, dfsan_label s_label,
+ dfsan_label size_label, dfsan_label stream_label,
+ dfsan_label *ret_label) {
+ char *ret = fgets(s, size, stream);
+ if (ret) {
+ dfsan_set_label(0, ret, strlen(ret) + 1);
+ *ret_label = s_label;
+ } else {
+ *ret_label = 0;
+ }
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+char *__dfsw_getcwd(char *buf, size_t size, dfsan_label buf_label,
+ dfsan_label size_label, dfsan_label *ret_label) {
+ char *ret = getcwd(buf, size);
+ if (ret) {
+ dfsan_set_label(0, ret, strlen(ret) + 1);
+ *ret_label = buf_label;
+ } else {
+ *ret_label = 0;
+ }
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+char *__dfsw_get_current_dir_name(dfsan_label *ret_label) {
+ char *ret = get_current_dir_name();
+ if (ret) {
+ dfsan_set_label(0, ret, strlen(ret) + 1);
+ }
+ *ret_label = 0;
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __dfsw_gethostname(char *name, size_t len, dfsan_label name_label,
+ dfsan_label len_label, dfsan_label *ret_label) {
+ int ret = gethostname(name, len);
+ if (ret == 0) {
+ dfsan_set_label(0, name, strlen(name) + 1);
+ }
+ *ret_label = 0;
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __dfsw_getrlimit(int resource, struct rlimit *rlim,
+ dfsan_label resource_label, dfsan_label rlim_label,
+ dfsan_label *ret_label) {
+ int ret = getrlimit(resource, rlim);
+ if (ret == 0) {
+ dfsan_set_label(0, rlim, sizeof(struct rlimit));
+ }
+ *ret_label = 0;
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __dfsw_getrusage(int who, struct rusage *usage, dfsan_label who_label,
+ dfsan_label usage_label, dfsan_label *ret_label) {
+ int ret = getrusage(who, usage);
+ if (ret == 0) {
+ dfsan_set_label(0, usage, sizeof(struct rusage));
+ }
+ *ret_label = 0;
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+char *__dfsw_strcpy(char *dest, const char *src, dfsan_label dst_label,
+ dfsan_label src_label, dfsan_label *ret_label) {
+ char *ret = strcpy(dest, src);
+ if (ret) {
+ internal_memcpy(shadow_for(dest), shadow_for(src),
+ sizeof(dfsan_label) * (strlen(src) + 1));
+ }
+ *ret_label = dst_label;
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+long int __dfsw_strtol(const char *nptr, char **endptr, int base,
+ dfsan_label nptr_label, dfsan_label endptr_label,
+ dfsan_label base_label, dfsan_label *ret_label) {
+ char *tmp_endptr;
+ long int ret = strtol(nptr, &tmp_endptr, base);
+ if (endptr) {
+ *endptr = tmp_endptr;
+ }
+ if (tmp_endptr > nptr) {
+ // If *tmp_endptr is '\0' include its label as well.
+ *ret_label = dfsan_union(
+ base_label,
+ dfsan_read_label(nptr, tmp_endptr - nptr + (*tmp_endptr ? 0 : 1)));
+ } else {
+ *ret_label = 0;
+ }
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+double __dfsw_strtod(const char *nptr, char **endptr,
+ dfsan_label nptr_label, dfsan_label endptr_label,
+ dfsan_label *ret_label) {
+ char *tmp_endptr;
+ double ret = strtod(nptr, &tmp_endptr);
+ if (endptr) {
+ *endptr = tmp_endptr;
+ }
+ if (tmp_endptr > nptr) {
+ // If *tmp_endptr is '\0' include its label as well.
+ *ret_label = dfsan_read_label(
+ nptr,
+ tmp_endptr - nptr + (*tmp_endptr ? 0 : 1));
+ } else {
+ *ret_label = 0;
+ }
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+long long int __dfsw_strtoll(const char *nptr, char **endptr, int base,
+ dfsan_label nptr_label, dfsan_label endptr_label,
+ dfsan_label base_label, dfsan_label *ret_label) {
+ char *tmp_endptr;
+ long long int ret = strtoll(nptr, &tmp_endptr, base);
+ if (endptr) {
+ *endptr = tmp_endptr;
+ }
+ if (tmp_endptr > nptr) {
+ // If *tmp_endptr is '\0' include its label as well.
+ *ret_label = dfsan_union(
+ base_label,
+ dfsan_read_label(nptr, tmp_endptr - nptr + (*tmp_endptr ? 0 : 1)));
+ } else {
+ *ret_label = 0;
+ }
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+unsigned long int __dfsw_strtoul(const char *nptr, char **endptr, int base,
+ dfsan_label nptr_label, dfsan_label endptr_label,
+ dfsan_label base_label, dfsan_label *ret_label) {
+ char *tmp_endptr;
+ unsigned long int ret = strtoul(nptr, &tmp_endptr, base);
+ if (endptr) {
+ *endptr = tmp_endptr;
+ }
+ if (tmp_endptr > nptr) {
+ // If *tmp_endptr is '\0' include its label as well.
+ *ret_label = dfsan_union(
+ base_label,
+ dfsan_read_label(nptr, tmp_endptr - nptr + (*tmp_endptr ? 0 : 1)));
+ } else {
+ *ret_label = 0;
+ }
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+long long unsigned int __dfsw_strtoull(const char *nptr, char **endptr,
+ dfsan_label nptr_label,
+ int base, dfsan_label endptr_label,
+ dfsan_label base_label,
+ dfsan_label *ret_label) {
+ char *tmp_endptr;
+ long long unsigned int ret = strtoull(nptr, &tmp_endptr, base);
+ if (endptr) {
+ *endptr = tmp_endptr;
+ }
+ if (tmp_endptr > nptr) {
+ // If *tmp_endptr is '\0' include its label as well.
+ *ret_label = dfsan_union(
+ base_label,
+ dfsan_read_label(nptr, tmp_endptr - nptr + (*tmp_endptr ? 0 : 1)));
+ } else {
+ *ret_label = 0;
+ }
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+time_t __dfsw_time(time_t *t, dfsan_label t_label, dfsan_label *ret_label) {
+ time_t ret = time(t);
+ if (ret != (time_t) -1 && t) {
+ dfsan_set_label(0, t, sizeof(time_t));
+ }
+ *ret_label = 0;
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __dfsw_inet_pton(int af, const char *src, void *dst, dfsan_label af_label,
+ dfsan_label src_label, dfsan_label dst_label,
+ dfsan_label *ret_label) {
+ int ret = inet_pton(af, src, dst);
+ if (ret == 1) {
+ dfsan_set_label(dfsan_read_label(src, strlen(src) + 1), dst,
+ af == AF_INET ? sizeof(struct in_addr) : sizeof(in6_addr));
+ }
+ *ret_label = 0;
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+struct tm *__dfsw_localtime_r(const time_t *timep, struct tm *result,
+ dfsan_label timep_label, dfsan_label result_label,
+ dfsan_label *ret_label) {
+ struct tm *ret = localtime_r(timep, result);
+ if (ret) {
+ dfsan_set_label(dfsan_read_label(timep, sizeof(time_t)), result,
+ sizeof(struct tm));
+ *ret_label = result_label;
+ } else {
+ *ret_label = 0;
+ }
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __dfsw_getpwuid_r(id_t uid, struct passwd *pwd,
+ char *buf, size_t buflen, struct passwd **result,
+ dfsan_label uid_label, dfsan_label pwd_label,
+ dfsan_label buf_label, dfsan_label buflen_label,
+ dfsan_label result_label, dfsan_label *ret_label) {
+ // Store the data in pwd, the strings referenced from pwd in buf, and the
+ // address of pwd in *result. On failure, NULL is stored in *result.
+ int ret = getpwuid_r(uid, pwd, buf, buflen, result);
+ if (ret == 0) {
+ dfsan_set_label(0, pwd, sizeof(struct passwd));
+ dfsan_set_label(0, buf, strlen(buf) + 1);
+ }
+ *ret_label = 0;
+ dfsan_set_label(0, result, sizeof(struct passwd*));
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __dfsw_poll(struct pollfd *fds, nfds_t nfds, int timeout,
+ dfsan_label dfs_label, dfsan_label nfds_label,
+ dfsan_label timeout_label, dfsan_label *ret_label) {
+ int ret = poll(fds, nfds, timeout);
+ if (ret >= 0) {
+ for (; nfds > 0; --nfds) {
+ dfsan_set_label(0, &fds[nfds - 1].revents, sizeof(fds[nfds - 1].revents));
+ }
+ }
+ *ret_label = 0;
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __dfsw_select(int nfds, fd_set *readfds, fd_set *writefds,
+ fd_set *exceptfds, struct timeval *timeout,
+ dfsan_label nfds_label, dfsan_label readfds_label,
+ dfsan_label writefds_label, dfsan_label exceptfds_label,
+ dfsan_label timeout_label, dfsan_label *ret_label) {
+ int ret = select(nfds, readfds, writefds, exceptfds, timeout);
+ // Clear everything (also on error) since their content is either set or
+ // undefined.
+ if (readfds) {
+ dfsan_set_label(0, readfds, sizeof(fd_set));
+ }
+ if (writefds) {
+ dfsan_set_label(0, writefds, sizeof(fd_set));
+ }
+ if (exceptfds) {
+ dfsan_set_label(0, exceptfds, sizeof(fd_set));
+ }
+ dfsan_set_label(0, timeout, sizeof(struct timeval));
+ *ret_label = 0;
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __dfsw_sched_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask,
+ dfsan_label pid_label,
+ dfsan_label cpusetsize_label,
+ dfsan_label mask_label, dfsan_label *ret_label) {
+ int ret = sched_getaffinity(pid, cpusetsize, mask);
+ if (ret == 0) {
+ dfsan_set_label(0, mask, cpusetsize);
+ }
+ *ret_label = 0;
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __dfsw_sigemptyset(sigset_t *set, dfsan_label set_label,
+ dfsan_label *ret_label) {
+ int ret = sigemptyset(set);
+ dfsan_set_label(0, set, sizeof(sigset_t));
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __dfsw_sigaction(int signum, const struct sigaction *act,
+ struct sigaction *oldact, dfsan_label signum_label,
+ dfsan_label act_label, dfsan_label oldact_label,
+ dfsan_label *ret_label) {
+ int ret = sigaction(signum, act, oldact);
+ if (oldact) {
+ dfsan_set_label(0, oldact, sizeof(struct sigaction));
+ }
+ *ret_label = 0;
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __dfsw_gettimeofday(struct timeval *tv, struct timezone *tz,
+ dfsan_label tv_label, dfsan_label tz_label,
+ dfsan_label *ret_label) {
+ int ret = gettimeofday(tv, tz);
+ if (tv) {
+ dfsan_set_label(0, tv, sizeof(struct timeval));
+ }
+ if (tz) {
+ dfsan_set_label(0, tz, sizeof(struct timezone));
+ }
+ *ret_label = 0;
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE void *__dfsw_memchr(void *s, int c, size_t n,
+ dfsan_label s_label,
+ dfsan_label c_label,
+ dfsan_label n_label,
+ dfsan_label *ret_label) {
+ void *ret = memchr(s, c, n);
+ if (flags().strict_data_dependencies) {
+ *ret_label = ret ? s_label : 0;
+ } else {
+ size_t len =
+ ret ? reinterpret_cast<char *>(ret) - reinterpret_cast<char *>(s) + 1
+ : n;
+ *ret_label =
+ dfsan_union(dfsan_read_label(s, len), dfsan_union(s_label, c_label));
+ }
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strrchr(char *s, int c,
+ dfsan_label s_label,
+ dfsan_label c_label,
+ dfsan_label *ret_label) {
+ char *ret = strrchr(s, c);
+ if (flags().strict_data_dependencies) {
+ *ret_label = ret ? s_label : 0;
+ } else {
+ *ret_label =
+ dfsan_union(dfsan_read_label(s, strlen(s) + 1),
+ dfsan_union(s_label, c_label));
+ }
+
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strstr(char *haystack, char *needle,
+ dfsan_label haystack_label,
+ dfsan_label needle_label,
+ dfsan_label *ret_label) {
+ char *ret = strstr(haystack, needle);
+ if (flags().strict_data_dependencies) {
+ *ret_label = ret ? haystack_label : 0;
+ } else {
+ size_t len = ret ? ret + strlen(needle) - haystack : strlen(haystack) + 1;
+ *ret_label =
+ dfsan_union(dfsan_read_label(haystack, len),
+ dfsan_union(dfsan_read_label(needle, strlen(needle) + 1),
+ dfsan_union(haystack_label, needle_label)));
+ }
+
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_nanosleep(const struct timespec *req,
+ struct timespec *rem,
+ dfsan_label req_label,
+ dfsan_label rem_label,
+ dfsan_label *ret_label) {
+ int ret = nanosleep(req, rem);
+ *ret_label = 0;
+ if (ret == -1) {
+ // Interrupted by a signal, rem is filled with the remaining time.
+ dfsan_set_label(0, rem, sizeof(struct timespec));
+ }
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE int
+__dfsw_socketpair(int domain, int type, int protocol, int sv[2],
+ dfsan_label domain_label, dfsan_label type_label,
+ dfsan_label protocol_label, dfsan_label sv_label,
+ dfsan_label *ret_label) {
+ int ret = socketpair(domain, type, protocol, sv);
+ *ret_label = 0;
+ if (ret == 0) {
+ dfsan_set_label(0, sv, sizeof(*sv) * 2);
+ }
+ return ret;
+}
+
+// Type of the trampoline function passed to the custom version of
+// dfsan_set_write_callback.
+typedef void (*write_trampoline_t)(
+ void *callback,
+ int fd, const void *buf, ssize_t count,
+ dfsan_label fd_label, dfsan_label buf_label, dfsan_label count_label);
+
+// 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_callback_info;
+
+SANITIZER_INTERFACE_ATTRIBUTE void
+__dfsw_dfsan_set_write_callback(
+ write_trampoline_t write_callback_trampoline,
+ void *write_callback,
+ dfsan_label write_callback_label,
+ dfsan_label *ret_label) {
+ write_callback_info.write_callback_trampoline = write_callback_trampoline;
+ write_callback_info.write_callback = write_callback;
+}
+
+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) {
+ write_callback_info.write_callback_trampoline(
+ write_callback_info.write_callback,
+ fd, buf, count,
+ fd_label, buf_label, count_label);
+ }
+
+ *ret_label = 0;
+ return write(fd, buf, count);
+}
+
+// Type used to extract a dfsan_label with va_arg()
+typedef int dfsan_label_va;
+
+// A chunk of data representing the output of formatting either a constant
+// string or a single format directive.
+struct Chunk {
+ // Address of the beginning of the formatted string
+ const char *ptr;
+ // Size of the formatted string
+ size_t size;
+
+ // Type of DFSan label (depends on the format directive)
+ enum {
+ // Constant string, no argument and thus no label
+ NONE = 0,
+ // Label for an argument of '%n'
+ IGNORED,
+ // Label for a '%s' argument
+ STRING,
+ // Label for any other type of argument
+ NUMERIC,
+ } label_type;
+
+ // Value of the argument (if label_type == STRING)
+ const char *arg;
+};
+
+// Formats the input. The output is stored in 'str' starting from offset
+// 'off'. The format directive is represented by the first 'format_size' bytes
+// of 'format'. If 'has_size' is true, 'size' bounds the number of output
+// bytes. Returns the return value of the vsnprintf call used to format the
+// input.
+static int format_chunk(char *str, size_t off, bool has_size, size_t size,
+ const char *format, size_t format_size, ...) {
+ char *chunk_format = (char *) malloc(format_size + 1);
+ assert(chunk_format);
+ internal_memcpy(chunk_format, format, format_size);
+ chunk_format[format_size] = '\0';
+
+ va_list ap;
+ va_start(ap, format_size);
+ int r = 0;
+ if (has_size) {
+ r = vsnprintf(str + off, off < size ? size - off : 0, chunk_format, ap);
+ } else {
+ r = vsprintf(str + off, chunk_format, ap);
+ }
+ va_end(ap);
+
+ free(chunk_format);
+ return r;
+}
+
+// Formats the input and propagates the input labels to the output. The output
+// is stored in 'str'. If 'has_size' is true, 'size' bounds the number of
+// output bytes. 'format' and 'ap' are the format string and the list of
+// arguments for formatting. Returns the return value vsnprintf would return.
+//
+// The function tokenizes the format string in chunks representing either a
+// constant string or a single format directive (e.g., '%.3f') and formats each
+// chunk independently into the output string. This approach allows to figure
+// out which bytes of the output string depends on which argument and thus to
+// propagate labels more precisely.
+static int format_buffer(char *str, bool has_size, size_t size,
+ const char *format, dfsan_label *va_labels,
+ dfsan_label *ret_label, va_list ap) {
+ InternalMmapVector<Chunk> chunks(8);
+ size_t off = 0;
+
+ while (*format) {
+ chunks.push_back(Chunk());
+ Chunk& chunk = chunks.back();
+ chunk.ptr = str + off;
+ chunk.arg = nullptr;
+
+ int status = 0;
+
+ if (*format != '%') {
+ // Ordinary character. Consume all the characters until a '%' or the end
+ // of the string.
+ size_t format_size = 0;
+ for (; *format && *format != '%'; ++format, ++format_size) {}
+ status = format_chunk(str, off, has_size, size, format - format_size,
+ format_size);
+ chunk.label_type = Chunk::NONE;
+ } else {
+ // Conversion directive. Consume all the characters until a conversion
+ // specifier or the end of the string.
+ bool end_format = false;
+#define FORMAT_CHUNK(t) \
+ format_chunk(str, off, has_size, size, format - format_size, \
+ format_size + 1, va_arg(ap, t))
+
+ for (size_t format_size = 1; *++format && !end_format; ++format_size) {
+ switch (*format) {
+ case 'd':
+ case 'i':
+ case 'o':
+ case 'u':
+ case 'x':
+ case 'X':
+ switch (*(format - 1)) {
+ case 'h':
+ // Also covers the 'hh' case (since the size of the arg is still
+ // an int).
+ status = FORMAT_CHUNK(int);
+ break;
+ case 'l':
+ if (format_size >= 2 && *(format - 2) == 'l') {
+ status = FORMAT_CHUNK(long long int);
+ } else {
+ status = FORMAT_CHUNK(long int);
+ }
+ break;
+ case 'q':
+ status = FORMAT_CHUNK(long long int);
+ break;
+ case 'j':
+ status = FORMAT_CHUNK(intmax_t);
+ break;
+ case 'z':
+ status = FORMAT_CHUNK(size_t);
+ break;
+ case 't':
+ status = FORMAT_CHUNK(size_t);
+ break;
+ default:
+ status = FORMAT_CHUNK(int);
+ }
+ chunk.label_type = Chunk::NUMERIC;
+ end_format = true;
+ break;
+
+ case 'a':
+ case 'A':
+ case 'e':
+ case 'E':
+ case 'f':
+ case 'F':
+ case 'g':
+ case 'G':
+ if (*(format - 1) == 'L') {
+ status = FORMAT_CHUNK(long double);
+ } else {
+ status = FORMAT_CHUNK(double);
+ }
+ chunk.label_type = Chunk::NUMERIC;
+ end_format = true;
+ break;
+
+ case 'c':
+ status = FORMAT_CHUNK(int);
+ chunk.label_type = Chunk::NUMERIC;
+ end_format = true;
+ break;
+
+ case 's':
+ chunk.arg = va_arg(ap, char *);
+ status =
+ format_chunk(str, off, has_size, size,
+ format - format_size, format_size + 1,
+ chunk.arg);
+ chunk.label_type = Chunk::STRING;
+ end_format = true;
+ break;
+
+ case 'p':
+ status = FORMAT_CHUNK(void *);
+ chunk.label_type = Chunk::NUMERIC;
+ end_format = true;
+ break;
+
+ case 'n':
+ *(va_arg(ap, int *)) = (int)off;
+ chunk.label_type = Chunk::IGNORED;
+ end_format = true;
+ break;
+
+ case '%':
+ status = format_chunk(str, off, has_size, size,
+ format - format_size, format_size + 1);
+ chunk.label_type = Chunk::NONE;
+ end_format = true;
+ break;
+
+ default:
+ break;
+ }
+ }
+#undef FORMAT_CHUNK
+ }
+
+ if (status < 0) {
+ return status;
+ }
+
+ // A return value of {v,}snprintf of size or more means that the output was
+ // truncated.
+ if (has_size) {
+ if (off < size) {
+ size_t ustatus = (size_t) status;
+ chunk.size = ustatus >= (size - off) ?
+ ustatus - (size - off) : ustatus;
+ } else {
+ chunk.size = 0;
+ }
+ } else {
+ chunk.size = status;
+ }
+ off += status;
+ }
+
+ // TODO(martignlo): Decide how to combine labels (e.g., whether to ignore or
+ // not the label of the format string).
+
+ // Label each output chunk according to the label supplied as argument to the
+ // function. We need to go through all the chunks and arguments even if the
+ // string was only partially printed ({v,}snprintf case).
+ for (size_t i = 0; i < chunks.size(); ++i) {
+ const Chunk& chunk = chunks[i];
+ void *chunk_ptr = const_cast<char *>(chunk.ptr);
+
+ switch (chunk.label_type) {
+ case Chunk::NONE:
+ dfsan_set_label(0, chunk_ptr, chunk.size);
+ break;
+ case Chunk::IGNORED:
+ va_labels++;
+ dfsan_set_label(0, chunk_ptr, chunk.size);
+ break;
+ case Chunk::NUMERIC: {
+ dfsan_label label = *va_labels++;
+ dfsan_set_label(label, chunk_ptr, chunk.size);
+ break;
+ }
+ case Chunk::STRING: {
+ // Consume the label of the pointer to the string
+ va_labels++;
+ internal_memcpy(shadow_for(chunk_ptr),
+ shadow_for(chunk.arg),
+ sizeof(dfsan_label) * (strlen(chunk.arg)));
+ break;
+ }
+ }
+ }
+
+ *ret_label = 0;
+
+ // Number of bytes written in total.
+ return off;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __dfsw_sprintf(char *str, const char *format, dfsan_label str_label,
+ dfsan_label format_label, dfsan_label *va_labels,
+ dfsan_label *ret_label, ...) {
+ va_list ap;
+ va_start(ap, ret_label);
+ int ret = format_buffer(str, false, 0, format, va_labels, ret_label, ap);
+ va_end(ap);
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __dfsw_snprintf(char *str, size_t size, const char *format,
+ dfsan_label str_label, dfsan_label size_label,
+ dfsan_label format_label, dfsan_label *va_labels,
+ dfsan_label *ret_label, ...) {
+ va_list ap;
+ va_start(ap, ret_label);
+ int ret = format_buffer(str, true, size, format, va_labels, ret_label, ap);
+ va_end(ap);
+ return ret;
+}
}
diff --git a/lib/dfsan/done_abilist.txt b/lib/dfsan/done_abilist.txt
index 27df3e9b707c..15c6d1bb2e39 100644
--- a/lib/dfsan/done_abilist.txt
+++ b/lib/dfsan/done_abilist.txt
@@ -1,38 +1,41 @@
fun:main=uninstrumented
fun:main=discard
-# DFSan interface functions.
+###############################################################################
+# DFSan interface functions
+###############################################################################
fun:dfsan_union=uninstrumented
fun:dfsan_union=discard
-
fun:dfsan_create_label=uninstrumented
fun:dfsan_create_label=discard
-
fun:dfsan_set_label=uninstrumented
fun:dfsan_set_label=discard
-
fun:dfsan_add_label=uninstrumented
fun:dfsan_add_label=discard
-
fun:dfsan_get_label=uninstrumented
fun:dfsan_get_label=custom
-
fun:dfsan_read_label=uninstrumented
fun:dfsan_read_label=discard
-
+fun:dfsan_get_label_count=uninstrumented
+fun:dfsan_get_label_count=discard
fun:dfsan_get_label_info=uninstrumented
fun:dfsan_get_label_info=discard
-
fun:dfsan_has_label=uninstrumented
fun:dfsan_has_label=discard
-
fun:dfsan_has_label_with_desc=uninstrumented
fun:dfsan_has_label_with_desc=discard
+fun:dfsan_set_write_callback=uninstrumented
+fun:dfsan_set_write_callback=custom
-# glibc functions.
+###############################################################################
+# glibc
+###############################################################################
fun:malloc=discard
fun:realloc=discard
fun:free=discard
+
+# Functions that return a value that depends on the input, but the output might
+# not be necessarily data-dependent on the input.
fun:isalpha=functional
fun:isdigit=functional
fun:isprint=functional
@@ -42,86 +45,216 @@ fun:ispunct=functional
fun:isspace=functional
fun:tolower=functional
fun:toupper=functional
+
+# Functions that return a value that is data-dependent on the input.
+fun:btowc=functional
fun:exp=functional
fun:exp2=functional
+fun:fabs=functional
+fun:finite=functional
+fun:floor=functional
+fun:fmod=functional
+fun:isinf=functional
+fun:isnan=functional
fun:log=functional
+fun:modf=functional
+fun:pow=functional
+fun:round=functional
fun:sqrt=functional
-fun:__cxa_atexit=discard
-fun:open=discard
-fun:pthread_key_create=discard
-fun:getenv=discard
+fun:wctob=functional
+
+# Functions that produce an output that does not depend on the input (shadow is
+# zeroed automatically).
+fun:__assert_fail=discard
fun:__ctype_b_loc=discard
+fun:__cxa_atexit=discard
fun:__errno_location=discard
-fun:mmap=discard
-fun:munmap=discard
-fun:write=discard
+fun:__newlocale=discard
+fun:__sbrk=discard
+fun:__sigsetjmp=discard
+fun:__uselocale=discard
+fun:__wctype_l=discard
+fun:access=discard
+fun:alarm=discard
+fun:atexit=discard
+fun:bind=discard
+fun:chdir=discard
fun:close=discard
-fun:pthread_equal=discard
-fun:pthread_getspecific=discard
-fun:pthread_setspecific=discard
-fun:pthread_mutex_destroy=discard
-fun:pthread_mutexattr_init=discard
-fun:pthread_mutexattr_settype=discard
-fun:pthread_mutex_init=discard
-fun:pthread_mutex_lock=discard
-fun:pthread_mutex_trylock=discard
-fun:pthread_mutex_unlock=discard
-fun:pthread_mutexattr_destroy=discard
-fun:pthread_once=discard
-fun:pthread_key_delete=discard
-fun:pthread_self=discard
-fun:printf=discard
+fun:closedir=discard
+fun:connect=discard
+fun:dladdr=discard
+fun:dlclose=discard
+fun:fclose=discard
+fun:feof=discard
+fun:ferror=discard
+fun:fflush=discard
+fun:fileno=discard
+fun:fopen=discard
fun:fprintf=discard
-fun:fputs=discard
fun:fputc=discard
-fun:fopen=discard
+fun:fputc=discard
+fun:fputs=discard
+fun:fputs=discard
fun:fseek=discard
-fun:lseek=discard
fun:ftell=discard
-fun:fclose=discard
-fun:dladdr=discard
+fun:fwrite=discard
+fun:getenv=discard
+fun:getuid=discard
+fun:geteuid=discard
fun:getpagesize=discard
+fun:getpid=discard
+fun:kill=discard
+fun:listen=discard
+fun:lseek=discard
+fun:mkdir=discard
+fun:mmap=discard
+fun:munmap=discard
+fun:open=discard
+fun:pipe=discard
+fun:posix_fadvise=discard
+fun:posix_memalign=discard
+fun:prctl=discard
+fun:printf=discard
+fun:pthread_sigmask=discard
+fun:putc=discard
+fun:putchar=discard
+fun:puts=discard
+fun:rand=discard
+fun:random=discard
+fun:remove=discard
fun:sched_getcpu=discard
-fun:sched_getaffinity=discard
+fun:sched_get_priority_max=discard
fun:sched_setaffinity=discard
-fun:syscall=discard
+fun:sched_yield=discard
+fun:sem_destroy=discard
fun:sem_init=discard
fun:sem_post=discard
fun:sem_wait=discard
-fun:sched_yield=discard
-fun:uselocale=discard
-fun:rand=discard
-fun:random=discard
+fun:send=discard
+fun:sendmsg=discard
+fun:sendto=discard
+fun:setsockopt=discard
+fun:shutdown=discard
fun:sleep=discard
+fun:socket=discard
+fun:strerror=discard
+fun:strspn=discard
+fun:strcspn=discard
+fun:symlink=discard
+fun:syscall=discard
+fun:unlink=discard
+fun:uselocale=discard
-fun:stat=custom
+# Functions that produce output does not depend on the input (need to zero the
+# shadow manually).
+fun:calloc=custom
+fun:clock_gettime=custom
+fun:dlopen=custom
+fun:fgets=custom
fun:fstat=custom
-fun:memcmp=custom
+fun:getcwd=custom
+fun:get_current_dir_name=custom
+fun:gethostname=custom
+fun:getrlimit=custom
+fun:getrusage=custom
+fun:nanosleep=custom
+fun:pread=custom
+fun:read=custom
+fun:socketpair=custom
+fun:stat=custom
+fun:time=custom
+
+# Functions that produce an output that depend on the input (propagate the
+# shadow manually).
+fun:ctime_r=custom
+fun:inet_pton=custom
+fun:localtime_r=custom
fun:memcpy=custom
fun:memset=custom
-fun:strcmp=custom
+fun:strcpy=custom
fun:strdup=custom
-fun:strncmp=custom
fun:strncpy=custom
+fun:strtod=custom
+fun:strtol=custom
+fun:strtoll=custom
+fun:strtoul=custom
+fun:strtoull=custom
+
+# Functions that produce an output that is computed from the input, but is not
+# necessarily data dependent.
+fun:memchr=custom
+fun:memcmp=custom
fun:strcasecmp=custom
-fun:strncasecmp=custom
fun:strchr=custom
+fun:strcmp=custom
fun:strlen=custom
-fun:calloc=custom
-fun:dlopen=custom
-fun:read=custom
-fun:pread=custom
-fun:clock_gettime=custom
-fun:pthread_create=custom
+fun:strncasecmp=custom
+fun:strncmp=custom
+fun:strrchr=custom
+fun:strstr=custom
+
+# Functions which take action based on global state, such as running a callback
+# set by a sepperate function.
+fun:write=custom
+
+# Functions that take a callback (wrap the callback manually).
fun:dl_iterate_phdr=custom
+fun:getpwuid_r=custom
+fun:poll=custom
+fun:sched_getaffinity=custom
+fun:select=custom
+fun:sigemptyset=custom
+fun:sigaction=custom
+fun:gettimeofday=custom
+
+# sprintf-like
+fun:sprintf=custom
+fun:snprintf=custom
+
# TODO: custom
-fun:snprintf=discard
-fun:vsnprintf=discard
fun:asprintf=discard
fun:qsort=discard
-fun:strtoll=discard
-fun:strtoull=discard
-fun:sigemptyset=discard
-fun:sigaction=discard
-fun:gettimeofday=discard
+
+###############################################################################
+# pthread
+###############################################################################
+fun:pthread_equal=discard
+fun:pthread_getspecific=discard
+fun:pthread_key_create=discard
+fun:pthread_key_delete=discard
+fun:pthread_mutex_destroy=discard
+fun:pthread_mutex_init=discard
+fun:pthread_mutex_lock=discard
+fun:pthread_mutex_trylock=discard
+fun:pthread_mutex_unlock=discard
+fun:pthread_mutexattr_destroy=discard
+fun:pthread_mutexattr_init=discard
+fun:pthread_mutexattr_settype=discard
+fun:pthread_once=discard
+fun:pthread_self=discard
+fun:pthread_setspecific=discard
+
+# Functions that take a callback (wrap the callback manually).
+fun:pthread_create=custom
+
+###############################################################################
+# libffi/libgo
+###############################################################################
+# Functions that are written in asm or are called from asm.
+fun:ffi_call_unix64=uninstrumented
+fun:ffi_call_unix64=discard
+fun:ffi_closure_unix64_inner=uninstrumented
+fun:ffi_closure_unix64_inner=discard
+fun:ffi_closure_unix64=uninstrumented
+fun:ffi_closure_unix64=discard
+fun:__go_get_closure=uninstrumented
+fun:__go_get_closure=discard
+fun:__go_makefunc_can_recover=uninstrumented
+fun:__go_makefunc_can_recover=discard
+fun:__go_makefunc_returning=uninstrumented
+fun:__go_makefunc_returning=discard
+fun:reflect.MakeFuncStubGo=uninstrumented
+fun:reflect.MakeFuncStubGo=discard
+fun:reflect.makeFuncStub=uninstrumented
+fun:reflect.makeFuncStub=discard
diff --git a/lib/dfsan/libc_ubuntu1204_abilist.txt b/lib/dfsan/libc_ubuntu1204_abilist.txt
deleted file mode 100644
index 5fc8194c8f16..000000000000
--- a/lib/dfsan/libc_ubuntu1204_abilist.txt
+++ /dev/null
@@ -1,3685 +0,0 @@
-fun:_Exit=uninstrumented
-fun:_IO_adjust_column=uninstrumented
-fun:_IO_adjust_wcolumn=uninstrumented
-fun:_IO_default_doallocate=uninstrumented
-fun:_IO_default_finish=uninstrumented
-fun:_IO_default_pbackfail=uninstrumented
-fun:_IO_default_uflow=uninstrumented
-fun:_IO_default_xsgetn=uninstrumented
-fun:_IO_default_xsputn=uninstrumented
-fun:_IO_do_write=uninstrumented
-fun:_IO_doallocbuf=uninstrumented
-fun:_IO_fclose=uninstrumented
-fun:_IO_fdopen=uninstrumented
-fun:_IO_feof=uninstrumented
-fun:_IO_ferror=uninstrumented
-fun:_IO_fflush=uninstrumented
-fun:_IO_fgetpos=uninstrumented
-fun:_IO_fgetpos64=uninstrumented
-fun:_IO_fgets=uninstrumented
-fun:_IO_file_attach=uninstrumented
-fun:_IO_file_close=uninstrumented
-fun:_IO_file_close_it=uninstrumented
-fun:_IO_file_doallocate=uninstrumented
-fun:_IO_file_finish=uninstrumented
-fun:_IO_file_fopen=uninstrumented
-fun:_IO_file_init=uninstrumented
-fun:_IO_file_open=uninstrumented
-fun:_IO_file_overflow=uninstrumented
-fun:_IO_file_read=uninstrumented
-fun:_IO_file_seek=uninstrumented
-fun:_IO_file_seekoff=uninstrumented
-fun:_IO_file_setbuf=uninstrumented
-fun:_IO_file_stat=uninstrumented
-fun:_IO_file_sync=uninstrumented
-fun:_IO_file_underflow=uninstrumented
-fun:_IO_file_write=uninstrumented
-fun:_IO_file_xsputn=uninstrumented
-fun:_IO_flockfile=uninstrumented
-fun:_IO_flush_all=uninstrumented
-fun:_IO_flush_all_linebuffered=uninstrumented
-fun:_IO_fopen=uninstrumented
-fun:_IO_fprintf=uninstrumented
-fun:_IO_fputs=uninstrumented
-fun:_IO_fread=uninstrumented
-fun:_IO_free_backup_area=uninstrumented
-fun:_IO_free_wbackup_area=uninstrumented
-fun:_IO_fsetpos=uninstrumented
-fun:_IO_fsetpos64=uninstrumented
-fun:_IO_ftell=uninstrumented
-fun:_IO_ftrylockfile=uninstrumented
-fun:_IO_funlockfile=uninstrumented
-fun:_IO_fwrite=uninstrumented
-fun:_IO_getc=uninstrumented
-fun:_IO_getline=uninstrumented
-fun:_IO_getline_info=uninstrumented
-fun:_IO_gets=uninstrumented
-fun:_IO_init=uninstrumented
-fun:_IO_init_marker=uninstrumented
-fun:_IO_init_wmarker=uninstrumented
-fun:_IO_iter_begin=uninstrumented
-fun:_IO_iter_end=uninstrumented
-fun:_IO_iter_file=uninstrumented
-fun:_IO_iter_next=uninstrumented
-fun:_IO_least_wmarker=uninstrumented
-fun:_IO_link_in=uninstrumented
-fun:_IO_list_lock=uninstrumented
-fun:_IO_list_resetlock=uninstrumented
-fun:_IO_list_unlock=uninstrumented
-fun:_IO_marker_delta=uninstrumented
-fun:_IO_marker_difference=uninstrumented
-fun:_IO_padn=uninstrumented
-fun:_IO_peekc_locked=uninstrumented
-fun:_IO_popen=uninstrumented
-fun:_IO_printf=uninstrumented
-fun:_IO_proc_close=uninstrumented
-fun:_IO_proc_open=uninstrumented
-fun:_IO_putc=uninstrumented
-fun:_IO_puts=uninstrumented
-fun:_IO_remove_marker=uninstrumented
-fun:_IO_seekmark=uninstrumented
-fun:_IO_seekoff=uninstrumented
-fun:_IO_seekpos=uninstrumented
-fun:_IO_seekwmark=uninstrumented
-fun:_IO_setb=uninstrumented
-fun:_IO_setbuffer=uninstrumented
-fun:_IO_setvbuf=uninstrumented
-fun:_IO_sgetn=uninstrumented
-fun:_IO_sprintf=uninstrumented
-fun:_IO_sputbackc=uninstrumented
-fun:_IO_sputbackwc=uninstrumented
-fun:_IO_sscanf=uninstrumented
-fun:_IO_str_init_readonly=uninstrumented
-fun:_IO_str_init_static=uninstrumented
-fun:_IO_str_overflow=uninstrumented
-fun:_IO_str_pbackfail=uninstrumented
-fun:_IO_str_seekoff=uninstrumented
-fun:_IO_str_underflow=uninstrumented
-fun:_IO_sungetc=uninstrumented
-fun:_IO_sungetwc=uninstrumented
-fun:_IO_switch_to_get_mode=uninstrumented
-fun:_IO_switch_to_main_wget_area=uninstrumented
-fun:_IO_switch_to_wbackup_area=uninstrumented
-fun:_IO_switch_to_wget_mode=uninstrumented
-fun:_IO_un_link=uninstrumented
-fun:_IO_ungetc=uninstrumented
-fun:_IO_unsave_markers=uninstrumented
-fun:_IO_unsave_wmarkers=uninstrumented
-fun:_IO_vfprintf=uninstrumented
-fun:_IO_vfscanf=uninstrumented
-fun:_IO_vsprintf=uninstrumented
-fun:_IO_wdefault_doallocate=uninstrumented
-fun:_IO_wdefault_finish=uninstrumented
-fun:_IO_wdefault_pbackfail=uninstrumented
-fun:_IO_wdefault_uflow=uninstrumented
-fun:_IO_wdefault_xsgetn=uninstrumented
-fun:_IO_wdefault_xsputn=uninstrumented
-fun:_IO_wdo_write=uninstrumented
-fun:_IO_wdoallocbuf=uninstrumented
-fun:_IO_wfile_overflow=uninstrumented
-fun:_IO_wfile_seekoff=uninstrumented
-fun:_IO_wfile_sync=uninstrumented
-fun:_IO_wfile_underflow=uninstrumented
-fun:_IO_wfile_xsputn=uninstrumented
-fun:_IO_wmarker_delta=uninstrumented
-fun:_IO_wsetb=uninstrumented
-fun:_L_cond_lock_1021=uninstrumented
-fun:_L_cond_lock_874=uninstrumented
-fun:_L_cond_lock_918=uninstrumented
-fun:_L_lock_1006=uninstrumented
-fun:_L_lock_125=uninstrumented
-fun:_L_lock_1281=uninstrumented
-fun:_L_lock_13=uninstrumented
-fun:_L_lock_133=uninstrumented
-fun:_L_lock_1392=uninstrumented
-fun:_L_lock_175=uninstrumented
-fun:_L_lock_19=uninstrumented
-fun:_L_lock_2009=uninstrumented
-fun:_L_lock_21=uninstrumented
-fun:_L_lock_211=uninstrumented
-fun:_L_lock_2143=uninstrumented
-fun:_L_lock_227=uninstrumented
-fun:_L_lock_23=uninstrumented
-fun:_L_lock_2338=uninstrumented
-fun:_L_lock_26=uninstrumented
-fun:_L_lock_29=uninstrumented
-fun:_L_lock_3116=uninstrumented
-fun:_L_lock_32=uninstrumented
-fun:_L_lock_3335=uninstrumented
-fun:_L_lock_34=uninstrumented
-fun:_L_lock_37=uninstrumented
-fun:_L_lock_40=uninstrumented
-fun:_L_lock_4016=uninstrumented
-fun:_L_lock_4410=uninstrumented
-fun:_L_lock_451=uninstrumented
-fun:_L_lock_4590=uninstrumented
-fun:_L_lock_466=uninstrumented
-fun:_L_lock_641=uninstrumented
-fun:_L_lock_858=uninstrumented
-fun:_L_lock_903=uninstrumented
-fun:_L_robust_cond_lock_164=uninstrumented
-fun:_L_robust_lock_160=uninstrumented
-fun:_L_robust_timedlock_361=uninstrumented
-fun:_L_robust_unlock_189=uninstrumented
-fun:_L_timedlock_1043=uninstrumented
-fun:_L_timedlock_108=uninstrumented
-fun:_L_timedlock_292=uninstrumented
-fun:_L_unlock_114=uninstrumented
-fun:_L_unlock_1157=uninstrumented
-fun:_L_unlock_1355=uninstrumented
-fun:_L_unlock_137=uninstrumented
-fun:_L_unlock_157=uninstrumented
-fun:_L_unlock_16=uninstrumented
-fun:_L_unlock_170=uninstrumented
-fun:_L_unlock_174=uninstrumented
-fun:_L_unlock_177=uninstrumented
-fun:_L_unlock_1946=uninstrumented
-fun:_L_unlock_197=uninstrumented
-fun:_L_unlock_2117=uninstrumented
-fun:_L_unlock_2318=uninstrumented
-fun:_L_unlock_2384=uninstrumented
-fun:_L_unlock_27=uninstrumented
-fun:_L_unlock_3119=uninstrumented
-fun:_L_unlock_312=uninstrumented
-fun:_L_unlock_3464=uninstrumented
-fun:_L_unlock_37=uninstrumented
-fun:_L_unlock_3744=uninstrumented
-fun:_L_unlock_4037=uninstrumented
-fun:_L_unlock_43=uninstrumented
-fun:_L_unlock_4353=uninstrumented
-fun:_L_unlock_4432=uninstrumented
-fun:_L_unlock_4525=uninstrumented
-fun:_L_unlock_4619=uninstrumented
-fun:_L_unlock_494=uninstrumented
-fun:_L_unlock_54=uninstrumented
-fun:_L_unlock_544=uninstrumented
-fun:_L_unlock_61=uninstrumented
-fun:_L_unlock_62=uninstrumented
-fun:_L_unlock_64=uninstrumented
-fun:_L_unlock_644=uninstrumented
-fun:_L_unlock_698=uninstrumented
-fun:_L_unlock_708=uninstrumented
-fun:_L_unlock_88=uninstrumented
-fun:_Unwind_Backtrace=uninstrumented
-fun:_Unwind_DeleteException=uninstrumented
-fun:_Unwind_FindEnclosingFunction=uninstrumented
-fun:_Unwind_Find_FDE=uninstrumented
-fun:_Unwind_ForcedUnwind=uninstrumented
-fun:_Unwind_GetCFA=uninstrumented
-fun:_Unwind_GetDataRelBase=uninstrumented
-fun:_Unwind_GetGR=uninstrumented
-fun:_Unwind_GetIP=uninstrumented
-fun:_Unwind_GetIPInfo=uninstrumented
-fun:_Unwind_GetLanguageSpecificData=uninstrumented
-fun:_Unwind_GetRegionStart=uninstrumented
-fun:_Unwind_GetTextRelBase=uninstrumented
-fun:_Unwind_RaiseException=uninstrumented
-fun:_Unwind_Resume=uninstrumented
-fun:_Unwind_Resume_or_Rethrow=uninstrumented
-fun:_Unwind_SetGR=uninstrumented
-fun:_Unwind_SetIP=uninstrumented
-fun:__GI___nptl_create_event=uninstrumented
-fun:__GI___nptl_death_event=uninstrumented
-fun:__GI___pthread_cleanup_upto=uninstrumented
-fun:__GI___pthread_register_cancel=uninstrumented
-fun:__GI___pthread_unregister_cancel=uninstrumented
-fun:__GI___pthread_unwind=uninstrumented
-fun:__GI___pthread_unwind_next=uninstrumented
-fun:__absvdi2=uninstrumented
-fun:__absvsi2=uninstrumented
-fun:__absvti2=uninstrumented
-fun:__accept=uninstrumented
-fun:__accept_nocancel=uninstrumented
-fun:__acos_finite=uninstrumented
-fun:__acosf_finite=uninstrumented
-fun:__acosh_finite=uninstrumented
-fun:__acoshf_finite=uninstrumented
-fun:__acoshl_finite=uninstrumented
-fun:__acosl_finite=uninstrumented
-fun:__addtf3=uninstrumented
-fun:__addvdi3=uninstrumented
-fun:__addvsi3=uninstrumented
-fun:__addvti3=uninstrumented
-fun:__adjtimex=uninstrumented
-fun:__arch_prctl=uninstrumented
-fun:__argz_count=uninstrumented
-fun:__argz_next=uninstrumented
-fun:__argz_stringify=uninstrumented
-fun:__ashlti3=uninstrumented
-fun:__ashrti3=uninstrumented
-fun:__asin_finite=uninstrumented
-fun:__asinf_finite=uninstrumented
-fun:__asinl_finite=uninstrumented
-fun:__asprintf=uninstrumented
-fun:__asprintf_chk=uninstrumented
-fun:__assert=uninstrumented
-fun:__assert_fail=uninstrumented
-fun:__assert_perror_fail=uninstrumented
-fun:__atan2_finite=uninstrumented
-fun:__atan2f_finite=uninstrumented
-fun:__atan2l_finite=uninstrumented
-fun:__atanh_finite=uninstrumented
-fun:__atanhf_finite=uninstrumented
-fun:__atanhl_finite=uninstrumented
-fun:__b64_ntop=uninstrumented
-fun:__b64_pton=uninstrumented
-fun:__backtrace=uninstrumented
-fun:__backtrace_symbols=uninstrumented
-fun:__backtrace_symbols_fd=uninstrumented
-fun:__bid128_abs=uninstrumented
-fun:__bid128_add=uninstrumented
-fun:__bid128_class=uninstrumented
-fun:__bid128_copy=uninstrumented
-fun:__bid128_copySign=uninstrumented
-fun:__bid128_div=uninstrumented
-fun:__bid128_fma=uninstrumented
-fun:__bid128_from_int32=uninstrumented
-fun:__bid128_from_int64=uninstrumented
-fun:__bid128_from_uint32=uninstrumented
-fun:__bid128_from_uint64=uninstrumented
-fun:__bid128_isCanonical=uninstrumented
-fun:__bid128_isFinite=uninstrumented
-fun:__bid128_isInf=uninstrumented
-fun:__bid128_isNaN=uninstrumented
-fun:__bid128_isNormal=uninstrumented
-fun:__bid128_isSignaling=uninstrumented
-fun:__bid128_isSigned=uninstrumented
-fun:__bid128_isSubnormal=uninstrumented
-fun:__bid128_isZero=uninstrumented
-fun:__bid128_mul=uninstrumented
-fun:__bid128_negate=uninstrumented
-fun:__bid128_quiet_equal=uninstrumented
-fun:__bid128_quiet_greater=uninstrumented
-fun:__bid128_quiet_greater_equal=uninstrumented
-fun:__bid128_quiet_greater_unordered=uninstrumented
-fun:__bid128_quiet_less=uninstrumented
-fun:__bid128_quiet_less_equal=uninstrumented
-fun:__bid128_quiet_less_unordered=uninstrumented
-fun:__bid128_quiet_not_equal=uninstrumented
-fun:__bid128_quiet_not_greater=uninstrumented
-fun:__bid128_quiet_not_less=uninstrumented
-fun:__bid128_quiet_ordered=uninstrumented
-fun:__bid128_quiet_unordered=uninstrumented
-fun:__bid128_radix=uninstrumented
-fun:__bid128_sameQuantum=uninstrumented
-fun:__bid128_signaling_greater=uninstrumented
-fun:__bid128_signaling_greater_equal=uninstrumented
-fun:__bid128_signaling_greater_unordered=uninstrumented
-fun:__bid128_signaling_less=uninstrumented
-fun:__bid128_signaling_less_equal=uninstrumented
-fun:__bid128_signaling_less_unordered=uninstrumented
-fun:__bid128_signaling_not_greater=uninstrumented
-fun:__bid128_signaling_not_less=uninstrumented
-fun:__bid128_sub=uninstrumented
-fun:__bid128_to_bid32=uninstrumented
-fun:__bid128_to_bid64=uninstrumented
-fun:__bid128_to_binary128=uninstrumented
-fun:__bid128_to_binary32=uninstrumented
-fun:__bid128_to_binary64=uninstrumented
-fun:__bid128_to_binary80=uninstrumented
-fun:__bid128_to_int32_ceil=uninstrumented
-fun:__bid128_to_int32_floor=uninstrumented
-fun:__bid128_to_int32_int=uninstrumented
-fun:__bid128_to_int32_rnint=uninstrumented
-fun:__bid128_to_int32_rninta=uninstrumented
-fun:__bid128_to_int32_xceil=uninstrumented
-fun:__bid128_to_int32_xfloor=uninstrumented
-fun:__bid128_to_int32_xint=uninstrumented
-fun:__bid128_to_int32_xrnint=uninstrumented
-fun:__bid128_to_int32_xrninta=uninstrumented
-fun:__bid128_to_int64_ceil=uninstrumented
-fun:__bid128_to_int64_floor=uninstrumented
-fun:__bid128_to_int64_int=uninstrumented
-fun:__bid128_to_int64_rnint=uninstrumented
-fun:__bid128_to_int64_rninta=uninstrumented
-fun:__bid128_to_int64_xceil=uninstrumented
-fun:__bid128_to_int64_xfloor=uninstrumented
-fun:__bid128_to_int64_xint=uninstrumented
-fun:__bid128_to_int64_xrnint=uninstrumented
-fun:__bid128_to_int64_xrninta=uninstrumented
-fun:__bid128_to_uint32_ceil=uninstrumented
-fun:__bid128_to_uint32_floor=uninstrumented
-fun:__bid128_to_uint32_int=uninstrumented
-fun:__bid128_to_uint32_rnint=uninstrumented
-fun:__bid128_to_uint32_rninta=uninstrumented
-fun:__bid128_to_uint32_xceil=uninstrumented
-fun:__bid128_to_uint32_xfloor=uninstrumented
-fun:__bid128_to_uint32_xint=uninstrumented
-fun:__bid128_to_uint32_xrnint=uninstrumented
-fun:__bid128_to_uint32_xrninta=uninstrumented
-fun:__bid128_to_uint64_ceil=uninstrumented
-fun:__bid128_to_uint64_floor=uninstrumented
-fun:__bid128_to_uint64_int=uninstrumented
-fun:__bid128_to_uint64_rnint=uninstrumented
-fun:__bid128_to_uint64_rninta=uninstrumented
-fun:__bid128_to_uint64_xceil=uninstrumented
-fun:__bid128_to_uint64_xfloor=uninstrumented
-fun:__bid128_to_uint64_xint=uninstrumented
-fun:__bid128_to_uint64_xrnint=uninstrumented
-fun:__bid128_to_uint64_xrninta=uninstrumented
-fun:__bid128_totalOrder=uninstrumented
-fun:__bid128_totalOrderMag=uninstrumented
-fun:__bid128dd_add=uninstrumented
-fun:__bid128dd_div=uninstrumented
-fun:__bid128dd_mul=uninstrumented
-fun:__bid128dd_sub=uninstrumented
-fun:__bid128ddd_fma=uninstrumented
-fun:__bid128ddq_fma=uninstrumented
-fun:__bid128dq_add=uninstrumented
-fun:__bid128dq_div=uninstrumented
-fun:__bid128dq_mul=uninstrumented
-fun:__bid128dq_sub=uninstrumented
-fun:__bid128dqd_fma=uninstrumented
-fun:__bid128dqq_fma=uninstrumented
-fun:__bid128qd_add=uninstrumented
-fun:__bid128qd_div=uninstrumented
-fun:__bid128qd_mul=uninstrumented
-fun:__bid128qd_sub=uninstrumented
-fun:__bid128qdd_fma=uninstrumented
-fun:__bid128qdq_fma=uninstrumented
-fun:__bid128qqd_fma=uninstrumented
-fun:__bid32_to_bid128=uninstrumented
-fun:__bid32_to_bid64=uninstrumented
-fun:__bid32_to_binary128=uninstrumented
-fun:__bid32_to_binary32=uninstrumented
-fun:__bid32_to_binary64=uninstrumented
-fun:__bid32_to_binary80=uninstrumented
-fun:__bid64_abs=uninstrumented
-fun:__bid64_add=uninstrumented
-fun:__bid64_class=uninstrumented
-fun:__bid64_copy=uninstrumented
-fun:__bid64_copySign=uninstrumented
-fun:__bid64_div=uninstrumented
-fun:__bid64_from_int32=uninstrumented
-fun:__bid64_from_int64=uninstrumented
-fun:__bid64_from_uint32=uninstrumented
-fun:__bid64_from_uint64=uninstrumented
-fun:__bid64_isCanonical=uninstrumented
-fun:__bid64_isFinite=uninstrumented
-fun:__bid64_isInf=uninstrumented
-fun:__bid64_isNaN=uninstrumented
-fun:__bid64_isNormal=uninstrumented
-fun:__bid64_isSignaling=uninstrumented
-fun:__bid64_isSigned=uninstrumented
-fun:__bid64_isSubnormal=uninstrumented
-fun:__bid64_isZero=uninstrumented
-fun:__bid64_mul=uninstrumented
-fun:__bid64_negate=uninstrumented
-fun:__bid64_quiet_equal=uninstrumented
-fun:__bid64_quiet_greater=uninstrumented
-fun:__bid64_quiet_greater_equal=uninstrumented
-fun:__bid64_quiet_greater_unordered=uninstrumented
-fun:__bid64_quiet_less=uninstrumented
-fun:__bid64_quiet_less_equal=uninstrumented
-fun:__bid64_quiet_less_unordered=uninstrumented
-fun:__bid64_quiet_not_equal=uninstrumented
-fun:__bid64_quiet_not_greater=uninstrumented
-fun:__bid64_quiet_not_less=uninstrumented
-fun:__bid64_quiet_ordered=uninstrumented
-fun:__bid64_quiet_unordered=uninstrumented
-fun:__bid64_radix=uninstrumented
-fun:__bid64_sameQuantum=uninstrumented
-fun:__bid64_signaling_greater=uninstrumented
-fun:__bid64_signaling_greater_equal=uninstrumented
-fun:__bid64_signaling_greater_unordered=uninstrumented
-fun:__bid64_signaling_less=uninstrumented
-fun:__bid64_signaling_less_equal=uninstrumented
-fun:__bid64_signaling_less_unordered=uninstrumented
-fun:__bid64_signaling_not_greater=uninstrumented
-fun:__bid64_signaling_not_less=uninstrumented
-fun:__bid64_sub=uninstrumented
-fun:__bid64_to_bid128=uninstrumented
-fun:__bid64_to_bid32=uninstrumented
-fun:__bid64_to_binary128=uninstrumented
-fun:__bid64_to_binary32=uninstrumented
-fun:__bid64_to_binary64=uninstrumented
-fun:__bid64_to_binary80=uninstrumented
-fun:__bid64_to_int32_ceil=uninstrumented
-fun:__bid64_to_int32_floor=uninstrumented
-fun:__bid64_to_int32_int=uninstrumented
-fun:__bid64_to_int32_rnint=uninstrumented
-fun:__bid64_to_int32_rninta=uninstrumented
-fun:__bid64_to_int32_xceil=uninstrumented
-fun:__bid64_to_int32_xfloor=uninstrumented
-fun:__bid64_to_int32_xint=uninstrumented
-fun:__bid64_to_int32_xrnint=uninstrumented
-fun:__bid64_to_int32_xrninta=uninstrumented
-fun:__bid64_to_int64_ceil=uninstrumented
-fun:__bid64_to_int64_floor=uninstrumented
-fun:__bid64_to_int64_int=uninstrumented
-fun:__bid64_to_int64_rnint=uninstrumented
-fun:__bid64_to_int64_rninta=uninstrumented
-fun:__bid64_to_int64_xceil=uninstrumented
-fun:__bid64_to_int64_xfloor=uninstrumented
-fun:__bid64_to_int64_xint=uninstrumented
-fun:__bid64_to_int64_xrnint=uninstrumented
-fun:__bid64_to_int64_xrninta=uninstrumented
-fun:__bid64_to_uint32_ceil=uninstrumented
-fun:__bid64_to_uint32_floor=uninstrumented
-fun:__bid64_to_uint32_int=uninstrumented
-fun:__bid64_to_uint32_rnint=uninstrumented
-fun:__bid64_to_uint32_rninta=uninstrumented
-fun:__bid64_to_uint32_xceil=uninstrumented
-fun:__bid64_to_uint32_xfloor=uninstrumented
-fun:__bid64_to_uint32_xint=uninstrumented
-fun:__bid64_to_uint32_xrnint=uninstrumented
-fun:__bid64_to_uint32_xrninta=uninstrumented
-fun:__bid64_to_uint64_ceil=uninstrumented
-fun:__bid64_to_uint64_floor=uninstrumented
-fun:__bid64_to_uint64_int=uninstrumented
-fun:__bid64_to_uint64_rnint=uninstrumented
-fun:__bid64_to_uint64_rninta=uninstrumented
-fun:__bid64_to_uint64_xceil=uninstrumented
-fun:__bid64_to_uint64_xfloor=uninstrumented
-fun:__bid64_to_uint64_xint=uninstrumented
-fun:__bid64_to_uint64_xrnint=uninstrumented
-fun:__bid64_to_uint64_xrninta=uninstrumented
-fun:__bid64_totalOrder=uninstrumented
-fun:__bid64_totalOrderMag=uninstrumented
-fun:__bid64ddq_fma=uninstrumented
-fun:__bid64dq_add=uninstrumented
-fun:__bid64dq_div=uninstrumented
-fun:__bid64dq_mul=uninstrumented
-fun:__bid64dq_sub=uninstrumented
-fun:__bid64dqd_fma=uninstrumented
-fun:__bid64dqq_fma=uninstrumented
-fun:__bid64qd_add=uninstrumented
-fun:__bid64qd_div=uninstrumented
-fun:__bid64qd_mul=uninstrumented
-fun:__bid64qd_sub=uninstrumented
-fun:__bid64qdd_fma=uninstrumented
-fun:__bid64qdq_fma=uninstrumented
-fun:__bid64qq_add=uninstrumented
-fun:__bid64qq_div=uninstrumented
-fun:__bid64qq_mul=uninstrumented
-fun:__bid64qq_sub=uninstrumented
-fun:__bid64qqd_fma=uninstrumented
-fun:__bid64qqq_fma=uninstrumented
-fun:__bid_adddd3=uninstrumented
-fun:__bid_addsd3=uninstrumented
-fun:__bid_addtd3=uninstrumented
-fun:__bid_divdd3=uninstrumented
-fun:__bid_divsd3=uninstrumented
-fun:__bid_divtd3=uninstrumented
-fun:__bid_eqdd2=uninstrumented
-fun:__bid_eqsd2=uninstrumented
-fun:__bid_eqtd2=uninstrumented
-fun:__bid_extendddtd2=uninstrumented
-fun:__bid_extendddtf=uninstrumented
-fun:__bid_extendddxf=uninstrumented
-fun:__bid_extenddfdd=uninstrumented
-fun:__bid_extenddftd=uninstrumented
-fun:__bid_extendsddd2=uninstrumented
-fun:__bid_extendsddf=uninstrumented
-fun:__bid_extendsdtd2=uninstrumented
-fun:__bid_extendsdtf=uninstrumented
-fun:__bid_extendsdxf=uninstrumented
-fun:__bid_extendsfdd=uninstrumented
-fun:__bid_extendsfsd=uninstrumented
-fun:__bid_extendsftd=uninstrumented
-fun:__bid_extendtftd=uninstrumented
-fun:__bid_extendxftd=uninstrumented
-fun:__bid_fixdddi=uninstrumented
-fun:__bid_fixddsi=uninstrumented
-fun:__bid_fixsddi=uninstrumented
-fun:__bid_fixsdsi=uninstrumented
-fun:__bid_fixtddi=uninstrumented
-fun:__bid_fixtdsi=uninstrumented
-fun:__bid_fixunsdddi=uninstrumented
-fun:__bid_fixunsddsi=uninstrumented
-fun:__bid_fixunssddi=uninstrumented
-fun:__bid_fixunssdsi=uninstrumented
-fun:__bid_fixunstddi=uninstrumented
-fun:__bid_fixunstdsi=uninstrumented
-fun:__bid_floatdidd=uninstrumented
-fun:__bid_floatdisd=uninstrumented
-fun:__bid_floatditd=uninstrumented
-fun:__bid_floatsidd=uninstrumented
-fun:__bid_floatsisd=uninstrumented
-fun:__bid_floatsitd=uninstrumented
-fun:__bid_floatunsdidd=uninstrumented
-fun:__bid_floatunsdisd=uninstrumented
-fun:__bid_floatunsditd=uninstrumented
-fun:__bid_floatunssidd=uninstrumented
-fun:__bid_floatunssisd=uninstrumented
-fun:__bid_floatunssitd=uninstrumented
-fun:__bid_gedd2=uninstrumented
-fun:__bid_gesd2=uninstrumented
-fun:__bid_getd2=uninstrumented
-fun:__bid_gtdd2=uninstrumented
-fun:__bid_gtsd2=uninstrumented
-fun:__bid_gttd2=uninstrumented
-fun:__bid_ledd2=uninstrumented
-fun:__bid_lesd2=uninstrumented
-fun:__bid_letd2=uninstrumented
-fun:__bid_ltdd2=uninstrumented
-fun:__bid_ltsd2=uninstrumented
-fun:__bid_lttd2=uninstrumented
-fun:__bid_muldd3=uninstrumented
-fun:__bid_mulsd3=uninstrumented
-fun:__bid_multd3=uninstrumented
-fun:__bid_nedd2=uninstrumented
-fun:__bid_nesd2=uninstrumented
-fun:__bid_netd2=uninstrumented
-fun:__bid_round128_19_38=uninstrumented
-fun:__bid_round192_39_57=uninstrumented
-fun:__bid_round256_58_76=uninstrumented
-fun:__bid_round64_2_18=uninstrumented
-fun:__bid_subdd3=uninstrumented
-fun:__bid_subsd3=uninstrumented
-fun:__bid_subtd3=uninstrumented
-fun:__bid_truncdddf=uninstrumented
-fun:__bid_truncddsd2=uninstrumented
-fun:__bid_truncddsf=uninstrumented
-fun:__bid_truncdfsd=uninstrumented
-fun:__bid_truncsdsf=uninstrumented
-fun:__bid_trunctddd2=uninstrumented
-fun:__bid_trunctddf=uninstrumented
-fun:__bid_trunctdsd2=uninstrumented
-fun:__bid_trunctdsf=uninstrumented
-fun:__bid_trunctdtf=uninstrumented
-fun:__bid_trunctdxf=uninstrumented
-fun:__bid_trunctfdd=uninstrumented
-fun:__bid_trunctfsd=uninstrumented
-fun:__bid_truncxfdd=uninstrumented
-fun:__bid_truncxfsd=uninstrumented
-fun:__bid_unorddd2=uninstrumented
-fun:__bid_unordsd2=uninstrumented
-fun:__bid_unordtd2=uninstrumented
-fun:__binary128_to_bid128=uninstrumented
-fun:__binary128_to_bid32=uninstrumented
-fun:__binary128_to_bid64=uninstrumented
-fun:__binary32_to_bid128=uninstrumented
-fun:__binary32_to_bid32=uninstrumented
-fun:__binary32_to_bid64=uninstrumented
-fun:__binary64_to_bid128=uninstrumented
-fun:__binary64_to_bid32=uninstrumented
-fun:__binary64_to_bid64=uninstrumented
-fun:__binary80_to_bid128=uninstrumented
-fun:__binary80_to_bid32=uninstrumented
-fun:__binary80_to_bid64=uninstrumented
-fun:__bsd_getpgrp=uninstrumented
-fun:__bswapdi2=uninstrumented
-fun:__bswapsi2=uninstrumented
-fun:__bzero=uninstrumented
-fun:__chk_fail=uninstrumented
-fun:__clear_cache=uninstrumented
-fun:__clog10=uninstrumented
-fun:__clog10f=uninstrumented
-fun:__clog10l=uninstrumented
-fun:__clone=uninstrumented
-fun:__close=uninstrumented
-fun:__close_nocancel=uninstrumented
-fun:__clzdi2=uninstrumented
-fun:__clzti2=uninstrumented
-fun:__cmpti2=uninstrumented
-fun:__cmsg_nxthdr=uninstrumented
-fun:__condvar_cleanup1=uninstrumented
-fun:__condvar_cleanup2=uninstrumented
-fun:__confstr_chk=uninstrumented
-fun:__connect=uninstrumented
-fun:__connect_internal=uninstrumented
-fun:__connect_nocancel=uninstrumented
-fun:__cosh_finite=uninstrumented
-fun:__coshf_finite=uninstrumented
-fun:__coshl_finite=uninstrumented
-fun:__create_ib_request=uninstrumented
-fun:__ctype_b_loc=uninstrumented
-fun:__ctype_get_mb_cur_max=uninstrumented
-fun:__ctype_init=uninstrumented
-fun:__ctype_tolower_loc=uninstrumented
-fun:__ctype_toupper_loc=uninstrumented
-fun:__ctzdi2=uninstrumented
-fun:__ctzti2=uninstrumented
-fun:__cxa_at_quick_exit=uninstrumented
-fun:__cxa_atexit=uninstrumented
-fun:__cxa_finalize=uninstrumented
-fun:__cyg_profile_func_enter=uninstrumented
-fun:__cyg_profile_func_exit=uninstrumented
-fun:__dcgettext=uninstrumented
-fun:__deallocate_stack=uninstrumented
-fun:__default_morecore=uninstrumented
-fun:__deregister_frame=uninstrumented
-fun:__deregister_frame_info=uninstrumented
-fun:__deregister_frame_info_bases=uninstrumented
-fun:__determine_cpumask_size=uninstrumented
-fun:__dfp_clear_except=uninstrumented
-fun:__dfp_get_round=uninstrumented
-fun:__dfp_raise_except=uninstrumented
-fun:__dfp_set_round=uninstrumented
-fun:__dfp_test_except=uninstrumented
-fun:__dgettext=uninstrumented
-fun:__divdc3=uninstrumented
-fun:__divsc3=uninstrumented
-fun:__divtc3=uninstrumented
-fun:__divtf3=uninstrumented
-fun:__divti3=uninstrumented
-fun:__divxc3=uninstrumented
-fun:__dn_comp=uninstrumented
-fun:__dn_count_labels=uninstrumented
-fun:__dn_expand=uninstrumented
-fun:__dn_skipname=uninstrumented
-fun:__do_global_ctors_aux=uninstrumented
-fun:__do_global_dtors_aux=uninstrumented
-fun:__do_niscall3=uninstrumented
-fun:__dprintf_chk=uninstrumented
-fun:__dup2=uninstrumented
-fun:__duplocale=uninstrumented
-fun:__dyn_pthread_atfork=uninstrumented
-fun:__emutls_get_address=uninstrumented
-fun:__emutls_register_common=uninstrumented
-fun:__enable_execute_stack=uninstrumented
-fun:__endmntent=uninstrumented
-fun:__eprintf=uninstrumented
-fun:__eqtf2=uninstrumented
-fun:__errno_location=uninstrumented
-fun:__exp10_finite=uninstrumented
-fun:__exp10f_finite=uninstrumented
-fun:__exp10l_finite=uninstrumented
-fun:__exp2_finite=uninstrumented
-fun:__exp2f_finite=uninstrumented
-fun:__exp2l_finite=uninstrumented
-fun:__exp_finite=uninstrumented
-fun:__expf_finite=uninstrumented
-fun:__expl_finite=uninstrumented
-fun:__extenddftf2=uninstrumented
-fun:__extendsftf2=uninstrumented
-fun:__extendxftf2=uninstrumented
-fun:__fbufsize=uninstrumented
-fun:__fcntl=uninstrumented
-fun:__fcntl_nocancel=uninstrumented
-fun:__fdelt_chk=uninstrumented
-fun:__fdelt_warn=uninstrumented
-fun:__fentry__=uninstrumented
-fun:__ffs=uninstrumented
-fun:__ffsdi2=uninstrumented
-fun:__ffsti2=uninstrumented
-fun:__fgets_chk=uninstrumented
-fun:__fgets_unlocked_chk=uninstrumented
-fun:__fgetws_chk=uninstrumented
-fun:__fgetws_unlocked_chk=uninstrumented
-fun:__find_in_stack_list=uninstrumented
-fun:__find_thread_by_id=uninstrumented
-fun:__finite=uninstrumented
-fun:__finitef=uninstrumented
-fun:__finitel=uninstrumented
-fun:__fixdfti=uninstrumented
-fun:__fixsfti=uninstrumented
-fun:__fixtfdi=uninstrumented
-fun:__fixtfsi=uninstrumented
-fun:__fixtfti=uninstrumented
-fun:__fixunsdfdi=uninstrumented
-fun:__fixunsdfti=uninstrumented
-fun:__fixunssfdi=uninstrumented
-fun:__fixunssfti=uninstrumented
-fun:__fixunstfdi=uninstrumented
-fun:__fixunstfsi=uninstrumented
-fun:__fixunstfti=uninstrumented
-fun:__fixunsxfdi=uninstrumented
-fun:__fixunsxfti=uninstrumented
-fun:__fixxfti=uninstrumented
-fun:__flbf=uninstrumented
-fun:__floatditf=uninstrumented
-fun:__floatsitf=uninstrumented
-fun:__floattidf=uninstrumented
-fun:__floattisf=uninstrumented
-fun:__floattitf=uninstrumented
-fun:__floattixf=uninstrumented
-fun:__floatunditf=uninstrumented
-fun:__floatunsitf=uninstrumented
-fun:__floatuntidf=uninstrumented
-fun:__floatuntisf=uninstrumented
-fun:__floatuntitf=uninstrumented
-fun:__floatuntixf=uninstrumented
-fun:__flockfile=uninstrumented
-fun:__fmod_finite=uninstrumented
-fun:__fmodf_finite=uninstrumented
-fun:__fmodl_finite=uninstrumented
-fun:__follow_path=uninstrumented
-fun:__fork=uninstrumented
-fun:__fortify_fail=uninstrumented
-fun:__fp_nquery=uninstrumented
-fun:__fp_query=uninstrumented
-fun:__fp_resstat=uninstrumented
-fun:__fpclassify=uninstrumented
-fun:__fpclassifyf=uninstrumented
-fun:__fpclassifyl=uninstrumented
-fun:__fpending=uninstrumented
-fun:__fprintf_chk=uninstrumented
-fun:__fpurge=uninstrumented
-fun:__fread_chk=uninstrumented
-fun:__fread_unlocked_chk=uninstrumented
-fun:__freadable=uninstrumented
-fun:__freading=uninstrumented
-fun:__free_fdresult=uninstrumented
-fun:__free_stacks=uninstrumented
-fun:__free_tcb=uninstrumented
-fun:__freelocale=uninstrumented
-fun:__fsetlocking=uninstrumented
-fun:__fstat=uninstrumented
-fun:__fsync_nocancel=uninstrumented
-fun:__ftrylockfile=uninstrumented
-fun:__funlockfile=uninstrumented
-fun:__fwprintf_chk=uninstrumented
-fun:__fwritable=uninstrumented
-fun:__fwriting=uninstrumented
-fun:__fxstat=uninstrumented
-fun:__fxstat64=uninstrumented
-fun:__fxstatat=uninstrumented
-fun:__fxstatat64=uninstrumented
-fun:__gai_sigqueue=uninstrumented
-fun:__gamma_r_finite=uninstrumented
-fun:__gammaf_r_finite=uninstrumented
-fun:__gammal_r_finite=uninstrumented
-fun:__gcc_bcmp=uninstrumented
-fun:__gcc_personality_v0=uninstrumented
-fun:__gconv_get_alias_db=uninstrumented
-fun:__gconv_get_cache=uninstrumented
-fun:__gconv_get_modules_db=uninstrumented
-fun:__generic_findstack=uninstrumented
-fun:__generic_morestack=uninstrumented
-fun:__generic_morestack_set_initial_sp=uninstrumented
-fun:__generic_releasestack=uninstrumented
-fun:__get_cpu_features=uninstrumented
-fun:__getcwd_chk=uninstrumented
-fun:__getdelim=uninstrumented
-fun:__getdomainname_chk=uninstrumented
-fun:__getf2=uninstrumented
-fun:__getgroups_chk=uninstrumented
-fun:__gethostname_chk=uninstrumented
-fun:__getlogin_r_chk=uninstrumented
-fun:__getmntent_r=uninstrumented
-fun:__getpagesize=uninstrumented
-fun:__getpgid=uninstrumented
-fun:__getpid=uninstrumented
-fun:__gets_chk=uninstrumented
-fun:__gettimeofday=uninstrumented
-fun:__getwd_chk=uninstrumented
-fun:__gmtime_r=uninstrumented
-fun:__gttf2=uninstrumented
-fun:__h_errno_location=uninstrumented
-fun:__hostalias=uninstrumented
-fun:__hypot_finite=uninstrumented
-fun:__hypotf_finite=uninstrumented
-fun:__hypotl_finite=uninstrumented
-fun:__init_sched_fifo_prio=uninstrumented
-fun:__internal_endnetgrent=uninstrumented
-fun:__internal_getnetgrent_r=uninstrumented
-fun:__internal_setnetgrent=uninstrumented
-fun:__isalnum_l=uninstrumented
-fun:__isalpha_l=uninstrumented
-fun:__isascii_l=uninstrumented
-fun:__isblank_l=uninstrumented
-fun:__iscntrl_l=uninstrumented
-fun:__isctype=uninstrumented
-fun:__isdigit_l=uninstrumented
-fun:__isgraph_l=uninstrumented
-fun:__isinf=uninstrumented
-fun:__isinff=uninstrumented
-fun:__isinfl=uninstrumented
-fun:__islower_l=uninstrumented
-fun:__isnan=uninstrumented
-fun:__isnanf=uninstrumented
-fun:__isnanl=uninstrumented
-fun:__isoc99_fscanf=uninstrumented
-fun:__isoc99_fwscanf=uninstrumented
-fun:__isoc99_scanf=uninstrumented
-fun:__isoc99_sscanf=uninstrumented
-fun:__isoc99_swscanf=uninstrumented
-fun:__isoc99_vfscanf=uninstrumented
-fun:__isoc99_vfwscanf=uninstrumented
-fun:__isoc99_vscanf=uninstrumented
-fun:__isoc99_vsscanf=uninstrumented
-fun:__isoc99_vswscanf=uninstrumented
-fun:__isoc99_vwscanf=uninstrumented
-fun:__isoc99_wscanf=uninstrumented
-fun:__isprint_l=uninstrumented
-fun:__ispunct_l=uninstrumented
-fun:__isspace_l=uninstrumented
-fun:__isupper_l=uninstrumented
-fun:__iswalnum_l=uninstrumented
-fun:__iswalpha_l=uninstrumented
-fun:__iswblank_l=uninstrumented
-fun:__iswcntrl_l=uninstrumented
-fun:__iswctype=uninstrumented
-fun:__iswctype_l=uninstrumented
-fun:__iswdigit_l=uninstrumented
-fun:__iswgraph_l=uninstrumented
-fun:__iswlower_l=uninstrumented
-fun:__iswprint_l=uninstrumented
-fun:__iswpunct_l=uninstrumented
-fun:__iswspace_l=uninstrumented
-fun:__iswupper_l=uninstrumented
-fun:__iswxdigit_l=uninstrumented
-fun:__isxdigit_l=uninstrumented
-fun:__ivaliduser=uninstrumented
-fun:__j0_finite=uninstrumented
-fun:__j0f_finite=uninstrumented
-fun:__j0l_finite=uninstrumented
-fun:__j1_finite=uninstrumented
-fun:__j1f_finite=uninstrumented
-fun:__j1l_finite=uninstrumented
-fun:__jn_finite=uninstrumented
-fun:__jnf_finite=uninstrumented
-fun:__jnl_finite=uninstrumented
-fun:__letf2=uninstrumented
-fun:__lgamma_r_finite=uninstrumented
-fun:__lgammaf_r_finite=uninstrumented
-fun:__lgammal_r_finite=uninstrumented
-fun:__libc_accept=uninstrumented
-fun:__libc_alloca_cutoff=uninstrumented
-fun:__libc_allocate_rtsig=uninstrumented
-fun:__libc_allocate_rtsig_private=uninstrumented
-fun:__libc_calloc=uninstrumented
-fun:__libc_clntudp_bufcreate=uninstrumented
-fun:__libc_close=uninstrumented
-fun:__libc_connect=uninstrumented
-fun:__libc_csu_fini=uninstrumented
-fun:__libc_csu_init=uninstrumented
-fun:__libc_current_sigrtmax=uninstrumented
-fun:__libc_current_sigrtmax_private=uninstrumented
-fun:__libc_current_sigrtmin=uninstrumented
-fun:__libc_current_sigrtmin_private=uninstrumented
-fun:__libc_dl_error_tsd=uninstrumented
-fun:__libc_dlclose=uninstrumented
-fun:__libc_dlopen_mode=uninstrumented
-fun:__libc_dlsym=uninstrumented
-fun:__libc_fatal=uninstrumented
-fun:__libc_fcntl=uninstrumented
-fun:__libc_fork=uninstrumented
-fun:__libc_free=uninstrumented
-fun:__libc_freeres=uninstrumented
-fun:__libc_fsync=uninstrumented
-fun:__libc_init_first=uninstrumented
-fun:__libc_longjmp=uninstrumented
-fun:__libc_lseek=uninstrumented
-fun:__libc_lseek64=uninstrumented
-fun:__libc_mallinfo=uninstrumented
-fun:__libc_malloc=uninstrumented
-fun:__libc_mallopt=uninstrumented
-fun:__libc_memalign=uninstrumented
-fun:__libc_msync=uninstrumented
-fun:__libc_nanosleep=uninstrumented
-fun:__libc_open=uninstrumented
-fun:__libc_pause=uninstrumented
-fun:__libc_pread=uninstrumented
-fun:__libc_pread64=uninstrumented
-fun:__libc_pthread_init=uninstrumented
-fun:__libc_pvalloc=uninstrumented
-fun:__libc_pwrite=uninstrumented
-fun:__libc_pwrite64=uninstrumented
-fun:__libc_read=uninstrumented
-fun:__libc_realloc=uninstrumented
-fun:__libc_recv=uninstrumented
-fun:__libc_recvfrom=uninstrumented
-fun:__libc_recvmsg=uninstrumented
-fun:__libc_res_nquery=uninstrumented
-fun:__libc_res_nsearch=uninstrumented
-fun:__libc_rpc_getport=uninstrumented
-fun:__libc_sa_len=uninstrumented
-fun:__libc_send=uninstrumented
-fun:__libc_sendmsg=uninstrumented
-fun:__libc_sendto=uninstrumented
-fun:__libc_sigaction=uninstrumented
-fun:__libc_siglongjmp=uninstrumented
-fun:__libc_sigsuspend=uninstrumented
-fun:__libc_sigwait=uninstrumented
-fun:__libc_start_main=uninstrumented
-fun:__libc_system=uninstrumented
-fun:__libc_tcdrain=uninstrumented
-fun:__libc_thread_freeres=uninstrumented
-fun:__libc_valloc=uninstrumented
-fun:__libc_wait=uninstrumented
-fun:__libc_waitpid=uninstrumented
-fun:__libc_write=uninstrumented
-fun:__lll_lock_wait=uninstrumented
-fun:__lll_lock_wait_private=uninstrumented
-fun:__lll_robust_lock_wait=uninstrumented
-fun:__lll_robust_timedlock_wait=uninstrumented
-fun:__lll_timedlock_wait=uninstrumented
-fun:__lll_timedwait_tid=uninstrumented
-fun:__lll_unlock_wake=uninstrumented
-fun:__lll_unlock_wake_private=uninstrumented
-fun:__llseek=uninstrumented
-fun:__loc_aton=uninstrumented
-fun:__loc_ntoa=uninstrumented
-fun:__log10_finite=uninstrumented
-fun:__log10f_finite=uninstrumented
-fun:__log10l_finite=uninstrumented
-fun:__log2_finite=uninstrumented
-fun:__log2f_finite=uninstrumented
-fun:__log2l_finite=uninstrumented
-fun:__log_finite=uninstrumented
-fun:__logf_finite=uninstrumented
-fun:__logl_finite=uninstrumented
-fun:__longjmp_chk=uninstrumented
-fun:__lseek=uninstrumented
-fun:__lseek64=uninstrumented
-fun:__lseek_nocancel=uninstrumented
-fun:__lshrti3=uninstrumented
-fun:__lstat=uninstrumented
-fun:__lttf2=uninstrumented
-fun:__lxstat=uninstrumented
-fun:__lxstat64=uninstrumented
-fun:__make_stacks_executable=uninstrumented
-fun:__mbrlen=uninstrumented
-fun:__mbrtowc=uninstrumented
-fun:__mbsnrtowcs_chk=uninstrumented
-fun:__mbsrtowcs_chk=uninstrumented
-fun:__mbstowcs_chk=uninstrumented
-fun:__memcpy_chk=uninstrumented
-fun:__memmove_chk=uninstrumented
-fun:__mempcpy=uninstrumented
-fun:__mempcpy_chk=uninstrumented
-fun:__mempcpy_small=uninstrumented
-fun:__memset_chk=uninstrumented
-fun:__mknod=uninstrumented
-fun:__modti3=uninstrumented
-fun:__monstartup=uninstrumented
-fun:__morestack=uninstrumented
-fun:__morestack_allocate_stack_space=uninstrumented
-fun:__morestack_block_signals=uninstrumented
-fun:__morestack_fail=uninstrumented
-fun:__morestack_large_model=uninstrumented
-fun:__morestack_load_mmap=uninstrumented
-fun:__morestack_non_split=uninstrumented
-fun:__morestack_release_segments=uninstrumented
-fun:__morestack_unblock_signals=uninstrumented
-fun:__mq_open_2=uninstrumented
-fun:__msgrcv=uninstrumented
-fun:__msgrcv_nocancel=uninstrumented
-fun:__msgsnd=uninstrumented
-fun:__msgsnd_nocancel=uninstrumented
-fun:__msync_nocancel=uninstrumented
-fun:__muldc3=uninstrumented
-fun:__mulsc3=uninstrumented
-fun:__multc3=uninstrumented
-fun:__multf3=uninstrumented
-fun:__multi3=uninstrumented
-fun:__mulvdi3=uninstrumented
-fun:__mulvsi3=uninstrumented
-fun:__mulvti3=uninstrumented
-fun:__mulxc3=uninstrumented
-fun:__nanosleep=uninstrumented
-fun:__nanosleep_nocancel=uninstrumented
-fun:__negtf2=uninstrumented
-fun:__negti2=uninstrumented
-fun:__negvdi2=uninstrumented
-fun:__negvsi2=uninstrumented
-fun:__negvti2=uninstrumented
-fun:__netf2=uninstrumented
-fun:__new_sem_destroy=uninstrumented
-fun:__new_sem_getvalue=uninstrumented
-fun:__new_sem_init=uninstrumented
-fun:__newlocale=uninstrumented
-fun:__nis_default_access=uninstrumented
-fun:__nis_default_group=uninstrumented
-fun:__nis_default_owner=uninstrumented
-fun:__nis_default_ttl=uninstrumented
-fun:__nis_finddirectory=uninstrumented
-fun:__nis_hash=uninstrumented
-fun:__nisbind_connect=uninstrumented
-fun:__nisbind_create=uninstrumented
-fun:__nisbind_destroy=uninstrumented
-fun:__nisbind_next=uninstrumented
-fun:__nl_langinfo_l=uninstrumented
-fun:__nptl_create_event=uninstrumented
-fun:__nptl_deallocate_tsd=uninstrumented
-fun:__nptl_death_event=uninstrumented
-fun:__nptl_main=uninstrumented
-fun:__nptl_set_robust=uninstrumented
-fun:__nptl_setxid=uninstrumented
-fun:__ns_get16=uninstrumented
-fun:__ns_get32=uninstrumented
-fun:__ns_name_ntop=uninstrumented
-fun:__ns_name_unpack=uninstrumented
-fun:__nss_configure_lookup=uninstrumented
-fun:__nss_database_lookup=uninstrumented
-fun:__nss_disable_nscd=uninstrumented
-fun:__nss_group_lookup=uninstrumented
-fun:__nss_group_lookup2=uninstrumented
-fun:__nss_hostname_digits_dots=uninstrumented
-fun:__nss_hosts_lookup=uninstrumented
-fun:__nss_hosts_lookup2=uninstrumented
-fun:__nss_lookup=uninstrumented
-fun:__nss_lookup_function=uninstrumented
-fun:__nss_next=uninstrumented
-fun:__nss_next2=uninstrumented
-fun:__nss_passwd_lookup=uninstrumented
-fun:__nss_passwd_lookup2=uninstrumented
-fun:__nss_services_lookup2=uninstrumented
-fun:__obstack_printf_chk=uninstrumented
-fun:__obstack_vprintf_chk=uninstrumented
-fun:__open=uninstrumented
-fun:__open64=uninstrumented
-fun:__open64_2=uninstrumented
-fun:__open_2=uninstrumented
-fun:__open_catalog=uninstrumented
-fun:__open_nocancel=uninstrumented
-fun:__openat64_2=uninstrumented
-fun:__openat_2=uninstrumented
-fun:__overflow=uninstrumented
-fun:__p_cdname=uninstrumented
-fun:__p_cdnname=uninstrumented
-fun:__p_class=uninstrumented
-fun:__p_fqname=uninstrumented
-fun:__p_fqnname=uninstrumented
-fun:__p_option=uninstrumented
-fun:__p_query=uninstrumented
-fun:__p_rcode=uninstrumented
-fun:__p_secstodate=uninstrumented
-fun:__p_time=uninstrumented
-fun:__p_type=uninstrumented
-fun:__paritydi2=uninstrumented
-fun:__parityti2=uninstrumented
-fun:__pause_nocancel=uninstrumented
-fun:__pipe=uninstrumented
-fun:__poll=uninstrumented
-fun:__popcountdi2=uninstrumented
-fun:__popcountti2=uninstrumented
-fun:__posix_getopt=uninstrumented
-fun:__pow_finite=uninstrumented
-fun:__powf_finite=uninstrumented
-fun:__powidf2=uninstrumented
-fun:__powisf2=uninstrumented
-fun:__powitf2=uninstrumented
-fun:__powixf2=uninstrumented
-fun:__powl_finite=uninstrumented
-fun:__pread=uninstrumented
-fun:__pread64=uninstrumented
-fun:__pread64_chk=uninstrumented
-fun:__pread_chk=uninstrumented
-fun:__pread_nocancel=uninstrumented
-fun:__prepare_niscall=uninstrumented
-fun:__printf_chk=uninstrumented
-fun:__printf_fp=uninstrumented
-fun:__profile_frequency=uninstrumented
-fun:__pthread_atfork=uninstrumented
-fun:__pthread_attr_destroy=uninstrumented
-fun:__pthread_attr_getaffinity_new=uninstrumented
-fun:__pthread_attr_getaffinity_old=uninstrumented
-fun:__pthread_attr_getdetachstate=uninstrumented
-fun:__pthread_attr_getinheritsched=uninstrumented
-fun:__pthread_attr_getschedparam=uninstrumented
-fun:__pthread_attr_getschedpolicy=uninstrumented
-fun:__pthread_attr_getscope=uninstrumented
-fun:__pthread_attr_getstack=uninstrumented
-fun:__pthread_attr_getstackaddr=uninstrumented
-fun:__pthread_attr_getstacksize=uninstrumented
-fun:__pthread_attr_init_2_1=uninstrumented
-fun:__pthread_attr_setaffinity_new=uninstrumented
-fun:__pthread_attr_setaffinity_old=uninstrumented
-fun:__pthread_attr_setdetachstate=uninstrumented
-fun:__pthread_attr_setinheritsched=uninstrumented
-fun:__pthread_attr_setschedparam=uninstrumented
-fun:__pthread_attr_setschedpolicy=uninstrumented
-fun:__pthread_attr_setscope=uninstrumented
-fun:__pthread_attr_setstack=uninstrumented
-fun:__pthread_attr_setstackaddr=uninstrumented
-fun:__pthread_attr_setstacksize=uninstrumented
-fun:__pthread_cleanup_pop=uninstrumented
-fun:__pthread_cleanup_pop_restore=uninstrumented
-fun:__pthread_cleanup_push=uninstrumented
-fun:__pthread_cleanup_push_defer=uninstrumented
-fun:__pthread_cleanup_routine=uninstrumented
-fun:__pthread_cleanup_upto=uninstrumented
-fun:__pthread_clock_gettime=uninstrumented
-fun:__pthread_clock_settime=uninstrumented
-fun:__pthread_cond_broadcast=uninstrumented
-fun:__pthread_cond_broadcast_2_0=uninstrumented
-fun:__pthread_cond_destroy=uninstrumented
-fun:__pthread_cond_destroy_2_0=uninstrumented
-fun:__pthread_cond_init=uninstrumented
-fun:__pthread_cond_init_2_0=uninstrumented
-fun:__pthread_cond_signal=uninstrumented
-fun:__pthread_cond_signal_2_0=uninstrumented
-fun:__pthread_cond_timedwait=uninstrumented
-fun:__pthread_cond_timedwait_2_0=uninstrumented
-fun:__pthread_cond_wait=uninstrumented
-fun:__pthread_cond_wait_2_0=uninstrumented
-fun:__pthread_condattr_destroy=uninstrumented
-fun:__pthread_condattr_init=uninstrumented
-fun:__pthread_create_2_1=uninstrumented
-fun:__pthread_current_priority=uninstrumented
-fun:__pthread_disable_asynccancel=uninstrumented
-fun:__pthread_enable_asynccancel=uninstrumented
-fun:__pthread_equal=uninstrumented
-fun:__pthread_exit=uninstrumented
-fun:__pthread_get_minstack=uninstrumented
-fun:__pthread_getaffinity_new=uninstrumented
-fun:__pthread_getaffinity_np=uninstrumented
-fun:__pthread_getaffinity_old=uninstrumented
-fun:__pthread_getschedparam=uninstrumented
-fun:__pthread_getspecific=uninstrumented
-fun:__pthread_getspecific_internal=uninstrumented
-fun:__pthread_init_static_tls=uninstrumented
-fun:__pthread_initialize_minimal=uninstrumented
-fun:__pthread_initialize_minimal_internal=uninstrumented
-fun:__pthread_key_create=uninstrumented
-fun:__pthread_key_create_internal=uninstrumented
-fun:__pthread_kill=uninstrumented
-fun:__pthread_kill_other_threads_np=uninstrumented
-fun:__pthread_mutex_cond_lock=uninstrumented
-fun:__pthread_mutex_cond_lock_adjust=uninstrumented
-fun:__pthread_mutex_cond_lock_full=uninstrumented
-fun:__pthread_mutex_destroy=uninstrumented
-fun:__pthread_mutex_destroy_internal=uninstrumented
-fun:__pthread_mutex_init=uninstrumented
-fun:__pthread_mutex_init_internal=uninstrumented
-fun:__pthread_mutex_lock=uninstrumented
-fun:__pthread_mutex_lock_full=uninstrumented
-fun:__pthread_mutex_lock_internal=uninstrumented
-fun:__pthread_mutex_trylock=uninstrumented
-fun:__pthread_mutex_unlock=uninstrumented
-fun:__pthread_mutex_unlock_full=uninstrumented
-fun:__pthread_mutex_unlock_internal=uninstrumented
-fun:__pthread_mutex_unlock_usercnt=uninstrumented
-fun:__pthread_mutexattr_destroy=uninstrumented
-fun:__pthread_mutexattr_init=uninstrumented
-fun:__pthread_mutexattr_settype=uninstrumented
-fun:__pthread_once=uninstrumented
-fun:__pthread_once_internal=uninstrumented
-fun:__pthread_register_cancel=uninstrumented
-fun:__pthread_register_cancel_defer=uninstrumented
-fun:__pthread_rwlock_destroy=uninstrumented
-fun:__pthread_rwlock_init=uninstrumented
-fun:__pthread_rwlock_rdlock=uninstrumented
-fun:__pthread_rwlock_rdlock_internal=uninstrumented
-fun:__pthread_rwlock_tryrdlock=uninstrumented
-fun:__pthread_rwlock_trywrlock=uninstrumented
-fun:__pthread_rwlock_unlock=uninstrumented
-fun:__pthread_rwlock_unlock_internal=uninstrumented
-fun:__pthread_rwlock_wrlock=uninstrumented
-fun:__pthread_rwlock_wrlock_internal=uninstrumented
-fun:__pthread_self=uninstrumented
-fun:__pthread_setaffinity_new=uninstrumented
-fun:__pthread_setaffinity_old=uninstrumented
-fun:__pthread_setcancelstate=uninstrumented
-fun:__pthread_setcanceltype=uninstrumented
-fun:__pthread_setschedparam=uninstrumented
-fun:__pthread_setspecific=uninstrumented
-fun:__pthread_setspecific_internal=uninstrumented
-fun:__pthread_tpp_change_priority=uninstrumented
-fun:__pthread_unregister_cancel=uninstrumented
-fun:__pthread_unregister_cancel_restore=uninstrumented
-fun:__pthread_unwind=uninstrumented
-fun:__pthread_unwind_next=uninstrumented
-fun:__ptsname_r_chk=uninstrumented
-fun:__putlong=uninstrumented
-fun:__putshort=uninstrumented
-fun:__pwrite=uninstrumented
-fun:__pwrite64=uninstrumented
-fun:__pwrite_nocancel=uninstrumented
-fun:__rawmemchr=uninstrumented
-fun:__read=uninstrumented
-fun:__read_chk=uninstrumented
-fun:__read_nocancel=uninstrumented
-fun:__readlink_chk=uninstrumented
-fun:__readlinkat_chk=uninstrumented
-fun:__realpath_chk=uninstrumented
-fun:__reclaim_stacks=uninstrumented
-fun:__recv=uninstrumented
-fun:__recv_chk=uninstrumented
-fun:__recvfrom=uninstrumented
-fun:__recvfrom_chk=uninstrumented
-fun:__recvfrom_nocancel=uninstrumented
-fun:__recvmsg=uninstrumented
-fun:__recvmsg_nocancel=uninstrumented
-fun:__register_atfork=uninstrumented
-fun:__register_frame=uninstrumented
-fun:__register_frame_info=uninstrumented
-fun:__register_frame_info_bases=uninstrumented
-fun:__register_frame_info_table=uninstrumented
-fun:__register_frame_info_table_bases=uninstrumented
-fun:__register_frame_table=uninstrumented
-fun:__remainder_finite=uninstrumented
-fun:__remainderf_finite=uninstrumented
-fun:__remainderl_finite=uninstrumented
-fun:__res_close=uninstrumented
-fun:__res_dnok=uninstrumented
-fun:__res_hnok=uninstrumented
-fun:__res_hostalias=uninstrumented
-fun:__res_iclose=uninstrumented
-fun:__res_init=uninstrumented
-fun:__res_isourserver=uninstrumented
-fun:__res_mailok=uninstrumented
-fun:__res_maybe_init=uninstrumented
-fun:__res_mkquery=uninstrumented
-fun:__res_nameinquery=uninstrumented
-fun:__res_nclose=uninstrumented
-fun:__res_ninit=uninstrumented
-fun:__res_nmkquery=uninstrumented
-fun:__res_nquery=uninstrumented
-fun:__res_nquerydomain=uninstrumented
-fun:__res_nsearch=uninstrumented
-fun:__res_nsend=uninstrumented
-fun:__res_ownok=uninstrumented
-fun:__res_queriesmatch=uninstrumented
-fun:__res_query=uninstrumented
-fun:__res_querydomain=uninstrumented
-fun:__res_randomid=uninstrumented
-fun:__res_search=uninstrumented
-fun:__res_send=uninstrumented
-fun:__res_state=uninstrumented
-fun:__restore_rt=uninstrumented
-fun:__rpc_thread_createerr=uninstrumented
-fun:__rpc_thread_svc_fdset=uninstrumented
-fun:__rpc_thread_svc_max_pollfd=uninstrumented
-fun:__rpc_thread_svc_pollfd=uninstrumented
-fun:__sbrk=uninstrumented
-fun:__scalb_finite=uninstrumented
-fun:__scalbf_finite=uninstrumented
-fun:__scalbl_finite=uninstrumented
-fun:__sched_cpualloc=uninstrumented
-fun:__sched_cpucount=uninstrumented
-fun:__sched_cpufree=uninstrumented
-fun:__sched_get_priority_max=uninstrumented
-fun:__sched_get_priority_min=uninstrumented
-fun:__sched_getparam=uninstrumented
-fun:__sched_getscheduler=uninstrumented
-fun:__sched_setscheduler=uninstrumented
-fun:__sched_yield=uninstrumented
-fun:__secure_getenv=uninstrumented
-fun:__select=uninstrumented
-fun:__sem_search=uninstrumented
-fun:__send=uninstrumented
-fun:__sendmsg=uninstrumented
-fun:__sendmsg_nocancel=uninstrumented
-fun:__sendto=uninstrumented
-fun:__sendto_nocancel=uninstrumented
-fun:__setmntent=uninstrumented
-fun:__setpgid=uninstrumented
-fun:__sigaction=uninstrumented
-fun:__sigaddset=uninstrumented
-fun:__sigdelset=uninstrumented
-fun:__sigismember=uninstrumented
-fun:__signbit=uninstrumented
-fun:__signbitf=uninstrumented
-fun:__signbitl=uninstrumented
-fun:__sigpause=uninstrumented
-fun:__sigsetjmp=uninstrumented
-fun:__sigsuspend=uninstrumented
-fun:__sigsuspend_nocancel=uninstrumented
-fun:__sigwait=uninstrumented
-fun:__sinh_finite=uninstrumented
-fun:__sinhf_finite=uninstrumented
-fun:__sinhl_finite=uninstrumented
-fun:__snprintf_chk=uninstrumented
-fun:__splitstack_find=uninstrumented
-fun:__sprintf_chk=uninstrumented
-fun:__sqrt_finite=uninstrumented
-fun:__sqrtf_finite=uninstrumented
-fun:__sqrtl_finite=uninstrumented
-fun:__stack_chk_fail=uninstrumented
-fun:__stack_chk_fail_local=uninstrumented
-fun:__stack_split_initialize=uninstrumented
-fun:__stat=uninstrumented
-fun:__statfs=uninstrumented
-fun:__stpcpy=uninstrumented
-fun:__stpcpy_chk=uninstrumented
-fun:__stpcpy_small=uninstrumented
-fun:__stpncpy=uninstrumented
-fun:__stpncpy_chk=uninstrumented
-fun:__strcasecmp=uninstrumented
-fun:__strcasecmp_l=uninstrumented
-fun:__strcasestr=uninstrumented
-fun:__strcat_chk=uninstrumented
-fun:__strcoll_l=uninstrumented
-fun:__strcpy_chk=uninstrumented
-fun:__strcpy_small=uninstrumented
-fun:__strcspn_c1=uninstrumented
-fun:__strcspn_c2=uninstrumented
-fun:__strcspn_c3=uninstrumented
-fun:__strdup=uninstrumented
-fun:__strerror_r=uninstrumented
-fun:__strfmon_l=uninstrumented
-fun:__strftime_l=uninstrumented
-fun:__strncasecmp_l=uninstrumented
-fun:__strncat_chk=uninstrumented
-fun:__strncpy_chk=uninstrumented
-fun:__strndup=uninstrumented
-fun:__strpbrk_c2=uninstrumented
-fun:__strpbrk_c3=uninstrumented
-fun:__strsep_1c=uninstrumented
-fun:__strsep_2c=uninstrumented
-fun:__strsep_3c=uninstrumented
-fun:__strsep_g=uninstrumented
-fun:__strspn_c1=uninstrumented
-fun:__strspn_c2=uninstrumented
-fun:__strspn_c3=uninstrumented
-fun:__strtod_internal=uninstrumented
-fun:__strtod_l=uninstrumented
-fun:__strtof_internal=uninstrumented
-fun:__strtof_l=uninstrumented
-fun:__strtok_r=uninstrumented
-fun:__strtok_r_1c=uninstrumented
-fun:__strtol_internal=uninstrumented
-fun:__strtol_l=uninstrumented
-fun:__strtold_internal=uninstrumented
-fun:__strtold_l=uninstrumented
-fun:__strtoll_internal=uninstrumented
-fun:__strtoll_l=uninstrumented
-fun:__strtoul_internal=uninstrumented
-fun:__strtoul_l=uninstrumented
-fun:__strtoull_internal=uninstrumented
-fun:__strtoull_l=uninstrumented
-fun:__strverscmp=uninstrumented
-fun:__strxfrm_l=uninstrumented
-fun:__subtf3=uninstrumented
-fun:__subvdi3=uninstrumented
-fun:__subvsi3=uninstrumented
-fun:__subvti3=uninstrumented
-fun:__swprintf_chk=uninstrumented
-fun:__sym_ntop=uninstrumented
-fun:__sym_ntos=uninstrumented
-fun:__sym_ston=uninstrumented
-fun:__sysconf=uninstrumented
-fun:__sysctl=uninstrumented
-fun:__syslog_chk=uninstrumented
-fun:__sysv_signal=uninstrumented
-fun:__tls_get_addr=uninstrumented
-fun:__toascii_l=uninstrumented
-fun:__tolower_l=uninstrumented
-fun:__toupper_l=uninstrumented
-fun:__towctrans=uninstrumented
-fun:__towctrans_l=uninstrumented
-fun:__towlower_l=uninstrumented
-fun:__towupper_l=uninstrumented
-fun:__trunctfdf2=uninstrumented
-fun:__trunctfsf2=uninstrumented
-fun:__trunctfxf2=uninstrumented
-fun:__ttyname_r_chk=uninstrumented
-fun:__ucmpti2=uninstrumented
-fun:__udiv_w_sdiv=uninstrumented
-fun:__udivmodti4=uninstrumented
-fun:__udivti3=uninstrumented
-fun:__uflow=uninstrumented
-fun:__umodti3=uninstrumented
-fun:__underflow=uninstrumented
-fun:__unordtf2=uninstrumented
-fun:__unwind_freeres=uninstrumented
-fun:__uselocale=uninstrumented
-fun:__vasprintf_chk=uninstrumented
-fun:__vdprintf_chk=uninstrumented
-fun:__vfork=uninstrumented
-fun:__vfprintf_chk=uninstrumented
-fun:__vfscanf=uninstrumented
-fun:__vfwprintf_chk=uninstrumented
-fun:__vprintf_chk=uninstrumented
-fun:__vsnprintf=uninstrumented
-fun:__vsnprintf_chk=uninstrumented
-fun:__vsprintf_chk=uninstrumented
-fun:__vsscanf=uninstrumented
-fun:__vswprintf_chk=uninstrumented
-fun:__vsyslog_chk=uninstrumented
-fun:__vwprintf_chk=uninstrumented
-fun:__wait=uninstrumented
-fun:__wait_lookup_done=uninstrumented
-fun:__waitpid=uninstrumented
-fun:__warn_memset_zero_len=uninstrumented
-fun:__wcpcpy_chk=uninstrumented
-fun:__wcpncpy_chk=uninstrumented
-fun:__wcrtomb_chk=uninstrumented
-fun:__wcscasecmp_l=uninstrumented
-fun:__wcscat_chk=uninstrumented
-fun:__wcscoll_l=uninstrumented
-fun:__wcscpy_chk=uninstrumented
-fun:__wcsftime_l=uninstrumented
-fun:__wcsncasecmp_l=uninstrumented
-fun:__wcsncat_chk=uninstrumented
-fun:__wcsncpy_chk=uninstrumented
-fun:__wcsnrtombs_chk=uninstrumented
-fun:__wcsrtombs_chk=uninstrumented
-fun:__wcstod_internal=uninstrumented
-fun:__wcstod_l=uninstrumented
-fun:__wcstof_internal=uninstrumented
-fun:__wcstof_l=uninstrumented
-fun:__wcstol_internal=uninstrumented
-fun:__wcstol_l=uninstrumented
-fun:__wcstold_internal=uninstrumented
-fun:__wcstold_l=uninstrumented
-fun:__wcstoll_internal=uninstrumented
-fun:__wcstoll_l=uninstrumented
-fun:__wcstombs_chk=uninstrumented
-fun:__wcstoul_internal=uninstrumented
-fun:__wcstoul_l=uninstrumented
-fun:__wcstoull_internal=uninstrumented
-fun:__wcstoull_l=uninstrumented
-fun:__wcsxfrm_l=uninstrumented
-fun:__wctomb_chk=uninstrumented
-fun:__wctrans_l=uninstrumented
-fun:__wctype_l=uninstrumented
-fun:__where_is_shmfs=uninstrumented
-fun:__wmemcpy_chk=uninstrumented
-fun:__wmemmove_chk=uninstrumented
-fun:__wmempcpy_chk=uninstrumented
-fun:__wmemset_chk=uninstrumented
-fun:__woverflow=uninstrumented
-fun:__wprintf_chk=uninstrumented
-fun:__wrap_pthread_create=uninstrumented
-fun:__write=uninstrumented
-fun:__write_nocancel=uninstrumented
-fun:__wuflow=uninstrumented
-fun:__wunderflow=uninstrumented
-fun:__xmknod=uninstrumented
-fun:__xmknodat=uninstrumented
-fun:__xpg_basename=uninstrumented
-fun:__xpg_sigpause=uninstrumented
-fun:__xpg_strerror_r=uninstrumented
-fun:__xstat=uninstrumented
-fun:__xstat64=uninstrumented
-fun:__y0_finite=uninstrumented
-fun:__y0f_finite=uninstrumented
-fun:__y0l_finite=uninstrumented
-fun:__y1_finite=uninstrumented
-fun:__y1f_finite=uninstrumented
-fun:__y1l_finite=uninstrumented
-fun:__yn_finite=uninstrumented
-fun:__ynf_finite=uninstrumented
-fun:__ynl_finite=uninstrumented
-fun:__yp_check=uninstrumented
-fun:_authenticate=uninstrumented
-fun:_dl_addr=uninstrumented
-fun:_dl_allocate_tls=uninstrumented
-fun:_dl_allocate_tls_init=uninstrumented
-fun:_dl_deallocate_tls=uninstrumented
-fun:_dl_debug_state=uninstrumented
-fun:_dl_get_tls_static_info=uninstrumented
-fun:_dl_make_stack_executable=uninstrumented
-fun:_dl_mcount=uninstrumented
-fun:_dl_mcount_wrapper=uninstrumented
-fun:_dl_mcount_wrapper_check=uninstrumented
-fun:_dl_rtld_di_serinfo=uninstrumented
-fun:_dl_sym=uninstrumented
-fun:_dl_tls_setup=uninstrumented
-fun:_dl_vsym=uninstrumented
-fun:_exit=uninstrumented
-fun:_fini=uninstrumented
-fun:_flushlbf=uninstrumented
-fun:_gethtbyaddr=uninstrumented
-fun:_gethtbyname=uninstrumented
-fun:_gethtbyname2=uninstrumented
-fun:_gethtent=uninstrumented
-fun:_getlong=uninstrumented
-fun:_getshort=uninstrumented
-fun:_init=uninstrumented
-fun:_longjmp=uninstrumented
-fun:_mcleanup=uninstrumented
-fun:_mcount=uninstrumented
-fun:_nsl_default_nss=uninstrumented
-fun:_nss_files_parse_grent=uninstrumented
-fun:_nss_files_parse_pwent=uninstrumented
-fun:_nss_files_parse_sgent=uninstrumented
-fun:_nss_files_parse_spent=uninstrumented
-fun:_obstack_allocated_p=uninstrumented
-fun:_obstack_begin=uninstrumented
-fun:_obstack_begin_1=uninstrumented
-fun:_obstack_free=uninstrumented
-fun:_obstack_memory_used=uninstrumented
-fun:_obstack_newchunk=uninstrumented
-fun:_pthread_cleanup_pop=uninstrumented
-fun:_pthread_cleanup_pop_restore=uninstrumented
-fun:_pthread_cleanup_push=uninstrumented
-fun:_pthread_cleanup_push_defer=uninstrumented
-fun:_rpc_dtablesize=uninstrumented
-fun:_seterr_reply=uninstrumented
-fun:_sethtent=uninstrumented
-fun:_setjmp=uninstrumented
-fun:_tolower=uninstrumented
-fun:_toupper=uninstrumented
-fun:_xdr_ib_request=uninstrumented
-fun:_xdr_nis_result=uninstrumented
-fun:a64l=uninstrumented
-fun:abort=uninstrumented
-fun:abs=uninstrumented
-fun:accept=uninstrumented
-fun:accept4=uninstrumented
-fun:access=uninstrumented
-fun:acct=uninstrumented
-fun:acos=uninstrumented
-fun:acosf=uninstrumented
-fun:acosh=uninstrumented
-fun:acoshf=uninstrumented
-fun:acoshl=uninstrumented
-fun:acosl=uninstrumented
-fun:add_and_round.constprop.0=uninstrumented
-fun:addmntent=uninstrumented
-fun:addseverity=uninstrumented
-fun:adjtime=uninstrumented
-fun:adjtimex=uninstrumented
-fun:advance=uninstrumented
-fun:aio_cancel=uninstrumented
-fun:aio_cancel64=uninstrumented
-fun:aio_error=uninstrumented
-fun:aio_error64=uninstrumented
-fun:aio_fsync=uninstrumented
-fun:aio_fsync64=uninstrumented
-fun:aio_init=uninstrumented
-fun:aio_read=uninstrumented
-fun:aio_read64=uninstrumented
-fun:aio_return=uninstrumented
-fun:aio_return64=uninstrumented
-fun:aio_suspend=uninstrumented
-fun:aio_suspend64=uninstrumented
-fun:aio_write=uninstrumented
-fun:aio_write64=uninstrumented
-fun:alarm=uninstrumented
-fun:alphasort=uninstrumented
-fun:alphasort64=uninstrumented
-fun:arch_prctl=uninstrumented
-fun:argp_error=uninstrumented
-fun:argp_failure=uninstrumented
-fun:argp_help=uninstrumented
-fun:argp_parse=uninstrumented
-fun:argp_state_help=uninstrumented
-fun:argp_usage=uninstrumented
-fun:argz_add=uninstrumented
-fun:argz_add_sep=uninstrumented
-fun:argz_append=uninstrumented
-fun:argz_count=uninstrumented
-fun:argz_create=uninstrumented
-fun:argz_create_sep=uninstrumented
-fun:argz_delete=uninstrumented
-fun:argz_extract=uninstrumented
-fun:argz_insert=uninstrumented
-fun:argz_next=uninstrumented
-fun:argz_replace=uninstrumented
-fun:argz_stringify=uninstrumented
-fun:asctime=uninstrumented
-fun:asctime_r=uninstrumented
-fun:asin=uninstrumented
-fun:asinf=uninstrumented
-fun:asinh=uninstrumented
-fun:asinhf=uninstrumented
-fun:asinhl=uninstrumented
-fun:asinl=uninstrumented
-fun:asprintf=uninstrumented
-fun:at_quick_exit=uninstrumented
-fun:atan=uninstrumented
-fun:atan2=uninstrumented
-fun:atan2f=uninstrumented
-fun:atan2l=uninstrumented
-fun:atanf=uninstrumented
-fun:atanh=uninstrumented
-fun:atanhf=uninstrumented
-fun:atanhl=uninstrumented
-fun:atanl=uninstrumented
-fun:atexit=uninstrumented
-fun:atof=uninstrumented
-fun:atoi=uninstrumented
-fun:atol=uninstrumented
-fun:atoll=uninstrumented
-fun:authdes_create=uninstrumented
-fun:authdes_getucred=uninstrumented
-fun:authdes_pk_create=uninstrumented
-fun:authnone_create=uninstrumented
-fun:authunix_create=uninstrumented
-fun:authunix_create_default=uninstrumented
-fun:backtrace=uninstrumented
-fun:backtrace_symbols=uninstrumented
-fun:backtrace_symbols_fd=uninstrumented
-fun:basename=uninstrumented
-fun:bcmp=uninstrumented
-fun:bcopy=uninstrumented
-fun:bdflush=uninstrumented
-fun:bid128_ext_fma=uninstrumented
-fun:bind=uninstrumented
-fun:bind_textdomain_codeset=uninstrumented
-fun:bindresvport=uninstrumented
-fun:bindtextdomain=uninstrumented
-fun:brk=uninstrumented
-fun:bsd_signal=uninstrumented
-fun:bsearch=uninstrumented
-fun:btowc=uninstrumented
-fun:bzero=uninstrumented
-fun:cabs=uninstrumented
-fun:cabsf=uninstrumented
-fun:cabsl=uninstrumented
-fun:cacos=uninstrumented
-fun:cacosf=uninstrumented
-fun:cacosh=uninstrumented
-fun:cacoshf=uninstrumented
-fun:cacoshl=uninstrumented
-fun:cacosl=uninstrumented
-fun:calloc=uninstrumented
-fun:callrpc=uninstrumented
-fun:canonicalize_file_name=uninstrumented
-fun:capget=uninstrumented
-fun:capset=uninstrumented
-fun:carg=uninstrumented
-fun:cargf=uninstrumented
-fun:cargl=uninstrumented
-fun:casin=uninstrumented
-fun:casinf=uninstrumented
-fun:casinh=uninstrumented
-fun:casinhf=uninstrumented
-fun:casinhl=uninstrumented
-fun:casinl=uninstrumented
-fun:catan=uninstrumented
-fun:catanf=uninstrumented
-fun:catanh=uninstrumented
-fun:catanhf=uninstrumented
-fun:catanhl=uninstrumented
-fun:catanl=uninstrumented
-fun:catclose=uninstrumented
-fun:catgets=uninstrumented
-fun:catopen=uninstrumented
-fun:cbc_crypt=uninstrumented
-fun:cbrt=uninstrumented
-fun:cbrtf=uninstrumented
-fun:cbrtl=uninstrumented
-fun:ccos=uninstrumented
-fun:ccosf=uninstrumented
-fun:ccosh=uninstrumented
-fun:ccoshf=uninstrumented
-fun:ccoshl=uninstrumented
-fun:ccosl=uninstrumented
-fun:ceil=uninstrumented
-fun:ceilf=uninstrumented
-fun:ceill=uninstrumented
-fun:cexp=uninstrumented
-fun:cexpf=uninstrumented
-fun:cexpl=uninstrumented
-fun:cfgetispeed=uninstrumented
-fun:cfgetospeed=uninstrumented
-fun:cfmakeraw=uninstrumented
-fun:cfree=uninstrumented
-fun:cfsetispeed=uninstrumented
-fun:cfsetospeed=uninstrumented
-fun:cfsetspeed=uninstrumented
-fun:chdir=uninstrumented
-fun:check_add_mapping=uninstrumented
-fun:chflags=uninstrumented
-fun:chmod=uninstrumented
-fun:chown=uninstrumented
-fun:chroot=uninstrumented
-fun:cimag=uninstrumented
-fun:cimagf=uninstrumented
-fun:cimagl=uninstrumented
-fun:cleanup=uninstrumented
-fun:clear_once_control=uninstrumented
-fun:clearenv=uninstrumented
-fun:clearerr=uninstrumented
-fun:clearerr_unlocked=uninstrumented
-fun:clnt_broadcast=uninstrumented
-fun:clnt_create=uninstrumented
-fun:clnt_pcreateerror=uninstrumented
-fun:clnt_perrno=uninstrumented
-fun:clnt_perror=uninstrumented
-fun:clnt_spcreateerror=uninstrumented
-fun:clnt_sperrno=uninstrumented
-fun:clnt_sperror=uninstrumented
-fun:clntraw_create=uninstrumented
-fun:clnttcp_create=uninstrumented
-fun:clntudp_bufcreate=uninstrumented
-fun:clntudp_create=uninstrumented
-fun:clntunix_create=uninstrumented
-fun:clock=uninstrumented
-fun:clock_adjtime=uninstrumented
-fun:clock_getcpuclockid=uninstrumented
-fun:clock_getres=uninstrumented
-fun:clock_gettime=uninstrumented
-fun:clock_nanosleep=uninstrumented
-fun:clock_settime=uninstrumented
-fun:clog=uninstrumented
-fun:clog10=uninstrumented
-fun:clog10f=uninstrumented
-fun:clog10l=uninstrumented
-fun:clogf=uninstrumented
-fun:clogl=uninstrumented
-fun:clone=uninstrumented
-fun:close=uninstrumented
-fun:closedir=uninstrumented
-fun:closelog=uninstrumented
-fun:confstr=uninstrumented
-fun:conj=uninstrumented
-fun:conjf=uninstrumented
-fun:conjl=uninstrumented
-fun:connect=uninstrumented
-fun:copysign=uninstrumented
-fun:copysignf=uninstrumented
-fun:copysignl=uninstrumented
-fun:cos=uninstrumented
-fun:cosf=uninstrumented
-fun:cosh=uninstrumented
-fun:coshf=uninstrumented
-fun:coshl=uninstrumented
-fun:cosl=uninstrumented
-fun:cpow=uninstrumented
-fun:cpowf=uninstrumented
-fun:cpowl=uninstrumented
-fun:cproj=uninstrumented
-fun:cprojf=uninstrumented
-fun:cprojl=uninstrumented
-fun:creal=uninstrumented
-fun:crealf=uninstrumented
-fun:creall=uninstrumented
-fun:creat=uninstrumented
-fun:creat64=uninstrumented
-fun:create_key=uninstrumented
-fun:create_module=uninstrumented
-fun:crypt=uninstrumented
-fun:crypt_r=uninstrumented
-fun:csin=uninstrumented
-fun:csinf=uninstrumented
-fun:csinh=uninstrumented
-fun:csinhf=uninstrumented
-fun:csinhl=uninstrumented
-fun:csinl=uninstrumented
-fun:csqrt=uninstrumented
-fun:csqrtf=uninstrumented
-fun:csqrtl=uninstrumented
-fun:ctan=uninstrumented
-fun:ctanf=uninstrumented
-fun:ctanh=uninstrumented
-fun:ctanhf=uninstrumented
-fun:ctanhl=uninstrumented
-fun:ctanl=uninstrumented
-fun:ctermid=uninstrumented
-fun:ctime=uninstrumented
-fun:ctime_r=uninstrumented
-fun:cuserid=uninstrumented
-fun:daemon=uninstrumented
-fun:dcgettext=uninstrumented
-fun:dcngettext=uninstrumented
-fun:delete_module=uninstrumented
-fun:des_setparity=uninstrumented
-fun:dgettext=uninstrumented
-fun:difftime=uninstrumented
-fun:dirfd=uninstrumented
-fun:dirname=uninstrumented
-fun:div=uninstrumented
-fun:dl_iterate_phdr=uninstrumented
-fun:dladdr=uninstrumented
-fun:dladdr1=uninstrumented
-fun:dlclose=uninstrumented
-fun:dlerror=uninstrumented
-fun:dlinfo=uninstrumented
-fun:dlmopen=uninstrumented
-fun:dlopen=uninstrumented
-fun:dlsym=uninstrumented
-fun:dlvsym=uninstrumented
-fun:dngettext=uninstrumented
-fun:do_clone.constprop.4=uninstrumented
-fun:do_sigwait=uninstrumented
-fun:dprintf=uninstrumented
-fun:drand48=uninstrumented
-fun:drand48_r=uninstrumented
-fun:drem=uninstrumented
-fun:dremf=uninstrumented
-fun:dreml=uninstrumented
-fun:dup=uninstrumented
-fun:dup2=uninstrumented
-fun:dup3=uninstrumented
-fun:duplocale=uninstrumented
-fun:dysize=uninstrumented
-fun:eaccess=uninstrumented
-fun:ecb_crypt=uninstrumented
-fun:ecvt=uninstrumented
-fun:ecvt_r=uninstrumented
-fun:encrypt=uninstrumented
-fun:encrypt_r=uninstrumented
-fun:endaliasent=uninstrumented
-fun:endfsent=uninstrumented
-fun:endgrent=uninstrumented
-fun:endhostent=uninstrumented
-fun:endmntent=uninstrumented
-fun:endnetent=uninstrumented
-fun:endnetgrent=uninstrumented
-fun:endprotoent=uninstrumented
-fun:endpwent=uninstrumented
-fun:endrpcent=uninstrumented
-fun:endservent=uninstrumented
-fun:endsgent=uninstrumented
-fun:endspent=uninstrumented
-fun:endttyent=uninstrumented
-fun:endusershell=uninstrumented
-fun:endutent=uninstrumented
-fun:endutxent=uninstrumented
-fun:envz_add=uninstrumented
-fun:envz_entry=uninstrumented
-fun:envz_get=uninstrumented
-fun:envz_merge=uninstrumented
-fun:envz_remove=uninstrumented
-fun:envz_strip=uninstrumented
-fun:epoll_create=uninstrumented
-fun:epoll_create1=uninstrumented
-fun:epoll_ctl=uninstrumented
-fun:epoll_pwait=uninstrumented
-fun:epoll_wait=uninstrumented
-fun:erand48=uninstrumented
-fun:erand48_r=uninstrumented
-fun:erf=uninstrumented
-fun:erfc=uninstrumented
-fun:erfcf=uninstrumented
-fun:erfcl=uninstrumented
-fun:erff=uninstrumented
-fun:erfl=uninstrumented
-fun:err=uninstrumented
-fun:error=uninstrumented
-fun:error_at_line=uninstrumented
-fun:errx=uninstrumented
-fun:ether_aton=uninstrumented
-fun:ether_aton_r=uninstrumented
-fun:ether_hostton=uninstrumented
-fun:ether_line=uninstrumented
-fun:ether_ntoa=uninstrumented
-fun:ether_ntoa_r=uninstrumented
-fun:ether_ntohost=uninstrumented
-fun:euidaccess=uninstrumented
-fun:eventfd=uninstrumented
-fun:eventfd_read=uninstrumented
-fun:eventfd_write=uninstrumented
-fun:execl=uninstrumented
-fun:execle=uninstrumented
-fun:execlp=uninstrumented
-fun:execv=uninstrumented
-fun:execve=uninstrumented
-fun:execvp=uninstrumented
-fun:execvpe=uninstrumented
-fun:exit=uninstrumented
-fun:exp=uninstrumented
-fun:exp10=uninstrumented
-fun:exp10f=uninstrumented
-fun:exp10l=uninstrumented
-fun:exp2=uninstrumented
-fun:exp2f=uninstrumented
-fun:exp2l=uninstrumented
-fun:expf=uninstrumented
-fun:expl=uninstrumented
-fun:expm1=uninstrumented
-fun:expm1f=uninstrumented
-fun:expm1l=uninstrumented
-fun:fabs=uninstrumented
-fun:fabsf=uninstrumented
-fun:fabsl=uninstrumented
-fun:faccessat=uninstrumented
-fun:fallocate=uninstrumented
-fun:fallocate64=uninstrumented
-fun:fanotify_init=uninstrumented
-fun:fanotify_mark=uninstrumented
-fun:fattach=uninstrumented
-fun:fchdir=uninstrumented
-fun:fchflags=uninstrumented
-fun:fchmod=uninstrumented
-fun:fchmodat=uninstrumented
-fun:fchown=uninstrumented
-fun:fchownat=uninstrumented
-fun:fclose=uninstrumented
-fun:fcloseall=uninstrumented
-fun:fcntl=uninstrumented
-fun:fcrypt=uninstrumented
-fun:fcvt=uninstrumented
-fun:fcvt_r=uninstrumented
-fun:fdatasync=uninstrumented
-fun:fdetach=uninstrumented
-fun:fdim=uninstrumented
-fun:fdimf=uninstrumented
-fun:fdiml=uninstrumented
-fun:fdopen=uninstrumented
-fun:fdopendir=uninstrumented
-fun:feclearexcept=uninstrumented
-fun:fedisableexcept=uninstrumented
-fun:feenableexcept=uninstrumented
-fun:fegetenv=uninstrumented
-fun:fegetexcept=uninstrumented
-fun:fegetexceptflag=uninstrumented
-fun:fegetround=uninstrumented
-fun:feholdexcept=uninstrumented
-fun:feof=uninstrumented
-fun:feof_unlocked=uninstrumented
-fun:feraiseexcept=uninstrumented
-fun:ferror=uninstrumented
-fun:ferror_unlocked=uninstrumented
-fun:fesetenv=uninstrumented
-fun:fesetexceptflag=uninstrumented
-fun:fesetround=uninstrumented
-fun:fetestexcept=uninstrumented
-fun:feupdateenv=uninstrumented
-fun:fexecve=uninstrumented
-fun:fflush=uninstrumented
-fun:fflush_unlocked=uninstrumented
-fun:ffs=uninstrumented
-fun:ffsl=uninstrumented
-fun:ffsll=uninstrumented
-fun:fgetc=uninstrumented
-fun:fgetc_unlocked=uninstrumented
-fun:fgetgrent=uninstrumented
-fun:fgetgrent_r=uninstrumented
-fun:fgetpos=uninstrumented
-fun:fgetpos64=uninstrumented
-fun:fgetpwent=uninstrumented
-fun:fgetpwent_r=uninstrumented
-fun:fgets=uninstrumented
-fun:fgets_unlocked=uninstrumented
-fun:fgetsgent=uninstrumented
-fun:fgetsgent_r=uninstrumented
-fun:fgetspent=uninstrumented
-fun:fgetspent_r=uninstrumented
-fun:fgetwc=uninstrumented
-fun:fgetwc_unlocked=uninstrumented
-fun:fgetws=uninstrumented
-fun:fgetws_unlocked=uninstrumented
-fun:fgetxattr=uninstrumented
-fun:fileno=uninstrumented
-fun:fileno_unlocked=uninstrumented
-fun:finite=uninstrumented
-fun:finitef=uninstrumented
-fun:finitel=uninstrumented
-fun:flistxattr=uninstrumented
-fun:flock=uninstrumented
-fun:flockfile=uninstrumented
-fun:floor=uninstrumented
-fun:floorf=uninstrumented
-fun:floorl=uninstrumented
-fun:fma=uninstrumented
-fun:fmaf=uninstrumented
-fun:fmal=uninstrumented
-fun:fmax=uninstrumented
-fun:fmaxf=uninstrumented
-fun:fmaxl=uninstrumented
-fun:fmemopen=uninstrumented
-fun:fmin=uninstrumented
-fun:fminf=uninstrumented
-fun:fminl=uninstrumented
-fun:fmod=uninstrumented
-fun:fmodf=uninstrumented
-fun:fmodl=uninstrumented
-fun:fmtmsg=uninstrumented
-fun:fnmatch=uninstrumented
-fun:fopen=uninstrumented
-fun:fopen64=uninstrumented
-fun:fopencookie=uninstrumented
-fun:fork=uninstrumented
-fun:forkpty=uninstrumented
-fun:fpathconf=uninstrumented
-fun:fprintf=uninstrumented
-fun:fputc=uninstrumented
-fun:fputc_unlocked=uninstrumented
-fun:fputs=uninstrumented
-fun:fputs_unlocked=uninstrumented
-fun:fputwc=uninstrumented
-fun:fputwc_unlocked=uninstrumented
-fun:fputws=uninstrumented
-fun:fputws_unlocked=uninstrumented
-fun:frame_dummy=uninstrumented
-fun:fread=uninstrumented
-fun:fread_unlocked=uninstrumented
-fun:free=uninstrumented
-fun:free_dynamic_blocks=uninstrumented
-fun:free_segments=uninstrumented
-fun:freeaddrinfo=uninstrumented
-fun:freeifaddrs=uninstrumented
-fun:freelocale=uninstrumented
-fun:fremovexattr=uninstrumented
-fun:freopen=uninstrumented
-fun:freopen64=uninstrumented
-fun:frexp=uninstrumented
-fun:frexpf=uninstrumented
-fun:frexpl=uninstrumented
-fun:fscanf=uninstrumented
-fun:fseek=uninstrumented
-fun:fseeko=uninstrumented
-fun:fseeko64=uninstrumented
-fun:fsetpos=uninstrumented
-fun:fsetpos64=uninstrumented
-fun:fsetxattr=uninstrumented
-fun:fstat=uninstrumented
-fun:fstat64=uninstrumented
-fun:fstatat=uninstrumented
-fun:fstatat64=uninstrumented
-fun:fstatfs=uninstrumented
-fun:fstatfs64=uninstrumented
-fun:fstatvfs=uninstrumented
-fun:fstatvfs64=uninstrumented
-fun:fsync=uninstrumented
-fun:ftell=uninstrumented
-fun:ftello=uninstrumented
-fun:ftello64=uninstrumented
-fun:ftime=uninstrumented
-fun:ftok=uninstrumented
-fun:ftruncate=uninstrumented
-fun:ftruncate64=uninstrumented
-fun:ftrylockfile=uninstrumented
-fun:fts_children=uninstrumented
-fun:fts_close=uninstrumented
-fun:fts_open=uninstrumented
-fun:fts_read=uninstrumented
-fun:fts_set=uninstrumented
-fun:ftw=uninstrumented
-fun:ftw64=uninstrumented
-fun:funlockfile=uninstrumented
-fun:futimens=uninstrumented
-fun:futimes=uninstrumented
-fun:futimesat=uninstrumented
-fun:fwide=uninstrumented
-fun:fwprintf=uninstrumented
-fun:fwrite=uninstrumented
-fun:fwrite_unlocked=uninstrumented
-fun:fwscanf=uninstrumented
-fun:gai_cancel=uninstrumented
-fun:gai_error=uninstrumented
-fun:gai_strerror=uninstrumented
-fun:gai_suspend=uninstrumented
-fun:gamma=uninstrumented
-fun:gammaf=uninstrumented
-fun:gammal=uninstrumented
-fun:gcvt=uninstrumented
-fun:get_BID128.constprop.5=uninstrumented
-fun:get_avphys_pages=uninstrumented
-fun:get_current_dir_name=uninstrumented
-fun:get_kernel_syms=uninstrumented
-fun:get_myaddress=uninstrumented
-fun:get_nprocs=uninstrumented
-fun:get_nprocs_conf=uninstrumented
-fun:get_phys_pages=uninstrumented
-fun:getaddrinfo=uninstrumented
-fun:getaddrinfo_a=uninstrumented
-fun:getaliasbyname=uninstrumented
-fun:getaliasbyname_r=uninstrumented
-fun:getaliasent=uninstrumented
-fun:getaliasent_r=uninstrumented
-fun:getc=uninstrumented
-fun:getc_unlocked=uninstrumented
-fun:getchar=uninstrumented
-fun:getchar_unlocked=uninstrumented
-fun:getcontext=uninstrumented
-fun:getcwd=uninstrumented
-fun:getdate=uninstrumented
-fun:getdate_r=uninstrumented
-fun:getdelim=uninstrumented
-fun:getdirentries=uninstrumented
-fun:getdirentries64=uninstrumented
-fun:getdomainname=uninstrumented
-fun:getdtablesize=uninstrumented
-fun:getegid=uninstrumented
-fun:getenv=uninstrumented
-fun:geteuid=uninstrumented
-fun:getfsent=uninstrumented
-fun:getfsfile=uninstrumented
-fun:getfsspec=uninstrumented
-fun:getgid=uninstrumented
-fun:getgrent=uninstrumented
-fun:getgrent_r=uninstrumented
-fun:getgrgid=uninstrumented
-fun:getgrgid_r=uninstrumented
-fun:getgrnam=uninstrumented
-fun:getgrnam_r=uninstrumented
-fun:getgrouplist=uninstrumented
-fun:getgroups=uninstrumented
-fun:gethostbyaddr=uninstrumented
-fun:gethostbyaddr_r=uninstrumented
-fun:gethostbyname=uninstrumented
-fun:gethostbyname2=uninstrumented
-fun:gethostbyname2_r=uninstrumented
-fun:gethostbyname_r=uninstrumented
-fun:gethostent=uninstrumented
-fun:gethostent_r=uninstrumented
-fun:gethostid=uninstrumented
-fun:gethostname=uninstrumented
-fun:getifaddrs=uninstrumented
-fun:getipv4sourcefilter=uninstrumented
-fun:getitimer=uninstrumented
-fun:getline=uninstrumented
-fun:getloadavg=uninstrumented
-fun:getlogin=uninstrumented
-fun:getlogin_r=uninstrumented
-fun:getmntent=uninstrumented
-fun:getmntent_r=uninstrumented
-fun:getmsg=uninstrumented
-fun:getnameinfo=uninstrumented
-fun:getnetbyaddr=uninstrumented
-fun:getnetbyaddr_r=uninstrumented
-fun:getnetbyname=uninstrumented
-fun:getnetbyname_r=uninstrumented
-fun:getnetent=uninstrumented
-fun:getnetent_r=uninstrumented
-fun:getnetgrent=uninstrumented
-fun:getnetgrent_r=uninstrumented
-fun:getnetname=uninstrumented
-fun:getopt=uninstrumented
-fun:getopt_long=uninstrumented
-fun:getopt_long_only=uninstrumented
-fun:getpagesize=uninstrumented
-fun:getpass=uninstrumented
-fun:getpeername=uninstrumented
-fun:getpgid=uninstrumented
-fun:getpgrp=uninstrumented
-fun:getpid=uninstrumented
-fun:getpmsg=uninstrumented
-fun:getppid=uninstrumented
-fun:getpriority=uninstrumented
-fun:getprotobyname=uninstrumented
-fun:getprotobyname_r=uninstrumented
-fun:getprotobynumber=uninstrumented
-fun:getprotobynumber_r=uninstrumented
-fun:getprotoent=uninstrumented
-fun:getprotoent_r=uninstrumented
-fun:getpt=uninstrumented
-fun:getpublickey=uninstrumented
-fun:getpw=uninstrumented
-fun:getpwent=uninstrumented
-fun:getpwent_r=uninstrumented
-fun:getpwnam=uninstrumented
-fun:getpwnam_r=uninstrumented
-fun:getpwuid=uninstrumented
-fun:getpwuid_r=uninstrumented
-fun:getresgid=uninstrumented
-fun:getresuid=uninstrumented
-fun:getrlimit=uninstrumented
-fun:getrlimit64=uninstrumented
-fun:getrpcbyname=uninstrumented
-fun:getrpcbyname_r=uninstrumented
-fun:getrpcbynumber=uninstrumented
-fun:getrpcbynumber_r=uninstrumented
-fun:getrpcent=uninstrumented
-fun:getrpcent_r=uninstrumented
-fun:getrpcport=uninstrumented
-fun:getrusage=uninstrumented
-fun:gets=uninstrumented
-fun:getsecretkey=uninstrumented
-fun:getservbyname=uninstrumented
-fun:getservbyname_r=uninstrumented
-fun:getservbyport=uninstrumented
-fun:getservbyport_r=uninstrumented
-fun:getservent=uninstrumented
-fun:getservent_r=uninstrumented
-fun:getsgent=uninstrumented
-fun:getsgent_r=uninstrumented
-fun:getsgnam=uninstrumented
-fun:getsgnam_r=uninstrumented
-fun:getsid=uninstrumented
-fun:getsockname=uninstrumented
-fun:getsockopt=uninstrumented
-fun:getsourcefilter=uninstrumented
-fun:getspent=uninstrumented
-fun:getspent_r=uninstrumented
-fun:getspnam=uninstrumented
-fun:getspnam_r=uninstrumented
-fun:getsubopt=uninstrumented
-fun:gettext=uninstrumented
-fun:gettimeofday=uninstrumented
-fun:getttyent=uninstrumented
-fun:getttynam=uninstrumented
-fun:getuid=uninstrumented
-fun:getusershell=uninstrumented
-fun:getutent=uninstrumented
-fun:getutent_r=uninstrumented
-fun:getutid=uninstrumented
-fun:getutid_r=uninstrumented
-fun:getutline=uninstrumented
-fun:getutline_r=uninstrumented
-fun:getutmp=uninstrumented
-fun:getutmpx=uninstrumented
-fun:getutxent=uninstrumented
-fun:getutxid=uninstrumented
-fun:getutxline=uninstrumented
-fun:getw=uninstrumented
-fun:getwc=uninstrumented
-fun:getwc_unlocked=uninstrumented
-fun:getwchar=uninstrumented
-fun:getwchar_unlocked=uninstrumented
-fun:getwd=uninstrumented
-fun:getxattr=uninstrumented
-fun:glob=uninstrumented
-fun:glob64=uninstrumented
-fun:glob_pattern_p=uninstrumented
-fun:globfree=uninstrumented
-fun:globfree64=uninstrumented
-fun:gmtime=uninstrumented
-fun:gmtime_r=uninstrumented
-fun:gnu_dev_major=uninstrumented
-fun:gnu_dev_makedev=uninstrumented
-fun:gnu_dev_minor=uninstrumented
-fun:gnu_get_libc_release=uninstrumented
-fun:gnu_get_libc_version=uninstrumented
-fun:grantpt=uninstrumented
-fun:group_member=uninstrumented
-fun:gsignal=uninstrumented
-fun:gtty=uninstrumented
-fun:hasmntopt=uninstrumented
-fun:hcreate=uninstrumented
-fun:hcreate_r=uninstrumented
-fun:hdestroy=uninstrumented
-fun:hdestroy_r=uninstrumented
-fun:herror=uninstrumented
-fun:host2netname=uninstrumented
-fun:hsearch=uninstrumented
-fun:hsearch_r=uninstrumented
-fun:hstrerror=uninstrumented
-fun:htonl=uninstrumented
-fun:htons=uninstrumented
-fun:hypot=uninstrumented
-fun:hypotf=uninstrumented
-fun:hypotl=uninstrumented
-fun:iconv=uninstrumented
-fun:iconv_close=uninstrumented
-fun:iconv_open=uninstrumented
-fun:idna_to_ascii_lz=uninstrumented
-fun:idna_to_unicode_lzlz=uninstrumented
-fun:if_freenameindex=uninstrumented
-fun:if_indextoname=uninstrumented
-fun:if_nameindex=uninstrumented
-fun:if_nametoindex=uninstrumented
-fun:ilogb=uninstrumented
-fun:ilogbf=uninstrumented
-fun:ilogbl=uninstrumented
-fun:imaxabs=uninstrumented
-fun:imaxdiv=uninstrumented
-fun:index=uninstrumented
-fun:inet6_opt_append=uninstrumented
-fun:inet6_opt_find=uninstrumented
-fun:inet6_opt_finish=uninstrumented
-fun:inet6_opt_get_val=uninstrumented
-fun:inet6_opt_init=uninstrumented
-fun:inet6_opt_next=uninstrumented
-fun:inet6_opt_set_val=uninstrumented
-fun:inet6_option_alloc=uninstrumented
-fun:inet6_option_append=uninstrumented
-fun:inet6_option_find=uninstrumented
-fun:inet6_option_init=uninstrumented
-fun:inet6_option_next=uninstrumented
-fun:inet6_option_space=uninstrumented
-fun:inet6_rth_add=uninstrumented
-fun:inet6_rth_getaddr=uninstrumented
-fun:inet6_rth_init=uninstrumented
-fun:inet6_rth_reverse=uninstrumented
-fun:inet6_rth_segments=uninstrumented
-fun:inet6_rth_space=uninstrumented
-fun:inet_addr=uninstrumented
-fun:inet_aton=uninstrumented
-fun:inet_lnaof=uninstrumented
-fun:inet_makeaddr=uninstrumented
-fun:inet_net_ntop=uninstrumented
-fun:inet_net_pton=uninstrumented
-fun:inet_neta=uninstrumented
-fun:inet_netof=uninstrumented
-fun:inet_network=uninstrumented
-fun:inet_nsap_addr=uninstrumented
-fun:inet_nsap_ntoa=uninstrumented
-fun:inet_ntoa=uninstrumented
-fun:inet_ntop=uninstrumented
-fun:inet_pton=uninstrumented
-fun:init_module=uninstrumented
-fun:initgroups=uninstrumented
-fun:initstate=uninstrumented
-fun:initstate_r=uninstrumented
-fun:innetgr=uninstrumented
-fun:inotify_add_watch=uninstrumented
-fun:inotify_init=uninstrumented
-fun:inotify_init1=uninstrumented
-fun:inotify_rm_watch=uninstrumented
-fun:insque=uninstrumented
-fun:ioctl=uninstrumented
-fun:ioperm=uninstrumented
-fun:iopl=uninstrumented
-fun:iruserok=uninstrumented
-fun:iruserok_af=uninstrumented
-fun:isalnum=uninstrumented
-fun:isalnum_l=uninstrumented
-fun:isalpha=uninstrumented
-fun:isalpha_l=uninstrumented
-fun:isascii=uninstrumented
-fun:isastream=uninstrumented
-fun:isatty=uninstrumented
-fun:isblank=uninstrumented
-fun:isblank_l=uninstrumented
-fun:iscntrl=uninstrumented
-fun:iscntrl_l=uninstrumented
-fun:isctype=uninstrumented
-fun:isdigit=uninstrumented
-fun:isdigit_l=uninstrumented
-fun:isfdtype=uninstrumented
-fun:isgraph=uninstrumented
-fun:isgraph_l=uninstrumented
-fun:isinf=uninstrumented
-fun:isinfd128=uninstrumented
-fun:isinfd32=uninstrumented
-fun:isinfd64=uninstrumented
-fun:isinff=uninstrumented
-fun:isinfl=uninstrumented
-fun:islower=uninstrumented
-fun:islower_l=uninstrumented
-fun:isnan=uninstrumented
-fun:isnanf=uninstrumented
-fun:isnanl=uninstrumented
-fun:isprint=uninstrumented
-fun:isprint_l=uninstrumented
-fun:ispunct=uninstrumented
-fun:ispunct_l=uninstrumented
-fun:isspace=uninstrumented
-fun:isspace_l=uninstrumented
-fun:isupper=uninstrumented
-fun:isupper_l=uninstrumented
-fun:iswalnum=uninstrumented
-fun:iswalnum_l=uninstrumented
-fun:iswalpha=uninstrumented
-fun:iswalpha_l=uninstrumented
-fun:iswblank=uninstrumented
-fun:iswblank_l=uninstrumented
-fun:iswcntrl=uninstrumented
-fun:iswcntrl_l=uninstrumented
-fun:iswctype=uninstrumented
-fun:iswctype_l=uninstrumented
-fun:iswdigit=uninstrumented
-fun:iswdigit_l=uninstrumented
-fun:iswgraph=uninstrumented
-fun:iswgraph_l=uninstrumented
-fun:iswlower=uninstrumented
-fun:iswlower_l=uninstrumented
-fun:iswprint=uninstrumented
-fun:iswprint_l=uninstrumented
-fun:iswpunct=uninstrumented
-fun:iswpunct_l=uninstrumented
-fun:iswspace=uninstrumented
-fun:iswspace_l=uninstrumented
-fun:iswupper=uninstrumented
-fun:iswupper_l=uninstrumented
-fun:iswxdigit=uninstrumented
-fun:iswxdigit_l=uninstrumented
-fun:isxdigit=uninstrumented
-fun:isxdigit_l=uninstrumented
-fun:j0=uninstrumented
-fun:j0f=uninstrumented
-fun:j0l=uninstrumented
-fun:j1=uninstrumented
-fun:j1f=uninstrumented
-fun:j1l=uninstrumented
-fun:jn=uninstrumented
-fun:jnf=uninstrumented
-fun:jnl=uninstrumented
-fun:jrand48=uninstrumented
-fun:jrand48_r=uninstrumented
-fun:key_decryptsession=uninstrumented
-fun:key_decryptsession_pk=uninstrumented
-fun:key_encryptsession=uninstrumented
-fun:key_encryptsession_pk=uninstrumented
-fun:key_gendes=uninstrumented
-fun:key_get_conv=uninstrumented
-fun:key_secretkey_is_set=uninstrumented
-fun:key_setnet=uninstrumented
-fun:key_setsecret=uninstrumented
-fun:kill=uninstrumented
-fun:killpg=uninstrumented
-fun:klogctl=uninstrumented
-fun:l64a=uninstrumented
-fun:labs=uninstrumented
-fun:lchmod=uninstrumented
-fun:lchown=uninstrumented
-fun:lckpwdf=uninstrumented
-fun:lcong48=uninstrumented
-fun:lcong48_r=uninstrumented
-fun:ldexp=uninstrumented
-fun:ldexpf=uninstrumented
-fun:ldexpl=uninstrumented
-fun:ldiv=uninstrumented
-fun:lfind=uninstrumented
-fun:lgamma=uninstrumented
-fun:lgamma_r=uninstrumented
-fun:lgammaf=uninstrumented
-fun:lgammaf_r=uninstrumented
-fun:lgammal=uninstrumented
-fun:lgammal_r=uninstrumented
-fun:lgetxattr=uninstrumented
-fun:link=uninstrumented
-fun:linkat=uninstrumented
-fun:lio_listio=uninstrumented
-fun:lio_listio64=uninstrumented
-fun:listen=uninstrumented
-fun:listxattr=uninstrumented
-fun:llabs=uninstrumented
-fun:lldiv=uninstrumented
-fun:llistxattr=uninstrumented
-fun:llrint=uninstrumented
-fun:llrintf=uninstrumented
-fun:llrintl=uninstrumented
-fun:llround=uninstrumented
-fun:llroundf=uninstrumented
-fun:llroundl=uninstrumented
-fun:llseek=uninstrumented
-fun:localeconv=uninstrumented
-fun:localtime=uninstrumented
-fun:localtime_r=uninstrumented
-fun:lockf=uninstrumented
-fun:lockf64=uninstrumented
-fun:log=uninstrumented
-fun:log10=uninstrumented
-fun:log10f=uninstrumented
-fun:log10l=uninstrumented
-fun:log1p=uninstrumented
-fun:log1pf=uninstrumented
-fun:log1pl=uninstrumented
-fun:log2=uninstrumented
-fun:log2f=uninstrumented
-fun:log2l=uninstrumented
-fun:logb=uninstrumented
-fun:logbf=uninstrumented
-fun:logbl=uninstrumented
-fun:logf=uninstrumented
-fun:login=uninstrumented
-fun:login_tty=uninstrumented
-fun:logl=uninstrumented
-fun:logout=uninstrumented
-fun:logwtmp=uninstrumented
-fun:longjmp=uninstrumented
-fun:lrand48=uninstrumented
-fun:lrand48_r=uninstrumented
-fun:lremovexattr=uninstrumented
-fun:lrint=uninstrumented
-fun:lrintf=uninstrumented
-fun:lrintl=uninstrumented
-fun:lround=uninstrumented
-fun:lroundf=uninstrumented
-fun:lroundl=uninstrumented
-fun:lsearch=uninstrumented
-fun:lseek=uninstrumented
-fun:lseek64=uninstrumented
-fun:lsetxattr=uninstrumented
-fun:lstat=uninstrumented
-fun:lstat64=uninstrumented
-fun:lutimes=uninstrumented
-fun:madvise=uninstrumented
-fun:makecontext=uninstrumented
-fun:mallinfo=uninstrumented
-fun:malloc=uninstrumented
-fun:malloc_get_state=uninstrumented
-fun:malloc_info=uninstrumented
-fun:malloc_set_state=uninstrumented
-fun:malloc_stats=uninstrumented
-fun:malloc_trim=uninstrumented
-fun:malloc_usable_size=uninstrumented
-fun:mallopt=uninstrumented
-fun:matherr=uninstrumented
-fun:mblen=uninstrumented
-fun:mbrlen=uninstrumented
-fun:mbrtowc=uninstrumented
-fun:mbsinit=uninstrumented
-fun:mbsnrtowcs=uninstrumented
-fun:mbsrtowcs=uninstrumented
-fun:mbstowcs=uninstrumented
-fun:mbtowc=uninstrumented
-fun:mcheck=uninstrumented
-fun:mcheck_check_all=uninstrumented
-fun:mcheck_pedantic=uninstrumented
-fun:mcount=uninstrumented
-fun:memalign=uninstrumented
-fun:memccpy=uninstrumented
-fun:memchr=uninstrumented
-fun:memcmp=uninstrumented
-fun:memcpy=uninstrumented
-fun:memfrob=uninstrumented
-fun:memmem=uninstrumented
-fun:memmove=uninstrumented
-fun:mempcpy=uninstrumented
-fun:memrchr=uninstrumented
-fun:memset=uninstrumented
-fun:mincore=uninstrumented
-fun:mkdir=uninstrumented
-fun:mkdirat=uninstrumented
-fun:mkdtemp=uninstrumented
-fun:mkfifo=uninstrumented
-fun:mkfifoat=uninstrumented
-fun:mknod=uninstrumented
-fun:mknodat=uninstrumented
-fun:mkostemp=uninstrumented
-fun:mkostemp64=uninstrumented
-fun:mkostemps=uninstrumented
-fun:mkostemps64=uninstrumented
-fun:mkstemp=uninstrumented
-fun:mkstemp64=uninstrumented
-fun:mkstemps=uninstrumented
-fun:mkstemps64=uninstrumented
-fun:mktemp=uninstrumented
-fun:mktime=uninstrumented
-fun:mlock=uninstrumented
-fun:mlockall=uninstrumented
-fun:mmap=uninstrumented
-fun:mmap64=uninstrumented
-fun:modf=uninstrumented
-fun:modff=uninstrumented
-fun:modfl=uninstrumented
-fun:modify_ldt=uninstrumented
-fun:moncontrol=uninstrumented
-fun:monstartup=uninstrumented
-fun:mount=uninstrumented
-fun:mprobe=uninstrumented
-fun:mprotect=uninstrumented
-fun:mq_close=uninstrumented
-fun:mq_getattr=uninstrumented
-fun:mq_notify=uninstrumented
-fun:mq_open=uninstrumented
-fun:mq_receive=uninstrumented
-fun:mq_send=uninstrumented
-fun:mq_setattr=uninstrumented
-fun:mq_timedreceive=uninstrumented
-fun:mq_timedsend=uninstrumented
-fun:mq_unlink=uninstrumented
-fun:mrand48=uninstrumented
-fun:mrand48_r=uninstrumented
-fun:mremap=uninstrumented
-fun:msgctl=uninstrumented
-fun:msgget=uninstrumented
-fun:msgrcv=uninstrumented
-fun:msgsnd=uninstrumented
-fun:msync=uninstrumented
-fun:mtrace=uninstrumented
-fun:munlock=uninstrumented
-fun:munlockall=uninstrumented
-fun:munmap=uninstrumented
-fun:muntrace=uninstrumented
-fun:name_to_handle_at=uninstrumented
-fun:nan=uninstrumented
-fun:nanf=uninstrumented
-fun:nanl=uninstrumented
-fun:nanosleep=uninstrumented
-fun:nearbyint=uninstrumented
-fun:nearbyintf=uninstrumented
-fun:nearbyintl=uninstrumented
-fun:netname2host=uninstrumented
-fun:netname2user=uninstrumented
-fun:newlocale=uninstrumented
-fun:nextafter=uninstrumented
-fun:nextafterf=uninstrumented
-fun:nextafterl=uninstrumented
-fun:nexttoward=uninstrumented
-fun:nexttowardf=uninstrumented
-fun:nexttowardl=uninstrumented
-fun:nfsservctl=uninstrumented
-fun:nftw=uninstrumented
-fun:nftw64=uninstrumented
-fun:ngettext=uninstrumented
-fun:nice=uninstrumented
-fun:nis_add=uninstrumented
-fun:nis_add_entry=uninstrumented
-fun:nis_addmember=uninstrumented
-fun:nis_checkpoint=uninstrumented
-fun:nis_clone_directory=uninstrumented
-fun:nis_clone_object=uninstrumented
-fun:nis_clone_result=uninstrumented
-fun:nis_creategroup=uninstrumented
-fun:nis_destroy_object=uninstrumented
-fun:nis_destroygroup=uninstrumented
-fun:nis_dir_cmp=uninstrumented
-fun:nis_domain_of=uninstrumented
-fun:nis_domain_of_r=uninstrumented
-fun:nis_first_entry=uninstrumented
-fun:nis_free_directory=uninstrumented
-fun:nis_free_object=uninstrumented
-fun:nis_free_request=uninstrumented
-fun:nis_freenames=uninstrumented
-fun:nis_freeresult=uninstrumented
-fun:nis_freeservlist=uninstrumented
-fun:nis_freetags=uninstrumented
-fun:nis_getnames=uninstrumented
-fun:nis_getservlist=uninstrumented
-fun:nis_ismember=uninstrumented
-fun:nis_leaf_of=uninstrumented
-fun:nis_leaf_of_r=uninstrumented
-fun:nis_lerror=uninstrumented
-fun:nis_list=uninstrumented
-fun:nis_local_directory=uninstrumented
-fun:nis_local_group=uninstrumented
-fun:nis_local_host=uninstrumented
-fun:nis_local_principal=uninstrumented
-fun:nis_lookup=uninstrumented
-fun:nis_mkdir=uninstrumented
-fun:nis_modify=uninstrumented
-fun:nis_modify_entry=uninstrumented
-fun:nis_name_of=uninstrumented
-fun:nis_name_of_r=uninstrumented
-fun:nis_next_entry=uninstrumented
-fun:nis_perror=uninstrumented
-fun:nis_ping=uninstrumented
-fun:nis_print_directory=uninstrumented
-fun:nis_print_entry=uninstrumented
-fun:nis_print_group=uninstrumented
-fun:nis_print_group_entry=uninstrumented
-fun:nis_print_link=uninstrumented
-fun:nis_print_object=uninstrumented
-fun:nis_print_result=uninstrumented
-fun:nis_print_rights=uninstrumented
-fun:nis_print_table=uninstrumented
-fun:nis_read_obj=uninstrumented
-fun:nis_remove=uninstrumented
-fun:nis_remove_entry=uninstrumented
-fun:nis_removemember=uninstrumented
-fun:nis_rmdir=uninstrumented
-fun:nis_servstate=uninstrumented
-fun:nis_sperrno=uninstrumented
-fun:nis_sperror=uninstrumented
-fun:nis_sperror_r=uninstrumented
-fun:nis_stats=uninstrumented
-fun:nis_verifygroup=uninstrumented
-fun:nis_write_obj=uninstrumented
-fun:nl_langinfo=uninstrumented
-fun:nl_langinfo_l=uninstrumented
-fun:nop=uninstrumented
-fun:nptl_freeres=uninstrumented
-fun:nr_digits256=uninstrumented
-fun:nrand48=uninstrumented
-fun:nrand48_r=uninstrumented
-fun:ns_datetosecs=uninstrumented
-fun:ns_format_ttl=uninstrumented
-fun:ns_get16=uninstrumented
-fun:ns_get32=uninstrumented
-fun:ns_initparse=uninstrumented
-fun:ns_makecanon=uninstrumented
-fun:ns_msg_getflag=uninstrumented
-fun:ns_name_compress=uninstrumented
-fun:ns_name_ntol=uninstrumented
-fun:ns_name_ntop=uninstrumented
-fun:ns_name_pack=uninstrumented
-fun:ns_name_pton=uninstrumented
-fun:ns_name_rollback=uninstrumented
-fun:ns_name_skip=uninstrumented
-fun:ns_name_uncompress=uninstrumented
-fun:ns_name_unpack=uninstrumented
-fun:ns_parse_ttl=uninstrumented
-fun:ns_parserr=uninstrumented
-fun:ns_put16=uninstrumented
-fun:ns_put32=uninstrumented
-fun:ns_samedomain=uninstrumented
-fun:ns_samename=uninstrumented
-fun:ns_skiprr=uninstrumented
-fun:ns_sprintrr=uninstrumented
-fun:ns_sprintrrf=uninstrumented
-fun:ns_subdomain=uninstrumented
-fun:ntohl=uninstrumented
-fun:ntohs=uninstrumented
-fun:ntp_adjtime=uninstrumented
-fun:ntp_gettime=uninstrumented
-fun:ntp_gettimex=uninstrumented
-fun:obstack_free=uninstrumented
-fun:obstack_printf=uninstrumented
-fun:obstack_vprintf=uninstrumented
-fun:on_exit=uninstrumented
-fun:open=uninstrumented
-fun:open64=uninstrumented
-fun:open_by_handle_at=uninstrumented
-fun:open_memstream=uninstrumented
-fun:open_wmemstream=uninstrumented
-fun:openat=uninstrumented
-fun:openat64=uninstrumented
-fun:opendir=uninstrumented
-fun:openlog=uninstrumented
-fun:openpty=uninstrumented
-fun:parse_printf_format=uninstrumented
-fun:passwd2des=uninstrumented
-fun:pathconf=uninstrumented
-fun:pause=uninstrumented
-fun:pclose=uninstrumented
-fun:perror=uninstrumented
-fun:personality=uninstrumented
-fun:pipe=uninstrumented
-fun:pipe2=uninstrumented
-fun:pivot_root=uninstrumented
-fun:pmap_getmaps=uninstrumented
-fun:pmap_getport=uninstrumented
-fun:pmap_rmtcall=uninstrumented
-fun:pmap_set=uninstrumented
-fun:pmap_unset=uninstrumented
-fun:poll=uninstrumented
-fun:popen=uninstrumented
-fun:posix_fadvise=uninstrumented
-fun:posix_fadvise64=uninstrumented
-fun:posix_fallocate=uninstrumented
-fun:posix_fallocate64=uninstrumented
-fun:posix_madvise=uninstrumented
-fun:posix_memalign=uninstrumented
-fun:posix_openpt=uninstrumented
-fun:posix_spawn=uninstrumented
-fun:posix_spawn_file_actions_addclose=uninstrumented
-fun:posix_spawn_file_actions_adddup2=uninstrumented
-fun:posix_spawn_file_actions_addopen=uninstrumented
-fun:posix_spawn_file_actions_destroy=uninstrumented
-fun:posix_spawn_file_actions_init=uninstrumented
-fun:posix_spawnattr_destroy=uninstrumented
-fun:posix_spawnattr_getflags=uninstrumented
-fun:posix_spawnattr_getpgroup=uninstrumented
-fun:posix_spawnattr_getschedparam=uninstrumented
-fun:posix_spawnattr_getschedpolicy=uninstrumented
-fun:posix_spawnattr_getsigdefault=uninstrumented
-fun:posix_spawnattr_getsigmask=uninstrumented
-fun:posix_spawnattr_init=uninstrumented
-fun:posix_spawnattr_setflags=uninstrumented
-fun:posix_spawnattr_setpgroup=uninstrumented
-fun:posix_spawnattr_setschedparam=uninstrumented
-fun:posix_spawnattr_setschedpolicy=uninstrumented
-fun:posix_spawnattr_setsigdefault=uninstrumented
-fun:posix_spawnattr_setsigmask=uninstrumented
-fun:posix_spawnp=uninstrumented
-fun:pow=uninstrumented
-fun:pow10=uninstrumented
-fun:pow10f=uninstrumented
-fun:pow10l=uninstrumented
-fun:powf=uninstrumented
-fun:powl=uninstrumented
-fun:ppoll=uninstrumented
-fun:prctl=uninstrumented
-fun:pread=uninstrumented
-fun:pread64=uninstrumented
-fun:preadv=uninstrumented
-fun:preadv64=uninstrumented
-fun:printf=uninstrumented
-fun:printf_size=uninstrumented
-fun:printf_size_info=uninstrumented
-fun:prlimit=uninstrumented
-fun:prlimit64=uninstrumented
-fun:process_vm_readv=uninstrumented
-fun:process_vm_writev=uninstrumented
-fun:profil=uninstrumented
-fun:pselect=uninstrumented
-fun:psiginfo=uninstrumented
-fun:psignal=uninstrumented
-fun:pthread_atfork=uninstrumented
-fun:pthread_attr_destroy=uninstrumented
-fun:pthread_attr_getaffinity_np=uninstrumented
-fun:pthread_attr_getdetachstate=uninstrumented
-fun:pthread_attr_getguardsize=uninstrumented
-fun:pthread_attr_getinheritsched=uninstrumented
-fun:pthread_attr_getschedparam=uninstrumented
-fun:pthread_attr_getschedpolicy=uninstrumented
-fun:pthread_attr_getscope=uninstrumented
-fun:pthread_attr_getstack=uninstrumented
-fun:pthread_attr_getstackaddr=uninstrumented
-fun:pthread_attr_getstacksize=uninstrumented
-fun:pthread_attr_init=uninstrumented
-fun:pthread_attr_setaffinity_np=uninstrumented
-fun:pthread_attr_setdetachstate=uninstrumented
-fun:pthread_attr_setguardsize=uninstrumented
-fun:pthread_attr_setinheritsched=uninstrumented
-fun:pthread_attr_setschedparam=uninstrumented
-fun:pthread_attr_setschedpolicy=uninstrumented
-fun:pthread_attr_setscope=uninstrumented
-fun:pthread_attr_setstack=uninstrumented
-fun:pthread_attr_setstackaddr=uninstrumented
-fun:pthread_attr_setstacksize=uninstrumented
-fun:pthread_barrier_destroy=uninstrumented
-fun:pthread_barrier_init=uninstrumented
-fun:pthread_barrier_wait=uninstrumented
-fun:pthread_barrierattr_destroy=uninstrumented
-fun:pthread_barrierattr_getpshared=uninstrumented
-fun:pthread_barrierattr_init=uninstrumented
-fun:pthread_barrierattr_setpshared=uninstrumented
-fun:pthread_cancel=uninstrumented
-fun:pthread_cancel_init=uninstrumented
-fun:pthread_cond_broadcast=uninstrumented
-fun:pthread_cond_destroy=uninstrumented
-fun:pthread_cond_init=uninstrumented
-fun:pthread_cond_signal=uninstrumented
-fun:pthread_cond_timedwait=uninstrumented
-fun:pthread_cond_wait=uninstrumented
-fun:pthread_condattr_destroy=uninstrumented
-fun:pthread_condattr_getclock=uninstrumented
-fun:pthread_condattr_getpshared=uninstrumented
-fun:pthread_condattr_init=uninstrumented
-fun:pthread_condattr_setclock=uninstrumented
-fun:pthread_condattr_setpshared=uninstrumented
-fun:pthread_create=uninstrumented
-fun:pthread_detach=uninstrumented
-fun:pthread_equal=uninstrumented
-fun:pthread_exit=uninstrumented
-fun:pthread_getaffinity_np=uninstrumented
-fun:pthread_getattr_np=uninstrumented
-fun:pthread_getconcurrency=uninstrumented
-fun:pthread_getcpuclockid=uninstrumented
-fun:pthread_getname_np=uninstrumented
-fun:pthread_getschedparam=uninstrumented
-fun:pthread_getspecific=uninstrumented
-fun:pthread_join=uninstrumented
-fun:pthread_key_create=uninstrumented
-fun:pthread_key_delete=uninstrumented
-fun:pthread_kill=uninstrumented
-fun:pthread_kill_other_threads_np=uninstrumented
-fun:pthread_mutex_consistent=uninstrumented
-fun:pthread_mutex_consistent_np=uninstrumented
-fun:pthread_mutex_destroy=uninstrumented
-fun:pthread_mutex_getprioceiling=uninstrumented
-fun:pthread_mutex_init=uninstrumented
-fun:pthread_mutex_lock=uninstrumented
-fun:pthread_mutex_setprioceiling=uninstrumented
-fun:pthread_mutex_timedlock=uninstrumented
-fun:pthread_mutex_trylock=uninstrumented
-fun:pthread_mutex_unlock=uninstrumented
-fun:pthread_mutexattr_destroy=uninstrumented
-fun:pthread_mutexattr_getkind_np=uninstrumented
-fun:pthread_mutexattr_getprioceiling=uninstrumented
-fun:pthread_mutexattr_getprotocol=uninstrumented
-fun:pthread_mutexattr_getpshared=uninstrumented
-fun:pthread_mutexattr_getrobust=uninstrumented
-fun:pthread_mutexattr_getrobust_np=uninstrumented
-fun:pthread_mutexattr_gettype=uninstrumented
-fun:pthread_mutexattr_init=uninstrumented
-fun:pthread_mutexattr_setkind_np=uninstrumented
-fun:pthread_mutexattr_setprioceiling=uninstrumented
-fun:pthread_mutexattr_setprotocol=uninstrumented
-fun:pthread_mutexattr_setpshared=uninstrumented
-fun:pthread_mutexattr_setrobust=uninstrumented
-fun:pthread_mutexattr_setrobust_np=uninstrumented
-fun:pthread_mutexattr_settype=uninstrumented
-fun:pthread_once=uninstrumented
-fun:pthread_rwlock_destroy=uninstrumented
-fun:pthread_rwlock_init=uninstrumented
-fun:pthread_rwlock_rdlock=uninstrumented
-fun:pthread_rwlock_timedrdlock=uninstrumented
-fun:pthread_rwlock_timedwrlock=uninstrumented
-fun:pthread_rwlock_tryrdlock=uninstrumented
-fun:pthread_rwlock_trywrlock=uninstrumented
-fun:pthread_rwlock_unlock=uninstrumented
-fun:pthread_rwlock_wrlock=uninstrumented
-fun:pthread_rwlockattr_destroy=uninstrumented
-fun:pthread_rwlockattr_getkind_np=uninstrumented
-fun:pthread_rwlockattr_getpshared=uninstrumented
-fun:pthread_rwlockattr_init=uninstrumented
-fun:pthread_rwlockattr_setkind_np=uninstrumented
-fun:pthread_rwlockattr_setpshared=uninstrumented
-fun:pthread_self=uninstrumented
-fun:pthread_setaffinity_np=uninstrumented
-fun:pthread_setcancelstate=uninstrumented
-fun:pthread_setcanceltype=uninstrumented
-fun:pthread_setconcurrency=uninstrumented
-fun:pthread_setname_np=uninstrumented
-fun:pthread_setschedparam=uninstrumented
-fun:pthread_setschedprio=uninstrumented
-fun:pthread_setspecific=uninstrumented
-fun:pthread_sigmask=uninstrumented
-fun:pthread_sigqueue=uninstrumented
-fun:pthread_spin_destroy=uninstrumented
-fun:pthread_spin_init=uninstrumented
-fun:pthread_spin_lock=uninstrumented
-fun:pthread_spin_trylock=uninstrumented
-fun:pthread_spin_unlock=uninstrumented
-fun:pthread_testcancel=uninstrumented
-fun:pthread_timedjoin_np=uninstrumented
-fun:pthread_tryjoin_np=uninstrumented
-fun:pthread_yield=uninstrumented
-fun:ptrace=uninstrumented
-fun:ptsname=uninstrumented
-fun:ptsname_r=uninstrumented
-fun:putc=uninstrumented
-fun:putc_unlocked=uninstrumented
-fun:putchar=uninstrumented
-fun:putchar_unlocked=uninstrumented
-fun:putenv=uninstrumented
-fun:putgrent=uninstrumented
-fun:putmsg=uninstrumented
-fun:putpmsg=uninstrumented
-fun:putpwent=uninstrumented
-fun:puts=uninstrumented
-fun:putsgent=uninstrumented
-fun:putspent=uninstrumented
-fun:pututline=uninstrumented
-fun:pututxline=uninstrumented
-fun:putw=uninstrumented
-fun:putwc=uninstrumented
-fun:putwc_unlocked=uninstrumented
-fun:putwchar=uninstrumented
-fun:putwchar_unlocked=uninstrumented
-fun:pvalloc=uninstrumented
-fun:pwrite=uninstrumented
-fun:pwrite64=uninstrumented
-fun:pwritev=uninstrumented
-fun:pwritev64=uninstrumented
-fun:qecvt=uninstrumented
-fun:qecvt_r=uninstrumented
-fun:qfcvt=uninstrumented
-fun:qfcvt_r=uninstrumented
-fun:qgcvt=uninstrumented
-fun:qsort=uninstrumented
-fun:qsort_r=uninstrumented
-fun:query_module=uninstrumented
-fun:quick_exit=uninstrumented
-fun:quotactl=uninstrumented
-fun:raise=uninstrumented
-fun:rand=uninstrumented
-fun:rand_r=uninstrumented
-fun:random=uninstrumented
-fun:random_r=uninstrumented
-fun:rawmemchr=uninstrumented
-fun:rcmd=uninstrumented
-fun:rcmd_af=uninstrumented
-fun:re_comp=uninstrumented
-fun:re_compile_fastmap=uninstrumented
-fun:re_compile_pattern=uninstrumented
-fun:re_exec=uninstrumented
-fun:re_match=uninstrumented
-fun:re_match_2=uninstrumented
-fun:re_search=uninstrumented
-fun:re_search_2=uninstrumented
-fun:re_set_registers=uninstrumented
-fun:re_set_syntax=uninstrumented
-fun:read=uninstrumented
-fun:readColdStartFile=uninstrumented
-fun:readahead=uninstrumented
-fun:readdir=uninstrumented
-fun:readdir64=uninstrumented
-fun:readdir64_r=uninstrumented
-fun:readdir_r=uninstrumented
-fun:readlink=uninstrumented
-fun:readlinkat=uninstrumented
-fun:readv=uninstrumented
-fun:realloc=uninstrumented
-fun:realpath=uninstrumented
-fun:reboot=uninstrumented
-fun:recv=uninstrumented
-fun:recvfrom=uninstrumented
-fun:recvmmsg=uninstrumented
-fun:recvmsg=uninstrumented
-fun:regcomp=uninstrumented
-fun:regerror=uninstrumented
-fun:regexec=uninstrumented
-fun:regfree=uninstrumented
-fun:register_printf_function=uninstrumented
-fun:register_printf_modifier=uninstrumented
-fun:register_printf_specifier=uninstrumented
-fun:register_printf_type=uninstrumented
-fun:registerrpc=uninstrumented
-fun:remainder=uninstrumented
-fun:remainderf=uninstrumented
-fun:remainderl=uninstrumented
-fun:remap_file_pages=uninstrumented
-fun:remove=uninstrumented
-fun:removexattr=uninstrumented
-fun:remque=uninstrumented
-fun:remquo=uninstrumented
-fun:remquof=uninstrumented
-fun:remquol=uninstrumented
-fun:rename=uninstrumented
-fun:renameat=uninstrumented
-fun:res_gethostbyaddr=uninstrumented
-fun:res_gethostbyname=uninstrumented
-fun:res_gethostbyname2=uninstrumented
-fun:res_send_setqhook=uninstrumented
-fun:res_send_setrhook=uninstrumented
-fun:revoke=uninstrumented
-fun:rewind=uninstrumented
-fun:rewinddir=uninstrumented
-fun:rexec=uninstrumented
-fun:rexec_af=uninstrumented
-fun:rindex=uninstrumented
-fun:rint=uninstrumented
-fun:rintf=uninstrumented
-fun:rintl=uninstrumented
-fun:rmdir=uninstrumented
-fun:round=uninstrumented
-fun:roundf=uninstrumented
-fun:rounding_correction.constprop.1=uninstrumented
-fun:roundl=uninstrumented
-fun:rpmatch=uninstrumented
-fun:rresvport=uninstrumented
-fun:rresvport_af=uninstrumented
-fun:rtime=uninstrumented
-fun:ruserok=uninstrumented
-fun:ruserok_af=uninstrumented
-fun:ruserpass=uninstrumented
-fun:sbrk=uninstrumented
-fun:scalb=uninstrumented
-fun:scalbf=uninstrumented
-fun:scalbl=uninstrumented
-fun:scalbln=uninstrumented
-fun:scalblnf=uninstrumented
-fun:scalblnl=uninstrumented
-fun:scalbn=uninstrumented
-fun:scalbnf=uninstrumented
-fun:scalbnl=uninstrumented
-fun:scandir=uninstrumented
-fun:scandir64=uninstrumented
-fun:scandirat=uninstrumented
-fun:scandirat64=uninstrumented
-fun:scanf=uninstrumented
-fun:sched_get_priority_max=uninstrumented
-fun:sched_get_priority_min=uninstrumented
-fun:sched_getaffinity=uninstrumented
-fun:sched_getcpu=uninstrumented
-fun:sched_getparam=uninstrumented
-fun:sched_getscheduler=uninstrumented
-fun:sched_rr_get_interval=uninstrumented
-fun:sched_setaffinity=uninstrumented
-fun:sched_setparam=uninstrumented
-fun:sched_setscheduler=uninstrumented
-fun:sched_yield=uninstrumented
-fun:seed48=uninstrumented
-fun:seed48_r=uninstrumented
-fun:seekdir=uninstrumented
-fun:select=uninstrumented
-fun:sem_close=uninstrumented
-fun:sem_destroy=uninstrumented
-fun:sem_getvalue=uninstrumented
-fun:sem_init=uninstrumented
-fun:sem_open=uninstrumented
-fun:sem_post=uninstrumented
-fun:sem_timedwait=uninstrumented
-fun:sem_timedwait_cleanup=uninstrumented
-fun:sem_timedwait_cleanup2=uninstrumented
-fun:sem_trywait=uninstrumented
-fun:sem_unlink=uninstrumented
-fun:sem_wait=uninstrumented
-fun:sem_wait_cleanup=uninstrumented
-fun:semctl=uninstrumented
-fun:semget=uninstrumented
-fun:semop=uninstrumented
-fun:semtimedop=uninstrumented
-fun:send=uninstrumented
-fun:sendfile=uninstrumented
-fun:sendfile64=uninstrumented
-fun:sendmmsg=uninstrumented
-fun:sendmsg=uninstrumented
-fun:sendto=uninstrumented
-fun:setaliasent=uninstrumented
-fun:setbuf=uninstrumented
-fun:setbuffer=uninstrumented
-fun:setcontext=uninstrumented
-fun:setdomainname=uninstrumented
-fun:setegid=uninstrumented
-fun:setenv=uninstrumented
-fun:seteuid=uninstrumented
-fun:setfsent=uninstrumented
-fun:setfsgid=uninstrumented
-fun:setfsuid=uninstrumented
-fun:setgid=uninstrumented
-fun:setgrent=uninstrumented
-fun:setgroups=uninstrumented
-fun:sethostent=uninstrumented
-fun:sethostid=uninstrumented
-fun:sethostname=uninstrumented
-fun:setipv4sourcefilter=uninstrumented
-fun:setitimer=uninstrumented
-fun:setjmp=uninstrumented
-fun:setkey=uninstrumented
-fun:setkey_r=uninstrumented
-fun:setlinebuf=uninstrumented
-fun:setlocale=uninstrumented
-fun:setlogin=uninstrumented
-fun:setlogmask=uninstrumented
-fun:setmntent=uninstrumented
-fun:setnetent=uninstrumented
-fun:setnetgrent=uninstrumented
-fun:setns=uninstrumented
-fun:setpgid=uninstrumented
-fun:setpgrp=uninstrumented
-fun:setpriority=uninstrumented
-fun:setprotoent=uninstrumented
-fun:setpwent=uninstrumented
-fun:setregid=uninstrumented
-fun:setresgid=uninstrumented
-fun:setresuid=uninstrumented
-fun:setreuid=uninstrumented
-fun:setrlimit=uninstrumented
-fun:setrlimit64=uninstrumented
-fun:setrpcent=uninstrumented
-fun:setservent=uninstrumented
-fun:setsgent=uninstrumented
-fun:setsid=uninstrumented
-fun:setsockopt=uninstrumented
-fun:setsourcefilter=uninstrumented
-fun:setspent=uninstrumented
-fun:setstate=uninstrumented
-fun:setstate_r=uninstrumented
-fun:settimeofday=uninstrumented
-fun:setttyent=uninstrumented
-fun:setuid=uninstrumented
-fun:setusershell=uninstrumented
-fun:setutent=uninstrumented
-fun:setutxent=uninstrumented
-fun:setvbuf=uninstrumented
-fun:setxattr=uninstrumented
-fun:setxid_mark_thread.isra.1=uninstrumented
-fun:sgetsgent=uninstrumented
-fun:sgetsgent_r=uninstrumented
-fun:sgetspent=uninstrumented
-fun:sgetspent_r=uninstrumented
-fun:shm_open=uninstrumented
-fun:shm_unlink=uninstrumented
-fun:shmat=uninstrumented
-fun:shmctl=uninstrumented
-fun:shmdt=uninstrumented
-fun:shmget=uninstrumented
-fun:shutdown=uninstrumented
-fun:sigaction=uninstrumented
-fun:sigaddset=uninstrumented
-fun:sigaltstack=uninstrumented
-fun:sigandset=uninstrumented
-fun:sigblock=uninstrumented
-fun:sigcancel_handler=uninstrumented
-fun:sigdelset=uninstrumented
-fun:sigemptyset=uninstrumented
-fun:sigfillset=uninstrumented
-fun:siggetmask=uninstrumented
-fun:sighandler_setxid=uninstrumented
-fun:sighold=uninstrumented
-fun:sigignore=uninstrumented
-fun:siginterrupt=uninstrumented
-fun:sigisemptyset=uninstrumented
-fun:sigismember=uninstrumented
-fun:siglongjmp=uninstrumented
-fun:signal=uninstrumented
-fun:signalfd=uninstrumented
-fun:significand=uninstrumented
-fun:significandf=uninstrumented
-fun:significandl=uninstrumented
-fun:sigorset=uninstrumented
-fun:sigpause=uninstrumented
-fun:sigpending=uninstrumented
-fun:sigprocmask=uninstrumented
-fun:sigqueue=uninstrumented
-fun:sigrelse=uninstrumented
-fun:sigreturn=uninstrumented
-fun:sigset=uninstrumented
-fun:sigsetmask=uninstrumented
-fun:sigstack=uninstrumented
-fun:sigsuspend=uninstrumented
-fun:sigtimedwait=uninstrumented
-fun:sigvec=uninstrumented
-fun:sigwait=uninstrumented
-fun:sigwaitinfo=uninstrumented
-fun:sin=uninstrumented
-fun:sincos=uninstrumented
-fun:sincosf=uninstrumented
-fun:sincosl=uninstrumented
-fun:sinf=uninstrumented
-fun:sinh=uninstrumented
-fun:sinhf=uninstrumented
-fun:sinhl=uninstrumented
-fun:sinl=uninstrumented
-fun:sleep=uninstrumented
-fun:snprintf=uninstrumented
-fun:sockatmark=uninstrumented
-fun:socket=uninstrumented
-fun:socketpair=uninstrumented
-fun:splice=uninstrumented
-fun:sprintf=uninstrumented
-fun:sprofil=uninstrumented
-fun:sqrt=uninstrumented
-fun:sqrtf=uninstrumented
-fun:sqrtl=uninstrumented
-fun:srand=uninstrumented
-fun:srand48=uninstrumented
-fun:srand48_r=uninstrumented
-fun:srandom=uninstrumented
-fun:srandom_r=uninstrumented
-fun:sscanf=uninstrumented
-fun:ssignal=uninstrumented
-fun:sstk=uninstrumented
-fun:stack_split_initialize_thread=uninstrumented
-fun:start_thread=uninstrumented
-fun:stat=uninstrumented
-fun:stat64=uninstrumented
-fun:statfs=uninstrumented
-fun:statfs64=uninstrumented
-fun:statvfs=uninstrumented
-fun:statvfs64=uninstrumented
-fun:step=uninstrumented
-fun:stime=uninstrumented
-fun:stpcpy=uninstrumented
-fun:stpncpy=uninstrumented
-fun:strcasecmp=uninstrumented
-fun:strcasecmp_l=uninstrumented
-fun:strcasestr=uninstrumented
-fun:strcat=uninstrumented
-fun:strchr=uninstrumented
-fun:strchrnul=uninstrumented
-fun:strcmp=uninstrumented
-fun:strcoll=uninstrumented
-fun:strcoll_l=uninstrumented
-fun:strcpy=uninstrumented
-fun:strcspn=uninstrumented
-fun:strdup=uninstrumented
-fun:strerror=uninstrumented
-fun:strerror_l=uninstrumented
-fun:strerror_r=uninstrumented
-fun:strfmon=uninstrumented
-fun:strfmon_l=uninstrumented
-fun:strfry=uninstrumented
-fun:strftime=uninstrumented
-fun:strftime_l=uninstrumented
-fun:strlen=uninstrumented
-fun:strncasecmp=uninstrumented
-fun:strncasecmp_l=uninstrumented
-fun:strncat=uninstrumented
-fun:strncmp=uninstrumented
-fun:strncpy=uninstrumented
-fun:strndup=uninstrumented
-fun:strnlen=uninstrumented
-fun:strpbrk=uninstrumented
-fun:strptime=uninstrumented
-fun:strptime_l=uninstrumented
-fun:strrchr=uninstrumented
-fun:strsep=uninstrumented
-fun:strsignal=uninstrumented
-fun:strspn=uninstrumented
-fun:strstr=uninstrumented
-fun:strtod=uninstrumented
-fun:strtod_l=uninstrumented
-fun:strtof=uninstrumented
-fun:strtof_l=uninstrumented
-fun:strtoimax=uninstrumented
-fun:strtok=uninstrumented
-fun:strtok_r=uninstrumented
-fun:strtol=uninstrumented
-fun:strtol_l=uninstrumented
-fun:strtold=uninstrumented
-fun:strtold_l=uninstrumented
-fun:strtoll=uninstrumented
-fun:strtoll_l=uninstrumented
-fun:strtoq=uninstrumented
-fun:strtoul=uninstrumented
-fun:strtoul_l=uninstrumented
-fun:strtoull=uninstrumented
-fun:strtoull_l=uninstrumented
-fun:strtoumax=uninstrumented
-fun:strtouq=uninstrumented
-fun:strverscmp=uninstrumented
-fun:strxfrm=uninstrumented
-fun:strxfrm_l=uninstrumented
-fun:stty=uninstrumented
-fun:sub256=uninstrumented
-fun:svc_exit=uninstrumented
-fun:svc_getreq=uninstrumented
-fun:svc_getreq_common=uninstrumented
-fun:svc_getreq_poll=uninstrumented
-fun:svc_getreqset=uninstrumented
-fun:svc_register=uninstrumented
-fun:svc_run=uninstrumented
-fun:svc_sendreply=uninstrumented
-fun:svc_unregister=uninstrumented
-fun:svcerr_auth=uninstrumented
-fun:svcerr_decode=uninstrumented
-fun:svcerr_noproc=uninstrumented
-fun:svcerr_noprog=uninstrumented
-fun:svcerr_progvers=uninstrumented
-fun:svcerr_systemerr=uninstrumented
-fun:svcerr_weakauth=uninstrumented
-fun:svcfd_create=uninstrumented
-fun:svcraw_create=uninstrumented
-fun:svctcp_create=uninstrumented
-fun:svcudp_bufcreate=uninstrumented
-fun:svcudp_create=uninstrumented
-fun:svcudp_enablecache=uninstrumented
-fun:svcunix_create=uninstrumented
-fun:svcunixfd_create=uninstrumented
-fun:swab=uninstrumented
-fun:swapcontext=uninstrumented
-fun:swapoff=uninstrumented
-fun:swapon=uninstrumented
-fun:swprintf=uninstrumented
-fun:swscanf=uninstrumented
-fun:symlink=uninstrumented
-fun:symlinkat=uninstrumented
-fun:sync=uninstrumented
-fun:sync_file_range=uninstrumented
-fun:syncfs=uninstrumented
-fun:syscall=uninstrumented
-fun:sysconf=uninstrumented
-fun:sysctl=uninstrumented
-fun:sysinfo=uninstrumented
-fun:syslog=uninstrumented
-fun:system=uninstrumented
-fun:sysv_signal=uninstrumented
-fun:tan=uninstrumented
-fun:tanf=uninstrumented
-fun:tanh=uninstrumented
-fun:tanhf=uninstrumented
-fun:tanhl=uninstrumented
-fun:tanl=uninstrumented
-fun:tcdrain=uninstrumented
-fun:tcflow=uninstrumented
-fun:tcflush=uninstrumented
-fun:tcgetattr=uninstrumented
-fun:tcgetpgrp=uninstrumented
-fun:tcgetsid=uninstrumented
-fun:tcsendbreak=uninstrumented
-fun:tcsetattr=uninstrumented
-fun:tcsetpgrp=uninstrumented
-fun:td_init=uninstrumented
-fun:td_log=uninstrumented
-fun:td_symbol_list=uninstrumented
-fun:td_ta_clear_event=uninstrumented
-fun:td_ta_delete=uninstrumented
-fun:td_ta_enable_stats=uninstrumented
-fun:td_ta_event_addr=uninstrumented
-fun:td_ta_event_getmsg=uninstrumented
-fun:td_ta_get_nthreads=uninstrumented
-fun:td_ta_get_ph=uninstrumented
-fun:td_ta_get_stats=uninstrumented
-fun:td_ta_map_id2thr=uninstrumented
-fun:td_ta_map_lwp2thr=uninstrumented
-fun:td_ta_new=uninstrumented
-fun:td_ta_reset_stats=uninstrumented
-fun:td_ta_set_event=uninstrumented
-fun:td_ta_setconcurrency=uninstrumented
-fun:td_ta_thr_iter=uninstrumented
-fun:td_ta_tsd_iter=uninstrumented
-fun:td_thr_clear_event=uninstrumented
-fun:td_thr_dbresume=uninstrumented
-fun:td_thr_dbsuspend=uninstrumented
-fun:td_thr_event_enable=uninstrumented
-fun:td_thr_event_getmsg=uninstrumented
-fun:td_thr_get_info=uninstrumented
-fun:td_thr_getfpregs=uninstrumented
-fun:td_thr_getgregs=uninstrumented
-fun:td_thr_getxregs=uninstrumented
-fun:td_thr_getxregsize=uninstrumented
-fun:td_thr_set_event=uninstrumented
-fun:td_thr_setfpregs=uninstrumented
-fun:td_thr_setgregs=uninstrumented
-fun:td_thr_setprio=uninstrumented
-fun:td_thr_setsigpending=uninstrumented
-fun:td_thr_setxregs=uninstrumented
-fun:td_thr_sigsetmask=uninstrumented
-fun:td_thr_tls_get_addr=uninstrumented
-fun:td_thr_tlsbase=uninstrumented
-fun:td_thr_tsd=uninstrumented
-fun:td_thr_validate=uninstrumented
-fun:tdelete=uninstrumented
-fun:tdestroy=uninstrumented
-fun:tee=uninstrumented
-fun:telldir=uninstrumented
-fun:tempnam=uninstrumented
-fun:textdomain=uninstrumented
-fun:tfind=uninstrumented
-fun:tgamma=uninstrumented
-fun:tgammaf=uninstrumented
-fun:tgammal=uninstrumented
-fun:time=uninstrumented
-fun:timegm=uninstrumented
-fun:timelocal=uninstrumented
-fun:timer_create=uninstrumented
-fun:timer_delete=uninstrumented
-fun:timer_getoverrun=uninstrumented
-fun:timer_gettime=uninstrumented
-fun:timer_settime=uninstrumented
-fun:timerfd_create=uninstrumented
-fun:timerfd_gettime=uninstrumented
-fun:timerfd_settime=uninstrumented
-fun:times=uninstrumented
-fun:tmpfile=uninstrumented
-fun:tmpfile64=uninstrumented
-fun:tmpnam=uninstrumented
-fun:tmpnam_r=uninstrumented
-fun:toascii=uninstrumented
-fun:tolower=uninstrumented
-fun:tolower_l=uninstrumented
-fun:toupper=uninstrumented
-fun:toupper_l=uninstrumented
-fun:towctrans=uninstrumented
-fun:towctrans_l=uninstrumented
-fun:towlower=uninstrumented
-fun:towlower_l=uninstrumented
-fun:towupper=uninstrumented
-fun:towupper_l=uninstrumented
-fun:tr_break=uninstrumented
-fun:trunc=uninstrumented
-fun:truncate=uninstrumented
-fun:truncate64=uninstrumented
-fun:truncf=uninstrumented
-fun:truncl=uninstrumented
-fun:tsearch=uninstrumented
-fun:ttyname=uninstrumented
-fun:ttyname_r=uninstrumented
-fun:ttyslot=uninstrumented
-fun:twalk=uninstrumented
-fun:tzset=uninstrumented
-fun:ualarm=uninstrumented
-fun:ulckpwdf=uninstrumented
-fun:ulimit=uninstrumented
-fun:umask=uninstrumented
-fun:umount=uninstrumented
-fun:umount2=uninstrumented
-fun:uname=uninstrumented
-fun:ungetc=uninstrumented
-fun:ungetwc=uninstrumented
-fun:unlink=uninstrumented
-fun:unlinkat=uninstrumented
-fun:unlockpt=uninstrumented
-fun:unsetenv=uninstrumented
-fun:unshare=uninstrumented
-fun:unwind_cleanup=uninstrumented
-fun:unwind_stop=uninstrumented
-fun:updwtmp=uninstrumented
-fun:updwtmpx=uninstrumented
-fun:uselib=uninstrumented
-fun:uselocale=uninstrumented
-fun:user2netname=uninstrumented
-fun:usleep=uninstrumented
-fun:ustat=uninstrumented
-fun:utime=uninstrumented
-fun:utimensat=uninstrumented
-fun:utimes=uninstrumented
-fun:utmpname=uninstrumented
-fun:utmpxname=uninstrumented
-fun:valloc=uninstrumented
-fun:vasprintf=uninstrumented
-fun:vdprintf=uninstrumented
-fun:verr=uninstrumented
-fun:verrx=uninstrumented
-fun:versionsort=uninstrumented
-fun:versionsort64=uninstrumented
-fun:vfork=uninstrumented
-fun:vfprintf=uninstrumented
-fun:vfscanf=uninstrumented
-fun:vfwprintf=uninstrumented
-fun:vfwscanf=uninstrumented
-fun:vhangup=uninstrumented
-fun:vlimit=uninstrumented
-fun:vmsplice=uninstrumented
-fun:vprintf=uninstrumented
-fun:vscanf=uninstrumented
-fun:vsnprintf=uninstrumented
-fun:vsprintf=uninstrumented
-fun:vsscanf=uninstrumented
-fun:vswprintf=uninstrumented
-fun:vswscanf=uninstrumented
-fun:vsyslog=uninstrumented
-fun:vtimes=uninstrumented
-fun:vwarn=uninstrumented
-fun:vwarnx=uninstrumented
-fun:vwprintf=uninstrumented
-fun:vwscanf=uninstrumented
-fun:wait=uninstrumented
-fun:wait3=uninstrumented
-fun:wait4=uninstrumented
-fun:waitid=uninstrumented
-fun:waitpid=uninstrumented
-fun:walker=uninstrumented
-fun:warn=uninstrumented
-fun:warnx=uninstrumented
-fun:wcpcpy=uninstrumented
-fun:wcpncpy=uninstrumented
-fun:wcrtomb=uninstrumented
-fun:wcscasecmp=uninstrumented
-fun:wcscasecmp_l=uninstrumented
-fun:wcscat=uninstrumented
-fun:wcschr=uninstrumented
-fun:wcschrnul=uninstrumented
-fun:wcscmp=uninstrumented
-fun:wcscoll=uninstrumented
-fun:wcscoll_l=uninstrumented
-fun:wcscpy=uninstrumented
-fun:wcscspn=uninstrumented
-fun:wcsdup=uninstrumented
-fun:wcsftime=uninstrumented
-fun:wcsftime_l=uninstrumented
-fun:wcslen=uninstrumented
-fun:wcsncasecmp=uninstrumented
-fun:wcsncasecmp_l=uninstrumented
-fun:wcsncat=uninstrumented
-fun:wcsncmp=uninstrumented
-fun:wcsncpy=uninstrumented
-fun:wcsnlen=uninstrumented
-fun:wcsnrtombs=uninstrumented
-fun:wcspbrk=uninstrumented
-fun:wcsrchr=uninstrumented
-fun:wcsrtombs=uninstrumented
-fun:wcsspn=uninstrumented
-fun:wcsstr=uninstrumented
-fun:wcstod=uninstrumented
-fun:wcstod_l=uninstrumented
-fun:wcstof=uninstrumented
-fun:wcstof_l=uninstrumented
-fun:wcstoimax=uninstrumented
-fun:wcstok=uninstrumented
-fun:wcstol=uninstrumented
-fun:wcstol_l=uninstrumented
-fun:wcstold=uninstrumented
-fun:wcstold_l=uninstrumented
-fun:wcstoll=uninstrumented
-fun:wcstoll_l=uninstrumented
-fun:wcstombs=uninstrumented
-fun:wcstoq=uninstrumented
-fun:wcstoul=uninstrumented
-fun:wcstoul_l=uninstrumented
-fun:wcstoull=uninstrumented
-fun:wcstoull_l=uninstrumented
-fun:wcstoumax=uninstrumented
-fun:wcstouq=uninstrumented
-fun:wcswcs=uninstrumented
-fun:wcswidth=uninstrumented
-fun:wcsxfrm=uninstrumented
-fun:wcsxfrm_l=uninstrumented
-fun:wctob=uninstrumented
-fun:wctomb=uninstrumented
-fun:wctrans=uninstrumented
-fun:wctrans_l=uninstrumented
-fun:wctype=uninstrumented
-fun:wctype_l=uninstrumented
-fun:wcwidth=uninstrumented
-fun:wmemchr=uninstrumented
-fun:wmemcmp=uninstrumented
-fun:wmemcpy=uninstrumented
-fun:wmemmove=uninstrumented
-fun:wmempcpy=uninstrumented
-fun:wmemset=uninstrumented
-fun:wordexp=uninstrumented
-fun:wordfree=uninstrumented
-fun:wprintf=uninstrumented
-fun:write=uninstrumented
-fun:writeColdStartFile=uninstrumented
-fun:writev=uninstrumented
-fun:wscanf=uninstrumented
-fun:xdecrypt=uninstrumented
-fun:xdr_accepted_reply=uninstrumented
-fun:xdr_array=uninstrumented
-fun:xdr_authdes_cred=uninstrumented
-fun:xdr_authdes_verf=uninstrumented
-fun:xdr_authunix_parms=uninstrumented
-fun:xdr_bool=uninstrumented
-fun:xdr_bytes=uninstrumented
-fun:xdr_callhdr=uninstrumented
-fun:xdr_callmsg=uninstrumented
-fun:xdr_cback_data=uninstrumented
-fun:xdr_char=uninstrumented
-fun:xdr_cryptkeyarg=uninstrumented
-fun:xdr_cryptkeyarg2=uninstrumented
-fun:xdr_cryptkeyres=uninstrumented
-fun:xdr_des_block=uninstrumented
-fun:xdr_domainname=uninstrumented
-fun:xdr_double=uninstrumented
-fun:xdr_enum=uninstrumented
-fun:xdr_float=uninstrumented
-fun:xdr_free=uninstrumented
-fun:xdr_getcredres=uninstrumented
-fun:xdr_hyper=uninstrumented
-fun:xdr_int=uninstrumented
-fun:xdr_int16_t=uninstrumented
-fun:xdr_int32_t=uninstrumented
-fun:xdr_int64_t=uninstrumented
-fun:xdr_int8_t=uninstrumented
-fun:xdr_key_netstarg=uninstrumented
-fun:xdr_key_netstres=uninstrumented
-fun:xdr_keybuf=uninstrumented
-fun:xdr_keydat=uninstrumented
-fun:xdr_keystatus=uninstrumented
-fun:xdr_long=uninstrumented
-fun:xdr_longlong_t=uninstrumented
-fun:xdr_mapname=uninstrumented
-fun:xdr_netnamestr=uninstrumented
-fun:xdr_netobj=uninstrumented
-fun:xdr_obj_p=uninstrumented
-fun:xdr_opaque=uninstrumented
-fun:xdr_opaque_auth=uninstrumented
-fun:xdr_peername=uninstrumented
-fun:xdr_pmap=uninstrumented
-fun:xdr_pmaplist=uninstrumented
-fun:xdr_pointer=uninstrumented
-fun:xdr_quad_t=uninstrumented
-fun:xdr_reference=uninstrumented
-fun:xdr_rejected_reply=uninstrumented
-fun:xdr_replymsg=uninstrumented
-fun:xdr_rmtcall_args=uninstrumented
-fun:xdr_rmtcallres=uninstrumented
-fun:xdr_short=uninstrumented
-fun:xdr_sizeof=uninstrumented
-fun:xdr_string=uninstrumented
-fun:xdr_u_char=uninstrumented
-fun:xdr_u_hyper=uninstrumented
-fun:xdr_u_int=uninstrumented
-fun:xdr_u_long=uninstrumented
-fun:xdr_u_longlong_t=uninstrumented
-fun:xdr_u_quad_t=uninstrumented
-fun:xdr_u_short=uninstrumented
-fun:xdr_uint16_t=uninstrumented
-fun:xdr_uint32_t=uninstrumented
-fun:xdr_uint64_t=uninstrumented
-fun:xdr_uint8_t=uninstrumented
-fun:xdr_union=uninstrumented
-fun:xdr_unixcred=uninstrumented
-fun:xdr_valdat=uninstrumented
-fun:xdr_vector=uninstrumented
-fun:xdr_void=uninstrumented
-fun:xdr_wrapstring=uninstrumented
-fun:xdr_yp_buf=uninstrumented
-fun:xdr_ypall=uninstrumented
-fun:xdr_ypbind_binding=uninstrumented
-fun:xdr_ypbind_resp=uninstrumented
-fun:xdr_ypbind_resptype=uninstrumented
-fun:xdr_ypbind_setdom=uninstrumented
-fun:xdr_ypdelete_args=uninstrumented
-fun:xdr_ypmap_parms=uninstrumented
-fun:xdr_ypmaplist=uninstrumented
-fun:xdr_yppush_status=uninstrumented
-fun:xdr_yppushresp_xfr=uninstrumented
-fun:xdr_ypreq_key=uninstrumented
-fun:xdr_ypreq_nokey=uninstrumented
-fun:xdr_ypreq_xfr=uninstrumented
-fun:xdr_ypresp_all=uninstrumented
-fun:xdr_ypresp_key_val=uninstrumented
-fun:xdr_ypresp_maplist=uninstrumented
-fun:xdr_ypresp_master=uninstrumented
-fun:xdr_ypresp_order=uninstrumented
-fun:xdr_ypresp_val=uninstrumented
-fun:xdr_ypresp_xfr=uninstrumented
-fun:xdr_ypstat=uninstrumented
-fun:xdr_ypupdate_args=uninstrumented
-fun:xdr_ypxfrstat=uninstrumented
-fun:xdrmem_create=uninstrumented
-fun:xdrrec_create=uninstrumented
-fun:xdrrec_endofrecord=uninstrumented
-fun:xdrrec_eof=uninstrumented
-fun:xdrrec_skiprecord=uninstrumented
-fun:xdrstdio_create=uninstrumented
-fun:xencrypt=uninstrumented
-fun:xprt_register=uninstrumented
-fun:xprt_unregister=uninstrumented
-fun:y0=uninstrumented
-fun:y0f=uninstrumented
-fun:y0l=uninstrumented
-fun:y1=uninstrumented
-fun:y1f=uninstrumented
-fun:y1l=uninstrumented
-fun:yn=uninstrumented
-fun:ynf=uninstrumented
-fun:ynl=uninstrumented
-fun:yp_all=uninstrumented
-fun:yp_bind=uninstrumented
-fun:yp_first=uninstrumented
-fun:yp_get_default_domain=uninstrumented
-fun:yp_maplist=uninstrumented
-fun:yp_master=uninstrumented
-fun:yp_match=uninstrumented
-fun:yp_next=uninstrumented
-fun:yp_order=uninstrumented
-fun:yp_unbind=uninstrumented
-fun:yp_update=uninstrumented
-fun:ypbinderr_string=uninstrumented
-fun:yperr_string=uninstrumented
-fun:ypprot_err=uninstrumented
diff --git a/lib/dfsan/libc_ubuntu1404_abilist.txt b/lib/dfsan/libc_ubuntu1404_abilist.txt
new file mode 100644
index 000000000000..a1ea0a06b537
--- /dev/null
+++ b/lib/dfsan/libc_ubuntu1404_abilist.txt
@@ -0,0 +1,3433 @@
+fun:_Exit=uninstrumented
+fun:_IO_adjust_column=uninstrumented
+fun:_IO_adjust_wcolumn=uninstrumented
+fun:_IO_default_doallocate=uninstrumented
+fun:_IO_default_finish=uninstrumented
+fun:_IO_default_pbackfail=uninstrumented
+fun:_IO_default_uflow=uninstrumented
+fun:_IO_default_xsgetn=uninstrumented
+fun:_IO_default_xsputn=uninstrumented
+fun:_IO_do_write=uninstrumented
+fun:_IO_doallocbuf=uninstrumented
+fun:_IO_fclose=uninstrumented
+fun:_IO_fdopen=uninstrumented
+fun:_IO_feof=uninstrumented
+fun:_IO_ferror=uninstrumented
+fun:_IO_fflush=uninstrumented
+fun:_IO_fgetpos=uninstrumented
+fun:_IO_fgetpos64=uninstrumented
+fun:_IO_fgets=uninstrumented
+fun:_IO_file_attach=uninstrumented
+fun:_IO_file_close=uninstrumented
+fun:_IO_file_close_it=uninstrumented
+fun:_IO_file_doallocate=uninstrumented
+fun:_IO_file_finish=uninstrumented
+fun:_IO_file_fopen=uninstrumented
+fun:_IO_file_init=uninstrumented
+fun:_IO_file_open=uninstrumented
+fun:_IO_file_overflow=uninstrumented
+fun:_IO_file_read=uninstrumented
+fun:_IO_file_seek=uninstrumented
+fun:_IO_file_seekoff=uninstrumented
+fun:_IO_file_setbuf=uninstrumented
+fun:_IO_file_stat=uninstrumented
+fun:_IO_file_sync=uninstrumented
+fun:_IO_file_underflow=uninstrumented
+fun:_IO_file_write=uninstrumented
+fun:_IO_file_xsputn=uninstrumented
+fun:_IO_flockfile=uninstrumented
+fun:_IO_flush_all=uninstrumented
+fun:_IO_flush_all_linebuffered=uninstrumented
+fun:_IO_fopen=uninstrumented
+fun:_IO_fprintf=uninstrumented
+fun:_IO_fputs=uninstrumented
+fun:_IO_fread=uninstrumented
+fun:_IO_free_backup_area=uninstrumented
+fun:_IO_free_wbackup_area=uninstrumented
+fun:_IO_fsetpos=uninstrumented
+fun:_IO_fsetpos64=uninstrumented
+fun:_IO_ftell=uninstrumented
+fun:_IO_ftrylockfile=uninstrumented
+fun:_IO_funlockfile=uninstrumented
+fun:_IO_fwrite=uninstrumented
+fun:_IO_getc=uninstrumented
+fun:_IO_getline=uninstrumented
+fun:_IO_getline_info=uninstrumented
+fun:_IO_gets=uninstrumented
+fun:_IO_init=uninstrumented
+fun:_IO_init_marker=uninstrumented
+fun:_IO_init_wmarker=uninstrumented
+fun:_IO_iter_begin=uninstrumented
+fun:_IO_iter_end=uninstrumented
+fun:_IO_iter_file=uninstrumented
+fun:_IO_iter_next=uninstrumented
+fun:_IO_least_wmarker=uninstrumented
+fun:_IO_link_in=uninstrumented
+fun:_IO_list_lock=uninstrumented
+fun:_IO_list_resetlock=uninstrumented
+fun:_IO_list_unlock=uninstrumented
+fun:_IO_marker_delta=uninstrumented
+fun:_IO_marker_difference=uninstrumented
+fun:_IO_padn=uninstrumented
+fun:_IO_peekc_locked=uninstrumented
+fun:_IO_popen=uninstrumented
+fun:_IO_printf=uninstrumented
+fun:_IO_proc_close=uninstrumented
+fun:_IO_proc_open=uninstrumented
+fun:_IO_putc=uninstrumented
+fun:_IO_puts=uninstrumented
+fun:_IO_remove_marker=uninstrumented
+fun:_IO_seekmark=uninstrumented
+fun:_IO_seekoff=uninstrumented
+fun:_IO_seekpos=uninstrumented
+fun:_IO_seekwmark=uninstrumented
+fun:_IO_setb=uninstrumented
+fun:_IO_setbuffer=uninstrumented
+fun:_IO_setvbuf=uninstrumented
+fun:_IO_sgetn=uninstrumented
+fun:_IO_sprintf=uninstrumented
+fun:_IO_sputbackc=uninstrumented
+fun:_IO_sputbackwc=uninstrumented
+fun:_IO_sscanf=uninstrumented
+fun:_IO_str_init_readonly=uninstrumented
+fun:_IO_str_init_static=uninstrumented
+fun:_IO_str_overflow=uninstrumented
+fun:_IO_str_pbackfail=uninstrumented
+fun:_IO_str_seekoff=uninstrumented
+fun:_IO_str_underflow=uninstrumented
+fun:_IO_sungetc=uninstrumented
+fun:_IO_sungetwc=uninstrumented
+fun:_IO_switch_to_get_mode=uninstrumented
+fun:_IO_switch_to_main_wget_area=uninstrumented
+fun:_IO_switch_to_wbackup_area=uninstrumented
+fun:_IO_switch_to_wget_mode=uninstrumented
+fun:_IO_un_link=uninstrumented
+fun:_IO_ungetc=uninstrumented
+fun:_IO_unsave_markers=uninstrumented
+fun:_IO_unsave_wmarkers=uninstrumented
+fun:_IO_vfprintf=uninstrumented
+fun:_IO_vfscanf=uninstrumented
+fun:_IO_vsprintf=uninstrumented
+fun:_IO_wdefault_doallocate=uninstrumented
+fun:_IO_wdefault_finish=uninstrumented
+fun:_IO_wdefault_pbackfail=uninstrumented
+fun:_IO_wdefault_uflow=uninstrumented
+fun:_IO_wdefault_xsgetn=uninstrumented
+fun:_IO_wdefault_xsputn=uninstrumented
+fun:_IO_wdo_write=uninstrumented
+fun:_IO_wdoallocbuf=uninstrumented
+fun:_IO_wfile_overflow=uninstrumented
+fun:_IO_wfile_seekoff=uninstrumented
+fun:_IO_wfile_sync=uninstrumented
+fun:_IO_wfile_underflow=uninstrumented
+fun:_IO_wfile_xsputn=uninstrumented
+fun:_IO_wmarker_delta=uninstrumented
+fun:_IO_wsetb=uninstrumented
+fun:_Unwind_Backtrace=uninstrumented
+fun:_Unwind_DeleteException=uninstrumented
+fun:_Unwind_FindEnclosingFunction=uninstrumented
+fun:_Unwind_Find_FDE=uninstrumented
+fun:_Unwind_ForcedUnwind=uninstrumented
+fun:_Unwind_GetCFA=uninstrumented
+fun:_Unwind_GetDataRelBase=uninstrumented
+fun:_Unwind_GetGR=uninstrumented
+fun:_Unwind_GetIP=uninstrumented
+fun:_Unwind_GetIPInfo=uninstrumented
+fun:_Unwind_GetLanguageSpecificData=uninstrumented
+fun:_Unwind_GetRegionStart=uninstrumented
+fun:_Unwind_GetTextRelBase=uninstrumented
+fun:_Unwind_RaiseException=uninstrumented
+fun:_Unwind_Resume=uninstrumented
+fun:_Unwind_Resume_or_Rethrow=uninstrumented
+fun:_Unwind_SetGR=uninstrumented
+fun:_Unwind_SetIP=uninstrumented
+fun:__absvdi2=uninstrumented
+fun:__absvsi2=uninstrumented
+fun:__absvti2=uninstrumented
+fun:__acos_finite=uninstrumented
+fun:__acosf_finite=uninstrumented
+fun:__acosh_finite=uninstrumented
+fun:__acoshf_finite=uninstrumented
+fun:__acoshl_finite=uninstrumented
+fun:__acosl_finite=uninstrumented
+fun:__addtf3=uninstrumented
+fun:__addvdi3=uninstrumented
+fun:__addvsi3=uninstrumented
+fun:__addvti3=uninstrumented
+fun:__adjtimex=uninstrumented
+fun:__arch_prctl=uninstrumented
+fun:__argz_count=uninstrumented
+fun:__argz_next=uninstrumented
+fun:__argz_stringify=uninstrumented
+fun:__ashlti3=uninstrumented
+fun:__ashrti3=uninstrumented
+fun:__asin_finite=uninstrumented
+fun:__asinf_finite=uninstrumented
+fun:__asinl_finite=uninstrumented
+fun:__asprintf=uninstrumented
+fun:__asprintf_chk=uninstrumented
+fun:__assert=uninstrumented
+fun:__assert_fail=uninstrumented
+fun:__assert_perror_fail=uninstrumented
+fun:__atan2_finite=uninstrumented
+fun:__atan2f_finite=uninstrumented
+fun:__atan2l_finite=uninstrumented
+fun:__atanh_finite=uninstrumented
+fun:__atanhf_finite=uninstrumented
+fun:__atanhl_finite=uninstrumented
+fun:__b64_ntop=uninstrumented
+fun:__b64_pton=uninstrumented
+fun:__backtrace=uninstrumented
+fun:__backtrace_symbols=uninstrumented
+fun:__backtrace_symbols_fd=uninstrumented
+fun:__bid128_abs=uninstrumented
+fun:__bid128_add=uninstrumented
+fun:__bid128_class=uninstrumented
+fun:__bid128_copy=uninstrumented
+fun:__bid128_copySign=uninstrumented
+fun:__bid128_div=uninstrumented
+fun:__bid128_fma=uninstrumented
+fun:__bid128_from_int32=uninstrumented
+fun:__bid128_from_int64=uninstrumented
+fun:__bid128_from_uint32=uninstrumented
+fun:__bid128_from_uint64=uninstrumented
+fun:__bid128_isCanonical=uninstrumented
+fun:__bid128_isFinite=uninstrumented
+fun:__bid128_isInf=uninstrumented
+fun:__bid128_isNaN=uninstrumented
+fun:__bid128_isNormal=uninstrumented
+fun:__bid128_isSignaling=uninstrumented
+fun:__bid128_isSigned=uninstrumented
+fun:__bid128_isSubnormal=uninstrumented
+fun:__bid128_isZero=uninstrumented
+fun:__bid128_mul=uninstrumented
+fun:__bid128_negate=uninstrumented
+fun:__bid128_quiet_equal=uninstrumented
+fun:__bid128_quiet_greater=uninstrumented
+fun:__bid128_quiet_greater_equal=uninstrumented
+fun:__bid128_quiet_greater_unordered=uninstrumented
+fun:__bid128_quiet_less=uninstrumented
+fun:__bid128_quiet_less_equal=uninstrumented
+fun:__bid128_quiet_less_unordered=uninstrumented
+fun:__bid128_quiet_not_equal=uninstrumented
+fun:__bid128_quiet_not_greater=uninstrumented
+fun:__bid128_quiet_not_less=uninstrumented
+fun:__bid128_quiet_ordered=uninstrumented
+fun:__bid128_quiet_unordered=uninstrumented
+fun:__bid128_radix=uninstrumented
+fun:__bid128_sameQuantum=uninstrumented
+fun:__bid128_signaling_greater=uninstrumented
+fun:__bid128_signaling_greater_equal=uninstrumented
+fun:__bid128_signaling_greater_unordered=uninstrumented
+fun:__bid128_signaling_less=uninstrumented
+fun:__bid128_signaling_less_equal=uninstrumented
+fun:__bid128_signaling_less_unordered=uninstrumented
+fun:__bid128_signaling_not_greater=uninstrumented
+fun:__bid128_signaling_not_less=uninstrumented
+fun:__bid128_sub=uninstrumented
+fun:__bid128_to_bid32=uninstrumented
+fun:__bid128_to_bid64=uninstrumented
+fun:__bid128_to_binary128=uninstrumented
+fun:__bid128_to_binary32=uninstrumented
+fun:__bid128_to_binary64=uninstrumented
+fun:__bid128_to_binary80=uninstrumented
+fun:__bid128_to_int32_ceil=uninstrumented
+fun:__bid128_to_int32_floor=uninstrumented
+fun:__bid128_to_int32_int=uninstrumented
+fun:__bid128_to_int32_rnint=uninstrumented
+fun:__bid128_to_int32_rninta=uninstrumented
+fun:__bid128_to_int32_xceil=uninstrumented
+fun:__bid128_to_int32_xfloor=uninstrumented
+fun:__bid128_to_int32_xint=uninstrumented
+fun:__bid128_to_int32_xrnint=uninstrumented
+fun:__bid128_to_int32_xrninta=uninstrumented
+fun:__bid128_to_int64_ceil=uninstrumented
+fun:__bid128_to_int64_floor=uninstrumented
+fun:__bid128_to_int64_int=uninstrumented
+fun:__bid128_to_int64_rnint=uninstrumented
+fun:__bid128_to_int64_rninta=uninstrumented
+fun:__bid128_to_int64_xceil=uninstrumented
+fun:__bid128_to_int64_xfloor=uninstrumented
+fun:__bid128_to_int64_xint=uninstrumented
+fun:__bid128_to_int64_xrnint=uninstrumented
+fun:__bid128_to_int64_xrninta=uninstrumented
+fun:__bid128_to_uint32_ceil=uninstrumented
+fun:__bid128_to_uint32_floor=uninstrumented
+fun:__bid128_to_uint32_int=uninstrumented
+fun:__bid128_to_uint32_rnint=uninstrumented
+fun:__bid128_to_uint32_rninta=uninstrumented
+fun:__bid128_to_uint32_xceil=uninstrumented
+fun:__bid128_to_uint32_xfloor=uninstrumented
+fun:__bid128_to_uint32_xint=uninstrumented
+fun:__bid128_to_uint32_xrnint=uninstrumented
+fun:__bid128_to_uint32_xrninta=uninstrumented
+fun:__bid128_to_uint64_ceil=uninstrumented
+fun:__bid128_to_uint64_floor=uninstrumented
+fun:__bid128_to_uint64_int=uninstrumented
+fun:__bid128_to_uint64_rnint=uninstrumented
+fun:__bid128_to_uint64_rninta=uninstrumented
+fun:__bid128_to_uint64_xceil=uninstrumented
+fun:__bid128_to_uint64_xfloor=uninstrumented
+fun:__bid128_to_uint64_xint=uninstrumented
+fun:__bid128_to_uint64_xrnint=uninstrumented
+fun:__bid128_to_uint64_xrninta=uninstrumented
+fun:__bid128_totalOrder=uninstrumented
+fun:__bid128_totalOrderMag=uninstrumented
+fun:__bid128dd_add=uninstrumented
+fun:__bid128dd_div=uninstrumented
+fun:__bid128dd_mul=uninstrumented
+fun:__bid128dd_sub=uninstrumented
+fun:__bid128ddd_fma=uninstrumented
+fun:__bid128ddq_fma=uninstrumented
+fun:__bid128dq_add=uninstrumented
+fun:__bid128dq_div=uninstrumented
+fun:__bid128dq_mul=uninstrumented
+fun:__bid128dq_sub=uninstrumented
+fun:__bid128dqd_fma=uninstrumented
+fun:__bid128dqq_fma=uninstrumented
+fun:__bid128qd_add=uninstrumented
+fun:__bid128qd_div=uninstrumented
+fun:__bid128qd_mul=uninstrumented
+fun:__bid128qd_sub=uninstrumented
+fun:__bid128qdd_fma=uninstrumented
+fun:__bid128qdq_fma=uninstrumented
+fun:__bid128qqd_fma=uninstrumented
+fun:__bid32_to_bid128=uninstrumented
+fun:__bid32_to_bid64=uninstrumented
+fun:__bid32_to_binary128=uninstrumented
+fun:__bid32_to_binary32=uninstrumented
+fun:__bid32_to_binary64=uninstrumented
+fun:__bid32_to_binary80=uninstrumented
+fun:__bid64_abs=uninstrumented
+fun:__bid64_add=uninstrumented
+fun:__bid64_class=uninstrumented
+fun:__bid64_copy=uninstrumented
+fun:__bid64_copySign=uninstrumented
+fun:__bid64_div=uninstrumented
+fun:__bid64_from_int32=uninstrumented
+fun:__bid64_from_int64=uninstrumented
+fun:__bid64_from_uint32=uninstrumented
+fun:__bid64_from_uint64=uninstrumented
+fun:__bid64_isCanonical=uninstrumented
+fun:__bid64_isFinite=uninstrumented
+fun:__bid64_isInf=uninstrumented
+fun:__bid64_isNaN=uninstrumented
+fun:__bid64_isNormal=uninstrumented
+fun:__bid64_isSignaling=uninstrumented
+fun:__bid64_isSigned=uninstrumented
+fun:__bid64_isSubnormal=uninstrumented
+fun:__bid64_isZero=uninstrumented
+fun:__bid64_mul=uninstrumented
+fun:__bid64_negate=uninstrumented
+fun:__bid64_quiet_equal=uninstrumented
+fun:__bid64_quiet_greater=uninstrumented
+fun:__bid64_quiet_greater_equal=uninstrumented
+fun:__bid64_quiet_greater_unordered=uninstrumented
+fun:__bid64_quiet_less=uninstrumented
+fun:__bid64_quiet_less_equal=uninstrumented
+fun:__bid64_quiet_less_unordered=uninstrumented
+fun:__bid64_quiet_not_equal=uninstrumented
+fun:__bid64_quiet_not_greater=uninstrumented
+fun:__bid64_quiet_not_less=uninstrumented
+fun:__bid64_quiet_ordered=uninstrumented
+fun:__bid64_quiet_unordered=uninstrumented
+fun:__bid64_radix=uninstrumented
+fun:__bid64_sameQuantum=uninstrumented
+fun:__bid64_signaling_greater=uninstrumented
+fun:__bid64_signaling_greater_equal=uninstrumented
+fun:__bid64_signaling_greater_unordered=uninstrumented
+fun:__bid64_signaling_less=uninstrumented
+fun:__bid64_signaling_less_equal=uninstrumented
+fun:__bid64_signaling_less_unordered=uninstrumented
+fun:__bid64_signaling_not_greater=uninstrumented
+fun:__bid64_signaling_not_less=uninstrumented
+fun:__bid64_sub=uninstrumented
+fun:__bid64_to_bid128=uninstrumented
+fun:__bid64_to_bid32=uninstrumented
+fun:__bid64_to_binary128=uninstrumented
+fun:__bid64_to_binary32=uninstrumented
+fun:__bid64_to_binary64=uninstrumented
+fun:__bid64_to_binary80=uninstrumented
+fun:__bid64_to_int32_ceil=uninstrumented
+fun:__bid64_to_int32_floor=uninstrumented
+fun:__bid64_to_int32_int=uninstrumented
+fun:__bid64_to_int32_rnint=uninstrumented
+fun:__bid64_to_int32_rninta=uninstrumented
+fun:__bid64_to_int32_xceil=uninstrumented
+fun:__bid64_to_int32_xfloor=uninstrumented
+fun:__bid64_to_int32_xint=uninstrumented
+fun:__bid64_to_int32_xrnint=uninstrumented
+fun:__bid64_to_int32_xrninta=uninstrumented
+fun:__bid64_to_int64_ceil=uninstrumented
+fun:__bid64_to_int64_floor=uninstrumented
+fun:__bid64_to_int64_int=uninstrumented
+fun:__bid64_to_int64_rnint=uninstrumented
+fun:__bid64_to_int64_rninta=uninstrumented
+fun:__bid64_to_int64_xceil=uninstrumented
+fun:__bid64_to_int64_xfloor=uninstrumented
+fun:__bid64_to_int64_xint=uninstrumented
+fun:__bid64_to_int64_xrnint=uninstrumented
+fun:__bid64_to_int64_xrninta=uninstrumented
+fun:__bid64_to_uint32_ceil=uninstrumented
+fun:__bid64_to_uint32_floor=uninstrumented
+fun:__bid64_to_uint32_int=uninstrumented
+fun:__bid64_to_uint32_rnint=uninstrumented
+fun:__bid64_to_uint32_rninta=uninstrumented
+fun:__bid64_to_uint32_xceil=uninstrumented
+fun:__bid64_to_uint32_xfloor=uninstrumented
+fun:__bid64_to_uint32_xint=uninstrumented
+fun:__bid64_to_uint32_xrnint=uninstrumented
+fun:__bid64_to_uint32_xrninta=uninstrumented
+fun:__bid64_to_uint64_ceil=uninstrumented
+fun:__bid64_to_uint64_floor=uninstrumented
+fun:__bid64_to_uint64_int=uninstrumented
+fun:__bid64_to_uint64_rnint=uninstrumented
+fun:__bid64_to_uint64_rninta=uninstrumented
+fun:__bid64_to_uint64_xceil=uninstrumented
+fun:__bid64_to_uint64_xfloor=uninstrumented
+fun:__bid64_to_uint64_xint=uninstrumented
+fun:__bid64_to_uint64_xrnint=uninstrumented
+fun:__bid64_to_uint64_xrninta=uninstrumented
+fun:__bid64_totalOrder=uninstrumented
+fun:__bid64_totalOrderMag=uninstrumented
+fun:__bid64ddq_fma=uninstrumented
+fun:__bid64dq_add=uninstrumented
+fun:__bid64dq_div=uninstrumented
+fun:__bid64dq_mul=uninstrumented
+fun:__bid64dq_sub=uninstrumented
+fun:__bid64dqd_fma=uninstrumented
+fun:__bid64dqq_fma=uninstrumented
+fun:__bid64qd_add=uninstrumented
+fun:__bid64qd_div=uninstrumented
+fun:__bid64qd_mul=uninstrumented
+fun:__bid64qd_sub=uninstrumented
+fun:__bid64qdd_fma=uninstrumented
+fun:__bid64qdq_fma=uninstrumented
+fun:__bid64qq_add=uninstrumented
+fun:__bid64qq_div=uninstrumented
+fun:__bid64qq_mul=uninstrumented
+fun:__bid64qq_sub=uninstrumented
+fun:__bid64qqd_fma=uninstrumented
+fun:__bid64qqq_fma=uninstrumented
+fun:__bid_adddd3=uninstrumented
+fun:__bid_addsd3=uninstrumented
+fun:__bid_addtd3=uninstrumented
+fun:__bid_divdd3=uninstrumented
+fun:__bid_divsd3=uninstrumented
+fun:__bid_divtd3=uninstrumented
+fun:__bid_eqdd2=uninstrumented
+fun:__bid_eqsd2=uninstrumented
+fun:__bid_eqtd2=uninstrumented
+fun:__bid_extendddtd2=uninstrumented
+fun:__bid_extendddtf=uninstrumented
+fun:__bid_extendddxf=uninstrumented
+fun:__bid_extenddfdd=uninstrumented
+fun:__bid_extenddftd=uninstrumented
+fun:__bid_extendsddd2=uninstrumented
+fun:__bid_extendsddf=uninstrumented
+fun:__bid_extendsdtd2=uninstrumented
+fun:__bid_extendsdtf=uninstrumented
+fun:__bid_extendsdxf=uninstrumented
+fun:__bid_extendsfdd=uninstrumented
+fun:__bid_extendsfsd=uninstrumented
+fun:__bid_extendsftd=uninstrumented
+fun:__bid_extendtftd=uninstrumented
+fun:__bid_extendxftd=uninstrumented
+fun:__bid_fixdddi=uninstrumented
+fun:__bid_fixddsi=uninstrumented
+fun:__bid_fixsddi=uninstrumented
+fun:__bid_fixsdsi=uninstrumented
+fun:__bid_fixtddi=uninstrumented
+fun:__bid_fixtdsi=uninstrumented
+fun:__bid_fixunsdddi=uninstrumented
+fun:__bid_fixunsddsi=uninstrumented
+fun:__bid_fixunssddi=uninstrumented
+fun:__bid_fixunssdsi=uninstrumented
+fun:__bid_fixunstddi=uninstrumented
+fun:__bid_fixunstdsi=uninstrumented
+fun:__bid_floatdidd=uninstrumented
+fun:__bid_floatdisd=uninstrumented
+fun:__bid_floatditd=uninstrumented
+fun:__bid_floatsidd=uninstrumented
+fun:__bid_floatsisd=uninstrumented
+fun:__bid_floatsitd=uninstrumented
+fun:__bid_floatunsdidd=uninstrumented
+fun:__bid_floatunsdisd=uninstrumented
+fun:__bid_floatunsditd=uninstrumented
+fun:__bid_floatunssidd=uninstrumented
+fun:__bid_floatunssisd=uninstrumented
+fun:__bid_floatunssitd=uninstrumented
+fun:__bid_gedd2=uninstrumented
+fun:__bid_gesd2=uninstrumented
+fun:__bid_getd2=uninstrumented
+fun:__bid_gtdd2=uninstrumented
+fun:__bid_gtsd2=uninstrumented
+fun:__bid_gttd2=uninstrumented
+fun:__bid_ledd2=uninstrumented
+fun:__bid_lesd2=uninstrumented
+fun:__bid_letd2=uninstrumented
+fun:__bid_ltdd2=uninstrumented
+fun:__bid_ltsd2=uninstrumented
+fun:__bid_lttd2=uninstrumented
+fun:__bid_muldd3=uninstrumented
+fun:__bid_mulsd3=uninstrumented
+fun:__bid_multd3=uninstrumented
+fun:__bid_nedd2=uninstrumented
+fun:__bid_nesd2=uninstrumented
+fun:__bid_netd2=uninstrumented
+fun:__bid_round128_19_38=uninstrumented
+fun:__bid_round192_39_57=uninstrumented
+fun:__bid_round256_58_76=uninstrumented
+fun:__bid_round64_2_18=uninstrumented
+fun:__bid_subdd3=uninstrumented
+fun:__bid_subsd3=uninstrumented
+fun:__bid_subtd3=uninstrumented
+fun:__bid_truncdddf=uninstrumented
+fun:__bid_truncddsd2=uninstrumented
+fun:__bid_truncddsf=uninstrumented
+fun:__bid_truncdfsd=uninstrumented
+fun:__bid_truncsdsf=uninstrumented
+fun:__bid_trunctddd2=uninstrumented
+fun:__bid_trunctddf=uninstrumented
+fun:__bid_trunctdsd2=uninstrumented
+fun:__bid_trunctdsf=uninstrumented
+fun:__bid_trunctdtf=uninstrumented
+fun:__bid_trunctdxf=uninstrumented
+fun:__bid_trunctfdd=uninstrumented
+fun:__bid_trunctfsd=uninstrumented
+fun:__bid_truncxfdd=uninstrumented
+fun:__bid_truncxfsd=uninstrumented
+fun:__bid_unorddd2=uninstrumented
+fun:__bid_unordsd2=uninstrumented
+fun:__bid_unordtd2=uninstrumented
+fun:__binary128_to_bid128=uninstrumented
+fun:__binary128_to_bid32=uninstrumented
+fun:__binary128_to_bid64=uninstrumented
+fun:__binary32_to_bid128=uninstrumented
+fun:__binary32_to_bid32=uninstrumented
+fun:__binary32_to_bid64=uninstrumented
+fun:__binary64_to_bid128=uninstrumented
+fun:__binary64_to_bid32=uninstrumented
+fun:__binary64_to_bid64=uninstrumented
+fun:__binary80_to_bid128=uninstrumented
+fun:__binary80_to_bid32=uninstrumented
+fun:__binary80_to_bid64=uninstrumented
+fun:__bsd_getpgrp=uninstrumented
+fun:__bswapdi2=uninstrumented
+fun:__bswapsi2=uninstrumented
+fun:__bzero=uninstrumented
+fun:__call_tls_dtors=uninstrumented
+fun:__chk_fail=uninstrumented
+fun:__clear_cache=uninstrumented
+fun:__clock_getcpuclockid=uninstrumented
+fun:__clock_getres=uninstrumented
+fun:__clock_gettime=uninstrumented
+fun:__clock_nanosleep=uninstrumented
+fun:__clock_settime=uninstrumented
+fun:__clog10=uninstrumented
+fun:__clog10f=uninstrumented
+fun:__clog10l=uninstrumented
+fun:__clone=uninstrumented
+fun:__close=uninstrumented
+fun:__clrsbdi2=uninstrumented
+fun:__clrsbti2=uninstrumented
+fun:__clzdi2=uninstrumented
+fun:__clzti2=uninstrumented
+fun:__cmpti2=uninstrumented
+fun:__cmsg_nxthdr=uninstrumented
+fun:__confstr_chk=uninstrumented
+fun:__connect=uninstrumented
+fun:__cosh_finite=uninstrumented
+fun:__coshf_finite=uninstrumented
+fun:__coshl_finite=uninstrumented
+fun:__cpu_indicator_init=uninstrumented
+fun:__create_ib_request=uninstrumented
+fun:__ctype_b_loc=uninstrumented
+fun:__ctype_get_mb_cur_max=uninstrumented
+fun:__ctype_init=uninstrumented
+fun:__ctype_tolower_loc=uninstrumented
+fun:__ctype_toupper_loc=uninstrumented
+fun:__ctzdi2=uninstrumented
+fun:__ctzti2=uninstrumented
+fun:__cxa_at_quick_exit=uninstrumented
+fun:__cxa_atexit=uninstrumented
+fun:__cxa_finalize=uninstrumented
+fun:__cxa_thread_atexit_impl=uninstrumented
+fun:__cyg_profile_func_enter=uninstrumented
+fun:__cyg_profile_func_exit=uninstrumented
+fun:__dcgettext=uninstrumented
+fun:__default_morecore=uninstrumented
+fun:__deregister_frame=uninstrumented
+fun:__deregister_frame_info=uninstrumented
+fun:__deregister_frame_info_bases=uninstrumented
+fun:__dfp_clear_except=uninstrumented
+fun:__dfp_get_round=uninstrumented
+fun:__dfp_raise_except=uninstrumented
+fun:__dfp_set_round=uninstrumented
+fun:__dfp_test_except=uninstrumented
+fun:__dgettext=uninstrumented
+fun:__divdc3=uninstrumented
+fun:__divsc3=uninstrumented
+fun:__divtc3=uninstrumented
+fun:__divtf3=uninstrumented
+fun:__divti3=uninstrumented
+fun:__divxc3=uninstrumented
+fun:__dn_comp=uninstrumented
+fun:__dn_count_labels=uninstrumented
+fun:__dn_expand=uninstrumented
+fun:__dn_skipname=uninstrumented
+fun:__do_niscall3=uninstrumented
+fun:__dprintf_chk=uninstrumented
+fun:__dup2=uninstrumented
+fun:__duplocale=uninstrumented
+fun:__emutls_get_address=uninstrumented
+fun:__emutls_register_common=uninstrumented
+fun:__enable_execute_stack=uninstrumented
+fun:__endmntent=uninstrumented
+fun:__eprintf=uninstrumented
+fun:__eqtf2=uninstrumented
+fun:__errno_location=uninstrumented
+fun:__exp10_finite=uninstrumented
+fun:__exp10f_finite=uninstrumented
+fun:__exp10l_finite=uninstrumented
+fun:__exp2_finite=uninstrumented
+fun:__exp2f_finite=uninstrumented
+fun:__exp2l_finite=uninstrumented
+fun:__exp_finite=uninstrumented
+fun:__expf_finite=uninstrumented
+fun:__expl_finite=uninstrumented
+fun:__extenddftf2=uninstrumented
+fun:__extendsftf2=uninstrumented
+fun:__extendxftf2=uninstrumented
+fun:__fbufsize=uninstrumented
+fun:__fcntl=uninstrumented
+fun:__fdelt_chk=uninstrumented
+fun:__fdelt_warn=uninstrumented
+fun:__fentry__=uninstrumented
+fun:__ffs=uninstrumented
+fun:__ffsdi2=uninstrumented
+fun:__ffsti2=uninstrumented
+fun:__fgets_chk=uninstrumented
+fun:__fgets_unlocked_chk=uninstrumented
+fun:__fgetws_chk=uninstrumented
+fun:__fgetws_unlocked_chk=uninstrumented
+fun:__finite=uninstrumented
+fun:__finitef=uninstrumented
+fun:__finitel=uninstrumented
+fun:__fixdfti=uninstrumented
+fun:__fixsfti=uninstrumented
+fun:__fixtfdi=uninstrumented
+fun:__fixtfsi=uninstrumented
+fun:__fixtfti=uninstrumented
+fun:__fixunsdfdi=uninstrumented
+fun:__fixunsdfti=uninstrumented
+fun:__fixunssfdi=uninstrumented
+fun:__fixunssfti=uninstrumented
+fun:__fixunstfdi=uninstrumented
+fun:__fixunstfsi=uninstrumented
+fun:__fixunstfti=uninstrumented
+fun:__fixunsxfdi=uninstrumented
+fun:__fixunsxfti=uninstrumented
+fun:__fixxfti=uninstrumented
+fun:__flbf=uninstrumented
+fun:__floatditf=uninstrumented
+fun:__floatsitf=uninstrumented
+fun:__floattidf=uninstrumented
+fun:__floattisf=uninstrumented
+fun:__floattitf=uninstrumented
+fun:__floattixf=uninstrumented
+fun:__floatunditf=uninstrumented
+fun:__floatunsitf=uninstrumented
+fun:__floatuntidf=uninstrumented
+fun:__floatuntisf=uninstrumented
+fun:__floatuntitf=uninstrumented
+fun:__floatuntixf=uninstrumented
+fun:__fmod_finite=uninstrumented
+fun:__fmodf_finite=uninstrumented
+fun:__fmodl_finite=uninstrumented
+fun:__follow_path=uninstrumented
+fun:__fork=uninstrumented
+fun:__fortify_fail=uninstrumented
+fun:__fp_nquery=uninstrumented
+fun:__fp_query=uninstrumented
+fun:__fp_resstat=uninstrumented
+fun:__fpclassify=uninstrumented
+fun:__fpclassifyf=uninstrumented
+fun:__fpclassifyl=uninstrumented
+fun:__fpending=uninstrumented
+fun:__fprintf_chk=uninstrumented
+fun:__fpurge=uninstrumented
+fun:__fread_chk=uninstrumented
+fun:__fread_unlocked_chk=uninstrumented
+fun:__freadable=uninstrumented
+fun:__freading=uninstrumented
+fun:__free_fdresult=uninstrumented
+fun:__freelocale=uninstrumented
+fun:__fsetlocking=uninstrumented
+fun:__fstat=uninstrumented
+fun:__fwprintf_chk=uninstrumented
+fun:__fwritable=uninstrumented
+fun:__fwriting=uninstrumented
+fun:__fxstat=uninstrumented
+fun:__fxstat64=uninstrumented
+fun:__fxstatat=uninstrumented
+fun:__fxstatat64=uninstrumented
+fun:__gai_sigqueue=uninstrumented
+fun:__gamma_r_finite=uninstrumented
+fun:__gammaf_r_finite=uninstrumented
+fun:__gammal_r_finite=uninstrumented
+fun:__gcc_bcmp=uninstrumented
+fun:__gcc_personality_v0=uninstrumented
+fun:__gconv_get_alias_db=uninstrumented
+fun:__gconv_get_cache=uninstrumented
+fun:__gconv_get_modules_db=uninstrumented
+fun:__generic_findstack=uninstrumented
+fun:__generic_morestack=uninstrumented
+fun:__generic_morestack_set_initial_sp=uninstrumented
+fun:__generic_releasestack=uninstrumented
+fun:__get_cpu_features=uninstrumented
+fun:__getauxval=uninstrumented
+fun:__getcwd_chk=uninstrumented
+fun:__getdelim=uninstrumented
+fun:__getdomainname_chk=uninstrumented
+fun:__getf2=uninstrumented
+fun:__getgroups_chk=uninstrumented
+fun:__gethostname_chk=uninstrumented
+fun:__getlogin_r_chk=uninstrumented
+fun:__getmntent_r=uninstrumented
+fun:__getpagesize=uninstrumented
+fun:__getpgid=uninstrumented
+fun:__getpid=uninstrumented
+fun:__gets_chk=uninstrumented
+fun:__gettimeofday=uninstrumented
+fun:__getwd_chk=uninstrumented
+fun:__gmtime_r=uninstrumented
+fun:__gttf2=uninstrumented
+fun:__h_errno_location=uninstrumented
+fun:__hostalias=uninstrumented
+fun:__hypot_finite=uninstrumented
+fun:__hypotf_finite=uninstrumented
+fun:__hypotl_finite=uninstrumented
+fun:__internal_endnetgrent=uninstrumented
+fun:__internal_getnetgrent_r=uninstrumented
+fun:__internal_setnetgrent=uninstrumented
+fun:__isalnum_l=uninstrumented
+fun:__isalpha_l=uninstrumented
+fun:__isascii_l=uninstrumented
+fun:__isblank_l=uninstrumented
+fun:__iscntrl_l=uninstrumented
+fun:__isctype=uninstrumented
+fun:__isdigit_l=uninstrumented
+fun:__isgraph_l=uninstrumented
+fun:__isinf=uninstrumented
+fun:__isinff=uninstrumented
+fun:__isinfl=uninstrumented
+fun:__islower_l=uninstrumented
+fun:__isnan=uninstrumented
+fun:__isnanf=uninstrumented
+fun:__isnanl=uninstrumented
+fun:__isoc99_fscanf=uninstrumented
+fun:__isoc99_fwscanf=uninstrumented
+fun:__isoc99_scanf=uninstrumented
+fun:__isoc99_sscanf=uninstrumented
+fun:__isoc99_swscanf=uninstrumented
+fun:__isoc99_vfscanf=uninstrumented
+fun:__isoc99_vfwscanf=uninstrumented
+fun:__isoc99_vscanf=uninstrumented
+fun:__isoc99_vsscanf=uninstrumented
+fun:__isoc99_vswscanf=uninstrumented
+fun:__isoc99_vwscanf=uninstrumented
+fun:__isoc99_wscanf=uninstrumented
+fun:__isprint_l=uninstrumented
+fun:__ispunct_l=uninstrumented
+fun:__issignaling=uninstrumented
+fun:__issignalingf=uninstrumented
+fun:__issignalingl=uninstrumented
+fun:__isspace_l=uninstrumented
+fun:__isupper_l=uninstrumented
+fun:__iswalnum_l=uninstrumented
+fun:__iswalpha_l=uninstrumented
+fun:__iswblank_l=uninstrumented
+fun:__iswcntrl_l=uninstrumented
+fun:__iswctype=uninstrumented
+fun:__iswctype_l=uninstrumented
+fun:__iswdigit_l=uninstrumented
+fun:__iswgraph_l=uninstrumented
+fun:__iswlower_l=uninstrumented
+fun:__iswprint_l=uninstrumented
+fun:__iswpunct_l=uninstrumented
+fun:__iswspace_l=uninstrumented
+fun:__iswupper_l=uninstrumented
+fun:__iswxdigit_l=uninstrumented
+fun:__isxdigit_l=uninstrumented
+fun:__ivaliduser=uninstrumented
+fun:__j0_finite=uninstrumented
+fun:__j0f_finite=uninstrumented
+fun:__j0l_finite=uninstrumented
+fun:__j1_finite=uninstrumented
+fun:__j1f_finite=uninstrumented
+fun:__j1l_finite=uninstrumented
+fun:__jn_finite=uninstrumented
+fun:__jnf_finite=uninstrumented
+fun:__jnl_finite=uninstrumented
+fun:__letf2=uninstrumented
+fun:__lgamma_r_finite=uninstrumented
+fun:__lgammaf_r_finite=uninstrumented
+fun:__lgammal_r_finite=uninstrumented
+fun:__libc_alloca_cutoff=uninstrumented
+fun:__libc_allocate_rtsig=uninstrumented
+fun:__libc_allocate_rtsig_private=uninstrumented
+fun:__libc_calloc=uninstrumented
+fun:__libc_clntudp_bufcreate=uninstrumented
+fun:__libc_csu_fini=uninstrumented
+fun:__libc_csu_init=uninstrumented
+fun:__libc_current_sigrtmax=uninstrumented
+fun:__libc_current_sigrtmax_private=uninstrumented
+fun:__libc_current_sigrtmin=uninstrumented
+fun:__libc_current_sigrtmin_private=uninstrumented
+fun:__libc_dl_error_tsd=uninstrumented
+fun:__libc_dlclose=uninstrumented
+fun:__libc_dlopen_mode=uninstrumented
+fun:__libc_dlsym=uninstrumented
+fun:__libc_fatal=uninstrumented
+fun:__libc_fork=uninstrumented
+fun:__libc_free=uninstrumented
+fun:__libc_freeres=uninstrumented
+fun:__libc_ifunc_impl_list=uninstrumented
+fun:__libc_init_first=uninstrumented
+fun:__libc_longjmp=uninstrumented
+fun:__libc_mallinfo=uninstrumented
+fun:__libc_malloc=uninstrumented
+fun:__libc_mallopt=uninstrumented
+fun:__libc_memalign=uninstrumented
+fun:__libc_pthread_init=uninstrumented
+fun:__libc_pvalloc=uninstrumented
+fun:__libc_pwrite=uninstrumented
+fun:__libc_realloc=uninstrumented
+fun:__libc_res_nquery=uninstrumented
+fun:__libc_res_nsearch=uninstrumented
+fun:__libc_rpc_getport=uninstrumented
+fun:__libc_sa_len=uninstrumented
+fun:__libc_secure_getenv=uninstrumented
+fun:__libc_siglongjmp=uninstrumented
+fun:__libc_start_main=uninstrumented
+fun:__libc_system=uninstrumented
+fun:__libc_thread_freeres=uninstrumented
+fun:__libc_valloc=uninstrumented
+fun:__loc_aton=uninstrumented
+fun:__loc_ntoa=uninstrumented
+fun:__log10_finite=uninstrumented
+fun:__log10f_finite=uninstrumented
+fun:__log10l_finite=uninstrumented
+fun:__log2_finite=uninstrumented
+fun:__log2f_finite=uninstrumented
+fun:__log2l_finite=uninstrumented
+fun:__log_finite=uninstrumented
+fun:__logf_finite=uninstrumented
+fun:__logl_finite=uninstrumented
+fun:__longjmp_chk=uninstrumented
+fun:__lseek=uninstrumented
+fun:__lshrti3=uninstrumented
+fun:__lstat=uninstrumented
+fun:__lttf2=uninstrumented
+fun:__lxstat=uninstrumented
+fun:__lxstat64=uninstrumented
+fun:__madvise=uninstrumented
+fun:__mbrlen=uninstrumented
+fun:__mbrtowc=uninstrumented
+fun:__mbsnrtowcs_chk=uninstrumented
+fun:__mbsrtowcs_chk=uninstrumented
+fun:__mbstowcs_chk=uninstrumented
+fun:__memcpy_chk=uninstrumented
+fun:__memmove_chk=uninstrumented
+fun:__mempcpy=uninstrumented
+fun:__mempcpy_chk=uninstrumented
+fun:__mempcpy_small=uninstrumented
+fun:__memset_chk=uninstrumented
+fun:__mknod=uninstrumented
+fun:__mktemp=uninstrumented
+fun:__modti3=uninstrumented
+fun:__monstartup=uninstrumented
+fun:__morestack=uninstrumented
+fun:__morestack_allocate_stack_space=uninstrumented
+fun:__morestack_block_signals=uninstrumented
+fun:__morestack_fail=uninstrumented
+fun:__morestack_get_guard=uninstrumented
+fun:__morestack_large_model=uninstrumented
+fun:__morestack_load_mmap=uninstrumented
+fun:__morestack_make_guard=uninstrumented
+fun:__morestack_non_split=uninstrumented
+fun:__morestack_release_segments=uninstrumented
+fun:__morestack_set_guard=uninstrumented
+fun:__morestack_unblock_signals=uninstrumented
+fun:__mq_open_2=uninstrumented
+fun:__muldc3=uninstrumented
+fun:__mulsc3=uninstrumented
+fun:__multc3=uninstrumented
+fun:__multf3=uninstrumented
+fun:__multi3=uninstrumented
+fun:__mulvdi3=uninstrumented
+fun:__mulvsi3=uninstrumented
+fun:__mulvti3=uninstrumented
+fun:__mulxc3=uninstrumented
+fun:__nanosleep=uninstrumented
+fun:__negtf2=uninstrumented
+fun:__negti2=uninstrumented
+fun:__negvdi2=uninstrumented
+fun:__negvsi2=uninstrumented
+fun:__negvti2=uninstrumented
+fun:__netf2=uninstrumented
+fun:__newlocale=uninstrumented
+fun:__nis_default_access=uninstrumented
+fun:__nis_default_group=uninstrumented
+fun:__nis_default_owner=uninstrumented
+fun:__nis_default_ttl=uninstrumented
+fun:__nis_finddirectory=uninstrumented
+fun:__nis_hash=uninstrumented
+fun:__nisbind_connect=uninstrumented
+fun:__nisbind_create=uninstrumented
+fun:__nisbind_destroy=uninstrumented
+fun:__nisbind_next=uninstrumented
+fun:__nl_langinfo_l=uninstrumented
+fun:__ns_get16=uninstrumented
+fun:__ns_get32=uninstrumented
+fun:__ns_name_ntop=uninstrumented
+fun:__ns_name_unpack=uninstrumented
+fun:__nss_configure_lookup=uninstrumented
+fun:__nss_database_lookup=uninstrumented
+fun:__nss_disable_nscd=uninstrumented
+fun:__nss_group_lookup=uninstrumented
+fun:__nss_group_lookup2=uninstrumented
+fun:__nss_hostname_digits_dots=uninstrumented
+fun:__nss_hosts_lookup=uninstrumented
+fun:__nss_hosts_lookup2=uninstrumented
+fun:__nss_lookup=uninstrumented
+fun:__nss_lookup_function=uninstrumented
+fun:__nss_next=uninstrumented
+fun:__nss_next2=uninstrumented
+fun:__nss_passwd_lookup=uninstrumented
+fun:__nss_passwd_lookup2=uninstrumented
+fun:__nss_services_lookup2=uninstrumented
+fun:__obstack_printf_chk=uninstrumented
+fun:__obstack_vprintf_chk=uninstrumented
+fun:__open=uninstrumented
+fun:__open64=uninstrumented
+fun:__open64_2=uninstrumented
+fun:__open_2=uninstrumented
+fun:__open_catalog=uninstrumented
+fun:__openat64_2=uninstrumented
+fun:__openat_2=uninstrumented
+fun:__overflow=uninstrumented
+fun:__p_cdname=uninstrumented
+fun:__p_cdnname=uninstrumented
+fun:__p_class=uninstrumented
+fun:__p_fqname=uninstrumented
+fun:__p_fqnname=uninstrumented
+fun:__p_option=uninstrumented
+fun:__p_query=uninstrumented
+fun:__p_rcode=uninstrumented
+fun:__p_secstodate=uninstrumented
+fun:__p_time=uninstrumented
+fun:__p_type=uninstrumented
+fun:__paritydi2=uninstrumented
+fun:__parityti2=uninstrumented
+fun:__pipe=uninstrumented
+fun:__poll=uninstrumented
+fun:__poll_chk=uninstrumented
+fun:__popcountdi2=uninstrumented
+fun:__popcountti2=uninstrumented
+fun:__posix_getopt=uninstrumented
+fun:__pow_finite=uninstrumented
+fun:__powf_finite=uninstrumented
+fun:__powidf2=uninstrumented
+fun:__powisf2=uninstrumented
+fun:__powitf2=uninstrumented
+fun:__powixf2=uninstrumented
+fun:__powl_finite=uninstrumented
+fun:__ppoll_chk=uninstrumented
+fun:__pread64=uninstrumented
+fun:__pread64_chk=uninstrumented
+fun:__pread_chk=uninstrumented
+fun:__prepare_niscall=uninstrumented
+fun:__printf_chk=uninstrumented
+fun:__printf_fp=uninstrumented
+fun:__profile_frequency=uninstrumented
+fun:__pthread_atfork=uninstrumented
+fun:__pthread_cleanup_routine=uninstrumented
+fun:__pthread_clock_gettime=uninstrumented
+fun:__pthread_clock_settime=uninstrumented
+fun:__pthread_get_minstack=uninstrumented
+fun:__pthread_getspecific=uninstrumented
+fun:__pthread_initialize_minimal=uninstrumented
+fun:__pthread_key_create=uninstrumented
+fun:__pthread_mutex_destroy=uninstrumented
+fun:__pthread_mutex_init=uninstrumented
+fun:__pthread_mutex_lock=uninstrumented
+fun:__pthread_mutex_trylock=uninstrumented
+fun:__pthread_mutex_unlock=uninstrumented
+fun:__pthread_mutexattr_destroy=uninstrumented
+fun:__pthread_mutexattr_init=uninstrumented
+fun:__pthread_mutexattr_settype=uninstrumented
+fun:__pthread_once=uninstrumented
+fun:__pthread_register_cancel=uninstrumented
+fun:__pthread_register_cancel_defer=uninstrumented
+fun:__pthread_rwlock_destroy=uninstrumented
+fun:__pthread_rwlock_init=uninstrumented
+fun:__pthread_rwlock_rdlock=uninstrumented
+fun:__pthread_rwlock_tryrdlock=uninstrumented
+fun:__pthread_rwlock_trywrlock=uninstrumented
+fun:__pthread_rwlock_unlock=uninstrumented
+fun:__pthread_rwlock_wrlock=uninstrumented
+fun:__pthread_setspecific=uninstrumented
+fun:__pthread_unregister_cancel=uninstrumented
+fun:__pthread_unregister_cancel_restore=uninstrumented
+fun:__pthread_unwind=uninstrumented
+fun:__pthread_unwind_next=uninstrumented
+fun:__ptsname_r_chk=uninstrumented
+fun:__putlong=uninstrumented
+fun:__putshort=uninstrumented
+fun:__pwrite64=uninstrumented
+fun:__rawmemchr=uninstrumented
+fun:__read=uninstrumented
+fun:__read_chk=uninstrumented
+fun:__readlink_chk=uninstrumented
+fun:__readlinkat_chk=uninstrumented
+fun:__realpath_chk=uninstrumented
+fun:__recv_chk=uninstrumented
+fun:__recvfrom_chk=uninstrumented
+fun:__register_atfork=uninstrumented
+fun:__register_frame=uninstrumented
+fun:__register_frame_info=uninstrumented
+fun:__register_frame_info_bases=uninstrumented
+fun:__register_frame_info_table=uninstrumented
+fun:__register_frame_info_table_bases=uninstrumented
+fun:__register_frame_table=uninstrumented
+fun:__remainder_finite=uninstrumented
+fun:__remainderf_finite=uninstrumented
+fun:__remainderl_finite=uninstrumented
+fun:__res_close=uninstrumented
+fun:__res_dnok=uninstrumented
+fun:__res_hnok=uninstrumented
+fun:__res_hostalias=uninstrumented
+fun:__res_iclose=uninstrumented
+fun:__res_init=uninstrumented
+fun:__res_isourserver=uninstrumented
+fun:__res_mailok=uninstrumented
+fun:__res_maybe_init=uninstrumented
+fun:__res_mkquery=uninstrumented
+fun:__res_nameinquery=uninstrumented
+fun:__res_nclose=uninstrumented
+fun:__res_ninit=uninstrumented
+fun:__res_nmkquery=uninstrumented
+fun:__res_nquery=uninstrumented
+fun:__res_nquerydomain=uninstrumented
+fun:__res_nsearch=uninstrumented
+fun:__res_nsend=uninstrumented
+fun:__res_ownok=uninstrumented
+fun:__res_queriesmatch=uninstrumented
+fun:__res_query=uninstrumented
+fun:__res_querydomain=uninstrumented
+fun:__res_randomid=uninstrumented
+fun:__res_search=uninstrumented
+fun:__res_send=uninstrumented
+fun:__res_state=uninstrumented
+fun:__rpc_thread_createerr=uninstrumented
+fun:__rpc_thread_svc_fdset=uninstrumented
+fun:__rpc_thread_svc_max_pollfd=uninstrumented
+fun:__rpc_thread_svc_pollfd=uninstrumented
+fun:__sbrk=uninstrumented
+fun:__scalb_finite=uninstrumented
+fun:__scalbf_finite=uninstrumented
+fun:__scalbl_finite=uninstrumented
+fun:__sched_cpualloc=uninstrumented
+fun:__sched_cpucount=uninstrumented
+fun:__sched_cpufree=uninstrumented
+fun:__sched_get_priority_max=uninstrumented
+fun:__sched_get_priority_min=uninstrumented
+fun:__sched_getparam=uninstrumented
+fun:__sched_getscheduler=uninstrumented
+fun:__sched_setscheduler=uninstrumented
+fun:__sched_yield=uninstrumented
+fun:__secure_getenv=uninstrumented
+fun:__select=uninstrumented
+fun:__send=uninstrumented
+fun:__sendmmsg=uninstrumented
+fun:__setmntent=uninstrumented
+fun:__setpgid=uninstrumented
+fun:__sfp_handle_exceptions=uninstrumented
+fun:__sigaction=uninstrumented
+fun:__sigaddset=uninstrumented
+fun:__sigdelset=uninstrumented
+fun:__sigismember=uninstrumented
+fun:__signbit=uninstrumented
+fun:__signbitf=uninstrumented
+fun:__signbitl=uninstrumented
+fun:__sigpause=uninstrumented
+fun:__sigsetjmp=uninstrumented
+fun:__sigsuspend=uninstrumented
+fun:__sinh_finite=uninstrumented
+fun:__sinhf_finite=uninstrumented
+fun:__sinhl_finite=uninstrumented
+fun:__snprintf_chk=uninstrumented
+fun:__splitstack_block_signals=uninstrumented
+fun:__splitstack_block_signals_context=uninstrumented
+fun:__splitstack_find=uninstrumented
+fun:__splitstack_find_context=uninstrumented
+fun:__splitstack_getcontext=uninstrumented
+fun:__splitstack_makecontext=uninstrumented
+fun:__splitstack_releasecontext=uninstrumented
+fun:__splitstack_resetcontext=uninstrumented
+fun:__splitstack_setcontext=uninstrumented
+fun:__sprintf_chk=uninstrumented
+fun:__sqrt_finite=uninstrumented
+fun:__sqrtf_finite=uninstrumented
+fun:__sqrtl_finite=uninstrumented
+fun:__stack_chk_fail=uninstrumented
+fun:__stack_chk_fail_local=uninstrumented
+fun:__stack_split_initialize=uninstrumented
+fun:__stat=uninstrumented
+fun:__statfs=uninstrumented
+fun:__stpcpy=uninstrumented
+fun:__stpcpy_chk=uninstrumented
+fun:__stpcpy_small=uninstrumented
+fun:__stpncpy=uninstrumented
+fun:__stpncpy_chk=uninstrumented
+fun:__strcasecmp=uninstrumented
+fun:__strcasecmp_l=uninstrumented
+fun:__strcasestr=uninstrumented
+fun:__strcat_chk=uninstrumented
+fun:__strcoll_l=uninstrumented
+fun:__strcpy_chk=uninstrumented
+fun:__strcpy_small=uninstrumented
+fun:__strcspn_c1=uninstrumented
+fun:__strcspn_c2=uninstrumented
+fun:__strcspn_c3=uninstrumented
+fun:__strdup=uninstrumented
+fun:__strerror_r=uninstrumented
+fun:__strfmon_l=uninstrumented
+fun:__strftime_l=uninstrumented
+fun:__strncasecmp_l=uninstrumented
+fun:__strncat_chk=uninstrumented
+fun:__strncpy_chk=uninstrumented
+fun:__strndup=uninstrumented
+fun:__strpbrk_c2=uninstrumented
+fun:__strpbrk_c3=uninstrumented
+fun:__strsep_1c=uninstrumented
+fun:__strsep_2c=uninstrumented
+fun:__strsep_3c=uninstrumented
+fun:__strsep_g=uninstrumented
+fun:__strspn_c1=uninstrumented
+fun:__strspn_c2=uninstrumented
+fun:__strspn_c3=uninstrumented
+fun:__strtod_internal=uninstrumented
+fun:__strtod_l=uninstrumented
+fun:__strtof_internal=uninstrumented
+fun:__strtof_l=uninstrumented
+fun:__strtok_r=uninstrumented
+fun:__strtok_r_1c=uninstrumented
+fun:__strtol_internal=uninstrumented
+fun:__strtol_l=uninstrumented
+fun:__strtold_internal=uninstrumented
+fun:__strtold_l=uninstrumented
+fun:__strtoll_internal=uninstrumented
+fun:__strtoll_l=uninstrumented
+fun:__strtoul_internal=uninstrumented
+fun:__strtoul_l=uninstrumented
+fun:__strtoull_internal=uninstrumented
+fun:__strtoull_l=uninstrumented
+fun:__strverscmp=uninstrumented
+fun:__strxfrm_l=uninstrumented
+fun:__subtf3=uninstrumented
+fun:__subvdi3=uninstrumented
+fun:__subvsi3=uninstrumented
+fun:__subvti3=uninstrumented
+fun:__swprintf_chk=uninstrumented
+fun:__sym_ntop=uninstrumented
+fun:__sym_ntos=uninstrumented
+fun:__sym_ston=uninstrumented
+fun:__sysconf=uninstrumented
+fun:__sysctl=uninstrumented
+fun:__syslog_chk=uninstrumented
+fun:__sysv_signal=uninstrumented
+fun:__tls_get_addr=uninstrumented
+fun:__toascii_l=uninstrumented
+fun:__tolower_l=uninstrumented
+fun:__toupper_l=uninstrumented
+fun:__towctrans=uninstrumented
+fun:__towctrans_l=uninstrumented
+fun:__towlower_l=uninstrumented
+fun:__towupper_l=uninstrumented
+fun:__trunctfdf2=uninstrumented
+fun:__trunctfsf2=uninstrumented
+fun:__trunctfxf2=uninstrumented
+fun:__ttyname_r_chk=uninstrumented
+fun:__ucmpti2=uninstrumented
+fun:__udiv_w_sdiv=uninstrumented
+fun:__udivmodti4=uninstrumented
+fun:__udivti3=uninstrumented
+fun:__uflow=uninstrumented
+fun:__umodti3=uninstrumented
+fun:__underflow=uninstrumented
+fun:__unordtf2=uninstrumented
+fun:__uselocale=uninstrumented
+fun:__vasprintf_chk=uninstrumented
+fun:__vdprintf_chk=uninstrumented
+fun:__vfork=uninstrumented
+fun:__vfprintf_chk=uninstrumented
+fun:__vfscanf=uninstrumented
+fun:__vfwprintf_chk=uninstrumented
+fun:__vprintf_chk=uninstrumented
+fun:__vsnprintf=uninstrumented
+fun:__vsnprintf_chk=uninstrumented
+fun:__vsprintf_chk=uninstrumented
+fun:__vsscanf=uninstrumented
+fun:__vswprintf_chk=uninstrumented
+fun:__vsyslog_chk=uninstrumented
+fun:__vwprintf_chk=uninstrumented
+fun:__wait=uninstrumented
+fun:__waitpid=uninstrumented
+fun:__warn_memset_zero_len=uninstrumented
+fun:__wcpcpy_chk=uninstrumented
+fun:__wcpncpy_chk=uninstrumented
+fun:__wcrtomb_chk=uninstrumented
+fun:__wcscasecmp_l=uninstrumented
+fun:__wcscat_chk=uninstrumented
+fun:__wcscoll_l=uninstrumented
+fun:__wcscpy_chk=uninstrumented
+fun:__wcsftime_l=uninstrumented
+fun:__wcsncasecmp_l=uninstrumented
+fun:__wcsncat_chk=uninstrumented
+fun:__wcsncpy_chk=uninstrumented
+fun:__wcsnrtombs_chk=uninstrumented
+fun:__wcsrtombs_chk=uninstrumented
+fun:__wcstod_internal=uninstrumented
+fun:__wcstod_l=uninstrumented
+fun:__wcstof_internal=uninstrumented
+fun:__wcstof_l=uninstrumented
+fun:__wcstol_internal=uninstrumented
+fun:__wcstol_l=uninstrumented
+fun:__wcstold_internal=uninstrumented
+fun:__wcstold_l=uninstrumented
+fun:__wcstoll_internal=uninstrumented
+fun:__wcstoll_l=uninstrumented
+fun:__wcstombs_chk=uninstrumented
+fun:__wcstoul_internal=uninstrumented
+fun:__wcstoul_l=uninstrumented
+fun:__wcstoull_internal=uninstrumented
+fun:__wcstoull_l=uninstrumented
+fun:__wcsxfrm_l=uninstrumented
+fun:__wctomb_chk=uninstrumented
+fun:__wctrans_l=uninstrumented
+fun:__wctype_l=uninstrumented
+fun:__wmemcpy_chk=uninstrumented
+fun:__wmemmove_chk=uninstrumented
+fun:__wmempcpy_chk=uninstrumented
+fun:__wmemset_chk=uninstrumented
+fun:__woverflow=uninstrumented
+fun:__wprintf_chk=uninstrumented
+fun:__wrap_pthread_create=uninstrumented
+fun:__write=uninstrumented
+fun:__wuflow=uninstrumented
+fun:__wunderflow=uninstrumented
+fun:__xmknod=uninstrumented
+fun:__xmknodat=uninstrumented
+fun:__xpg_basename=uninstrumented
+fun:__xpg_sigpause=uninstrumented
+fun:__xpg_strerror_r=uninstrumented
+fun:__xstat=uninstrumented
+fun:__xstat64=uninstrumented
+fun:__y0_finite=uninstrumented
+fun:__y0f_finite=uninstrumented
+fun:__y0l_finite=uninstrumented
+fun:__y1_finite=uninstrumented
+fun:__y1f_finite=uninstrumented
+fun:__y1l_finite=uninstrumented
+fun:__yn_finite=uninstrumented
+fun:__ynf_finite=uninstrumented
+fun:__ynl_finite=uninstrumented
+fun:__yp_check=uninstrumented
+fun:_authenticate=uninstrumented
+fun:_dl_addr=uninstrumented
+fun:_dl_allocate_tls=uninstrumented
+fun:_dl_allocate_tls_init=uninstrumented
+fun:_dl_deallocate_tls=uninstrumented
+fun:_dl_debug_state=uninstrumented
+fun:_dl_find_dso_for_object=uninstrumented
+fun:_dl_get_tls_static_info=uninstrumented
+fun:_dl_make_stack_executable=uninstrumented
+fun:_dl_mcount=uninstrumented
+fun:_dl_mcount_wrapper=uninstrumented
+fun:_dl_mcount_wrapper_check=uninstrumented
+fun:_dl_rtld_di_serinfo=uninstrumented
+fun:_dl_sym=uninstrumented
+fun:_dl_tls_setup=uninstrumented
+fun:_dl_vsym=uninstrumented
+fun:_exit=uninstrumented
+fun:_flushlbf=uninstrumented
+fun:_gethtbyaddr=uninstrumented
+fun:_gethtbyname=uninstrumented
+fun:_gethtbyname2=uninstrumented
+fun:_gethtent=uninstrumented
+fun:_getlong=uninstrumented
+fun:_getshort=uninstrumented
+fun:_longjmp=uninstrumented
+fun:_mcleanup=uninstrumented
+fun:_mcount=uninstrumented
+fun:_nsl_default_nss=uninstrumented
+fun:_nss_files_parse_grent=uninstrumented
+fun:_nss_files_parse_pwent=uninstrumented
+fun:_nss_files_parse_sgent=uninstrumented
+fun:_nss_files_parse_spent=uninstrumented
+fun:_obstack_allocated_p=uninstrumented
+fun:_obstack_begin=uninstrumented
+fun:_obstack_begin_1=uninstrumented
+fun:_obstack_free=uninstrumented
+fun:_obstack_memory_used=uninstrumented
+fun:_obstack_newchunk=uninstrumented
+fun:_pthread_cleanup_pop=uninstrumented
+fun:_pthread_cleanup_pop_restore=uninstrumented
+fun:_pthread_cleanup_push=uninstrumented
+fun:_pthread_cleanup_push_defer=uninstrumented
+fun:_rpc_dtablesize=uninstrumented
+fun:_seterr_reply=uninstrumented
+fun:_sethtent=uninstrumented
+fun:_setjmp=uninstrumented
+fun:_tolower=uninstrumented
+fun:_toupper=uninstrumented
+fun:_xdr_ib_request=uninstrumented
+fun:_xdr_nis_result=uninstrumented
+fun:a64l=uninstrumented
+fun:abort=uninstrumented
+fun:abs=uninstrumented
+fun:accept=uninstrumented
+fun:accept4=uninstrumented
+fun:access=uninstrumented
+fun:acct=uninstrumented
+fun:acos=uninstrumented
+fun:acosf=uninstrumented
+fun:acosh=uninstrumented
+fun:acoshf=uninstrumented
+fun:acoshl=uninstrumented
+fun:acosl=uninstrumented
+fun:addmntent=uninstrumented
+fun:addseverity=uninstrumented
+fun:adjtime=uninstrumented
+fun:adjtimex=uninstrumented
+fun:advance=uninstrumented
+fun:aio_cancel=uninstrumented
+fun:aio_cancel64=uninstrumented
+fun:aio_error=uninstrumented
+fun:aio_error64=uninstrumented
+fun:aio_fsync=uninstrumented
+fun:aio_fsync64=uninstrumented
+fun:aio_init=uninstrumented
+fun:aio_read=uninstrumented
+fun:aio_read64=uninstrumented
+fun:aio_return=uninstrumented
+fun:aio_return64=uninstrumented
+fun:aio_suspend=uninstrumented
+fun:aio_suspend64=uninstrumented
+fun:aio_write=uninstrumented
+fun:aio_write64=uninstrumented
+fun:alarm=uninstrumented
+fun:aligned_alloc=uninstrumented
+fun:alphasort=uninstrumented
+fun:alphasort64=uninstrumented
+fun:arch_prctl=uninstrumented
+fun:argp_error=uninstrumented
+fun:argp_failure=uninstrumented
+fun:argp_help=uninstrumented
+fun:argp_parse=uninstrumented
+fun:argp_state_help=uninstrumented
+fun:argp_usage=uninstrumented
+fun:argz_add=uninstrumented
+fun:argz_add_sep=uninstrumented
+fun:argz_append=uninstrumented
+fun:argz_count=uninstrumented
+fun:argz_create=uninstrumented
+fun:argz_create_sep=uninstrumented
+fun:argz_delete=uninstrumented
+fun:argz_extract=uninstrumented
+fun:argz_insert=uninstrumented
+fun:argz_next=uninstrumented
+fun:argz_replace=uninstrumented
+fun:argz_stringify=uninstrumented
+fun:asctime=uninstrumented
+fun:asctime_r=uninstrumented
+fun:asin=uninstrumented
+fun:asinf=uninstrumented
+fun:asinh=uninstrumented
+fun:asinhf=uninstrumented
+fun:asinhl=uninstrumented
+fun:asinl=uninstrumented
+fun:asprintf=uninstrumented
+fun:at_quick_exit=uninstrumented
+fun:atan=uninstrumented
+fun:atan2=uninstrumented
+fun:atan2f=uninstrumented
+fun:atan2l=uninstrumented
+fun:atanf=uninstrumented
+fun:atanh=uninstrumented
+fun:atanhf=uninstrumented
+fun:atanhl=uninstrumented
+fun:atanl=uninstrumented
+fun:atexit=uninstrumented
+fun:atof=uninstrumented
+fun:atoi=uninstrumented
+fun:atol=uninstrumented
+fun:atoll=uninstrumented
+fun:authdes_create=uninstrumented
+fun:authdes_getucred=uninstrumented
+fun:authdes_pk_create=uninstrumented
+fun:authnone_create=uninstrumented
+fun:authunix_create=uninstrumented
+fun:authunix_create_default=uninstrumented
+fun:backtrace=uninstrumented
+fun:backtrace_symbols=uninstrumented
+fun:backtrace_symbols_fd=uninstrumented
+fun:basename=uninstrumented
+fun:bcmp=uninstrumented
+fun:bcopy=uninstrumented
+fun:bdflush=uninstrumented
+fun:bind=uninstrumented
+fun:bind_textdomain_codeset=uninstrumented
+fun:bindresvport=uninstrumented
+fun:bindtextdomain=uninstrumented
+fun:brk=uninstrumented
+fun:bsd_signal=uninstrumented
+fun:bsearch=uninstrumented
+fun:btowc=uninstrumented
+fun:bzero=uninstrumented
+fun:c16rtomb=uninstrumented
+fun:c32rtomb=uninstrumented
+fun:cabs=uninstrumented
+fun:cabsf=uninstrumented
+fun:cabsl=uninstrumented
+fun:cacos=uninstrumented
+fun:cacosf=uninstrumented
+fun:cacosh=uninstrumented
+fun:cacoshf=uninstrumented
+fun:cacoshl=uninstrumented
+fun:cacosl=uninstrumented
+fun:calloc=uninstrumented
+fun:callrpc=uninstrumented
+fun:canonicalize_file_name=uninstrumented
+fun:capget=uninstrumented
+fun:capset=uninstrumented
+fun:carg=uninstrumented
+fun:cargf=uninstrumented
+fun:cargl=uninstrumented
+fun:casin=uninstrumented
+fun:casinf=uninstrumented
+fun:casinh=uninstrumented
+fun:casinhf=uninstrumented
+fun:casinhl=uninstrumented
+fun:casinl=uninstrumented
+fun:catan=uninstrumented
+fun:catanf=uninstrumented
+fun:catanh=uninstrumented
+fun:catanhf=uninstrumented
+fun:catanhl=uninstrumented
+fun:catanl=uninstrumented
+fun:catclose=uninstrumented
+fun:catgets=uninstrumented
+fun:catopen=uninstrumented
+fun:cbc_crypt=uninstrumented
+fun:cbrt=uninstrumented
+fun:cbrtf=uninstrumented
+fun:cbrtl=uninstrumented
+fun:ccos=uninstrumented
+fun:ccosf=uninstrumented
+fun:ccosh=uninstrumented
+fun:ccoshf=uninstrumented
+fun:ccoshl=uninstrumented
+fun:ccosl=uninstrumented
+fun:ceil=uninstrumented
+fun:ceilf=uninstrumented
+fun:ceill=uninstrumented
+fun:cexp=uninstrumented
+fun:cexpf=uninstrumented
+fun:cexpl=uninstrumented
+fun:cfgetispeed=uninstrumented
+fun:cfgetospeed=uninstrumented
+fun:cfmakeraw=uninstrumented
+fun:cfree=uninstrumented
+fun:cfsetispeed=uninstrumented
+fun:cfsetospeed=uninstrumented
+fun:cfsetspeed=uninstrumented
+fun:chdir=uninstrumented
+fun:chflags=uninstrumented
+fun:chmod=uninstrumented
+fun:chown=uninstrumented
+fun:chroot=uninstrumented
+fun:cimag=uninstrumented
+fun:cimagf=uninstrumented
+fun:cimagl=uninstrumented
+fun:clearenv=uninstrumented
+fun:clearerr=uninstrumented
+fun:clearerr_unlocked=uninstrumented
+fun:clnt_broadcast=uninstrumented
+fun:clnt_create=uninstrumented
+fun:clnt_pcreateerror=uninstrumented
+fun:clnt_perrno=uninstrumented
+fun:clnt_perror=uninstrumented
+fun:clnt_spcreateerror=uninstrumented
+fun:clnt_sperrno=uninstrumented
+fun:clnt_sperror=uninstrumented
+fun:clntraw_create=uninstrumented
+fun:clnttcp_create=uninstrumented
+fun:clntudp_bufcreate=uninstrumented
+fun:clntudp_create=uninstrumented
+fun:clntunix_create=uninstrumented
+fun:clock=uninstrumented
+fun:clock_adjtime=uninstrumented
+fun:clock_getcpuclockid=uninstrumented
+fun:clock_getres=uninstrumented
+fun:clock_gettime=uninstrumented
+fun:clock_nanosleep=uninstrumented
+fun:clock_settime=uninstrumented
+fun:clog=uninstrumented
+fun:clog10=uninstrumented
+fun:clog10f=uninstrumented
+fun:clog10l=uninstrumented
+fun:clogf=uninstrumented
+fun:clogl=uninstrumented
+fun:clone=uninstrumented
+fun:close=uninstrumented
+fun:closedir=uninstrumented
+fun:closelog=uninstrumented
+fun:confstr=uninstrumented
+fun:conj=uninstrumented
+fun:conjf=uninstrumented
+fun:conjl=uninstrumented
+fun:connect=uninstrumented
+fun:copysign=uninstrumented
+fun:copysignf=uninstrumented
+fun:copysignl=uninstrumented
+fun:cos=uninstrumented
+fun:cosf=uninstrumented
+fun:cosh=uninstrumented
+fun:coshf=uninstrumented
+fun:coshl=uninstrumented
+fun:cosl=uninstrumented
+fun:cpow=uninstrumented
+fun:cpowf=uninstrumented
+fun:cpowl=uninstrumented
+fun:cproj=uninstrumented
+fun:cprojf=uninstrumented
+fun:cprojl=uninstrumented
+fun:creal=uninstrumented
+fun:crealf=uninstrumented
+fun:creall=uninstrumented
+fun:creat=uninstrumented
+fun:creat64=uninstrumented
+fun:create_module=uninstrumented
+fun:crypt=uninstrumented
+fun:crypt_r=uninstrumented
+fun:csin=uninstrumented
+fun:csinf=uninstrumented
+fun:csinh=uninstrumented
+fun:csinhf=uninstrumented
+fun:csinhl=uninstrumented
+fun:csinl=uninstrumented
+fun:csqrt=uninstrumented
+fun:csqrtf=uninstrumented
+fun:csqrtl=uninstrumented
+fun:ctan=uninstrumented
+fun:ctanf=uninstrumented
+fun:ctanh=uninstrumented
+fun:ctanhf=uninstrumented
+fun:ctanhl=uninstrumented
+fun:ctanl=uninstrumented
+fun:ctermid=uninstrumented
+fun:ctime=uninstrumented
+fun:ctime_r=uninstrumented
+fun:cuserid=uninstrumented
+fun:daemon=uninstrumented
+fun:dcgettext=uninstrumented
+fun:dcngettext=uninstrumented
+fun:delete_module=uninstrumented
+fun:des_setparity=uninstrumented
+fun:dgettext=uninstrumented
+fun:difftime=uninstrumented
+fun:dirfd=uninstrumented
+fun:dirname=uninstrumented
+fun:div=uninstrumented
+fun:dl_iterate_phdr=uninstrumented
+fun:dladdr=uninstrumented
+fun:dladdr1=uninstrumented
+fun:dlclose=uninstrumented
+fun:dlerror=uninstrumented
+fun:dlinfo=uninstrumented
+fun:dlmopen=uninstrumented
+fun:dlopen=uninstrumented
+fun:dlsym=uninstrumented
+fun:dlvsym=uninstrumented
+fun:dngettext=uninstrumented
+fun:dprintf=uninstrumented
+fun:drand48=uninstrumented
+fun:drand48_r=uninstrumented
+fun:drem=uninstrumented
+fun:dremf=uninstrumented
+fun:dreml=uninstrumented
+fun:dup=uninstrumented
+fun:dup2=uninstrumented
+fun:dup3=uninstrumented
+fun:duplocale=uninstrumented
+fun:dysize=uninstrumented
+fun:eaccess=uninstrumented
+fun:ecb_crypt=uninstrumented
+fun:ecvt=uninstrumented
+fun:ecvt_r=uninstrumented
+fun:encrypt=uninstrumented
+fun:encrypt_r=uninstrumented
+fun:endaliasent=uninstrumented
+fun:endfsent=uninstrumented
+fun:endgrent=uninstrumented
+fun:endhostent=uninstrumented
+fun:endmntent=uninstrumented
+fun:endnetent=uninstrumented
+fun:endnetgrent=uninstrumented
+fun:endprotoent=uninstrumented
+fun:endpwent=uninstrumented
+fun:endrpcent=uninstrumented
+fun:endservent=uninstrumented
+fun:endsgent=uninstrumented
+fun:endspent=uninstrumented
+fun:endttyent=uninstrumented
+fun:endusershell=uninstrumented
+fun:endutent=uninstrumented
+fun:endutxent=uninstrumented
+fun:envz_add=uninstrumented
+fun:envz_entry=uninstrumented
+fun:envz_get=uninstrumented
+fun:envz_merge=uninstrumented
+fun:envz_remove=uninstrumented
+fun:envz_strip=uninstrumented
+fun:epoll_create=uninstrumented
+fun:epoll_create1=uninstrumented
+fun:epoll_ctl=uninstrumented
+fun:epoll_pwait=uninstrumented
+fun:epoll_wait=uninstrumented
+fun:erand48=uninstrumented
+fun:erand48_r=uninstrumented
+fun:erf=uninstrumented
+fun:erfc=uninstrumented
+fun:erfcf=uninstrumented
+fun:erfcl=uninstrumented
+fun:erff=uninstrumented
+fun:erfl=uninstrumented
+fun:err=uninstrumented
+fun:error=uninstrumented
+fun:error_at_line=uninstrumented
+fun:errx=uninstrumented
+fun:ether_aton=uninstrumented
+fun:ether_aton_r=uninstrumented
+fun:ether_hostton=uninstrumented
+fun:ether_line=uninstrumented
+fun:ether_ntoa=uninstrumented
+fun:ether_ntoa_r=uninstrumented
+fun:ether_ntohost=uninstrumented
+fun:euidaccess=uninstrumented
+fun:eventfd=uninstrumented
+fun:eventfd_read=uninstrumented
+fun:eventfd_write=uninstrumented
+fun:execl=uninstrumented
+fun:execle=uninstrumented
+fun:execlp=uninstrumented
+fun:execv=uninstrumented
+fun:execve=uninstrumented
+fun:execvp=uninstrumented
+fun:execvpe=uninstrumented
+fun:exit=uninstrumented
+fun:exp=uninstrumented
+fun:exp10=uninstrumented
+fun:exp10f=uninstrumented
+fun:exp10l=uninstrumented
+fun:exp2=uninstrumented
+fun:exp2f=uninstrumented
+fun:exp2l=uninstrumented
+fun:expf=uninstrumented
+fun:expl=uninstrumented
+fun:expm1=uninstrumented
+fun:expm1f=uninstrumented
+fun:expm1l=uninstrumented
+fun:fabs=uninstrumented
+fun:fabsf=uninstrumented
+fun:fabsl=uninstrumented
+fun:faccessat=uninstrumented
+fun:fallocate=uninstrumented
+fun:fallocate64=uninstrumented
+fun:fanotify_init=uninstrumented
+fun:fanotify_mark=uninstrumented
+fun:fattach=uninstrumented
+fun:fchdir=uninstrumented
+fun:fchflags=uninstrumented
+fun:fchmod=uninstrumented
+fun:fchmodat=uninstrumented
+fun:fchown=uninstrumented
+fun:fchownat=uninstrumented
+fun:fclose=uninstrumented
+fun:fcloseall=uninstrumented
+fun:fcntl=uninstrumented
+fun:fcrypt=uninstrumented
+fun:fcvt=uninstrumented
+fun:fcvt_r=uninstrumented
+fun:fdatasync=uninstrumented
+fun:fdetach=uninstrumented
+fun:fdim=uninstrumented
+fun:fdimf=uninstrumented
+fun:fdiml=uninstrumented
+fun:fdopen=uninstrumented
+fun:fdopendir=uninstrumented
+fun:feclearexcept=uninstrumented
+fun:fedisableexcept=uninstrumented
+fun:feenableexcept=uninstrumented
+fun:fegetenv=uninstrumented
+fun:fegetexcept=uninstrumented
+fun:fegetexceptflag=uninstrumented
+fun:fegetround=uninstrumented
+fun:feholdexcept=uninstrumented
+fun:feof=uninstrumented
+fun:feof_unlocked=uninstrumented
+fun:feraiseexcept=uninstrumented
+fun:ferror=uninstrumented
+fun:ferror_unlocked=uninstrumented
+fun:fesetenv=uninstrumented
+fun:fesetexceptflag=uninstrumented
+fun:fesetround=uninstrumented
+fun:fetestexcept=uninstrumented
+fun:feupdateenv=uninstrumented
+fun:fexecve=uninstrumented
+fun:fflush=uninstrumented
+fun:fflush_unlocked=uninstrumented
+fun:ffs=uninstrumented
+fun:ffsl=uninstrumented
+fun:ffsll=uninstrumented
+fun:fgetc=uninstrumented
+fun:fgetc_unlocked=uninstrumented
+fun:fgetgrent=uninstrumented
+fun:fgetgrent_r=uninstrumented
+fun:fgetpos=uninstrumented
+fun:fgetpos64=uninstrumented
+fun:fgetpwent=uninstrumented
+fun:fgetpwent_r=uninstrumented
+fun:fgets=uninstrumented
+fun:fgets_unlocked=uninstrumented
+fun:fgetsgent=uninstrumented
+fun:fgetsgent_r=uninstrumented
+fun:fgetspent=uninstrumented
+fun:fgetspent_r=uninstrumented
+fun:fgetwc=uninstrumented
+fun:fgetwc_unlocked=uninstrumented
+fun:fgetws=uninstrumented
+fun:fgetws_unlocked=uninstrumented
+fun:fgetxattr=uninstrumented
+fun:fileno=uninstrumented
+fun:fileno_unlocked=uninstrumented
+fun:finite=uninstrumented
+fun:finitef=uninstrumented
+fun:finitel=uninstrumented
+fun:flistxattr=uninstrumented
+fun:flock=uninstrumented
+fun:flockfile=uninstrumented
+fun:floor=uninstrumented
+fun:floorf=uninstrumented
+fun:floorl=uninstrumented
+fun:fma=uninstrumented
+fun:fmaf=uninstrumented
+fun:fmal=uninstrumented
+fun:fmax=uninstrumented
+fun:fmaxf=uninstrumented
+fun:fmaxl=uninstrumented
+fun:fmemopen=uninstrumented
+fun:fmin=uninstrumented
+fun:fminf=uninstrumented
+fun:fminl=uninstrumented
+fun:fmod=uninstrumented
+fun:fmodf=uninstrumented
+fun:fmodl=uninstrumented
+fun:fmtmsg=uninstrumented
+fun:fnmatch=uninstrumented
+fun:fopen=uninstrumented
+fun:fopen64=uninstrumented
+fun:fopencookie=uninstrumented
+fun:fork=uninstrumented
+fun:forkpty=uninstrumented
+fun:fpathconf=uninstrumented
+fun:fprintf=uninstrumented
+fun:fputc=uninstrumented
+fun:fputc_unlocked=uninstrumented
+fun:fputs=uninstrumented
+fun:fputs_unlocked=uninstrumented
+fun:fputwc=uninstrumented
+fun:fputwc_unlocked=uninstrumented
+fun:fputws=uninstrumented
+fun:fputws_unlocked=uninstrumented
+fun:fread=uninstrumented
+fun:fread_unlocked=uninstrumented
+fun:free=uninstrumented
+fun:freeaddrinfo=uninstrumented
+fun:freeifaddrs=uninstrumented
+fun:freelocale=uninstrumented
+fun:fremovexattr=uninstrumented
+fun:freopen=uninstrumented
+fun:freopen64=uninstrumented
+fun:frexp=uninstrumented
+fun:frexpf=uninstrumented
+fun:frexpl=uninstrumented
+fun:fscanf=uninstrumented
+fun:fseek=uninstrumented
+fun:fseeko=uninstrumented
+fun:fseeko64=uninstrumented
+fun:fsetpos=uninstrumented
+fun:fsetpos64=uninstrumented
+fun:fsetxattr=uninstrumented
+fun:fstat=uninstrumented
+fun:fstat64=uninstrumented
+fun:fstatat=uninstrumented
+fun:fstatat64=uninstrumented
+fun:fstatfs=uninstrumented
+fun:fstatfs64=uninstrumented
+fun:fstatvfs=uninstrumented
+fun:fstatvfs64=uninstrumented
+fun:fsync=uninstrumented
+fun:ftell=uninstrumented
+fun:ftello=uninstrumented
+fun:ftello64=uninstrumented
+fun:ftime=uninstrumented
+fun:ftok=uninstrumented
+fun:ftruncate=uninstrumented
+fun:ftruncate64=uninstrumented
+fun:ftrylockfile=uninstrumented
+fun:fts_children=uninstrumented
+fun:fts_close=uninstrumented
+fun:fts_open=uninstrumented
+fun:fts_read=uninstrumented
+fun:fts_set=uninstrumented
+fun:ftw=uninstrumented
+fun:ftw64=uninstrumented
+fun:funlockfile=uninstrumented
+fun:futimens=uninstrumented
+fun:futimes=uninstrumented
+fun:futimesat=uninstrumented
+fun:fwide=uninstrumented
+fun:fwprintf=uninstrumented
+fun:fwrite=uninstrumented
+fun:fwrite_unlocked=uninstrumented
+fun:fwscanf=uninstrumented
+fun:gai_cancel=uninstrumented
+fun:gai_error=uninstrumented
+fun:gai_strerror=uninstrumented
+fun:gai_suspend=uninstrumented
+fun:gamma=uninstrumented
+fun:gammaf=uninstrumented
+fun:gammal=uninstrumented
+fun:gcvt=uninstrumented
+fun:get_avphys_pages=uninstrumented
+fun:get_current_dir_name=uninstrumented
+fun:get_kernel_syms=uninstrumented
+fun:get_myaddress=uninstrumented
+fun:get_nprocs=uninstrumented
+fun:get_nprocs_conf=uninstrumented
+fun:get_phys_pages=uninstrumented
+fun:getaddrinfo=uninstrumented
+fun:getaddrinfo_a=uninstrumented
+fun:getaliasbyname=uninstrumented
+fun:getaliasbyname_r=uninstrumented
+fun:getaliasent=uninstrumented
+fun:getaliasent_r=uninstrumented
+fun:getauxval=uninstrumented
+fun:getc=uninstrumented
+fun:getc_unlocked=uninstrumented
+fun:getchar=uninstrumented
+fun:getchar_unlocked=uninstrumented
+fun:getcontext=uninstrumented
+fun:getcwd=uninstrumented
+fun:getdate=uninstrumented
+fun:getdate_r=uninstrumented
+fun:getdelim=uninstrumented
+fun:getdirentries=uninstrumented
+fun:getdirentries64=uninstrumented
+fun:getdomainname=uninstrumented
+fun:getdtablesize=uninstrumented
+fun:getegid=uninstrumented
+fun:getenv=uninstrumented
+fun:geteuid=uninstrumented
+fun:getfsent=uninstrumented
+fun:getfsfile=uninstrumented
+fun:getfsspec=uninstrumented
+fun:getgid=uninstrumented
+fun:getgrent=uninstrumented
+fun:getgrent_r=uninstrumented
+fun:getgrgid=uninstrumented
+fun:getgrgid_r=uninstrumented
+fun:getgrnam=uninstrumented
+fun:getgrnam_r=uninstrumented
+fun:getgrouplist=uninstrumented
+fun:getgroups=uninstrumented
+fun:gethostbyaddr=uninstrumented
+fun:gethostbyaddr_r=uninstrumented
+fun:gethostbyname=uninstrumented
+fun:gethostbyname2=uninstrumented
+fun:gethostbyname2_r=uninstrumented
+fun:gethostbyname_r=uninstrumented
+fun:gethostent=uninstrumented
+fun:gethostent_r=uninstrumented
+fun:gethostid=uninstrumented
+fun:gethostname=uninstrumented
+fun:getifaddrs=uninstrumented
+fun:getipv4sourcefilter=uninstrumented
+fun:getitimer=uninstrumented
+fun:getline=uninstrumented
+fun:getloadavg=uninstrumented
+fun:getlogin=uninstrumented
+fun:getlogin_r=uninstrumented
+fun:getmntent=uninstrumented
+fun:getmntent_r=uninstrumented
+fun:getmsg=uninstrumented
+fun:getnameinfo=uninstrumented
+fun:getnetbyaddr=uninstrumented
+fun:getnetbyaddr_r=uninstrumented
+fun:getnetbyname=uninstrumented
+fun:getnetbyname_r=uninstrumented
+fun:getnetent=uninstrumented
+fun:getnetent_r=uninstrumented
+fun:getnetgrent=uninstrumented
+fun:getnetgrent_r=uninstrumented
+fun:getnetname=uninstrumented
+fun:getopt=uninstrumented
+fun:getopt_long=uninstrumented
+fun:getopt_long_only=uninstrumented
+fun:getpagesize=uninstrumented
+fun:getpass=uninstrumented
+fun:getpeername=uninstrumented
+fun:getpgid=uninstrumented
+fun:getpgrp=uninstrumented
+fun:getpid=uninstrumented
+fun:getpmsg=uninstrumented
+fun:getppid=uninstrumented
+fun:getpriority=uninstrumented
+fun:getprotobyname=uninstrumented
+fun:getprotobyname_r=uninstrumented
+fun:getprotobynumber=uninstrumented
+fun:getprotobynumber_r=uninstrumented
+fun:getprotoent=uninstrumented
+fun:getprotoent_r=uninstrumented
+fun:getpt=uninstrumented
+fun:getpublickey=uninstrumented
+fun:getpw=uninstrumented
+fun:getpwent=uninstrumented
+fun:getpwent_r=uninstrumented
+fun:getpwnam=uninstrumented
+fun:getpwnam_r=uninstrumented
+fun:getpwuid=uninstrumented
+fun:getpwuid_r=uninstrumented
+fun:getresgid=uninstrumented
+fun:getresuid=uninstrumented
+fun:getrlimit=uninstrumented
+fun:getrlimit64=uninstrumented
+fun:getrpcbyname=uninstrumented
+fun:getrpcbyname_r=uninstrumented
+fun:getrpcbynumber=uninstrumented
+fun:getrpcbynumber_r=uninstrumented
+fun:getrpcent=uninstrumented
+fun:getrpcent_r=uninstrumented
+fun:getrpcport=uninstrumented
+fun:getrusage=uninstrumented
+fun:gets=uninstrumented
+fun:getsecretkey=uninstrumented
+fun:getservbyname=uninstrumented
+fun:getservbyname_r=uninstrumented
+fun:getservbyport=uninstrumented
+fun:getservbyport_r=uninstrumented
+fun:getservent=uninstrumented
+fun:getservent_r=uninstrumented
+fun:getsgent=uninstrumented
+fun:getsgent_r=uninstrumented
+fun:getsgnam=uninstrumented
+fun:getsgnam_r=uninstrumented
+fun:getsid=uninstrumented
+fun:getsockname=uninstrumented
+fun:getsockopt=uninstrumented
+fun:getsourcefilter=uninstrumented
+fun:getspent=uninstrumented
+fun:getspent_r=uninstrumented
+fun:getspnam=uninstrumented
+fun:getspnam_r=uninstrumented
+fun:getsubopt=uninstrumented
+fun:gettext=uninstrumented
+fun:gettimeofday=uninstrumented
+fun:getttyent=uninstrumented
+fun:getttynam=uninstrumented
+fun:getuid=uninstrumented
+fun:getusershell=uninstrumented
+fun:getutent=uninstrumented
+fun:getutent_r=uninstrumented
+fun:getutid=uninstrumented
+fun:getutid_r=uninstrumented
+fun:getutline=uninstrumented
+fun:getutline_r=uninstrumented
+fun:getutmp=uninstrumented
+fun:getutmpx=uninstrumented
+fun:getutxent=uninstrumented
+fun:getutxid=uninstrumented
+fun:getutxline=uninstrumented
+fun:getw=uninstrumented
+fun:getwc=uninstrumented
+fun:getwc_unlocked=uninstrumented
+fun:getwchar=uninstrumented
+fun:getwchar_unlocked=uninstrumented
+fun:getwd=uninstrumented
+fun:getxattr=uninstrumented
+fun:glob=uninstrumented
+fun:glob64=uninstrumented
+fun:glob_pattern_p=uninstrumented
+fun:globfree=uninstrumented
+fun:globfree64=uninstrumented
+fun:gmtime=uninstrumented
+fun:gmtime_r=uninstrumented
+fun:gnu_dev_major=uninstrumented
+fun:gnu_dev_makedev=uninstrumented
+fun:gnu_dev_minor=uninstrumented
+fun:gnu_get_libc_release=uninstrumented
+fun:gnu_get_libc_version=uninstrumented
+fun:grantpt=uninstrumented
+fun:group_member=uninstrumented
+fun:gsignal=uninstrumented
+fun:gtty=uninstrumented
+fun:hasmntopt=uninstrumented
+fun:hcreate=uninstrumented
+fun:hcreate_r=uninstrumented
+fun:hdestroy=uninstrumented
+fun:hdestroy_r=uninstrumented
+fun:herror=uninstrumented
+fun:host2netname=uninstrumented
+fun:hsearch=uninstrumented
+fun:hsearch_r=uninstrumented
+fun:hstrerror=uninstrumented
+fun:htonl=uninstrumented
+fun:htons=uninstrumented
+fun:hypot=uninstrumented
+fun:hypotf=uninstrumented
+fun:hypotl=uninstrumented
+fun:iconv=uninstrumented
+fun:iconv_close=uninstrumented
+fun:iconv_open=uninstrumented
+fun:idna_to_ascii_lz=uninstrumented
+fun:idna_to_unicode_lzlz=uninstrumented
+fun:if_freenameindex=uninstrumented
+fun:if_indextoname=uninstrumented
+fun:if_nameindex=uninstrumented
+fun:if_nametoindex=uninstrumented
+fun:ilogb=uninstrumented
+fun:ilogbf=uninstrumented
+fun:ilogbl=uninstrumented
+fun:imaxabs=uninstrumented
+fun:imaxdiv=uninstrumented
+fun:index=uninstrumented
+fun:inet6_opt_append=uninstrumented
+fun:inet6_opt_find=uninstrumented
+fun:inet6_opt_finish=uninstrumented
+fun:inet6_opt_get_val=uninstrumented
+fun:inet6_opt_init=uninstrumented
+fun:inet6_opt_next=uninstrumented
+fun:inet6_opt_set_val=uninstrumented
+fun:inet6_option_alloc=uninstrumented
+fun:inet6_option_append=uninstrumented
+fun:inet6_option_find=uninstrumented
+fun:inet6_option_init=uninstrumented
+fun:inet6_option_next=uninstrumented
+fun:inet6_option_space=uninstrumented
+fun:inet6_rth_add=uninstrumented
+fun:inet6_rth_getaddr=uninstrumented
+fun:inet6_rth_init=uninstrumented
+fun:inet6_rth_reverse=uninstrumented
+fun:inet6_rth_segments=uninstrumented
+fun:inet6_rth_space=uninstrumented
+fun:inet_addr=uninstrumented
+fun:inet_aton=uninstrumented
+fun:inet_lnaof=uninstrumented
+fun:inet_makeaddr=uninstrumented
+fun:inet_net_ntop=uninstrumented
+fun:inet_net_pton=uninstrumented
+fun:inet_neta=uninstrumented
+fun:inet_netof=uninstrumented
+fun:inet_network=uninstrumented
+fun:inet_nsap_addr=uninstrumented
+fun:inet_nsap_ntoa=uninstrumented
+fun:inet_ntoa=uninstrumented
+fun:inet_ntop=uninstrumented
+fun:inet_pton=uninstrumented
+fun:init_module=uninstrumented
+fun:initgroups=uninstrumented
+fun:initstate=uninstrumented
+fun:initstate_r=uninstrumented
+fun:innetgr=uninstrumented
+fun:inotify_add_watch=uninstrumented
+fun:inotify_init=uninstrumented
+fun:inotify_init1=uninstrumented
+fun:inotify_rm_watch=uninstrumented
+fun:insque=uninstrumented
+fun:ioctl=uninstrumented
+fun:ioperm=uninstrumented
+fun:iopl=uninstrumented
+fun:iruserok=uninstrumented
+fun:iruserok_af=uninstrumented
+fun:isalnum=uninstrumented
+fun:isalnum_l=uninstrumented
+fun:isalpha=uninstrumented
+fun:isalpha_l=uninstrumented
+fun:isascii=uninstrumented
+fun:isastream=uninstrumented
+fun:isatty=uninstrumented
+fun:isblank=uninstrumented
+fun:isblank_l=uninstrumented
+fun:iscntrl=uninstrumented
+fun:iscntrl_l=uninstrumented
+fun:isctype=uninstrumented
+fun:isdigit=uninstrumented
+fun:isdigit_l=uninstrumented
+fun:isfdtype=uninstrumented
+fun:isgraph=uninstrumented
+fun:isgraph_l=uninstrumented
+fun:isinf=uninstrumented
+fun:isinfd128=uninstrumented
+fun:isinfd32=uninstrumented
+fun:isinfd64=uninstrumented
+fun:isinff=uninstrumented
+fun:isinfl=uninstrumented
+fun:islower=uninstrumented
+fun:islower_l=uninstrumented
+fun:isnan=uninstrumented
+fun:isnanf=uninstrumented
+fun:isnanl=uninstrumented
+fun:isprint=uninstrumented
+fun:isprint_l=uninstrumented
+fun:ispunct=uninstrumented
+fun:ispunct_l=uninstrumented
+fun:isspace=uninstrumented
+fun:isspace_l=uninstrumented
+fun:isupper=uninstrumented
+fun:isupper_l=uninstrumented
+fun:iswalnum=uninstrumented
+fun:iswalnum_l=uninstrumented
+fun:iswalpha=uninstrumented
+fun:iswalpha_l=uninstrumented
+fun:iswblank=uninstrumented
+fun:iswblank_l=uninstrumented
+fun:iswcntrl=uninstrumented
+fun:iswcntrl_l=uninstrumented
+fun:iswctype=uninstrumented
+fun:iswctype_l=uninstrumented
+fun:iswdigit=uninstrumented
+fun:iswdigit_l=uninstrumented
+fun:iswgraph=uninstrumented
+fun:iswgraph_l=uninstrumented
+fun:iswlower=uninstrumented
+fun:iswlower_l=uninstrumented
+fun:iswprint=uninstrumented
+fun:iswprint_l=uninstrumented
+fun:iswpunct=uninstrumented
+fun:iswpunct_l=uninstrumented
+fun:iswspace=uninstrumented
+fun:iswspace_l=uninstrumented
+fun:iswupper=uninstrumented
+fun:iswupper_l=uninstrumented
+fun:iswxdigit=uninstrumented
+fun:iswxdigit_l=uninstrumented
+fun:isxdigit=uninstrumented
+fun:isxdigit_l=uninstrumented
+fun:j0=uninstrumented
+fun:j0f=uninstrumented
+fun:j0l=uninstrumented
+fun:j1=uninstrumented
+fun:j1f=uninstrumented
+fun:j1l=uninstrumented
+fun:jn=uninstrumented
+fun:jnf=uninstrumented
+fun:jnl=uninstrumented
+fun:jrand48=uninstrumented
+fun:jrand48_r=uninstrumented
+fun:key_decryptsession=uninstrumented
+fun:key_decryptsession_pk=uninstrumented
+fun:key_encryptsession=uninstrumented
+fun:key_encryptsession_pk=uninstrumented
+fun:key_gendes=uninstrumented
+fun:key_get_conv=uninstrumented
+fun:key_secretkey_is_set=uninstrumented
+fun:key_setnet=uninstrumented
+fun:key_setsecret=uninstrumented
+fun:kill=uninstrumented
+fun:killpg=uninstrumented
+fun:klogctl=uninstrumented
+fun:l64a=uninstrumented
+fun:labs=uninstrumented
+fun:lchmod=uninstrumented
+fun:lchown=uninstrumented
+fun:lckpwdf=uninstrumented
+fun:lcong48=uninstrumented
+fun:lcong48_r=uninstrumented
+fun:ldexp=uninstrumented
+fun:ldexpf=uninstrumented
+fun:ldexpl=uninstrumented
+fun:ldiv=uninstrumented
+fun:lfind=uninstrumented
+fun:lgamma=uninstrumented
+fun:lgamma_r=uninstrumented
+fun:lgammaf=uninstrumented
+fun:lgammaf_r=uninstrumented
+fun:lgammal=uninstrumented
+fun:lgammal_r=uninstrumented
+fun:lgetxattr=uninstrumented
+fun:link=uninstrumented
+fun:linkat=uninstrumented
+fun:lio_listio=uninstrumented
+fun:lio_listio64=uninstrumented
+fun:listen=uninstrumented
+fun:listxattr=uninstrumented
+fun:llabs=uninstrumented
+fun:lldiv=uninstrumented
+fun:llistxattr=uninstrumented
+fun:llrint=uninstrumented
+fun:llrintf=uninstrumented
+fun:llrintl=uninstrumented
+fun:llround=uninstrumented
+fun:llroundf=uninstrumented
+fun:llroundl=uninstrumented
+fun:llseek=uninstrumented
+fun:localeconv=uninstrumented
+fun:localtime=uninstrumented
+fun:localtime_r=uninstrumented
+fun:lockf=uninstrumented
+fun:lockf64=uninstrumented
+fun:log=uninstrumented
+fun:log10=uninstrumented
+fun:log10f=uninstrumented
+fun:log10l=uninstrumented
+fun:log1p=uninstrumented
+fun:log1pf=uninstrumented
+fun:log1pl=uninstrumented
+fun:log2=uninstrumented
+fun:log2f=uninstrumented
+fun:log2l=uninstrumented
+fun:logb=uninstrumented
+fun:logbf=uninstrumented
+fun:logbl=uninstrumented
+fun:logf=uninstrumented
+fun:login=uninstrumented
+fun:login_tty=uninstrumented
+fun:logl=uninstrumented
+fun:logout=uninstrumented
+fun:logwtmp=uninstrumented
+fun:longjmp=uninstrumented
+fun:lrand48=uninstrumented
+fun:lrand48_r=uninstrumented
+fun:lremovexattr=uninstrumented
+fun:lrint=uninstrumented
+fun:lrintf=uninstrumented
+fun:lrintl=uninstrumented
+fun:lround=uninstrumented
+fun:lroundf=uninstrumented
+fun:lroundl=uninstrumented
+fun:lsearch=uninstrumented
+fun:lseek=uninstrumented
+fun:lseek64=uninstrumented
+fun:lsetxattr=uninstrumented
+fun:lstat=uninstrumented
+fun:lstat64=uninstrumented
+fun:lutimes=uninstrumented
+fun:madvise=uninstrumented
+fun:makecontext=uninstrumented
+fun:mallinfo=uninstrumented
+fun:malloc=uninstrumented
+fun:malloc_get_state=uninstrumented
+fun:malloc_info=uninstrumented
+fun:malloc_set_state=uninstrumented
+fun:malloc_stats=uninstrumented
+fun:malloc_trim=uninstrumented
+fun:malloc_usable_size=uninstrumented
+fun:mallopt=uninstrumented
+fun:matherr=uninstrumented
+fun:mblen=uninstrumented
+fun:mbrlen=uninstrumented
+fun:mbrtoc16=uninstrumented
+fun:mbrtoc32=uninstrumented
+fun:mbrtowc=uninstrumented
+fun:mbsinit=uninstrumented
+fun:mbsnrtowcs=uninstrumented
+fun:mbsrtowcs=uninstrumented
+fun:mbstowcs=uninstrumented
+fun:mbtowc=uninstrumented
+fun:mcheck=uninstrumented
+fun:mcheck_check_all=uninstrumented
+fun:mcheck_pedantic=uninstrumented
+fun:mcount=uninstrumented
+fun:memalign=uninstrumented
+fun:memccpy=uninstrumented
+fun:memchr=uninstrumented
+fun:memcmp=uninstrumented
+fun:memcpy=uninstrumented
+fun:memfrob=uninstrumented
+fun:memmem=uninstrumented
+fun:memmove=uninstrumented
+fun:mempcpy=uninstrumented
+fun:memrchr=uninstrumented
+fun:memset=uninstrumented
+fun:mincore=uninstrumented
+fun:mkdir=uninstrumented
+fun:mkdirat=uninstrumented
+fun:mkdtemp=uninstrumented
+fun:mkfifo=uninstrumented
+fun:mkfifoat=uninstrumented
+fun:mknod=uninstrumented
+fun:mknodat=uninstrumented
+fun:mkostemp=uninstrumented
+fun:mkostemp64=uninstrumented
+fun:mkostemps=uninstrumented
+fun:mkostemps64=uninstrumented
+fun:mkstemp=uninstrumented
+fun:mkstemp64=uninstrumented
+fun:mkstemps=uninstrumented
+fun:mkstemps64=uninstrumented
+fun:mktemp=uninstrumented
+fun:mktime=uninstrumented
+fun:mlock=uninstrumented
+fun:mlockall=uninstrumented
+fun:mmap=uninstrumented
+fun:mmap64=uninstrumented
+fun:modf=uninstrumented
+fun:modff=uninstrumented
+fun:modfl=uninstrumented
+fun:modify_ldt=uninstrumented
+fun:moncontrol=uninstrumented
+fun:monstartup=uninstrumented
+fun:mount=uninstrumented
+fun:mprobe=uninstrumented
+fun:mprotect=uninstrumented
+fun:mq_close=uninstrumented
+fun:mq_getattr=uninstrumented
+fun:mq_notify=uninstrumented
+fun:mq_open=uninstrumented
+fun:mq_receive=uninstrumented
+fun:mq_send=uninstrumented
+fun:mq_setattr=uninstrumented
+fun:mq_timedreceive=uninstrumented
+fun:mq_timedsend=uninstrumented
+fun:mq_unlink=uninstrumented
+fun:mrand48=uninstrumented
+fun:mrand48_r=uninstrumented
+fun:mremap=uninstrumented
+fun:msgctl=uninstrumented
+fun:msgget=uninstrumented
+fun:msgrcv=uninstrumented
+fun:msgsnd=uninstrumented
+fun:msync=uninstrumented
+fun:mtrace=uninstrumented
+fun:munlock=uninstrumented
+fun:munlockall=uninstrumented
+fun:munmap=uninstrumented
+fun:muntrace=uninstrumented
+fun:name_to_handle_at=uninstrumented
+fun:nan=uninstrumented
+fun:nanf=uninstrumented
+fun:nanl=uninstrumented
+fun:nanosleep=uninstrumented
+fun:nearbyint=uninstrumented
+fun:nearbyintf=uninstrumented
+fun:nearbyintl=uninstrumented
+fun:netname2host=uninstrumented
+fun:netname2user=uninstrumented
+fun:newlocale=uninstrumented
+fun:nextafter=uninstrumented
+fun:nextafterf=uninstrumented
+fun:nextafterl=uninstrumented
+fun:nexttoward=uninstrumented
+fun:nexttowardf=uninstrumented
+fun:nexttowardl=uninstrumented
+fun:nfsservctl=uninstrumented
+fun:nftw=uninstrumented
+fun:nftw64=uninstrumented
+fun:ngettext=uninstrumented
+fun:nice=uninstrumented
+fun:nis_add=uninstrumented
+fun:nis_add_entry=uninstrumented
+fun:nis_addmember=uninstrumented
+fun:nis_checkpoint=uninstrumented
+fun:nis_clone_directory=uninstrumented
+fun:nis_clone_object=uninstrumented
+fun:nis_clone_result=uninstrumented
+fun:nis_creategroup=uninstrumented
+fun:nis_destroy_object=uninstrumented
+fun:nis_destroygroup=uninstrumented
+fun:nis_dir_cmp=uninstrumented
+fun:nis_domain_of=uninstrumented
+fun:nis_domain_of_r=uninstrumented
+fun:nis_first_entry=uninstrumented
+fun:nis_free_directory=uninstrumented
+fun:nis_free_object=uninstrumented
+fun:nis_free_request=uninstrumented
+fun:nis_freenames=uninstrumented
+fun:nis_freeresult=uninstrumented
+fun:nis_freeservlist=uninstrumented
+fun:nis_freetags=uninstrumented
+fun:nis_getnames=uninstrumented
+fun:nis_getservlist=uninstrumented
+fun:nis_ismember=uninstrumented
+fun:nis_leaf_of=uninstrumented
+fun:nis_leaf_of_r=uninstrumented
+fun:nis_lerror=uninstrumented
+fun:nis_list=uninstrumented
+fun:nis_local_directory=uninstrumented
+fun:nis_local_group=uninstrumented
+fun:nis_local_host=uninstrumented
+fun:nis_local_principal=uninstrumented
+fun:nis_lookup=uninstrumented
+fun:nis_mkdir=uninstrumented
+fun:nis_modify=uninstrumented
+fun:nis_modify_entry=uninstrumented
+fun:nis_name_of=uninstrumented
+fun:nis_name_of_r=uninstrumented
+fun:nis_next_entry=uninstrumented
+fun:nis_perror=uninstrumented
+fun:nis_ping=uninstrumented
+fun:nis_print_directory=uninstrumented
+fun:nis_print_entry=uninstrumented
+fun:nis_print_group=uninstrumented
+fun:nis_print_group_entry=uninstrumented
+fun:nis_print_link=uninstrumented
+fun:nis_print_object=uninstrumented
+fun:nis_print_result=uninstrumented
+fun:nis_print_rights=uninstrumented
+fun:nis_print_table=uninstrumented
+fun:nis_read_obj=uninstrumented
+fun:nis_remove=uninstrumented
+fun:nis_remove_entry=uninstrumented
+fun:nis_removemember=uninstrumented
+fun:nis_rmdir=uninstrumented
+fun:nis_servstate=uninstrumented
+fun:nis_sperrno=uninstrumented
+fun:nis_sperror=uninstrumented
+fun:nis_sperror_r=uninstrumented
+fun:nis_stats=uninstrumented
+fun:nis_verifygroup=uninstrumented
+fun:nis_write_obj=uninstrumented
+fun:nl_langinfo=uninstrumented
+fun:nl_langinfo_l=uninstrumented
+fun:nrand48=uninstrumented
+fun:nrand48_r=uninstrumented
+fun:ns_datetosecs=uninstrumented
+fun:ns_format_ttl=uninstrumented
+fun:ns_get16=uninstrumented
+fun:ns_get32=uninstrumented
+fun:ns_initparse=uninstrumented
+fun:ns_makecanon=uninstrumented
+fun:ns_msg_getflag=uninstrumented
+fun:ns_name_compress=uninstrumented
+fun:ns_name_ntol=uninstrumented
+fun:ns_name_ntop=uninstrumented
+fun:ns_name_pack=uninstrumented
+fun:ns_name_pton=uninstrumented
+fun:ns_name_rollback=uninstrumented
+fun:ns_name_skip=uninstrumented
+fun:ns_name_uncompress=uninstrumented
+fun:ns_name_unpack=uninstrumented
+fun:ns_parse_ttl=uninstrumented
+fun:ns_parserr=uninstrumented
+fun:ns_put16=uninstrumented
+fun:ns_put32=uninstrumented
+fun:ns_samedomain=uninstrumented
+fun:ns_samename=uninstrumented
+fun:ns_skiprr=uninstrumented
+fun:ns_sprintrr=uninstrumented
+fun:ns_sprintrrf=uninstrumented
+fun:ns_subdomain=uninstrumented
+fun:ntohl=uninstrumented
+fun:ntohs=uninstrumented
+fun:ntp_adjtime=uninstrumented
+fun:ntp_gettime=uninstrumented
+fun:ntp_gettimex=uninstrumented
+fun:obstack_free=uninstrumented
+fun:obstack_printf=uninstrumented
+fun:obstack_vprintf=uninstrumented
+fun:on_exit=uninstrumented
+fun:open=uninstrumented
+fun:open64=uninstrumented
+fun:open_by_handle_at=uninstrumented
+fun:open_memstream=uninstrumented
+fun:open_wmemstream=uninstrumented
+fun:openat=uninstrumented
+fun:openat64=uninstrumented
+fun:opendir=uninstrumented
+fun:openlog=uninstrumented
+fun:openpty=uninstrumented
+fun:parse_printf_format=uninstrumented
+fun:passwd2des=uninstrumented
+fun:pathconf=uninstrumented
+fun:pause=uninstrumented
+fun:pclose=uninstrumented
+fun:perror=uninstrumented
+fun:personality=uninstrumented
+fun:pipe=uninstrumented
+fun:pipe2=uninstrumented
+fun:pivot_root=uninstrumented
+fun:pmap_getmaps=uninstrumented
+fun:pmap_getport=uninstrumented
+fun:pmap_rmtcall=uninstrumented
+fun:pmap_set=uninstrumented
+fun:pmap_unset=uninstrumented
+fun:poll=uninstrumented
+fun:popen=uninstrumented
+fun:posix_fadvise=uninstrumented
+fun:posix_fadvise64=uninstrumented
+fun:posix_fallocate=uninstrumented
+fun:posix_fallocate64=uninstrumented
+fun:posix_madvise=uninstrumented
+fun:posix_memalign=uninstrumented
+fun:posix_openpt=uninstrumented
+fun:posix_spawn=uninstrumented
+fun:posix_spawn_file_actions_addclose=uninstrumented
+fun:posix_spawn_file_actions_adddup2=uninstrumented
+fun:posix_spawn_file_actions_addopen=uninstrumented
+fun:posix_spawn_file_actions_destroy=uninstrumented
+fun:posix_spawn_file_actions_init=uninstrumented
+fun:posix_spawnattr_destroy=uninstrumented
+fun:posix_spawnattr_getflags=uninstrumented
+fun:posix_spawnattr_getpgroup=uninstrumented
+fun:posix_spawnattr_getschedparam=uninstrumented
+fun:posix_spawnattr_getschedpolicy=uninstrumented
+fun:posix_spawnattr_getsigdefault=uninstrumented
+fun:posix_spawnattr_getsigmask=uninstrumented
+fun:posix_spawnattr_init=uninstrumented
+fun:posix_spawnattr_setflags=uninstrumented
+fun:posix_spawnattr_setpgroup=uninstrumented
+fun:posix_spawnattr_setschedparam=uninstrumented
+fun:posix_spawnattr_setschedpolicy=uninstrumented
+fun:posix_spawnattr_setsigdefault=uninstrumented
+fun:posix_spawnattr_setsigmask=uninstrumented
+fun:posix_spawnp=uninstrumented
+fun:pow=uninstrumented
+fun:pow10=uninstrumented
+fun:pow10f=uninstrumented
+fun:pow10l=uninstrumented
+fun:powf=uninstrumented
+fun:powl=uninstrumented
+fun:ppoll=uninstrumented
+fun:prctl=uninstrumented
+fun:pread=uninstrumented
+fun:pread64=uninstrumented
+fun:preadv=uninstrumented
+fun:preadv64=uninstrumented
+fun:printf=uninstrumented
+fun:printf_size=uninstrumented
+fun:printf_size_info=uninstrumented
+fun:prlimit=uninstrumented
+fun:prlimit64=uninstrumented
+fun:process_vm_readv=uninstrumented
+fun:process_vm_writev=uninstrumented
+fun:profil=uninstrumented
+fun:pselect=uninstrumented
+fun:psiginfo=uninstrumented
+fun:psignal=uninstrumented
+fun:pthread_atfork=uninstrumented
+fun:pthread_attr_destroy=uninstrumented
+fun:pthread_attr_getaffinity_np=uninstrumented
+fun:pthread_attr_getdetachstate=uninstrumented
+fun:pthread_attr_getguardsize=uninstrumented
+fun:pthread_attr_getinheritsched=uninstrumented
+fun:pthread_attr_getschedparam=uninstrumented
+fun:pthread_attr_getschedpolicy=uninstrumented
+fun:pthread_attr_getscope=uninstrumented
+fun:pthread_attr_getstack=uninstrumented
+fun:pthread_attr_getstackaddr=uninstrumented
+fun:pthread_attr_getstacksize=uninstrumented
+fun:pthread_attr_init=uninstrumented
+fun:pthread_attr_setaffinity_np=uninstrumented
+fun:pthread_attr_setdetachstate=uninstrumented
+fun:pthread_attr_setguardsize=uninstrumented
+fun:pthread_attr_setinheritsched=uninstrumented
+fun:pthread_attr_setschedparam=uninstrumented
+fun:pthread_attr_setschedpolicy=uninstrumented
+fun:pthread_attr_setscope=uninstrumented
+fun:pthread_attr_setstack=uninstrumented
+fun:pthread_attr_setstackaddr=uninstrumented
+fun:pthread_attr_setstacksize=uninstrumented
+fun:pthread_barrier_destroy=uninstrumented
+fun:pthread_barrier_init=uninstrumented
+fun:pthread_barrier_wait=uninstrumented
+fun:pthread_barrierattr_destroy=uninstrumented
+fun:pthread_barrierattr_getpshared=uninstrumented
+fun:pthread_barrierattr_init=uninstrumented
+fun:pthread_barrierattr_setpshared=uninstrumented
+fun:pthread_cancel=uninstrumented
+fun:pthread_cond_broadcast=uninstrumented
+fun:pthread_cond_destroy=uninstrumented
+fun:pthread_cond_init=uninstrumented
+fun:pthread_cond_signal=uninstrumented
+fun:pthread_cond_timedwait=uninstrumented
+fun:pthread_cond_wait=uninstrumented
+fun:pthread_condattr_destroy=uninstrumented
+fun:pthread_condattr_getclock=uninstrumented
+fun:pthread_condattr_getpshared=uninstrumented
+fun:pthread_condattr_init=uninstrumented
+fun:pthread_condattr_setclock=uninstrumented
+fun:pthread_condattr_setpshared=uninstrumented
+fun:pthread_create=uninstrumented
+fun:pthread_detach=uninstrumented
+fun:pthread_equal=uninstrumented
+fun:pthread_exit=uninstrumented
+fun:pthread_getaffinity_np=uninstrumented
+fun:pthread_getattr_default_np=uninstrumented
+fun:pthread_getattr_np=uninstrumented
+fun:pthread_getconcurrency=uninstrumented
+fun:pthread_getcpuclockid=uninstrumented
+fun:pthread_getname_np=uninstrumented
+fun:pthread_getschedparam=uninstrumented
+fun:pthread_getspecific=uninstrumented
+fun:pthread_join=uninstrumented
+fun:pthread_key_create=uninstrumented
+fun:pthread_key_delete=uninstrumented
+fun:pthread_kill=uninstrumented
+fun:pthread_kill_other_threads_np=uninstrumented
+fun:pthread_mutex_consistent=uninstrumented
+fun:pthread_mutex_consistent_np=uninstrumented
+fun:pthread_mutex_destroy=uninstrumented
+fun:pthread_mutex_getprioceiling=uninstrumented
+fun:pthread_mutex_init=uninstrumented
+fun:pthread_mutex_lock=uninstrumented
+fun:pthread_mutex_setprioceiling=uninstrumented
+fun:pthread_mutex_timedlock=uninstrumented
+fun:pthread_mutex_trylock=uninstrumented
+fun:pthread_mutex_unlock=uninstrumented
+fun:pthread_mutexattr_destroy=uninstrumented
+fun:pthread_mutexattr_getkind_np=uninstrumented
+fun:pthread_mutexattr_getprioceiling=uninstrumented
+fun:pthread_mutexattr_getprotocol=uninstrumented
+fun:pthread_mutexattr_getpshared=uninstrumented
+fun:pthread_mutexattr_getrobust=uninstrumented
+fun:pthread_mutexattr_getrobust_np=uninstrumented
+fun:pthread_mutexattr_gettype=uninstrumented
+fun:pthread_mutexattr_init=uninstrumented
+fun:pthread_mutexattr_setkind_np=uninstrumented
+fun:pthread_mutexattr_setprioceiling=uninstrumented
+fun:pthread_mutexattr_setprotocol=uninstrumented
+fun:pthread_mutexattr_setpshared=uninstrumented
+fun:pthread_mutexattr_setrobust=uninstrumented
+fun:pthread_mutexattr_setrobust_np=uninstrumented
+fun:pthread_mutexattr_settype=uninstrumented
+fun:pthread_once=uninstrumented
+fun:pthread_rwlock_destroy=uninstrumented
+fun:pthread_rwlock_init=uninstrumented
+fun:pthread_rwlock_rdlock=uninstrumented
+fun:pthread_rwlock_timedrdlock=uninstrumented
+fun:pthread_rwlock_timedwrlock=uninstrumented
+fun:pthread_rwlock_tryrdlock=uninstrumented
+fun:pthread_rwlock_trywrlock=uninstrumented
+fun:pthread_rwlock_unlock=uninstrumented
+fun:pthread_rwlock_wrlock=uninstrumented
+fun:pthread_rwlockattr_destroy=uninstrumented
+fun:pthread_rwlockattr_getkind_np=uninstrumented
+fun:pthread_rwlockattr_getpshared=uninstrumented
+fun:pthread_rwlockattr_init=uninstrumented
+fun:pthread_rwlockattr_setkind_np=uninstrumented
+fun:pthread_rwlockattr_setpshared=uninstrumented
+fun:pthread_self=uninstrumented
+fun:pthread_setaffinity_np=uninstrumented
+fun:pthread_setattr_default_np=uninstrumented
+fun:pthread_setcancelstate=uninstrumented
+fun:pthread_setcanceltype=uninstrumented
+fun:pthread_setconcurrency=uninstrumented
+fun:pthread_setname_np=uninstrumented
+fun:pthread_setschedparam=uninstrumented
+fun:pthread_setschedprio=uninstrumented
+fun:pthread_setspecific=uninstrumented
+fun:pthread_sigmask=uninstrumented
+fun:pthread_sigqueue=uninstrumented
+fun:pthread_spin_destroy=uninstrumented
+fun:pthread_spin_init=uninstrumented
+fun:pthread_spin_lock=uninstrumented
+fun:pthread_spin_trylock=uninstrumented
+fun:pthread_spin_unlock=uninstrumented
+fun:pthread_testcancel=uninstrumented
+fun:pthread_timedjoin_np=uninstrumented
+fun:pthread_tryjoin_np=uninstrumented
+fun:pthread_yield=uninstrumented
+fun:ptrace=uninstrumented
+fun:ptsname=uninstrumented
+fun:ptsname_r=uninstrumented
+fun:putc=uninstrumented
+fun:putc_unlocked=uninstrumented
+fun:putchar=uninstrumented
+fun:putchar_unlocked=uninstrumented
+fun:putenv=uninstrumented
+fun:putgrent=uninstrumented
+fun:putmsg=uninstrumented
+fun:putpmsg=uninstrumented
+fun:putpwent=uninstrumented
+fun:puts=uninstrumented
+fun:putsgent=uninstrumented
+fun:putspent=uninstrumented
+fun:pututline=uninstrumented
+fun:pututxline=uninstrumented
+fun:putw=uninstrumented
+fun:putwc=uninstrumented
+fun:putwc_unlocked=uninstrumented
+fun:putwchar=uninstrumented
+fun:putwchar_unlocked=uninstrumented
+fun:pvalloc=uninstrumented
+fun:pwrite=uninstrumented
+fun:pwrite64=uninstrumented
+fun:pwritev=uninstrumented
+fun:pwritev64=uninstrumented
+fun:qecvt=uninstrumented
+fun:qecvt_r=uninstrumented
+fun:qfcvt=uninstrumented
+fun:qfcvt_r=uninstrumented
+fun:qgcvt=uninstrumented
+fun:qsort=uninstrumented
+fun:qsort_r=uninstrumented
+fun:query_module=uninstrumented
+fun:quick_exit=uninstrumented
+fun:quotactl=uninstrumented
+fun:raise=uninstrumented
+fun:rand=uninstrumented
+fun:rand_r=uninstrumented
+fun:random=uninstrumented
+fun:random_r=uninstrumented
+fun:rawmemchr=uninstrumented
+fun:rcmd=uninstrumented
+fun:rcmd_af=uninstrumented
+fun:re_comp=uninstrumented
+fun:re_compile_fastmap=uninstrumented
+fun:re_compile_pattern=uninstrumented
+fun:re_exec=uninstrumented
+fun:re_match=uninstrumented
+fun:re_match_2=uninstrumented
+fun:re_search=uninstrumented
+fun:re_search_2=uninstrumented
+fun:re_set_registers=uninstrumented
+fun:re_set_syntax=uninstrumented
+fun:read=uninstrumented
+fun:readColdStartFile=uninstrumented
+fun:readahead=uninstrumented
+fun:readdir=uninstrumented
+fun:readdir64=uninstrumented
+fun:readdir64_r=uninstrumented
+fun:readdir_r=uninstrumented
+fun:readlink=uninstrumented
+fun:readlinkat=uninstrumented
+fun:readv=uninstrumented
+fun:realloc=uninstrumented
+fun:realpath=uninstrumented
+fun:reboot=uninstrumented
+fun:recv=uninstrumented
+fun:recvfrom=uninstrumented
+fun:recvmmsg=uninstrumented
+fun:recvmsg=uninstrumented
+fun:regcomp=uninstrumented
+fun:regerror=uninstrumented
+fun:regexec=uninstrumented
+fun:regfree=uninstrumented
+fun:register_printf_function=uninstrumented
+fun:register_printf_modifier=uninstrumented
+fun:register_printf_specifier=uninstrumented
+fun:register_printf_type=uninstrumented
+fun:registerrpc=uninstrumented
+fun:remainder=uninstrumented
+fun:remainderf=uninstrumented
+fun:remainderl=uninstrumented
+fun:remap_file_pages=uninstrumented
+fun:remove=uninstrumented
+fun:removexattr=uninstrumented
+fun:remque=uninstrumented
+fun:remquo=uninstrumented
+fun:remquof=uninstrumented
+fun:remquol=uninstrumented
+fun:rename=uninstrumented
+fun:renameat=uninstrumented
+fun:res_gethostbyaddr=uninstrumented
+fun:res_gethostbyname=uninstrumented
+fun:res_gethostbyname2=uninstrumented
+fun:res_send_setqhook=uninstrumented
+fun:res_send_setrhook=uninstrumented
+fun:revoke=uninstrumented
+fun:rewind=uninstrumented
+fun:rewinddir=uninstrumented
+fun:rexec=uninstrumented
+fun:rexec_af=uninstrumented
+fun:rindex=uninstrumented
+fun:rint=uninstrumented
+fun:rintf=uninstrumented
+fun:rintl=uninstrumented
+fun:rmdir=uninstrumented
+fun:round=uninstrumented
+fun:roundf=uninstrumented
+fun:roundl=uninstrumented
+fun:rpmatch=uninstrumented
+fun:rresvport=uninstrumented
+fun:rresvport_af=uninstrumented
+fun:rtime=uninstrumented
+fun:ruserok=uninstrumented
+fun:ruserok_af=uninstrumented
+fun:ruserpass=uninstrumented
+fun:sbrk=uninstrumented
+fun:scalb=uninstrumented
+fun:scalbf=uninstrumented
+fun:scalbl=uninstrumented
+fun:scalbln=uninstrumented
+fun:scalblnf=uninstrumented
+fun:scalblnl=uninstrumented
+fun:scalbn=uninstrumented
+fun:scalbnf=uninstrumented
+fun:scalbnl=uninstrumented
+fun:scandir=uninstrumented
+fun:scandir64=uninstrumented
+fun:scandirat=uninstrumented
+fun:scandirat64=uninstrumented
+fun:scanf=uninstrumented
+fun:sched_get_priority_max=uninstrumented
+fun:sched_get_priority_min=uninstrumented
+fun:sched_getaffinity=uninstrumented
+fun:sched_getcpu=uninstrumented
+fun:sched_getparam=uninstrumented
+fun:sched_getscheduler=uninstrumented
+fun:sched_rr_get_interval=uninstrumented
+fun:sched_setaffinity=uninstrumented
+fun:sched_setparam=uninstrumented
+fun:sched_setscheduler=uninstrumented
+fun:sched_yield=uninstrumented
+fun:secure_getenv=uninstrumented
+fun:seed48=uninstrumented
+fun:seed48_r=uninstrumented
+fun:seekdir=uninstrumented
+fun:select=uninstrumented
+fun:sem_close=uninstrumented
+fun:sem_destroy=uninstrumented
+fun:sem_getvalue=uninstrumented
+fun:sem_init=uninstrumented
+fun:sem_open=uninstrumented
+fun:sem_post=uninstrumented
+fun:sem_timedwait=uninstrumented
+fun:sem_trywait=uninstrumented
+fun:sem_unlink=uninstrumented
+fun:sem_wait=uninstrumented
+fun:semctl=uninstrumented
+fun:semget=uninstrumented
+fun:semop=uninstrumented
+fun:semtimedop=uninstrumented
+fun:send=uninstrumented
+fun:sendfile=uninstrumented
+fun:sendfile64=uninstrumented
+fun:sendmmsg=uninstrumented
+fun:sendmsg=uninstrumented
+fun:sendto=uninstrumented
+fun:setaliasent=uninstrumented
+fun:setbuf=uninstrumented
+fun:setbuffer=uninstrumented
+fun:setcontext=uninstrumented
+fun:setdomainname=uninstrumented
+fun:setegid=uninstrumented
+fun:setenv=uninstrumented
+fun:seteuid=uninstrumented
+fun:setfsent=uninstrumented
+fun:setfsgid=uninstrumented
+fun:setfsuid=uninstrumented
+fun:setgid=uninstrumented
+fun:setgrent=uninstrumented
+fun:setgroups=uninstrumented
+fun:sethostent=uninstrumented
+fun:sethostid=uninstrumented
+fun:sethostname=uninstrumented
+fun:setipv4sourcefilter=uninstrumented
+fun:setitimer=uninstrumented
+fun:setjmp=uninstrumented
+fun:setkey=uninstrumented
+fun:setkey_r=uninstrumented
+fun:setlinebuf=uninstrumented
+fun:setlocale=uninstrumented
+fun:setlogin=uninstrumented
+fun:setlogmask=uninstrumented
+fun:setmntent=uninstrumented
+fun:setnetent=uninstrumented
+fun:setnetgrent=uninstrumented
+fun:setns=uninstrumented
+fun:setpgid=uninstrumented
+fun:setpgrp=uninstrumented
+fun:setpriority=uninstrumented
+fun:setprotoent=uninstrumented
+fun:setpwent=uninstrumented
+fun:setregid=uninstrumented
+fun:setresgid=uninstrumented
+fun:setresuid=uninstrumented
+fun:setreuid=uninstrumented
+fun:setrlimit=uninstrumented
+fun:setrlimit64=uninstrumented
+fun:setrpcent=uninstrumented
+fun:setservent=uninstrumented
+fun:setsgent=uninstrumented
+fun:setsid=uninstrumented
+fun:setsockopt=uninstrumented
+fun:setsourcefilter=uninstrumented
+fun:setspent=uninstrumented
+fun:setstate=uninstrumented
+fun:setstate_r=uninstrumented
+fun:settimeofday=uninstrumented
+fun:setttyent=uninstrumented
+fun:setuid=uninstrumented
+fun:setusershell=uninstrumented
+fun:setutent=uninstrumented
+fun:setutxent=uninstrumented
+fun:setvbuf=uninstrumented
+fun:setxattr=uninstrumented
+fun:sgetsgent=uninstrumented
+fun:sgetsgent_r=uninstrumented
+fun:sgetspent=uninstrumented
+fun:sgetspent_r=uninstrumented
+fun:shm_open=uninstrumented
+fun:shm_unlink=uninstrumented
+fun:shmat=uninstrumented
+fun:shmctl=uninstrumented
+fun:shmdt=uninstrumented
+fun:shmget=uninstrumented
+fun:shutdown=uninstrumented
+fun:sigaction=uninstrumented
+fun:sigaddset=uninstrumented
+fun:sigaltstack=uninstrumented
+fun:sigandset=uninstrumented
+fun:sigblock=uninstrumented
+fun:sigdelset=uninstrumented
+fun:sigemptyset=uninstrumented
+fun:sigfillset=uninstrumented
+fun:siggetmask=uninstrumented
+fun:sighold=uninstrumented
+fun:sigignore=uninstrumented
+fun:siginterrupt=uninstrumented
+fun:sigisemptyset=uninstrumented
+fun:sigismember=uninstrumented
+fun:siglongjmp=uninstrumented
+fun:signal=uninstrumented
+fun:signalfd=uninstrumented
+fun:significand=uninstrumented
+fun:significandf=uninstrumented
+fun:significandl=uninstrumented
+fun:sigorset=uninstrumented
+fun:sigpause=uninstrumented
+fun:sigpending=uninstrumented
+fun:sigprocmask=uninstrumented
+fun:sigqueue=uninstrumented
+fun:sigrelse=uninstrumented
+fun:sigreturn=uninstrumented
+fun:sigset=uninstrumented
+fun:sigsetmask=uninstrumented
+fun:sigstack=uninstrumented
+fun:sigsuspend=uninstrumented
+fun:sigtimedwait=uninstrumented
+fun:sigvec=uninstrumented
+fun:sigwait=uninstrumented
+fun:sigwaitinfo=uninstrumented
+fun:sin=uninstrumented
+fun:sincos=uninstrumented
+fun:sincosf=uninstrumented
+fun:sincosl=uninstrumented
+fun:sinf=uninstrumented
+fun:sinh=uninstrumented
+fun:sinhf=uninstrumented
+fun:sinhl=uninstrumented
+fun:sinl=uninstrumented
+fun:sleep=uninstrumented
+fun:snprintf=uninstrumented
+fun:sockatmark=uninstrumented
+fun:socket=uninstrumented
+fun:socketpair=uninstrumented
+fun:splice=uninstrumented
+fun:sprintf=uninstrumented
+fun:sprofil=uninstrumented
+fun:sqrt=uninstrumented
+fun:sqrtf=uninstrumented
+fun:sqrtl=uninstrumented
+fun:srand=uninstrumented
+fun:srand48=uninstrumented
+fun:srand48_r=uninstrumented
+fun:srandom=uninstrumented
+fun:srandom_r=uninstrumented
+fun:sscanf=uninstrumented
+fun:ssignal=uninstrumented
+fun:sstk=uninstrumented
+fun:stat=uninstrumented
+fun:stat64=uninstrumented
+fun:statfs=uninstrumented
+fun:statfs64=uninstrumented
+fun:statvfs=uninstrumented
+fun:statvfs64=uninstrumented
+fun:step=uninstrumented
+fun:stime=uninstrumented
+fun:stpcpy=uninstrumented
+fun:stpncpy=uninstrumented
+fun:strcasecmp=uninstrumented
+fun:strcasecmp_l=uninstrumented
+fun:strcasestr=uninstrumented
+fun:strcat=uninstrumented
+fun:strchr=uninstrumented
+fun:strchrnul=uninstrumented
+fun:strcmp=uninstrumented
+fun:strcoll=uninstrumented
+fun:strcoll_l=uninstrumented
+fun:strcpy=uninstrumented
+fun:strcspn=uninstrumented
+fun:strdup=uninstrumented
+fun:strerror=uninstrumented
+fun:strerror_l=uninstrumented
+fun:strerror_r=uninstrumented
+fun:strfmon=uninstrumented
+fun:strfmon_l=uninstrumented
+fun:strfry=uninstrumented
+fun:strftime=uninstrumented
+fun:strftime_l=uninstrumented
+fun:strlen=uninstrumented
+fun:strncasecmp=uninstrumented
+fun:strncasecmp_l=uninstrumented
+fun:strncat=uninstrumented
+fun:strncmp=uninstrumented
+fun:strncpy=uninstrumented
+fun:strndup=uninstrumented
+fun:strnlen=uninstrumented
+fun:strpbrk=uninstrumented
+fun:strptime=uninstrumented
+fun:strptime_l=uninstrumented
+fun:strrchr=uninstrumented
+fun:strsep=uninstrumented
+fun:strsignal=uninstrumented
+fun:strspn=uninstrumented
+fun:strstr=uninstrumented
+fun:strtod=uninstrumented
+fun:strtod_l=uninstrumented
+fun:strtof=uninstrumented
+fun:strtof_l=uninstrumented
+fun:strtoimax=uninstrumented
+fun:strtok=uninstrumented
+fun:strtok_r=uninstrumented
+fun:strtol=uninstrumented
+fun:strtol_l=uninstrumented
+fun:strtold=uninstrumented
+fun:strtold_l=uninstrumented
+fun:strtoll=uninstrumented
+fun:strtoll_l=uninstrumented
+fun:strtoq=uninstrumented
+fun:strtoul=uninstrumented
+fun:strtoul_l=uninstrumented
+fun:strtoull=uninstrumented
+fun:strtoull_l=uninstrumented
+fun:strtoumax=uninstrumented
+fun:strtouq=uninstrumented
+fun:strverscmp=uninstrumented
+fun:strxfrm=uninstrumented
+fun:strxfrm_l=uninstrumented
+fun:stty=uninstrumented
+fun:svc_exit=uninstrumented
+fun:svc_getreq=uninstrumented
+fun:svc_getreq_common=uninstrumented
+fun:svc_getreq_poll=uninstrumented
+fun:svc_getreqset=uninstrumented
+fun:svc_register=uninstrumented
+fun:svc_run=uninstrumented
+fun:svc_sendreply=uninstrumented
+fun:svc_unregister=uninstrumented
+fun:svcerr_auth=uninstrumented
+fun:svcerr_decode=uninstrumented
+fun:svcerr_noproc=uninstrumented
+fun:svcerr_noprog=uninstrumented
+fun:svcerr_progvers=uninstrumented
+fun:svcerr_systemerr=uninstrumented
+fun:svcerr_weakauth=uninstrumented
+fun:svcfd_create=uninstrumented
+fun:svcraw_create=uninstrumented
+fun:svctcp_create=uninstrumented
+fun:svcudp_bufcreate=uninstrumented
+fun:svcudp_create=uninstrumented
+fun:svcudp_enablecache=uninstrumented
+fun:svcunix_create=uninstrumented
+fun:svcunixfd_create=uninstrumented
+fun:swab=uninstrumented
+fun:swapcontext=uninstrumented
+fun:swapoff=uninstrumented
+fun:swapon=uninstrumented
+fun:swprintf=uninstrumented
+fun:swscanf=uninstrumented
+fun:symlink=uninstrumented
+fun:symlinkat=uninstrumented
+fun:sync=uninstrumented
+fun:sync_file_range=uninstrumented
+fun:syncfs=uninstrumented
+fun:syscall=uninstrumented
+fun:sysconf=uninstrumented
+fun:sysctl=uninstrumented
+fun:sysinfo=uninstrumented
+fun:syslog=uninstrumented
+fun:system=uninstrumented
+fun:sysv_signal=uninstrumented
+fun:tan=uninstrumented
+fun:tanf=uninstrumented
+fun:tanh=uninstrumented
+fun:tanhf=uninstrumented
+fun:tanhl=uninstrumented
+fun:tanl=uninstrumented
+fun:tcdrain=uninstrumented
+fun:tcflow=uninstrumented
+fun:tcflush=uninstrumented
+fun:tcgetattr=uninstrumented
+fun:tcgetpgrp=uninstrumented
+fun:tcgetsid=uninstrumented
+fun:tcsendbreak=uninstrumented
+fun:tcsetattr=uninstrumented
+fun:tcsetpgrp=uninstrumented
+fun:td_init=uninstrumented
+fun:td_log=uninstrumented
+fun:td_symbol_list=uninstrumented
+fun:td_ta_clear_event=uninstrumented
+fun:td_ta_delete=uninstrumented
+fun:td_ta_enable_stats=uninstrumented
+fun:td_ta_event_addr=uninstrumented
+fun:td_ta_event_getmsg=uninstrumented
+fun:td_ta_get_nthreads=uninstrumented
+fun:td_ta_get_ph=uninstrumented
+fun:td_ta_get_stats=uninstrumented
+fun:td_ta_map_id2thr=uninstrumented
+fun:td_ta_map_lwp2thr=uninstrumented
+fun:td_ta_new=uninstrumented
+fun:td_ta_reset_stats=uninstrumented
+fun:td_ta_set_event=uninstrumented
+fun:td_ta_setconcurrency=uninstrumented
+fun:td_ta_thr_iter=uninstrumented
+fun:td_ta_tsd_iter=uninstrumented
+fun:td_thr_clear_event=uninstrumented
+fun:td_thr_dbresume=uninstrumented
+fun:td_thr_dbsuspend=uninstrumented
+fun:td_thr_event_enable=uninstrumented
+fun:td_thr_event_getmsg=uninstrumented
+fun:td_thr_get_info=uninstrumented
+fun:td_thr_getfpregs=uninstrumented
+fun:td_thr_getgregs=uninstrumented
+fun:td_thr_getxregs=uninstrumented
+fun:td_thr_getxregsize=uninstrumented
+fun:td_thr_set_event=uninstrumented
+fun:td_thr_setfpregs=uninstrumented
+fun:td_thr_setgregs=uninstrumented
+fun:td_thr_setprio=uninstrumented
+fun:td_thr_setsigpending=uninstrumented
+fun:td_thr_setxregs=uninstrumented
+fun:td_thr_sigsetmask=uninstrumented
+fun:td_thr_tls_get_addr=uninstrumented
+fun:td_thr_tlsbase=uninstrumented
+fun:td_thr_tsd=uninstrumented
+fun:td_thr_validate=uninstrumented
+fun:tdelete=uninstrumented
+fun:tdestroy=uninstrumented
+fun:tee=uninstrumented
+fun:telldir=uninstrumented
+fun:tempnam=uninstrumented
+fun:textdomain=uninstrumented
+fun:tfind=uninstrumented
+fun:tgamma=uninstrumented
+fun:tgammaf=uninstrumented
+fun:tgammal=uninstrumented
+fun:time=uninstrumented
+fun:timegm=uninstrumented
+fun:timelocal=uninstrumented
+fun:timer_create=uninstrumented
+fun:timer_delete=uninstrumented
+fun:timer_getoverrun=uninstrumented
+fun:timer_gettime=uninstrumented
+fun:timer_settime=uninstrumented
+fun:timerfd_create=uninstrumented
+fun:timerfd_gettime=uninstrumented
+fun:timerfd_settime=uninstrumented
+fun:times=uninstrumented
+fun:timespec_get=uninstrumented
+fun:tmpfile=uninstrumented
+fun:tmpfile64=uninstrumented
+fun:tmpnam=uninstrumented
+fun:tmpnam_r=uninstrumented
+fun:toascii=uninstrumented
+fun:tolower=uninstrumented
+fun:tolower_l=uninstrumented
+fun:toupper=uninstrumented
+fun:toupper_l=uninstrumented
+fun:towctrans=uninstrumented
+fun:towctrans_l=uninstrumented
+fun:towlower=uninstrumented
+fun:towlower_l=uninstrumented
+fun:towupper=uninstrumented
+fun:towupper_l=uninstrumented
+fun:tr_break=uninstrumented
+fun:trunc=uninstrumented
+fun:truncate=uninstrumented
+fun:truncate64=uninstrumented
+fun:truncf=uninstrumented
+fun:truncl=uninstrumented
+fun:tsearch=uninstrumented
+fun:ttyname=uninstrumented
+fun:ttyname_r=uninstrumented
+fun:ttyslot=uninstrumented
+fun:twalk=uninstrumented
+fun:tzset=uninstrumented
+fun:ualarm=uninstrumented
+fun:ulckpwdf=uninstrumented
+fun:ulimit=uninstrumented
+fun:umask=uninstrumented
+fun:umount=uninstrumented
+fun:umount2=uninstrumented
+fun:uname=uninstrumented
+fun:ungetc=uninstrumented
+fun:ungetwc=uninstrumented
+fun:unlink=uninstrumented
+fun:unlinkat=uninstrumented
+fun:unlockpt=uninstrumented
+fun:unsetenv=uninstrumented
+fun:unshare=uninstrumented
+fun:updwtmp=uninstrumented
+fun:updwtmpx=uninstrumented
+fun:uselib=uninstrumented
+fun:uselocale=uninstrumented
+fun:user2netname=uninstrumented
+fun:usleep=uninstrumented
+fun:ustat=uninstrumented
+fun:utime=uninstrumented
+fun:utimensat=uninstrumented
+fun:utimes=uninstrumented
+fun:utmpname=uninstrumented
+fun:utmpxname=uninstrumented
+fun:valloc=uninstrumented
+fun:vasprintf=uninstrumented
+fun:vdprintf=uninstrumented
+fun:verr=uninstrumented
+fun:verrx=uninstrumented
+fun:versionsort=uninstrumented
+fun:versionsort64=uninstrumented
+fun:vfork=uninstrumented
+fun:vfprintf=uninstrumented
+fun:vfscanf=uninstrumented
+fun:vfwprintf=uninstrumented
+fun:vfwscanf=uninstrumented
+fun:vhangup=uninstrumented
+fun:vlimit=uninstrumented
+fun:vmsplice=uninstrumented
+fun:vprintf=uninstrumented
+fun:vscanf=uninstrumented
+fun:vsnprintf=uninstrumented
+fun:vsprintf=uninstrumented
+fun:vsscanf=uninstrumented
+fun:vswprintf=uninstrumented
+fun:vswscanf=uninstrumented
+fun:vsyslog=uninstrumented
+fun:vtimes=uninstrumented
+fun:vwarn=uninstrumented
+fun:vwarnx=uninstrumented
+fun:vwprintf=uninstrumented
+fun:vwscanf=uninstrumented
+fun:wait=uninstrumented
+fun:wait3=uninstrumented
+fun:wait4=uninstrumented
+fun:waitid=uninstrumented
+fun:waitpid=uninstrumented
+fun:warn=uninstrumented
+fun:warnx=uninstrumented
+fun:wcpcpy=uninstrumented
+fun:wcpncpy=uninstrumented
+fun:wcrtomb=uninstrumented
+fun:wcscasecmp=uninstrumented
+fun:wcscasecmp_l=uninstrumented
+fun:wcscat=uninstrumented
+fun:wcschr=uninstrumented
+fun:wcschrnul=uninstrumented
+fun:wcscmp=uninstrumented
+fun:wcscoll=uninstrumented
+fun:wcscoll_l=uninstrumented
+fun:wcscpy=uninstrumented
+fun:wcscspn=uninstrumented
+fun:wcsdup=uninstrumented
+fun:wcsftime=uninstrumented
+fun:wcsftime_l=uninstrumented
+fun:wcslen=uninstrumented
+fun:wcsncasecmp=uninstrumented
+fun:wcsncasecmp_l=uninstrumented
+fun:wcsncat=uninstrumented
+fun:wcsncmp=uninstrumented
+fun:wcsncpy=uninstrumented
+fun:wcsnlen=uninstrumented
+fun:wcsnrtombs=uninstrumented
+fun:wcspbrk=uninstrumented
+fun:wcsrchr=uninstrumented
+fun:wcsrtombs=uninstrumented
+fun:wcsspn=uninstrumented
+fun:wcsstr=uninstrumented
+fun:wcstod=uninstrumented
+fun:wcstod_l=uninstrumented
+fun:wcstof=uninstrumented
+fun:wcstof_l=uninstrumented
+fun:wcstoimax=uninstrumented
+fun:wcstok=uninstrumented
+fun:wcstol=uninstrumented
+fun:wcstol_l=uninstrumented
+fun:wcstold=uninstrumented
+fun:wcstold_l=uninstrumented
+fun:wcstoll=uninstrumented
+fun:wcstoll_l=uninstrumented
+fun:wcstombs=uninstrumented
+fun:wcstoq=uninstrumented
+fun:wcstoul=uninstrumented
+fun:wcstoul_l=uninstrumented
+fun:wcstoull=uninstrumented
+fun:wcstoull_l=uninstrumented
+fun:wcstoumax=uninstrumented
+fun:wcstouq=uninstrumented
+fun:wcswcs=uninstrumented
+fun:wcswidth=uninstrumented
+fun:wcsxfrm=uninstrumented
+fun:wcsxfrm_l=uninstrumented
+fun:wctob=uninstrumented
+fun:wctomb=uninstrumented
+fun:wctrans=uninstrumented
+fun:wctrans_l=uninstrumented
+fun:wctype=uninstrumented
+fun:wctype_l=uninstrumented
+fun:wcwidth=uninstrumented
+fun:wmemchr=uninstrumented
+fun:wmemcmp=uninstrumented
+fun:wmemcpy=uninstrumented
+fun:wmemmove=uninstrumented
+fun:wmempcpy=uninstrumented
+fun:wmemset=uninstrumented
+fun:wordexp=uninstrumented
+fun:wordfree=uninstrumented
+fun:wprintf=uninstrumented
+fun:write=uninstrumented
+fun:writeColdStartFile=uninstrumented
+fun:writev=uninstrumented
+fun:wscanf=uninstrumented
+fun:xdecrypt=uninstrumented
+fun:xdr_accepted_reply=uninstrumented
+fun:xdr_array=uninstrumented
+fun:xdr_authdes_cred=uninstrumented
+fun:xdr_authdes_verf=uninstrumented
+fun:xdr_authunix_parms=uninstrumented
+fun:xdr_bool=uninstrumented
+fun:xdr_bytes=uninstrumented
+fun:xdr_callhdr=uninstrumented
+fun:xdr_callmsg=uninstrumented
+fun:xdr_cback_data=uninstrumented
+fun:xdr_char=uninstrumented
+fun:xdr_cryptkeyarg=uninstrumented
+fun:xdr_cryptkeyarg2=uninstrumented
+fun:xdr_cryptkeyres=uninstrumented
+fun:xdr_des_block=uninstrumented
+fun:xdr_domainname=uninstrumented
+fun:xdr_double=uninstrumented
+fun:xdr_enum=uninstrumented
+fun:xdr_float=uninstrumented
+fun:xdr_free=uninstrumented
+fun:xdr_getcredres=uninstrumented
+fun:xdr_hyper=uninstrumented
+fun:xdr_int=uninstrumented
+fun:xdr_int16_t=uninstrumented
+fun:xdr_int32_t=uninstrumented
+fun:xdr_int64_t=uninstrumented
+fun:xdr_int8_t=uninstrumented
+fun:xdr_key_netstarg=uninstrumented
+fun:xdr_key_netstres=uninstrumented
+fun:xdr_keybuf=uninstrumented
+fun:xdr_keydat=uninstrumented
+fun:xdr_keystatus=uninstrumented
+fun:xdr_long=uninstrumented
+fun:xdr_longlong_t=uninstrumented
+fun:xdr_mapname=uninstrumented
+fun:xdr_netnamestr=uninstrumented
+fun:xdr_netobj=uninstrumented
+fun:xdr_obj_p=uninstrumented
+fun:xdr_opaque=uninstrumented
+fun:xdr_opaque_auth=uninstrumented
+fun:xdr_peername=uninstrumented
+fun:xdr_pmap=uninstrumented
+fun:xdr_pmaplist=uninstrumented
+fun:xdr_pointer=uninstrumented
+fun:xdr_quad_t=uninstrumented
+fun:xdr_reference=uninstrumented
+fun:xdr_rejected_reply=uninstrumented
+fun:xdr_replymsg=uninstrumented
+fun:xdr_rmtcall_args=uninstrumented
+fun:xdr_rmtcallres=uninstrumented
+fun:xdr_short=uninstrumented
+fun:xdr_sizeof=uninstrumented
+fun:xdr_string=uninstrumented
+fun:xdr_u_char=uninstrumented
+fun:xdr_u_hyper=uninstrumented
+fun:xdr_u_int=uninstrumented
+fun:xdr_u_long=uninstrumented
+fun:xdr_u_longlong_t=uninstrumented
+fun:xdr_u_quad_t=uninstrumented
+fun:xdr_u_short=uninstrumented
+fun:xdr_uint16_t=uninstrumented
+fun:xdr_uint32_t=uninstrumented
+fun:xdr_uint64_t=uninstrumented
+fun:xdr_uint8_t=uninstrumented
+fun:xdr_union=uninstrumented
+fun:xdr_unixcred=uninstrumented
+fun:xdr_valdat=uninstrumented
+fun:xdr_vector=uninstrumented
+fun:xdr_void=uninstrumented
+fun:xdr_wrapstring=uninstrumented
+fun:xdr_yp_buf=uninstrumented
+fun:xdr_ypall=uninstrumented
+fun:xdr_ypbind_binding=uninstrumented
+fun:xdr_ypbind_resp=uninstrumented
+fun:xdr_ypbind_resptype=uninstrumented
+fun:xdr_ypbind_setdom=uninstrumented
+fun:xdr_ypdelete_args=uninstrumented
+fun:xdr_ypmap_parms=uninstrumented
+fun:xdr_ypmaplist=uninstrumented
+fun:xdr_yppush_status=uninstrumented
+fun:xdr_yppushresp_xfr=uninstrumented
+fun:xdr_ypreq_key=uninstrumented
+fun:xdr_ypreq_nokey=uninstrumented
+fun:xdr_ypreq_xfr=uninstrumented
+fun:xdr_ypresp_all=uninstrumented
+fun:xdr_ypresp_key_val=uninstrumented
+fun:xdr_ypresp_maplist=uninstrumented
+fun:xdr_ypresp_master=uninstrumented
+fun:xdr_ypresp_order=uninstrumented
+fun:xdr_ypresp_val=uninstrumented
+fun:xdr_ypresp_xfr=uninstrumented
+fun:xdr_ypstat=uninstrumented
+fun:xdr_ypupdate_args=uninstrumented
+fun:xdr_ypxfrstat=uninstrumented
+fun:xdrmem_create=uninstrumented
+fun:xdrrec_create=uninstrumented
+fun:xdrrec_endofrecord=uninstrumented
+fun:xdrrec_eof=uninstrumented
+fun:xdrrec_skiprecord=uninstrumented
+fun:xdrstdio_create=uninstrumented
+fun:xencrypt=uninstrumented
+fun:xprt_register=uninstrumented
+fun:xprt_unregister=uninstrumented
+fun:y0=uninstrumented
+fun:y0f=uninstrumented
+fun:y0l=uninstrumented
+fun:y1=uninstrumented
+fun:y1f=uninstrumented
+fun:y1l=uninstrumented
+fun:yn=uninstrumented
+fun:ynf=uninstrumented
+fun:ynl=uninstrumented
+fun:yp_all=uninstrumented
+fun:yp_bind=uninstrumented
+fun:yp_first=uninstrumented
+fun:yp_get_default_domain=uninstrumented
+fun:yp_maplist=uninstrumented
+fun:yp_master=uninstrumented
+fun:yp_match=uninstrumented
+fun:yp_next=uninstrumented
+fun:yp_order=uninstrumented
+fun:yp_unbind=uninstrumented
+fun:yp_update=uninstrumented
+fun:ypbinderr_string=uninstrumented
+fun:yperr_string=uninstrumented
+fun:ypprot_err=uninstrumented
diff --git a/lib/dfsan/lit_tests/CMakeLists.txt b/lib/dfsan/lit_tests/CMakeLists.txt
deleted file mode 100644
index d7c5c82ac3c0..000000000000
--- a/lib/dfsan/lit_tests/CMakeLists.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-set(DFSAN_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/..)
-set(DFSAN_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/..)
-
-configure_lit_site_cfg(
- ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
- ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg)
-
-if(COMPILER_RT_CAN_EXECUTE_TESTS)
- # Run DFSan tests only if we're sure we may produce working binaries.
- set(DFSAN_TEST_DEPS
- ${SANITIZER_COMMON_LIT_TEST_DEPS}
- ${DFSAN_RUNTIME_LIBRARIES}
- dfsan_abilist)
- set(DFSAN_TEST_PARAMS
- dfsan_site_config=${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg)
- add_lit_testsuite(check-dfsan "Running the DataFlowSanitizer tests"
- ${CMAKE_CURRENT_BINARY_DIR}
- PARAMS ${DFSAN_TEST_PARAMS}
- DEPENDS ${DFSAN_TEST_DEPS})
- set_target_properties(check-dfsan PROPERTIES FOLDER "DFSan tests")
-endif()
diff --git a/lib/dfsan/lit_tests/Inputs/flags_abilist.txt b/lib/dfsan/lit_tests/Inputs/flags_abilist.txt
deleted file mode 100644
index 94b1fa298259..000000000000
--- a/lib/dfsan/lit_tests/Inputs/flags_abilist.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-fun:f=uninstrumented
-
-fun:main=uninstrumented
-fun:main=discard
-
-fun:dfsan_create_label=uninstrumented
-fun:dfsan_create_label=discard
-
-fun:dfsan_set_label=uninstrumented
-fun:dfsan_set_label=discard
diff --git a/lib/dfsan/lit_tests/basic.c b/lib/dfsan/lit_tests/basic.c
deleted file mode 100644
index b566c9271d0b..000000000000
--- a/lib/dfsan/lit_tests/basic.c
+++ /dev/null
@@ -1,21 +0,0 @@
-// RUN: %clang_dfsan -m64 %s -o %t && %t
-// RUN: %clang_dfsan -mllvm -dfsan-args-abi -m64 %s -o %t && %t
-
-// Tests that labels are propagated through loads and stores.
-
-#include <sanitizer/dfsan_interface.h>
-#include <assert.h>
-
-int main(void) {
- int i = 1;
- dfsan_label i_label = dfsan_create_label("i", 0);
- dfsan_set_label(i_label, &i, sizeof(i));
-
- dfsan_label new_label = dfsan_get_label(i);
- assert(i_label == new_label);
-
- dfsan_label read_label = dfsan_read_label(&i, sizeof(i));
- assert(i_label == read_label);
-
- return 0;
-}
diff --git a/lib/dfsan/lit_tests/custom.c b/lib/dfsan/lit_tests/custom.c
deleted file mode 100644
index c9fa9356154d..000000000000
--- a/lib/dfsan/lit_tests/custom.c
+++ /dev/null
@@ -1,154 +0,0 @@
-// RUN: %clang_dfsan -m64 %s -o %t && %t
-// RUN: %clang_dfsan -mllvm -dfsan-args-abi -m64 %s -o %t && %t
-
-// Tests custom implementations of various libc functions.
-
-#define _GNU_SOURCE
-#include <sanitizer/dfsan_interface.h>
-#include <assert.h>
-#include <link.h>
-#include <pthread.h>
-#include <string.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-
-void *ptcb(void *p) {
- assert(p == (void *)1);
- assert(dfsan_get_label((uintptr_t)p) == 0);
- return (void *)2;
-}
-
-int dlcb(struct dl_phdr_info *info, size_t size, void *data) {
- assert(data == (void *)3);
- assert(dfsan_get_label((uintptr_t)info) == 0);
- assert(dfsan_get_label(size) == 0);
- assert(dfsan_get_label((uintptr_t)data) == 0);
- return 0;
-}
-
-int main(void) {
- int i = 1;
- dfsan_label i_label = dfsan_create_label("i", 0);
- dfsan_set_label(i_label, &i, sizeof(i));
-
- int j = 2;
- dfsan_label j_label = dfsan_create_label("j", 0);
- dfsan_set_label(j_label, &j, sizeof(j));
-
- struct stat s;
- s.st_dev = i;
- int rv = stat("/", &s);
- assert(rv == 0);
- assert(dfsan_get_label(s.st_dev) == 0);
-
- s.st_dev = i;
- rv = stat("/nonexistent", &s);
- assert(rv == -1);
- assert(dfsan_get_label(s.st_dev) == i_label);
-
- int fd = open("/dev/zero", O_RDONLY);
- s.st_dev = i;
- rv = fstat(fd, &s);
- assert(rv == 0);
- assert(dfsan_get_label(s.st_dev) == 0);
-
- char str1[] = "str1", str2[] = "str2";
- dfsan_set_label(i_label, &str1[3], 1);
- dfsan_set_label(j_label, &str2[3], 1);
-
- rv = memcmp(str1, str2, sizeof(str1));
- assert(rv < 0);
- assert(dfsan_get_label(rv) == dfsan_union(i_label, j_label));
-
- char strc[sizeof(str1)];
- memcpy(strc, str1, sizeof(str1));
- assert(dfsan_get_label(strc[0]) == 0);
- assert(dfsan_get_label(strc[3]) == i_label);
-
- memset(strc, j, sizeof(strc));
- assert(dfsan_get_label(strc[0]) == j_label);
- assert(dfsan_get_label(strc[1]) == j_label);
- assert(dfsan_get_label(strc[2]) == j_label);
- assert(dfsan_get_label(strc[3]) == j_label);
- assert(dfsan_get_label(strc[4]) == j_label);
-
- rv = strcmp(str1, str2);
- assert(rv < 0);
- assert(dfsan_get_label(rv) == dfsan_union(i_label, j_label));
-
- char *strd = strdup(str1);
- assert(dfsan_get_label(strd[0]) == 0);
- assert(dfsan_get_label(strd[3]) == i_label);
- free(strd);
-
- rv = strncmp(str1, str2, sizeof(str1));
- assert(rv < 0);
- assert(dfsan_get_label(rv) == dfsan_union(i_label, j_label));
-
- rv = strncmp(str1, str2, 3);
- assert(rv == 0);
- assert(dfsan_get_label(rv) == 0);
-
- str1[0] = 'S';
-
- rv = strncasecmp(str1, str2, sizeof(str1));
- assert(rv < 0);
- assert(dfsan_get_label(rv) == dfsan_union(i_label, j_label));
-
- rv = strncasecmp(str1, str2, 3);
- assert(rv == 0);
- assert(dfsan_get_label(rv) == 0);
-
- char *crv = strchr(str1, 'r');
- assert(crv == &str1[2]);
- assert(dfsan_get_label((uintptr_t)crv) == 0);
-
- crv = strchr(str1, '1');
- assert(crv == &str1[3]);
- assert(dfsan_get_label((uintptr_t)crv) == i_label);
-
- crv = strchr(str1, 'x');
- assert(crv == 0);
- assert(dfsan_get_label((uintptr_t)crv) == i_label);
-
- // With any luck this sequence of calls will cause calloc to return the same
- // pointer both times. This is probably the best we can do to test this
- // function.
- crv = calloc(4096, 1);
- assert(dfsan_get_label(crv[0]) == 0);
- free(crv);
-
- crv = calloc(4096, 1);
- assert(dfsan_get_label(crv[0]) == 0);
- free(crv);
-
- char buf[16];
- buf[0] = i;
- buf[15] = j;
- rv = read(fd, buf, sizeof(buf));
- assert(rv == sizeof(buf));
- assert(dfsan_get_label(buf[0]) == 0);
- assert(dfsan_get_label(buf[15]) == 0);
-
- close(fd);
- fd = open("/bin/sh", O_RDONLY);
- buf[0] = i;
- buf[15] = j;
- rv = pread(fd, buf, sizeof(buf), 0);
- assert(rv == sizeof(buf));
- assert(dfsan_get_label(buf[0]) == 0);
- assert(dfsan_get_label(buf[15]) == 0);
-
- pthread_t pt;
- pthread_create(&pt, 0, ptcb, (void *)1);
- void *cbrv;
- pthread_join(pt, &cbrv);
- assert(cbrv == (void *)2);
-
- dl_iterate_phdr(dlcb, (void *)3);
-
- return 0;
-}
diff --git a/lib/dfsan/lit_tests/flags.c b/lib/dfsan/lit_tests/flags.c
deleted file mode 100644
index 5cf970dce90d..000000000000
--- a/lib/dfsan/lit_tests/flags.c
+++ /dev/null
@@ -1,24 +0,0 @@
-// RUN: %clang_dfsan -m64 %s -fsanitize-blacklist=%S/Inputs/flags_abilist.txt -mllvm -dfsan-debug-nonzero-labels -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clang_dfsan -m64 %s -fsanitize-blacklist=%S/Inputs/flags_abilist.txt -mllvm -dfsan-debug-nonzero-labels -o %t && DFSAN_OPTIONS=warn_unimplemented=0 %t 2>&1 | count 0
-// RUN: %clang_dfsan -m64 %s -fsanitize-blacklist=%S/Inputs/flags_abilist.txt -mllvm -dfsan-debug-nonzero-labels -o %t && DFSAN_OPTIONS=warn_nonzero_labels=1 %t 2>&1 | FileCheck --check-prefix=CHECK-NONZERO %s
-
-// Tests that flags work correctly.
-
-#include <sanitizer/dfsan_interface.h>
-
-int f(int i) {
- return i;
-}
-
-int main(void) {
- int i = 1;
- dfsan_label i_label = dfsan_create_label("i", 0);
- dfsan_set_label(i_label, &i, sizeof(i));
-
- // CHECK: WARNING: DataFlowSanitizer: call to uninstrumented function f
- // CHECK-NOT: WARNING: DataFlowSanitizer: saw nonzero label
- // CHECK-NONZERO: WARNING: DataFlowSanitizer: saw nonzero label
- f(i);
-
- return 0;
-}
diff --git a/lib/dfsan/lit_tests/fncall.c b/lib/dfsan/lit_tests/fncall.c
deleted file mode 100644
index 15b77bd67902..000000000000
--- a/lib/dfsan/lit_tests/fncall.c
+++ /dev/null
@@ -1,26 +0,0 @@
-// RUN: %clang_dfsan -m64 %s -o %t && %t
-// RUN: %clang_dfsan -mllvm -dfsan-args-abi -m64 %s -o %t && %t
-
-// Tests that labels are propagated through function calls.
-
-#include <sanitizer/dfsan_interface.h>
-#include <assert.h>
-
-int f(int x) {
- int j = 2;
- dfsan_label j_label = dfsan_create_label("j", 0);
- dfsan_set_label(j_label, &j, sizeof(j));
- return x + j;
-}
-
-int main(void) {
- int i = 1;
- dfsan_label i_label = dfsan_create_label("i", 0);
- dfsan_set_label(i_label, &i, sizeof(i));
-
- dfsan_label ij_label = dfsan_get_label(f(i));
- assert(dfsan_has_label(ij_label, i_label));
- assert(dfsan_has_label_with_desc(ij_label, "j"));
-
- return 0;
-}
diff --git a/lib/dfsan/lit_tests/lit.cfg b/lib/dfsan/lit_tests/lit.cfg
deleted file mode 100644
index 19bc97690a86..000000000000
--- a/lib/dfsan/lit_tests/lit.cfg
+++ /dev/null
@@ -1,69 +0,0 @@
-# -*- Python -*-
-
-import os
-
-import lit.util
-
-def get_required_attr(config, attr_name):
- attr_value = getattr(config, attr_name, None)
- if not attr_value:
- lit_config.fatal(
- "No attribute %r in test configuration! You may need to run "
- "tests from your build directory or add this attribute "
- "to lit.site.cfg " % attr_name)
- return attr_value
-
-# Setup config name.
-config.name = 'DataFlowSanitizer'
-
-# Setup source root.
-config.test_source_root = os.path.dirname(__file__)
-
-def DisplayNoConfigMessage():
- lit_config.fatal("No site specific configuration available! " +
- "Try running your test from the build tree or running " +
- "make check-dfsan")
-
-# Figure out LLVM source root.
-llvm_src_root = getattr(config, 'llvm_src_root', None)
-if llvm_src_root is None:
- # We probably haven't loaded the site-specific configuration: the user
- # is likely trying to run a test file directly, and the site configuration
- # wasn't created by the build system.
- dfsan_site_cfg = lit_config.params.get('dfsan_site_config', None)
- if (dfsan_site_cfg) and (os.path.exists(dfsan_site_cfg)):
- lit_config.load_config(config, dfsan_site_cfg)
- raise SystemExit
-
- # Try to guess the location of site-specific configuration using llvm-config
- # util that can point where the build tree is.
- llvm_config = lit.util.which("llvm-config", config.environment["PATH"])
- if not llvm_config:
- DisplayNoConfigMessage()
-
- # Find out the presumed location of generated site config.
- llvm_obj_root = lit.util.capture(["llvm-config", "--obj-root"]).strip()
- dfsan_site_cfg = os.path.join(llvm_obj_root, "projects", "compiler-rt",
- "lib", "dfsan", "lit_tests", "lit.site.cfg")
- if (not dfsan_site_cfg) or (not os.path.exists(dfsan_site_cfg)):
- DisplayNoConfigMessage()
-
- lit_config.load_config(config, dfsan_site_cfg)
- raise SystemExit
-
-# Setup default compiler flags used with -fsanitize=dataflow option.
-clang_dfsan_cflags = ["-fsanitize=dataflow"]
-clang_dfsan_cxxflags = ["--driver-mode=g++ "] + clang_dfsan_cflags
-config.substitutions.append( ("%clang_dfsan ",
- " ".join([config.clang] + clang_dfsan_cflags) +
- " ") )
-config.substitutions.append( ("%clangxx_dfsan ",
- " ".join([config.clang] + clang_dfsan_cxxflags) +
- " ") )
-
-# Default test suffixes.
-config.suffixes = ['.c', '.cc', '.cpp']
-
-# DataFlowSanitizer tests are currently supported on Linux only.
-if config.host_os not in ['Linux']:
- config.unsupported = True
diff --git a/lib/dfsan/lit_tests/lit.site.cfg.in b/lib/dfsan/lit_tests/lit.site.cfg.in
deleted file mode 100644
index 0cf6d6b5580f..000000000000
--- a/lib/dfsan/lit_tests/lit.site.cfg.in
+++ /dev/null
@@ -1,5 +0,0 @@
-# Load common config for all compiler-rt lit tests.
-lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/lib/lit.common.configured")
-
-# Load tool-specific config that would do the real work.
-lit_config.load_config(config, "@DFSAN_SOURCE_DIR@/lit_tests/lit.cfg")
diff --git a/lib/dfsan/lit_tests/propagate.c b/lib/dfsan/lit_tests/propagate.c
deleted file mode 100644
index 86d182b8a7fc..000000000000
--- a/lib/dfsan/lit_tests/propagate.c
+++ /dev/null
@@ -1,47 +0,0 @@
-// RUN: %clang_dfsan -m64 %s -o %t && %t
-// RUN: %clang_dfsan -mllvm -dfsan-args-abi -m64 %s -o %t && %t
-
-// Tests that labels are propagated through computation and that union labels
-// are properly created.
-
-#include <sanitizer/dfsan_interface.h>
-#include <assert.h>
-
-int main(void) {
- assert(dfsan_union(0, 0) == 0);
-
- int i = 1;
- dfsan_label i_label = dfsan_create_label("i", 0);
- dfsan_set_label(i_label, &i, sizeof(i));
-
- int j = 2;
- dfsan_label j_label = dfsan_create_label("j", 0);
- dfsan_set_label(j_label, &j, sizeof(j));
-
- int k = 3;
- dfsan_label k_label = dfsan_create_label("k", 0);
- dfsan_set_label(k_label, &k, sizeof(k));
-
- int k2 = 4;
- dfsan_set_label(k_label, &k2, sizeof(k2));
-
- dfsan_label ij_label = dfsan_get_label(i + j);
- assert(dfsan_has_label(ij_label, i_label));
- assert(dfsan_has_label(ij_label, j_label));
- assert(!dfsan_has_label(ij_label, k_label));
- // Test uniquing.
- assert(dfsan_union(i_label, j_label) == ij_label);
- assert(dfsan_union(j_label, i_label) == ij_label);
-
- dfsan_label ijk_label = dfsan_get_label(i + j + k);
- assert(dfsan_has_label(ijk_label, i_label));
- assert(dfsan_has_label(ijk_label, j_label));
- assert(dfsan_has_label(ijk_label, k_label));
-
- assert(dfsan_get_label(k + k2) == k_label);
-
- struct { int i, j; } s = { i, j };
- assert(dfsan_read_label(&s, sizeof(s)) == ij_label);
-
- return 0;
-}
diff --git a/lib/dfsan/scripts/build-libc-list.py b/lib/dfsan/scripts/build-libc-list.py
index 8f6b8d513631..eddb6c07e99d 100755
--- a/lib/dfsan/scripts/build-libc-list.py
+++ b/lib/dfsan/scripts/build-libc-list.py
@@ -26,27 +26,38 @@ def defined_function_list(object):
raise subprocess.CalledProcessError(readelf_proc.returncode, 'readelf')
for line in readelf:
if (line[31:35] == 'FUNC' or line[31:36] == 'IFUNC') and \
+ line[39:44] != 'LOCAL' and \
line[55:58] != 'UND':
function_name = line[59:].split('@')[0]
functions.append(function_name)
return functions
p = OptionParser()
-p.add_option('--lib', metavar='PATH',
- help='path to lib directory to use',
+
+p.add_option('--libc-dso-path', metavar='PATH',
+ help='path to libc DSO directory',
default='/lib/x86_64-linux-gnu')
-p.add_option('--usrlib', metavar='PATH',
- help='path to usr/lib directory to use',
+p.add_option('--libc-archive-path', metavar='PATH',
+ help='path to libc archive directory',
default='/usr/lib/x86_64-linux-gnu')
-p.add_option('--gcclib', metavar='PATH',
- help='path to gcc lib directory to use',
+
+p.add_option('--libgcc-dso-path', metavar='PATH',
+ help='path to libgcc DSO directory',
+ default='/lib/x86_64-linux-gnu')
+p.add_option('--libgcc-archive-path', metavar='PATH',
+ help='path to libgcc archive directory',
default='/usr/lib/gcc/x86_64-linux-gnu/4.6')
+
p.add_option('--with-libstdcxx', action='store_true',
dest='with_libstdcxx',
help='include libstdc++ in the list (inadvisable)')
+p.add_option('--libstdcxx-dso-path', metavar='PATH',
+ help='path to libstdc++ DSO directory',
+ default='/usr/lib/x86_64-linux-gnu')
+
(options, args) = p.parse_args()
-libs = [os.path.join(options.lib, name) for name in
+libs = [os.path.join(options.libc_dso_path, name) for name in
['ld-linux-x86-64.so.2',
'libanl.so.1',
'libBrokenLocale.so.1',
@@ -61,14 +72,15 @@ libs = [os.path.join(options.lib, name) for name in
'librt.so.1',
'libthread_db.so.1',
'libutil.so.1']]
-libs += [os.path.join(options.usrlib, name) for name in
+libs += [os.path.join(options.libc_archive_path, name) for name in
['libc_nonshared.a',
'libpthread_nonshared.a']]
-gcclibs = ['libgcc.a',
- 'libgcc_s.so']
+
+libs.append(os.path.join(options.libgcc_dso_path, 'libgcc_s.so.1'))
+libs.append(os.path.join(options.libgcc_archive_path, 'libgcc.a'))
+
if options.with_libstdcxx:
- gcclibs += ['libstdc++.so']
-libs += [os.path.join(options.gcclib, name) for name in gcclibs]
+ libs.append(os.path.join(options.libstdcxx_dso_path, 'libstdc++.so.6'))
functions = []
for l in libs:
diff --git a/lib/dfsan/scripts/check_custom_wrappers.sh b/lib/dfsan/scripts/check_custom_wrappers.sh
new file mode 100755
index 000000000000..50bc85d4aef5
--- /dev/null
+++ b/lib/dfsan/scripts/check_custom_wrappers.sh
@@ -0,0 +1,50 @@
+#!/bin/sh
+
+DFSAN_DIR=$(dirname "$0")/../
+DFSAN_CUSTOM_TESTS=${DFSAN_DIR}/../../test/dfsan/custom.cc
+DFSAN_CUSTOM_WRAPPERS=${DFSAN_DIR}/dfsan_custom.cc
+DFSAN_ABI_LIST=${DFSAN_DIR}/done_abilist.txt
+
+DIFFOUT=$(mktemp -q /tmp/tmp.XXXXXXXXXX)
+ERRORLOG=$(mktemp -q /tmp/tmp.XXXXXXXXXX)
+DIFF_A=$(mktemp -q /tmp/tmp.XXXXXXXXXX)
+DIFF_B=$(mktemp -q /tmp/tmp.XXXXXXXXXX)
+
+on_exit() {
+ rm -f ${DIFFOUT} 2> /dev/null
+ rm -f ${ERRORLOG} 2> /dev/null
+ rm -f ${DIFF_A} 2> /dev/null
+ rm -f ${DIFF_B} 2> /dev/null
+}
+
+trap on_exit EXIT
+grep -E "^fun:.*=custom" ${DFSAN_ABI_LIST} | grep -v "dfsan_get_label" \
+ | sed "s/^fun:\(.*\)=custom.*/\1/" | sort > $DIFF_A
+grep -E "__dfsw.*\(" ${DFSAN_CUSTOM_WRAPPERS} \
+ | sed "s/.*__dfsw_\(.*\)(.*/\1/" | sort > $DIFF_B
+diff -u $DIFF_A $DIFF_B > ${DIFFOUT}
+if [ $? -ne 0 ]
+then
+ echo -n "The following differences between the ABI list and ">> ${ERRORLOG}
+ echo "the implemented custom wrappers have been found:" >> ${ERRORLOG}
+ cat ${DIFFOUT} >> ${ERRORLOG}
+fi
+
+grep -E __dfsw_ ${DFSAN_CUSTOM_WRAPPERS} \
+ | sed "s/.*__dfsw_\([^(]*\).*/\1/" | sort > $DIFF_A
+grep -E "^\\s*test_.*\(\);" ${DFSAN_CUSTOM_TESTS} \
+ | sed "s/.*test_\(.*\)();/\1/" | sort > $DIFF_B
+diff -u $DIFF_A $DIFF_B > ${DIFFOUT}
+if [ $? -ne 0 ]
+then
+ echo -n "The following differences between the implemented " >> ${ERRORLOG}
+ echo "custom wrappers and the tests have been found:" >> ${ERRORLOG}
+ cat ${DIFFOUT} >> ${ERRORLOG}
+fi
+
+if [ -s ${ERRORLOG} ]
+then
+ cat ${ERRORLOG}
+ exit 1
+fi
+
diff --git a/lib/divdc3.c b/lib/divdc3.c
deleted file mode 100644
index cfbc498e7b44..000000000000
--- a/lib/divdc3.c
+++ /dev/null
@@ -1,60 +0,0 @@
-/* ===-- divdc3.c - Implement __divdc3 -------------------------------------===
- *
- * 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 __divdc3 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-#include "int_math.h"
-
-/* Returns: the quotient of (a + ib) / (c + id) */
-
-double _Complex
-__divdc3(double __a, double __b, double __c, double __d)
-{
- int __ilogbw = 0;
- double __logbw = crt_logb(crt_fmax(crt_fabs(__c), crt_fabs(__d)));
- if (crt_isfinite(__logbw))
- {
- __ilogbw = (int)__logbw;
- __c = crt_scalbn(__c, -__ilogbw);
- __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))
- {
- 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;
- }
- 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);
- }
- 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);
- }
- }
- return z;
-}
diff --git a/lib/divdf3.c b/lib/divdf3.c
deleted file mode 100644
index efce6bb4bedc..000000000000
--- a/lib/divdf3.c
+++ /dev/null
@@ -1,184 +0,0 @@
-//===-- lib/divdf3.c - Double-precision division ------------------*- 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 double-precision soft-float division
-// with the IEEE-754 default rounding (to nearest, ties to even).
-//
-// For simplicity, this implementation currently flushes denormals to zero.
-// It should be a fairly straightforward exercise to implement gradual
-// underflow with correct rounding.
-//
-//===----------------------------------------------------------------------===//
-
-#define DOUBLE_PRECISION
-#include "fp_lib.h"
-
-ARM_EABI_FNALIAS(ddiv, divdf3)
-
-fp_t __divdf3(fp_t a, fp_t b) {
-
- const unsigned int aExponent = toRep(a) >> significandBits & maxExponent;
- const unsigned int bExponent = toRep(b) >> significandBits & maxExponent;
- const rep_t quotientSign = (toRep(a) ^ toRep(b)) & signBit;
-
- rep_t aSignificand = toRep(a) & significandMask;
- rep_t bSignificand = toRep(b) & significandMask;
- int scale = 0;
-
- // Detect if a or b is zero, denormal, infinity, or NaN.
- if (aExponent-1U >= maxExponent-1U || bExponent-1U >= maxExponent-1U) {
-
- const rep_t aAbs = toRep(a) & absMask;
- const rep_t bAbs = toRep(b) & absMask;
-
- // NaN / anything = qNaN
- if (aAbs > infRep) return fromRep(toRep(a) | quietBit);
- // anything / NaN = qNaN
- if (bAbs > infRep) return fromRep(toRep(b) | quietBit);
-
- if (aAbs == infRep) {
- // infinity / infinity = NaN
- if (bAbs == infRep) return fromRep(qnanRep);
- // infinity / anything else = +/- infinity
- else return fromRep(aAbs | quotientSign);
- }
-
- // anything else / infinity = +/- 0
- if (bAbs == infRep) return fromRep(quotientSign);
-
- if (!aAbs) {
- // zero / zero = NaN
- if (!bAbs) return fromRep(qnanRep);
- // zero / anything else = +/- zero
- else return fromRep(quotientSign);
- }
- // anything else / zero = +/- infinity
- if (!bAbs) return fromRep(infRep | quotientSign);
-
- // one or both of a or b is denormal, the other (if applicable) is a
- // normal number. Renormalize one or both of a and b, and set scale to
- // include the necessary exponent adjustment.
- if (aAbs < implicitBit) scale += normalize(&aSignificand);
- if (bAbs < implicitBit) scale -= normalize(&bSignificand);
- }
-
- // Or in the implicit significand bit. (If we fell through from the
- // denormal path it was already set by normalize( ), but setting it twice
- // won't hurt anything.)
- aSignificand |= implicitBit;
- bSignificand |= implicitBit;
- int quotientExponent = aExponent - bExponent + scale;
-
- // Align the significand of b as a Q31 fixed-point number in the range
- // [1, 2.0) and get a Q32 approximate reciprocal using a small minimax
- // polynomial approximation: reciprocal = 3/4 + 1/sqrt(2) - b/2. This
- // is accurate to about 3.5 binary digits.
- const uint32_t q31b = bSignificand >> 21;
- uint32_t recip32 = UINT32_C(0x7504f333) - q31b;
-
- // Now refine the reciprocal estimate using a Newton-Raphson iteration:
- //
- // x1 = x0 * (2 - x0 * b)
- //
- // This doubles the number of correct binary digits in the approximation
- // with each iteration, so after three iterations, we have about 28 binary
- // digits of accuracy.
- uint32_t correction32;
- correction32 = -((uint64_t)recip32 * q31b >> 32);
- recip32 = (uint64_t)recip32 * correction32 >> 31;
- correction32 = -((uint64_t)recip32 * q31b >> 32);
- recip32 = (uint64_t)recip32 * correction32 >> 31;
- correction32 = -((uint64_t)recip32 * q31b >> 32);
- recip32 = (uint64_t)recip32 * correction32 >> 31;
-
- // recip32 might have overflowed to exactly zero in the preceeding
- // computation if the high word of b is exactly 1.0. This would sabotage
- // the full-width final stage of the computation that follows, so we adjust
- // recip32 downward by one bit.
- recip32--;
-
- // We need to perform one more iteration to get us to 56 binary digits;
- // The last iteration needs to happen with extra precision.
- const uint32_t q63blo = bSignificand << 11;
- uint64_t correction, reciprocal;
- correction = -((uint64_t)recip32*q31b + ((uint64_t)recip32*q63blo >> 32));
- uint32_t cHi = correction >> 32;
- uint32_t cLo = correction;
- reciprocal = (uint64_t)recip32*cHi + ((uint64_t)recip32*cLo >> 32);
-
- // We already adjusted the 32-bit estimate, now we need to adjust the final
- // 64-bit reciprocal estimate downward to ensure that it is strictly smaller
- // than the infinitely precise exact reciprocal. Because the computation
- // of the Newton-Raphson step is truncating at every step, this adjustment
- // is small; most of the work is already done.
- reciprocal -= 2;
-
- // The numerical reciprocal is accurate to within 2^-56, lies in the
- // interval [0.5, 1.0), and is strictly smaller than the true reciprocal
- // of b. Multiplying a by this reciprocal thus gives a numerical q = a/b
- // in Q53 with the following properties:
- //
- // 1. q < a/b
- // 2. q is in the interval [0.5, 2.0)
- // 3. the error in q is bounded away from 2^-53 (actually, we have a
- // couple of bits to spare, but this is all we need).
-
- // We need a 64 x 64 multiply high to compute q, which isn't a basic
- // operation in C, so we need to be a little bit fussy.
- rep_t quotient, quotientLo;
- wideMultiply(aSignificand << 2, reciprocal, &quotient, &quotientLo);
-
- // Two cases: quotient is in [0.5, 1.0) or quotient is in [1.0, 2.0).
- // In either case, we are going to compute a residual of the form
- //
- // r = a - q*b
- //
- // We know from the construction of q that r satisfies:
- //
- // 0 <= r < ulp(q)*b
- //
- // if r is greater than 1/2 ulp(q)*b, then q rounds up. Otherwise, we
- // already have the correct result. The exact halfway case cannot occur.
- // We also take this time to right shift quotient if it falls in the [1,2)
- // range and adjust the exponent accordingly.
- rep_t residual;
- if (quotient < (implicitBit << 1)) {
- residual = (aSignificand << 53) - quotient * bSignificand;
- quotientExponent--;
- } else {
- quotient >>= 1;
- residual = (aSignificand << 52) - quotient * bSignificand;
- }
-
- const int writtenExponent = quotientExponent + exponentBias;
-
- if (writtenExponent >= maxExponent) {
- // If we have overflowed the exponent, return infinity.
- return fromRep(infRep | quotientSign);
- }
-
- else if (writtenExponent < 1) {
- // Flush denormals to zero. In the future, it would be nice to add
- // code to round them correctly.
- return fromRep(quotientSign);
- }
-
- else {
- const bool round = (residual << 1) > bSignificand;
- // Clear the implicit bit
- rep_t absResult = quotient & significandMask;
- // Insert the exponent
- absResult |= (rep_t)writtenExponent << significandBits;
- // Round
- absResult += round;
- // Insert the sign and return
- const double result = fromRep(absResult | quotientSign);
- return result;
- }
-}
diff --git a/lib/divdi3.c b/lib/divdi3.c
deleted file mode 100644
index 2c2bcc26d581..000000000000
--- a/lib/divdi3.c
+++ /dev/null
@@ -1,31 +0,0 @@
-/* ===-- divdi3.c - Implement __divdi3 -------------------------------------===
- *
- * 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 __divdi3 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-du_int COMPILER_RT_ABI __udivmoddi4(du_int a, du_int b, du_int* rem);
-
-/* Returns: a / b */
-
-COMPILER_RT_ABI di_int
-__divdi3(di_int a, di_int b)
-{
- const int bits_in_dword_m1 = (int)(sizeof(di_int) * CHAR_BIT) - 1;
- di_int s_a = a >> bits_in_dword_m1; /* s_a = a < 0 ? -1 : 0 */
- di_int s_b = b >> bits_in_dword_m1; /* s_b = b < 0 ? -1 : 0 */
- a = (a ^ s_a) - s_a; /* negate if s_a == -1 */
- b = (b ^ s_b) - s_b; /* negate if s_b == -1 */
- s_a ^= s_b; /*sign of quotient */
- return (__udivmoddi4(a, b, (du_int*)0) ^ s_a) - s_a; /* negate if s_a == -1 */
-}
diff --git a/lib/divmoddi4.c b/lib/divmoddi4.c
deleted file mode 100644
index 2fe2b48183ff..000000000000
--- a/lib/divmoddi4.c
+++ /dev/null
@@ -1,27 +0,0 @@
-/*===-- divmoddi4.c - Implement __divmoddi4 --------------------------------===
- *
- * 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 __divmoddi4 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-extern COMPILER_RT_ABI di_int __divdi3(di_int a, di_int b);
-
-/* Returns: a / b, *rem = a % b */
-
-COMPILER_RT_ABI di_int
-__divmoddi4(di_int a, di_int b, di_int* rem)
-{
- di_int d = __divdi3(a,b);
- *rem = a - (d*b);
- return d;
-}
diff --git a/lib/divmodsi4.c b/lib/divmodsi4.c
deleted file mode 100644
index c7f7b1a7c322..000000000000
--- a/lib/divmodsi4.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/*===-- divmodsi4.c - Implement __divmodsi4 --------------------------------===
- *
- * 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 __divmodsi4 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-extern COMPILER_RT_ABI si_int __divsi3(si_int a, si_int b);
-
-
-/* Returns: a / b, *rem = a % b */
-
-COMPILER_RT_ABI si_int
-__divmodsi4(si_int a, si_int b, si_int* rem)
-{
- si_int d = __divsi3(a,b);
- *rem = a - (d*b);
- return d;
-}
-
-
diff --git a/lib/divsc3.c b/lib/divsc3.c
deleted file mode 100644
index caa0c4075eb3..000000000000
--- a/lib/divsc3.c
+++ /dev/null
@@ -1,60 +0,0 @@
-/*===-- divsc3.c - Implement __divsc3 -------------------------------------===
- *
- * 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 __divsc3 for the compiler_rt library.
- *
- *===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-#include "int_math.h"
-
-/* Returns: the quotient of (a + ib) / (c + id) */
-
-float _Complex
-__divsc3(float __a, float __b, float __c, float __d)
-{
- int __ilogbw = 0;
- float __logbw = crt_logbf(crt_fmaxf(crt_fabsf(__c), crt_fabsf(__d)));
- if (crt_isfinite(__logbw))
- {
- __ilogbw = (int)__logbw;
- __c = crt_scalbnf(__c, -__ilogbw);
- __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))
- {
- 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;
- }
- 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);
- }
- 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);
- }
- }
- return z;
-}
diff --git a/lib/divsf3.c b/lib/divsf3.c
deleted file mode 100644
index c91c648fa24c..000000000000
--- a/lib/divsf3.c
+++ /dev/null
@@ -1,168 +0,0 @@
-//===-- lib/divsf3.c - Single-precision division ------------------*- 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 single-precision soft-float division
-// with the IEEE-754 default rounding (to nearest, ties to even).
-//
-// For simplicity, this implementation currently flushes denormals to zero.
-// It should be a fairly straightforward exercise to implement gradual
-// underflow with correct rounding.
-//
-//===----------------------------------------------------------------------===//
-
-#define SINGLE_PRECISION
-#include "fp_lib.h"
-
-ARM_EABI_FNALIAS(fdiv, divsf3)
-
-fp_t __divsf3(fp_t a, fp_t b) {
-
- const unsigned int aExponent = toRep(a) >> significandBits & maxExponent;
- const unsigned int bExponent = toRep(b) >> significandBits & maxExponent;
- const rep_t quotientSign = (toRep(a) ^ toRep(b)) & signBit;
-
- rep_t aSignificand = toRep(a) & significandMask;
- rep_t bSignificand = toRep(b) & significandMask;
- int scale = 0;
-
- // Detect if a or b is zero, denormal, infinity, or NaN.
- if (aExponent-1U >= maxExponent-1U || bExponent-1U >= maxExponent-1U) {
-
- const rep_t aAbs = toRep(a) & absMask;
- const rep_t bAbs = toRep(b) & absMask;
-
- // NaN / anything = qNaN
- if (aAbs > infRep) return fromRep(toRep(a) | quietBit);
- // anything / NaN = qNaN
- if (bAbs > infRep) return fromRep(toRep(b) | quietBit);
-
- if (aAbs == infRep) {
- // infinity / infinity = NaN
- if (bAbs == infRep) return fromRep(qnanRep);
- // infinity / anything else = +/- infinity
- else return fromRep(aAbs | quotientSign);
- }
-
- // anything else / infinity = +/- 0
- if (bAbs == infRep) return fromRep(quotientSign);
-
- if (!aAbs) {
- // zero / zero = NaN
- if (!bAbs) return fromRep(qnanRep);
- // zero / anything else = +/- zero
- else return fromRep(quotientSign);
- }
- // anything else / zero = +/- infinity
- if (!bAbs) return fromRep(infRep | quotientSign);
-
- // one or both of a or b is denormal, the other (if applicable) is a
- // normal number. Renormalize one or both of a and b, and set scale to
- // include the necessary exponent adjustment.
- if (aAbs < implicitBit) scale += normalize(&aSignificand);
- if (bAbs < implicitBit) scale -= normalize(&bSignificand);
- }
-
- // Or in the implicit significand bit. (If we fell through from the
- // denormal path it was already set by normalize( ), but setting it twice
- // won't hurt anything.)
- aSignificand |= implicitBit;
- bSignificand |= implicitBit;
- int quotientExponent = aExponent - bExponent + scale;
-
- // Align the significand of b as a Q31 fixed-point number in the range
- // [1, 2.0) and get a Q32 approximate reciprocal using a small minimax
- // polynomial approximation: reciprocal = 3/4 + 1/sqrt(2) - b/2. This
- // is accurate to about 3.5 binary digits.
- uint32_t q31b = bSignificand << 8;
- uint32_t reciprocal = UINT32_C(0x7504f333) - q31b;
-
- // Now refine the reciprocal estimate using a Newton-Raphson iteration:
- //
- // x1 = x0 * (2 - x0 * b)
- //
- // This doubles the number of correct binary digits in the approximation
- // with each iteration, so after three iterations, we have about 28 binary
- // digits of accuracy.
- uint32_t correction;
- correction = -((uint64_t)reciprocal * q31b >> 32);
- reciprocal = (uint64_t)reciprocal * correction >> 31;
- correction = -((uint64_t)reciprocal * q31b >> 32);
- reciprocal = (uint64_t)reciprocal * correction >> 31;
- correction = -((uint64_t)reciprocal * q31b >> 32);
- reciprocal = (uint64_t)reciprocal * correction >> 31;
-
- // Exhaustive testing shows that the error in reciprocal after three steps
- // is in the interval [-0x1.f58108p-31, 0x1.d0e48cp-29], in line with our
- // expectations. We bump the reciprocal by a tiny value to force the error
- // to be strictly positive (in the range [0x1.4fdfp-37,0x1.287246p-29], to
- // be specific). This also causes 1/1 to give a sensible approximation
- // instead of zero (due to overflow).
- reciprocal -= 2;
-
- // The numerical reciprocal is accurate to within 2^-28, lies in the
- // interval [0x1.000000eep-1, 0x1.fffffffcp-1], and is strictly smaller
- // than the true reciprocal of b. Multiplying a by this reciprocal thus
- // gives a numerical q = a/b in Q24 with the following properties:
- //
- // 1. q < a/b
- // 2. q is in the interval [0x1.000000eep-1, 0x1.fffffffcp0)
- // 3. the error in q is at most 2^-24 + 2^-27 -- the 2^24 term comes
- // from the fact that we truncate the product, and the 2^27 term
- // is the error in the reciprocal of b scaled by the maximum
- // possible value of a. As a consequence of this error bound,
- // either q or nextafter(q) is the correctly rounded
- rep_t quotient = (uint64_t)reciprocal*(aSignificand << 1) >> 32;
-
- // Two cases: quotient is in [0.5, 1.0) or quotient is in [1.0, 2.0).
- // In either case, we are going to compute a residual of the form
- //
- // r = a - q*b
- //
- // We know from the construction of q that r satisfies:
- //
- // 0 <= r < ulp(q)*b
- //
- // if r is greater than 1/2 ulp(q)*b, then q rounds up. Otherwise, we
- // already have the correct result. The exact halfway case cannot occur.
- // We also take this time to right shift quotient if it falls in the [1,2)
- // range and adjust the exponent accordingly.
- rep_t residual;
- if (quotient < (implicitBit << 1)) {
- residual = (aSignificand << 24) - quotient * bSignificand;
- quotientExponent--;
- } else {
- quotient >>= 1;
- residual = (aSignificand << 23) - quotient * bSignificand;
- }
-
- const int writtenExponent = quotientExponent + exponentBias;
-
- if (writtenExponent >= maxExponent) {
- // If we have overflowed the exponent, return infinity.
- return fromRep(infRep | quotientSign);
- }
-
- else if (writtenExponent < 1) {
- // Flush denormals to zero. In the future, it would be nice to add
- // code to round them correctly.
- return fromRep(quotientSign);
- }
-
- else {
- const bool round = (residual << 1) > bSignificand;
- // Clear the implicit bit
- rep_t absResult = quotient & significandMask;
- // Insert the exponent
- absResult |= (rep_t)writtenExponent << significandBits;
- // Round
- absResult += round;
- // Insert the sign and return
- return fromRep(absResult | quotientSign);
- }
-}
diff --git a/lib/divsi3.c b/lib/divsi3.c
deleted file mode 100644
index cd19de9525c0..000000000000
--- a/lib/divsi3.c
+++ /dev/null
@@ -1,39 +0,0 @@
-/* ===-- divsi3.c - Implement __divsi3 -------------------------------------===
- *
- * 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 __divsi3 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-su_int COMPILER_RT_ABI __udivsi3(su_int n, su_int d);
-
-/* Returns: a / b */
-
-ARM_EABI_FNALIAS(idiv, divsi3)
-
-COMPILER_RT_ABI si_int
-__divsi3(si_int a, si_int b)
-{
- const int bits_in_word_m1 = (int)(sizeof(si_int) * CHAR_BIT) - 1;
- si_int s_a = a >> bits_in_word_m1; /* s_a = a < 0 ? -1 : 0 */
- si_int s_b = b >> bits_in_word_m1; /* s_b = b < 0 ? -1 : 0 */
- a = (a ^ s_a) - s_a; /* negate if s_a == -1 */
- b = (b ^ s_b) - s_b; /* negate if s_b == -1 */
- s_a ^= s_b; /* sign of quotient */
- /*
- * On CPUs without unsigned hardware division support,
- * this calls __udivsi3 (notice the cast to su_int).
- * On CPUs with unsigned hardware division support,
- * this uses the unsigned division instruction.
- */
- return ((su_int)a/(su_int)b ^ s_a) - s_a; /* negate if s_a == -1 */
-}
diff --git a/lib/divti3.c b/lib/divti3.c
deleted file mode 100644
index 0242c13683f8..000000000000
--- a/lib/divti3.c
+++ /dev/null
@@ -1,35 +0,0 @@
-/* ===-- divti3.c - Implement __divti3 -------------------------------------===
- *
- * 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 __divti3 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-#if __x86_64
-
-tu_int __udivmodti4(tu_int a, tu_int b, tu_int* rem);
-
-/* Returns: a / b */
-
-ti_int
-__divti3(ti_int a, ti_int b)
-{
- const int bits_in_tword_m1 = (int)(sizeof(ti_int) * CHAR_BIT) - 1;
- ti_int s_a = a >> bits_in_tword_m1; /* s_a = a < 0 ? -1 : 0 */
- ti_int s_b = b >> bits_in_tword_m1; /* s_b = b < 0 ? -1 : 0 */
- a = (a ^ s_a) - s_a; /* negate if s_a == -1 */
- b = (b ^ s_b) - s_b; /* negate if s_b == -1 */
- s_a ^= s_b; /* sign of quotient */
- return (__udivmodti4(a, b, (tu_int*)0) ^ s_a) - s_a; /* negate if s_a == -1 */
-}
-
-#endif
diff --git a/lib/divxc3.c b/lib/divxc3.c
deleted file mode 100644
index 5f240e956d84..000000000000
--- a/lib/divxc3.c
+++ /dev/null
@@ -1,63 +0,0 @@
-/* ===-- divxc3.c - Implement __divxc3 -------------------------------------===
- *
- * 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 __divxc3 for the compiler_rt library.
- *
- */
-
-#if !_ARCH_PPC
-
-#include "int_lib.h"
-#include "int_math.h"
-
-/* Returns: the quotient of (a + ib) / (c + id) */
-
-long double _Complex
-__divxc3(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) && (!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, __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);
- }
- 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);
- }
- }
- return z;
-}
-
-#endif
diff --git a/lib/enable_execute_stack.c b/lib/enable_execute_stack.c
deleted file mode 100644
index 278ca246f537..000000000000
--- a/lib/enable_execute_stack.c
+++ /dev/null
@@ -1,59 +0,0 @@
-/* ===-- enable_execute_stack.c - Implement __enable_execute_stack ---------===
- *
- * 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 "int_lib.h"
-
-#include <sys/mman.h>
-
-/* #include "config.h"
- * FIXME: CMake - include when cmake system is ready.
- * Remove #define HAVE_SYSCONF 1 line.
- */
-#define HAVE_SYSCONF 1
-
-#ifndef __APPLE__
-#include <unistd.h>
-#endif /* __APPLE__ */
-
-#if __LP64__
- #define TRAMPOLINE_SIZE 48
-#else
- #define TRAMPOLINE_SIZE 40
-#endif
-
-/*
- * The compiler generates calls to __enable_execute_stack() when creating
- * trampoline functions on the stack for use with nested functions.
- * It is expected to mark the page(s) containing the address
- * and the next 48 bytes as executable. Since the stack is normally rw-
- * that means changing the protection on those page(s) to rwx.
- */
-
-void __enable_execute_stack(void* addr)
-{
-
-#if __APPLE__
- /* On Darwin, pagesize is always 4096 bytes */
- const uintptr_t pageSize = 4096;
-#elif !defined(HAVE_SYSCONF)
-#error "HAVE_SYSCONF not defined! See enable_execute_stack.c"
-#else
- const uintptr_t pageSize = sysconf(_SC_PAGESIZE);
-#endif /* __APPLE__ */
-
- const uintptr_t pageAlignMask = ~(pageSize-1);
- uintptr_t p = (uintptr_t)addr;
- unsigned char* startPage = (unsigned char*)(p & pageAlignMask);
- unsigned char* endPage = (unsigned char*)((p+TRAMPOLINE_SIZE+pageSize) & pageAlignMask);
- size_t length = endPage - startPage;
- (void) mprotect((void *)startPage, length, PROT_READ | PROT_WRITE | PROT_EXEC);
-}
-
-
diff --git a/lib/eprintf.c b/lib/eprintf.c
deleted file mode 100644
index 3626dbf8b0c4..000000000000
--- a/lib/eprintf.c
+++ /dev/null
@@ -1,34 +0,0 @@
-/* ===---------- eprintf.c - Implements __eprintf --------------------------===
- *
- * 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 "int_lib.h"
-#include <stdio.h>
-
-
-/*
- * __eprintf() was used in an old version of <assert.h>.
- * It can eventually go away, but it is needed when linking
- * .o files built with the old <assert.h>.
- *
- * It should never be exported from a dylib, so it is marked
- * visibility hidden.
- */
-#ifndef _WIN32
-__attribute__((visibility("hidden")))
-#endif
-void __eprintf(const char* format, const char* assertion_expression,
- const char* line, const char* file)
-{
- fprintf(stderr, format, assertion_expression, line, file);
- fflush(stderr);
- compilerrt_abort();
-}
diff --git a/lib/extendsfdf2.c b/lib/extendsfdf2.c
deleted file mode 100644
index 91fd2b436a33..000000000000
--- a/lib/extendsfdf2.c
+++ /dev/null
@@ -1,137 +0,0 @@
-//===-- lib/extendsfdf2.c - single -> double 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 a fairly generic conversion from a narrower to a wider
-// IEEE-754 floating-point type. The constants and types defined following the
-// includes below parameterize the conversion.
-//
-// This routine can be trivially adapted to support conversions from
-// half-precision or to quad-precision. It does not support types that don't
-// use the usual IEEE-754 interchange formats; specifically, some work would be
-// needed to adapt it to (for example) the Intel 80-bit format or PowerPC
-// double-double format.
-//
-// Note please, however, that this implementation is only intended to support
-// *widening* operations; if you need to convert to a *narrower* floating-point
-// type (e.g. double -> float), then this routine will not do what you want it
-// to.
-//
-// It also requires that integer types at least as large as both formats
-// are available on the target platform; this may pose a problem when trying
-// to add support for quad on some 32-bit systems, for example. You also may
-// run into trouble finding an appropriate CLZ function for wide source types;
-// you will likely need to roll your own on some platforms.
-//
-// Finally, the following assumptions are made:
-//
-// 1. floating-point types and integer types have the same endianness on the
-// target platform
-//
-// 2. quiet NaNs, if supported, are indicated by the leading bit of the
-// significand field being set
-//
-//===----------------------------------------------------------------------===//
-
-#include "int_lib.h"
-
-typedef float src_t;
-typedef uint32_t src_rep_t;
-#define SRC_REP_C UINT32_C
-static const int srcSigBits = 23;
-#define src_rep_t_clz __builtin_clz
-
-typedef double dst_t;
-typedef uint64_t dst_rep_t;
-#define DST_REP_C UINT64_C
-static const int dstSigBits = 52;
-
-// 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) {
- const union { src_t f; src_rep_t i; } rep = {.f = x};
- return rep.i;
-}
-
-static inline dst_t dstFromRep(dst_rep_t x) {
- const union { dst_t f; dst_rep_t i; } rep = {.i = x};
- return rep.f;
-}
-
-// End helper routines. Conversion implementation follows.
-
-ARM_EABI_FNALIAS(f2d, extendsfdf2)
-
-dst_t __extendsfdf2(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;
- const int srcExpBits = srcBits - srcSigBits - 1;
- const int srcInfExp = (1 << srcExpBits) - 1;
- const int srcExpBias = srcInfExp >> 1;
-
- const src_rep_t srcMinNormal = SRC_REP_C(1) << srcSigBits;
- const src_rep_t srcInfinity = (src_rep_t)srcInfExp << srcSigBits;
- const src_rep_t srcSignMask = SRC_REP_C(1) << (srcSigBits + srcExpBits);
- const src_rep_t srcAbsMask = srcSignMask - 1;
- const src_rep_t srcQNaN = SRC_REP_C(1) << (srcSigBits - 1);
- const src_rep_t srcNaNCode = srcQNaN - 1;
-
- const int dstBits = sizeof(dst_t)*CHAR_BIT;
- const int dstExpBits = dstBits - dstSigBits - 1;
- const int dstInfExp = (1 << dstExpBits) - 1;
- const int dstExpBias = dstInfExp >> 1;
-
- const dst_rep_t dstMinNormal = DST_REP_C(1) << dstSigBits;
-
- // Break a into a sign and representation of the absolute value
- const src_rep_t aRep = srcToRep(a);
- const src_rep_t aAbs = aRep & srcAbsMask;
- const src_rep_t sign = aRep & srcSignMask;
- dst_rep_t absResult;
-
- if (aAbs - srcMinNormal < srcInfinity - srcMinNormal) {
- // a is a normal number.
- // Extend to the destination type by shifting the significand and
- // exponent into the proper position and rebiasing the exponent.
- absResult = (dst_rep_t)aAbs << (dstSigBits - srcSigBits);
- absResult += (dst_rep_t)(dstExpBias - srcExpBias) << dstSigBits;
- }
-
- else if (aAbs >= srcInfinity) {
- // a is NaN or infinity.
- // Conjure the result by beginning with infinity, then setting the qNaN
- // bit (if needed) and right-aligning the rest of the trailing NaN
- // payload field.
- absResult = (dst_rep_t)dstInfExp << dstSigBits;
- absResult |= (dst_rep_t)(aAbs & srcQNaN) << (dstSigBits - srcSigBits);
- absResult |= aAbs & srcNaNCode;
- }
-
- else if (aAbs) {
- // a is denormal.
- // renormalize the significand and clear the leading bit, then insert
- // the correct adjusted exponent in the destination type.
- const int scale = src_rep_t_clz(aAbs) - src_rep_t_clz(srcMinNormal);
- absResult = (dst_rep_t)aAbs << (dstSigBits - srcSigBits + scale);
- absResult ^= dstMinNormal;
- const int resultExponent = dstExpBias - srcExpBias - scale + 1;
- absResult |= (dst_rep_t)resultExponent << dstSigBits;
- }
-
- else {
- // a is zero.
- absResult = 0;
- }
-
- // Apply the signbit to (dst_t)abs(a).
- const dst_rep_t result = absResult | (dst_rep_t)sign << (dstBits - srcBits);
- return dstFromRep(result);
-}
diff --git a/lib/ffsti2.c b/lib/ffsti2.c
deleted file mode 100644
index 27e15d5810ef..000000000000
--- a/lib/ffsti2.c
+++ /dev/null
@@ -1,37 +0,0 @@
-/* ===-- ffsti2.c - Implement __ffsti2 -------------------------------------===
- *
- * 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 __ffsti2 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-#if __x86_64
-
-/* Returns: the index of the least significant 1-bit in a, or
- * the value zero if a is zero. The least significant bit is index one.
- */
-
-si_int
-__ffsti2(ti_int a)
-{
- twords x;
- x.all = a;
- if (x.s.low == 0)
- {
- if (x.s.high == 0)
- return 0;
- return __builtin_ctzll(x.s.high) + (1 + sizeof(di_int) * CHAR_BIT);
- }
- return __builtin_ctzll(x.s.low) + 1;
-}
-
-#endif /* __x86_64 */
diff --git a/lib/fixdfdi.c b/lib/fixdfdi.c
deleted file mode 100644
index 7665ea5a3629..000000000000
--- a/lib/fixdfdi.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/* ===-- fixdfdi.c - Implement __fixdfdi -----------------------------------===
- *
- * 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 __fixdfdi for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-/* Returns: convert a to a signed long long, rounding toward zero. */
-
-/* Assumption: double is a IEEE 64 bit floating point type
- * su_int is a 32 bit integral type
- * value in double is representable in di_int (no range checking performed)
- */
-
-/* seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm */
-
-ARM_EABI_FNALIAS(d2lz, fixdfdi)
-
-di_int
-__fixdfdi(double a)
-{
- double_bits fb;
- fb.f = a;
- int e = ((fb.u.s.high & 0x7FF00000) >> 20) - 1023;
- if (e < 0)
- return 0;
- di_int s = (si_int)(fb.u.s.high & 0x80000000) >> 31;
- dwords r;
- r.s.high = (fb.u.s.high & 0x000FFFFF) | 0x00100000;
- r.s.low = fb.u.s.low;
- if (e > 52)
- r.all <<= (e - 52);
- else
- r.all >>= (52 - e);
- return (r.all ^ s) - s;
-}
diff --git a/lib/fixdfsi.c b/lib/fixdfsi.c
deleted file mode 100644
index 614d032a4e14..000000000000
--- a/lib/fixdfsi.c
+++ /dev/null
@@ -1,49 +0,0 @@
-//===-- lib/fixdfsi.c - Double-precision -> integer 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 double-precision to integer conversion for the
-// compiler-rt library. No range checking is performed; the behavior of this
-// conversion is undefined for out of range values in the C standard.
-//
-//===----------------------------------------------------------------------===//
-
-#define DOUBLE_PRECISION
-#include "fp_lib.h"
-
-#include "int_lib.h"
-
-ARM_EABI_FNALIAS(d2iz, fixdfsi)
-
-int __fixdfsi(fp_t a) {
-
- // Break a into sign, exponent, significand
- const rep_t aRep = toRep(a);
- const rep_t aAbs = aRep & absMask;
- const int sign = aRep & signBit ? -1 : 1;
- const int exponent = (aAbs >> significandBits) - exponentBias;
- const rep_t significand = (aAbs & significandMask) | implicitBit;
-
- // If 0 < exponent < significandBits, right shift to get the result.
- if ((unsigned int)exponent < significandBits) {
- return sign * (significand >> (significandBits - exponent));
- }
-
- // If exponent is negative, the result is zero.
- else if (exponent < 0) {
- return 0;
- }
-
- // If significandBits < exponent, left shift to get the result. This shift
- // may end up being larger than the type width, which incurs undefined
- // behavior, but the conversion itself is undefined in that case, so
- // whatever the compiler decides to do is fine.
- else {
- return sign * (significand << (exponent - significandBits));
- }
-}
diff --git a/lib/fixdfti.c b/lib/fixdfti.c
deleted file mode 100644
index b110a94b8427..000000000000
--- a/lib/fixdfti.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/* ===-- fixdfti.c - Implement __fixdfti -----------------------------------===
- *
- * 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 __fixdfti for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-#if __x86_64
-
-/* Returns: convert a to a signed long long, rounding toward zero. */
-
-/* Assumption: double is a IEEE 64 bit floating point type
- * su_int is a 32 bit integral type
- * value in double is representable in ti_int (no range checking performed)
- */
-
-/* seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm */
-
-ti_int
-__fixdfti(double a)
-{
- double_bits fb;
- fb.f = a;
- int e = ((fb.u.s.high & 0x7FF00000) >> 20) - 1023;
- if (e < 0)
- return 0;
- ti_int s = (si_int)(fb.u.s.high & 0x80000000) >> 31;
- ti_int r = 0x0010000000000000uLL | (0x000FFFFFFFFFFFFFuLL & fb.u.all);
- if (e > 52)
- r <<= (e - 52);
- else
- r >>= (52 - e);
- return (r ^ s) - s;
-}
-
-#endif
diff --git a/lib/fixsfti.c b/lib/fixsfti.c
deleted file mode 100644
index c730ae0467c4..000000000000
--- a/lib/fixsfti.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/* ===-- fixsfti.c - Implement __fixsfti -----------------------------------===
- *
- * 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 __fixsfti for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-#if __x86_64
-
-/* Returns: convert a to a signed long long, rounding toward zero. */
-
-/* Assumption: float is a IEEE 32 bit floating point type
- * su_int is a 32 bit integral type
- * value in float is representable in ti_int (no range checking performed)
- */
-
-/* seee eeee emmm mmmm mmmm mmmm mmmm mmmm */
-
-ti_int
-__fixsfti(float a)
-{
- float_bits fb;
- fb.f = a;
- int e = ((fb.u & 0x7F800000) >> 23) - 127;
- if (e < 0)
- return 0;
- ti_int s = (si_int)(fb.u & 0x80000000) >> 31;
- ti_int r = (fb.u & 0x007FFFFF) | 0x00800000;
- if (e > 23)
- r <<= (e - 23);
- else
- r >>= (23 - e);
- return (r ^ s) - s;
-}
-
-#endif
diff --git a/lib/fixunsdfti.c b/lib/fixunsdfti.c
deleted file mode 100644
index fb0336f69081..000000000000
--- a/lib/fixunsdfti.c
+++ /dev/null
@@ -1,47 +0,0 @@
-/* ===-- fixunsdfti.c - Implement __fixunsdfti -----------------------------===
- *
- * 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 __fixunsdfti for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-#if __x86_64
-
-/* Returns: convert a to a unsigned long long, rounding toward zero.
- * Negative values all become zero.
- */
-
-/* Assumption: double is a IEEE 64 bit floating point type
- * tu_int is a 64 bit integral type
- * value in double is representable in tu_int or is negative
- * (no range checking performed)
- */
-
-/* seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm */
-
-tu_int
-__fixunsdfti(double a)
-{
- double_bits fb;
- fb.f = a;
- int e = ((fb.u.s.high & 0x7FF00000) >> 20) - 1023;
- if (e < 0 || (fb.u.s.high & 0x80000000))
- return 0;
- tu_int r = 0x0010000000000000uLL | (fb.u.all & 0x000FFFFFFFFFFFFFuLL);
- if (e > 52)
- r <<= (e - 52);
- else
- r >>= (52 - e);
- return r;
-}
-
-#endif
diff --git a/lib/fixunssfti.c b/lib/fixunssfti.c
deleted file mode 100644
index 8f4c62627ca5..000000000000
--- a/lib/fixunssfti.c
+++ /dev/null
@@ -1,47 +0,0 @@
-/* ===-- fixunssfti.c - Implement __fixunssfti -----------------------------===
- *
- * 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 __fixunssfti for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-#if __x86_64
-
-/* Returns: convert a to a unsigned long long, rounding toward zero.
- * Negative values all become zero.
- */
-
-/* Assumption: float is a IEEE 32 bit floating point type
- * tu_int is a 64 bit integral type
- * value in float is representable in tu_int or is negative
- * (no range checking performed)
- */
-
-/* seee eeee emmm mmmm mmmm mmmm mmmm mmmm */
-
-tu_int
-__fixunssfti(float a)
-{
- float_bits fb;
- fb.f = a;
- int e = ((fb.u & 0x7F800000) >> 23) - 127;
- if (e < 0 || (fb.u & 0x80000000))
- return 0;
- tu_int r = (fb.u & 0x007FFFFF) | 0x00800000;
- if (e > 23)
- r <<= (e - 23);
- else
- r >>= (23 - e);
- return r;
-}
-
-#endif
diff --git a/lib/fixunsxfdi.c b/lib/fixunsxfdi.c
deleted file mode 100644
index 6c817d8e1289..000000000000
--- a/lib/fixunsxfdi.c
+++ /dev/null
@@ -1,44 +0,0 @@
-/* ===-- fixunsxfdi.c - Implement __fixunsxfdi -----------------------------===
- *
- * 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 __fixunsxfdi for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#if !_ARCH_PPC
-
-#include "int_lib.h"
-
-/* Returns: convert a to a unsigned long long, rounding toward zero.
- * Negative values all become zero.
- */
-
-/* Assumption: long double is an intel 80 bit floating point type padded with 6 bytes
- * du_int is a 64 bit integral type
- * value in long double is representable in du_int or is negative
- * (no range checking performed)
- */
-
-/* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee |
- * 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm
- */
-
-du_int
-__fixunsxfdi(long double a)
-{
- long_double_bits fb;
- fb.f = a;
- int e = (fb.u.high.s.low & 0x00007FFF) - 16383;
- if (e < 0 || (fb.u.high.s.low & 0x00008000))
- return 0;
- return fb.u.low.all >> (63 - e);
-}
-
-#endif
diff --git a/lib/fixunsxfsi.c b/lib/fixunsxfsi.c
deleted file mode 100644
index b9da86c4f8ea..000000000000
--- a/lib/fixunsxfsi.c
+++ /dev/null
@@ -1,44 +0,0 @@
-/* ===-- fixunsxfsi.c - Implement __fixunsxfsi -----------------------------===
- *
- * 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 __fixunsxfsi for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#if !_ARCH_PPC
-
-#include "int_lib.h"
-
-/* Returns: convert a to a unsigned int, rounding toward zero.
- * Negative values all become zero.
- */
-
-/* Assumption: long double is an intel 80 bit floating point type padded with 6 bytes
- * su_int is a 32 bit integral type
- * value in long double is representable in su_int or is negative
- * (no range checking performed)
- */
-
-/* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee |
- * 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm
- */
-
-su_int
-__fixunsxfsi(long double a)
-{
- long_double_bits fb;
- fb.f = a;
- int e = (fb.u.high.s.low & 0x00007FFF) - 16383;
- if (e < 0 || (fb.u.high.s.low & 0x00008000))
- return 0;
- return fb.u.low.s.high >> (31 - e);
-}
-
-#endif /* !_ARCH_PPC */
diff --git a/lib/fixunsxfti.c b/lib/fixunsxfti.c
deleted file mode 100644
index 260bfc01f647..000000000000
--- a/lib/fixunsxfti.c
+++ /dev/null
@@ -1,49 +0,0 @@
-/* ===-- fixunsxfti.c - Implement __fixunsxfti -----------------------------===
- *
- * 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 __fixunsxfti for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-#if __x86_64
-
-/* Returns: convert a to a unsigned long long, rounding toward zero.
- * Negative values all become zero.
- */
-
-/* Assumption: long double is an intel 80 bit floating point type padded with 6 bytes
- * tu_int is a 64 bit integral type
- * value in long double is representable in tu_int or is negative
- * (no range checking performed)
- */
-
-/* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee |
- * 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm
- */
-
-tu_int
-__fixunsxfti(long double a)
-{
- long_double_bits fb;
- fb.f = a;
- int e = (fb.u.high.s.low & 0x00007FFF) - 16383;
- if (e < 0 || (fb.u.high.s.low & 0x00008000))
- return 0;
- tu_int r = fb.u.low.all;
- if (e > 63)
- r <<= (e - 63);
- else
- r >>= (63 - e);
- return r;
-}
-
-#endif
diff --git a/lib/fixxfdi.c b/lib/fixxfdi.c
deleted file mode 100644
index 9592ce43025b..000000000000
--- a/lib/fixxfdi.c
+++ /dev/null
@@ -1,44 +0,0 @@
-/* ===-- fixxfdi.c - Implement __fixxfdi -----------------------------------===
- *
- * 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 __fixxfdi for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#if !_ARCH_PPC
-
-#include "int_lib.h"
-
-/* Returns: convert a to a signed long long, rounding toward zero. */
-
-/* Assumption: long double is an intel 80 bit floating point type padded with 6 bytes
- * su_int is a 32 bit integral type
- * value in long double is representable in di_int (no range checking performed)
- */
-
-/* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee |
- * 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm
- */
-
-di_int
-__fixxfdi(long double a)
-{
- long_double_bits fb;
- fb.f = a;
- int e = (fb.u.high.s.low & 0x00007FFF) - 16383;
- if (e < 0)
- return 0;
- di_int s = -(si_int)((fb.u.high.s.low & 0x00008000) >> 15);
- di_int r = fb.u.low.all;
- r = (du_int)r >> (63 - e);
- return (r ^ s) - s;
-}
-
-#endif /* !_ARCH_PPC */
diff --git a/lib/fixxfti.c b/lib/fixxfti.c
deleted file mode 100644
index 973dc31bf937..000000000000
--- a/lib/fixxfti.c
+++ /dev/null
@@ -1,47 +0,0 @@
-/* ===-- fixxfti.c - Implement __fixxfti -----------------------------------===
- *
- * 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 __fixxfti for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-#if __x86_64
-
-/* Returns: convert a to a signed long long, rounding toward zero. */
-
-/* Assumption: long double is an intel 80 bit floating point type padded with 6 bytes
- * su_int is a 32 bit integral type
- * value in long double is representable in ti_int (no range checking performed)
- */
-
-/* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee |
- * 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm
- */
-
-ti_int
-__fixxfti(long double a)
-{
- long_double_bits fb;
- fb.f = a;
- int e = (fb.u.high.s.low & 0x00007FFF) - 16383;
- if (e < 0)
- return 0;
- ti_int s = -(si_int)((fb.u.high.s.low & 0x00008000) >> 15);
- ti_int r = fb.u.low.all;
- if (e > 63)
- r <<= (e - 63);
- else
- r >>= (63 - e);
- return (r ^ s) - s;
-}
-
-#endif /* __x86_64 */
diff --git a/lib/floatdixf.c b/lib/floatdixf.c
deleted file mode 100644
index ebf62dba0584..000000000000
--- a/lib/floatdixf.c
+++ /dev/null
@@ -1,46 +0,0 @@
-/* ===-- floatdixf.c - Implement __floatdixf -------------------------------===
- *
- * 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 __floatdixf for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#if !_ARCH_PPC
-
-#include "int_lib.h"
-
-/* Returns: convert a to a long double, rounding toward even. */
-
-/* Assumption: long double is a IEEE 80 bit floating point type padded to 128 bits
- * di_int is a 64 bit integral type
- */
-
-/* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee |
- * 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm
- */
-
-long double
-__floatdixf(di_int a)
-{
- if (a == 0)
- return 0.0;
- const unsigned N = sizeof(di_int) * CHAR_BIT;
- const di_int s = a >> (N-1);
- a = (a ^ s) - s;
- int clz = __builtin_clzll(a);
- int e = (N - 1) - clz ; /* exponent */
- long_double_bits fb;
- fb.u.high.s.low = ((su_int)s & 0x00008000) | /* sign */
- (e + 16383); /* exponent */
- fb.u.low.all = a << clz; /* mantissa */
- return fb.f;
-}
-
-#endif /* !_ARCH_PPC */
diff --git a/lib/floatsidf.c b/lib/floatsidf.c
deleted file mode 100644
index 18f378f2a900..000000000000
--- a/lib/floatsidf.c
+++ /dev/null
@@ -1,52 +0,0 @@
-//===-- lib/floatsidf.c - integer -> double-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 integer to double-precision conversion for the
-// compiler-rt library in the IEEE-754 default round-to-nearest, ties-to-even
-// mode.
-//
-//===----------------------------------------------------------------------===//
-
-#define DOUBLE_PRECISION
-#include "fp_lib.h"
-
-#include "int_lib.h"
-
-ARM_EABI_FNALIAS(i2d, floatsidf)
-
-fp_t __floatsidf(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;
- if (a < 0) {
- sign = signBit;
- a = -a;
- }
-
- // Exponent of (fp_t)a is the width of abs(a).
- const int exponent = (aWidth - 1) - __builtin_clz(a);
- 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.
- const int shift = significandBits - exponent;
- result = (rep_t)(unsigned int)a << shift ^ implicitBit;
-
- // Insert the exponent
- result += (rep_t)(exponent + exponentBias) << significandBits;
- // Insert the sign bit and return
- return fromRep(result | sign);
-}
diff --git a/lib/floatsisf.c b/lib/floatsisf.c
deleted file mode 100644
index 83983934f590..000000000000
--- a/lib/floatsisf.c
+++ /dev/null
@@ -1,58 +0,0 @@
-//===-- lib/floatsisf.c - integer -> single-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 integer to single-precision conversion for the
-// compiler-rt library in the IEEE-754 default round-to-nearest, ties-to-even
-// mode.
-//
-//===----------------------------------------------------------------------===//
-
-#define SINGLE_PRECISION
-#include "fp_lib.h"
-
-#include "int_lib.h"
-
-ARM_EABI_FNALIAS(i2f, floatsisf)
-
-fp_t __floatsisf(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;
- if (a < 0) {
- sign = signBit;
- a = -a;
- }
-
- // Exponent of (fp_t)a is the width of abs(a).
- const int exponent = (aWidth - 1) - __builtin_clz(a);
- rep_t result;
-
- // Shift a into the significand field, rounding if it is a right-shift
- if (exponent <= significandBits) {
- const int shift = significandBits - exponent;
- result = (rep_t)a << shift ^ implicitBit;
- } else {
- const int shift = exponent - significandBits;
- result = (rep_t)a >> shift ^ implicitBit;
- rep_t round = (rep_t)a << (typeWidth - shift);
- if (round > signBit) result++;
- if (round == signBit) result += result & 1;
- }
-
- // Insert the exponent
- result += (rep_t)(exponent + exponentBias) << significandBits;
- // Insert the sign bit and return
- return fromRep(result | sign);
-}
diff --git a/lib/floattidf.c b/lib/floattidf.c
deleted file mode 100644
index 77749f8d340b..000000000000
--- a/lib/floattidf.c
+++ /dev/null
@@ -1,85 +0,0 @@
-/* ===-- floattidf.c - Implement __floattidf -------------------------------===
- *
- * 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 __floattidf for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-#if __x86_64
-
-/* Returns: convert a to a double, rounding toward even.*/
-
-/* Assumption: double is a IEEE 64 bit floating point type
- * ti_int is a 128 bit integral type
- */
-
-/* seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm */
-
-si_int __clzti2(ti_int a);
-
-double
-__floattidf(ti_int a)
-{
- if (a == 0)
- return 0.0;
- const unsigned N = sizeof(ti_int) * CHAR_BIT;
- const ti_int s = a >> (N-1);
- a = (a ^ s) - s;
- int sd = N - __clzti2(a); /* number of significant digits */
- int e = sd - 1; /* exponent */
- if (sd > DBL_MANT_DIG)
- {
- /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
- * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
- * 12345678901234567890123456
- * 1 = msb 1 bit
- * P = bit DBL_MANT_DIG-1 bits to the right of 1
- * Q = bit DBL_MANT_DIG bits to the right of 1
- * R = "or" of all bits to the right of Q
- */
- switch (sd)
- {
- case DBL_MANT_DIG + 1:
- a <<= 1;
- break;
- case DBL_MANT_DIG + 2:
- break;
- default:
- a = ((tu_int)a >> (sd - (DBL_MANT_DIG+2))) |
- ((a & ((tu_int)(-1) >> ((N + DBL_MANT_DIG+2) - sd))) != 0);
- };
- /* finish: */
- a |= (a & 4) != 0; /* Or P into R */
- ++a; /* round - this step may add a significant bit */
- a >>= 2; /* dump Q and R */
- /* a is now rounded to DBL_MANT_DIG or DBL_MANT_DIG+1 bits */
- if (a & ((tu_int)1 << DBL_MANT_DIG))
- {
- a >>= 1;
- ++e;
- }
- /* a is now rounded to DBL_MANT_DIG bits */
- }
- else
- {
- a <<= (DBL_MANT_DIG - sd);
- /* a is now rounded to DBL_MANT_DIG bits */
- }
- double_bits fb;
- fb.u.s.high = ((su_int)s & 0x80000000) | /* sign */
- ((e + 1023) << 20) | /* exponent */
- ((su_int)(a >> 32) & 0x000FFFFF); /* mantissa-high */
- fb.u.s.low = (su_int)a; /* mantissa-low */
- return fb.f;
-}
-
-#endif
diff --git a/lib/floattisf.c b/lib/floattisf.c
deleted file mode 100644
index 4776125ded79..000000000000
--- a/lib/floattisf.c
+++ /dev/null
@@ -1,84 +0,0 @@
-/* ===-- floattisf.c - Implement __floattisf -------------------------------===
- *
- * 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 __floattisf for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-#if __x86_64
-
-/* Returns: convert a to a float, rounding toward even. */
-
-/* Assumption: float is a IEEE 32 bit floating point type
- * ti_int is a 128 bit integral type
- */
-
-/* seee eeee emmm mmmm mmmm mmmm mmmm mmmm */
-
-si_int __clzti2(ti_int a);
-
-float
-__floattisf(ti_int a)
-{
- if (a == 0)
- return 0.0F;
- const unsigned N = sizeof(ti_int) * CHAR_BIT;
- const ti_int s = a >> (N-1);
- a = (a ^ s) - s;
- int sd = N - __clzti2(a); /* number of significant digits */
- int e = sd - 1; /* exponent */
- if (sd > FLT_MANT_DIG)
- {
- /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
- * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
- * 12345678901234567890123456
- * 1 = msb 1 bit
- * P = bit FLT_MANT_DIG-1 bits to the right of 1
- * Q = bit FLT_MANT_DIG bits to the right of 1
- * R = "or" of all bits to the right of Q
- */
- switch (sd)
- {
- case FLT_MANT_DIG + 1:
- a <<= 1;
- break;
- case FLT_MANT_DIG + 2:
- break;
- default:
- a = ((tu_int)a >> (sd - (FLT_MANT_DIG+2))) |
- ((a & ((tu_int)(-1) >> ((N + FLT_MANT_DIG+2) - sd))) != 0);
- };
- /* finish: */
- a |= (a & 4) != 0; /* Or P into R */
- ++a; /* round - this step may add a significant bit */
- a >>= 2; /* dump Q and R */
- /* a is now rounded to FLT_MANT_DIG or FLT_MANT_DIG+1 bits */
- if (a & ((tu_int)1 << FLT_MANT_DIG))
- {
- a >>= 1;
- ++e;
- }
- /* a is now rounded to FLT_MANT_DIG bits */
- }
- else
- {
- a <<= (FLT_MANT_DIG - sd);
- /* a is now rounded to FLT_MANT_DIG bits */
- }
- float_bits fb;
- fb.u = ((su_int)s & 0x80000000) | /* sign */
- ((e + 127) << 23) | /* exponent */
- ((su_int)a & 0x007FFFFF); /* mantissa */
- return fb.f;
-}
-
-#endif
diff --git a/lib/floattixf.c b/lib/floattixf.c
deleted file mode 100644
index 3813dc6b7754..000000000000
--- a/lib/floattixf.c
+++ /dev/null
@@ -1,86 +0,0 @@
-/* ===-- floattixf.c - Implement __floattixf -------------------------------===
- *
- * 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 __floattixf for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-#if __x86_64
-
-/* Returns: convert a to a long double, rounding toward even. */
-
-/* Assumption: long double is a IEEE 80 bit floating point type padded to 128 bits
- * ti_int is a 128 bit integral type
- */
-
-/* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee |
- * 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm
- */
-
-si_int __clzti2(ti_int a);
-
-long double
-__floattixf(ti_int a)
-{
- if (a == 0)
- return 0.0;
- const unsigned N = sizeof(ti_int) * CHAR_BIT;
- const ti_int s = a >> (N-1);
- a = (a ^ s) - s;
- int sd = N - __clzti2(a); /* number of significant digits */
- int e = sd - 1; /* exponent */
- if (sd > LDBL_MANT_DIG)
- {
- /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
- * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
- * 12345678901234567890123456
- * 1 = msb 1 bit
- * P = bit LDBL_MANT_DIG-1 bits to the right of 1
- * Q = bit LDBL_MANT_DIG bits to the right of 1
- * R = "or" of all bits to the right of Q
- */
- switch (sd)
- {
- case LDBL_MANT_DIG + 1:
- a <<= 1;
- break;
- case LDBL_MANT_DIG + 2:
- break;
- default:
- a = ((tu_int)a >> (sd - (LDBL_MANT_DIG+2))) |
- ((a & ((tu_int)(-1) >> ((N + LDBL_MANT_DIG+2) - sd))) != 0);
- };
- /* finish: */
- a |= (a & 4) != 0; /* Or P into R */
- ++a; /* round - this step may add a significant bit */
- a >>= 2; /* dump Q and R */
- /* a is now rounded to LDBL_MANT_DIG or LDBL_MANT_DIG+1 bits */
- if (a & ((tu_int)1 << LDBL_MANT_DIG))
- {
- a >>= 1;
- ++e;
- }
- /* a is now rounded to LDBL_MANT_DIG bits */
- }
- else
- {
- a <<= (LDBL_MANT_DIG - sd);
- /* a is now rounded to LDBL_MANT_DIG bits */
- }
- long_double_bits fb;
- fb.u.high.s.low = ((su_int)s & 0x8000) | /* sign */
- (e + 16383); /* exponent */
- fb.u.low.all = (du_int)a; /* mantissa */
- return fb.f;
-}
-
-#endif
diff --git a/lib/floatundidf.c b/lib/floatundidf.c
deleted file mode 100644
index e52fa0a3359b..000000000000
--- a/lib/floatundidf.c
+++ /dev/null
@@ -1,107 +0,0 @@
-/* ===-- floatundidf.c - Implement __floatundidf ---------------------------===
- *
- * 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 __floatundidf for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-/* Returns: convert a to a double, rounding toward even. */
-
-/* Assumption: double is a IEEE 64 bit floating point type
- * du_int is a 64 bit integral type
- */
-
-/* seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm */
-
-#include "int_lib.h"
-
-ARM_EABI_FNALIAS(ul2d, floatundidf)
-
-#ifndef __SOFT_FP__
-/* Support for systems that have hardware floating-point; we'll set the inexact flag
- * as a side-effect of this computation.
- */
-
-
-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;
-
- union { uint64_t x; double d; } high = { .d = twop84 };
- union { uint64_t x; double d; } low = { .d = twop52 };
-
- high.x |= a >> 32;
- low.x |= a & UINT64_C(0x00000000ffffffff);
-
- const double result = (high.d - twop84_plus_twop52) + low.d;
- return result;
-}
-
-#else
-/* Support for systems that don't have hardware floating-point; there are no flags to
- * set, and we don't want to code-gen to an unknown soft-float implementation.
- */
-
-COMPILER_RT_ABI double
-__floatundidf(du_int a)
-{
- if (a == 0)
- return 0.0;
- const unsigned N = sizeof(du_int) * CHAR_BIT;
- int sd = N - __builtin_clzll(a); /* number of significant digits */
- int e = sd - 1; /* exponent */
- if (sd > DBL_MANT_DIG)
- {
- /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
- * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
- * 12345678901234567890123456
- * 1 = msb 1 bit
- * P = bit DBL_MANT_DIG-1 bits to the right of 1
- * Q = bit DBL_MANT_DIG bits to the right of 1
- * R = "or" of all bits to the right of Q
- */
- switch (sd)
- {
- case DBL_MANT_DIG + 1:
- a <<= 1;
- break;
- case DBL_MANT_DIG + 2:
- break;
- default:
- a = (a >> (sd - (DBL_MANT_DIG+2))) |
- ((a & ((du_int)(-1) >> ((N + DBL_MANT_DIG+2) - sd))) != 0);
- };
- /* finish: */
- a |= (a & 4) != 0; /* Or P into R */
- ++a; /* round - this step may add a significant bit */
- a >>= 2; /* dump Q and R */
- /* a is now rounded to DBL_MANT_DIG or DBL_MANT_DIG+1 bits */
- if (a & ((du_int)1 << DBL_MANT_DIG))
- {
- a >>= 1;
- ++e;
- }
- /* a is now rounded to DBL_MANT_DIG bits */
- }
- else
- {
- a <<= (DBL_MANT_DIG - sd);
- /* a is now rounded to DBL_MANT_DIG bits */
- }
- double_bits fb;
- fb.u.high = ((e + 1023) << 20) | /* exponent */
- ((su_int)(a >> 32) & 0x000FFFFF); /* mantissa-high */
- fb.u.low = (su_int)a; /* mantissa-low */
- return fb.f;
-}
-#endif
diff --git a/lib/floatundixf.c b/lib/floatundixf.c
deleted file mode 100644
index 64f7662d9525..000000000000
--- a/lib/floatundixf.c
+++ /dev/null
@@ -1,42 +0,0 @@
-/* ===-- floatundixf.c - Implement __floatundixf ---------------------------===
- *
- * 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 __floatundixf for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#if !_ARCH_PPC
-
-#include "int_lib.h"
-
-/* Returns: convert a to a long double, rounding toward even. */
-
-/* Assumption: long double is a IEEE 80 bit floating point type padded to 128 bits
- * du_int is a 64 bit integral type
- */
-
-/* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee |
- * 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm
- */
-long double
-__floatundixf(du_int a)
-{
- if (a == 0)
- return 0.0;
- const unsigned N = sizeof(du_int) * CHAR_BIT;
- int clz = __builtin_clzll(a);
- int e = (N - 1) - clz ; /* exponent */
- long_double_bits fb;
- fb.u.high.s.low = (e + 16383); /* exponent */
- fb.u.low.all = a << clz; /* mantissa */
- return fb.f;
-}
-
-#endif /* _ARCH_PPC */
diff --git a/lib/floatunsidf.c b/lib/floatunsidf.c
deleted file mode 100644
index ba6c2cfd2a17..000000000000
--- a/lib/floatunsidf.c
+++ /dev/null
@@ -1,41 +0,0 @@
-//===-- lib/floatunsidf.c - uint -> double-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 unsigned integer to double-precision conversion for the
-// compiler-rt library in the IEEE-754 default round-to-nearest, ties-to-even
-// mode.
-//
-//===----------------------------------------------------------------------===//
-
-#define DOUBLE_PRECISION
-#include "fp_lib.h"
-
-#include "int_lib.h"
-
-ARM_EABI_FNALIAS(ui2d, floatunsidf)
-
-fp_t __floatunsidf(unsigned 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_clz(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);
-}
diff --git a/lib/floatunsisf.c b/lib/floatunsisf.c
deleted file mode 100644
index e392c0ecf116..000000000000
--- a/lib/floatunsisf.c
+++ /dev/null
@@ -1,49 +0,0 @@
-//===-- lib/floatunsisf.c - uint -> single-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 unsigned integer to single-precision conversion for the
-// compiler-rt library in the IEEE-754 default round-to-nearest, ties-to-even
-// mode.
-//
-//===----------------------------------------------------------------------===//
-
-#define SINGLE_PRECISION
-#include "fp_lib.h"
-
-#include "int_lib.h"
-
-ARM_EABI_FNALIAS(ui2f, floatunsisf)
-
-fp_t __floatunsisf(unsigned 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_clz(a);
- rep_t result;
-
- // Shift a into the significand field, rounding if it is a right-shift
- if (exponent <= significandBits) {
- const int shift = significandBits - exponent;
- result = (rep_t)a << shift ^ implicitBit;
- } else {
- const int shift = exponent - significandBits;
- result = (rep_t)a >> shift ^ implicitBit;
- rep_t round = (rep_t)a << (typeWidth - shift);
- if (round > signBit) result++;
- if (round == signBit) result += result & 1;
- }
-
- // Insert the exponent
- result += (rep_t)(exponent + exponentBias) << significandBits;
- return fromRep(result);
-}
diff --git a/lib/floatuntidf.c b/lib/floatuntidf.c
deleted file mode 100644
index 4c1d3289f511..000000000000
--- a/lib/floatuntidf.c
+++ /dev/null
@@ -1,82 +0,0 @@
-/* ===-- floatuntidf.c - Implement __floatuntidf ---------------------------===
- *
- * 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 __floatuntidf for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-#if __x86_64
-
-/* Returns: convert a to a double, rounding toward even. */
-
-/* Assumption: double is a IEEE 64 bit floating point type
- * tu_int is a 128 bit integral type
- */
-
-/* seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm */
-
-si_int __clzti2(ti_int a);
-
-double
-__floatuntidf(tu_int a)
-{
- if (a == 0)
- return 0.0;
- const unsigned N = sizeof(tu_int) * CHAR_BIT;
- int sd = N - __clzti2(a); /* number of significant digits */
- int e = sd - 1; /* exponent */
- if (sd > DBL_MANT_DIG)
- {
- /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
- * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
- * 12345678901234567890123456
- * 1 = msb 1 bit
- * P = bit DBL_MANT_DIG-1 bits to the right of 1
- * Q = bit DBL_MANT_DIG bits to the right of 1
- * R = "or" of all bits to the right of Q
- */
- switch (sd)
- {
- case DBL_MANT_DIG + 1:
- a <<= 1;
- break;
- case DBL_MANT_DIG + 2:
- break;
- default:
- a = (a >> (sd - (DBL_MANT_DIG+2))) |
- ((a & ((tu_int)(-1) >> ((N + DBL_MANT_DIG+2) - sd))) != 0);
- };
- /* finish: */
- a |= (a & 4) != 0; /* Or P into R */
- ++a; /* round - this step may add a significant bit */
- a >>= 2; /* dump Q and R */
- /* a is now rounded to DBL_MANT_DIG or DBL_MANT_DIG+1 bits */
- if (a & ((tu_int)1 << DBL_MANT_DIG))
- {
- a >>= 1;
- ++e;
- }
- /* a is now rounded to DBL_MANT_DIG bits */
- }
- else
- {
- a <<= (DBL_MANT_DIG - sd);
- /* a is now rounded to DBL_MANT_DIG bits */
- }
- double_bits fb;
- fb.u.s.high = ((e + 1023) << 20) | /* exponent */
- ((su_int)(a >> 32) & 0x000FFFFF); /* mantissa-high */
- fb.u.s.low = (su_int)a; /* mantissa-low */
- return fb.f;
-}
-
-#endif
diff --git a/lib/floatuntisf.c b/lib/floatuntisf.c
deleted file mode 100644
index c8da2601ba8d..000000000000
--- a/lib/floatuntisf.c
+++ /dev/null
@@ -1,81 +0,0 @@
-/* ===-- floatuntisf.c - Implement __floatuntisf ---------------------------===
- *
- * 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 __floatuntisf for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-#if __x86_64
-
-/* Returns: convert a to a float, rounding toward even. */
-
-/* Assumption: float is a IEEE 32 bit floating point type
- * tu_int is a 128 bit integral type
- */
-
-/* seee eeee emmm mmmm mmmm mmmm mmmm mmmm */
-
-si_int __clzti2(ti_int a);
-
-float
-__floatuntisf(tu_int a)
-{
- if (a == 0)
- return 0.0F;
- const unsigned N = sizeof(tu_int) * CHAR_BIT;
- int sd = N - __clzti2(a); /* number of significant digits */
- int e = sd - 1; /* exponent */
- if (sd > FLT_MANT_DIG)
- {
- /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
- * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
- * 12345678901234567890123456
- * 1 = msb 1 bit
- * P = bit FLT_MANT_DIG-1 bits to the right of 1
- * Q = bit FLT_MANT_DIG bits to the right of 1
- * R = "or" of all bits to the right of Q
- */
- switch (sd)
- {
- case FLT_MANT_DIG + 1:
- a <<= 1;
- break;
- case FLT_MANT_DIG + 2:
- break;
- default:
- a = (a >> (sd - (FLT_MANT_DIG+2))) |
- ((a & ((tu_int)(-1) >> ((N + FLT_MANT_DIG+2) - sd))) != 0);
- };
- /* finish: */
- a |= (a & 4) != 0; /* Or P into R */
- ++a; /* round - this step may add a significant bit */
- a >>= 2; /* dump Q and R */
- /* a is now rounded to FLT_MANT_DIG or FLT_MANT_DIG+1 bits */
- if (a & ((tu_int)1 << FLT_MANT_DIG))
- {
- a >>= 1;
- ++e;
- }
- /* a is now rounded to FLT_MANT_DIG bits */
- }
- else
- {
- a <<= (FLT_MANT_DIG - sd);
- /* a is now rounded to FLT_MANT_DIG bits */
- }
- float_bits fb;
- fb.u = ((e + 127) << 23) | /* exponent */
- ((su_int)a & 0x007FFFFF); /* mantissa */
- return fb.f;
-}
-
-#endif
diff --git a/lib/floatuntixf.c b/lib/floatuntixf.c
deleted file mode 100644
index dbce80f16ee5..000000000000
--- a/lib/floatuntixf.c
+++ /dev/null
@@ -1,83 +0,0 @@
-/* ===-- floatuntixf.c - Implement __floatuntixf ---------------------------===
- *
- * 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 __floatuntixf for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-#if __x86_64
-
-/* Returns: convert a to a long double, rounding toward even. */
-
-/* Assumption: long double is a IEEE 80 bit floating point type padded to 128 bits
- * tu_int is a 128 bit integral type
- */
-
-/* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee |
- * 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm
- */
-
-si_int __clzti2(ti_int a);
-
-long double
-__floatuntixf(tu_int a)
-{
- if (a == 0)
- return 0.0;
- const unsigned N = sizeof(tu_int) * CHAR_BIT;
- int sd = N - __clzti2(a); /* number of significant digits */
- int e = sd - 1; /* exponent */
- if (sd > LDBL_MANT_DIG)
- {
- /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
- * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
- * 12345678901234567890123456
- * 1 = msb 1 bit
- * P = bit LDBL_MANT_DIG-1 bits to the right of 1
- * Q = bit LDBL_MANT_DIG bits to the right of 1
- * R = "or" of all bits to the right of Q
- */
- switch (sd)
- {
- case LDBL_MANT_DIG + 1:
- a <<= 1;
- break;
- case LDBL_MANT_DIG + 2:
- break;
- default:
- a = (a >> (sd - (LDBL_MANT_DIG+2))) |
- ((a & ((tu_int)(-1) >> ((N + LDBL_MANT_DIG+2) - sd))) != 0);
- };
- /* finish: */
- a |= (a & 4) != 0; /* Or P into R */
- ++a; /* round - this step may add a significant bit */
- a >>= 2; /* dump Q and R */
- /* a is now rounded to LDBL_MANT_DIG or LDBL_MANT_DIG+1 bits */
- if (a & ((tu_int)1 << LDBL_MANT_DIG))
- {
- a >>= 1;
- ++e;
- }
- /* a is now rounded to LDBL_MANT_DIG bits */
- }
- else
- {
- a <<= (LDBL_MANT_DIG - sd);
- /* a is now rounded to LDBL_MANT_DIG bits */
- }
- long_double_bits fb;
- fb.u.high.s.low = (e + 16383); /* exponent */
- fb.u.low.all = (du_int)a; /* mantissa */
- return fb.f;
-}
-
-#endif
diff --git a/lib/fp_lib.h b/lib/fp_lib.h
deleted file mode 100644
index 661119ae412a..000000000000
--- a/lib/fp_lib.h
+++ /dev/null
@@ -1,144 +0,0 @@
-//===-- lib/fp_lib.h - Floating-point utilities -------------------*- 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 is a configuration header for soft-float routines in compiler-rt.
-// This file does not provide any part of the compiler-rt interface, but defines
-// many useful constants and utility routines that are used in the
-// implementation of the soft-float routines in compiler-rt.
-//
-// Assumes that float and double correspond to the IEEE-754 binary32 and
-// binary64 types, respectively, and that integer endianness matches floating
-// point endianness on the target platform.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef FP_LIB_HEADER
-#define FP_LIB_HEADER
-
-#include <stdint.h>
-#include <stdbool.h>
-#include <limits.h>
-#include "int_lib.h"
-
-#if defined SINGLE_PRECISION
-
-typedef uint32_t rep_t;
-typedef int32_t srep_t;
-typedef float fp_t;
-#define REP_C UINT32_C
-#define significandBits 23
-
-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) {
- const uint64_t product = (uint64_t)a*b;
- *hi = product >> 32;
- *lo = product;
-}
-
-#elif defined DOUBLE_PRECISION
-
-typedef uint64_t rep_t;
-typedef int64_t srep_t;
-typedef double fp_t;
-#define REP_C UINT64_C
-#define significandBits 52
-
-static inline int rep_clz(rep_t a) {
-#if defined __LP64__
- return __builtin_clzl(a);
-#else
- if (a & REP_C(0xffffffff00000000))
- return __builtin_clz(a >> 32);
- else
- return 32 + __builtin_clz(a & REP_C(0xffffffff));
-#endif
-}
-
-#define loWord(a) (a & 0xffffffffU)
-#define hiWord(a) (a >> 32)
-
-// 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) {
- // Each of the component 32x32 -> 64 products
- const uint64_t plolo = loWord(a) * loWord(b);
- const uint64_t plohi = loWord(a) * hiWord(b);
- const uint64_t philo = hiWord(a) * loWord(b);
- const uint64_t phihi = hiWord(a) * hiWord(b);
- // Sum terms that contribute to lo in a way that allows us to get the carry
- const uint64_t r0 = loWord(plolo);
- const uint64_t r1 = hiWord(plolo) + loWord(plohi) + loWord(philo);
- *lo = r0 + (r1 << 32);
- // Sum terms contributing to hi with the carry from lo
- *hi = hiWord(plohi) + hiWord(philo) + hiWord(r1) + phihi;
-}
-
-#else
-#error Either SINGLE_PRECISION or DOUBLE_PRECISION must be defined.
-#endif
-
-#define typeWidth (sizeof(rep_t)*CHAR_BIT)
-#define exponentBits (typeWidth - significandBits - 1)
-#define maxExponent ((1 << exponentBits) - 1)
-#define exponentBias (maxExponent >> 1)
-
-#define implicitBit (REP_C(1) << significandBits)
-#define significandMask (implicitBit - 1U)
-#define signBit (REP_C(1) << (significandBits + exponentBits))
-#define absMask (signBit - 1U)
-#define exponentMask (absMask ^ significandMask)
-#define oneRep ((rep_t)exponentBias << significandBits)
-#define infRep exponentMask
-#define quietBit (implicitBit >> 1)
-#define qnanRep (exponentMask | quietBit)
-
-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) {
- const union { fp_t f; rep_t i; } rep = {.i = x};
- return rep.f;
-}
-
-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) {
- *hi = *hi << count | *lo >> (typeWidth - count);
- *lo = *lo << 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;
- *hi = *hi >> count;
- }
- else if (count < 2*typeWidth) {
- const bool sticky = *hi << (2*typeWidth - count) | *lo;
- *lo = *hi >> (count - typeWidth) | sticky;
- *hi = 0;
- } else {
- const bool sticky = *hi | *lo;
- *lo = sticky;
- *hi = 0;
- }
-}
-
-#endif // FP_LIB_HEADER
diff --git a/lib/gcc_personality_v0.c b/lib/gcc_personality_v0.c
deleted file mode 100644
index 8a708cae5974..000000000000
--- a/lib/gcc_personality_v0.c
+++ /dev/null
@@ -1,247 +0,0 @@
-/* ===-- gcc_personality_v0.c - Implement __gcc_personality_v0 -------------===
- *
- * 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 "int_lib.h"
-
-/*
- * _Unwind_* stuff based on C++ ABI public documentation
- * http://refspecs.freestandards.org/abi-eh-1.21.html
- */
-
-typedef enum {
- _URC_NO_REASON = 0,
- _URC_FOREIGN_EXCEPTION_CAUGHT = 1,
- _URC_FATAL_PHASE2_ERROR = 2,
- _URC_FATAL_PHASE1_ERROR = 3,
- _URC_NORMAL_STOP = 4,
- _URC_END_OF_STACK = 5,
- _URC_HANDLER_FOUND = 6,
- _URC_INSTALL_CONTEXT = 7,
- _URC_CONTINUE_UNWIND = 8
-} _Unwind_Reason_Code;
-
-typedef enum {
- _UA_SEARCH_PHASE = 1,
- _UA_CLEANUP_PHASE = 2,
- _UA_HANDLER_FRAME = 4,
- _UA_FORCE_UNWIND = 8,
- _UA_END_OF_STACK = 16
-} _Unwind_Action;
-
-typedef struct _Unwind_Context* _Unwind_Context_t;
-
-struct _Unwind_Exception {
- uint64_t exception_class;
- void (*exception_cleanup)(_Unwind_Reason_Code reason,
- struct _Unwind_Exception* exc);
- uintptr_t private_1;
- uintptr_t private_2;
-};
-
-extern const uint8_t* _Unwind_GetLanguageSpecificData(_Unwind_Context_t c);
-extern void _Unwind_SetGR(_Unwind_Context_t c, int i, uintptr_t n);
-extern void _Unwind_SetIP(_Unwind_Context_t, uintptr_t new_value);
-extern uintptr_t _Unwind_GetIP(_Unwind_Context_t context);
-extern uintptr_t _Unwind_GetRegionStart(_Unwind_Context_t context);
-
-
-/*
- * Pointer encodings documented at:
- * http://refspecs.freestandards.org/LSB_1.3.0/gLSB/gLSB/ehframehdr.html
- */
-
-#define DW_EH_PE_omit 0xff /* no data follows */
-
-#define DW_EH_PE_absptr 0x00
-#define DW_EH_PE_uleb128 0x01
-#define DW_EH_PE_udata2 0x02
-#define DW_EH_PE_udata4 0x03
-#define DW_EH_PE_udata8 0x04
-#define DW_EH_PE_sleb128 0x09
-#define DW_EH_PE_sdata2 0x0A
-#define DW_EH_PE_sdata4 0x0B
-#define DW_EH_PE_sdata8 0x0C
-
-#define DW_EH_PE_pcrel 0x10
-#define DW_EH_PE_textrel 0x20
-#define DW_EH_PE_datarel 0x30
-#define DW_EH_PE_funcrel 0x40
-#define DW_EH_PE_aligned 0x50
-#define DW_EH_PE_indirect 0x80 /* gcc extension */
-
-
-
-/* read a uleb128 encoded value and advance pointer */
-static uintptr_t readULEB128(const uint8_t** data)
-{
- uintptr_t result = 0;
- uintptr_t shift = 0;
- unsigned char byte;
- const uint8_t* p = *data;
- do {
- byte = *p++;
- result |= (byte & 0x7f) << shift;
- shift += 7;
- } while (byte & 0x80);
- *data = p;
- return result;
-}
-
-/* read a pointer encoded value and advance pointer */
-static uintptr_t readEncodedPointer(const uint8_t** data, uint8_t encoding)
-{
- const uint8_t* p = *data;
- uintptr_t result = 0;
-
- if ( encoding == DW_EH_PE_omit )
- return 0;
-
- /* first get value */
- switch (encoding & 0x0F) {
- case DW_EH_PE_absptr:
- result = *((uintptr_t*)p);
- p += sizeof(uintptr_t);
- break;
- case DW_EH_PE_uleb128:
- result = readULEB128(&p);
- break;
- case DW_EH_PE_udata2:
- result = *((uint16_t*)p);
- p += sizeof(uint16_t);
- break;
- case DW_EH_PE_udata4:
- result = *((uint32_t*)p);
- p += sizeof(uint32_t);
- break;
- case DW_EH_PE_udata8:
- result = *((uint64_t*)p);
- p += sizeof(uint64_t);
- break;
- case DW_EH_PE_sdata2:
- result = *((int16_t*)p);
- p += sizeof(int16_t);
- break;
- case DW_EH_PE_sdata4:
- result = *((int32_t*)p);
- p += sizeof(int32_t);
- break;
- case DW_EH_PE_sdata8:
- result = *((int64_t*)p);
- p += sizeof(int64_t);
- break;
- case DW_EH_PE_sleb128:
- default:
- /* not supported */
- compilerrt_abort();
- break;
- }
-
- /* then add relative offset */
- switch ( encoding & 0x70 ) {
- case DW_EH_PE_absptr:
- /* do nothing */
- break;
- case DW_EH_PE_pcrel:
- result += (uintptr_t)(*data);
- break;
- case DW_EH_PE_textrel:
- case DW_EH_PE_datarel:
- case DW_EH_PE_funcrel:
- case DW_EH_PE_aligned:
- default:
- /* not supported */
- compilerrt_abort();
- break;
- }
-
- /* then apply indirection */
- if (encoding & DW_EH_PE_indirect) {
- result = *((uintptr_t*)result);
- }
-
- *data = p;
- return result;
-}
-
-
-/*
- * The C compiler makes references to __gcc_personality_v0 in
- * the dwarf unwind information for translation units that use
- * __attribute__((cleanup(xx))) on local variables.
- * This personality routine is called by the system unwinder
- * on each frame as the stack is unwound during a C++ exception
- * throw through a C function compiled with -fexceptions.
- */
-#if __arm__
-// the setjump-longjump based exceptions personality routine has a different name
-_Unwind_Reason_Code __gcc_personality_sj0(int version, _Unwind_Action actions,
- uint64_t exceptionClass, struct _Unwind_Exception* exceptionObject,
- _Unwind_Context_t context)
-#else
-_Unwind_Reason_Code __gcc_personality_v0(int version, _Unwind_Action actions,
- uint64_t exceptionClass, struct _Unwind_Exception* exceptionObject,
- _Unwind_Context_t context)
-#endif
-{
- /* Since C does not have catch clauses, there is nothing to do during */
- /* phase 1 (the search phase). */
- if ( actions & _UA_SEARCH_PHASE )
- return _URC_CONTINUE_UNWIND;
-
- /* There is nothing to do if there is no LSDA for this frame. */
- const uint8_t* lsda = _Unwind_GetLanguageSpecificData(context);
- if ( lsda == (uint8_t*) 0 )
- return _URC_CONTINUE_UNWIND;
-
- uintptr_t pc = _Unwind_GetIP(context)-1;
- uintptr_t funcStart = _Unwind_GetRegionStart(context);
- uintptr_t pcOffset = pc - funcStart;
-
- /* Parse LSDA header. */
- uint8_t lpStartEncoding = *lsda++;
- if (lpStartEncoding != DW_EH_PE_omit) {
- readEncodedPointer(&lsda, lpStartEncoding);
- }
- uint8_t ttypeEncoding = *lsda++;
- if (ttypeEncoding != DW_EH_PE_omit) {
- readULEB128(&lsda);
- }
- /* Walk call-site table looking for range that includes current PC. */
- uint8_t callSiteEncoding = *lsda++;
- uint32_t callSiteTableLength = readULEB128(&lsda);
- const uint8_t* callSiteTableStart = lsda;
- const uint8_t* callSiteTableEnd = callSiteTableStart + callSiteTableLength;
- const uint8_t* p=callSiteTableStart;
- while (p < callSiteTableEnd) {
- uintptr_t start = readEncodedPointer(&p, callSiteEncoding);
- uintptr_t length = readEncodedPointer(&p, callSiteEncoding);
- uintptr_t landingPad = readEncodedPointer(&p, callSiteEncoding);
- readULEB128(&p); /* action value not used for C code */
- if ( landingPad == 0 )
- continue; /* no landing pad for this entry */
- if ( (start <= pcOffset) && (pcOffset < (start+length)) ) {
- /* Found landing pad for the PC.
- * 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(1), 0);
- _Unwind_SetIP(context, funcStart+landingPad);
- return _URC_INSTALL_CONTEXT;
- }
- }
-
- /* No landing pad found, continue unwinding. */
- return _URC_CONTINUE_UNWIND;
-}
-
diff --git a/lib/i386/Makefile.mk b/lib/i386/Makefile.mk
deleted file mode 100644
index 1f5c680c08f5..000000000000
--- a/lib/i386/Makefile.mk
+++ /dev/null
@@ -1,20 +0,0 @@
-#===- lib/i386/Makefile.mk ---------------------------------*- Makefile -*--===#
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-#===------------------------------------------------------------------------===#
-
-ModuleName := builtins
-SubDirs :=
-OnlyArchs := i386
-
-AsmSources := $(foreach file,$(wildcard $(Dir)/*.S),$(notdir $(file)))
-Sources := $(foreach file,$(wildcard $(Dir)/*.c),$(notdir $(file)))
-ObjNames := $(Sources:%.c=%.o) $(AsmSources:%.S=%.o)
-Implementation := Optimized
-
-# FIXME: use automatic dependencies?
-Dependencies := $(wildcard lib/*.h $(Dir)/*.h)
diff --git a/lib/i386/ashldi3.S b/lib/i386/ashldi3.S
deleted file mode 100644
index 5488ad6e52be..000000000000
--- a/lib/i386/ashldi3.S
+++ /dev/null
@@ -1,56 +0,0 @@
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
-
-#include "../assembly.h"
-
-// di_int __ashldi3(di_int input, int count);
-
-// This routine has some extra memory traffic, loading the 64-bit input via two
-// 32-bit loads, then immediately storing it back to the stack via a single 64-bit
-// store. This is to avoid a write-small, read-large stall.
-// However, if callers of this routine can be safely assumed to store the argument
-// via a 64-bt store, this is unnecessary memory traffic, and should be avoided.
-// It can be turned off by defining the TRUST_CALLERS_USE_64_BIT_STORES macro.
-
-#ifdef __i386__
-#ifdef __SSE2__
-
-.text
-.align 4
-DEFINE_COMPILERRT_FUNCTION(__ashldi3)
- movd 12(%esp), %xmm2 // Load count
-#ifndef TRUST_CALLERS_USE_64_BIT_STORES
- movd 4(%esp), %xmm0
- movd 8(%esp), %xmm1
- punpckldq %xmm1, %xmm0 // Load input
-#else
- movq 4(%esp), %xmm0 // Load input
-#endif
- psllq %xmm2, %xmm0 // shift input by count
- movd %xmm0, %eax
- psrlq $32, %xmm0
- movd %xmm0, %edx
- ret
-
-#else // Use GPRs instead of SSE2 instructions, if they aren't available.
-
-.text
-.align 4
-DEFINE_COMPILERRT_FUNCTION(__ashldi3)
- movl 12(%esp), %ecx // Load count
- movl 8(%esp), %edx // Load high
- movl 4(%esp), %eax // Load low
-
- testl $0x20, %ecx // If count >= 32
- jnz 1f // goto 1
- shldl %cl, %eax, %edx // left shift high by count
- shll %cl, %eax // left shift low by count
- ret
-
-1: movl %eax, %edx // Move low to high
- xorl %eax, %eax // clear low
- shll %cl, %edx // shift high by count - 32
- ret
-
-#endif // __SSE2__
-#endif // __i386__
diff --git a/lib/i386/ashrdi3.S b/lib/i386/ashrdi3.S
deleted file mode 100644
index b1445ddb99c1..000000000000
--- a/lib/i386/ashrdi3.S
+++ /dev/null
@@ -1,67 +0,0 @@
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
-
-#include "../assembly.h"
-
-// di_int __ashrdi3(di_int input, int count);
-
-#ifdef __i386__
-#ifdef __SSE2__
-
-.text
-.align 4
-DEFINE_COMPILERRT_FUNCTION(__ashrdi3)
- movd 12(%esp), %xmm2 // Load count
- movl 8(%esp), %eax
-#ifndef TRUST_CALLERS_USE_64_BIT_STORES
- movd 4(%esp), %xmm0
- movd 8(%esp), %xmm1
- punpckldq %xmm1, %xmm0 // Load input
-#else
- movq 4(%esp), %xmm0 // Load input
-#endif
-
- psrlq %xmm2, %xmm0 // unsigned shift input by count
-
- testl %eax, %eax // check the sign-bit of the input
- jns 1f // early out for positive inputs
-
- // If the input is negative, we need to construct the shifted sign bit
- // to or into the result, as xmm does not have a signed right shift.
- pcmpeqb %xmm1, %xmm1 // -1ULL
- psrlq $58, %xmm1 // 0x3f
- pandn %xmm1, %xmm2 // 63 - count
- pcmpeqb %xmm1, %xmm1 // -1ULL
- psubq %xmm1, %xmm2 // 64 - count
- psllq %xmm2, %xmm1 // -1 << (64 - count) = leading sign bits
- por %xmm1, %xmm0
-
- // Move the result back to the general purpose registers and return
-1: movd %xmm0, %eax
- psrlq $32, %xmm0
- movd %xmm0, %edx
- ret
-
-#else // Use GPRs instead of SSE2 instructions, if they aren't available.
-
-.text
-.align 4
-DEFINE_COMPILERRT_FUNCTION(__ashrdi3)
- movl 12(%esp), %ecx // Load count
- movl 8(%esp), %edx // Load high
- movl 4(%esp), %eax // Load low
-
- testl $0x20, %ecx // If count >= 32
- jnz 1f // goto 1
-
- shrdl %cl, %edx, %eax // right shift low by count
- sarl %cl, %edx // right shift high by count
- ret
-
-1: movl %edx, %eax // Move high to low
- sarl $31, %edx // clear high
- sarl %cl, %eax // shift low by count - 32
- ret
-
-#endif // __SSE2__
-#endif // __i386__
diff --git a/lib/i386/divdi3.S b/lib/i386/divdi3.S
deleted file mode 100644
index 69593e32e9e3..000000000000
--- a/lib/i386/divdi3.S
+++ /dev/null
@@ -1,161 +0,0 @@
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
-
-#include "../assembly.h"
-
-// di_int __divdi3(di_int a, di_int b);
-
-// result = a / b.
-// both inputs and the output are 64-bit signed integers.
-// This will do whatever the underlying hardware is set to do on division by zero.
-// No other exceptions are generated, as the divide cannot overflow.
-//
-// This is targeted at 32-bit x86 *only*, as this can be done directly in hardware
-// on x86_64. The performance goal is ~40 cycles per divide, which is faster than
-// currently possible via simulation of integer divides on the x87 unit.
-//
-// Stephen Canon, December 2008
-
-#ifdef __i386__
-
-.text
-.align 4
-DEFINE_COMPILERRT_FUNCTION(__divdi3)
-
-/* This is currently implemented by wrapping the unsigned divide up in an absolute
- value, then restoring the correct sign at the end of the computation. This could
- certainly be improved upon. */
-
- pushl %esi
- movl 20(%esp), %edx // high word of b
- movl 16(%esp), %eax // low word of b
- movl %edx, %ecx
- sarl $31, %ecx // (b < 0) ? -1 : 0
- xorl %ecx, %eax
- xorl %ecx, %edx // EDX:EAX = (b < 0) ? not(b) : b
- subl %ecx, %eax
- sbbl %ecx, %edx // EDX:EAX = abs(b)
- movl %edx, 20(%esp)
- movl %eax, 16(%esp) // store abs(b) back to stack
- movl %ecx, %esi // set aside sign of b
-
- movl 12(%esp), %edx // high word of b
- movl 8(%esp), %eax // low word of b
- movl %edx, %ecx
- sarl $31, %ecx // (a < 0) ? -1 : 0
- xorl %ecx, %eax
- xorl %ecx, %edx // EDX:EAX = (a < 0) ? not(a) : a
- subl %ecx, %eax
- sbbl %ecx, %edx // EDX:EAX = abs(a)
- movl %edx, 12(%esp)
- movl %eax, 8(%esp) // store abs(a) back to stack
- xorl %ecx, %esi // sign of result = (sign of a) ^ (sign of b)
-
- pushl %ebx
- movl 24(%esp), %ebx // Find the index i of the leading bit in b.
- bsrl %ebx, %ecx // If the high word of b is zero, jump to
- jz 9f // the code to handle that special case [9].
-
- /* High word of b is known to be non-zero on this branch */
-
- movl 20(%esp), %eax // Construct bhi, containing bits [1+i:32+i] of b
-
- shrl %cl, %eax // Practically, this means that bhi is given by:
- shrl %eax //
- notl %ecx // bhi = (high word of b) << (31 - i) |
- shll %cl, %ebx // (low word of b) >> (1 + i)
- orl %eax, %ebx //
- movl 16(%esp), %edx // Load the high and low words of a, and jump
- movl 12(%esp), %eax // to [1] if the high word is larger than bhi
- cmpl %ebx, %edx // to avoid overflowing the upcoming divide.
- jae 1f
-
- /* High word of a is greater than or equal to (b >> (1 + i)) on this branch */
-
- divl %ebx // eax <-- qs, edx <-- r such that ahi:alo = bs*qs + r
-
- pushl %edi
- notl %ecx
- shrl %eax
- shrl %cl, %eax // q = qs >> (1 + i)
- movl %eax, %edi
- mull 24(%esp) // q*blo
- movl 16(%esp), %ebx
- movl 20(%esp), %ecx // ECX:EBX = a
- subl %eax, %ebx
- sbbl %edx, %ecx // ECX:EBX = a - q*blo
- movl 28(%esp), %eax
- imull %edi, %eax // q*bhi
- subl %eax, %ecx // ECX:EBX = a - q*b
- sbbl $0, %edi // decrement q if remainder is negative
- xorl %edx, %edx
- movl %edi, %eax
-
- addl %esi, %eax // Restore correct sign to result
- adcl %esi, %edx
- xorl %esi, %eax
- xorl %esi, %edx
- popl %edi // Restore callee-save registers
- popl %ebx
- popl %esi
- retl // Return
-
-
-1: /* High word of a is greater than or equal to (b >> (1 + i)) on this branch */
-
- subl %ebx, %edx // subtract bhi from ahi so that divide will not
- divl %ebx // overflow, and find q and r such that
- //
- // ahi:alo = (1:q)*bhi + r
- //
- // Note that q is a number in (31-i).(1+i)
- // fix point.
-
- pushl %edi
- notl %ecx
- shrl %eax
- orl $0x80000000, %eax
- shrl %cl, %eax // q = (1:qs) >> (1 + i)
- movl %eax, %edi
- mull 24(%esp) // q*blo
- movl 16(%esp), %ebx
- movl 20(%esp), %ecx // ECX:EBX = a
- subl %eax, %ebx
- sbbl %edx, %ecx // ECX:EBX = a - q*blo
- movl 28(%esp), %eax
- imull %edi, %eax // q*bhi
- subl %eax, %ecx // ECX:EBX = a - q*b
- sbbl $0, %edi // decrement q if remainder is negative
- xorl %edx, %edx
- movl %edi, %eax
-
- addl %esi, %eax // Restore correct sign to result
- adcl %esi, %edx
- xorl %esi, %eax
- xorl %esi, %edx
- popl %edi // Restore callee-save registers
- popl %ebx
- popl %esi
- retl // Return
-
-
-9: /* High word of b is zero on this branch */
-
- movl 16(%esp), %eax // Find qhi and rhi such that
- movl 20(%esp), %ecx //
- xorl %edx, %edx // ahi = qhi*b + rhi with 0 ≤ rhi < b
- divl %ecx //
- movl %eax, %ebx //
- movl 12(%esp), %eax // Find qlo such that
- divl %ecx //
- movl %ebx, %edx // rhi:alo = qlo*b + rlo with 0 ≤ rlo < b
-
- addl %esi, %eax // Restore correct sign to result
- adcl %esi, %edx
- xorl %esi, %eax
- xorl %esi, %edx
- popl %ebx // Restore callee-save registers
- popl %esi
- retl // Return
-
-#endif // __i386__
diff --git a/lib/i386/floatdidf.S b/lib/i386/floatdidf.S
deleted file mode 100644
index a953d26cec06..000000000000
--- a/lib/i386/floatdidf.S
+++ /dev/null
@@ -1,35 +0,0 @@
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
-
-#include "../assembly.h"
-
-// double __floatundidf(du_int a);
-
-#ifdef __i386__
-
-#ifndef __ELF__
-.const
-#endif
-.align 4
-twop52: .quad 0x4330000000000000
-twop32: .quad 0x41f0000000000000
-
-#define REL_ADDR(_a) (_a)-0b(%eax)
-
-.text
-.align 4
-DEFINE_COMPILERRT_FUNCTION(__floatdidf)
- cvtsi2sd 8(%esp), %xmm1
- movss 4(%esp), %xmm0 // low 32 bits of a
- calll 0f
-0: popl %eax
- mulsd REL_ADDR(twop32), %xmm1 // a_hi as a double (without rounding)
- movsd REL_ADDR(twop52), %xmm2 // 0x1.0p52
- subsd %xmm2, %xmm1 // a_hi - 0x1p52 (no rounding occurs)
- orpd %xmm2, %xmm0 // 0x1p52 + a_lo (no rounding occurs)
- addsd %xmm1, %xmm0 // a_hi + a_lo (round happens here)
- movsd %xmm0, 4(%esp)
- fldl 4(%esp)
- ret
-
-#endif // __i386__
diff --git a/lib/i386/floatdisf.S b/lib/i386/floatdisf.S
deleted file mode 100644
index a98a46ee33ab..000000000000
--- a/lib/i386/floatdisf.S
+++ /dev/null
@@ -1,31 +0,0 @@
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
-
-#include "../assembly.h"
-
-// float __floatdisf(di_int a);
-
-// This routine has some extra memory traffic, loading the 64-bit input via two
-// 32-bit loads, then immediately storing it back to the stack via a single 64-bit
-// store. This is to avoid a write-small, read-large stall.
-// However, if callers of this routine can be safely assumed to store the argument
-// via a 64-bt store, this is unnecessary memory traffic, and should be avoided.
-// It can be turned off by defining the TRUST_CALLERS_USE_64_BIT_STORES macro.
-
-#ifdef __i386__
-
-.text
-.align 4
-DEFINE_COMPILERRT_FUNCTION(__floatdisf)
-#ifndef TRUST_CALLERS_USE_64_BIT_STORES
- movd 4(%esp), %xmm0
- movd 8(%esp), %xmm1
- punpckldq %xmm1, %xmm0
- movq %xmm0, 4(%esp)
-#endif
- fildll 4(%esp)
- fstps 4(%esp)
- flds 4(%esp)
- ret
-
-#endif // __i386__
diff --git a/lib/i386/floatdixf.S b/lib/i386/floatdixf.S
deleted file mode 100644
index 412976fb41b1..000000000000
--- a/lib/i386/floatdixf.S
+++ /dev/null
@@ -1,29 +0,0 @@
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
-
-#include "../assembly.h"
-
-// float __floatdixf(di_int a);
-
-#ifdef __i386__
-
-// This routine has some extra memory traffic, loading the 64-bit input via two
-// 32-bit loads, then immediately storing it back to the stack via a single 64-bit
-// store. This is to avoid a write-small, read-large stall.
-// However, if callers of this routine can be safely assumed to store the argument
-// via a 64-bt store, this is unnecessary memory traffic, and should be avoided.
-// It can be turned off by defining the TRUST_CALLERS_USE_64_BIT_STORES macro.
-
-.text
-.align 4
-DEFINE_COMPILERRT_FUNCTION(__floatdixf)
-#ifndef TRUST_CALLERS_USE_64_BIT_STORES
- movd 4(%esp), %xmm0
- movd 8(%esp), %xmm1
- punpckldq %xmm1, %xmm0
- movq %xmm0, 4(%esp)
-#endif
- fildll 4(%esp)
- ret
-
-#endif // __i386__
diff --git a/lib/i386/floatundidf.S b/lib/i386/floatundidf.S
deleted file mode 100644
index 6bba7e1cf72a..000000000000
--- a/lib/i386/floatundidf.S
+++ /dev/null
@@ -1,46 +0,0 @@
-//===-- floatundidf.S - Implement __floatundidf for i386 ------------------===//
-//
-// 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 __floatundidf for the compiler_rt library.
-//
-//===----------------------------------------------------------------------===//
-
-#include "../assembly.h"
-
-// double __floatundidf(du_int a);
-
-#ifdef __i386__
-
-#ifndef __ELF__
-.const
-#endif
-.align 4
-twop52: .quad 0x4330000000000000
-twop84_plus_twop52:
- .quad 0x4530000000100000
-twop84: .quad 0x4530000000000000
-
-#define REL_ADDR(_a) (_a)-0b(%eax)
-
-.text
-.align 4
-DEFINE_COMPILERRT_FUNCTION(__floatundidf)
- movss 8(%esp), %xmm1 // high 32 bits of a
- movss 4(%esp), %xmm0 // low 32 bits of a
- calll 0f
-0: popl %eax
- orpd REL_ADDR(twop84), %xmm1 // 0x1p84 + a_hi (no rounding occurs)
- subsd REL_ADDR(twop84_plus_twop52), %xmm1 // a_hi - 0x1p52 (no rounding occurs)
- orpd REL_ADDR(twop52), %xmm0 // 0x1p52 + a_lo (no rounding occurs)
- addsd %xmm1, %xmm0 // a_hi + a_lo (round happens here)
- movsd %xmm0, 4(%esp)
- fldl 4(%esp)
- ret
-
-#endif // __i386__
diff --git a/lib/i386/floatundisf.S b/lib/i386/floatundisf.S
deleted file mode 100644
index 1afd1d4d05b3..000000000000
--- a/lib/i386/floatundisf.S
+++ /dev/null
@@ -1,99 +0,0 @@
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
-
-#include "../assembly.h"
-
-// float __floatundisf(du_int a);
-
-// Note that there is a hardware instruction, fildll, that does most of what
-// this function needs to do. However, because of our ia32 ABI, it will take
-// a write-small read-large stall, so the software implementation here is
-// actually several cycles faster.
-
-// This is a branch-free implementation. A branchy implementation might be
-// faster for the common case if you know something a priori about the input
-// distribution.
-
-/* branch-free x87 implementation - one cycle slower than without x87.
-
-#ifdef __i386__
-
-.const
-.align 3
-
- .quad 0x43f0000000000000
-twop64: .quad 0x0000000000000000
-
-#define TWOp64 twop64-0b(%ecx,%eax,8)
-
-.text
-.align 4
-DEFINE_COMPILERRT_FUNCTION(__floatundisf)
- movl 8(%esp), %eax
- movd 8(%esp), %xmm1
- movd 4(%esp), %xmm0
- punpckldq %xmm1, %xmm0
- calll 0f
-0: popl %ecx
- sarl $31, %eax
- movq %xmm0, 4(%esp)
- fildll 4(%esp)
- faddl TWOp64
- fstps 4(%esp)
- flds 4(%esp)
- ret
-
-#endif // __i386__
-
-*/
-
-/* branch-free, x87-free implementation - faster at the expense of code size */
-
-#ifdef __i386__
-
-#ifndef __ELF__
-.const
-.align 3
-#else
-.align 8
-#endif
-twop52: .quad 0x4330000000000000
- .quad 0x0000000000000fff
-sticky: .quad 0x0000000000000000
- .long 0x00000012
-twelve: .long 0x00000000
-
-#define TWOp52 twop52-0b(%ecx)
-#define STICKY sticky-0b(%ecx,%eax,8)
-
-.text
-.align 4
-DEFINE_COMPILERRT_FUNCTION(__floatundisf)
- movl 8(%esp), %eax
- movd 8(%esp), %xmm1
- movd 4(%esp), %xmm0
- punpckldq %xmm1, %xmm0
-
- calll 0f
-0: popl %ecx
- shrl %eax // high 31 bits of input as sint32
- addl $0x7ff80000, %eax
- sarl $31, %eax // (big input) ? -1 : 0
- movsd STICKY, %xmm1 // (big input) ? 0xfff : 0
- movl $12, %edx
- andl %eax, %edx // (big input) ? 12 : 0
- movd %edx, %xmm3
- andpd %xmm0, %xmm1 // (big input) ? input & 0xfff : 0
- movsd TWOp52, %xmm2 // 0x1.0p52
- psrlq %xmm3, %xmm0 // (big input) ? input >> 12 : input
- orpd %xmm2, %xmm1 // 0x1.0p52 + ((big input) ? input & 0xfff : input)
- orpd %xmm1, %xmm0 // 0x1.0p52 + ((big input) ? (input >> 12 | input & 0xfff) : input)
- subsd %xmm2, %xmm0 // (double)((big input) ? (input >> 12 | input & 0xfff) : input)
- cvtsd2ss %xmm0, %xmm0 // (float)((big input) ? (input >> 12 | input & 0xfff) : input)
- pslld $23, %xmm3
- paddd %xmm3, %xmm0 // (float)input
- movd %xmm0, 4(%esp)
- flds 4(%esp)
- ret
-
-#endif // __i386__
diff --git a/lib/i386/floatundixf.S b/lib/i386/floatundixf.S
deleted file mode 100644
index 6e6710bd4ac6..000000000000
--- a/lib/i386/floatundixf.S
+++ /dev/null
@@ -1,37 +0,0 @@
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
-
-#include "../assembly.h"
-
-// long double __floatundixf(du_int a);16
-
-#ifdef __i386__
-
-#ifndef __ELF__
-.const
-#endif
-.align 4
-twop52: .quad 0x4330000000000000
-twop84_plus_twop52_neg:
- .quad 0xc530000000100000
-twop84: .quad 0x4530000000000000
-
-#define REL_ADDR(_a) (_a)-0b(%eax)
-
-.text
-.align 4
-DEFINE_COMPILERRT_FUNCTION(__floatundixf)
- calll 0f
-0: popl %eax
- movss 8(%esp), %xmm0 // hi 32 bits of input
- movss 4(%esp), %xmm1 // lo 32 bits of input
- orpd REL_ADDR(twop84), %xmm0 // 2^84 + hi (as a double)
- orpd REL_ADDR(twop52), %xmm1 // 2^52 + lo (as a double)
- addsd REL_ADDR(twop84_plus_twop52_neg), %xmm0 // hi - 2^52 (no rounding occurs)
- movsd %xmm1, 4(%esp)
- fldl 4(%esp)
- movsd %xmm0, 4(%esp)
- faddl 4(%esp)
- ret
-
-#endif // __i386__
diff --git a/lib/i386/lshrdi3.S b/lib/i386/lshrdi3.S
deleted file mode 100644
index cf411f22e0be..000000000000
--- a/lib/i386/lshrdi3.S
+++ /dev/null
@@ -1,57 +0,0 @@
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
-
-#include "../assembly.h"
-
-// di_int __lshrdi3(di_int input, int count);
-
-// This routine has some extra memory traffic, loading the 64-bit input via two
-// 32-bit loads, then immediately storing it back to the stack via a single 64-bit
-// store. This is to avoid a write-small, read-large stall.
-// However, if callers of this routine can be safely assumed to store the argument
-// via a 64-bt store, this is unnecessary memory traffic, and should be avoided.
-// It can be turned off by defining the TRUST_CALLERS_USE_64_BIT_STORES macro.
-
-#ifdef __i386__
-#ifdef __SSE2__
-
-.text
-.align 4
-DEFINE_COMPILERRT_FUNCTION(__lshrdi3)
- movd 12(%esp), %xmm2 // Load count
-#ifndef TRUST_CALLERS_USE_64_BIT_STORES
- movd 4(%esp), %xmm0
- movd 8(%esp), %xmm1
- punpckldq %xmm1, %xmm0 // Load input
-#else
- movq 4(%esp), %xmm0 // Load input
-#endif
- psrlq %xmm2, %xmm0 // shift input by count
- movd %xmm0, %eax
- psrlq $32, %xmm0
- movd %xmm0, %edx
- ret
-
-#else // Use GPRs instead of SSE2 instructions, if they aren't available.
-
-.text
-.align 4
-DEFINE_COMPILERRT_FUNCTION(__lshrdi3)
- movl 12(%esp), %ecx // Load count
- movl 8(%esp), %edx // Load high
- movl 4(%esp), %eax // Load low
-
- testl $0x20, %ecx // If count >= 32
- jnz 1f // goto 1
-
- shrdl %cl, %edx, %eax // right shift low by count
- shrl %cl, %edx // right shift high by count
- ret
-
-1: movl %edx, %eax // Move high to low
- xorl %edx, %edx // clear high
- shrl %cl, %eax // shift low by count - 32
- ret
-
-#endif // __SSE2__
-#endif // __i386__
diff --git a/lib/i386/moddi3.S b/lib/i386/moddi3.S
deleted file mode 100644
index 8839cfc51d95..000000000000
--- a/lib/i386/moddi3.S
+++ /dev/null
@@ -1,166 +0,0 @@
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
-
-#include "../assembly.h"
-
-// di_int __moddi3(di_int a, di_int b);
-
-// result = remainder of a / b.
-// both inputs and the output are 64-bit signed integers.
-// This will do whatever the underlying hardware is set to do on division by zero.
-// No other exceptions are generated, as the divide cannot overflow.
-//
-// This is targeted at 32-bit x86 *only*, as this can be done directly in hardware
-// on x86_64. The performance goal is ~40 cycles per divide, which is faster than
-// currently possible via simulation of integer divides on the x87 unit.
-//
-
-// Stephen Canon, December 2008
-
-#ifdef __i386__
-
-.text
-.align 4
-DEFINE_COMPILERRT_FUNCTION(__moddi3)
-
-/* This is currently implemented by wrapping the unsigned modulus up in an absolute
- value. This could certainly be improved upon. */
-
- pushl %esi
- movl 20(%esp), %edx // high word of b
- movl 16(%esp), %eax // low word of b
- movl %edx, %ecx
- sarl $31, %ecx // (b < 0) ? -1 : 0
- xorl %ecx, %eax
- xorl %ecx, %edx // EDX:EAX = (b < 0) ? not(b) : b
- subl %ecx, %eax
- sbbl %ecx, %edx // EDX:EAX = abs(b)
- movl %edx, 20(%esp)
- movl %eax, 16(%esp) // store abs(b) back to stack
-
- movl 12(%esp), %edx // high word of b
- movl 8(%esp), %eax // low word of b
- movl %edx, %ecx
- sarl $31, %ecx // (a < 0) ? -1 : 0
- xorl %ecx, %eax
- xorl %ecx, %edx // EDX:EAX = (a < 0) ? not(a) : a
- subl %ecx, %eax
- sbbl %ecx, %edx // EDX:EAX = abs(a)
- movl %edx, 12(%esp)
- movl %eax, 8(%esp) // store abs(a) back to stack
- movl %ecx, %esi // set aside sign of a
-
- pushl %ebx
- movl 24(%esp), %ebx // Find the index i of the leading bit in b.
- bsrl %ebx, %ecx // If the high word of b is zero, jump to
- jz 9f // the code to handle that special case [9].
-
- /* High word of b is known to be non-zero on this branch */
-
- movl 20(%esp), %eax // Construct bhi, containing bits [1+i:32+i] of b
-
- shrl %cl, %eax // Practically, this means that bhi is given by:
- shrl %eax //
- notl %ecx // bhi = (high word of b) << (31 - i) |
- shll %cl, %ebx // (low word of b) >> (1 + i)
- orl %eax, %ebx //
- movl 16(%esp), %edx // Load the high and low words of a, and jump
- movl 12(%esp), %eax // to [2] if the high word is larger than bhi
- cmpl %ebx, %edx // to avoid overflowing the upcoming divide.
- jae 2f
-
- /* High word of a is greater than or equal to (b >> (1 + i)) on this branch */
-
- divl %ebx // eax <-- qs, edx <-- r such that ahi:alo = bs*qs + r
-
- pushl %edi
- notl %ecx
- shrl %eax
- shrl %cl, %eax // q = qs >> (1 + i)
- movl %eax, %edi
- mull 24(%esp) // q*blo
- movl 16(%esp), %ebx
- movl 20(%esp), %ecx // ECX:EBX = a
- subl %eax, %ebx
- sbbl %edx, %ecx // ECX:EBX = a - q*blo
- movl 28(%esp), %eax
- imull %edi, %eax // q*bhi
- subl %eax, %ecx // ECX:EBX = a - q*b
-
- jnc 1f // if positive, this is the result.
- addl 24(%esp), %ebx // otherwise
- adcl 28(%esp), %ecx // ECX:EBX = a - (q-1)*b = result
-1: movl %ebx, %eax
- movl %ecx, %edx
-
- addl %esi, %eax // Restore correct sign to result
- adcl %esi, %edx
- xorl %esi, %eax
- xorl %esi, %edx
- popl %edi // Restore callee-save registers
- popl %ebx
- popl %esi
- retl // Return
-
-2: /* High word of a is greater than or equal to (b >> (1 + i)) on this branch */
-
- subl %ebx, %edx // subtract bhi from ahi so that divide will not
- divl %ebx // overflow, and find q and r such that
- //
- // ahi:alo = (1:q)*bhi + r
- //
- // Note that q is a number in (31-i).(1+i)
- // fix point.
-
- pushl %edi
- notl %ecx
- shrl %eax
- orl $0x80000000, %eax
- shrl %cl, %eax // q = (1:qs) >> (1 + i)
- movl %eax, %edi
- mull 24(%esp) // q*blo
- movl 16(%esp), %ebx
- movl 20(%esp), %ecx // ECX:EBX = a
- subl %eax, %ebx
- sbbl %edx, %ecx // ECX:EBX = a - q*blo
- movl 28(%esp), %eax
- imull %edi, %eax // q*bhi
- subl %eax, %ecx // ECX:EBX = a - q*b
-
- jnc 3f // if positive, this is the result.
- addl 24(%esp), %ebx // otherwise
- adcl 28(%esp), %ecx // ECX:EBX = a - (q-1)*b = result
-3: movl %ebx, %eax
- movl %ecx, %edx
-
- addl %esi, %eax // Restore correct sign to result
- adcl %esi, %edx
- xorl %esi, %eax
- xorl %esi, %edx
- popl %edi // Restore callee-save registers
- popl %ebx
- popl %esi
- retl // Return
-
-9: /* High word of b is zero on this branch */
-
- movl 16(%esp), %eax // Find qhi and rhi such that
- movl 20(%esp), %ecx //
- xorl %edx, %edx // ahi = qhi*b + rhi with 0 ≤ rhi < b
- divl %ecx //
- movl %eax, %ebx //
- movl 12(%esp), %eax // Find rlo such that
- divl %ecx //
- movl %edx, %eax // rhi:alo = qlo*b + rlo with 0 ≤ rlo < b
- popl %ebx //
- xorl %edx, %edx // and return 0:rlo
-
- addl %esi, %eax // Restore correct sign to result
- adcl %esi, %edx
- xorl %esi, %eax
- xorl %esi, %edx
- popl %esi
- retl // Return
-
-
-#endif // __i386__
diff --git a/lib/i386/muldi3.S b/lib/i386/muldi3.S
deleted file mode 100644
index e56a3553bd31..000000000000
--- a/lib/i386/muldi3.S
+++ /dev/null
@@ -1,29 +0,0 @@
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
-
-#include "../assembly.h"
-
-// di_int __muldi3(di_int a, di_int b);
-
-#ifdef __i386__
-
-.text
-.align 4
-DEFINE_COMPILERRT_FUNCTION(__muldi3)
- pushl %ebx
- movl 16(%esp), %eax // b.lo
- movl 12(%esp), %ecx // a.hi
- imull %eax, %ecx // b.lo * a.hi
-
- movl 8(%esp), %edx // a.lo
- movl 20(%esp), %ebx // b.hi
- imull %edx, %ebx // a.lo * b.hi
-
- mull %edx // EDX:EAX = a.lo * b.lo
- addl %ecx, %ebx // EBX = (a.lo*b.hi + a.hi*b.lo)
- addl %ebx, %edx
-
- popl %ebx
- retl
-
-#endif // __i386__
diff --git a/lib/i386/udivdi3.S b/lib/i386/udivdi3.S
deleted file mode 100644
index 5abeaeaaf476..000000000000
--- a/lib/i386/udivdi3.S
+++ /dev/null
@@ -1,114 +0,0 @@
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
-
-#include "../assembly.h"
-
-// du_int __udivdi3(du_int a, du_int b);
-
-// result = a / b.
-// both inputs and the output are 64-bit unsigned integers.
-// This will do whatever the underlying hardware is set to do on division by zero.
-// No other exceptions are generated, as the divide cannot overflow.
-//
-// This is targeted at 32-bit x86 *only*, as this can be done directly in hardware
-// on x86_64. The performance goal is ~40 cycles per divide, which is faster than
-// currently possible via simulation of integer divides on the x87 unit.
-//
-// Stephen Canon, December 2008
-
-#ifdef __i386__
-
-.text
-.align 4
-DEFINE_COMPILERRT_FUNCTION(__udivdi3)
-
- pushl %ebx
- movl 20(%esp), %ebx // Find the index i of the leading bit in b.
- bsrl %ebx, %ecx // If the high word of b is zero, jump to
- jz 9f // the code to handle that special case [9].
-
- /* High word of b is known to be non-zero on this branch */
-
- movl 16(%esp), %eax // Construct bhi, containing bits [1+i:32+i] of b
-
- shrl %cl, %eax // Practically, this means that bhi is given by:
- shrl %eax //
- notl %ecx // bhi = (high word of b) << (31 - i) |
- shll %cl, %ebx // (low word of b) >> (1 + i)
- orl %eax, %ebx //
- movl 12(%esp), %edx // Load the high and low words of a, and jump
- movl 8(%esp), %eax // to [1] if the high word is larger than bhi
- cmpl %ebx, %edx // to avoid overflowing the upcoming divide.
- jae 1f
-
- /* High word of a is greater than or equal to (b >> (1 + i)) on this branch */
-
- divl %ebx // eax <-- qs, edx <-- r such that ahi:alo = bs*qs + r
-
- pushl %edi
- notl %ecx
- shrl %eax
- shrl %cl, %eax // q = qs >> (1 + i)
- movl %eax, %edi
- mull 20(%esp) // q*blo
- movl 12(%esp), %ebx
- movl 16(%esp), %ecx // ECX:EBX = a
- subl %eax, %ebx
- sbbl %edx, %ecx // ECX:EBX = a - q*blo
- movl 24(%esp), %eax
- imull %edi, %eax // q*bhi
- subl %eax, %ecx // ECX:EBX = a - q*b
- sbbl $0, %edi // decrement q if remainder is negative
- xorl %edx, %edx
- movl %edi, %eax
- popl %edi
- popl %ebx
- retl
-
-
-1: /* High word of a is greater than or equal to (b >> (1 + i)) on this branch */
-
- subl %ebx, %edx // subtract bhi from ahi so that divide will not
- divl %ebx // overflow, and find q and r such that
- //
- // ahi:alo = (1:q)*bhi + r
- //
- // Note that q is a number in (31-i).(1+i)
- // fix point.
-
- pushl %edi
- notl %ecx
- shrl %eax
- orl $0x80000000, %eax
- shrl %cl, %eax // q = (1:qs) >> (1 + i)
- movl %eax, %edi
- mull 20(%esp) // q*blo
- movl 12(%esp), %ebx
- movl 16(%esp), %ecx // ECX:EBX = a
- subl %eax, %ebx
- sbbl %edx, %ecx // ECX:EBX = a - q*blo
- movl 24(%esp), %eax
- imull %edi, %eax // q*bhi
- subl %eax, %ecx // ECX:EBX = a - q*b
- sbbl $0, %edi // decrement q if remainder is negative
- xorl %edx, %edx
- movl %edi, %eax
- popl %edi
- popl %ebx
- retl
-
-
-9: /* High word of b is zero on this branch */
-
- movl 12(%esp), %eax // Find qhi and rhi such that
- movl 16(%esp), %ecx //
- xorl %edx, %edx // ahi = qhi*b + rhi with 0 ≤ rhi < b
- divl %ecx //
- movl %eax, %ebx //
- movl 8(%esp), %eax // Find qlo such that
- divl %ecx //
- movl %ebx, %edx // rhi:alo = qlo*b + rlo with 0 ≤ rlo < b
- popl %ebx //
- retl // and return qhi:qlo
-
-#endif // __i386__
diff --git a/lib/i386/umoddi3.S b/lib/i386/umoddi3.S
deleted file mode 100644
index 7fd84853b5b2..000000000000
--- a/lib/i386/umoddi3.S
+++ /dev/null
@@ -1,125 +0,0 @@
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
-
-#include "../assembly.h"
-
-// du_int __umoddi3(du_int a, du_int b);
-
-// result = remainder of a / b.
-// both inputs and the output are 64-bit unsigned integers.
-// This will do whatever the underlying hardware is set to do on division by zero.
-// No other exceptions are generated, as the divide cannot overflow.
-//
-// This is targeted at 32-bit x86 *only*, as this can be done directly in hardware
-// on x86_64. The performance goal is ~40 cycles per divide, which is faster than
-// currently possible via simulation of integer divides on the x87 unit.
-//
-
-// Stephen Canon, December 2008
-
-#ifdef __i386__
-
-.text
-.align 4
-DEFINE_COMPILERRT_FUNCTION(__umoddi3)
-
- pushl %ebx
- movl 20(%esp), %ebx // Find the index i of the leading bit in b.
- bsrl %ebx, %ecx // If the high word of b is zero, jump to
- jz 9f // the code to handle that special case [9].
-
- /* High word of b is known to be non-zero on this branch */
-
- movl 16(%esp), %eax // Construct bhi, containing bits [1+i:32+i] of b
-
- shrl %cl, %eax // Practically, this means that bhi is given by:
- shrl %eax //
- notl %ecx // bhi = (high word of b) << (31 - i) |
- shll %cl, %ebx // (low word of b) >> (1 + i)
- orl %eax, %ebx //
- movl 12(%esp), %edx // Load the high and low words of a, and jump
- movl 8(%esp), %eax // to [2] if the high word is larger than bhi
- cmpl %ebx, %edx // to avoid overflowing the upcoming divide.
- jae 2f
-
- /* High word of a is greater than or equal to (b >> (1 + i)) on this branch */
-
- divl %ebx // eax <-- qs, edx <-- r such that ahi:alo = bs*qs + r
-
- pushl %edi
- notl %ecx
- shrl %eax
- shrl %cl, %eax // q = qs >> (1 + i)
- movl %eax, %edi
- mull 20(%esp) // q*blo
- movl 12(%esp), %ebx
- movl 16(%esp), %ecx // ECX:EBX = a
- subl %eax, %ebx
- sbbl %edx, %ecx // ECX:EBX = a - q*blo
- movl 24(%esp), %eax
- imull %edi, %eax // q*bhi
- subl %eax, %ecx // ECX:EBX = a - q*b
-
- jnc 1f // if positive, this is the result.
- addl 20(%esp), %ebx // otherwise
- adcl 24(%esp), %ecx // ECX:EBX = a - (q-1)*b = result
-1: movl %ebx, %eax
- movl %ecx, %edx
-
- popl %edi
- popl %ebx
- retl
-
-
-2: /* High word of a is greater than or equal to (b >> (1 + i)) on this branch */
-
- subl %ebx, %edx // subtract bhi from ahi so that divide will not
- divl %ebx // overflow, and find q and r such that
- //
- // ahi:alo = (1:q)*bhi + r
- //
- // Note that q is a number in (31-i).(1+i)
- // fix point.
-
- pushl %edi
- notl %ecx
- shrl %eax
- orl $0x80000000, %eax
- shrl %cl, %eax // q = (1:qs) >> (1 + i)
- movl %eax, %edi
- mull 20(%esp) // q*blo
- movl 12(%esp), %ebx
- movl 16(%esp), %ecx // ECX:EBX = a
- subl %eax, %ebx
- sbbl %edx, %ecx // ECX:EBX = a - q*blo
- movl 24(%esp), %eax
- imull %edi, %eax // q*bhi
- subl %eax, %ecx // ECX:EBX = a - q*b
-
- jnc 3f // if positive, this is the result.
- addl 20(%esp), %ebx // otherwise
- adcl 24(%esp), %ecx // ECX:EBX = a - (q-1)*b = result
-3: movl %ebx, %eax
- movl %ecx, %edx
-
- popl %edi
- popl %ebx
- retl
-
-
-
-9: /* High word of b is zero on this branch */
-
- movl 12(%esp), %eax // Find qhi and rhi such that
- movl 16(%esp), %ecx //
- xorl %edx, %edx // ahi = qhi*b + rhi with 0 ≤ rhi < b
- divl %ecx //
- movl %eax, %ebx //
- movl 8(%esp), %eax // Find rlo such that
- divl %ecx //
- movl %edx, %eax // rhi:alo = qlo*b + rlo with 0 ≤ rlo < b
- popl %ebx //
- xorl %edx, %edx // and return 0:rlo
- retl //
-
-#endif // __i386__
diff --git a/lib/int_endianness.h b/lib/int_endianness.h
deleted file mode 100644
index a64f926478ca..000000000000
--- a/lib/int_endianness.h
+++ /dev/null
@@ -1,111 +0,0 @@
-/* ===-- int_endianness.h - configuration header for compiler-rt ------------===
- *
- * 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 is a configuration header for compiler-rt.
- * This file is not part of the interface of this library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#ifndef INT_ENDIANNESS_H
-#define INT_ENDIANNESS_H
-
-#if defined(__SVR4) && defined(__sun)
-#include <sys/byteorder.h>
-
-#if defined(_BIG_ENDIAN)
-#define _YUGA_LITTLE_ENDIAN 0
-#define _YUGA_BIG_ENDIAN 1
-#elif defined(_LITTLE_ENDIAN)
-#define _YUGA_LITTLE_ENDIAN 1
-#define _YUGA_BIG_ENDIAN 0
-#else /* !_LITTLE_ENDIAN */
-#error "unknown endianness"
-#endif /* !_LITTLE_ENDIAN */
-
-#endif /* Solaris and AuroraUX. */
-
-/* .. */
-
-#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__minix)
-#include <sys/endian.h>
-
-#if _BYTE_ORDER == _BIG_ENDIAN
-#define _YUGA_LITTLE_ENDIAN 0
-#define _YUGA_BIG_ENDIAN 1
-#elif _BYTE_ORDER == _LITTLE_ENDIAN
-#define _YUGA_LITTLE_ENDIAN 1
-#define _YUGA_BIG_ENDIAN 0
-#endif /* _BYTE_ORDER */
-
-#endif /* *BSD */
-
-#if defined(__OpenBSD__) || defined(__Bitrig__)
-#include <machine/endian.h>
-
-#if _BYTE_ORDER == _BIG_ENDIAN
-#define _YUGA_LITTLE_ENDIAN 0
-#define _YUGA_BIG_ENDIAN 1
-#elif _BYTE_ORDER == _LITTLE_ENDIAN
-#define _YUGA_LITTLE_ENDIAN 1
-#define _YUGA_BIG_ENDIAN 0
-#endif /* _BYTE_ORDER */
-
-#endif /* OpenBSD and Bitrig. */
-
-/* .. */
-
-/* Mac OSX has __BIG_ENDIAN__ or __LITTLE_ENDIAN__ automatically set by the compiler (at least with GCC) */
-#if defined(__APPLE__) && defined(__MACH__) || defined(__ellcc__ )
-
-#ifdef __BIG_ENDIAN__
-#if __BIG_ENDIAN__
-#define _YUGA_LITTLE_ENDIAN 0
-#define _YUGA_BIG_ENDIAN 1
-#endif
-#endif /* __BIG_ENDIAN__ */
-
-#ifdef __LITTLE_ENDIAN__
-#if __LITTLE_ENDIAN__
-#define _YUGA_LITTLE_ENDIAN 1
-#define _YUGA_BIG_ENDIAN 0
-#endif
-#endif /* __LITTLE_ENDIAN__ */
-
-#endif /* Mac OSX */
-
-/* .. */
-
-#if defined(__linux__)
-#include <endian.h>
-
-#if __BYTE_ORDER == __BIG_ENDIAN
-#define _YUGA_LITTLE_ENDIAN 0
-#define _YUGA_BIG_ENDIAN 1
-#elif __BYTE_ORDER == __LITTLE_ENDIAN
-#define _YUGA_LITTLE_ENDIAN 1
-#define _YUGA_BIG_ENDIAN 0
-#endif /* __BYTE_ORDER */
-
-#endif /* GNU/Linux */
-
-#if defined(_WIN32)
-
-#define _YUGA_LITTLE_ENDIAN 1
-#define _YUGA_BIG_ENDIAN 0
-
-#endif /* Windows */
-
-/* . */
-
-#if !defined(_YUGA_LITTLE_ENDIAN) || !defined(_YUGA_BIG_ENDIAN)
-#error Unable to determine endian
-#endif /* Check we found an endianness correctly. */
-
-#endif /* INT_ENDIANNESS_H */
diff --git a/lib/int_lib.h b/lib/int_lib.h
deleted file mode 100644
index a87426c513c6..000000000000
--- a/lib/int_lib.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/* ===-- int_lib.h - configuration header for compiler-rt -----------------===
- *
- * 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 is a configuration header for compiler-rt.
- * This file is not part of the interface of this library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#ifndef INT_LIB_H
-#define INT_LIB_H
-
-/* Assumption: Signed integral is 2's complement. */
-/* Assumption: Right shift of signed negative is arithmetic shift. */
-/* Assumption: Endianness is little or big (not mixed). */
-
-/* ABI macro definitions */
-
-#if __ARM_EABI__
-# define ARM_EABI_FNALIAS(aeabi_name, name) \
- void __aeabi_##aeabi_name() __attribute__((alias("__" #name)));
-# define COMPILER_RT_ABI __attribute__((pcs("aapcs")))
-#else
-# define ARM_EABI_FNALIAS(aeabi_name, name)
-# define COMPILER_RT_ABI
-#endif
-
-/* Include the standard compiler builtin headers we use functionality from. */
-#include <limits.h>
-#include <stdint.h>
-#include <stdbool.h>
-#include <float.h>
-
-/* Include the commonly used internal type definitions. */
-#include "int_types.h"
-
-/* Include internal utility function declarations. */
-#include "int_util.h"
-
-#endif /* INT_LIB_H */
diff --git a/lib/int_types.h b/lib/int_types.h
deleted file mode 100644
index fcce390f9a9b..000000000000
--- a/lib/int_types.h
+++ /dev/null
@@ -1,140 +0,0 @@
-/* ===-- int_lib.h - configuration header for compiler-rt -----------------===
- *
- * 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 is not part of the interface of this library.
- *
- * This file defines various standard types, most importantly a number of unions
- * used to access parts of larger types.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#ifndef INT_TYPES_H
-#define INT_TYPES_H
-
-#include "int_endianness.h"
-
-typedef int si_int;
-typedef unsigned su_int;
-
-typedef long long di_int;
-typedef unsigned long long du_int;
-
-typedef union
-{
- di_int all;
- struct
- {
-#if _YUGA_LITTLE_ENDIAN
- su_int low;
- si_int high;
-#else
- si_int high;
- su_int low;
-#endif /* _YUGA_LITTLE_ENDIAN */
- }s;
-} dwords;
-
-typedef union
-{
- du_int all;
- struct
- {
-#if _YUGA_LITTLE_ENDIAN
- su_int low;
- su_int high;
-#else
- su_int high;
- su_int low;
-#endif /* _YUGA_LITTLE_ENDIAN */
- }s;
-} udwords;
-
-#if __x86_64
-
-typedef int ti_int __attribute__ ((mode (TI)));
-typedef unsigned tu_int __attribute__ ((mode (TI)));
-
-typedef union
-{
- ti_int all;
- struct
- {
-#if _YUGA_LITTLE_ENDIAN
- du_int low;
- di_int high;
-#else
- di_int high;
- du_int low;
-#endif /* _YUGA_LITTLE_ENDIAN */
- }s;
-} twords;
-
-typedef union
-{
- tu_int all;
- struct
- {
-#if _YUGA_LITTLE_ENDIAN
- du_int low;
- du_int high;
-#else
- du_int high;
- du_int low;
-#endif /* _YUGA_LITTLE_ENDIAN */
- }s;
-} utwords;
-
-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) {
- utwords r;
- r.s.high = h;
- r.s.low = l;
- return r.all;
-}
-
-#endif /* __x86_64 */
-
-typedef union
-{
- su_int u;
- float f;
-} float_bits;
-
-typedef union
-{
- udwords u;
- double f;
-} double_bits;
-
-typedef struct
-{
-#if _YUGA_LITTLE_ENDIAN
- udwords low;
- udwords high;
-#else
- udwords high;
- udwords low;
-#endif /* _YUGA_LITTLE_ENDIAN */
-} uqwords;
-
-typedef union
-{
- uqwords u;
- long double f;
-} long_double_bits;
-
-#endif /* INT_TYPES_H */
-
diff --git a/lib/int_util.h b/lib/int_util.h
deleted file mode 100644
index 1348b85eb923..000000000000
--- a/lib/int_util.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/* ===-- int_util.h - internal utility functions ----------------------------===
- *
- * 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 is not part of the interface of this library.
- *
- * This file defines non-inline utilities which are available for use in the
- * library. The function definitions themselves are all contained in int_util.c
- * which will always be compiled into any compiler-rt library.
- *
- * ===-----------------------------------------------------------------------===
- */
-
-#ifndef INT_UTIL_H
-#define INT_UTIL_H
-
-/** \brief Trigger a program abort (or panic for kernel code). */
-#define compilerrt_abort() compilerrt_abort_impl(__FILE__, __LINE__, \
- __FUNCTION__)
-
-void compilerrt_abort_impl(const char *file, int line,
- const char *function) __attribute__((noreturn));
-
-#endif /* INT_UTIL_H */
diff --git a/lib/interception/CMakeLists.txt b/lib/interception/CMakeLists.txt
index 1dfdaffb6dc1..b77f2d1562b7 100644
--- a/lib/interception/CMakeLists.txt
+++ b/lib/interception/CMakeLists.txt
@@ -10,6 +10,7 @@ set(INTERCEPTION_SOURCES
include_directories(..)
set(INTERCEPTION_CFLAGS ${SANITIZER_COMMON_CFLAGS})
+append_no_rtti_flag(INTERCEPTION_CFLAGS)
if(APPLE)
# Build universal binary on APPLE.
@@ -19,10 +20,6 @@ if(APPLE)
SOURCES ${INTERCEPTION_SOURCES}
CFLAGS ${INTERCEPTION_CFLAGS})
endforeach()
-elseif(ANDROID)
- add_library(RTInterception.arm.android OBJECT ${INTERCEPTION_SOURCES})
- set_target_compile_flags(RTInterception.arm.android
- ${INTERCEPTION_CFLAGS})
else()
# Otherwise, build separate libraries for each target.
foreach(arch ${SANITIZER_COMMON_SUPPORTED_ARCH})
diff --git a/lib/interception/interception.h b/lib/interception/interception.h
index baddd6c132c9..52573258bf98 100644
--- a/lib/interception/interception.h
+++ b/lib/interception/interception.h
@@ -15,7 +15,8 @@
#ifndef INTERCEPTION_H
#define INTERCEPTION_H
-#if !defined(__linux__) && !defined(__APPLE__) && !defined(_WIN32)
+#if !defined(__linux__) && !defined(__FreeBSD__) && \
+ !defined(__APPLE__) && !defined(_WIN32)
# error "Interception doesn't work on this operating system."
#endif
@@ -121,19 +122,23 @@ const interpose_substitution substitution_##func_name[] \
# define DECLARE_WRAPPER(ret_type, func, ...)
#elif defined(_WIN32)
-# if defined(_DLL) // DLL CRT
-# define WRAP(x) x
-# define WRAPPER_NAME(x) #x
-# define INTERCEPTOR_ATTRIBUTE
-# else // Static CRT
-# define WRAP(x) wrap_##x
-# define WRAPPER_NAME(x) "wrap_"#x
-# define INTERCEPTOR_ATTRIBUTE
-# endif
+# define WRAP(x) __asan_wrap_##x
+# define WRAPPER_NAME(x) "__asan_wrap_"#x
+# define INTERCEPTOR_ATTRIBUTE __declspec(dllexport)
# define DECLARE_WRAPPER(ret_type, func, ...) \
extern "C" ret_type func(__VA_ARGS__);
# define DECLARE_WRAPPER_WINAPI(ret_type, func, ...) \
extern "C" __declspec(dllimport) ret_type __stdcall func(__VA_ARGS__);
+#elif defined(__FreeBSD__)
+# define WRAP(x) __interceptor_ ## x
+# define WRAPPER_NAME(x) "__interceptor_" #x
+# define INTERCEPTOR_ATTRIBUTE __attribute__((visibility("default")))
+// FreeBSD's dynamic linker (incompliantly) gives non-weak symbols higher
+// priority than weak ones so weak aliases won't work for indirect calls
+// in position-independent (-fPIC / -fPIE) mode.
+# define DECLARE_WRAPPER(ret_type, func, ...) \
+ extern "C" ret_type func(__VA_ARGS__) \
+ __attribute__((alias("__interceptor_" #func), visibility("default")));
#else
# define WRAP(x) __interceptor_ ## x
# define WRAPPER_NAME(x) "__interceptor_" #x
@@ -235,11 +240,11 @@ typedef unsigned long uptr; // NOLINT
#define INCLUDED_FROM_INTERCEPTION_LIB
-#if defined(__linux__)
+#if defined(__linux__) || defined(__FreeBSD__)
# include "interception_linux.h"
-# define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_LINUX(func)
+# define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_LINUX_OR_FREEBSD(func)
# define INTERCEPT_FUNCTION_VER(func, symver) \
- INTERCEPT_FUNCTION_VER_LINUX(func, symver)
+ INTERCEPT_FUNCTION_VER_LINUX_OR_FREEBSD(func, symver)
#elif defined(__APPLE__)
# include "interception_mac.h"
# define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_MAC(func)
diff --git a/lib/interception/interception_linux.cc b/lib/interception/interception_linux.cc
index 53f42881016c..6e908ac017b2 100644
--- a/lib/interception/interception_linux.cc
+++ b/lib/interception/interception_linux.cc
@@ -12,10 +12,10 @@
// Linux-specific interception methods.
//===----------------------------------------------------------------------===//
-#ifdef __linux__
+#if defined(__linux__) || defined(__FreeBSD__)
#include "interception.h"
-#include <dlfcn.h> // for dlsym
+#include <dlfcn.h> // for dlsym() and dlvsym()
namespace __interception {
bool GetRealFunctionAddress(const char *func_name, uptr *func_addr,
@@ -33,4 +33,4 @@ void *GetFuncAddrVer(const char *func_name, const char *ver) {
} // namespace __interception
-#endif // __linux__
+#endif // __linux__ || __FreeBSD__
diff --git a/lib/interception/interception_linux.h b/lib/interception/interception_linux.h
index cea957320d05..d3f774bede9f 100644
--- a/lib/interception/interception_linux.h
+++ b/lib/interception/interception_linux.h
@@ -12,7 +12,7 @@
// Linux-specific interception methods.
//===----------------------------------------------------------------------===//
-#ifdef __linux__
+#if defined(__linux__) || defined(__FreeBSD__)
#if !defined(INCLUDED_FROM_INTERCEPTION_LIB)
# error "interception_linux.h should be included from interception library only"
@@ -28,20 +28,20 @@ bool GetRealFunctionAddress(const char *func_name, uptr *func_addr,
void *GetFuncAddrVer(const char *func_name, const char *ver);
} // namespace __interception
-#define INTERCEPT_FUNCTION_LINUX(func) \
- ::__interception::GetRealFunctionAddress( \
- #func, (::__interception::uptr*)&REAL(func), \
- (::__interception::uptr)&(func), \
- (::__interception::uptr)&WRAP(func))
+#define INTERCEPT_FUNCTION_LINUX_OR_FREEBSD(func) \
+ ::__interception::GetRealFunctionAddress( \
+ #func, (::__interception::uptr *)&__interception::PTR_TO_REAL(func), \
+ (::__interception::uptr) & (func), \
+ (::__interception::uptr) & WRAP(func))
#if !defined(__ANDROID__) // android does not have dlvsym
-# define INTERCEPT_FUNCTION_VER_LINUX(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(func, symver) \
- INTERCEPT_FUNCTION_LINUX(func)
+# define INTERCEPT_FUNCTION_VER_LINUX_OR_FREEBSD(func, symver) \
+ INTERCEPT_FUNCTION_LINUX_OR_FREEBSD(func)
#endif // !defined(__ANDROID__)
#endif // INTERCEPTION_LINUX_H
-#endif // __linux__
+#endif // __linux__ || __FreeBSD__
diff --git a/lib/interception/interception_type_test.cc b/lib/interception/interception_type_test.cc
index 7b79b783fbe9..98ce2e6afc1b 100644
--- a/lib/interception/interception_type_test.cc
+++ b/lib/interception/interception_type_test.cc
@@ -19,13 +19,13 @@
#include <stddef.h>
#include <stdint.h>
-COMPILER_CHECK(sizeof(SIZE_T) == sizeof(size_t));
-COMPILER_CHECK(sizeof(SSIZE_T) == sizeof(ssize_t));
-COMPILER_CHECK(sizeof(PTRDIFF_T) == sizeof(ptrdiff_t));
-COMPILER_CHECK(sizeof(INTMAX_T) == sizeof(intmax_t));
+COMPILER_CHECK(sizeof(::SIZE_T) == sizeof(size_t));
+COMPILER_CHECK(sizeof(::SSIZE_T) == sizeof(ssize_t));
+COMPILER_CHECK(sizeof(::PTRDIFF_T) == sizeof(ptrdiff_t));
+COMPILER_CHECK(sizeof(::INTMAX_T) == sizeof(intmax_t));
#ifndef __APPLE__
-COMPILER_CHECK(sizeof(OFF64_T) == sizeof(off64_t));
+COMPILER_CHECK(sizeof(::OFF64_T) == sizeof(off64_t));
#endif
// The following are the cases when pread (and friends) is used instead of
@@ -33,7 +33,7 @@ COMPILER_CHECK(sizeof(OFF64_T) == sizeof(off64_t));
// rest (they depend on _FILE_OFFSET_BITS setting when building an application).
# if defined(__ANDROID__) || !defined _FILE_OFFSET_BITS || \
_FILE_OFFSET_BITS != 64
-COMPILER_CHECK(sizeof(OFF_T) == sizeof(off_t));
+COMPILER_CHECK(sizeof(::OFF_T) == sizeof(off_t));
# endif
#endif
diff --git a/lib/interception/interception_win.cc b/lib/interception/interception_win.cc
index abbab24970cd..cd241c3d23c3 100644
--- a/lib/interception/interception_win.cc
+++ b/lib/interception/interception_win.cc
@@ -19,20 +19,6 @@
namespace __interception {
-bool GetRealFunctionAddress(const char *func_name, uptr *func_addr) {
- const char *DLLS[] = {
- "msvcr80.dll",
- "msvcr90.dll",
- "kernel32.dll",
- NULL
- };
- *func_addr = 0;
- for (size_t i = 0; *func_addr == 0 && DLLS[i]; ++i) {
- *func_addr = (uptr)GetProcAddress(GetModuleHandleA(DLLS[i]), func_name);
- }
- return (*func_addr != 0);
-}
-
// FIXME: internal_str* and internal_mem* functions should be moved from the
// ASan sources into interception/.
@@ -56,96 +42,175 @@ static void WriteJumpInstruction(char *jmp_from, char *to) {
*(ptrdiff_t*)(jmp_from + 1) = offset;
}
-bool OverrideFunction(uptr old_func, uptr new_func, uptr *orig_old_func) {
-#ifdef _WIN64
-# error OverrideFunction was not tested on x64
-#endif
- // Basic idea:
- // We write 5 bytes (jmp-to-new_func) at the beginning of the 'old_func'
- // to override it. We want to be able to execute the original 'old_func' from
- // the wrapper, so we need to keep the leading 5+ bytes ('head') of the
- // original instructions somewhere with a "jmp old_func+head".
- // We call these 'head'+5 bytes of instructions a "trampoline".
-
+static char *GetMemoryForTrampoline(size_t size) {
// Trampolines are allocated from a common pool.
const int POOL_SIZE = 1024;
static char *pool = NULL;
static size_t pool_used = 0;
- if (pool == NULL) {
- pool = (char*)VirtualAlloc(NULL, POOL_SIZE,
- MEM_RESERVE | MEM_COMMIT,
- PAGE_EXECUTE_READWRITE);
- // FIXME: set PAGE_EXECUTE_READ access after setting all interceptors?
- if (pool == NULL)
- return false;
+ if (!pool) {
+ pool = (char *)VirtualAlloc(NULL, POOL_SIZE, MEM_RESERVE | MEM_COMMIT,
+ PAGE_EXECUTE_READWRITE);
+ // FIXME: Might want to apply PAGE_EXECUTE_READ access after all the
+ // interceptors are in place.
+ if (!pool)
+ return NULL;
_memset(pool, 0xCC /* int 3 */, POOL_SIZE);
}
- char* old_bytes = (char*)old_func;
- char* trampoline = pool + pool_used;
+ if (pool_used + size > POOL_SIZE)
+ return NULL;
+
+ char *ret = pool + pool_used;
+ pool_used += size;
+ return ret;
+}
- // Find out the number of bytes of the instructions we need to copy to the
- // island and store it in 'head'.
- size_t head = 0;
- while (head < 5) {
- switch (old_bytes[head]) {
+// Returns 0 on error.
+static size_t RoundUpToInstrBoundary(size_t size, char *code) {
+ size_t cursor = 0;
+ while (cursor < size) {
+ switch (code[cursor]) {
+ case '\x51': // push ecx
+ case '\x52': // push edx
+ case '\x53': // push ebx
+ case '\x54': // push esp
case '\x55': // push ebp
case '\x56': // push esi
case '\x57': // push edi
- head++;
+ case '\x5D': // pop ebp
+ cursor++;
+ continue;
+ case '\x6A': // 6A XX = push XX
+ cursor += 2;
+ continue;
+ case '\xE9': // E9 XX YY ZZ WW = jmp WWZZYYXX
+ cursor += 5;
continue;
}
- switch (*(unsigned short*)(old_bytes + head)) { // NOLINT
+ switch (*(unsigned short*)(code + cursor)) { // NOLINT
case 0xFF8B: // 8B FF = mov edi, edi
case 0xEC8B: // 8B EC = mov ebp, esp
case 0xC033: // 33 C0 = xor eax, eax
- head += 2;
+ cursor += 2;
continue;
+ case 0x458B: // 8B 45 XX = mov eax, dword ptr [ebp+XXh]
+ case 0x5D8B: // 8B 5D XX = mov ebx, dword ptr [ebp+XXh]
case 0xEC83: // 83 EC XX = sub esp, XX
- head += 3;
+ case 0x75FF: // FF 75 XX = push dword ptr [ebp+XXh]
+ cursor += 3;
continue;
case 0xC1F7: // F7 C1 XX YY ZZ WW = test ecx, WWZZYYXX
- head += 6;
+ case 0x25FF: // FF 25 XX YY ZZ WW = jmp dword ptr ds:[WWZZYYXX]
+ cursor += 6;
+ continue;
+ case 0x3D83: // 83 3D XX YY ZZ WW TT = cmp TT, WWZZYYXX
+ cursor += 7;
continue;
}
- switch (0x00FFFFFF & *(unsigned int*)(old_bytes + head)) {
+ switch (0x00FFFFFF & *(unsigned int*)(code + cursor)) {
case 0x24448A: // 8A 44 24 XX = mov eal, dword ptr [esp+XXh]
+ case 0x24448B: // 8B 44 24 XX = mov eax, dword ptr [esp+XXh]
case 0x244C8B: // 8B 4C 24 XX = mov ecx, dword ptr [esp+XXh]
case 0x24548B: // 8B 54 24 XX = mov edx, dword ptr [esp+XXh]
+ case 0x24748B: // 8B 74 24 XX = mov esi, dword ptr [esp+XXh]
case 0x247C8B: // 8B 7C 24 XX = mov edi, dword ptr [esp+XXh]
- head += 4;
+ cursor += 4;
continue;
}
// Unknown instruction!
- return false;
+ // FIXME: Unknown instruction failures might happen when we add a new
+ // interceptor or a new compiler version. In either case, they should result
+ // in visible and readable error messages. However, merely calling abort()
+ // leads to an infinite recursion in CheckFailed.
+ // Do we have a good way to abort with an error message here?
+ __debugbreak();
+ return 0;
}
- if (pool_used + head + 5 > POOL_SIZE)
- return false;
+ return cursor;
+}
+
+bool OverrideFunction(uptr old_func, uptr new_func, uptr *orig_old_func) {
+#ifdef _WIN64
+#error OverrideFunction is not yet supported on x64
+#endif
+ // Function overriding works basically like this:
+ // We write "jmp <new_func>" (5 bytes) at the beginning of the 'old_func'
+ // to override it.
+ // We might want to be able to execute the original 'old_func' from the
+ // wrapper, in this case we need to keep the leading 5+ bytes ('head')
+ // of the original code somewhere with a "jmp <old_func+head>".
+ // We call these 'head'+5 bytes of instructions a "trampoline".
+ char *old_bytes = (char *)old_func;
+
+ // We'll need at least 5 bytes for a 'jmp'.
+ size_t head = 5;
+ if (orig_old_func) {
+ // Find out the number of bytes of the instructions we need to copy
+ // to the trampoline and store it in 'head'.
+ head = RoundUpToInstrBoundary(head, old_bytes);
+ if (!head)
+ return false;
- // Now put the "jump to trampoline" instruction into the original code.
+ // Put the needed instructions into the trampoline bytes.
+ char *trampoline = GetMemoryForTrampoline(head + 5);
+ if (!trampoline)
+ return false;
+ _memcpy(trampoline, old_bytes, head);
+ WriteJumpInstruction(trampoline + head, old_bytes + head);
+ *orig_old_func = (uptr)trampoline;
+ }
+
+ // Now put the "jmp <new_func>" instruction at the original code location.
+ // We should preserve the EXECUTE flag as some of our own code might be
+ // located in the same page (sic!). FIXME: might consider putting the
+ // __interception code into a separate section or something?
DWORD old_prot, unused_prot;
- if (!VirtualProtect((void*)old_func, head, PAGE_EXECUTE_READWRITE,
+ if (!VirtualProtect((void *)old_bytes, head, PAGE_EXECUTE_READWRITE,
&old_prot))
return false;
- // Put the needed instructions into the trampoline bytes.
- _memcpy(trampoline, old_bytes, head);
- WriteJumpInstruction(trampoline + head, old_bytes + head);
- *orig_old_func = (uptr)trampoline;
- pool_used += head + 5;
-
- // Intercept the 'old_func'.
- WriteJumpInstruction(old_bytes, (char*)new_func);
+ WriteJumpInstruction(old_bytes, (char *)new_func);
_memset(old_bytes + 5, 0xCC /* int 3 */, head - 5);
- if (!VirtualProtect((void*)old_func, head, old_prot, &unused_prot))
+ // Restore the original permissions.
+ if (!VirtualProtect((void *)old_bytes, head, old_prot, &unused_prot))
return false; // not clear if this failure bothers us.
return true;
}
+static const void **InterestingDLLsAvailable() {
+ const char *InterestingDLLs[] = {"kernel32.dll",
+ "msvcr110.dll", // VS2012
+ "msvcr120.dll", // VS2013
+ NULL};
+ static void *result[ARRAY_SIZE(InterestingDLLs)] = { 0 };
+ if (!result[0]) {
+ for (size_t i = 0, j = 0; InterestingDLLs[i]; ++i) {
+ if (HMODULE h = GetModuleHandleA(InterestingDLLs[i]))
+ result[j++] = (void *)h;
+ }
+ }
+ return (const void **)&result[0];
+}
+
+static bool GetFunctionAddressInDLLs(const char *func_name, uptr *func_addr) {
+ *func_addr = 0;
+ const void **DLLs = InterestingDLLsAvailable();
+ for (size_t i = 0; *func_addr == 0 && DLLs[i]; ++i)
+ *func_addr = (uptr)GetProcAddress((HMODULE)DLLs[i], func_name);
+ return (*func_addr != 0);
+}
+
+bool OverrideFunction(const char *name, uptr new_func, uptr *orig_old_func) {
+ uptr orig_func;
+ if (!GetFunctionAddressInDLLs(name, &orig_func))
+ return false;
+ return OverrideFunction(orig_func, new_func, orig_old_func);
+}
+
} // namespace __interception
#endif // _WIN32
diff --git a/lib/interception/interception_win.h b/lib/interception/interception_win.h
index f2727c9241d3..ba768a7233f9 100644
--- a/lib/interception/interception_win.h
+++ b/lib/interception/interception_win.h
@@ -22,27 +22,29 @@
#define INTERCEPTION_WIN_H
namespace __interception {
-// returns true if a function with the given name was found.
-bool GetRealFunctionAddress(const char *func_name, uptr *func_addr);
+// All the functions in the OverrideFunction() family return true on success,
+// false on failure (including "couldn't find the function").
-// returns true if the old function existed, false on failure.
-bool OverrideFunction(uptr old_func, uptr new_func, uptr *orig_old_func);
+// Overrides a function by its address.
+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);
} // namespace __interception
-#if defined(_DLL)
-# define INTERCEPT_FUNCTION_WIN(func) \
- ::__interception::GetRealFunctionAddress( \
- #func, (::__interception::uptr*)&REAL(func))
+#if defined(INTERCEPTION_DYNAMIC_CRT)
+#define INTERCEPT_FUNCTION_WIN(func) \
+ ::__interception::OverrideFunction(#func, \
+ (::__interception::uptr)WRAP(func), \
+ (::__interception::uptr *)&REAL(func))
#else
-# define INTERCEPT_FUNCTION_WIN(func) \
- ::__interception::OverrideFunction( \
- (::__interception::uptr)func, \
- (::__interception::uptr)WRAP(func), \
- (::__interception::uptr*)&REAL(func))
+#define INTERCEPT_FUNCTION_WIN(func) \
+ ::__interception::OverrideFunction((::__interception::uptr)func, \
+ (::__interception::uptr)WRAP(func), \
+ (::__interception::uptr *)&REAL(func))
#endif
-#define INTERCEPT_FUNCTION_VER_WIN(func, symver) \
- INTERCEPT_FUNCTION_WIN(func)
+#define INTERCEPT_FUNCTION_VER_WIN(func, symver) INTERCEPT_FUNCTION_WIN(func)
#endif // INTERCEPTION_WIN_H
#endif // _WIN32
diff --git a/lib/lit.common.cfg b/lib/lit.common.cfg
deleted file mode 100644
index 6c2b4cca4546..000000000000
--- a/lib/lit.common.cfg
+++ /dev/null
@@ -1,62 +0,0 @@
-# -*- Python -*-
-
-# Configuration file for 'lit' test runner.
-# This file contains common rules for various compiler-rt testsuites.
-# It is mostly copied from lit.cfg used by Clang.
-import os
-import platform
-
-import lit.formats
-
-# Setup test format
-execute_external = (platform.system() != 'Windows'
- or lit_config.getBashPath() not in [None, ""])
-config.test_format = lit.formats.ShTest(execute_external)
-
-# Setup clang binary.
-clang_path = getattr(config, 'clang', None)
-if (not clang_path) or (not os.path.exists(clang_path)):
- lit_config.fatal("Can't find Clang on path %r" % clang_path)
-
-# Clear some environment variables that might affect Clang.
-possibly_dangerous_env_vars = ['COMPILER_PATH', 'RC_DEBUG_OPTIONS',
- 'CINDEXTEST_PREAMBLE_FILE', 'LIBRARY_PATH',
- 'CPATH', 'C_INCLUDE_PATH', 'CPLUS_INCLUDE_PATH',
- 'OBJC_INCLUDE_PATH', 'OBJCPLUS_INCLUDE_PATH',
- 'LIBCLANG_TIMING', 'LIBCLANG_OBJTRACKING',
- 'LIBCLANG_LOGGING', 'LIBCLANG_BGPRIO_INDEX',
- 'LIBCLANG_BGPRIO_EDIT', 'LIBCLANG_NOTHREADS',
- 'LIBCLANG_RESOURCE_USAGE',
- 'LIBCLANG_CODE_COMPLETION_LOGGING']
-# Clang/Win32 may refer to %INCLUDE%. vsvarsall.bat sets it.
-if platform.system() != 'Windows':
- possibly_dangerous_env_vars.append('INCLUDE')
-for name in possibly_dangerous_env_vars:
- if name in config.environment:
- del config.environment[name]
-
-# Tweak PATH to include llvm tools dir.
-llvm_tools_dir = getattr(config, 'llvm_tools_dir', None)
-if (not llvm_tools_dir) or (not os.path.exists(llvm_tools_dir)):
- lit_config.fatal("Invalid llvm_tools_dir config attribute: %r" % llvm_tools_dir)
-path = os.path.pathsep.join((llvm_tools_dir, config.environment['PATH']))
-config.environment['PATH'] = path
-
-# Define path to external llvm-symbolizer tool.
-config.llvm_symbolizer_path = os.path.join(llvm_tools_dir, "llvm-symbolizer")
-
-# Use ugly construction to explicitly prohibit "clang", "clang++" etc.
-# in RUN lines.
-config.substitutions.append(
- (' clang', """\n\n*** Do not use 'clangXXX' in tests,
- instead define '%clangXXX' substitution in lit config. ***\n\n""") )
-
-# Add supported compiler_rt architectures to a list of available features.
-compiler_rt_arch = getattr(config, 'compiler_rt_arch', None)
-if compiler_rt_arch:
- for arch in compiler_rt_arch.split(";"):
- config.available_features.add(arch + "-supported-target")
-
-compiler_rt_debug = getattr(config, 'compiler_rt_debug', False)
-if not compiler_rt_debug:
- config.available_features.add('compiler-rt-optimized')
diff --git a/lib/lit.common.configured.in b/lib/lit.common.configured.in
deleted file mode 100644
index 558655cbbee8..000000000000
--- a/lib/lit.common.configured.in
+++ /dev/null
@@ -1,27 +0,0 @@
-## Autogenerated by LLVM/Clang configuration.
-# Do not edit!
-
-# Generic config options for all compiler-rt lit tests.
-config.target_triple = "@TARGET_TRIPLE@"
-config.host_arch = "@HOST_ARCH@"
-config.host_os = "@HOST_OS@"
-config.llvm_build_mode = "@LLVM_BUILD_MODE@"
-config.llvm_src_root = "@LLVM_SOURCE_DIR@"
-config.llvm_obj_root = "@LLVM_BINARY_DIR@"
-config.compiler_rt_src_root = "@COMPILER_RT_SOURCE_DIR@"
-config.llvm_tools_dir = "@LLVM_TOOLS_DIR@"
-config.clang = "@LLVM_BINARY_DIR@/bin/clang"
-config.compiler_rt_arch = "@COMPILER_RT_SUPPORTED_ARCH@"
-config.python_executable = "@PYTHON_EXECUTABLE@"
-config.compiler_rt_debug = @COMPILER_RT_DEBUG_PYBOOL@
-
-# LLVM tools dir can be passed in lit parameters, so try to
-# apply substitution.
-try:
- config.llvm_tools_dir = config.llvm_tools_dir % lit_config.params
-except KeyError,e:
- key, = e.args
- lit_config.fatal("unable to find %r parameter, use '--param=%s=VALUE'" % (key, key))
-
-# Setup attributes common for all compiler-rt projects.
-lit_config.load_config(config, "@COMPILER_RT_SOURCE_DIR@/lib/lit.common.cfg")
diff --git a/lib/lit.common.unit.cfg b/lib/lit.common.unit.cfg
deleted file mode 100644
index 2bd8f376f00e..000000000000
--- a/lib/lit.common.unit.cfg
+++ /dev/null
@@ -1,30 +0,0 @@
-# -*- Python -*-
-
-# Configuration file for 'lit' test runner.
-# This file contains common config setup rules for unit tests in various
-# compiler-rt testsuites.
-
-import os
-
-import lit.formats
-
-# Setup test format
-llvm_build_mode = getattr(config, "llvm_build_mode", "Debug")
-config.test_format = lit.formats.GoogleTest(llvm_build_mode, "Test")
-
-# Setup test suffixes.
-config.suffixes = []
-
-# Tweak PATH to include llvm tools dir.
-llvm_tools_dir = getattr(config, 'llvm_tools_dir', None)
-if (not llvm_tools_dir) or (not os.path.exists(llvm_tools_dir)):
- lit_config.fatal("Invalid llvm_tools_dir config attribute: %r" % llvm_tools_dir)
-path = os.path.pathsep.join((llvm_tools_dir, config.environment['PATH']))
-config.environment['PATH'] = path
-
-# Propagate the temp directory. Windows requires this because it uses \Windows\
-# if none of these are present.
-if 'TMP' in os.environ:
- config.environment['TMP'] = os.environ['TMP']
-if 'TEMP' in os.environ:
- config.environment['TEMP'] = os.environ['TEMP']
diff --git a/lib/lit.common.unit.configured.in b/lib/lit.common.unit.configured.in
deleted file mode 100644
index 430816b24280..000000000000
--- a/lib/lit.common.unit.configured.in
+++ /dev/null
@@ -1,23 +0,0 @@
-## Autogenerated by LLVM/Clang configuration.
-# Do not edit!
-
-# Generic config options for all compiler-rt unit tests.
-config.target_triple = "@TARGET_TRIPLE@"
-config.llvm_src_root = "@LLVM_SOURCE_DIR@"
-config.llvm_obj_root = "@LLVM_BINARY_DIR@"
-config.llvm_tools_dir = "@LLVM_TOOLS_DIR@"
-config.compiler_rt_src_root = "@COMPILER_RT_SOURCE_DIR@"
-config.llvm_build_mode = "@LLVM_BUILD_MODE@"
-config.host_os = "@HOST_OS@"
-
-# LLVM tools dir and build mode can be passed in lit parameters,
-# so try to apply substitution.
-try:
- config.llvm_tools_dir = config.llvm_tools_dir % lit_config.params
- config.llvm_build_mode = config.llvm_build_mode % lit_config.params
-except KeyError,e:
- key, = e.args
- lit_config.fatal("unable to find %r parameter, use '--param=%s=VALUE'" % (key, key))
-
-# Setup attributes common for all compiler-rt unit tests.
-lit_config.load_config(config, "@COMPILER_RT_SOURCE_DIR@/lib/lit.common.unit.cfg")
diff --git a/lib/lsan/CMakeLists.txt b/lib/lsan/CMakeLists.txt
index 3018a06622ee..2ea765de1bc7 100644
--- a/lib/lsan/CMakeLists.txt
+++ b/lib/lsan/CMakeLists.txt
@@ -1,8 +1,7 @@
include_directories(..)
-set(LSAN_CFLAGS
- ${SANITIZER_COMMON_CFLAGS}
- -fno-rtti)
+set(LSAN_CFLAGS ${SANITIZER_COMMON_CFLAGS})
+append_no_rtti_flag(LSAN_CFLAGS)
set(LSAN_COMMON_SOURCES
lsan_common.cc
@@ -17,16 +16,7 @@ set(LSAN_SOURCES
set(LSAN_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR})
-# The common files need to build on every arch supported by ASan.
-# (Even if they build into dummy object files.)
-filter_available_targets(LSAN_COMMON_SUPPORTED_ARCH
- x86_64 i386 powerpc64)
-
-# Architectures supported by the standalone LSan.
-filter_available_targets(LSAN_SUPPORTED_ARCH
- x86_64)
-
-set(LSAN_RUNTIME_LIBRARIES)
+add_custom_target(lsan)
if(APPLE)
foreach(os ${SANITIZER_COMMON_SUPPORTED_DARWIN_OS})
@@ -35,7 +25,7 @@ if(APPLE)
SOURCES ${LSAN_COMMON_SOURCES}
CFLAGS ${LSAN_CFLAGS})
endforeach()
-elseif(NOT ANDROID)
+else()
foreach(arch ${LSAN_COMMON_SUPPORTED_ARCH})
add_compiler_rt_object_library(RTLSanCommon ${arch}
SOURCES ${LSAN_COMMON_SOURCES}
@@ -43,18 +33,15 @@ elseif(NOT ANDROID)
endforeach()
foreach(arch ${LSAN_SUPPORTED_ARCH})
- add_compiler_rt_static_runtime(clang_rt.lsan-${arch} ${arch}
+ add_compiler_rt_runtime(clang_rt.lsan-${arch} ${arch} STATIC
SOURCES ${LSAN_SOURCES}
$<TARGET_OBJECTS:RTInterception.${arch}>
$<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
$<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>
$<TARGET_OBJECTS:RTLSanCommon.${arch}>
CFLAGS ${LSAN_CFLAGS})
- list(APPEND LSAN_RUNTIME_LIBRARIES clang_rt.lsan-${arch})
+ add_dependencies(lsan clang_rt.lsan-${arch})
endforeach()
endif()
-if (LLVM_INCLUDE_TESTS)
- add_subdirectory(tests)
-endif()
-add_subdirectory(lit_tests)
+add_dependencies(compiler-rt lsan)
diff --git a/lib/lsan/lit_tests/AsanConfig/lit.cfg b/lib/lsan/lit_tests/AsanConfig/lit.cfg
deleted file mode 100644
index ae9198173ffc..000000000000
--- a/lib/lsan/lit_tests/AsanConfig/lit.cfg
+++ /dev/null
@@ -1,32 +0,0 @@
-# -*- Python -*-
-
-import os
-
-def get_required_attr(config, attr_name):
- attr_value = getattr(config, attr_name, None)
- if not attr_value:
- lit_config.fatal(
- "No attribute %r in test configuration! You may need to run "
- "tests from your build directory or add this attribute "
- "to lit.site.cfg " % attr_name)
- return attr_value
-
-lsan_lit_src_root = get_required_attr(config, "lsan_lit_src_root")
-lsan_lit_cfg = os.path.join(lsan_lit_src_root, "lit.common.cfg")
-if not os.path.exists(lsan_lit_cfg):
- lit_config.fatal("Can't find common LSan lit config at: %r" % lsan_lit_cfg)
-lit_config.load_config(config, lsan_lit_cfg)
-
-config.name = 'LeakSanitizer-AddressSanitizer'
-
-clang_lsan_cxxflags = config.clang_cxxflags + " -fsanitize=address "
-
-config.substitutions.append( ("%clangxx_lsan ", (" " + config.clang + " " +
- clang_lsan_cxxflags + " ")) )
-
-clang_lsan_cflags = config.clang_cflags + " -fsanitize=address "
-
-config.substitutions.append( ("%clang_lsan ", (" " + config.clang + " " +
- clang_lsan_cflags + " ")) )
-
-config.environment['ASAN_OPTIONS'] = 'detect_leaks=1'
diff --git a/lib/lsan/lit_tests/AsanConfig/lit.site.cfg.in b/lib/lsan/lit_tests/AsanConfig/lit.site.cfg.in
deleted file mode 100644
index 9cf6572c54b7..000000000000
--- a/lib/lsan/lit_tests/AsanConfig/lit.site.cfg.in
+++ /dev/null
@@ -1,8 +0,0 @@
-# Load common config for all compiler-rt lit tests.
-lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/lib/lit.common.configured")
-
-# Tool-specific config options.
-config.lsan_lit_src_root = "@LSAN_LIT_SOURCE_DIR@"
-
-# Load tool-specific config that would do the real work.
-lit_config.load_config(config, "@LSAN_LIT_SOURCE_DIR@/AsanConfig/lit.cfg")
diff --git a/lib/lsan/lit_tests/CMakeLists.txt b/lib/lsan/lit_tests/CMakeLists.txt
deleted file mode 100644
index 526d71bf3418..000000000000
--- a/lib/lsan/lit_tests/CMakeLists.txt
+++ /dev/null
@@ -1,37 +0,0 @@
-set(LSAN_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/..)
-set(LSAN_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/..)
-
-set(LSAN_LIT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
-
-configure_lit_site_cfg(
- ${CMAKE_CURRENT_SOURCE_DIR}/LsanConfig/lit.site.cfg.in
- ${CMAKE_CURRENT_BINARY_DIR}/LsanConfig/lit.site.cfg
- )
-
-configure_lit_site_cfg(
- ${CMAKE_CURRENT_SOURCE_DIR}/AsanConfig/lit.site.cfg.in
- ${CMAKE_CURRENT_BINARY_DIR}/AsanConfig/lit.site.cfg
- )
-
-configure_lit_site_cfg(
- ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.in
- ${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg
- )
-
-if(COMPILER_RT_CAN_EXECUTE_TESTS AND NOT APPLE AND NOT ANDROID)
- set(LSAN_TEST_DEPS
- ${SANITIZER_COMMON_LIT_TEST_DEPS}
- ${LSAN_RUNTIME_LIBRARIES})
- foreach(arch ${LSAN_SUPPORTED_ARCH})
- list(APPEND LSAN_TEST_DEPS clang_rt.asan-${arch})
- endforeach()
- if(LLVM_INCLUDE_TESTS)
- list(APPEND LSAN_TEST_DEPS LsanUnitTests)
- endif()
- add_lit_testsuite(check-lsan "Running the LeakSanitizer tests"
- ${CMAKE_CURRENT_BINARY_DIR}/LsanConfig
- ${CMAKE_CURRENT_BINARY_DIR}/AsanConfig
- ${CMAKE_CURRENT_BINARY_DIR}/Unit
- DEPENDS ${LSAN_TEST_DEPS})
- set_target_properties(check-lsan PROPERTIES FOLDER "LSan tests")
-endif()
diff --git a/lib/lsan/lit_tests/LsanConfig/lit.cfg b/lib/lsan/lit_tests/LsanConfig/lit.cfg
deleted file mode 100644
index 84faf9167a78..000000000000
--- a/lib/lsan/lit_tests/LsanConfig/lit.cfg
+++ /dev/null
@@ -1,30 +0,0 @@
-# -*- Python -*-
-
-import os
-
-def get_required_attr(config, attr_name):
- attr_value = getattr(config, attr_name, None)
- if not attr_value:
- lit_config.fatal(
- "No attribute %r in test configuration! You may need to run "
- "tests from your build directory or add this attribute "
- "to lit.site.cfg " % attr_name)
- return attr_value
-
-lsan_lit_src_root = get_required_attr(config, "lsan_lit_src_root")
-lsan_lit_cfg = os.path.join(lsan_lit_src_root, "lit.common.cfg")
-if not os.path.exists(lsan_lit_cfg):
- lit_config.fatal("Can't find common LSan lit config at: %r" % lsan_lit_cfg)
-lit_config.load_config(config, lsan_lit_cfg)
-
-config.name = 'LeakSanitizer-Standalone'
-
-clang_lsan_cxxflags = config.clang_cxxflags + " -fsanitize=leak "
-
-config.substitutions.append( ("%clangxx_lsan ", (" " + config.clang + " " +
- clang_lsan_cxxflags + " ")) )
-
-clang_lsan_cflags = config.clang_cflags + " -fsanitize=leak "
-
-config.substitutions.append( ("%clang_lsan ", (" " + config.clang + " " +
- clang_lsan_cflags + " ")) )
diff --git a/lib/lsan/lit_tests/LsanConfig/lit.site.cfg.in b/lib/lsan/lit_tests/LsanConfig/lit.site.cfg.in
deleted file mode 100644
index 2a6d724c0436..000000000000
--- a/lib/lsan/lit_tests/LsanConfig/lit.site.cfg.in
+++ /dev/null
@@ -1,8 +0,0 @@
-# Load common config for all compiler-rt lit tests.
-lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/lib/lit.common.configured")
-
-# Tool-specific config options.
-config.lsan_lit_src_root = "@LSAN_LIT_SOURCE_DIR@"
-
-# Load tool-specific config that would do the real work.
-lit_config.load_config(config, "@LSAN_LIT_SOURCE_DIR@/LsanConfig/lit.cfg")
diff --git a/lib/lsan/lit_tests/TestCases/SharedLibs/huge_tls_lib_so.cc b/lib/lsan/lit_tests/TestCases/SharedLibs/huge_tls_lib_so.cc
deleted file mode 100644
index 475a66ec12a4..000000000000
--- a/lib/lsan/lit_tests/TestCases/SharedLibs/huge_tls_lib_so.cc
+++ /dev/null
@@ -1,12 +0,0 @@
-// A loadable module with a large thread local section, which would require
-// allocation of a new TLS storage chunk when loaded with dlopen(). We use it
-// to test the reachability of such chunks in LSan tests.
-
-// This must be large enough that it doesn't fit into preallocated static TLS
-// space (see STATIC_TLS_SURPLUS in glibc).
-__thread void *huge_thread_local_array[(1 << 20) / sizeof(void *)]; // NOLINT
-
-extern "C" void **StoreToTLS(void *p) {
- huge_thread_local_array[0] = p;
- return &huge_thread_local_array[0];
-}
diff --git a/lib/lsan/lit_tests/TestCases/SharedLibs/lit.local.cfg b/lib/lsan/lit_tests/TestCases/SharedLibs/lit.local.cfg
deleted file mode 100644
index b3677c17a0f2..000000000000
--- a/lib/lsan/lit_tests/TestCases/SharedLibs/lit.local.cfg
+++ /dev/null
@@ -1,4 +0,0 @@
-# Sources in this directory are compiled as shared libraries and used by
-# tests in parent directory.
-
-config.suffixes = []
diff --git a/lib/lsan/lit_tests/TestCases/cleanup_in_tsd_destructor.cc b/lib/lsan/lit_tests/TestCases/cleanup_in_tsd_destructor.cc
deleted file mode 100644
index ab368245317c..000000000000
--- a/lib/lsan/lit_tests/TestCases/cleanup_in_tsd_destructor.cc
+++ /dev/null
@@ -1,45 +0,0 @@
-// Regression test for thread lifetime tracking. Thread data should be
-// considered live during the thread's termination, at least until the
-// user-installed TSD destructors have finished running (since they may contain
-// additional cleanup tasks). LSan doesn't actually meet that goal 100%, but it
-// makes its best effort.
-// RUN: LSAN_BASE="report_objects=1:use_registers=0:use_stacks=0:use_globals=0"
-// RUN: %clangxx_lsan %s -o %t
-// RUN: LSAN_OPTIONS=$LSAN_BASE:use_tls=1 %t
-// RUN: LSAN_OPTIONS=$LSAN_BASE:use_tls=0 not %t 2>&1 | FileCheck %s
-
-#include <assert.h>
-#include <pthread.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "sanitizer/lsan_interface.h"
-
-pthread_key_t key;
-__thread void *p;
-
-void key_destructor(void *arg) {
- // Generally this may happen on a different thread.
- __lsan_do_leak_check();
-}
-
-void *thread_func(void *arg) {
- p = malloc(1337);
- fprintf(stderr, "Test alloc: %p.\n", p);
- int res = pthread_setspecific(key, (void*)1);
- assert(res == 0);
- return 0;
-}
-
-int main() {
- int res = pthread_key_create(&key, &key_destructor);
- assert(res == 0);
- pthread_t thread_id;
- res = pthread_create(&thread_id, 0, thread_func, 0);
- assert(res == 0);
- res = pthread_join(thread_id, 0);
- assert(res == 0);
- return 0;
-}
-// CHECK: Test alloc: [[ADDR:.*]].
-// CHECK: leaked 1337 byte object at [[ADDR]]
diff --git a/lib/lsan/lit_tests/TestCases/disabler.cc b/lib/lsan/lit_tests/TestCases/disabler.cc
deleted file mode 100644
index db0cd8fabe4d..000000000000
--- a/lib/lsan/lit_tests/TestCases/disabler.cc
+++ /dev/null
@@ -1,23 +0,0 @@
-// Test for ScopedDisabler.
-// RUN: LSAN_BASE="report_objects=1:use_registers=0:use_stacks=0:use_globals=0:use_tls=0"
-// RUN: %clangxx_lsan %s -o %t
-// RUN: LSAN_OPTIONS=$LSAN_BASE not %t 2>&1 | FileCheck %s
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "sanitizer/lsan_interface.h"
-
-int main() {
- void **p;
- {
- __lsan::ScopedDisabler d;
- p = new void *;
- }
- *reinterpret_cast<void **>(p) = malloc(666);
- void *q = malloc(1337);
- // Break optimization.
- fprintf(stderr, "Test alloc: %p.\n", q);
- return 0;
-}
-// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: 1337 byte(s) leaked in 1 allocation(s)
diff --git a/lib/lsan/lit_tests/TestCases/disabler_in_tsd_destructor.cc b/lib/lsan/lit_tests/TestCases/disabler_in_tsd_destructor.cc
deleted file mode 100644
index 94e4fc390b3b..000000000000
--- a/lib/lsan/lit_tests/TestCases/disabler_in_tsd_destructor.cc
+++ /dev/null
@@ -1,38 +0,0 @@
-// Regression test. Disabler should not depend on TSD validity.
-// RUN: LSAN_BASE="report_objects=1:use_registers=0:use_stacks=0:use_globals=0:use_tls=1"
-// RUN: %clangxx_lsan %s -o %t
-// RUN: LSAN_OPTIONS=$LSAN_BASE %t
-
-#include <assert.h>
-#include <pthread.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "sanitizer/lsan_interface.h"
-
-pthread_key_t key;
-
-void key_destructor(void *arg) {
- __lsan::ScopedDisabler d;
- void *p = malloc(1337);
- // Break optimization.
- fprintf(stderr, "Test alloc: %p.\n", p);
- pthread_setspecific(key, 0);
-}
-
-void *thread_func(void *arg) {
- int res = pthread_setspecific(key, (void*)1);
- assert(res == 0);
- return 0;
-}
-
-int main() {
- int res = pthread_key_create(&key, &key_destructor);
- assert(res == 0);
- pthread_t thread_id;
- res = pthread_create(&thread_id, 0, thread_func, 0);
- assert(res == 0);
- res = pthread_join(thread_id, 0);
- assert(res == 0);
- return 0;
-}
diff --git a/lib/lsan/lit_tests/TestCases/do_leak_check_override.cc b/lib/lsan/lit_tests/TestCases/do_leak_check_override.cc
deleted file mode 100644
index be0ed0a6d48f..000000000000
--- a/lib/lsan/lit_tests/TestCases/do_leak_check_override.cc
+++ /dev/null
@@ -1,36 +0,0 @@
-// Test for __lsan_do_leak_check(). We test it by making the leak check run
-// before global destructors, which also tests compatibility with HeapChecker's
-// "normal" mode (LSan runs in "strict" mode by default).
-// RUN: LSAN_BASE="use_stacks=0:use_registers=0"
-// RUN: %clangxx_lsan %s -o %t
-// RUN: LSAN_OPTIONS=$LSAN_BASE not %t 2>&1 | FileCheck --check-prefix=CHECK-strict %s
-// RUN: LSAN_OPTIONS=$LSAN_BASE not %t foo 2>&1 | FileCheck --check-prefix=CHECK-normal %s
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <sanitizer/lsan_interface.h>
-
-struct LeakyGlobal {
- LeakyGlobal() {
- p = malloc(1337);
- }
- ~LeakyGlobal() {
- p = 0;
- }
- void *p;
-};
-
-LeakyGlobal leaky_global;
-
-int main(int argc, char *argv[]) {
- // Register leak check to run before global destructors.
- if (argc > 1)
- atexit(&__lsan_do_leak_check);
- void *p = malloc(666);
- printf("Test alloc: %p\n", p);
- printf("Test alloc in leaky global: %p\n", leaky_global.p);
- return 0;
-}
-
-// CHECK-strict: SUMMARY: {{(Leak|Address)}}Sanitizer: 2003 byte(s) leaked in 2 allocation(s)
-// CHECK-normal: SUMMARY: {{(Leak|Address)}}Sanitizer: 666 byte(s) leaked in 1 allocation(s)
diff --git a/lib/lsan/lit_tests/TestCases/fork.cc b/lib/lsan/lit_tests/TestCases/fork.cc
deleted file mode 100644
index 69258d9a0c72..000000000000
--- a/lib/lsan/lit_tests/TestCases/fork.cc
+++ /dev/null
@@ -1,24 +0,0 @@
-// Test that thread local data is handled correctly after forking without exec().
-// RUN: %clangxx_lsan %s -o %t
-// RUN: %t 2>&1
-
-#include <assert.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-__thread void *thread_local_var;
-
-int main() {
- int status = 0;
- thread_local_var = malloc(1337);
- pid_t pid = fork();
- assert(pid >= 0);
- if (pid > 0) {
- waitpid(pid, &status, 0);
- assert(WIFEXITED(status));
- return WEXITSTATUS(status);
- }
- return 0;
-}
diff --git a/lib/lsan/lit_tests/TestCases/fork_threaded.cc b/lib/lsan/lit_tests/TestCases/fork_threaded.cc
deleted file mode 100644
index 24a586109e28..000000000000
--- a/lib/lsan/lit_tests/TestCases/fork_threaded.cc
+++ /dev/null
@@ -1,43 +0,0 @@
-// Test that thread local data is handled correctly after forking without
-// exec(). In this test leak checking is initiated from a non-main thread.
-// RUN: %clangxx_lsan %s -o %t
-// RUN: %t 2>&1
-
-#include <assert.h>
-#include <pthread.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-__thread void *thread_local_var;
-
-void *exit_thread_func(void *arg) {
- exit(0);
-}
-
-void ExitFromThread() {
- pthread_t tid;
- int res;
- res = pthread_create(&tid, 0, exit_thread_func, 0);
- assert(res == 0);
- pthread_join(tid, 0);
-}
-
-int main() {
- int status = 0;
- thread_local_var = malloc(1337);
- pid_t pid = fork();
- assert(pid >= 0);
- if (pid > 0) {
- waitpid(pid, &status, 0);
- assert(WIFEXITED(status));
- return WEXITSTATUS(status);
- } else {
- // Spawn a thread and call exit() from there, to check that we track main
- // thread's pid correctly even if leak checking is initiated from another
- // thread.
- ExitFromThread();
- }
- return 0;
-}
diff --git a/lib/lsan/lit_tests/TestCases/high_allocator_contention.cc b/lib/lsan/lit_tests/TestCases/high_allocator_contention.cc
deleted file mode 100644
index 1cecb2a550a1..000000000000
--- a/lib/lsan/lit_tests/TestCases/high_allocator_contention.cc
+++ /dev/null
@@ -1,48 +0,0 @@
-// A benchmark that executes malloc/free pairs in parallel.
-// Usage: ./a.out number_of_threads total_number_of_allocations
-// RUN: %clangxx_lsan %s -o %t
-// RUN: %t 5 1000000 2>&1
-#include <assert.h>
-#include <pthread.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-int num_threads;
-int total_num_alloc;
-const int kMaxNumThreads = 5000;
-pthread_t tid[kMaxNumThreads];
-
-pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
-pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
-bool go = false;
-
-void *thread_fun(void *arg) {
- pthread_mutex_lock(&mutex);
- while (!go) pthread_cond_wait(&cond, &mutex);
- pthread_mutex_unlock(&mutex);
- for (int i = 0; i < total_num_alloc / num_threads; i++) {
- void *p = malloc(10);
- __asm__ __volatile__("" : : "r"(p) : "memory");
- free((void *)p);
- }
- return 0;
-}
-
-int main(int argc, char** argv) {
- assert(argc == 3);
- num_threads = atoi(argv[1]);
- assert(num_threads > 0);
- assert(num_threads <= kMaxNumThreads);
- total_num_alloc = atoi(argv[2]);
- assert(total_num_alloc > 0);
- printf("%d threads, %d allocations in each\n", num_threads,
- total_num_alloc / num_threads);
- for (int i = 0; i < num_threads; i++)
- pthread_create(&tid[i], 0, thread_fun, 0);
- pthread_mutex_lock(&mutex);
- go = true;
- pthread_cond_broadcast(&cond);
- pthread_mutex_unlock(&mutex);
- for (int i = 0; i < num_threads; i++) pthread_join(tid[i], 0);
- return 0;
-}
diff --git a/lib/lsan/lit_tests/TestCases/ignore_object.cc b/lib/lsan/lit_tests/TestCases/ignore_object.cc
deleted file mode 100644
index cbc743b75497..000000000000
--- a/lib/lsan/lit_tests/TestCases/ignore_object.cc
+++ /dev/null
@@ -1,30 +0,0 @@
-// Test for __lsan_ignore_object().
-// RUN: LSAN_BASE="report_objects=1:use_registers=0:use_stacks=0:use_globals=0:use_tls=0:verbosity=3"
-// RUN: %clangxx_lsan %s -o %t
-// RUN: LSAN_OPTIONS=$LSAN_BASE not %t 2>&1 | FileCheck %s
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "sanitizer/lsan_interface.h"
-
-int main() {
- {
- // The first malloc call can cause an allocation in libdl. Ignore it here so
- // it doesn't show up in our output.
- __lsan::ScopedDisabler d;
- malloc(1);
- }
- // Explicitly ignored object.
- void **p = new void *;
- // Transitively ignored object.
- *p = malloc(666);
- // Non-ignored object.
- volatile void *q = malloc(1337);
- fprintf(stderr, "Test alloc: %p.\n", p);
- __lsan_ignore_object(p);
- return 0;
-}
-// CHECK: Test alloc: [[ADDR:.*]].
-// CHECK: ignoring heap object at [[ADDR]]
-// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: 1337 byte(s) leaked in 1 allocation(s)
diff --git a/lib/lsan/lit_tests/TestCases/ignore_object_errors.cc b/lib/lsan/lit_tests/TestCases/ignore_object_errors.cc
deleted file mode 100644
index 2a6c72551772..000000000000
--- a/lib/lsan/lit_tests/TestCases/ignore_object_errors.cc
+++ /dev/null
@@ -1,22 +0,0 @@
-// Test for incorrect use of __lsan_ignore_object().
-// RUN: LSAN_BASE="verbosity=2"
-// RUN: %clangxx_lsan %s -o %t
-// RUN: LSAN_OPTIONS=$LSAN_BASE %t 2>&1 | FileCheck %s
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "sanitizer/lsan_interface.h"
-
-int main() {
- void *p = malloc(1337);
- fprintf(stderr, "Test alloc: %p.\n", p);
- __lsan_ignore_object(p);
- __lsan_ignore_object(p);
- free(p);
- __lsan_ignore_object(p);
- return 0;
-}
-// CHECK: Test alloc: [[ADDR:.*]].
-// CHECK: heap object at [[ADDR]] is already being ignored
-// CHECK: no heap object found at [[ADDR]]
diff --git a/lib/lsan/lit_tests/TestCases/large_allocation_leak.cc b/lib/lsan/lit_tests/TestCases/large_allocation_leak.cc
deleted file mode 100644
index 57d056597ee2..000000000000
--- a/lib/lsan/lit_tests/TestCases/large_allocation_leak.cc
+++ /dev/null
@@ -1,18 +0,0 @@
-// Test that LargeMmapAllocator's chunks aren't reachable via some internal data structure.
-// RUN: LSAN_BASE="report_objects=1:use_stacks=0:use_registers=0"
-// RUN: %clangxx_lsan %s -o %t
-// RUN: LSAN_OPTIONS=$LSAN_BASE not %t 2>&1 | FileCheck %s
-
-#include <stdio.h>
-#include <stdlib.h>
-
-int main() {
- // maxsize in primary allocator is always less than this (1 << 25).
- void *large_alloc = malloc(33554432);
- fprintf(stderr, "Test alloc: %p.\n", large_alloc);
- return 0;
-}
-// CHECK: Test alloc: [[ADDR:.*]].
-// CHECK: Directly leaked 33554432 byte object at [[ADDR]]
-// CHECK: LeakSanitizer: detected memory leaks
-// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer:
diff --git a/lib/lsan/lit_tests/TestCases/leak_check_at_exit.cc b/lib/lsan/lit_tests/TestCases/leak_check_at_exit.cc
deleted file mode 100644
index 38c1063b6ebb..000000000000
--- a/lib/lsan/lit_tests/TestCases/leak_check_at_exit.cc
+++ /dev/null
@@ -1,19 +0,0 @@
-// Test for the leak_check_at_exit flag.
-// RUN: %clangxx_lsan %s -o %t
-// RUN: LSAN_OPTIONS="verbosity=1" %t foo 2>&1 | FileCheck %s --check-prefix=CHECK-do
-// RUN: LSAN_OPTIONS="verbosity=1" %t 2>&1 | FileCheck %s --check-prefix=CHECK-do
-// RUN: LSAN_OPTIONS="verbosity=1:leak_check_at_exit=0" ASAN_OPTIONS="$ASAN_OPTIONS:leak_check_at_exit=0" %t foo 2>&1 | FileCheck %s --check-prefix=CHECK-do
-// RUN: LSAN_OPTIONS="verbosity=1:leak_check_at_exit=0" ASAN_OPTIONS="$ASAN_OPTIONS:leak_check_at_exit=0" %t 2>&1 | FileCheck %s --check-prefix=CHECK-dont
-
-#include <stdio.h>
-#include <sanitizer/lsan_interface.h>
-
-int main(int argc, char *argv[]) {
- printf("printf to break optimization\n");
- if (argc > 1)
- __lsan_do_leak_check();
- return 0;
-}
-
-// CHECK-do: SUMMARY: {{(Leak|Address)}}Sanitizer:
-// CHECK-dont-NOT: SUMMARY: {{(Leak|Address)}}Sanitizer:
diff --git a/lib/lsan/lit_tests/TestCases/link_turned_off.cc b/lib/lsan/lit_tests/TestCases/link_turned_off.cc
deleted file mode 100644
index 93628a1d15ee..000000000000
--- a/lib/lsan/lit_tests/TestCases/link_turned_off.cc
+++ /dev/null
@@ -1,24 +0,0 @@
-// Test for disabling LSan at link-time.
-// RUN: LSAN_BASE="use_stacks=0:use_registers=0"
-// RUN: %clangxx_lsan %s -o %t
-// RUN: LSAN_OPTIONS=$LSAN_BASE %t
-// RUN: LSAN_OPTIONS=$LSAN_BASE not %t foo 2>&1 | FileCheck %s
-
-#include <sanitizer/lsan_interface.h>
-
-int argc_copy;
-
-extern "C" {
-int __lsan_is_turned_off() {
- return (argc_copy == 1);
-}
-}
-
-int main(int argc, char *argv[]) {
- volatile int *x = new int;
- *x = 42;
- argc_copy = argc;
- return 0;
-}
-
-// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: 4 byte(s) leaked in 1 allocation(s)
diff --git a/lib/lsan/lit_tests/TestCases/pointer_to_self.cc b/lib/lsan/lit_tests/TestCases/pointer_to_self.cc
deleted file mode 100644
index 0d2818d2fa1d..000000000000
--- a/lib/lsan/lit_tests/TestCases/pointer_to_self.cc
+++ /dev/null
@@ -1,18 +0,0 @@
-// Regression test: pointers to self should not confuse LSan into thinking the
-// object is indirectly leaked. Only external pointers count.
-// RUN: LSAN_BASE="report_objects=1:use_registers=0"
-// RUN: %clangxx_lsan %s -o %t
-// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_stacks=0" not %t 2>&1 | FileCheck %s
-
-#include <stdio.h>
-#include <stdlib.h>
-
-int main() {
- void *p = malloc(1337);
- *reinterpret_cast<void **>(p) = p;
- fprintf(stderr, "Test alloc: %p.\n", p);
-}
-// CHECK: Test alloc: [[ADDR:.*]].
-// CHECK: Directly leaked 1337 byte object at [[ADDR]]
-// CHECK: LeakSanitizer: detected memory leaks
-// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer:
diff --git a/lib/lsan/lit_tests/TestCases/sanity_check_pure_c.c b/lib/lsan/lit_tests/TestCases/sanity_check_pure_c.c
deleted file mode 100644
index 085412b47d55..000000000000
--- a/lib/lsan/lit_tests/TestCases/sanity_check_pure_c.c
+++ /dev/null
@@ -1,10 +0,0 @@
-// Check that we can build C code.
-// RUN: %clang_lsan %s -o %t
-#ifdef __cplusplus
-#error "This test must be built in C mode"
-#endif
-
-int main() {
- // FIXME: ideally this should somehow check that we don't have libstdc++
- return 0;
-}
diff --git a/lib/lsan/lit_tests/TestCases/stale_stack_leak.cc b/lib/lsan/lit_tests/TestCases/stale_stack_leak.cc
deleted file mode 100644
index fabfb4ff21a9..000000000000
--- a/lib/lsan/lit_tests/TestCases/stale_stack_leak.cc
+++ /dev/null
@@ -1,42 +0,0 @@
-// Test that out-of-scope local variables are ignored by LSan.
-// RUN: LSAN_BASE="report_objects=1:use_registers=0:use_stacks=1"
-// RUN: %clangxx_lsan %s -o %t
-// RUN: LSAN_OPTIONS=$LSAN_BASE not %t 2>&1 | FileCheck %s
-// RUN: LSAN_OPTIONS=$LSAN_BASE":exitcode=0" %t 2>&1 | FileCheck --check-prefix=CHECK-sanity %s
-
-#include <stdio.h>
-#include <stdlib.h>
-
-void **pp;
-
-// Put pointer far enough on the stack that LSan has space to run in without
-// overwriting it.
-// Hopefully the argument p will be passed on a register, saving us from false
-// negatives.
-__attribute__((noinline))
-void *PutPointerOnStaleStack(void *p) {
- void *locals[2048];
- locals[0] = p;
- pp = &locals[0];
- fprintf(stderr, "Test alloc: %p.\n", locals[0]);
- return 0;
-}
-
-int main() {
- PutPointerOnStaleStack(malloc(1337));
- return 0;
-}
-
-// This must run after LSan, to ensure LSan didn't overwrite the pointer before
-// it had a chance to see it. If LSan is invoked with atexit(), this works.
-// Otherwise, we need a different method.
-__attribute__((destructor))
-void ConfirmPointerHasSurvived() {
- fprintf(stderr, "Value after LSan: %p.\n", *pp);
-}
-// CHECK: Test alloc: [[ADDR:.*]].
-// CHECK-sanity: Test alloc: [[ADDR:.*]].
-// CHECK: Directly leaked 1337 byte object at [[ADDR]]
-// CHECK: LeakSanitizer: detected memory leaks
-// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer:
-// CHECK-sanity: Value after LSan: [[ADDR]].
diff --git a/lib/lsan/lit_tests/TestCases/suppressions_default.cc b/lib/lsan/lit_tests/TestCases/suppressions_default.cc
deleted file mode 100644
index 9a165f8770f9..000000000000
--- a/lib/lsan/lit_tests/TestCases/suppressions_default.cc
+++ /dev/null
@@ -1,29 +0,0 @@
-// Test for ScopedDisabler.
-// RUN: LSAN_BASE="use_registers=0:use_stacks=0"
-// RUN: %clangxx_lsan %s -o %t
-// RUN: LSAN_OPTIONS=$LSAN_BASE not %t 2>&1 | FileCheck %s
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "sanitizer/lsan_interface.h"
-
-extern "C"
-const char *__lsan_default_suppressions() {
- return "leak:*LSanTestLeakingFunc*";
-}
-
-void LSanTestLeakingFunc() {
- void *p = malloc(666);
- fprintf(stderr, "Test alloc: %p.\n", p);
-}
-
-int main() {
- LSanTestLeakingFunc();
- void *q = malloc(1337);
- fprintf(stderr, "Test alloc: %p.\n", q);
- return 0;
-}
-// CHECK: Suppressions used:
-// CHECK: 1 666 *LSanTestLeakingFunc*
-// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: 1337 byte(s) leaked in 1 allocation(s)
diff --git a/lib/lsan/lit_tests/TestCases/suppressions_file.cc b/lib/lsan/lit_tests/TestCases/suppressions_file.cc
deleted file mode 100644
index 9a165f8770f9..000000000000
--- a/lib/lsan/lit_tests/TestCases/suppressions_file.cc
+++ /dev/null
@@ -1,29 +0,0 @@
-// Test for ScopedDisabler.
-// RUN: LSAN_BASE="use_registers=0:use_stacks=0"
-// RUN: %clangxx_lsan %s -o %t
-// RUN: LSAN_OPTIONS=$LSAN_BASE not %t 2>&1 | FileCheck %s
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "sanitizer/lsan_interface.h"
-
-extern "C"
-const char *__lsan_default_suppressions() {
- return "leak:*LSanTestLeakingFunc*";
-}
-
-void LSanTestLeakingFunc() {
- void *p = malloc(666);
- fprintf(stderr, "Test alloc: %p.\n", p);
-}
-
-int main() {
- LSanTestLeakingFunc();
- void *q = malloc(1337);
- fprintf(stderr, "Test alloc: %p.\n", q);
- return 0;
-}
-// CHECK: Suppressions used:
-// CHECK: 1 666 *LSanTestLeakingFunc*
-// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: 1337 byte(s) leaked in 1 allocation(s)
diff --git a/lib/lsan/lit_tests/TestCases/suppressions_file.cc.supp b/lib/lsan/lit_tests/TestCases/suppressions_file.cc.supp
deleted file mode 100644
index 8d8e560cba4c..000000000000
--- a/lib/lsan/lit_tests/TestCases/suppressions_file.cc.supp
+++ /dev/null
@@ -1 +0,0 @@
-leak:*LSanTestLeakingFunc*
diff --git a/lib/lsan/lit_tests/TestCases/swapcontext.cc b/lib/lsan/lit_tests/TestCases/swapcontext.cc
deleted file mode 100644
index a06685ca2f03..000000000000
--- a/lib/lsan/lit_tests/TestCases/swapcontext.cc
+++ /dev/null
@@ -1,42 +0,0 @@
-// We can't unwind stack if we're running coroutines on heap-allocated
-// memory. Make sure we don't report these leaks.
-
-// RUN: %clangxx_lsan %s -o %t
-// RUN: %t 2>&1
-// RUN: not %t foo 2>&1 | FileCheck %s
-
-#include <stdio.h>
-#include <ucontext.h>
-#include <unistd.h>
-
-const int kStackSize = 1 << 20;
-
-void Child() {
- int child_stack;
- printf("Child: %p\n", &child_stack);
- int *leaked = new int[666];
-}
-
-int main(int argc, char *argv[]) {
- char stack_memory[kStackSize + 1];
- char *heap_memory = new char[kStackSize + 1];
- char *child_stack = (argc > 1) ? stack_memory : heap_memory;
-
- printf("Child stack: %p\n", child_stack);
- ucontext_t orig_context;
- ucontext_t child_context;
- getcontext(&child_context);
- child_context.uc_stack.ss_sp = child_stack;
- child_context.uc_stack.ss_size = kStackSize / 2;
- child_context.uc_link = &orig_context;
- makecontext(&child_context, Child, 0);
- if (swapcontext(&orig_context, &child_context) < 0) {
- perror("swapcontext");
- return 1;
- }
-
- delete[] heap_memory;
- return 0;
-}
-
-// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: 2664 byte(s) leaked in 1 allocation(s)
diff --git a/lib/lsan/lit_tests/TestCases/use_after_return.cc b/lib/lsan/lit_tests/TestCases/use_after_return.cc
deleted file mode 100644
index 93b0ea6068ef..000000000000
--- a/lib/lsan/lit_tests/TestCases/use_after_return.cc
+++ /dev/null
@@ -1,23 +0,0 @@
-// Test that fake stack (introduced by ASan's use-after-return mode) is included
-// in the root set.
-// RUN: LSAN_BASE="report_objects=1:use_registers=0"
-// RUN: %clangxx_lsan %s -O2 -o %t
-// RUN: ASAN_OPTIONS=$ASAN_OPTIONS:detect_stack_use_after_return=1 LSAN_OPTIONS=$LSAN_BASE:"use_stacks=0" not %t 2>&1 | FileCheck %s
-// RUN: ASAN_OPTIONS=$ASAN_OPTIONS:detect_stack_use_after_return=1 LSAN_OPTIONS=$LSAN_BASE:"use_stacks=1" %t 2>&1
-// RUN: ASAN_OPTIONS=$ASAN_OPTIONS:detect_stack_use_after_return=1 LSAN_OPTIONS="" %t 2>&1
-
-#include <stdio.h>
-#include <stdlib.h>
-
-int main() {
- void *stack_var = malloc(1337);
- fprintf(stderr, "Test alloc: %p.\n", stack_var);
- // Take pointer to variable, to ensure it's not optimized into a register.
- fprintf(stderr, "Stack var at: %p.\n", &stack_var);
- // Do not return from main to prevent the pointer from going out of scope.
- exit(0);
-}
-// CHECK: Test alloc: [[ADDR:.*]].
-// CHECK: Directly leaked 1337 byte object at [[ADDR]]
-// CHECK: LeakSanitizer: detected memory leaks
-// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer:
diff --git a/lib/lsan/lit_tests/TestCases/use_globals_initialized.cc b/lib/lsan/lit_tests/TestCases/use_globals_initialized.cc
deleted file mode 100644
index 5a7c48bdf49a..000000000000
--- a/lib/lsan/lit_tests/TestCases/use_globals_initialized.cc
+++ /dev/null
@@ -1,21 +0,0 @@
-// Test that initialized globals are included in the root set.
-// RUN: LSAN_BASE="report_objects=1:use_stacks=0:use_registers=0"
-// RUN: %clangxx_lsan %s -o %t
-// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_globals=0" not %t 2>&1 | FileCheck %s
-// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_globals=1" %t 2>&1
-// RUN: LSAN_OPTIONS="" %t 2>&1
-
-#include <stdio.h>
-#include <stdlib.h>
-
-void *data_var = (void *)1;
-
-int main() {
- data_var = malloc(1337);
- fprintf(stderr, "Test alloc: %p.\n", data_var);
- return 0;
-}
-// CHECK: Test alloc: [[ADDR:.*]].
-// CHECK: Directly leaked 1337 byte object at [[ADDR]]
-// CHECK: LeakSanitizer: detected memory leaks
-// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer:
diff --git a/lib/lsan/lit_tests/TestCases/use_globals_uninitialized.cc b/lib/lsan/lit_tests/TestCases/use_globals_uninitialized.cc
deleted file mode 100644
index e1d045e3f79f..000000000000
--- a/lib/lsan/lit_tests/TestCases/use_globals_uninitialized.cc
+++ /dev/null
@@ -1,21 +0,0 @@
-// Test that uninitialized globals are included in the root set.
-// RUN: LSAN_BASE="report_objects=1:use_stacks=0:use_registers=0"
-// RUN: %clangxx_lsan %s -o %t
-// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_globals=0" not %t 2>&1 | FileCheck %s
-// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_globals=1" %t 2>&1
-// RUN: LSAN_OPTIONS="" %t 2>&1
-
-#include <stdio.h>
-#include <stdlib.h>
-
-void *bss_var;
-
-int main() {
- bss_var = malloc(1337);
- fprintf(stderr, "Test alloc: %p.\n", bss_var);
- return 0;
-}
-// CHECK: Test alloc: [[ADDR:.*]].
-// CHECK: Directly leaked 1337 byte object at [[ADDR]]
-// CHECK: LeakSanitizer: detected memory leaks
-// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer:
diff --git a/lib/lsan/lit_tests/TestCases/use_registers.cc b/lib/lsan/lit_tests/TestCases/use_registers.cc
deleted file mode 100644
index a7d8a69d7173..000000000000
--- a/lib/lsan/lit_tests/TestCases/use_registers.cc
+++ /dev/null
@@ -1,51 +0,0 @@
-// Test that registers of running threads are included in the root set.
-// RUN: LSAN_BASE="report_objects=1:use_stacks=0"
-// RUN: %clangxx_lsan -pthread %s -o %t
-// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_registers=0" not %t 2>&1 | FileCheck %s
-// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_registers=1" %t 2>&1
-// RUN: LSAN_OPTIONS="" %t 2>&1
-
-#include <assert.h>
-#include <pthread.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-extern "C"
-void *registers_thread_func(void *arg) {
- int *sync = reinterpret_cast<int *>(arg);
- void *p = malloc(1337);
- // To store the pointer, choose a register which is unlikely to be reused by
- // a function call.
-#if defined(__i386__)
- asm ( "mov %0, %%esi"
- :
- : "r" (p)
- );
-#elif defined(__x86_64__)
- asm ( "mov %0, %%r15"
- :
- : "r" (p)
- );
-#else
-#error "Test is not supported on this architecture."
-#endif
- fprintf(stderr, "Test alloc: %p.\n", p);
- fflush(stderr);
- __sync_fetch_and_xor(sync, 1);
- while (true)
- pthread_yield();
-}
-
-int main() {
- int sync = 0;
- pthread_t thread_id;
- int res = pthread_create(&thread_id, 0, registers_thread_func, &sync);
- assert(res == 0);
- while (!__sync_fetch_and_xor(&sync, 0))
- pthread_yield();
- return 0;
-}
-// CHECK: Test alloc: [[ADDR:.*]].
-// CHECK: Directly leaked 1337 byte object at [[ADDR]]
-// CHECK: LeakSanitizer: detected memory leaks
-// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer:
diff --git a/lib/lsan/lit_tests/TestCases/use_stacks.cc b/lib/lsan/lit_tests/TestCases/use_stacks.cc
deleted file mode 100644
index 4287a96b2285..000000000000
--- a/lib/lsan/lit_tests/TestCases/use_stacks.cc
+++ /dev/null
@@ -1,20 +0,0 @@
-// Test that stack of main thread is included in the root set.
-// RUN: LSAN_BASE="report_objects=1:use_registers=0"
-// RUN: %clangxx_lsan %s -o %t
-// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_stacks=0" not %t 2>&1 | FileCheck %s
-// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_stacks=1" %t 2>&1
-// RUN: LSAN_OPTIONS="" %t 2>&1
-
-#include <stdio.h>
-#include <stdlib.h>
-
-int main() {
- void *stack_var = malloc(1337);
- fprintf(stderr, "Test alloc: %p.\n", stack_var);
- // Do not return from main to prevent the pointer from going out of scope.
- exit(0);
-}
-// CHECK: Test alloc: [[ADDR:.*]].
-// CHECK: Directly leaked 1337 byte object at [[ADDR]]
-// CHECK: LeakSanitizer: detected memory leaks
-// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer:
diff --git a/lib/lsan/lit_tests/TestCases/use_stacks_threaded.cc b/lib/lsan/lit_tests/TestCases/use_stacks_threaded.cc
deleted file mode 100644
index c7dfaf8abad6..000000000000
--- a/lib/lsan/lit_tests/TestCases/use_stacks_threaded.cc
+++ /dev/null
@@ -1,36 +0,0 @@
-// Test that stacks of non-main threads are included in the root set.
-// RUN: LSAN_BASE="report_objects=1:use_registers=0"
-// RUN: %clangxx_lsan -pthread %s -o %t
-// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_stacks=0" not %t 2>&1 | FileCheck %s
-// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_stacks=1" %t 2>&1
-// RUN: LSAN_OPTIONS="" %t 2>&1
-
-#include <assert.h>
-#include <pthread.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-extern "C"
-void *stacks_thread_func(void *arg) {
- int *sync = reinterpret_cast<int *>(arg);
- void *p = malloc(1337);
- fprintf(stderr, "Test alloc: %p.\n", p);
- fflush(stderr);
- __sync_fetch_and_xor(sync, 1);
- while (true)
- pthread_yield();
-}
-
-int main() {
- int sync = 0;
- pthread_t thread_id;
- int res = pthread_create(&thread_id, 0, stacks_thread_func, &sync);
- assert(res == 0);
- while (!__sync_fetch_and_xor(&sync, 0))
- pthread_yield();
- return 0;
-}
-// CHECK: Test alloc: [[ADDR:.*]].
-// CHECK: Directly leaked 1337 byte object at [[ADDR]]
-// CHECK: LeakSanitizer: detected memory leaks
-// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer:
diff --git a/lib/lsan/lit_tests/TestCases/use_tls_dynamic.cc b/lib/lsan/lit_tests/TestCases/use_tls_dynamic.cc
deleted file mode 100644
index 2570b63f0c5e..000000000000
--- a/lib/lsan/lit_tests/TestCases/use_tls_dynamic.cc
+++ /dev/null
@@ -1,33 +0,0 @@
-// Test that dynamically allocated TLS space is included in the root set.
-// RUN: LSAN_BASE="report_objects=1:use_stacks=0:use_registers=0"
-// RUN: %clangxx %p/SharedLibs/huge_tls_lib_so.cc -fPIC -shared -o %t-so.so
-// RUN: %clangxx_lsan %s -o %t
-// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=0" not %t 2>&1 | FileCheck %s
-// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=1" %t 2>&1
-// RUN: LSAN_OPTIONS="" %t 2>&1
-
-#include <assert.h>
-#include <dlfcn.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string>
-
-int main(int argc, char *argv[]) {
- std::string path = std::string(argv[0]) + "-so.so";
-
- void *handle = dlopen(path.c_str(), RTLD_LAZY);
- assert(handle != 0);
- typedef void **(* store_t)(void *p);
- store_t StoreToTLS = (store_t)dlsym(handle, "StoreToTLS");
- assert(dlerror() == 0);
-
- void *p = malloc(1337);
- void **p_in_tls = StoreToTLS(p);
- assert(*p_in_tls == p);
- fprintf(stderr, "Test alloc: %p.\n", p);
- return 0;
-}
-// CHECK: Test alloc: [[ADDR:.*]].
-// CHECK: leaked 1337 byte object at [[ADDR]]
-// CHECK: LeakSanitizer: detected memory leaks
-// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer:
diff --git a/lib/lsan/lit_tests/TestCases/use_tls_pthread_specific_dynamic.cc b/lib/lsan/lit_tests/TestCases/use_tls_pthread_specific_dynamic.cc
deleted file mode 100644
index 3dea41edddd4..000000000000
--- a/lib/lsan/lit_tests/TestCases/use_tls_pthread_specific_dynamic.cc
+++ /dev/null
@@ -1,37 +0,0 @@
-// Test that dynamically allocated thread-specific storage is included in the root set.
-// RUN: LSAN_BASE="report_objects=1:use_stacks=0:use_registers=0"
-// RUN: %clangxx_lsan %s -o %t
-// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=0" not %t 2>&1 | FileCheck %s
-// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=1" %t 2>&1
-// RUN: LSAN_OPTIONS="" %t 2>&1
-
-#include <assert.h>
-#include <pthread.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-// From glibc: this many keys are stored in the thread descriptor directly.
-const unsigned PTHREAD_KEY_2NDLEVEL_SIZE = 32;
-
-int main() {
- static const unsigned kDummyKeysCount = PTHREAD_KEY_2NDLEVEL_SIZE;
- int res;
- pthread_key_t dummy_keys[kDummyKeysCount];
- for (unsigned i = 0; i < kDummyKeysCount; i++) {
- res = pthread_key_create(&dummy_keys[i], NULL);
- assert(res == 0);
- }
- pthread_key_t key;
- res = pthread_key_create(&key, NULL);
- assert(key >= PTHREAD_KEY_2NDLEVEL_SIZE);
- assert(res == 0);
- void *p = malloc(1337);
- res = pthread_setspecific(key, p);
- assert(res == 0);
- fprintf(stderr, "Test alloc: %p.\n", p);
- return 0;
-}
-// CHECK: Test alloc: [[ADDR:.*]].
-// CHECK: leaked 1337 byte object at [[ADDR]]
-// CHECK: LeakSanitizer: detected memory leaks
-// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer:
diff --git a/lib/lsan/lit_tests/TestCases/use_tls_pthread_specific_static.cc b/lib/lsan/lit_tests/TestCases/use_tls_pthread_specific_static.cc
deleted file mode 100644
index b75f15153863..000000000000
--- a/lib/lsan/lit_tests/TestCases/use_tls_pthread_specific_static.cc
+++ /dev/null
@@ -1,31 +0,0 @@
-// Test that statically allocated thread-specific storage is included in the root set.
-// RUN: LSAN_BASE="report_objects=1:use_stacks=0:use_registers=0"
-// RUN: %clangxx_lsan %s -o %t
-// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=0" not %t 2>&1 | FileCheck %s
-// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=1" %t 2>&1
-// RUN: LSAN_OPTIONS="" %t 2>&1
-
-#include <assert.h>
-#include <pthread.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-// From glibc: this many keys are stored in the thread descriptor directly.
-const unsigned PTHREAD_KEY_2NDLEVEL_SIZE = 32;
-
-int main() {
- pthread_key_t key;
- int res;
- res = pthread_key_create(&key, NULL);
- assert(res == 0);
- assert(key < PTHREAD_KEY_2NDLEVEL_SIZE);
- void *p = malloc(1337);
- res = pthread_setspecific(key, p);
- assert(res == 0);
- fprintf(stderr, "Test alloc: %p.\n", p);
- return 0;
-}
-// CHECK: Test alloc: [[ADDR:.*]].
-// CHECK: Directly leaked 1337 byte object at [[ADDR]]
-// CHECK: LeakSanitizer: detected memory leaks
-// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer:
diff --git a/lib/lsan/lit_tests/TestCases/use_tls_static.cc b/lib/lsan/lit_tests/TestCases/use_tls_static.cc
deleted file mode 100644
index 9ccb2b2b7fb1..000000000000
--- a/lib/lsan/lit_tests/TestCases/use_tls_static.cc
+++ /dev/null
@@ -1,21 +0,0 @@
-// Test that statically allocated TLS space is included in the root set.
-// RUN: LSAN_BASE="report_objects=1:use_stacks=0:use_registers=0"
-// RUN: %clangxx_lsan %s -o %t
-// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=0" not %t 2>&1 | FileCheck %s
-// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=1" %t 2>&1
-// RUN: LSAN_OPTIONS="" %t 2>&1
-
-#include <stdio.h>
-#include <stdlib.h>
-
-__thread void *tls_var;
-
-int main() {
- tls_var = malloc(1337);
- fprintf(stderr, "Test alloc: %p.\n", tls_var);
- return 0;
-}
-// CHECK: Test alloc: [[ADDR:.*]].
-// CHECK: Directly leaked 1337 byte object at [[ADDR]]
-// CHECK: LeakSanitizer: detected memory leaks
-// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer:
diff --git a/lib/lsan/lit_tests/TestCases/use_unaligned.cc b/lib/lsan/lit_tests/TestCases/use_unaligned.cc
deleted file mode 100644
index bc75f11b99f0..000000000000
--- a/lib/lsan/lit_tests/TestCases/use_unaligned.cc
+++ /dev/null
@@ -1,23 +0,0 @@
-// Test that unaligned pointers are detected correctly.
-// RUN: LSAN_BASE="report_objects=1:use_stacks=0:use_registers=0"
-// RUN: %clangxx_lsan %s -o %t
-// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_unaligned=0" not %t 2>&1 | FileCheck %s
-// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_unaligned=1" %t 2>&1
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-void *arr[2];
-
-int main() {
- void *p = malloc(1337);
- fprintf(stderr, "Test alloc: %p.\n", p);
- char *char_arr = (char *)arr;
- memcpy(char_arr + 1, &p, sizeof(p));
- return 0;
-}
-// CHECK: Test alloc: [[ADDR:.*]].
-// CHECK: Directly leaked 1337 byte object at [[ADDR]]
-// CHECK: LeakSanitizer: detected memory leaks
-// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer:
diff --git a/lib/lsan/lit_tests/Unit/lit.site.cfg.in b/lib/lsan/lit_tests/Unit/lit.site.cfg.in
deleted file mode 100644
index a3a4e9ad0b13..000000000000
--- a/lib/lsan/lit_tests/Unit/lit.site.cfg.in
+++ /dev/null
@@ -1,12 +0,0 @@
-## Autogenerated by LLVM/Clang configuration.
-# Do not edit!
-
-# Load common config for all compiler-rt unit tests.
-lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/lib/lit.common.unit.configured")
-
-# Setup config name.
-config.name = 'LeakSanitizer-Unit'
-# Setup test source and exec root. For unit tests, we define
-# it as build directory with LSan unit tests.
-config.test_exec_root = "@LSAN_BINARY_DIR@/tests"
-config.test_source_root = config.test_exec_root
diff --git a/lib/lsan/lit_tests/lit.common.cfg b/lib/lsan/lit_tests/lit.common.cfg
deleted file mode 100644
index 96dc1b1f55fc..000000000000
--- a/lib/lsan/lit_tests/lit.common.cfg
+++ /dev/null
@@ -1,43 +0,0 @@
-# -*- Python -*-
-
-# Common configuration for running leak detection tests under LSan/ASan.
-
-import os
-
-def get_required_attr(config, attr_name):
- attr_value = getattr(config, attr_name, None)
- if not attr_value:
- lit_config.fatal(
- "No attribute %r in test configuration! You may need to run "
- "tests from your build directory or add this attribute "
- "to lit.site.cfg " % attr_name)
- return attr_value
-
-# Setup source root.
-lsan_lit_src_root = get_required_attr(config, 'lsan_lit_src_root')
-config.test_source_root = os.path.join(lsan_lit_src_root, 'TestCases')
-
-clang_cxxflags = ("--driver-mode=g++ "
- + "-g "
- + "-O0 "
- + "-m64 ")
-
-clang_cflags = ("-g "
- + "-O0 "
- + "-m64 ")
-
-config.clang_cxxflags = clang_cxxflags
-
-config.substitutions.append( ("%clangxx ", (" " + config.clang + " " +
- clang_cxxflags + " ")) )
-
-config.clang_cflags = clang_cflags
-
-config.substitutions.append( ("%clang ", (" " + config.clang + " " +
- clang_cflags + " ")) )
-
-# LeakSanitizer tests are currently supported on x86-64 Linux only.
-if config.host_os not in ['Linux'] or config.host_arch not in ['x86_64']:
- config.unsupported = True
-
-config.suffixes = ['.c', '.cc', '.cpp']
diff --git a/lib/lsan/lsan.cc b/lib/lsan/lsan.cc
index 058bbdba3907..1598fcac4a76 100644
--- a/lib/lsan/lsan.cc
+++ b/lib/lsan/lsan.cc
@@ -25,14 +25,9 @@ bool lsan_init_is_running;
namespace __lsan {
-static void InitializeCommonFlags() {
- CommonFlags *cf = common_flags();
- SetCommonFlagDefaults();
- cf->external_symbolizer_path = GetEnv("LSAN_SYMBOLIZER_PATH");
- cf->malloc_context_size = 30;
- cf->detect_leaks = true;
-
- ParseCommonFlagsFromString(GetEnv("LSAN_OPTIONS"));
+///// Interface to the common LSan module. /////
+bool WordIsPoisoned(uptr addr) {
+ return false;
}
} // namespace __lsan
@@ -45,7 +40,7 @@ extern "C" void __lsan_init() {
return;
lsan_init_is_running = true;
SanitizerToolName = "LeakSanitizer";
- InitializeCommonFlags();
+ InitCommonLsan(true);
InitializeAllocator();
InitTlsSize();
InitializeInterceptors();
@@ -55,17 +50,14 @@ extern "C" void __lsan_init() {
ThreadStart(tid, GetTid());
SetCurrentThread(tid);
- // Start symbolizer process if necessary.
- if (common_flags()->symbolize) {
- Symbolizer::Init(common_flags()->external_symbolizer_path);
- } else {
- Symbolizer::Disable();
- }
-
- InitCommonLsan();
if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit)
Atexit(DoLeakCheck);
lsan_inited = true;
lsan_init_is_running = false;
}
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_print_stack_trace() {
+ GET_STACK_TRACE_FATAL;
+ stack.Print();
+}
diff --git a/lib/lsan/lsan.h b/lib/lsan/lsan.h
index 3e7f76b08193..53783cdc9c7d 100644
--- a/lib/lsan/lsan.h
+++ b/lib/lsan/lsan.h
@@ -15,6 +15,26 @@
#include "sanitizer_common/sanitizer_flags.h"
#include "sanitizer_common/sanitizer_stacktrace.h"
+#define GET_STACK_TRACE(max_size, fast) \
+ BufferedStackTrace stack; \
+ { \
+ uptr stack_top = 0, stack_bottom = 0; \
+ ThreadContext *t; \
+ if (fast && (t = CurrentThreadContext())) { \
+ stack_top = t->stack_end(); \
+ stack_bottom = t->stack_begin(); \
+ } \
+ stack.Unwind(max_size, StackTrace::GetCurrentPc(), GET_CURRENT_FRAME(), \
+ /* context */ 0, stack_top, stack_bottom, fast); \
+ }
+
+#define GET_STACK_TRACE_FATAL \
+ GET_STACK_TRACE(kStackTraceMax, common_flags()->fast_unwind_on_fatal)
+
+#define GET_STACK_TRACE_MALLOC \
+ GET_STACK_TRACE(__sanitizer::common_flags()->malloc_context_size, \
+ common_flags()->fast_unwind_on_malloc)
+
namespace __lsan {
void InitializeInterceptors();
diff --git a/lib/lsan/lsan_allocator.cc b/lib/lsan/lsan_allocator.cc
index f7eee1314bf0..8be2a2ad9224 100644
--- a/lib/lsan/lsan_allocator.cc
+++ b/lib/lsan/lsan_allocator.cc
@@ -15,6 +15,7 @@
#include "lsan_allocator.h"
#include "sanitizer_common/sanitizer_allocator.h"
+#include "sanitizer_common/sanitizer_allocator_interface.h"
#include "sanitizer_common/sanitizer_internal_defs.h"
#include "sanitizer_common/sanitizer_stackdepot.h"
#include "sanitizer_common/sanitizer_stacktrace.h"
@@ -53,7 +54,7 @@ void AllocatorThreadFinish() {
allocator.SwallowCache(&cache);
}
-static ChunkMetadata *Metadata(void *p) {
+static ChunkMetadata *Metadata(const void *p) {
return reinterpret_cast<ChunkMetadata *>(allocator.GetMetaData(p));
}
@@ -62,7 +63,7 @@ static void RegisterAllocation(const StackTrace &stack, void *p, uptr size) {
ChunkMetadata *m = Metadata(p);
CHECK(m);
m->tag = DisabledInThisThread() ? kIgnored : kDirectlyLeaked;
- m->stack_trace_id = StackDepotPut(stack.trace, stack.size);
+ m->stack_trace_id = StackDepotPut(stack);
m->requested_size = size;
atomic_store(reinterpret_cast<atomic_uint8_t *>(m), 1, memory_order_relaxed);
}
@@ -87,10 +88,12 @@ void *Allocate(const StackTrace &stack, uptr size, uptr alignment,
if (cleared && allocator.FromPrimary(p))
memset(p, 0, size);
RegisterAllocation(stack, p, size);
+ if (&__sanitizer_malloc_hook) __sanitizer_malloc_hook(p, size);
return p;
}
void Deallocate(void *p) {
+ if (&__sanitizer_free_hook) __sanitizer_free_hook(p);
RegisterDeallocation(p);
allocator.Deallocate(&cache, p);
}
@@ -113,7 +116,7 @@ void GetAllocatorCacheRange(uptr *begin, uptr *end) {
*end = *begin + sizeof(cache);
}
-uptr GetMallocUsableSize(void *p) {
+uptr GetMallocUsableSize(const void *p) {
ChunkMetadata *m = Metadata(p);
if (!m) return 0;
return m->requested_size;
@@ -143,7 +146,11 @@ uptr PointsIntoChunk(void* p) {
if (addr < chunk) return 0;
ChunkMetadata *m = Metadata(reinterpret_cast<void *>(chunk));
CHECK(m);
- if (m->allocated && addr < chunk + m->requested_size)
+ if (!m->allocated)
+ return 0;
+ if (addr < chunk + m->requested_size)
+ return chunk;
+ if (IsSpecialCaseOfOperatorNew0(chunk, m->requested_size, addr))
return chunk;
return 0;
}
@@ -196,3 +203,38 @@ IgnoreObjectResult IgnoreObjectLocked(const void *p) {
}
}
} // namespace __lsan
+
+using namespace __lsan;
+
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE
+uptr __sanitizer_get_current_allocated_bytes() {
+ uptr stats[AllocatorStatCount];
+ allocator.GetStats(stats);
+ return stats[AllocatorStatAllocated];
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+uptr __sanitizer_get_heap_size() {
+ uptr stats[AllocatorStatCount];
+ allocator.GetStats(stats);
+ return stats[AllocatorStatMapped];
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+uptr __sanitizer_get_free_bytes() { return 0; }
+
+SANITIZER_INTERFACE_ATTRIBUTE
+uptr __sanitizer_get_unmapped_bytes() { return 0; }
+
+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; }
+
+SANITIZER_INTERFACE_ATTRIBUTE
+uptr __sanitizer_get_allocated_size(const void *p) {
+ return GetMallocUsableSize(p);
+}
+} // extern "C"
diff --git a/lib/lsan/lsan_allocator.h b/lib/lsan/lsan_allocator.h
index 00c55ae02f15..f564601193bd 100644
--- a/lib/lsan/lsan_allocator.h
+++ b/lib/lsan/lsan_allocator.h
@@ -25,7 +25,7 @@ void *Allocate(const StackTrace &stack, uptr size, uptr alignment,
void Deallocate(void *p);
void *Reallocate(const StackTrace &stack, void *p, uptr new_size,
uptr alignment);
-uptr GetMallocUsableSize(void *p);
+uptr GetMallocUsableSize(const void *p);
template<typename Callable>
void ForEachChunk(const Callable &callback);
diff --git a/lib/lsan/lsan_common.cc b/lib/lsan/lsan_common.cc
index 152588411e2f..c2ba52e46911 100644
--- a/lib/lsan/lsan_common.cc
+++ b/lib/lsan/lsan_common.cc
@@ -17,6 +17,7 @@
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_flags.h"
#include "sanitizer_common/sanitizer_placement_new.h"
+#include "sanitizer_common/sanitizer_procmaps.h"
#include "sanitizer_common/sanitizer_stackdepot.h"
#include "sanitizer_common/sanitizer_stacktrace.h"
#include "sanitizer_common/sanitizer_stoptheworld.h"
@@ -26,7 +27,8 @@
#if CAN_SANITIZE_LEAKS
namespace __lsan {
-// This mutex is used to prevent races between DoLeakCheck and IgnoreObject.
+// This mutex is used to prevent races between DoLeakCheck and IgnoreObject, and
+// also to protect the global list of root regions.
BlockingMutex global_mutex(LINKER_INITIALIZED);
THREADLOCAL int disable_counter;
@@ -34,65 +36,90 @@ bool DisabledInThisThread() { return disable_counter > 0; }
Flags lsan_flags;
-static void InitializeFlags() {
+static void InitializeFlags(bool standalone) {
Flags *f = flags();
// Default values.
f->report_objects = false;
f->resolution = 0;
f->max_leaks = 0;
f->exitcode = 23;
- f->suppressions="";
f->use_registers = true;
f->use_globals = true;
f->use_stacks = true;
f->use_tls = true;
+ f->use_root_regions = true;
f->use_unaligned = false;
- f->verbosity = 0;
+ f->use_poisoned = false;
f->log_pointers = false;
f->log_threads = false;
const char *options = GetEnv("LSAN_OPTIONS");
if (options) {
- ParseFlag(options, &f->use_registers, "use_registers");
- ParseFlag(options, &f->use_globals, "use_globals");
- ParseFlag(options, &f->use_stacks, "use_stacks");
- ParseFlag(options, &f->use_tls, "use_tls");
- ParseFlag(options, &f->use_unaligned, "use_unaligned");
- ParseFlag(options, &f->report_objects, "report_objects");
- ParseFlag(options, &f->resolution, "resolution");
+ ParseFlag(options, &f->use_registers, "use_registers", "");
+ ParseFlag(options, &f->use_globals, "use_globals", "");
+ ParseFlag(options, &f->use_stacks, "use_stacks", "");
+ ParseFlag(options, &f->use_tls, "use_tls", "");
+ ParseFlag(options, &f->use_root_regions, "use_root_regions", "");
+ ParseFlag(options, &f->use_unaligned, "use_unaligned", "");
+ ParseFlag(options, &f->use_poisoned, "use_poisoned", "");
+ ParseFlag(options, &f->report_objects, "report_objects", "");
+ ParseFlag(options, &f->resolution, "resolution", "");
CHECK_GE(&f->resolution, 0);
- ParseFlag(options, &f->max_leaks, "max_leaks");
+ ParseFlag(options, &f->max_leaks, "max_leaks", "");
CHECK_GE(&f->max_leaks, 0);
- ParseFlag(options, &f->verbosity, "verbosity");
- ParseFlag(options, &f->log_pointers, "log_pointers");
- ParseFlag(options, &f->log_threads, "log_threads");
- ParseFlag(options, &f->exitcode, "exitcode");
- ParseFlag(options, &f->suppressions, "suppressions");
+ ParseFlag(options, &f->log_pointers, "log_pointers", "");
+ ParseFlag(options, &f->log_threads, "log_threads", "");
+ ParseFlag(options, &f->exitcode, "exitcode", "");
}
+
+ // Set defaults for common flags (only in standalone mode) and parse
+ // them from LSAN_OPTIONS.
+ CommonFlags *cf = common_flags();
+ if (standalone) {
+ SetCommonFlagsDefaults(cf);
+ cf->external_symbolizer_path = GetEnv("LSAN_SYMBOLIZER_PATH");
+ cf->malloc_context_size = 30;
+ cf->detect_leaks = true;
+ }
+ ParseCommonFlagsFromString(cf, options);
}
-SuppressionContext *suppression_ctx;
+#define LOG_POINTERS(...) \
+ do { \
+ if (flags()->log_pointers) Report(__VA_ARGS__); \
+ } while (0);
+
+#define LOG_THREADS(...) \
+ do { \
+ if (flags()->log_threads) Report(__VA_ARGS__); \
+ } while (0);
+
+static bool suppressions_inited = false;
void InitializeSuppressions() {
- CHECK(!suppression_ctx);
- ALIGNED(64) static char placeholder_[sizeof(SuppressionContext)];
- suppression_ctx = new(placeholder_) SuppressionContext;
- char *suppressions_from_file;
- uptr buffer_size;
- if (ReadFileToBuffer(flags()->suppressions, &suppressions_from_file,
- &buffer_size, 1 << 26 /* max_len */))
- suppression_ctx->Parse(suppressions_from_file);
- if (flags()->suppressions[0] && !buffer_size) {
- Printf("LeakSanitizer: failed to read suppressions file '%s'\n",
- flags()->suppressions);
- Die();
- }
+ CHECK(!suppressions_inited);
+ SuppressionContext::InitIfNecessary();
if (&__lsan_default_suppressions)
- suppression_ctx->Parse(__lsan_default_suppressions());
+ SuppressionContext::Get()->Parse(__lsan_default_suppressions());
+ suppressions_inited = true;
+}
+
+struct RootRegion {
+ const void *begin;
+ uptr size;
+};
+
+InternalMmapVector<RootRegion> *root_regions;
+
+void InitializeRootRegions() {
+ CHECK(!root_regions);
+ ALIGNED(64) static char placeholder[sizeof(InternalMmapVector<RootRegion>)];
+ root_regions = new(placeholder) InternalMmapVector<RootRegion>(1);
}
-void InitCommonLsan() {
- InitializeFlags();
+void InitCommonLsan(bool standalone) {
+ InitializeFlags(standalone);
+ InitializeRootRegions();
if (common_flags()->detect_leaks) {
// Initialization which can fail or print warnings should only be done if
// LSan is actually enabled.
@@ -101,9 +128,9 @@ void InitCommonLsan() {
}
}
-class Decorator: private __sanitizer::AnsiColorDecorator {
+class Decorator: public __sanitizer::SanitizerCommonDecorator {
public:
- Decorator() : __sanitizer::AnsiColorDecorator(PrintsToTtyCached()) { }
+ Decorator() : SanitizerCommonDecorator() { }
const char *Error() { return Red(); }
const char *Leak() { return Blue(); }
const char *End() { return Default(); }
@@ -132,8 +159,7 @@ void ScanRangeForPointers(uptr begin, uptr end,
Frontier *frontier,
const char *region_type, ChunkTag tag) {
const uptr alignment = flags()->pointer_alignment();
- if (flags()->log_pointers)
- Report("Scanning %s range %p-%p.\n", region_type, begin, end);
+ LOG_POINTERS("Scanning %s range %p-%p.\n", region_type, begin, end);
uptr pp = begin;
if (pp % alignment)
pp = pp + alignment - pp % alignment;
@@ -148,10 +174,19 @@ void ScanRangeForPointers(uptr begin, uptr end,
// Reachable beats ignored beats leaked.
if (m.tag() == kReachable) continue;
if (m.tag() == kIgnored && tag != kReachable) continue;
+
+ // Do this check relatively late so we can log only the interesting cases.
+ if (!flags()->use_poisoned && WordIsPoisoned(pp)) {
+ LOG_POINTERS(
+ "%p is poisoned: ignoring %p pointing into chunk %p-%p of size "
+ "%zu.\n",
+ pp, p, chunk, chunk + m.requested_size(), m.requested_size());
+ continue;
+ }
+
m.set_tag(tag);
- if (flags()->log_pointers)
- Report("%p: found %p pointing into chunk %p-%p of size %zu.\n", pp, p,
- chunk, chunk + m.requested_size(), m.requested_size());
+ LOG_POINTERS("%p: found %p pointing into chunk %p-%p of size %zu.\n", pp, p,
+ chunk, chunk + m.requested_size(), m.requested_size());
if (frontier)
frontier->push_back(chunk);
}
@@ -170,7 +205,7 @@ static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
uptr registers_end = registers_begin + registers.size();
for (uptr i = 0; i < suspended_threads.thread_count(); i++) {
uptr os_id = static_cast<uptr>(suspended_threads.GetThreadID(i));
- if (flags()->log_threads) Report("Processing thread %d.\n", os_id);
+ LOG_THREADS("Processing thread %d.\n", os_id);
uptr stack_begin, stack_end, tls_begin, tls_end, cache_begin, cache_end;
bool thread_found = GetThreadRangesLocked(os_id, &stack_begin, &stack_end,
&tls_begin, &tls_end,
@@ -178,8 +213,7 @@ static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
if (!thread_found) {
// If a thread can't be found in the thread registry, it's probably in the
// process of destruction. Log this event and move on.
- if (flags()->log_threads)
- Report("Thread %d not found in registry.\n", os_id);
+ LOG_THREADS("Thread %d not found in registry.\n", os_id);
continue;
}
uptr sp;
@@ -196,14 +230,12 @@ static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
"REGISTERS", kReachable);
if (flags()->use_stacks) {
- if (flags()->log_threads)
- Report("Stack at %p-%p, SP = %p.\n", stack_begin, stack_end, sp);
+ LOG_THREADS("Stack at %p-%p (SP = %p).\n", stack_begin, stack_end, sp);
if (sp < stack_begin || sp >= stack_end) {
// SP is outside the recorded stack range (e.g. the thread is running a
// signal handler on alternate stack). Again, consider the entire stack
// range to be reachable.
- if (flags()->log_threads)
- Report("WARNING: stack pointer not in stack range.\n");
+ LOG_THREADS("WARNING: stack pointer not in stack range.\n");
} else {
// Shrink the stack range to ignore out-of-scope values.
stack_begin = sp;
@@ -214,7 +246,7 @@ static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
}
if (flags()->use_tls) {
- if (flags()->log_threads) Report("TLS at %p-%p.\n", tls_begin, tls_end);
+ LOG_THREADS("TLS at %p-%p.\n", tls_begin, tls_end);
if (cache_begin == cache_end) {
ScanRangeForPointers(tls_begin, tls_end, frontier, "TLS", kReachable);
} else {
@@ -232,6 +264,37 @@ static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
}
}
+static void ProcessRootRegion(Frontier *frontier, uptr root_begin,
+ uptr root_end) {
+ MemoryMappingLayout proc_maps(/*cache_enabled*/true);
+ uptr begin, end, prot;
+ while (proc_maps.Next(&begin, &end,
+ /*offset*/ 0, /*filename*/ 0, /*filename_size*/ 0,
+ &prot)) {
+ uptr intersection_begin = Max(root_begin, begin);
+ uptr intersection_end = Min(end, root_end);
+ if (intersection_begin >= intersection_end) continue;
+ bool is_readable = prot & MemoryMappingLayout::kProtectionRead;
+ LOG_POINTERS("Root region %p-%p intersects with mapped region %p-%p (%s)\n",
+ root_begin, root_end, begin, end,
+ is_readable ? "readable" : "unreadable");
+ if (is_readable)
+ ScanRangeForPointers(intersection_begin, intersection_end, frontier,
+ "ROOT", kReachable);
+ }
+}
+
+// Scans root regions for heap pointers.
+static void ProcessRootRegions(Frontier *frontier) {
+ if (!flags()->use_root_regions) return;
+ CHECK(root_regions);
+ for (uptr i = 0; i < root_regions->size(); i++) {
+ RootRegion region = (*root_regions)[i];
+ uptr begin_addr = reinterpret_cast<uptr>(region.begin);
+ ProcessRootRegion(frontier, begin_addr, begin_addr + region.size);
+ }
+}
+
static void FloodFillTag(Frontier *frontier, ChunkTag tag) {
while (frontier->size()) {
uptr next_chunk = frontier->back();
@@ -266,41 +329,37 @@ static void CollectIgnoredCb(uptr chunk, void *arg) {
// Sets the appropriate tag on each chunk.
static void ClassifyAllChunks(SuspendedThreadsList const &suspended_threads) {
// Holds the flood fill frontier.
- Frontier frontier(GetPageSizeCached());
+ Frontier frontier(1);
- if (flags()->use_globals)
- ProcessGlobalRegions(&frontier);
+ ProcessGlobalRegions(&frontier);
ProcessThreads(suspended_threads, &frontier);
+ ProcessRootRegions(&frontier);
FloodFillTag(&frontier, kReachable);
// The check here is relatively expensive, so we do this in a separate flood
// fill. That way we can skip the check for chunks that are reachable
// otherwise.
- if (flags()->log_pointers)
- Report("Processing platform-specific allocations.\n");
+ LOG_POINTERS("Processing platform-specific allocations.\n");
ProcessPlatformSpecificAllocations(&frontier);
FloodFillTag(&frontier, kReachable);
- if (flags()->log_pointers)
- Report("Scanning ignored chunks.\n");
+ LOG_POINTERS("Scanning ignored chunks.\n");
CHECK_EQ(0, frontier.size());
ForEachChunk(CollectIgnoredCb, &frontier);
FloodFillTag(&frontier, kIgnored);
// Iterate over leaked chunks and mark those that are reachable from other
// leaked chunks.
- if (flags()->log_pointers)
- Report("Scanning leaked chunks.\n");
+ LOG_POINTERS("Scanning leaked chunks.\n");
ForEachChunk(MarkIndirectlyLeakedCb, 0 /* arg */);
}
static void PrintStackTraceById(u32 stack_trace_id) {
CHECK(stack_trace_id);
- uptr size = 0;
- const uptr *trace = StackDepotGet(stack_trace_id, &size);
- StackTrace::PrintStack(trace, size);
+ StackDepotGet(stack_trace_id).Print();
}
-// ForEachChunk callback. Aggregates unreachable chunks into a LeakReport.
+// ForEachChunk callback. Aggregates information about unreachable chunks into
+// a LeakReport.
static void CollectLeaksCb(uptr chunk, void *arg) {
CHECK(arg);
LeakReport *leak_report = reinterpret_cast<LeakReport *>(arg);
@@ -309,32 +368,22 @@ static void CollectLeaksCb(uptr chunk, void *arg) {
if (!m.allocated()) return;
if (m.tag() == kDirectlyLeaked || m.tag() == kIndirectlyLeaked) {
uptr resolution = flags()->resolution;
+ u32 stack_trace_id = 0;
if (resolution > 0) {
- uptr size = 0;
- const uptr *trace = StackDepotGet(m.stack_trace_id(), &size);
- size = Min(size, resolution);
- leak_report->Add(StackDepotPut(trace, size), m.requested_size(), m.tag());
+ StackTrace stack = StackDepotGet(m.stack_trace_id());
+ stack.size = Min(stack.size, resolution);
+ stack_trace_id = StackDepotPut(stack);
} else {
- leak_report->Add(m.stack_trace_id(), m.requested_size(), m.tag());
+ stack_trace_id = m.stack_trace_id();
}
- }
-}
-
-// ForEachChunkCallback. Prints addresses of unreachable chunks.
-static void PrintLeakedCb(uptr chunk, void *arg) {
- chunk = GetUserBegin(chunk);
- LsanMetadata m(chunk);
- if (!m.allocated()) return;
- if (m.tag() == kDirectlyLeaked || m.tag() == kIndirectlyLeaked) {
- Printf("%s leaked %zu byte object at %p.\n",
- m.tag() == kDirectlyLeaked ? "Directly" : "Indirectly",
- m.requested_size(), chunk);
+ leak_report->AddLeakedChunk(chunk, stack_trace_id, m.requested_size(),
+ m.tag());
}
}
static void PrintMatchedSuppressions() {
InternalMmapVector<Suppression *> matched(1);
- suppression_ctx->GetMatched(&matched);
+ SuppressionContext::Get()->GetMatched(&matched);
if (!matched.size())
return;
const char *line = "-----------------------------------------------------";
@@ -347,12 +396,6 @@ static void PrintMatchedSuppressions() {
Printf("%s\n\n", line);
}
-static void PrintLeaked() {
- Printf("\n");
- Printf("Reporting individual objects:\n");
- ForEachChunk(PrintLeakedCb, 0 /* arg */);
-}
-
struct DoLeakCheckParam {
bool success;
LeakReport leak_report;
@@ -363,11 +406,8 @@ static void DoLeakCheckCallback(const SuspendedThreadsList &suspended_threads,
DoLeakCheckParam *param = reinterpret_cast<DoLeakCheckParam *>(arg);
CHECK(param);
CHECK(!param->success);
- CHECK(param->leak_report.IsEmpty());
ClassifyAllChunks(suspended_threads);
ForEachChunk(CollectLeaksCb, &param->leak_report);
- if (!param->leak_report.IsEmpty() && flags()->report_objects)
- PrintLeaked();
param->success = true;
}
@@ -378,7 +418,7 @@ void DoLeakCheck() {
if (already_done) return;
already_done = true;
if (&__lsan_is_turned_off && __lsan_is_turned_off())
- return;
+ return;
DoLeakCheckParam param;
param.success = false;
@@ -392,8 +432,9 @@ void DoLeakCheck() {
Report("LeakSanitizer has encountered a fatal error.\n");
Die();
}
- uptr have_unsuppressed = param.leak_report.ApplySuppressions();
- if (have_unsuppressed) {
+ param.leak_report.ApplySuppressions();
+ uptr unsuppressed_count = param.leak_report.UnsuppressedLeakCount();
+ if (unsuppressed_count > 0) {
Decorator d;
Printf("\n"
"================================================================="
@@ -401,38 +442,49 @@ void DoLeakCheck() {
Printf("%s", d.Error());
Report("ERROR: LeakSanitizer: detected memory leaks\n");
Printf("%s", d.End());
- param.leak_report.PrintLargest(flags()->max_leaks);
+ param.leak_report.ReportTopLeaks(flags()->max_leaks);
}
- if (have_unsuppressed || (flags()->verbosity >= 1)) {
+ if (common_flags()->print_suppressions)
PrintMatchedSuppressions();
+ if (unsuppressed_count > 0) {
param.leak_report.PrintSummary();
+ if (flags()->exitcode) {
+ if (common_flags()->coverage)
+ __sanitizer_cov_dump();
+ internal__exit(flags()->exitcode);
+ }
}
- if (have_unsuppressed && flags()->exitcode)
- internal__exit(flags()->exitcode);
}
static Suppression *GetSuppressionForAddr(uptr addr) {
- static const uptr kMaxAddrFrames = 16;
- InternalScopedBuffer<AddressInfo> addr_frames(kMaxAddrFrames);
- for (uptr i = 0; i < kMaxAddrFrames; i++) new (&addr_frames[i]) AddressInfo();
- uptr addr_frames_num = Symbolizer::Get()->SymbolizeCode(
- addr, addr_frames.data(), kMaxAddrFrames);
- for (uptr i = 0; i < addr_frames_num; i++) {
- Suppression* s;
- if (suppression_ctx->Match(addr_frames[i].function, SuppressionLeak, &s) ||
- suppression_ctx->Match(addr_frames[i].file, SuppressionLeak, &s) ||
- suppression_ctx->Match(addr_frames[i].module, SuppressionLeak, &s))
- return s;
+ Suppression *s = nullptr;
+
+ // Suppress by module name.
+ const char *module_name;
+ uptr module_offset;
+ if (Symbolizer::GetOrInit()->GetModuleNameAndOffsetForPC(addr, &module_name,
+ &module_offset) &&
+ SuppressionContext::Get()->Match(module_name, SuppressionLeak, &s))
+ return s;
+
+ // Suppress by file or function name.
+ SymbolizedStack *frames = Symbolizer::GetOrInit()->SymbolizePC(addr);
+ for (SymbolizedStack *cur = frames; cur; cur = cur->next) {
+ if (SuppressionContext::Get()->Match(cur->info.function, SuppressionLeak,
+ &s) ||
+ SuppressionContext::Get()->Match(cur->info.file, SuppressionLeak, &s)) {
+ break;
+ }
}
- return 0;
+ frames->ClearAll();
+ return s;
}
static Suppression *GetSuppressionForStack(u32 stack_trace_id) {
- uptr size = 0;
- const uptr *trace = StackDepotGet(stack_trace_id, &size);
- for (uptr i = 0; i < size; i++) {
- Suppression *s =
- GetSuppressionForAddr(StackTrace::GetPreviousInstructionPc(trace[i]));
+ StackTrace stack = StackDepotGet(stack_trace_id);
+ for (uptr i = 0; i < stack.size; i++) {
+ Suppression *s = GetSuppressionForAddr(
+ StackTrace::GetPreviousInstructionPc(stack.trace[i]));
if (s) return s;
}
return 0;
@@ -441,26 +493,35 @@ static Suppression *GetSuppressionForStack(u32 stack_trace_id) {
///// LeakReport implementation. /////
// A hard limit on the number of distinct leaks, to avoid quadratic complexity
-// in LeakReport::Add(). We don't expect to ever see this many leaks in
-// real-world applications.
+// in LeakReport::AddLeakedChunk(). We don't expect to ever see this many leaks
+// in real-world applications.
// FIXME: Get rid of this limit by changing the implementation of LeakReport to
// use a hash table.
const uptr kMaxLeaksConsidered = 5000;
-void LeakReport::Add(u32 stack_trace_id, uptr leaked_size, ChunkTag tag) {
+void LeakReport::AddLeakedChunk(uptr chunk, u32 stack_trace_id,
+ uptr leaked_size, ChunkTag tag) {
CHECK(tag == kDirectlyLeaked || tag == kIndirectlyLeaked);
bool is_directly_leaked = (tag == kDirectlyLeaked);
- for (uptr i = 0; i < leaks_.size(); i++)
+ uptr i;
+ for (i = 0; i < leaks_.size(); i++) {
if (leaks_[i].stack_trace_id == stack_trace_id &&
leaks_[i].is_directly_leaked == is_directly_leaked) {
leaks_[i].hit_count++;
leaks_[i].total_size += leaked_size;
- return;
+ break;
}
- if (leaks_.size() == kMaxLeaksConsidered) return;
- Leak leak = { /* hit_count */ 1, leaked_size, stack_trace_id,
- is_directly_leaked, /* is_suppressed */ false };
- leaks_.push_back(leak);
+ }
+ if (i == leaks_.size()) {
+ if (leaks_.size() == kMaxLeaksConsidered) return;
+ Leak leak = { next_id_++, /* hit_count */ 1, leaked_size, stack_trace_id,
+ is_directly_leaked, /* is_suppressed */ false };
+ leaks_.push_back(leak);
+ }
+ if (flags()->report_objects) {
+ LeakedObject obj = {leaks_[i].id, chunk, leaked_size};
+ leaked_objects_.push_back(obj);
+ }
}
static bool LeakComparator(const Leak &leak1, const Leak &leak2) {
@@ -470,7 +531,7 @@ static bool LeakComparator(const Leak &leak1, const Leak &leak2) {
return leak1.is_directly_leaked;
}
-void LeakReport::PrintLargest(uptr num_leaks_to_print) {
+void LeakReport::ReportTopLeaks(uptr num_leaks_to_report) {
CHECK(leaks_.size() <= kMaxLeaksConsidered);
Printf("\n");
if (leaks_.size() == kMaxLeaksConsidered)
@@ -478,31 +539,49 @@ void LeakReport::PrintLargest(uptr num_leaks_to_print) {
"reported.\n",
kMaxLeaksConsidered);
- uptr unsuppressed_count = 0;
- for (uptr i = 0; i < leaks_.size(); i++)
- if (!leaks_[i].is_suppressed) unsuppressed_count++;
- if (num_leaks_to_print > 0 && num_leaks_to_print < unsuppressed_count)
- Printf("The %zu largest leak(s):\n", num_leaks_to_print);
+ uptr unsuppressed_count = UnsuppressedLeakCount();
+ if (num_leaks_to_report > 0 && num_leaks_to_report < unsuppressed_count)
+ Printf("The %zu top leak(s):\n", num_leaks_to_report);
InternalSort(&leaks_, leaks_.size(), LeakComparator);
- uptr leaks_printed = 0;
- Decorator d;
+ uptr leaks_reported = 0;
for (uptr i = 0; i < leaks_.size(); i++) {
if (leaks_[i].is_suppressed) continue;
- Printf("%s", d.Leak());
- Printf("%s leak of %zu byte(s) in %zu object(s) allocated from:\n",
- leaks_[i].is_directly_leaked ? "Direct" : "Indirect",
- leaks_[i].total_size, leaks_[i].hit_count);
- Printf("%s", d.End());
- PrintStackTraceById(leaks_[i].stack_trace_id);
- leaks_printed++;
- if (leaks_printed == num_leaks_to_print) break;
+ PrintReportForLeak(i);
+ leaks_reported++;
+ if (leaks_reported == num_leaks_to_report) break;
}
- if (leaks_printed < unsuppressed_count) {
- uptr remaining = unsuppressed_count - leaks_printed;
+ if (leaks_reported < unsuppressed_count) {
+ uptr remaining = unsuppressed_count - leaks_reported;
Printf("Omitting %zu more leak(s).\n", remaining);
}
}
+void LeakReport::PrintReportForLeak(uptr index) {
+ Decorator d;
+ Printf("%s", d.Leak());
+ Printf("%s leak of %zu byte(s) in %zu object(s) allocated from:\n",
+ leaks_[index].is_directly_leaked ? "Direct" : "Indirect",
+ leaks_[index].total_size, leaks_[index].hit_count);
+ Printf("%s", d.End());
+
+ PrintStackTraceById(leaks_[index].stack_trace_id);
+
+ if (flags()->report_objects) {
+ Printf("Objects leaked above:\n");
+ PrintLeakedObjectsForLeak(index);
+ Printf("\n");
+ }
+}
+
+void LeakReport::PrintLeakedObjectsForLeak(uptr index) {
+ u32 leak_id = leaks_[index].id;
+ for (uptr j = 0; j < leaked_objects_.size(); j++) {
+ if (leaked_objects_[j].leak_id == leak_id)
+ Printf("%p (%zu bytes)\n", leaked_objects_[j].addr,
+ leaked_objects_[j].size);
+ }
+}
+
void LeakReport::PrintSummary() {
CHECK(leaks_.size() <= kMaxLeaksConsidered);
uptr bytes = 0, allocations = 0;
@@ -511,27 +590,30 @@ void LeakReport::PrintSummary() {
bytes += leaks_[i].total_size;
allocations += leaks_[i].hit_count;
}
- InternalScopedBuffer<char> summary(kMaxSummaryLength);
- internal_snprintf(summary.data(), summary.size(),
- "%zu byte(s) leaked in %zu allocation(s).", bytes,
- allocations);
+ InternalScopedString summary(kMaxSummaryLength);
+ summary.append("%zu byte(s) leaked in %zu allocation(s).", bytes,
+ allocations);
ReportErrorSummary(summary.data());
}
-uptr LeakReport::ApplySuppressions() {
- uptr unsuppressed_count = 0;
+void LeakReport::ApplySuppressions() {
for (uptr i = 0; i < leaks_.size(); i++) {
Suppression *s = GetSuppressionForStack(leaks_[i].stack_trace_id);
if (s) {
s->weight += leaks_[i].total_size;
s->hit_count += leaks_[i].hit_count;
leaks_[i].is_suppressed = true;
- } else {
- unsuppressed_count++;
}
}
- return unsuppressed_count;
}
+
+uptr LeakReport::UnsuppressedLeakCount() {
+ uptr result = 0;
+ for (uptr i = 0; i < leaks_.size(); i++)
+ if (!leaks_[i].is_suppressed) result++;
+ return result;
+}
+
} // namespace __lsan
#endif // CAN_SANITIZE_LEAKS
@@ -547,13 +629,51 @@ void __lsan_ignore_object(const void *p) {
// locked.
BlockingMutexLock l(&global_mutex);
IgnoreObjectResult res = IgnoreObjectLocked(p);
- if (res == kIgnoreObjectInvalid && flags()->verbosity >= 2)
- Report("__lsan_ignore_object(): no heap object found at %p", p);
- if (res == kIgnoreObjectAlreadyIgnored && flags()->verbosity >= 2)
- Report("__lsan_ignore_object(): "
+ if (res == kIgnoreObjectInvalid)
+ VReport(1, "__lsan_ignore_object(): no heap object found at %p", p);
+ if (res == kIgnoreObjectAlreadyIgnored)
+ VReport(1, "__lsan_ignore_object(): "
"heap object at %p is already being ignored\n", p);
- if (res == kIgnoreObjectSuccess && flags()->verbosity >= 3)
- Report("__lsan_ignore_object(): ignoring heap object at %p\n", p);
+ if (res == kIgnoreObjectSuccess)
+ VReport(1, "__lsan_ignore_object(): ignoring heap object at %p\n", p);
+#endif // CAN_SANITIZE_LEAKS
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __lsan_register_root_region(const void *begin, uptr size) {
+#if CAN_SANITIZE_LEAKS
+ BlockingMutexLock l(&global_mutex);
+ CHECK(root_regions);
+ 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
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __lsan_unregister_root_region(const void *begin, uptr size) {
+#if CAN_SANITIZE_LEAKS
+ BlockingMutexLock l(&global_mutex);
+ CHECK(root_regions);
+ bool removed = false;
+ for (uptr i = 0; i < root_regions->size(); i++) {
+ RootRegion region = (*root_regions)[i];
+ if (region.begin == begin && region.size == size) {
+ removed = true;
+ uptr last_index = root_regions->size() - 1;
+ (*root_regions)[i] = (*root_regions)[last_index];
+ root_regions->pop_back();
+ VReport(1, "Unregistered root region at %p of size %llu\n", begin, size);
+ break;
+ }
+ }
+ if (!removed) {
+ Report(
+ "__lsan_unregister_root_region(): region at %p of size %llu has not "
+ "been registered.\n",
+ begin, size);
+ Die();
+ }
#endif // CAN_SANITIZE_LEAKS
}
diff --git a/lib/lsan/lsan_common.h b/lib/lsan/lsan_common.h
index d490f8bafd9e..86ff12da6e0f 100644
--- a/lib/lsan/lsan_common.h
+++ b/lib/lsan/lsan_common.h
@@ -21,7 +21,7 @@
#include "sanitizer_common/sanitizer_platform.h"
#include "sanitizer_common/sanitizer_symbolizer.h"
-#if SANITIZER_LINUX && defined(__x86_64__)
+#if SANITIZER_LINUX && defined(__x86_64__) && (SANITIZER_WORDSIZE == 64)
#define CAN_SANITIZE_LEAKS 1
#else
#define CAN_SANITIZE_LEAKS 0
@@ -51,8 +51,6 @@ struct Flags {
int max_leaks;
// If nonzero kill the process with this exit code upon finding leaks.
int exitcode;
- // Suppressions file name.
- const char* suppressions;
// Flags controlling the root set of reachable memory.
// Global variables (.data and .bss).
@@ -63,12 +61,13 @@ struct Flags {
bool use_registers;
// TLS and thread-specific storage.
bool use_tls;
+ // Regions added via __lsan_register_root_region().
+ bool use_root_regions;
// Consider unaligned pointers valid.
bool use_unaligned;
-
- // User-visible verbosity.
- int verbosity;
+ // Consider pointers found in poisoned memory to be valid.
+ bool use_poisoned;
// Debug logging.
bool log_pointers;
@@ -79,6 +78,7 @@ extern Flags lsan_flags;
inline Flags *flags() { return &lsan_flags; }
struct Leak {
+ u32 id;
uptr hit_count;
uptr total_size;
u32 stack_trace_id;
@@ -86,17 +86,31 @@ struct Leak {
bool is_suppressed;
};
+struct LeakedObject {
+ u32 leak_id;
+ uptr addr;
+ uptr size;
+};
+
// Aggregates leaks by stack trace prefix.
class LeakReport {
public:
- LeakReport() : leaks_(1) {}
- void Add(u32 stack_trace_id, uptr leaked_size, ChunkTag tag);
- void PrintLargest(uptr max_leaks);
+ LeakReport() : next_id_(0), leaks_(1), leaked_objects_(1) {}
+ void AddLeakedChunk(uptr chunk, u32 stack_trace_id, uptr leaked_size,
+ ChunkTag tag);
+ void ReportTopLeaks(uptr max_leaks);
void PrintSummary();
- bool IsEmpty() { return leaks_.size() == 0; }
- uptr ApplySuppressions();
+ void ApplySuppressions();
+ uptr UnsuppressedLeakCount();
+
+
private:
+ void PrintReportForLeak(uptr index);
+ void PrintLeakedObjectsForLeak(uptr index);
+
+ u32 next_id_;
InternalMmapVector<Leak> leaks_;
+ InternalMmapVector<LeakedObject> leaked_objects_;
};
typedef InternalMmapVector<uptr> Frontier;
@@ -117,10 +131,19 @@ enum IgnoreObjectResult {
};
// Functions called from the parent tool.
-void InitCommonLsan();
+void InitCommonLsan(bool standalone);
void DoLeakCheck();
bool DisabledInThisThread();
+// Special case for "new T[0]" where T is a type with DTOR.
+// new T[0] will allocate one word for the array size (0) and store a pointer
+// to the end of allocated chunk.
+inline bool IsSpecialCaseOfOperatorNew0(uptr chunk_beg, uptr chunk_size,
+ uptr addr) {
+ return chunk_size == sizeof(uptr) && chunk_beg + chunk_size == addr &&
+ *reinterpret_cast<uptr *>(chunk_beg) == 0;
+}
+
// The following must be implemented in the parent tool.
void ForEachChunk(ForEachChunkCallback callback, void *arg);
@@ -129,6 +152,8 @@ void GetAllocatorGlobalRange(uptr *begin, uptr *end);
// Wrappers for allocator's ForceLock()/ForceUnlock().
void LockAllocator();
void UnlockAllocator();
+// Returns true if [addr, addr + sizeof(void *)) is poisoned.
+bool WordIsPoisoned(uptr addr);
// Wrappers for ThreadRegistry access.
void LockThreadRegistry();
void UnlockThreadRegistry();
diff --git a/lib/lsan/lsan_common_linux.cc b/lib/lsan/lsan_common_linux.cc
index ef8857fe8dbb..ba51868c76e8 100644
--- a/lib/lsan/lsan_common_linux.cc
+++ b/lib/lsan/lsan_common_linux.cc
@@ -19,6 +19,7 @@
#include <link.h>
#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_flags.h"
#include "sanitizer_common/sanitizer_linux.h"
#include "sanitizer_common/sanitizer_stackdepot.h"
@@ -43,11 +44,11 @@ void InitializePlatformSpecificModules() {
return;
}
if (num_matches == 0)
- Report("LeakSanitizer: Dynamic linker not found. "
- "TLS will not be handled correctly.\n");
+ VReport(1, "LeakSanitizer: Dynamic linker not found. "
+ "TLS will not be handled correctly.\n");
else if (num_matches > 1)
- Report("LeakSanitizer: Multiple modules match \"%s\". "
- "TLS will not be handled correctly.\n", kLinkerName);
+ VReport(1, "LeakSanitizer: Multiple modules match \"%s\". "
+ "TLS will not be handled correctly.\n", kLinkerName);
linker = 0;
}
@@ -83,6 +84,7 @@ static int ProcessGlobalRegionsCallback(struct dl_phdr_info *info, size_t size,
// Scans global variables for heap pointers.
void ProcessGlobalRegions(Frontier *frontier) {
+ if (!flags()->use_globals) return;
// FIXME: dl_iterate_phdr acquires a linker lock, so we run a risk of
// deadlocking by running this under StopTheWorld. However, the lock is
// reentrant, so we should be able to fix this by acquiring the lock before
@@ -92,11 +94,10 @@ void ProcessGlobalRegions(Frontier *frontier) {
static uptr GetCallerPC(u32 stack_id, StackDepotReverseMap *map) {
CHECK(stack_id);
- uptr size = 0;
- const uptr *trace = map->Get(stack_id, &size);
+ StackTrace stack = map->Get(stack_id);
// The top frame is our malloc/calloc/etc. The next frame is the caller.
- if (size >= 2)
- return trace[1];
+ if (stack.size >= 2)
+ return stack.trace[1];
return 0;
}
@@ -129,6 +130,21 @@ static void ProcessPlatformSpecificAllocationsCb(uptr chunk, void *arg) {
// Handles dynamically allocated TLS blocks by treating all chunks allocated
// from ld-linux.so as reachable.
+// Dynamic TLS blocks contain the TLS variables of dynamically loaded modules.
+// They are allocated with a __libc_memalign() call in allocate_and_init()
+// (elf/dl-tls.c). Glibc won't tell us the address ranges occupied by those
+// blocks, but we can make sure they come from our own allocator by intercepting
+// __libc_memalign(). On top of that, there is no easy way to reach them. Their
+// addresses are stored in a dynamically allocated array (the DTV) which is
+// referenced from the static TLS. Unfortunately, we can't just rely on the DTV
+// being reachable from the static TLS, and the dynamic TLS being reachable from
+// the DTV. This is because the initial DTV is allocated before our interception
+// mechanism kicks in, and thus we don't recognize it as allocated memory. We
+// can't special-case it either, since we don't know its size.
+// Our solution is to include in the root set all allocations made from
+// ld-linux.so (which is where allocate_and_init() is implemented). This is
+// guaranteed to include all dynamic TLS blocks (and possibly other allocations
+// which we don't care about).
void ProcessPlatformSpecificAllocations(Frontier *frontier) {
if (!flags()->use_tls) return;
if (!linker) return;
diff --git a/lib/lsan/lsan_interceptors.cc b/lib/lsan/lsan_interceptors.cc
index 400230b885ff..ba2519dcb25d 100644
--- a/lib/lsan/lsan_interceptors.cc
+++ b/lib/lsan/lsan_interceptors.cc
@@ -34,21 +34,6 @@ int pthread_key_create(unsigned *key, void (*destructor)(void* v));
int pthread_setspecific(unsigned key, const void *v);
}
-#define GET_STACK_TRACE \
- StackTrace stack; \
- { \
- uptr stack_top = 0, stack_bottom = 0; \
- ThreadContext *t; \
- bool fast = common_flags()->fast_unwind_on_malloc; \
- if (fast && (t = CurrentThreadContext())) { \
- stack_top = t->stack_end(); \
- stack_bottom = t->stack_begin(); \
- } \
- stack.Unwind(__sanitizer::common_flags()->malloc_context_size, \
- StackTrace::GetCurrentPc(), \
- GET_CURRENT_FRAME(), stack_top, stack_bottom, fast); \
- }
-
#define ENSURE_LSAN_INITED do { \
CHECK(!lsan_init_is_running); \
if (!lsan_inited) \
@@ -65,7 +50,7 @@ namespace std {
INTERCEPTOR(void*, malloc, uptr size) {
ENSURE_LSAN_INITED;
- GET_STACK_TRACE;
+ GET_STACK_TRACE_MALLOC;
return Allocate(stack, size, 1, kAlwaysClearMemory);
}
@@ -88,26 +73,32 @@ INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) {
}
if (CallocShouldReturnNullDueToOverflow(size, nmemb)) return 0;
ENSURE_LSAN_INITED;
- GET_STACK_TRACE;
+ GET_STACK_TRACE_MALLOC;
size *= nmemb;
return Allocate(stack, size, 1, true);
}
INTERCEPTOR(void*, realloc, void *q, uptr size) {
ENSURE_LSAN_INITED;
- GET_STACK_TRACE;
+ GET_STACK_TRACE_MALLOC;
return Reallocate(stack, q, size, 1);
}
INTERCEPTOR(void*, memalign, uptr alignment, uptr size) {
ENSURE_LSAN_INITED;
- GET_STACK_TRACE;
+ GET_STACK_TRACE_MALLOC;
+ return Allocate(stack, size, alignment, kAlwaysClearMemory);
+}
+
+INTERCEPTOR(void*, aligned_alloc, uptr alignment, uptr size) {
+ ENSURE_LSAN_INITED;
+ GET_STACK_TRACE_MALLOC;
return Allocate(stack, size, alignment, kAlwaysClearMemory);
}
INTERCEPTOR(int, posix_memalign, void **memptr, uptr alignment, uptr size) {
ENSURE_LSAN_INITED;
- GET_STACK_TRACE;
+ GET_STACK_TRACE_MALLOC;
*memptr = Allocate(stack, size, alignment, kAlwaysClearMemory);
// FIXME: Return ENOMEM if user requested more than max alloc size.
return 0;
@@ -115,7 +106,7 @@ INTERCEPTOR(int, posix_memalign, void **memptr, uptr alignment, uptr size) {
INTERCEPTOR(void*, valloc, uptr size) {
ENSURE_LSAN_INITED;
- GET_STACK_TRACE;
+ GET_STACK_TRACE_MALLOC;
if (size == 0)
size = GetPageSizeCached();
return Allocate(stack, size, GetPageSizeCached(), kAlwaysClearMemory);
@@ -142,7 +133,7 @@ INTERCEPTOR(int, mallopt, int cmd, int value) {
INTERCEPTOR(void*, pvalloc, uptr size) {
ENSURE_LSAN_INITED;
- GET_STACK_TRACE;
+ GET_STACK_TRACE_MALLOC;
uptr PageSize = GetPageSizeCached();
size = RoundUpTo(size, PageSize);
if (size == 0) {
@@ -152,11 +143,11 @@ INTERCEPTOR(void*, pvalloc, uptr size) {
return Allocate(stack, size, GetPageSizeCached(), kAlwaysClearMemory);
}
-INTERCEPTOR(void, cfree, void *p) ALIAS("free");
+INTERCEPTOR(void, cfree, void *p) ALIAS(WRAPPER_NAME(free));
#define OPERATOR_NEW_BODY \
ENSURE_LSAN_INITED; \
- GET_STACK_TRACE; \
+ GET_STACK_TRACE_MALLOC; \
return Allocate(stack, size, 1, kAlwaysClearMemory);
INTERCEPTOR_ATTRIBUTE
@@ -173,9 +164,9 @@ void *operator new[](uptr size, std::nothrow_t const&) { OPERATOR_NEW_BODY; }
Deallocate(ptr);
INTERCEPTOR_ATTRIBUTE
-void operator delete(void *ptr) { OPERATOR_DELETE_BODY; }
+void operator delete(void *ptr) throw() { OPERATOR_DELETE_BODY; }
INTERCEPTOR_ATTRIBUTE
-void operator delete[](void *ptr) { OPERATOR_DELETE_BODY; }
+void operator delete[](void *ptr) throw() { OPERATOR_DELETE_BODY; }
INTERCEPTOR_ATTRIBUTE
void operator delete(void *ptr, std::nothrow_t const&) { OPERATOR_DELETE_BODY; }
INTERCEPTOR_ATTRIBUTE
@@ -185,7 +176,8 @@ void operator delete[](void *ptr, std::nothrow_t const &) {
// We need this to intercept the __libc_memalign calls that are used to
// allocate dynamic TLS space in ld-linux.so.
-INTERCEPTOR(void *, __libc_memalign, uptr align, uptr s) ALIAS("memalign");
+INTERCEPTOR(void *, __libc_memalign, uptr align, uptr s)
+ ALIAS(WRAPPER_NAME(memalign));
///// Thread initialization and finalization. /////
@@ -223,9 +215,9 @@ extern "C" void *__lsan_thread_start_func(void *arg) {
int tid = 0;
while ((tid = atomic_load(&p->tid, memory_order_acquire)) == 0)
internal_sched_yield();
- atomic_store(&p->tid, 0, memory_order_release);
SetCurrentThread(tid);
ThreadStart(tid, GetTid());
+ atomic_store(&p->tid, 0, memory_order_release);
return callback(param);
}
@@ -238,7 +230,7 @@ INTERCEPTOR(int, pthread_create, void *th, void *attr,
pthread_attr_init(&myattr);
attr = &myattr;
}
- AdjustStackSizeLinux(attr);
+ AdjustStackSize(attr);
int detached = 0;
pthread_attr_getdetachstate(attr, &detached);
ThreadParam p;
diff --git a/lib/lsan/lsan_preinit.cc b/lib/lsan/lsan_preinit.cc
index e6639516dc81..5a190959c15d 100644
--- a/lib/lsan/lsan_preinit.cc
+++ b/lib/lsan/lsan_preinit.cc
@@ -14,11 +14,7 @@
#include "lsan.h"
-#ifndef LSAN_USE_PREINIT_ARRAY
-#define LSAN_USE_PREINIT_ARRAY 1
-#endif
-
-#if LSAN_USE_PREINIT_ARRAY && !defined(PIC)
+#if SANITIZER_CAN_USE_PREINIT_ARRAY
// We force __lsan_init to be called before anyone else by placing it into
// .preinit_array section.
__attribute__((section(".preinit_array"), used))
diff --git a/lib/lsan/tests/CMakeLists.txt b/lib/lsan/tests/CMakeLists.txt
deleted file mode 100644
index 2221e0650237..000000000000
--- a/lib/lsan/tests/CMakeLists.txt
+++ /dev/null
@@ -1,58 +0,0 @@
-include(CheckCXXCompilerFlag)
-include(CompilerRTCompile)
-include(CompilerRTLink)
-
-include_directories(..)
-include_directories(../..)
-
-set(LSAN_TESTS_SRC
- lsan_dummy_unittest.cc)
-
-set(LSAN_TESTS_CFLAGS
- ${SANITIZER_COMMON_CFLAGS}
- ${COMPILER_RT_GTEST_INCLUDE_CFLAGS}
- -I${COMPILER_RT_SOURCE_DIR}/lib
- -I${LSAN_SRC_DIR})
-
-set(LSAN_TEST_LINK_FLAGS_COMMON
- -lstdc++ -ldl -lpthread -lm)
-
-add_custom_target(LsanUnitTests)
-set_target_properties(LsanUnitTests PROPERTIES
- FOLDER "LSan unit tests")
-
-# Compile source for the given architecture, using compiler
-# options in ${ARGN}, and add it to the object list.
-macro(lsan_compile obj_list source arch)
- get_filename_component(basename ${source} NAME)
- set(output_obj "${basename}.${arch}.o")
- get_target_flags_for_arch(${arch} TARGET_CFLAGS)
- clang_compile(${output_obj} ${source}
- CFLAGS ${ARGN} ${TARGET_CFLAGS}
- DEPS gtest ${LSAN_RUNTIME_LIBRARIES})
- list(APPEND ${obj_list} ${output_obj})
-endmacro()
-
-function(add_lsan_test test_suite test_name arch)
- get_target_flags_for_arch(${arch} TARGET_LINK_FLAGS)
- add_compiler_rt_test(${test_suite} ${test_name}
- OBJECTS ${ARGN}
- DEPS ${LSAN_RUNTIME_LIBRARIES} ${ARGN}
- LINK_FLAGS ${LSAN_TEST_LINK_FLAGS_COMMON}
- ${TARGET_LINK_FLAGS})
-endfunction()
-
-macro(add_lsan_tests_for_arch arch)
- set(LSAN_TESTS_OBJ)
- set(LSAN_TEST_SOURCES ${LSAN_TESTS_SRC}
- ${COMPILER_RT_GTEST_SOURCE})
- foreach(source ${LSAN_TEST_SOURCES})
- lsan_compile(LSAN_TESTS_OBJ ${source} ${arch} ${LSAN_TESTS_CFLAGS})
- endforeach()
- add_lsan_test(LsanUnitTests Lsan-${arch}-Test ${arch} ${LSAN_TESTS_OBJ})
-endmacro()
-
-# Build tests for 64-bit Linux only.
-if(UNIX AND NOT APPLE AND CAN_TARGET_x86_64)
- add_lsan_tests_for_arch(x86_64)
-endif()
diff --git a/lib/lsan/tests/lsan_dummy_unittest.cc b/lib/lsan/tests/lsan_dummy_unittest.cc
deleted file mode 100644
index 5468400775a0..000000000000
--- a/lib/lsan/tests/lsan_dummy_unittest.cc
+++ /dev/null
@@ -1,22 +0,0 @@
-//===-- lsan_dummy_unittest.cc --------------------------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file is a part of LeakSanitizer runtime.
-//
-//===----------------------------------------------------------------------===//
-#include "gtest/gtest.h"
-
-TEST(LeakSanitizer, EmptyTest) {
- // Empty test to suppress LIT warnings about lack of tests.
-}
-
-int main(int argc, char **argv) {
- ::testing::InitGoogleTest(&argc, argv);
- return RUN_ALL_TESTS();
-}
diff --git a/lib/lsan/tests/lsan_testlib.cc b/lib/lsan/tests/lsan_testlib.cc
deleted file mode 100644
index 8db6cf1e2f8c..000000000000
--- a/lib/lsan/tests/lsan_testlib.cc
+++ /dev/null
@@ -1,25 +0,0 @@
-//===-- lsan_testlib.cc ---------------------------------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file is a part of LeakSanitizer.
-// Standalone LSan tool as a shared library, to be used with LD_PRELOAD.
-//
-//===----------------------------------------------------------------------===//
-/* Usage:
-clang++ ../sanitizer_common/sanitizer_*.cc ../interception/interception_*.cc \
- lsan*.cc tests/lsan_testlib.cc -I. -I.. -g -ldl -lpthread -fPIC -shared -O2 \
- -DLSAN_USE_PREINIT_ARRAY=0 -o lsan.so
-LD_PRELOAD=./lsan.so /your/app
-*/
-#include "lsan.h"
-
-__attribute__((constructor))
-void constructor() {
- __lsan_init();
-}
diff --git a/lib/lshrti3.c b/lib/lshrti3.c
deleted file mode 100644
index be768143b581..000000000000
--- a/lib/lshrti3.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/* ===-- lshrti3.c - Implement __lshrti3 -----------------------------------===
- *
- * 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 __lshrti3 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-#if __x86_64
-
-/* Returns: logical a >> b */
-
-/* Precondition: 0 <= b < bits_in_tword */
-
-ti_int
-__lshrti3(ti_int a, si_int b)
-{
- const int bits_in_dword = (int)(sizeof(di_int) * CHAR_BIT);
- utwords input;
- utwords result;
- input.all = a;
- if (b & bits_in_dword) /* bits_in_dword <= b < bits_in_tword */
- {
- result.s.high = 0;
- result.s.low = input.s.high >> (b - bits_in_dword);
- }
- else /* 0 <= b < bits_in_dword */
- {
- if (b == 0)
- return a;
- result.s.high = input.s.high >> b;
- result.s.low = (input.s.high << (bits_in_dword - b)) | (input.s.low >> b);
- }
- return result.all;
-}
-
-#endif /* __x86_64 */
diff --git a/lib/moddi3.c b/lib/moddi3.c
deleted file mode 100644
index 2f3b9cc4f291..000000000000
--- a/lib/moddi3.c
+++ /dev/null
@@ -1,32 +0,0 @@
-/*===-- moddi3.c - Implement __moddi3 -------------------------------------===
- *
- * 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 __moddi3 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-COMPILER_RT_ABI du_int __udivmoddi4(du_int a, du_int b, du_int* rem);
-
-/* Returns: a % b */
-
-COMPILER_RT_ABI di_int
-__moddi3(di_int a, di_int b)
-{
- const int bits_in_dword_m1 = (int)(sizeof(di_int) * CHAR_BIT) - 1;
- di_int s = b >> bits_in_dword_m1; /* s = b < 0 ? -1 : 0 */
- b = (b ^ s) - s; /* negate if s == -1 */
- s = a >> bits_in_dword_m1; /* s = a < 0 ? -1 : 0 */
- a = (a ^ s) - s; /* negate if s == -1 */
- di_int r;
- __udivmoddi4(a, b, (du_int*)&r);
- return (r ^ s) - s; /* negate if s == -1 */
-}
diff --git a/lib/modsi3.c b/lib/modsi3.c
deleted file mode 100644
index d16213c49038..000000000000
--- a/lib/modsi3.c
+++ /dev/null
@@ -1,25 +0,0 @@
-/* ===-- modsi3.c - Implement __modsi3 -------------------------------------===
- *
- * 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 __modsi3 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-su_int COMPILER_RT_ABI __divsi3(si_int a, si_int b);
-
-/* Returns: a % b */
-
-COMPILER_RT_ABI si_int
-__modsi3(si_int a, si_int b)
-{
- return a - __divsi3(a, b) * b;
-}
diff --git a/lib/modti3.c b/lib/modti3.c
deleted file mode 100644
index 752202d45e01..000000000000
--- a/lib/modti3.c
+++ /dev/null
@@ -1,36 +0,0 @@
-/* ===-- modti3.c - Implement __modti3 -------------------------------------===
- *
- * 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 __modti3 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-#if __x86_64
-
-tu_int __udivmodti4(tu_int a, tu_int b, tu_int* rem);
-
-/*Returns: a % b */
-
-ti_int
-__modti3(ti_int a, ti_int b)
-{
- const int bits_in_tword_m1 = (int)(sizeof(ti_int) * CHAR_BIT) - 1;
- ti_int s = b >> bits_in_tword_m1; /* s = b < 0 ? -1 : 0 */
- b = (b ^ s) - s; /* negate if s == -1 */
- s = a >> bits_in_tword_m1; /* s = a < 0 ? -1 : 0 */
- a = (a ^ s) - s; /* negate if s == -1 */
- ti_int r;
- __udivmodti4(a, b, (tu_int*)&r);
- return (r ^ s) - s; /* negate if s == -1 */
-}
-
-#endif
diff --git a/lib/msan/CMakeLists.txt b/lib/msan/CMakeLists.txt
index 06f3f65d8e38..90d9face1731 100644
--- a/lib/msan/CMakeLists.txt
+++ b/lib/msan/CMakeLists.txt
@@ -4,47 +4,43 @@ include_directories(..)
set(MSAN_RTL_SOURCES
msan.cc
msan_allocator.cc
+ msan_chained_origin_depot.cc
msan_interceptors.cc
msan_linux.cc
msan_new_delete.cc
msan_report.cc
+ msan_thread.cc
)
-set(MSAN_RTL_CFLAGS
- ${SANITIZER_COMMON_CFLAGS}
- -fno-rtti
- -fPIE
- # Prevent clang from generating libc calls.
- -ffreestanding)
-# Static runtime library.
+set(MSAN_RTL_CFLAGS ${SANITIZER_COMMON_CFLAGS})
+append_no_rtti_flag(MSAN_RTL_CFLAGS)
+append_list_if(COMPILER_RT_HAS_FPIE_FLAG -fPIE MSAN_RTL_CFLAGS)
+# Prevent clang from generating libc calls.
+append_list_if(COMPILER_RT_HAS_FFREESTANDING_FLAG -ffreestanding MSAN_RTL_CFLAGS)
+
set(MSAN_RUNTIME_LIBRARIES)
-set(arch "x86_64")
-if(CAN_TARGET_${arch})
- add_compiler_rt_static_runtime(clang_rt.msan-${arch} ${arch}
+
+# Static runtime library.
+add_custom_target(msan)
+foreach(arch ${MSAN_SUPPORTED_ARCH})
+ add_compiler_rt_runtime(clang_rt.msan-${arch} ${arch} STATIC
SOURCES ${MSAN_RTL_SOURCES}
$<TARGET_OBJECTS:RTInterception.${arch}>
$<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
$<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>
CFLAGS ${MSAN_RTL_CFLAGS})
+ add_dependencies(msan clang_rt.msan-${arch})
list(APPEND MSAN_RUNTIME_LIBRARIES clang_rt.msan-${arch})
if(UNIX)
add_sanitizer_rt_symbols(clang_rt.msan-${arch} msan.syms.extra)
- list(APPEND MSAN_RUNTIME_LIBRARIES clang_rt.msan-${arch}-symbols)
+ add_dependencies(msan clang_rt.msan-${arch}-symbols)
endif()
-endif()
+endforeach()
add_compiler_rt_resource_file(msan_blacklist msan_blacklist.txt)
+add_dependencies(msan msan_blacklist)
+add_dependencies(compiler-rt msan)
-# We should only build MSan unit tests if we can build instrumented libcxx.
-set(MSAN_LIBCXX_PATH ${LLVM_MAIN_SRC_DIR}/projects/libcxx)
-if(EXISTS ${MSAN_LIBCXX_PATH}/)
- set(MSAN_CAN_INSTRUMENT_LIBCXX TRUE)
-else()
- set(MSAN_CAN_INSTRUMENT_LIBCXX FALSE)
-endif()
-
-if(LLVM_INCLUDE_TESTS)
+if(COMPILER_RT_INCLUDE_TESTS)
add_subdirectory(tests)
endif()
-
-add_subdirectory(lit_tests)
diff --git a/lib/msan/lit_tests/CMakeLists.txt b/lib/msan/lit_tests/CMakeLists.txt
deleted file mode 100644
index 38d1e59e709e..000000000000
--- a/lib/msan/lit_tests/CMakeLists.txt
+++ /dev/null
@@ -1,31 +0,0 @@
-set(MSAN_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/..)
-set(MSAN_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/..)
-
-configure_lit_site_cfg(
- ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
- ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg)
-
-if(MSAN_CAN_INSTRUMENT_LIBCXX)
- configure_lit_site_cfg(
- ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.in
- ${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg)
-endif()
-
-if(COMPILER_RT_CAN_EXECUTE_TESTS AND CAN_TARGET_x86_64)
- # Run MSan tests only if we're sure we may produce working binaries.
- set(MSAN_TEST_DEPS
- ${SANITIZER_COMMON_LIT_TEST_DEPS}
- ${MSAN_RUNTIME_LIBRARIES}
- msan_blacklist)
- set(MSAN_TEST_PARAMS
- msan_site_config=${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg)
- if(LLVM_INCLUDE_TESTS AND MSAN_CAN_INSTRUMENT_LIBCXX)
- list(APPEND MSAN_TEST_DEPS MsanUnitTests)
- endif()
- add_lit_testsuite(check-msan "Running the MemorySanitizer tests"
- ${CMAKE_CURRENT_BINARY_DIR}
- PARAMS ${MSAN_TEST_PARAMS}
- DEPENDS ${MSAN_TEST_DEPS}
- )
- set_target_properties(check-msan PROPERTIES FOLDER "MSan tests")
-endif()
diff --git a/lib/msan/lit_tests/Linux/glob.cc b/lib/msan/lit_tests/Linux/glob.cc
deleted file mode 100644
index 387ce3cf5f1a..000000000000
--- a/lib/msan/lit_tests/Linux/glob.cc
+++ /dev/null
@@ -1,27 +0,0 @@
-// RUN: %clangxx_msan -m64 -O0 %s -o %t && %t %p 2>&1 | FileCheck %s
-// RUN: %clangxx_msan -m64 -O0 -D_FILE_OFFSET_BITS=64 %s -o %t && %t %p 2>&1 | FileCheck %s
-// RUN: %clangxx_msan -m64 -O3 %s -o %t && %t %p 2>&1 | FileCheck %s
-
-#include <assert.h>
-#include <glob.h>
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-
-int main(int argc, char *argv[]) {
- assert(argc == 2);
- char buf[1024];
- snprintf(buf, sizeof(buf), "%s/%s", argv[1], "glob_test_root/*a");
-
- glob_t globbuf;
- int res = glob(buf, 0, 0, &globbuf);
-
- printf("%d %s\n", errno, strerror(errno));
- assert(res == 0);
- assert(globbuf.gl_pathc == 2);
- printf("%zu\n", strlen(globbuf.gl_pathv[0]));
- printf("%zu\n", strlen(globbuf.gl_pathv[1]));
- printf("PASS\n");
- // CHECK: PASS
- return 0;
-}
diff --git a/lib/msan/lit_tests/Linux/glob_altdirfunc.cc b/lib/msan/lit_tests/Linux/glob_altdirfunc.cc
deleted file mode 100644
index b8200c3ee899..000000000000
--- a/lib/msan/lit_tests/Linux/glob_altdirfunc.cc
+++ /dev/null
@@ -1,78 +0,0 @@
-// RUN: %clangxx_msan -m64 -O0 %s -o %t && %t %p 2>&1 | FileCheck %s
-// RUN: %clangxx_msan -m64 -O0 -D_FILE_OFFSET_BITS=64 %s -o %t && %t %p 2>&1 | FileCheck %s
-// RUN: %clangxx_msan -m64 -O3 %s -o %t && %t %p 2>&1 | FileCheck %s
-
-#include <assert.h>
-#include <glob.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <dirent.h>
-#include <unistd.h>
-
-#include <sanitizer/msan_interface.h>
-
-static void my_gl_closedir(void *dir) {
- if (!dir)
- exit(1);
- closedir((DIR *)dir);
-}
-
-static struct dirent *my_gl_readdir(void *dir) {
- if (!dir)
- exit(1);
- struct dirent *d = readdir((DIR *)dir);
- if (d) __msan_poison(d, d->d_reclen); // hehe
- return d;
-}
-
-static void *my_gl_opendir(const char *s) {
- assert(__msan_test_shadow(s, strlen(s) + 1) == (size_t)-1);
- return opendir(s);
-}
-
-static int my_gl_lstat(const char *s, struct stat *st) {
- assert(__msan_test_shadow(s, strlen(s) + 1) == (size_t)-1);
- if (!st)
- exit(1);
- return lstat(s, st);
-}
-
-static int my_gl_stat(const char *s, struct stat *st) {
- assert(__msan_test_shadow(s, strlen(s) + 1) == (size_t)-1);
- if (!st)
- exit(1);
- return lstat(s, st);
-}
-
-int main(int argc, char *argv[]) {
- assert(argc == 2);
- char buf[1024];
- snprintf(buf, sizeof(buf), "%s/%s", argv[1], "glob_test_root/*a");
-
- glob_t globbuf;
- globbuf.gl_closedir = my_gl_closedir;
- globbuf.gl_readdir = my_gl_readdir;
- globbuf.gl_opendir = my_gl_opendir;
- globbuf.gl_lstat = my_gl_lstat;
- globbuf.gl_stat = my_gl_stat;
- for (int i = 0; i < 10000; ++i) {
- int res = glob(buf, GLOB_ALTDIRFUNC | GLOB_MARK, 0, &globbuf);
- assert(res == 0);
- printf("%d %s\n", errno, strerror(errno));
- assert(globbuf.gl_pathc == 2);
- printf("%zu\n", strlen(globbuf.gl_pathv[0]));
- printf("%zu\n", strlen(globbuf.gl_pathv[1]));
- __msan_poison(globbuf.gl_pathv[0], strlen(globbuf.gl_pathv[0]) + 1);
- __msan_poison(globbuf.gl_pathv[1], strlen(globbuf.gl_pathv[1]) + 1);
- globfree(&globbuf);
- }
-
- printf("PASS\n");
- // CHECK: PASS
- return 0;
-}
diff --git a/lib/msan/lit_tests/Linux/glob_nomatch.cc b/lib/msan/lit_tests/Linux/glob_nomatch.cc
deleted file mode 100644
index 0262034aec5b..000000000000
--- a/lib/msan/lit_tests/Linux/glob_nomatch.cc
+++ /dev/null
@@ -1,21 +0,0 @@
-// RUN: %clangxx_msan -m64 -O0 %s -o %t && %t %p
-// RUN: %clangxx_msan -m64 -O3 %s -o %t && %t %p
-
-#include <assert.h>
-#include <glob.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-int main(int argc, char *argv[]) {
- assert(argc == 2);
- char buf[1024];
- snprintf(buf, sizeof(buf), "%s/%s", argv[1], "glob_test_root/*c");
-
- glob_t globbuf;
- int res = glob(buf, 0, 0, &globbuf);
- assert(res == GLOB_NOMATCH);
- assert(globbuf.gl_pathc == 0);
- if (globbuf.gl_pathv == 0)
- exit(0);
- return 0;
-}
diff --git a/lib/msan/lit_tests/Linux/glob_test_root/aa b/lib/msan/lit_tests/Linux/glob_test_root/aa
deleted file mode 100644
index e69de29bb2d1..000000000000
--- a/lib/msan/lit_tests/Linux/glob_test_root/aa
+++ /dev/null
diff --git a/lib/msan/lit_tests/Linux/glob_test_root/ab b/lib/msan/lit_tests/Linux/glob_test_root/ab
deleted file mode 100644
index e69de29bb2d1..000000000000
--- a/lib/msan/lit_tests/Linux/glob_test_root/ab
+++ /dev/null
diff --git a/lib/msan/lit_tests/Linux/glob_test_root/ba b/lib/msan/lit_tests/Linux/glob_test_root/ba
deleted file mode 100644
index e69de29bb2d1..000000000000
--- a/lib/msan/lit_tests/Linux/glob_test_root/ba
+++ /dev/null
diff --git a/lib/msan/lit_tests/Linux/lit.local.cfg b/lib/msan/lit_tests/Linux/lit.local.cfg
deleted file mode 100644
index 57271b8078a4..000000000000
--- a/lib/msan/lit_tests/Linux/lit.local.cfg
+++ /dev/null
@@ -1,9 +0,0 @@
-def getRoot(config):
- if not config.parent:
- return config
- return getRoot(config.parent)
-
-root = getRoot(config)
-
-if root.host_os not in ['Linux']:
- config.unsupported = True
diff --git a/lib/msan/lit_tests/Linux/syscalls.cc b/lib/msan/lit_tests/Linux/syscalls.cc
deleted file mode 100644
index ec308bfe30ca..000000000000
--- a/lib/msan/lit_tests/Linux/syscalls.cc
+++ /dev/null
@@ -1,100 +0,0 @@
-// RUN: %clangxx_msan -m64 -O0 %s -o %t && %t 2>&1
-// RUN: %clangxx_msan -m64 -O3 %s -o %t && %t 2>&1
-
-#include <assert.h>
-#include <errno.h>
-#include <glob.h>
-#include <stdio.h>
-#include <string.h>
-
-#include <linux/aio_abi.h>
-#include <sys/ptrace.h>
-#include <sys/stat.h>
-
-#include <sanitizer/linux_syscall_hooks.h>
-#include <sanitizer/msan_interface.h>
-
-/* Test the presence of __sanitizer_syscall_ in the tool runtime, and general
- sanity of their behaviour. */
-
-int main(int argc, char *argv[]) {
- char buf[1000];
- const int kTen = 10;
- const int kFortyTwo = 42;
- memset(buf, 0, sizeof(buf));
- __msan_unpoison(buf, sizeof(buf));
- __sanitizer_syscall_pre_recvmsg(0, buf, 0);
- __sanitizer_syscall_pre_rt_sigpending(buf, kTen);
- __sanitizer_syscall_pre_getdents(0, buf, kTen);
- __sanitizer_syscall_pre_getdents64(0, buf, kTen);
-
- __msan_unpoison(buf, sizeof(buf));
- __sanitizer_syscall_post_recvmsg(0, 0, buf, 0);
- __sanitizer_syscall_post_rt_sigpending(-1, buf, kTen);
- __sanitizer_syscall_post_getdents(0, 0, buf, kTen);
- __sanitizer_syscall_post_getdents64(0, 0, buf, kTen);
- assert(__msan_test_shadow(buf, sizeof(buf)) == -1);
-
- __msan_unpoison(buf, sizeof(buf));
- __sanitizer_syscall_post_recvmsg(kTen, 0, buf, 0);
-
- // Tell the kernel that the output struct size is 10 bytes, verify that those
- // bytes are unpoisoned, and the next byte is not.
- __msan_poison(buf, kTen + 1);
- __sanitizer_syscall_post_rt_sigpending(0, buf, kTen);
- assert(__msan_test_shadow(buf, sizeof(buf)) == kTen);
-
- __msan_poison(buf, kTen + 1);
- __sanitizer_syscall_post_getdents(kTen, 0, buf, kTen);
- assert(__msan_test_shadow(buf, sizeof(buf)) == kTen);
-
- __msan_poison(buf, kTen + 1);
- __sanitizer_syscall_post_getdents64(kTen, 0, buf, kTen);
- assert(__msan_test_shadow(buf, sizeof(buf)) == kTen);
-
- __msan_poison(buf, sizeof(buf));
- __sanitizer_syscall_post_clock_getres(0, 0, buf);
- assert(__msan_test_shadow(buf, sizeof(buf)) == sizeof(long) * 2);
-
- __msan_poison(buf, sizeof(buf));
- __sanitizer_syscall_post_clock_gettime(0, 0, buf);
- assert(__msan_test_shadow(buf, sizeof(buf)) == sizeof(long) * 2);
-
- // Failed syscall does not write to the buffer.
- __msan_poison(buf, sizeof(buf));
- __sanitizer_syscall_post_clock_gettime(-1, 0, buf);
- assert(__msan_test_shadow(buf, sizeof(buf)) == 0);
-
- __msan_poison(buf, sizeof(buf));
- __sanitizer_syscall_post_read(5, 42, buf, 10);
- assert(__msan_test_shadow(buf, sizeof(buf)) == 5);
-
- __msan_poison(buf, sizeof(buf));
- __sanitizer_syscall_post_newfstatat(0, 5, "/path/to/file", buf, 0);
- assert(__msan_test_shadow(buf, sizeof(buf)) == sizeof(struct stat));
-
- __msan_poison(buf, sizeof(buf));
- int prio = 0;
- __sanitizer_syscall_post_mq_timedreceive(kFortyTwo, 5, buf, sizeof(buf), &prio, 0);
- assert(__msan_test_shadow(buf, sizeof(buf)) == kFortyTwo);
- assert(__msan_test_shadow(&prio, sizeof(prio)) == -1);
-
- __msan_poison(buf, sizeof(buf));
- __sanitizer_syscall_post_ptrace(0, PTRACE_PEEKUSER, kFortyTwo, 0xABCD, buf);
- assert(__msan_test_shadow(buf, sizeof(buf)) == sizeof(void *));
-
- __msan_poison(buf, sizeof(buf));
- struct iocb iocb[2];
- struct iocb *iocbp[2] = { &iocb[0], &iocb[1] };
- memset(iocb, 0, sizeof(iocb));
- iocb[0].aio_lio_opcode = IOCB_CMD_PREAD;
- iocb[0].aio_buf = (__u64)buf;
- iocb[0].aio_nbytes = kFortyTwo;
- iocb[1].aio_lio_opcode = IOCB_CMD_PREAD;
- iocb[1].aio_buf = (__u64)(&buf[kFortyTwo]);
- iocb[1].aio_nbytes = kFortyTwo;
- __sanitizer_syscall_post_io_submit(1, 0, 2, &iocbp);
- assert(__msan_test_shadow(buf, sizeof(buf)) == kFortyTwo);
-
- return 0;
-}
diff --git a/lib/msan/lit_tests/Linux/tcgetattr.cc b/lib/msan/lit_tests/Linux/tcgetattr.cc
deleted file mode 100644
index e6e101db884f..000000000000
--- a/lib/msan/lit_tests/Linux/tcgetattr.cc
+++ /dev/null
@@ -1,21 +0,0 @@
-// RUN: %clangxx_msan -m64 -O0 %s -o %t && %t %p
-
-#include <assert.h>
-#include <glob.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <termios.h>
-#include <unistd.h>
-
-int main(int argc, char *argv[]) {
- int fd = getpt();
- assert(fd >= 0);
-
- struct termios t;
- int res = tcgetattr(fd, &t);
- assert(!res);
-
- if (t.c_iflag == 0)
- exit(0);
- return 0;
-}
diff --git a/lib/msan/lit_tests/SharedLibs/dso-origin-so.cc b/lib/msan/lit_tests/SharedLibs/dso-origin-so.cc
deleted file mode 100644
index 8930a7159246..000000000000
--- a/lib/msan/lit_tests/SharedLibs/dso-origin-so.cc
+++ /dev/null
@@ -1,14 +0,0 @@
-#include <stdlib.h>
-
-#include "dso-origin.h"
-
-void my_access(int *p) {
- volatile int tmp;
- // Force initialize-ness check.
- if (*p)
- tmp = 1;
-}
-
-void *my_alloc(unsigned sz) {
- return malloc(sz);
-}
diff --git a/lib/msan/lit_tests/SharedLibs/dso-origin.h b/lib/msan/lit_tests/SharedLibs/dso-origin.h
deleted file mode 100644
index ff926b3f61c8..000000000000
--- a/lib/msan/lit_tests/SharedLibs/dso-origin.h
+++ /dev/null
@@ -1,4 +0,0 @@
-extern "C" {
-void my_access(int *p);
-void *my_alloc(unsigned sz);
-}
diff --git a/lib/msan/lit_tests/SharedLibs/lit.local.cfg b/lib/msan/lit_tests/SharedLibs/lit.local.cfg
deleted file mode 100644
index b3677c17a0f2..000000000000
--- a/lib/msan/lit_tests/SharedLibs/lit.local.cfg
+++ /dev/null
@@ -1,4 +0,0 @@
-# Sources in this directory are compiled as shared libraries and used by
-# tests in parent directory.
-
-config.suffixes = []
diff --git a/lib/msan/lit_tests/Unit/lit.site.cfg.in b/lib/msan/lit_tests/Unit/lit.site.cfg.in
deleted file mode 100644
index 8e67f557d7fd..000000000000
--- a/lib/msan/lit_tests/Unit/lit.site.cfg.in
+++ /dev/null
@@ -1,13 +0,0 @@
-## Autogenerated by LLVM/Clang configuration.
-# Do not edit!
-
-# Load common config for all compiler-rt unit tests.
-lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/lib/lit.common.unit.configured")
-
-# Setup config name.
-config.name = 'MemorySanitizer-Unit'
-
-# Setup test source and exec root. For unit tests, we define
-# it as build directory with MSan unit tests.
-config.test_exec_root = "@MSAN_BINARY_DIR@/tests"
-config.test_source_root = config.test_exec_root
diff --git a/lib/msan/lit_tests/allocator_returns_null.cc b/lib/msan/lit_tests/allocator_returns_null.cc
deleted file mode 100644
index aaa85cce7113..000000000000
--- a/lib/msan/lit_tests/allocator_returns_null.cc
+++ /dev/null
@@ -1,81 +0,0 @@
-// Test the behavior of malloc/calloc/realloc when the allocation size is huge.
-// By default (allocator_may_return_null=0) the process should crash.
-// With allocator_may_return_null=1 the allocator should return 0.
-//
-// RUN: %clangxx_msan -O0 %s -o %t
-// RUN: not %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mCRASH
-// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mCRASH
-// RUN: MSAN_OPTIONS=allocator_may_return_null=1 %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mNULL
-// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %t calloc 2>&1 | FileCheck %s --check-prefix=CHECK-cCRASH
-// RUN: MSAN_OPTIONS=allocator_may_return_null=1 %t calloc 2>&1 | FileCheck %s --check-prefix=CHECK-cNULL
-// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %t calloc-overflow 2>&1 | FileCheck %s --check-prefix=CHECK-coCRASH
-// RUN: MSAN_OPTIONS=allocator_may_return_null=1 %t calloc-overflow 2>&1 | FileCheck %s --check-prefix=CHECK-coNULL
-// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %t realloc 2>&1 | FileCheck %s --check-prefix=CHECK-rCRASH
-// RUN: MSAN_OPTIONS=allocator_may_return_null=1 %t realloc 2>&1 | FileCheck %s --check-prefix=CHECK-rNULL
-// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %t realloc-after-malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mrCRASH
-// RUN: MSAN_OPTIONS=allocator_may_return_null=1 %t realloc-after-malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mrNULL
-
-#include <limits.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#include <assert.h>
-#include <limits>
-int main(int argc, char **argv) {
- volatile size_t size = std::numeric_limits<size_t>::max() - 10000;
- assert(argc == 2);
- char *x = 0;
- if (!strcmp(argv[1], "malloc")) {
- fprintf(stderr, "malloc:\n");
- x = (char*)malloc(size);
- }
- if (!strcmp(argv[1], "calloc")) {
- fprintf(stderr, "calloc:\n");
- x = (char*)calloc(size / 4, 4);
- }
-
- if (!strcmp(argv[1], "calloc-overflow")) {
- fprintf(stderr, "calloc-overflow:\n");
- volatile size_t kMaxSizeT = std::numeric_limits<size_t>::max();
- size_t kArraySize = 4096;
- volatile size_t kArraySize2 = kMaxSizeT / kArraySize + 10;
- x = (char*)calloc(kArraySize, kArraySize2);
- }
-
- if (!strcmp(argv[1], "realloc")) {
- fprintf(stderr, "realloc:\n");
- x = (char*)realloc(0, size);
- }
- if (!strcmp(argv[1], "realloc-after-malloc")) {
- fprintf(stderr, "realloc-after-malloc:\n");
- char *t = (char*)malloc(100);
- *t = 42;
- x = (char*)realloc(t, size);
- assert(*t == 42);
- }
- // The NULL pointer is printed differently on different systems, while (long)0
- // is always the same.
- fprintf(stderr, "x: %lx\n", (long)x);
- return x != 0;
-}
-// CHECK-mCRASH: malloc:
-// CHECK-mCRASH: MemorySanitizer's allocator is terminating the process
-// CHECK-cCRASH: calloc:
-// CHECK-cCRASH: MemorySanitizer's allocator is terminating the process
-// CHECK-coCRASH: calloc-overflow:
-// CHECK-coCRASH: MemorySanitizer's allocator is terminating the process
-// CHECK-rCRASH: realloc:
-// CHECK-rCRASH: MemorySanitizer's allocator is terminating the process
-// CHECK-mrCRASH: realloc-after-malloc:
-// CHECK-mrCRASH: MemorySanitizer's allocator is terminating the process
-
-// CHECK-mNULL: malloc:
-// CHECK-mNULL: x: 0
-// CHECK-cNULL: calloc:
-// CHECK-cNULL: x: 0
-// CHECK-coNULL: calloc-overflow:
-// CHECK-coNULL: x: 0
-// CHECK-rNULL: realloc:
-// CHECK-rNULL: x: 0
-// CHECK-mrNULL: realloc-after-malloc:
-// CHECK-mrNULL: x: 0
diff --git a/lib/msan/lit_tests/backtrace.cc b/lib/msan/lit_tests/backtrace.cc
deleted file mode 100644
index 48684c29c60d..000000000000
--- a/lib/msan/lit_tests/backtrace.cc
+++ /dev/null
@@ -1,26 +0,0 @@
-// RUN: %clangxx_msan -m64 -O0 %s -o %t && %t
-
-#include <assert.h>
-#include <execinfo.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-
-__attribute__((noinline))
-void f() {
- void *buf[10];
- int sz = backtrace(buf, sizeof(buf) / sizeof(*buf));
- assert(sz > 0);
- for (int i = 0; i < sz; ++i)
- if (!buf[i])
- exit(1);
- char **s = backtrace_symbols(buf, sz);
- assert(s > 0);
- for (int i = 0; i < sz; ++i)
- printf("%d\n", strlen(s[i]));
-}
-
-int main(void) {
- f();
- return 0;
-}
diff --git a/lib/msan/lit_tests/c-strdup.c b/lib/msan/lit_tests/c-strdup.c
deleted file mode 100644
index 7772f0f307b7..000000000000
--- a/lib/msan/lit_tests/c-strdup.c
+++ /dev/null
@@ -1,17 +0,0 @@
-// RUN: %clang_msan -m64 -O0 %s -o %t && %t >%t.out 2>&1
-// RUN: %clang_msan -m64 -O1 %s -o %t && %t >%t.out 2>&1
-// RUN: %clang_msan -m64 -O2 %s -o %t && %t >%t.out 2>&1
-// RUN: %clang_msan -m64 -O3 %s -o %t && %t >%t.out 2>&1
-
-// Test that strdup in C programs is intercepted.
-// GLibC headers translate strdup to __strdup at -O1 and higher.
-
-#include <stdlib.h>
-#include <string.h>
-int main(int argc, char **argv) {
- char buf[] = "abc";
- char *p = strdup(buf);
- if (*p)
- exit(0);
- return 0;
-}
diff --git a/lib/msan/lit_tests/cxa_atexit.cc b/lib/msan/lit_tests/cxa_atexit.cc
deleted file mode 100644
index f3641aadce03..000000000000
--- a/lib/msan/lit_tests/cxa_atexit.cc
+++ /dev/null
@@ -1,28 +0,0 @@
-// RUN: %clangxx_msan -m64 -O0 %s -o %t && %t %p
-
-// PR17377: C++ module destructors get stale argument shadow.
-
-#include <stdio.h>
-#include <stdlib.h>
-class A {
-public:
- // This destructor get stale argument shadow left from the call to f().
- ~A() {
- if (this)
- exit(0);
- }
-};
-
-A a;
-
-__attribute__((noinline))
-void f(long x) {
-}
-
-int main(void) {
- long x;
- long * volatile p = &x;
- // This call poisons TLS shadow for the first function argument.
- f(*p);
- return 0;
-}
diff --git a/lib/msan/lit_tests/default_blacklist.cc b/lib/msan/lit_tests/default_blacklist.cc
deleted file mode 100644
index 32cc02257cb0..000000000000
--- a/lib/msan/lit_tests/default_blacklist.cc
+++ /dev/null
@@ -1,3 +0,0 @@
-// Test that MSan uses the default blacklist from resource directory.
-// RUN: %clangxx_msan -### %s 2>&1 | FileCheck %s
-// CHECK: fsanitize-blacklist={{.*}}msan_blacklist.txt
diff --git a/lib/msan/lit_tests/dlerror.cc b/lib/msan/lit_tests/dlerror.cc
deleted file mode 100644
index 281b3164fd7e..000000000000
--- a/lib/msan/lit_tests/dlerror.cc
+++ /dev/null
@@ -1,14 +0,0 @@
-// RUN: %clangxx_msan -m64 -O0 %s -o %t && %t
-
-#include <assert.h>
-#include <dlfcn.h>
-#include <stdio.h>
-#include <string.h>
-
-int main(void) {
- void *p = dlopen("/bad/file/name", RTLD_NOW);
- assert(!p);
- char *s = dlerror();
- printf("%s, %zu\n", s, strlen(s));
- return 0;
-}
diff --git a/lib/msan/lit_tests/dso-origin.cc b/lib/msan/lit_tests/dso-origin.cc
deleted file mode 100644
index 13661c65e744..000000000000
--- a/lib/msan/lit_tests/dso-origin.cc
+++ /dev/null
@@ -1,25 +0,0 @@
-// Build a library with origin tracking and an executable w/o origin tracking.
-// Test that origin tracking is enabled at runtime.
-// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O0 %p/SharedLibs/dso-origin-so.cc \
-// RUN: -fPIC -shared -o %t-so.so
-// RUN: %clangxx_msan -m64 -O0 %s %t-so.so -o %t && not %t 2>&1 | FileCheck %s
-
-#include <stdlib.h>
-
-#include "SharedLibs/dso-origin.h"
-
-int main(int argc, char **argv) {
- int *x = (int *)my_alloc(sizeof(int));
- my_access(x);
- delete x;
-
- // CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value
- // CHECK: {{#0 0x.* in my_access .*dso-origin-so.cc:}}
- // CHECK: {{#1 0x.* in main .*dso-origin.cc:}}[[@LINE-5]]
- // CHECK: Uninitialized value was created by a heap allocation
- // CHECK: {{#0 0x.* in .*malloc}}
- // CHECK: {{#1 0x.* in my_alloc .*dso-origin-so.cc:}}
- // CHECK: {{#2 0x.* in main .*dso-origin.cc:}}[[@LINE-10]]
- // CHECK: SUMMARY: MemorySanitizer: use-of-uninitialized-value {{.*dso-origin-so.cc:.* my_access}}
- return 0;
-}
diff --git a/lib/msan/lit_tests/errno.cc b/lib/msan/lit_tests/errno.cc
deleted file mode 100644
index af27ad0b0329..000000000000
--- a/lib/msan/lit_tests/errno.cc
+++ /dev/null
@@ -1,17 +0,0 @@
-// RUN: %clangxx_msan -m64 -O0 %s -o %t && %t
-
-#include <assert.h>
-#include <errno.h>
-#include <stdio.h>
-#include <unistd.h>
-
-int main()
-{
- int x;
- int *volatile p = &x;
- errno = *p;
- int res = read(-1, 0, 0);
- assert(res == -1);
- if (errno) printf("errno %d\n", errno);
- return 0;
-}
diff --git a/lib/msan/lit_tests/getaddrinfo-positive.cc b/lib/msan/lit_tests/getaddrinfo-positive.cc
deleted file mode 100644
index 7fde1fdfab93..000000000000
--- a/lib/msan/lit_tests/getaddrinfo-positive.cc
+++ /dev/null
@@ -1,23 +0,0 @@
-// RUN: %clangxx_msan -m64 -O0 %s -o %t && not %t >%t.out 2>&1
-// RUN: FileCheck %s < %t.out
-// RUN: %clangxx_msan -m64 -O3 %s -o %t && not %t >%t.out 2>&1
-// RUN: FileCheck %s < %t.out
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netdb.h>
-#include <stdlib.h>
-
-volatile int z;
-
-int main(void) {
- struct addrinfo *ai;
- struct addrinfo hint;
- int res = getaddrinfo("localhost", NULL, NULL, &ai);
- if (ai) z = 1; // OK
- res = getaddrinfo("localhost", NULL, &hint, &ai);
- // CHECK: UMR in __interceptor_getaddrinfo at offset 0 inside
- // CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value
- // CHECK: #0 {{.*}} in main {{.*}}getaddrinfo-positive.cc:[[@LINE-3]]
- return 0;
-}
diff --git a/lib/msan/lit_tests/getaddrinfo.cc b/lib/msan/lit_tests/getaddrinfo.cc
deleted file mode 100644
index 0518cf4733d0..000000000000
--- a/lib/msan/lit_tests/getaddrinfo.cc
+++ /dev/null
@@ -1,24 +0,0 @@
-// RUN: %clangxx_msan -m64 -O0 %s -o %t && %t
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netdb.h>
-#include <stdlib.h>
-
-void poison_stack_ahead() {
- char buf[100000];
- // With -O0 this poisons a large chunk of stack.
-}
-
-int main(void) {
- poison_stack_ahead();
-
- struct addrinfo *ai;
-
- // This should trigger loading of libnss_dns and friends.
- // Those libraries are typically uninstrumented.They will call strlen() on a
- // stack-allocated buffer, which is very likely to be poisoned. Test that we
- // don't report this as an UMR.
- int res = getaddrinfo("not-in-etc-hosts", NULL, NULL, &ai);
- return 0;
-}
diff --git a/lib/msan/lit_tests/getline.cc b/lib/msan/lit_tests/getline.cc
deleted file mode 100644
index 27168a885606..000000000000
--- a/lib/msan/lit_tests/getline.cc
+++ /dev/null
@@ -1,30 +0,0 @@
-// RUN: %clangxx_msan -O0 %s -o %t && %t %p
-
-#include <assert.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-int main(int argc, char **argv) {
- assert(argc == 2);
- char buf[1024];
- snprintf(buf, sizeof(buf), "%s/%s", argv[1], "getline_test_data");
-
- FILE *fp = fopen(buf, "r");
- assert(fp);
-
- char *line = 0;
- size_t len = 0;
- int n = getline(&line, &len, fp);
- assert(n == 6);
- assert(strcmp(line, "abcde\n") == 0);
-
- n = getline(&line, &len, fp);
- assert(n == 6);
- assert(strcmp(line, "12345\n") == 0);
-
- free(line);
- fclose(fp);
-
- return 0;
-}
diff --git a/lib/msan/lit_tests/getline_test_data b/lib/msan/lit_tests/getline_test_data
deleted file mode 100644
index 5ba1d4cec0dd..000000000000
--- a/lib/msan/lit_tests/getline_test_data
+++ /dev/null
@@ -1,2 +0,0 @@
-abcde
-12345
diff --git a/lib/msan/lit_tests/heap-origin.cc b/lib/msan/lit_tests/heap-origin.cc
deleted file mode 100644
index dfe7edd27e82..000000000000
--- a/lib/msan/lit_tests/heap-origin.cc
+++ /dev/null
@@ -1,31 +0,0 @@
-// RUN: %clangxx_msan -m64 -O0 %s -o %t && not %t >%t.out 2>&1
-// RUN: FileCheck %s < %t.out
-// RUN: %clangxx_msan -m64 -O1 %s -o %t && not %t >%t.out 2>&1
-// RUN: FileCheck %s < %t.out
-// RUN: %clangxx_msan -m64 -O2 %s -o %t && not %t >%t.out 2>&1
-// RUN: FileCheck %s < %t.out
-// RUN: %clangxx_msan -m64 -O3 %s -o %t && not %t >%t.out 2>&1
-// RUN: FileCheck %s < %t.out
-
-// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O0 %s -o %t && not %t >%t.out 2>&1
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out
-// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O1 %s -o %t && not %t >%t.out 2>&1
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out
-// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O2 %s -o %t && not %t >%t.out 2>&1
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out
-// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O3 %s -o %t && not %t >%t.out 2>&1
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out
-
-#include <stdlib.h>
-int main(int argc, char **argv) {
- char *volatile x = (char*)malloc(5 * sizeof(char));
- return *x;
- // CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value
- // CHECK: {{#0 0x.* in main .*heap-origin.cc:}}[[@LINE-2]]
-
- // CHECK-ORIGINS: Uninitialized value was created by a heap allocation
- // CHECK-ORIGINS: {{#0 0x.* in .*malloc}}
- // CHECK-ORIGINS: {{#1 0x.* in main .*heap-origin.cc:}}[[@LINE-7]]
-
- // CHECK: SUMMARY: MemorySanitizer: use-of-uninitialized-value {{.*heap-origin.cc:.* main}}
-}
diff --git a/lib/msan/lit_tests/initgroups.cc b/lib/msan/lit_tests/initgroups.cc
deleted file mode 100644
index adba5369579a..000000000000
--- a/lib/msan/lit_tests/initgroups.cc
+++ /dev/null
@@ -1,11 +0,0 @@
-// RUN: %clangxx_msan -m64 -O0 %s -o %t && %t
-
-#include <sys/types.h>
-#include <grp.h>
-
-int main(void) {
- initgroups("root", 0);
- // The above fails unless you are root. Does not matter, MSan false positive
- // (which we are testing for) happens anyway.
- return 0;
-}
diff --git a/lib/msan/lit_tests/inline.cc b/lib/msan/lit_tests/inline.cc
deleted file mode 100644
index 4aeb15583f84..000000000000
--- a/lib/msan/lit_tests/inline.cc
+++ /dev/null
@@ -1,20 +0,0 @@
-// RUN: %clangxx_msan -O3 %s -o %t && %t
-
-// Test that no_sanitize_memory attribute applies even when the function would
-// be normally inlined.
-
-#include <stdlib.h>
-
-__attribute__((no_sanitize_memory))
-int f(int *p) {
- if (*p) // BOOOM?? Nope!
- exit(0);
- return 0;
-}
-
-int main(int argc, char **argv) {
- int x;
- int * volatile p = &x;
- int res = f(p);
- return 0;
-}
diff --git a/lib/msan/lit_tests/insertvalue_origin.cc b/lib/msan/lit_tests/insertvalue_origin.cc
deleted file mode 100644
index 769ea45f8c4d..000000000000
--- a/lib/msan/lit_tests/insertvalue_origin.cc
+++ /dev/null
@@ -1,35 +0,0 @@
-// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O0 %s -o %t && not %t >%t.out 2>&1
-// RUN: FileCheck %s < %t.out && FileCheck %s < %t.out
-// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O3 %s -o %t && not %t >%t.out 2>&1
-// RUN: FileCheck %s < %t.out && FileCheck %s < %t.out
-
-// Test origin propagation through insertvalue IR instruction.
-
-#include <stdio.h>
-#include <stdint.h>
-
-struct mypair {
- int64_t x;
- int y;
-};
-
-mypair my_make_pair(int64_t x, int y) {
- mypair p;
- p.x = x;
- p.y = y;
- return p;
-}
-
-int main() {
- int64_t * volatile p = new int64_t;
- mypair z = my_make_pair(*p, 0);
- if (z.x)
- printf("zzz\n");
- // CHECK: MemorySanitizer: use-of-uninitialized-value
- // CHECK: {{in main .*insertvalue_origin.cc:}}[[@LINE-3]]
-
- // CHECK: Uninitialized value was created by a heap allocation
- // CHECK: {{in main .*insertvalue_origin.cc:}}[[@LINE-8]]
- delete p;
- return 0;
-}
diff --git a/lib/msan/lit_tests/ioctl.cc b/lib/msan/lit_tests/ioctl.cc
deleted file mode 100644
index caff80c2e5d7..000000000000
--- a/lib/msan/lit_tests/ioctl.cc
+++ /dev/null
@@ -1,20 +0,0 @@
-// RUN: %clangxx_msan -m64 -O0 -g %s -o %t && %t
-// RUN: %clangxx_msan -m64 -O3 -g %s -o %t && %t
-
-#include <assert.h>
-#include <stdlib.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-#include <unistd.h>
-
-int main(int argc, char **argv) {
- int fd = socket(AF_INET, SOCK_DGRAM, 0);
-
- unsigned int z;
- int res = ioctl(fd, FIOGETOWN, &z);
- assert(res == 0);
- close(fd);
- if (z)
- exit(0);
- return 0;
-}
diff --git a/lib/msan/lit_tests/ioctl_custom.cc b/lib/msan/lit_tests/ioctl_custom.cc
deleted file mode 100644
index 94ed528c70b9..000000000000
--- a/lib/msan/lit_tests/ioctl_custom.cc
+++ /dev/null
@@ -1,33 +0,0 @@
-// RUN: %clangxx_msan -m64 -O0 -g %s -o %t && %t
-// RUN: %clangxx_msan -m64 -O3 -g %s -o %t && %t
-
-// RUN: %clangxx_msan -DPOSITIVE -m64 -O0 -g %s -o %t && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_msan -DPOSITIVE -m64 -O3 -g %s -o %t && not %t 2>&1 | FileCheck %s
-
-#include <assert.h>
-#include <stdlib.h>
-#include <net/if.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-#include <unistd.h>
-
-int main(int argc, char **argv) {
- int fd = socket(AF_INET, SOCK_STREAM, 0);
-
- struct ifreq ifreqs[20];
- struct ifconf ifc;
- ifc.ifc_ifcu.ifcu_req = ifreqs;
-#ifndef POSITIVE
- ifc.ifc_len = sizeof(ifreqs);
-#endif
- int res = ioctl(fd, SIOCGIFCONF, (void *)&ifc);
- // CHECK: UMR in ioctl{{.*}} at offset 0
- // CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value
- // CHECK: #{{.*}} in main {{.*}}ioctl_custom.cc:[[@LINE-3]]
- assert(res == 0);
- for (int i = 0; i < ifc.ifc_len / sizeof(*ifc.ifc_ifcu.ifcu_req); ++i)
- printf("%d %zu %s\n", i, strlen(ifreqs[i].ifr_name), ifreqs[i].ifr_name);
- return 0;
-}
diff --git a/lib/msan/lit_tests/keep-going-dso.cc b/lib/msan/lit_tests/keep-going-dso.cc
deleted file mode 100644
index 6d006756a110..000000000000
--- a/lib/msan/lit_tests/keep-going-dso.cc
+++ /dev/null
@@ -1,33 +0,0 @@
-// RUN: %clangxx_msan -m64 -O0 %s -o %t && not %t >%t.out 2>&1
-// FileCheck --check-prefix=CHECK-KEEP-GOING %s <%t.out
-// RUN: %clangxx_msan -m64 -O0 %s -o %t && MSAN_OPTIONS=keep_going=0 not %t >%t.out 2>&1
-// FileCheck %s <%t.out
-// RUN: %clangxx_msan -m64 -O0 %s -o %t && MSAN_OPTIONS=keep_going=1 not %t >%t.out 2>&1
-// FileCheck --check-prefix=CHECK-KEEP-GOING %s <%t.out
-
-// RUN: %clangxx_msan -m64 -mllvm -msan-keep-going=1 -O0 %s -o %t && not %t >%t.out 2>&1
-// FileCheck --check-prefix=CHECK-KEEP-GOING %s <%t.out
-// RUN: %clangxx_msan -m64 -mllvm -msan-keep-going=1 -O0 %s -o %t && MSAN_OPTIONS=keep_going=0 not %t >%t.out 2>&1
-// FileCheck %s <%t.out
-// RUN: %clangxx_msan -m64 -mllvm -msan-keep-going=1 -O0 %s -o %t && MSAN_OPTIONS=keep_going=1 not %t >%t.out 2>&1
-// FileCheck --check-prefix=CHECK-KEEP-GOING %s <%t.out
-
-// Test how -mllvm -msan-keep-going and MSAN_OPTIONS=keep_going affect reports
-// from interceptors.
-// -mllvm -msan-keep-going provides the default value of keep_going flag, but is
-// always overwritten by MSAN_OPTIONS
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-int main(int argc, char **argv) {
- char *volatile x = (char*)malloc(5 * sizeof(char));
- x[4] = 0;
- if (strlen(x) < 3)
- exit(0);
- fprintf(stderr, "Done\n");
- // CHECK-NOT: Done
- // CHECK-KEEP-GOING: Done
- return 0;
-}
diff --git a/lib/msan/lit_tests/keep-going.cc b/lib/msan/lit_tests/keep-going.cc
deleted file mode 100644
index e33b137c76f7..000000000000
--- a/lib/msan/lit_tests/keep-going.cc
+++ /dev/null
@@ -1,34 +0,0 @@
-// RUN: %clangxx_msan -m64 -O0 %s -o %t && not %t >%t.out 2>&1
-// FileCheck %s <%t.out
-// RUN: %clangxx_msan -m64 -O0 %s -o %t && MSAN_OPTIONS=keep_going=0 not %t >%t.out 2>&1
-// FileCheck %s <%t.out
-// RUN: %clangxx_msan -m64 -O0 %s -o %t && MSAN_OPTIONS=keep_going=1 not %t >%t.out 2>&1
-// FileCheck %s <%t.out
-
-// RUN: %clangxx_msan -m64 -mllvm -msan-keep-going=1 -O0 %s -o %t && not %t >%t.out 2>&1
-// FileCheck --check-prefix=CHECK-KEEP-GOING %s <%t.out
-// RUN: %clangxx_msan -m64 -mllvm -msan-keep-going=1 -O0 %s -o %t && MSAN_OPTIONS=keep_going=0 not %t >%t.out 2>&1
-// FileCheck %s <%t.out
-// RUN: %clangxx_msan -m64 -mllvm -msan-keep-going=1 -O0 %s -o %t && MSAN_OPTIONS=keep_going=1 not %t >%t.out 2>&1
-// FileCheck --check-prefix=CHECK-KEEP-GOING %s <%t.out
-// RUN: %clangxx_msan -m64 -mllvm -msan-keep-going=1 -O0 %s -o %t && MSAN_OPTIONS=halt_on_error=1 not %t >%t.out 2>&1
-// FileCheck %s <%t.out
-// RUN: %clangxx_msan -m64 -mllvm -msan-keep-going=1 -O0 %s -o %t && MSAN_OPTIONS=halt_on_error=0 not %t >%t.out 2>&1
-// FileCheck --check-prefix=CHECK-KEEP-GOING %s <%t.out
-
-// Test behaviour of -mllvm -msan-keep-going and MSAN_OPTIONS=keep_going.
-// -mllvm -msan-keep-going provides the default value of keep_going flag; value
-// of 1 can be overwritten by MSAN_OPTIONS, value of 0 can not.
-
-#include <stdio.h>
-#include <stdlib.h>
-
-int main(int argc, char **argv) {
- char *volatile x = (char*)malloc(5 * sizeof(char));
- if (x[0])
- exit(0);
- fprintf(stderr, "Done\n");
- // CHECK-NOT: Done
- // CHECK-KEEP-GOING: Done
- return 0;
-}
diff --git a/lib/msan/lit_tests/lit.cfg b/lib/msan/lit_tests/lit.cfg
deleted file mode 100644
index da1bde6dd04a..000000000000
--- a/lib/msan/lit_tests/lit.cfg
+++ /dev/null
@@ -1,74 +0,0 @@
-# -*- Python -*-
-
-import os
-
-import lit.util
-
-def get_required_attr(config, attr_name):
- attr_value = getattr(config, attr_name, None)
- if not attr_value:
- lit_config.fatal(
- "No attribute %r in test configuration! You may need to run "
- "tests from your build directory or add this attribute "
- "to lit.site.cfg " % attr_name)
- return attr_value
-
-# Setup config name.
-config.name = 'MemorySanitizer'
-
-# Setup source root.
-config.test_source_root = os.path.dirname(__file__)
-
-def DisplayNoConfigMessage():
- lit_config.fatal("No site specific configuration available! " +
- "Try running your test from the build tree or running " +
- "make check-msan")
-
-# Figure out LLVM source root.
-llvm_src_root = getattr(config, 'llvm_src_root', None)
-if llvm_src_root is None:
- # We probably haven't loaded the site-specific configuration: the user
- # is likely trying to run a test file directly, and the site configuration
- # wasn't created by the build system.
- msan_site_cfg = lit_config.params.get('msan_site_config', None)
- if (msan_site_cfg) and (os.path.exists(msan_site_cfg)):
- lit_config.load_config(config, msan_site_cfg)
- raise SystemExit
-
- # Try to guess the location of site-specific configuration using llvm-config
- # util that can point where the build tree is.
- llvm_config = lit.util.which("llvm-config", config.environment["PATH"])
- if not llvm_config:
- DisplayNoConfigMessage()
-
- # Find out the presumed location of generated site config.
- llvm_obj_root = lit.util.capture(["llvm-config", "--obj-root"]).strip()
- msan_site_cfg = os.path.join(llvm_obj_root, "projects", "compiler-rt",
- "lib", "msan", "lit_tests", "lit.site.cfg")
- if (not msan_site_cfg) or (not os.path.exists(msan_site_cfg)):
- DisplayNoConfigMessage()
-
- lit_config.load_config(config, msan_site_cfg)
- raise SystemExit
-
-# Setup default compiler flags used with -fsanitize=memory option.
-clang_msan_cflags = ["-fsanitize=memory",
- "-mno-omit-leaf-frame-pointer",
- "-fno-omit-frame-pointer",
- "-fno-optimize-sibling-calls",
- "-g",
- "-m64"]
-clang_msan_cxxflags = ["--driver-mode=g++ "] + clang_msan_cflags
-config.substitutions.append( ("%clang_msan ",
- " ".join([config.clang] + clang_msan_cflags) +
- " ") )
-config.substitutions.append( ("%clangxx_msan ",
- " ".join([config.clang] + clang_msan_cxxflags) +
- " ") )
-
-# Default test suffixes.
-config.suffixes = ['.c', '.cc', '.cpp']
-
-# MemorySanitizer tests are currently supported on Linux only.
-if config.host_os not in ['Linux']:
- config.unsupported = True
diff --git a/lib/msan/lit_tests/lit.site.cfg.in b/lib/msan/lit_tests/lit.site.cfg.in
deleted file mode 100644
index 946df778f3d3..000000000000
--- a/lib/msan/lit_tests/lit.site.cfg.in
+++ /dev/null
@@ -1,5 +0,0 @@
-# Load common config for all compiler-rt lit tests.
-lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/lib/lit.common.configured")
-
-# Load tool-specific config that would do the real work.
-lit_config.load_config(config, "@MSAN_SOURCE_DIR@/lit_tests/lit.cfg")
diff --git a/lib/msan/lit_tests/malloc_hook.cc b/lib/msan/lit_tests/malloc_hook.cc
deleted file mode 100644
index fc68fbc35fbb..000000000000
--- a/lib/msan/lit_tests/malloc_hook.cc
+++ /dev/null
@@ -1,36 +0,0 @@
-// RUN: %clangxx_msan -O2 %s -o %t
-// RUN: %t 2>&1 | FileCheck %s
-#include <stdlib.h>
-#include <unistd.h>
-
-extern "C" {
-int __msan_get_ownership(const void *p);
-
-void *global_ptr;
-
-// Note: avoid calling functions that allocate memory in malloc/free
-// to avoid infinite recursion.
-void __msan_malloc_hook(void *ptr, size_t sz) {
- if (__msan_get_ownership(ptr)) {
- write(1, "MallocHook\n", sizeof("MallocHook\n"));
- global_ptr = ptr;
- }
-}
-void __msan_free_hook(void *ptr) {
- if (__msan_get_ownership(ptr) && ptr == global_ptr)
- write(1, "FreeHook\n", sizeof("FreeHook\n"));
-}
-} // extern "C"
-
-int main() {
- volatile int *x = new int;
- // CHECK: MallocHook
- // Check that malloc hook was called with correct argument.
- if (global_ptr != (void*)x) {
- _exit(1);
- }
- *x = 0;
- delete x;
- // CHECK: FreeHook
- return 0;
-}
diff --git a/lib/msan/lit_tests/no_sanitize_memory.cc b/lib/msan/lit_tests/no_sanitize_memory.cc
deleted file mode 100644
index 48afc17e35e9..000000000000
--- a/lib/msan/lit_tests/no_sanitize_memory.cc
+++ /dev/null
@@ -1,34 +0,0 @@
-// RUN: %clangxx_msan -m64 -O0 %s -o %t && %t >%t.out 2>&1
-// RUN: %clangxx_msan -m64 -O1 %s -o %t && %t >%t.out 2>&1
-// RUN: %clangxx_msan -m64 -O2 %s -o %t && %t >%t.out 2>&1
-// RUN: %clangxx_msan -m64 -O3 %s -o %t && %t >%t.out 2>&1
-
-// RUN: %clangxx_msan -m64 -O0 %s -o %t -DCHECK_IN_F && %t >%t.out 2>&1
-// RUN: %clangxx_msan -m64 -O1 %s -o %t -DCHECK_IN_F && %t >%t.out 2>&1
-// RUN: %clangxx_msan -m64 -O2 %s -o %t -DCHECK_IN_F && %t >%t.out 2>&1
-// RUN: %clangxx_msan -m64 -O3 %s -o %t -DCHECK_IN_F && %t >%t.out 2>&1
-
-// Test that (no_sanitize_memory) functions
-// * don't check shadow values (-DCHECK_IN_F)
-// * treat all values loaded from memory as fully initialized (-UCHECK_IN_F)
-
-#include <stdlib.h>
-#include <stdio.h>
-
-__attribute__((noinline))
-__attribute__((no_sanitize_memory))
-int f(void) {
- int x;
- int * volatile p = &x;
-#ifdef CHECK_IN_F
- if (*p)
- exit(0);
-#endif
- return *p;
-}
-
-int main(void) {
- if (f())
- exit(0);
- return 0;
-}
diff --git a/lib/msan/lit_tests/no_sanitize_memory_prop.cc b/lib/msan/lit_tests/no_sanitize_memory_prop.cc
deleted file mode 100644
index 355152478852..000000000000
--- a/lib/msan/lit_tests/no_sanitize_memory_prop.cc
+++ /dev/null
@@ -1,33 +0,0 @@
-// RUN: %clangxx_msan -m64 -O0 %s -o %t && %t >%t.out 2>&1
-// RUN: %clangxx_msan -m64 -O1 %s -o %t && not %t >%t.out 2>&1
-// RUN: FileCheck %s < %t.out
-// RUN: %clangxx_msan -m64 -O2 %s -o %t && not %t >%t.out 2>&1
-// RUN: FileCheck %s < %t.out
-// RUN: %clangxx_msan -m64 -O3 %s -o %t && not %t >%t.out 2>&1
-// RUN: FileCheck %s < %t.out
-
-// Test that (no_sanitize_memory) functions propagate shadow.
-
-// Note that at -O0 there is no report, because 'x' in 'f' is spilled to the
-// stack, and then loaded back as a fully initialiazed value (due to
-// no_sanitize_memory attribute).
-
-#include <stdlib.h>
-#include <stdio.h>
-
-__attribute__((noinline))
-__attribute__((no_sanitize_memory))
-int f(int x) {
- return x;
-}
-
-int main(void) {
- int x;
- int * volatile p = &x;
- int y = f(*p);
- // CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value
- // CHECK: {{#0 0x.* in main .*no_sanitize_memory_prop.cc:}}[[@LINE+1]]
- if (y)
- exit(0);
- return 0;
-}
diff --git a/lib/msan/lit_tests/poison_in_free.cc b/lib/msan/lit_tests/poison_in_free.cc
deleted file mode 100644
index f134d05abb1e..000000000000
--- a/lib/msan/lit_tests/poison_in_free.cc
+++ /dev/null
@@ -1,16 +0,0 @@
-// RUN: %clangxx_msan -O0 %s -o %t && not %t >%t.out 2>&1
-// FileCheck %s <%t.out
-// RUN: %clangxx_msan -O0 %s -o %t && MSAN_OPTIONS=poison_in_free=0 %t >%t.out 2>&1
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-int main(int argc, char **argv) {
- char *volatile x = (char*)malloc(50 * sizeof(char));
- memset(x, 0, 50);
- free(x);
- return x[25];
- // CHECK: MemorySanitizer: use-of-uninitialized-value
- // CHECK: #0 {{.*}} in main{{.*}}poison_in_free.cc:[[@LINE-2]]
-}
diff --git a/lib/msan/lit_tests/ptrace.cc b/lib/msan/lit_tests/ptrace.cc
deleted file mode 100644
index d0e83eabd6a4..000000000000
--- a/lib/msan/lit_tests/ptrace.cc
+++ /dev/null
@@ -1,36 +0,0 @@
-// RUN: %clangxx_msan -m64 -O0 %s -o %t && %t
-
-#include <assert.h>
-#include <stdio.h>
-#include <sys/ptrace.h>
-#include <sys/types.h>
-#include <sys/user.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-int main(void) {
- pid_t pid;
- pid = fork();
- if (pid == 0) { // child
- ptrace(PTRACE_TRACEME, 0, NULL, NULL);
- execl("/bin/true", "true", NULL);
- } else {
- wait(NULL);
- user_regs_struct regs;
- int res;
- res = ptrace(PTRACE_GETREGS, pid, NULL, &regs);
- assert(!res);
- if (regs.rip)
- printf("%zx\n", regs.rip);
-
- user_fpregs_struct fpregs;
- res = ptrace(PTRACE_GETFPREGS, pid, NULL, &fpregs);
- assert(!res);
- if (fpregs.mxcsr)
- printf("%x\n", fpregs.mxcsr);
-
- ptrace(PTRACE_CONT, pid, NULL, NULL);
- wait(NULL);
- }
- return 0;
-}
diff --git a/lib/msan/lit_tests/readdir64.cc b/lib/msan/lit_tests/readdir64.cc
deleted file mode 100644
index 0ec106c741f5..000000000000
--- a/lib/msan/lit_tests/readdir64.cc
+++ /dev/null
@@ -1,27 +0,0 @@
-// RUN: %clangxx_msan -m64 -O0 %s -o %t && %t
-// RUN: %clangxx_msan -m64 -O1 %s -o %t && %t
-// RUN: %clangxx_msan -m64 -O2 %s -o %t && %t
-// RUN: %clangxx_msan -m64 -O3 %s -o %t && %t
-
-// RUN: %clangxx_msan -m64 -O0 -D_FILE_OFFSET_BITS=64 %s -o %t && %t
-// RUN: %clangxx_msan -m64 -O1 -D_FILE_OFFSET_BITS=64 %s -o %t && %t
-// RUN: %clangxx_msan -m64 -O2 -D_FILE_OFFSET_BITS=64 %s -o %t && %t
-// RUN: %clangxx_msan -m64 -O3 -D_FILE_OFFSET_BITS=64 %s -o %t && %t
-
-// Test that readdir64 is intercepted as well as readdir.
-
-#include <sys/types.h>
-#include <dirent.h>
-#include <stdlib.h>
-
-
-int main(void) {
- DIR *dir = opendir(".");
- struct dirent *d = readdir(dir);
- if (d->d_name[0]) {
- closedir(dir);
- exit(0);
- }
- closedir(dir);
- return 0;
-}
diff --git a/lib/msan/lit_tests/scandir.cc b/lib/msan/lit_tests/scandir.cc
deleted file mode 100644
index 94672e1adbee..000000000000
--- a/lib/msan/lit_tests/scandir.cc
+++ /dev/null
@@ -1,56 +0,0 @@
-// RUN: %clangxx_msan -m64 -O0 %s -o %t && %t %p
-// RUN: %clangxx_msan -m64 -O0 -D_FILE_OFFSET_BITS=64 %s -o %t && %t %p
-// RUN: %clangxx_msan -m64 -O3 %s -o %t && %t %p
-
-#include <assert.h>
-#include <glob.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <dirent.h>
-#include <unistd.h>
-
-#include <sanitizer/msan_interface.h>
-
-
-static int my_filter(const struct dirent *a) {
- assert(__msan_test_shadow(&a, sizeof(a)) == (size_t)-1);
- printf("%s\n", a->d_name);
- __msan_print_shadow(a, a->d_reclen);
- assert(__msan_test_shadow(a, a->d_reclen) == (size_t)-1);
- printf("%s\n", a->d_name);
- return strlen(a->d_name) == 3 && a->d_name[2] == 'b';
-}
-
-static int my_compar(const struct dirent **a, const struct dirent **b) {
- assert(__msan_test_shadow(a, sizeof(*a)) == (size_t)-1);
- assert(__msan_test_shadow(*a, (*a)->d_reclen) == (size_t)-1);
- assert(__msan_test_shadow(b, sizeof(*b)) == (size_t)-1);
- assert(__msan_test_shadow(*b, (*b)->d_reclen) == (size_t)-1);
- if ((*a)->d_name[1] == (*b)->d_name[1])
- return 0;
- return ((*a)->d_name[1] < (*b)->d_name[1]) ? 1 : -1;
-}
-
-int main(int argc, char *argv[]) {
- assert(argc == 2);
- char buf[1024];
- snprintf(buf, sizeof(buf), "%s/%s", argv[1], "scandir_test_root/");
-
- struct dirent **d;
- int res = scandir(buf, &d, my_filter, my_compar);
- assert(res == 2);
- assert(__msan_test_shadow(&d, sizeof(*d)) == (size_t)-1);
- for (int i = 0; i < res; ++i) {
- assert(__msan_test_shadow(&d[i], sizeof(d[i])) == (size_t)-1);
- assert(__msan_test_shadow(d[i], d[i]->d_reclen) == (size_t)-1);
- }
-
- assert(strcmp(d[0]->d_name, "bbb") == 0);
- assert(strcmp(d[1]->d_name, "aab") == 0);
- return 0;
-}
diff --git a/lib/msan/lit_tests/scandir_null.cc b/lib/msan/lit_tests/scandir_null.cc
deleted file mode 100644
index 84af7f418d21..000000000000
--- a/lib/msan/lit_tests/scandir_null.cc
+++ /dev/null
@@ -1,34 +0,0 @@
-// RUN: %clangxx_msan -m64 -O0 %s -o %t && %t %p
-// RUN: %clangxx_msan -m64 -O0 -D_FILE_OFFSET_BITS=64 %s -o %t && %t %p
-// RUN: %clangxx_msan -m64 -O3 %s -o %t && %t %p
-
-#include <assert.h>
-#include <glob.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <dirent.h>
-#include <unistd.h>
-
-#include <sanitizer/msan_interface.h>
-
-
-int main(int argc, char *argv[]) {
- assert(argc == 2);
- char buf[1024];
- snprintf(buf, sizeof(buf), "%s/%s", argv[1], "scandir_test_root/");
-
- struct dirent **d;
- int res = scandir(buf, &d, NULL, NULL);
- assert(res >= 3);
- assert(__msan_test_shadow(&d, sizeof(*d)) == (size_t)-1);
- for (int i = 0; i < res; ++i) {
- assert(__msan_test_shadow(&d[i], sizeof(d[i])) == (size_t)-1);
- assert(__msan_test_shadow(d[i], d[i]->d_reclen) == (size_t)-1);
- }
- return 0;
-}
diff --git a/lib/msan/lit_tests/scandir_test_root/aaa b/lib/msan/lit_tests/scandir_test_root/aaa
deleted file mode 100644
index e69de29bb2d1..000000000000
--- a/lib/msan/lit_tests/scandir_test_root/aaa
+++ /dev/null
diff --git a/lib/msan/lit_tests/scandir_test_root/aab b/lib/msan/lit_tests/scandir_test_root/aab
deleted file mode 100644
index e69de29bb2d1..000000000000
--- a/lib/msan/lit_tests/scandir_test_root/aab
+++ /dev/null
diff --git a/lib/msan/lit_tests/scandir_test_root/bbb b/lib/msan/lit_tests/scandir_test_root/bbb
deleted file mode 100644
index e69de29bb2d1..000000000000
--- a/lib/msan/lit_tests/scandir_test_root/bbb
+++ /dev/null
diff --git a/lib/msan/lit_tests/select.cc b/lib/msan/lit_tests/select.cc
deleted file mode 100644
index a169a2dd9118..000000000000
--- a/lib/msan/lit_tests/select.cc
+++ /dev/null
@@ -1,22 +0,0 @@
-// RUN: %clangxx_msan -m64 -O0 %s -o %t && not %t >%t.out 2>&1
-// RUN: FileCheck %s < %t.out
-// RUN: %clangxx_msan -m64 -O1 %s -o %t && not %t >%t.out 2>&1
-// RUN: FileCheck %s < %t.out
-// RUN: %clangxx_msan -m64 -O2 %s -o %t && not %t >%t.out 2>&1
-// RUN: FileCheck %s < %t.out
-// RUN: %clangxx_msan -m64 -O3 %s -o %t && not %t >%t.out 2>&1
-// RUN: FileCheck %s < %t.out
-
-#include <stdlib.h>
-int main(int argc, char **argv) {
- int x;
- int *volatile p = &x;
- int z = *p ? 1 : 0;
- if (z)
- exit(0);
- // CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value
- // CHECK: {{#0 0x.* in main .*select.cc:}}[[@LINE-3]]
-
- // CHECK: SUMMARY: MemorySanitizer: use-of-uninitialized-value {{.*select.cc:.* main}}
- return 0;
-}
diff --git a/lib/msan/lit_tests/setlocale.cc b/lib/msan/lit_tests/setlocale.cc
deleted file mode 100644
index a22b744d74db..000000000000
--- a/lib/msan/lit_tests/setlocale.cc
+++ /dev/null
@@ -1,13 +0,0 @@
-// RUN: %clangxx_msan -m64 -O0 %s -o %t && %t
-
-#include <assert.h>
-#include <locale.h>
-#include <stdlib.h>
-
-int main(void) {
- char *locale = setlocale (LC_ALL, "");
- assert(locale);
- if (locale[0])
- exit(0);
- return 0;
-}
diff --git a/lib/msan/lit_tests/signal_stress_test.cc b/lib/msan/lit_tests/signal_stress_test.cc
deleted file mode 100644
index ea75eae1bdaa..000000000000
--- a/lib/msan/lit_tests/signal_stress_test.cc
+++ /dev/null
@@ -1,71 +0,0 @@
-// RUN: %clangxx_msan -std=c++11 -O0 %s -o %t && %t
-
-// Test that va_arg shadow from a signal handler does not leak outside.
-
-#include <signal.h>
-#include <stdarg.h>
-#include <sanitizer/msan_interface.h>
-#include <assert.h>
-#include <sys/time.h>
-#include <stdio.h>
-
-const int kSigCnt = 200;
-
-void f(bool poisoned, int n, ...) {
- va_list vl;
- va_start(vl, n);
- for (int i = 0; i < n; ++i) {
- void *p = va_arg(vl, void *);
- if (!poisoned)
- assert(__msan_test_shadow(&p, sizeof(p)) == -1);
- }
- va_end(vl);
-}
-
-int sigcnt;
-
-void SignalHandler(int signo) {
- assert(signo == SIGPROF);
- void *p;
- void **volatile q = &p;
- f(true, 10,
- *q, *q, *q, *q, *q,
- *q, *q, *q, *q, *q);
- ++sigcnt;
-}
-
-int main() {
- signal(SIGPROF, SignalHandler);
-
- itimerval itv;
- itv.it_interval.tv_sec = 0;
- itv.it_interval.tv_usec = 100;
- itv.it_value.tv_sec = 0;
- itv.it_value.tv_usec = 100;
- setitimer(ITIMER_PROF, &itv, NULL);
-
- void *p;
- void **volatile q = &p;
-
- do {
- f(false, 20,
- nullptr, nullptr, nullptr, nullptr, nullptr,
- nullptr, nullptr, nullptr, nullptr, nullptr,
- nullptr, nullptr, nullptr, nullptr, nullptr,
- nullptr, nullptr, nullptr, nullptr, nullptr);
- f(true, 20,
- *q, *q, *q, *q, *q,
- *q, *q, *q, *q, *q,
- *q, *q, *q, *q, *q,
- *q, *q, *q, *q, *q);
- } while (sigcnt < kSigCnt);
-
- itv.it_interval.tv_sec = 0;
- itv.it_interval.tv_usec = 0;
- itv.it_value.tv_sec = 0;
- itv.it_value.tv_usec = 0;
- setitimer(ITIMER_PROF, &itv, NULL);
-
- signal(SIGPROF, SIG_DFL);
- return 0;
-}
diff --git a/lib/msan/lit_tests/sigwait.cc b/lib/msan/lit_tests/sigwait.cc
deleted file mode 100644
index 29aa86c938f2..000000000000
--- a/lib/msan/lit_tests/sigwait.cc
+++ /dev/null
@@ -1,30 +0,0 @@
-// RUN: %clangxx_msan -std=c++11 -O0 -g %s -o %t && %t
-
-#include <assert.h>
-#include <sanitizer/msan_interface.h>
-#include <signal.h>
-#include <sys/time.h>
-#include <unistd.h>
-
-void test_sigwait() {
- sigset_t s;
- sigemptyset(&s);
- sigaddset(&s, SIGUSR1);
- sigprocmask(SIG_BLOCK, &s, 0);
-
- if (pid_t pid = fork()) {
- kill(pid, SIGUSR1);
- _exit(0);
- } else {
- int sig;
- int res = sigwait(&s, &sig);
- assert(!res);
- // The following checks that sig is initialized.
- assert(sig == SIGUSR1);
- }
-}
-
-int main(void) {
- test_sigwait();
- return 0;
-}
diff --git a/lib/msan/lit_tests/sigwaitinfo.cc b/lib/msan/lit_tests/sigwaitinfo.cc
deleted file mode 100644
index d4f004598a62..000000000000
--- a/lib/msan/lit_tests/sigwaitinfo.cc
+++ /dev/null
@@ -1,31 +0,0 @@
-// RUN: %clangxx_msan -std=c++11 -O0 -g %s -o %t && %t
-
-#include <assert.h>
-#include <sanitizer/msan_interface.h>
-#include <signal.h>
-#include <sys/time.h>
-#include <unistd.h>
-
-void test_sigwaitinfo() {
- sigset_t s;
- sigemptyset(&s);
- sigaddset(&s, SIGUSR1);
- sigprocmask(SIG_BLOCK, &s, 0);
-
- if (pid_t pid = fork()) {
- kill(pid, SIGUSR1);
- _exit(0);
- } else {
- siginfo_t info;
- int res = sigwaitinfo(&s, &info);
- assert(!res);
- // The following checks that sig is initialized.
- assert(info.si_signo == SIGUSR1);
- assert(-1 == __msan_test_shadow(&info, sizeof(info)));
- }
-}
-
-int main(void) {
- test_sigwaitinfo();
- return 0;
-}
diff --git a/lib/msan/lit_tests/stack-origin.cc b/lib/msan/lit_tests/stack-origin.cc
deleted file mode 100644
index b0b05d9658bf..000000000000
--- a/lib/msan/lit_tests/stack-origin.cc
+++ /dev/null
@@ -1,31 +0,0 @@
-// RUN: %clangxx_msan -m64 -O0 %s -o %t && not %t >%t.out 2>&1
-// RUN: FileCheck %s < %t.out
-// RUN: %clangxx_msan -m64 -O1 %s -o %t && not %t >%t.out 2>&1
-// RUN: FileCheck %s < %t.out
-// RUN: %clangxx_msan -m64 -O2 %s -o %t && not %t >%t.out 2>&1
-// RUN: FileCheck %s < %t.out
-// RUN: %clangxx_msan -m64 -O3 %s -o %t && not %t >%t.out 2>&1
-// RUN: FileCheck %s < %t.out
-
-// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O0 %s -o %t && not %t >%t.out 2>&1
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out
-// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O1 %s -o %t && not %t >%t.out 2>&1
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out
-// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O2 %s -o %t && not %t >%t.out 2>&1
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out
-// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O3 %s -o %t && not %t >%t.out 2>&1
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out
-
-#include <stdlib.h>
-int main(int argc, char **argv) {
- int x;
- int *volatile p = &x;
- return *p;
- // CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value
- // CHECK: {{#0 0x.* in main .*stack-origin.cc:}}[[@LINE-2]]
-
- // CHECK-ORIGINS: Uninitialized value was created by an allocation of 'x' in the stack frame of function 'main'
- // CHECK-ORIGINS: {{#0 0x.* in main .*stack-origin.cc:}}[[@LINE-8]]
-
- // CHECK: SUMMARY: MemorySanitizer: use-of-uninitialized-value {{.*stack-origin.cc:.* main}}
-}
diff --git a/lib/msan/lit_tests/sync_lock_set_and_test.cc b/lib/msan/lit_tests/sync_lock_set_and_test.cc
deleted file mode 100644
index 1023b3e54368..000000000000
--- a/lib/msan/lit_tests/sync_lock_set_and_test.cc
+++ /dev/null
@@ -1,7 +0,0 @@
-// RUN: %clangxx_msan -m64 -O0 %s -o %t && %t
-
-int main(void) {
- int i;
- __sync_lock_test_and_set(&i, 0);
- return i;
-}
diff --git a/lib/msan/lit_tests/tzset.cc b/lib/msan/lit_tests/tzset.cc
deleted file mode 100644
index 7e1c2cfad566..000000000000
--- a/lib/msan/lit_tests/tzset.cc
+++ /dev/null
@@ -1,16 +0,0 @@
-// RUN: %clangxx_msan -m64 -O0 %s -o %t && %t
-
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-
-extern char *tzname[2];
-
-int main(void) {
- if (!strlen(tzname[0]) || !strlen(tzname[1]))
- exit(1);
- tzset();
- if (!strlen(tzname[0]) || !strlen(tzname[1]))
- exit(1);
- return 0;
-}
diff --git a/lib/msan/lit_tests/unaligned_read_origin.cc b/lib/msan/lit_tests/unaligned_read_origin.cc
deleted file mode 100644
index fa29ab69de1b..000000000000
--- a/lib/msan/lit_tests/unaligned_read_origin.cc
+++ /dev/null
@@ -1,16 +0,0 @@
-// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O0 %s -o %t && not %t >%t.out 2>&1
-// RUN: FileCheck %s < %t.out && FileCheck %s < %t.out
-// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O3 %s -o %t && not %t >%t.out 2>&1
-// RUN: FileCheck %s < %t.out && FileCheck %s < %t.out
-
-#include <sanitizer/msan_interface.h>
-
-int main(int argc, char **argv) {
- int x;
- int *volatile p = &x;
- return __sanitizer_unaligned_load32(p);
- // CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value
- // CHECK: {{#0 0x.* in main .*unaligned_read_origin.cc:}}[[@LINE-2]]
- // CHECK: Uninitialized value was created by an allocation of 'x' in the stack frame of function 'main'
- // CHECK: {{#0 0x.* in main .*unaligned_read_origin.cc:}}[[@LINE-7]]
-}
diff --git a/lib/msan/lit_tests/use-after-free.cc b/lib/msan/lit_tests/use-after-free.cc
deleted file mode 100644
index ac47c0233a10..000000000000
--- a/lib/msan/lit_tests/use-after-free.cc
+++ /dev/null
@@ -1,34 +0,0 @@
-// RUN: %clangxx_msan -m64 -O0 %s -o %t && not %t >%t.out 2>&1
-// RUN: FileCheck %s < %t.out
-// RUN: %clangxx_msan -m64 -O1 %s -o %t && not %t >%t.out 2>&1
-// RUN: FileCheck %s < %t.out
-// RUN: %clangxx_msan -m64 -O2 %s -o %t && not %t >%t.out 2>&1
-// RUN: FileCheck %s < %t.out
-// RUN: %clangxx_msan -m64 -O3 %s -o %t && not %t >%t.out 2>&1
-// RUN: FileCheck %s < %t.out
-
-// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O0 %s -o %t && not %t >%t.out 2>&1
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out
-// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O1 %s -o %t && not %t >%t.out 2>&1
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out
-// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O2 %s -o %t && not %t >%t.out 2>&1
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out
-// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O3 %s -o %t && not %t >%t.out 2>&1
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out
-
-#include <stdlib.h>
-int main(int argc, char **argv) {
- int *volatile p = (int *)malloc(sizeof(int));
- *p = 42;
- free(p);
-
- if (*p)
- exit(0);
- // CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value
- // CHECK: {{#0 0x.* in main .*use-after-free.cc:}}[[@LINE-3]]
-
- // CHECK-ORIGINS: Uninitialized value was created by a heap allocation
- // CHECK-ORIGINS: {{#0 0x.* in .*free}}
- // CHECK-ORIGINS: {{#1 0x.* in main .*use-after-free.cc:}}[[@LINE-9]]
- return 0;
-}
diff --git a/lib/msan/lit_tests/vector_cvt.cc b/lib/msan/lit_tests/vector_cvt.cc
deleted file mode 100644
index c200c77de96a..000000000000
--- a/lib/msan/lit_tests/vector_cvt.cc
+++ /dev/null
@@ -1,23 +0,0 @@
-// RUN: %clangxx_msan -m64 -O0 %s -o %t && %t
-// RUN: %clangxx_msan -DPOSITIVE -m64 -O0 %s -o %t && not %t 2>&1 | FileCheck %s
-
-#include <emmintrin.h>
-
-int to_int(double v) {
- __m128d t = _mm_set_sd(v);
- int x = _mm_cvtsd_si32(t);
- return x;
- // CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value
- // CHECK: #{{.*}} in to_int{{.*}}vector_cvt.cc:[[@LINE-4]]
-}
-
-int main() {
-#ifdef POSITIVE
- double v;
-#else
- double v = 1.1;
-#endif
- double* volatile p = &v;
- int x = to_int(*p);
- return !x;
-}
diff --git a/lib/msan/lit_tests/vector_select.cc b/lib/msan/lit_tests/vector_select.cc
deleted file mode 100644
index e8d55423293c..000000000000
--- a/lib/msan/lit_tests/vector_select.cc
+++ /dev/null
@@ -1,13 +0,0 @@
-// RUN: %clangxx_msan -m64 -O0 %s -c -o %t
-// RUN: %clangxx_msan -m64 -O3 %s -c -o %t
-
-// Regression test for MemorySanitizer instrumentation of a select instruction
-// with vector arguments.
-
-#include <emmintrin.h>
-
-__m128d select(bool b, __m128d c, __m128d d)
-{
- return b ? c : d;
-}
-
diff --git a/lib/msan/lit_tests/wrap_indirect_calls.cc b/lib/msan/lit_tests/wrap_indirect_calls.cc
deleted file mode 100644
index b4bac1ecbd22..000000000000
--- a/lib/msan/lit_tests/wrap_indirect_calls.cc
+++ /dev/null
@@ -1,64 +0,0 @@
-// Test indirect call wrapping in MemorySanitizer.
-
-// RUN: %clangxx_msan -O0 %p/wrap_indirect_calls/two.cc -fPIC -shared -o %t-two-so.so
-// RUN: %clangxx_msan -O0 %p/wrap_indirect_calls/wrapper.cc -fPIC -shared -o %t-wrapper-so.so
-
-// Disable fast path.
-
-// RUN: %clangxx_msan -O0 %p/wrap_indirect_calls/caller.cc %p/wrap_indirect_calls/one.cc %s \
-// RUN: %t-two-so.so %t-wrapper-so.so \
-// RUN: -mllvm -msan-wrap-indirect-calls=wrapper \
-// RUN: -mllvm -msan-wrap-indirect-calls-fast=0 \
-// RUN: -DSLOW=1 \
-// RUN: -Wl,--defsym=__executable_start=0 -o %t
-// RUN: %t
-
-// Enable fast path, call from executable, -O0.
-
-// RUN: %clangxx_msan -O0 %p/wrap_indirect_calls/caller.cc %p/wrap_indirect_calls/one.cc %s \
-// RUN: %t-two-so.so %t-wrapper-so.so \
-// RUN: -mllvm -msan-wrap-indirect-calls=wrapper \
-// RUN: -mllvm -msan-wrap-indirect-calls-fast=1 \
-// RUN: -DSLOW=0 \
-// RUN: -Wl,--defsym=__executable_start=0 -o %t
-// RUN: %t
-
-// Enable fast path, call from executable, -O3.
-
-// RUN: %clangxx_msan -O3 %p/wrap_indirect_calls/caller.cc %p/wrap_indirect_calls/one.cc %s \
-// RUN: %t-two-so.so %t-wrapper-so.so \
-// RUN: -mllvm -msan-wrap-indirect-calls=wrapper \
-// RUN: -mllvm -msan-wrap-indirect-calls-fast=1 \
-// RUN: -DSLOW=0 \
-// RUN: -Wl,--defsym=__executable_start=0 -o %t
-// RUN: %t
-
-// Enable fast path, call from DSO, -O0.
-
-// RUN: %clangxx_msan -O0 %p/wrap_indirect_calls/caller.cc %p/wrap_indirect_calls/one.cc -shared \
-// RUN: %t-two-so.so %t-wrapper-so.so \
-// RUN: -mllvm -msan-wrap-indirect-calls=wrapper \
-// RUN: -mllvm -msan-wrap-indirect-calls-fast=1 \
-// RUN: -DSLOW=0 \
-// RUN: -Wl,--defsym=__executable_start=0 -o %t-caller-so.so
-// RUN: %clangxx_msan -O0 %s %t-caller-so.so %t-two-so.so %t-wrapper-so.so -o %t
-// RUN: %t
-
-// Enable fast path, call from DSO, -O3.
-
-// RUN: %clangxx_msan -O3 %p/wrap_indirect_calls/caller.cc %p/wrap_indirect_calls/one.cc -shared \
-// RUN: %t-two-so.so %t-wrapper-so.so \
-// RUN: -mllvm -msan-wrap-indirect-calls=wrapper \
-// RUN: -mllvm -msan-wrap-indirect-calls-fast=1 \
-// RUN: -DSLOW=0 \
-// RUN: -Wl,--defsym=__executable_start=0 -o %t-caller-so.so
-// RUN: %clangxx_msan -O3 %s %t-caller-so.so %t-two-so.so %t-wrapper-so.so -o %t
-// RUN: %t
-
-// The actual test is in multiple files in wrap_indirect_calls/ directory.
-void run_test();
-
-int main() {
- run_test();
- return 0;
-}
diff --git a/lib/msan/lit_tests/wrap_indirect_calls/caller.cc b/lib/msan/lit_tests/wrap_indirect_calls/caller.cc
deleted file mode 100644
index a0af8b7bb0c5..000000000000
--- a/lib/msan/lit_tests/wrap_indirect_calls/caller.cc
+++ /dev/null
@@ -1,51 +0,0 @@
-// Indirectly call a bunch of functions.
-
-#include <assert.h>
-
-extern int cnt;
-
-typedef int (*F)(int, int);
-
-// A function in the same object.
-int f_local(int x, int y) {
- return x + y;
-}
-
-// A function in another object.
-int f_other_object(int x, int y);
-
-// A function in another DSO.
-int f_dso(int x, int y);
-
-// A function in another DSO that is replaced by the wrapper.
-int f_replaced(int x, int y);
-
-void run_test(void) {
- int x;
- int expected_cnt = 0;
- volatile F f;
-
- if (SLOW) ++expected_cnt;
- f = &f_local;
- x = f(1, 2);
- assert(x == 3);
- assert(cnt == expected_cnt);
-
- if (SLOW) ++expected_cnt;
- f = &f_other_object;
- x = f(2, 3);
- assert(x == 6);
- assert(cnt == expected_cnt);
-
- ++expected_cnt;
- f = &f_dso;
- x = f(2, 3);
- assert(x == 7);
- assert(cnt == expected_cnt);
-
- ++expected_cnt;
- f = &f_replaced;
- x = f(2, 3);
- assert(x == 11);
- assert(cnt == expected_cnt);
-}
diff --git a/lib/msan/lit_tests/wrap_indirect_calls/lit.local.cfg b/lib/msan/lit_tests/wrap_indirect_calls/lit.local.cfg
deleted file mode 100644
index 5e01230c0986..000000000000
--- a/lib/msan/lit_tests/wrap_indirect_calls/lit.local.cfg
+++ /dev/null
@@ -1,3 +0,0 @@
-# Sources in this directory are used by tests in parent directory.
-
-config.suffixes = []
diff --git a/lib/msan/lit_tests/wrap_indirect_calls/one.cc b/lib/msan/lit_tests/wrap_indirect_calls/one.cc
deleted file mode 100644
index ab7bf4125c0a..000000000000
--- a/lib/msan/lit_tests/wrap_indirect_calls/one.cc
+++ /dev/null
@@ -1,3 +0,0 @@
-int f_other_object(int x, int y) {
- return x * y;
-}
diff --git a/lib/msan/lit_tests/wrap_indirect_calls/two.cc b/lib/msan/lit_tests/wrap_indirect_calls/two.cc
deleted file mode 100644
index c939a993bc9a..000000000000
--- a/lib/msan/lit_tests/wrap_indirect_calls/two.cc
+++ /dev/null
@@ -1,11 +0,0 @@
-int f_dso(int x, int y) {
- return 2 * x + y;
-}
-
-int f_replaced(int x, int y) {
- return x + y + 5;
-}
-
-int f_replacement(int x, int y) {
- return x + y + 6;
-}
diff --git a/lib/msan/lit_tests/wrap_indirect_calls/wrapper.cc b/lib/msan/lit_tests/wrap_indirect_calls/wrapper.cc
deleted file mode 100644
index 8fcd0c635d96..000000000000
--- a/lib/msan/lit_tests/wrap_indirect_calls/wrapper.cc
+++ /dev/null
@@ -1,11 +0,0 @@
-int f_replaced(int x, int y);
-int f_replacement(int x, int y);
-
-int cnt;
-
-extern "C" void *wrapper(void *p) {
- ++cnt;
- if (p == (void *)f_replaced)
- return (void *)f_replacement;
- return p;
-}
diff --git a/lib/msan/msan.cc b/lib/msan/msan.cc
index 83b11e5c2ff3..853e448fab8e 100644
--- a/lib/msan/msan.cc
+++ b/lib/msan/msan.cc
@@ -13,6 +13,9 @@
//===----------------------------------------------------------------------===//
#include "msan.h"
+#include "msan_chained_origin_depot.h"
+#include "msan_origin.h"
+#include "msan_thread.h"
#include "sanitizer_common/sanitizer_atomic.h"
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_flags.h"
@@ -20,8 +23,8 @@
#include "sanitizer_common/sanitizer_procmaps.h"
#include "sanitizer_common/sanitizer_stacktrace.h"
#include "sanitizer_common/sanitizer_symbolizer.h"
+#include "sanitizer_common/sanitizer_stackdepot.h"
-#include "interception/interception.h"
// ACHTUNG! No system header includes in this file.
@@ -31,22 +34,25 @@ using namespace __sanitizer;
static THREADLOCAL int msan_expect_umr = 0;
static THREADLOCAL int msan_expected_umr_found = 0;
-static int msan_running_under_dr = 0;
-
+// Function argument shadow. Each argument starts at the next available 8-byte
+// aligned address.
SANITIZER_INTERFACE_ATTRIBUTE
-THREADLOCAL u64 __msan_param_tls[kMsanParamTlsSizeInWords];
+THREADLOCAL u64 __msan_param_tls[kMsanParamTlsSize / sizeof(u64)];
+// Function argument origin. Each argument starts at the same offset as the
+// corresponding shadow in (__msan_param_tls). Slightly weird, but changing this
+// would break compatibility with older prebuilt binaries.
SANITIZER_INTERFACE_ATTRIBUTE
-THREADLOCAL u32 __msan_param_origin_tls[kMsanParamTlsSizeInWords];
+THREADLOCAL u32 __msan_param_origin_tls[kMsanParamTlsSize / sizeof(u32)];
SANITIZER_INTERFACE_ATTRIBUTE
-THREADLOCAL u64 __msan_retval_tls[kMsanRetvalTlsSizeInWords];
+THREADLOCAL u64 __msan_retval_tls[kMsanRetvalTlsSize / sizeof(u64)];
SANITIZER_INTERFACE_ATTRIBUTE
THREADLOCAL u32 __msan_retval_origin_tls;
SANITIZER_INTERFACE_ATTRIBUTE
-THREADLOCAL u64 __msan_va_arg_tls[kMsanParamTlsSizeInWords];
+THREADLOCAL u64 __msan_va_arg_tls[kMsanParamTlsSize / sizeof(u64)];
SANITIZER_INTERFACE_ATTRIBUTE
THREADLOCAL u64 __msan_va_arg_overflow_size_tls;
@@ -54,12 +60,7 @@ THREADLOCAL u64 __msan_va_arg_overflow_size_tls;
SANITIZER_INTERFACE_ATTRIBUTE
THREADLOCAL u32 __msan_origin_tls;
-static THREADLOCAL struct {
- uptr stack_top, stack_bottom;
-} __msan_stack_bounds;
-
static THREADLOCAL int is_in_symbolizer;
-static THREADLOCAL int is_in_loader;
extern "C" SANITIZER_WEAK_ATTRIBUTE const int __msan_track_origins;
@@ -71,34 +72,10 @@ extern "C" SANITIZER_WEAK_ATTRIBUTE const int __msan_keep_going;
namespace __msan {
-static bool IsRunningUnderDr() {
- bool result = false;
- MemoryMappingLayout proc_maps(/*cache_enabled*/true);
- const sptr kBufSize = 4095;
- char *filename = (char*)MmapOrDie(kBufSize, __FUNCTION__);
- while (proc_maps.Next(/* start */0, /* end */0, /* file_offset */0,
- filename, kBufSize, /* protection */0)) {
- if (internal_strstr(filename, "libdynamorio") != 0) {
- result = true;
- break;
- }
- }
- UnmapOrDie(filename, kBufSize);
- return result;
-}
-
void EnterSymbolizer() { ++is_in_symbolizer; }
void ExitSymbolizer() { --is_in_symbolizer; }
bool IsInSymbolizer() { return is_in_symbolizer; }
-void EnterLoader() { ++is_in_loader; }
-void ExitLoader() { --is_in_loader; }
-
-extern "C" {
-SANITIZER_INTERFACE_ATTRIBUTE
-bool __msan_is_in_loader() { return is_in_loader; }
-}
-
static Flags msan_flags;
Flags *flags() {
@@ -110,6 +87,8 @@ 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;
@@ -118,33 +97,63 @@ static uptr StackOriginPC[kNumStackOriginDescrs];
static atomic_uint32_t NumStackOriginDescrs;
static void ParseFlagsFromString(Flags *f, const char *str) {
- ParseCommonFlagsFromString(str);
- ParseFlag(str, &f->poison_heap_with_zeroes, "poison_heap_with_zeroes");
- ParseFlag(str, &f->poison_stack_with_zeroes, "poison_stack_with_zeroes");
- ParseFlag(str, &f->poison_in_malloc, "poison_in_malloc");
- ParseFlag(str, &f->poison_in_free, "poison_in_free");
- ParseFlag(str, &f->exit_code, "exit_code");
+ CommonFlags *cf = common_flags();
+ ParseCommonFlagsFromString(cf, str);
+ ParseFlag(str, &f->poison_heap_with_zeroes, "poison_heap_with_zeroes", "");
+ ParseFlag(str, &f->poison_stack_with_zeroes, "poison_stack_with_zeroes", "");
+ ParseFlag(str, &f->poison_in_malloc, "poison_in_malloc", "");
+ ParseFlag(str, &f->poison_in_free, "poison_in_free", "");
+ ParseFlag(str, &f->exit_code, "exit_code", "");
if (f->exit_code < 0 || f->exit_code > 127) {
Printf("Exit code not in [0, 128) range: %d\n", f->exit_code);
Die();
}
- ParseFlag(str, &f->report_umrs, "report_umrs");
- ParseFlag(str, &f->wrap_signals, "wrap_signals");
+ ParseFlag(str, &f->origin_history_size, "origin_history_size", "");
+ if (f->origin_history_size < 0 ||
+ f->origin_history_size > Origin::kMaxDepth) {
+ Printf(
+ "Origin history size invalid: %d. Must be 0 (unlimited) or in [1, %d] "
+ "range.\n",
+ f->origin_history_size, Origin::kMaxDepth);
+ Die();
+ }
+ ParseFlag(str, &f->origin_history_per_stack_limit,
+ "origin_history_per_stack_limit", "");
+ // Limiting to kStackDepotMaxUseCount / 2 to avoid overflow in
+ // StackDepotHandle::inc_use_count_unsafe.
+ if (f->origin_history_per_stack_limit < 0 ||
+ f->origin_history_per_stack_limit > kStackDepotMaxUseCount / 2) {
+ Printf(
+ "Origin per-stack limit invalid: %d. Must be 0 (unlimited) or in [1, "
+ "%d] range.\n",
+ f->origin_history_per_stack_limit, kStackDepotMaxUseCount / 2);
+ Die();
+ }
+
+ ParseFlag(str, &f->report_umrs, "report_umrs", "");
+ ParseFlag(str, &f->wrap_signals, "wrap_signals", "");
+ ParseFlag(str, &f->print_stats, "print_stats", "");
+ ParseFlag(str, &f->atexit, "atexit", "");
+ ParseFlag(str, &f->store_context_size, "store_context_size", "");
+ if (f->store_context_size < 1) f->store_context_size = 1;
// keep_going is an old name for halt_on_error,
// and it has inverse meaning.
f->halt_on_error = !f->halt_on_error;
- ParseFlag(str, &f->halt_on_error, "keep_going");
+ ParseFlag(str, &f->halt_on_error, "keep_going", "");
f->halt_on_error = !f->halt_on_error;
- ParseFlag(str, &f->halt_on_error, "halt_on_error");
+ ParseFlag(str, &f->halt_on_error, "halt_on_error", "");
}
static void InitializeFlags(Flags *f, const char *options) {
CommonFlags *cf = common_flags();
- SetCommonFlagDefaults();
+ SetCommonFlagsDefaults(cf);
cf->external_symbolizer_path = GetEnv("MSAN_SYMBOLIZER_PATH");
cf->malloc_context_size = 20;
cf->handle_ioctl = true;
+ // FIXME: test and enable.
+ cf->check_printf = false;
+ cf->intercept_tls_get_addr = true;
internal_memset(f, 0, sizeof(*f));
f->poison_heap_with_zeroes = false;
@@ -152,9 +161,14 @@ static void InitializeFlags(Flags *f, const char *options) {
f->poison_in_malloc = true;
f->poison_in_free = true;
f->exit_code = 77;
+ f->origin_history_size = Origin::kMaxDepth;
+ f->origin_history_per_stack_limit = 20000;
f->report_umrs = true;
f->wrap_signals = true;
+ f->print_stats = false;
+ f->atexit = false;
f->halt_on_error = !&__msan_keep_going;
+ f->store_context_size = 20;
// Override from user-specified string.
if (__msan_default_options)
@@ -162,39 +176,22 @@ static void InitializeFlags(Flags *f, const char *options) {
ParseFlagsFromString(f, options);
}
-static void GetCurrentStackBounds(uptr *stack_top, uptr *stack_bottom) {
- if (__msan_stack_bounds.stack_top == 0) {
- // Break recursion (GetStackTrace -> GetThreadStackTopAndBottom ->
- // realloc -> GetStackTrace).
- __msan_stack_bounds.stack_top = __msan_stack_bounds.stack_bottom = 1;
- GetThreadStackTopAndBottom(/* at_initialization */false,
- &__msan_stack_bounds.stack_top,
- &__msan_stack_bounds.stack_bottom);
- }
- *stack_top = __msan_stack_bounds.stack_top;
- *stack_bottom = __msan_stack_bounds.stack_bottom;
-}
-
-void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp,
+void GetStackTrace(BufferedStackTrace *stack, uptr max_s, uptr pc, uptr bp,
bool request_fast_unwind) {
- if (!StackTrace::WillUseFastUnwind(request_fast_unwind)) {
+ MsanThread *t = GetCurrentThread();
+ 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, request_fast_unwind);
+ return stack->Unwind(max_s, pc, bp, 0, 0, 0, request_fast_unwind);
}
- uptr stack_top, stack_bottom;
- GetCurrentStackBounds(&stack_top, &stack_bottom);
- stack->Unwind(max_s, pc, bp, stack_top, stack_bottom, request_fast_unwind);
+ stack->Unwind(max_s, pc, bp, 0, t->stack_top(), t->stack_bottom(),
+ request_fast_unwind);
}
void PrintWarning(uptr pc, uptr bp) {
PrintWarningWithOrigin(pc, bp, __msan_origin_tls);
}
-bool OriginIsValid(u32 origin) {
- return origin != 0 && origin != (u32)-1;
-}
-
void PrintWarningWithOrigin(uptr pc, uptr bp, u32 origin) {
if (msan_expect_umr) {
// Printf("Expected UMR\n");
@@ -205,15 +202,13 @@ void PrintWarningWithOrigin(uptr pc, uptr bp, u32 origin) {
++msan_report_count;
- StackTrace stack;
- GetStackTrace(&stack, kStackTraceMax, pc, bp,
- common_flags()->fast_unwind_on_fatal);
+ GET_FATAL_STACK_TRACE_PC_BP(pc, bp);
u32 report_origin =
- (__msan_get_track_origins() && OriginIsValid(origin)) ? origin : 0;
+ (__msan_get_track_origins() && Origin::isValidId(origin)) ? origin : 0;
ReportUMR(&stack, report_origin);
- if (__msan_get_track_origins() && !OriginIsValid(origin)) {
+ if (__msan_get_track_origins() && !Origin::isValidId(origin)) {
Printf(
" ORIGIN: invalid (%x). Might be a bug in MemorySanitizer origin "
"tracking.\n This could still be a bug in your code, too!\n",
@@ -242,7 +237,8 @@ void ScopedThreadLocalStateBackup::Restore() {
internal_memset(__msan_va_arg_tls, 0, sizeof(__msan_va_arg_tls));
if (__msan_get_track_origins()) {
- internal_memset(&__msan_retval_origin_tls, 0, sizeof(__msan_retval_tls));
+ internal_memset(&__msan_retval_origin_tls, 0,
+ sizeof(__msan_retval_origin_tls));
internal_memset(__msan_param_origin_tls, 0,
sizeof(__msan_param_origin_tls));
}
@@ -251,25 +247,71 @@ void ScopedThreadLocalStateBackup::Restore() {
void UnpoisonThreadLocalState() {
}
-const char *GetOriginDescrIfStack(u32 id, uptr *pc) {
- if ((id >> 31) == 0) return 0;
- id &= (1U << 31) - 1;
+const char *GetStackOriginDescr(u32 id, uptr *pc) {
CHECK_LT(id, kNumStackOriginDescrs);
if (pc) *pc = StackOriginPC[id];
return StackOriginDescr[id];
}
+u32 ChainOrigin(u32 id, StackTrace *stack) {
+ MsanThread *t = GetCurrentThread();
+ if (t && t->InSignalHandler())
+ return id;
+
+ Origin o = Origin::FromRawId(id);
+ Origin chained = Origin::CreateChainedOrigin(o, stack);
+ return chained.raw_id();
+}
+
} // namespace __msan
// Interface.
using namespace __msan;
+#define MSAN_MAYBE_WARNING(type, size) \
+ void __msan_maybe_warning_##size(type s, u32 o) { \
+ GET_CALLER_PC_BP_SP; \
+ (void) sp; \
+ if (UNLIKELY(s)) { \
+ PrintWarningWithOrigin(pc, bp, o); \
+ if (__msan::flags()->halt_on_error) { \
+ Printf("Exiting\n"); \
+ Die(); \
+ } \
+ } \
+ }
+
+MSAN_MAYBE_WARNING(u8, 1)
+MSAN_MAYBE_WARNING(u16, 2)
+MSAN_MAYBE_WARNING(u32, 4)
+MSAN_MAYBE_WARNING(u64, 8)
+
+#define MSAN_MAYBE_STORE_ORIGIN(type, size) \
+ void __msan_maybe_store_origin_##size(type s, void *p, u32 o) { \
+ if (UNLIKELY(s)) { \
+ if (__msan_get_track_origins() > 1) { \
+ GET_CALLER_PC_BP_SP; \
+ (void) sp; \
+ GET_STORE_STACK_TRACE_PC_BP(pc, bp); \
+ o = ChainOrigin(o, &stack); \
+ } \
+ *(u32 *)MEM_TO_ORIGIN((uptr)p & ~3UL) = o; \
+ } \
+ }
+
+MSAN_MAYBE_STORE_ORIGIN(u8, 1)
+MSAN_MAYBE_STORE_ORIGIN(u16, 2)
+MSAN_MAYBE_STORE_ORIGIN(u32, 4)
+MSAN_MAYBE_STORE_ORIGIN(u64, 8)
+
void __msan_warning() {
GET_CALLER_PC_BP_SP;
(void)sp;
PrintWarning(pc, bp);
if (__msan::flags()->halt_on_error) {
+ if (__msan::flags()->print_stats)
+ ReportStats();
Printf("Exiting\n");
Die();
}
@@ -279,11 +321,14 @@ void __msan_warning_noreturn() {
GET_CALLER_PC_BP_SP;
(void)sp;
PrintWarning(pc, bp);
+ if (__msan::flags()->print_stats)
+ ReportStats();
Printf("Exiting\n");
Die();
}
void __msan_init() {
+ CHECK(!msan_init_is_running);
if (msan_inited) return;
msan_init_is_running = 1;
SanitizerToolName = "MemorySanitizer";
@@ -293,6 +338,7 @@ void __msan_init() {
const char *msan_options = GetEnv("MSAN_OPTIONS");
InitializeFlags(&msan_flags, msan_options);
+ if (common_flags()->help) PrintFlagDescriptions();
__sanitizer_set_report_path(common_flags()->log_path);
InitializeInterceptors();
@@ -300,25 +346,21 @@ void __msan_init() {
if (MSAN_REPLACE_OPERATORS_NEW_AND_DELETE)
ReplaceOperatorsNewAndDelete();
+ DisableCoreDumperIfNecessary();
if (StackSizeIsUnlimited()) {
- if (common_flags()->verbosity)
- Printf("Unlimited stack, doing reexec\n");
+ VPrintf(1, "Unlimited stack, doing reexec\n");
// A reasonably large stack size. It is bigger than the usual 8Mb, because,
// well, the program could have been run with unlimited stack for a reason.
SetStackSizeLimitInBytes(32 * 1024 * 1024);
ReExec();
}
- if (common_flags()->verbosity)
- Printf("MSAN_OPTIONS: %s\n", msan_options ? msan_options : "<empty>");
+ VPrintf(1, "MSAN_OPTIONS: %s\n", msan_options ? msan_options : "<empty>");
- msan_running_under_dr = IsRunningUnderDr();
__msan_clear_on_return();
- if (__msan_get_track_origins() && common_flags()->verbosity > 0)
- Printf("msan_track_origins\n");
- if (!InitShadow(/* prot1 */ false, /* prot2 */ true, /* map_shadow */ true,
- __msan_get_track_origins())) {
- // FIXME: prot1 = false is only required when running under DR.
+ if (__msan_get_track_origins())
+ VPrintf(1, "msan_track_origins\n");
+ if (!InitShadow(/* map_shadow */ true, __msan_get_track_origins())) {
Printf("FATAL: MemorySanitizer can not mmap the shadow memory.\n");
Printf("FATAL: Make sure to compile with -fPIE and to link with -pie.\n");
Printf("FATAL: Disabling ASLR is known to cause this error.\n");
@@ -328,19 +370,21 @@ void __msan_init() {
Die();
}
- const char *external_symbolizer = common_flags()->external_symbolizer_path;
- bool external_symbolizer_started =
- Symbolizer::Init(external_symbolizer)->IsExternalAvailable();
- if (external_symbolizer && external_symbolizer[0]) {
- CHECK(external_symbolizer_started);
+ Symbolizer::GetOrInit()->AddHooks(EnterSymbolizer, ExitSymbolizer);
+
+ if (common_flags()->coverage) {
+ __sanitizer_cov_init();
+ Atexit(__sanitizer_cov_dump);
}
- Symbolizer::Get()->AddHooks(EnterSymbolizer, ExitSymbolizer);
- GetThreadStackTopAndBottom(/* at_initialization */true,
- &__msan_stack_bounds.stack_top,
- &__msan_stack_bounds.stack_bottom);
- if (common_flags()->verbosity)
- Printf("MemorySanitizer init done\n");
+ MsanTSDInit(MsanTSDDtor);
+
+ MsanThread *main_thread = MsanThread::Create(0, 0);
+ SetCurrentThread(main_thread);
+ main_thread->ThreadStart();
+
+ VPrintf(1, "MemorySanitizer init done\n");
+
msan_init_is_running = 0;
msan_inited = 1;
}
@@ -359,9 +403,7 @@ void __msan_set_expect_umr(int expect_umr) {
} else if (!msan_expected_umr_found) {
GET_CALLER_PC_BP_SP;
(void)sp;
- StackTrace stack;
- GetStackTrace(&stack, kStackTraceMax, pc, bp,
- common_flags()->fast_unwind_on_fatal);
+ GET_FATAL_STACK_TRACE_PC_BP(pc, bp);
ReportExpectedUMRNotFound(&stack);
Die();
}
@@ -373,75 +415,66 @@ void __msan_print_shadow(const void *x, uptr size) {
Printf("Not a valid application address: %p\n", x);
return;
}
+
+ DescribeMemoryRange(x, size);
+}
+
+void __msan_dump_shadow(const void *x, uptr size) {
+ if (!MEM_IS_APP(x)) {
+ Printf("Not a valid application address: %p\n", x);
+ return;
+ }
+
unsigned char *s = (unsigned char*)MEM_TO_SHADOW(x);
- u32 *o = (u32*)MEM_TO_ORIGIN(x);
for (uptr i = 0; i < size; i++) {
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+ Printf("%x%x ", s[i] & 0xf, s[i] >> 4);
+#else
Printf("%x%x ", s[i] >> 4, s[i] & 0xf);
- }
- Printf("\n");
- if (__msan_get_track_origins()) {
- for (uptr i = 0; i < size / 4; i++) {
- Printf(" o: %x ", o[i]);
- }
- Printf("\n");
- }
-}
-
-void __msan_print_param_shadow() {
- for (int i = 0; i < 16; i++) {
- Printf("#%d:%zx ", i, __msan_param_tls[i]);
+#endif
}
Printf("\n");
}
sptr __msan_test_shadow(const void *x, uptr size) {
- unsigned char *s = (unsigned char*)MEM_TO_SHADOW((uptr)x);
+ if (!MEM_IS_APP(x)) return -1;
+ unsigned char *s = (unsigned char *)MEM_TO_SHADOW((uptr)x);
for (uptr i = 0; i < size; ++i)
if (s[i])
return i;
return -1;
}
+void __msan_check_mem_is_initialized(const void *x, uptr size) {
+ if (!__msan::flags()->report_umrs) return;
+ sptr offset = __msan_test_shadow(x, size);
+ if (offset < 0)
+ return;
+
+ GET_CALLER_PC_BP_SP;
+ (void)sp;
+ ReportUMRInsideAddressRange(__func__, x, size, offset);
+ __msan::PrintWarningWithOrigin(pc, bp,
+ __msan_get_origin(((const char *)x) + offset));
+ if (__msan::flags()->halt_on_error) {
+ Printf("Exiting\n");
+ Die();
+ }
+}
+
int __msan_set_poison_in_malloc(int do_poison) {
int old = flags()->poison_in_malloc;
flags()->poison_in_malloc = do_poison;
return old;
}
-int __msan_has_dynamic_component() {
- return msan_running_under_dr;
-}
+int __msan_has_dynamic_component() { return false; }
NOINLINE
void __msan_clear_on_return() {
__msan_param_tls[0] = 0;
}
-static void* get_tls_base() {
- u64 p;
- asm("mov %%fs:0, %0"
- : "=r"(p) ::);
- return (void*)p;
-}
-
-int __msan_get_retval_tls_offset() {
- // volatile here is needed to avoid UB, because the compiler thinks that we
- // are doing address arithmetics on unrelated pointers, and takes some
- // shortcuts
- volatile sptr retval_tls_p = (sptr)&__msan_retval_tls;
- volatile sptr tls_base_p = (sptr)get_tls_base();
- return retval_tls_p - tls_base_p;
-}
-
-int __msan_get_param_tls_offset() {
- // volatile here is needed to avoid UB, because the compiler thinks that we
- // are doing address arithmetics on unrelated pointers, and takes some
- // shortcuts
- volatile sptr param_tls_p = (sptr)&__msan_param_tls;
- volatile sptr tls_base_p = (sptr)get_tls_base();
- return param_tls_p - tls_base_p;
-}
-
void __msan_partial_poison(const void* data, void* shadow, uptr size) {
internal_memcpy((void*)MEM_TO_SHADOW((uptr)data), shadow, size);
}
@@ -460,8 +493,8 @@ void __msan_set_origin(const void *a, uptr size, u32 origin) {
uptr beg = x & ~3UL; // align down.
uptr end = (x + size + 3) & ~3UL; // align up.
u64 origin64 = ((u64)origin << 32) | origin;
- // This is like memset, but the value is 32-bit. We unroll by 2 two write
- // 64-bits at once. May want to unroll further to get 128-bit stores.
+ // This is like memset, but the value is 32-bit. We unroll by 2 to write
+ // 64 bits at once. May want to unroll further to get 128-bit stores.
if (beg & 7ULL) {
*(u32*)beg = origin;
beg += 4;
@@ -475,11 +508,11 @@ void __msan_set_origin(const void *a, uptr size, u32 origin) {
// 'descr' is created at compile time and contains '----' in the beginning.
// When we see descr for the first time we replace '----' with a uniq id
// and set the origin to (id | (31-th bit)).
-void __msan_set_alloca_origin(void *a, uptr size, const char *descr) {
+void __msan_set_alloca_origin(void *a, uptr size, char *descr) {
__msan_set_alloca_origin4(a, size, descr, 0);
}
-void __msan_set_alloca_origin4(void *a, uptr size, const char *descr, uptr pc) {
+void __msan_set_alloca_origin4(void *a, uptr size, char *descr, uptr pc) {
static const u32 dash = '-';
static const u32 first_timer =
dash + (dash << 8) + (dash << 16) + (dash << 24);
@@ -487,23 +520,25 @@ void __msan_set_alloca_origin4(void *a, uptr size, const char *descr, uptr pc) {
bool print = false; // internal_strstr(descr + 4, "AllocaTOTest") != 0;
u32 id = *id_ptr;
if (id == first_timer) {
- id = atomic_fetch_add(&NumStackOriginDescrs,
- 1, memory_order_relaxed);
+ u32 idx = atomic_fetch_add(&NumStackOriginDescrs, 1, memory_order_relaxed);
+ CHECK_LT(idx, kNumStackOriginDescrs);
+ StackOriginDescr[idx] = descr + 4;
+ StackOriginPC[idx] = pc;
+ id = Origin::CreateStackOrigin(idx).raw_id();
*id_ptr = id;
- CHECK_LT(id, kNumStackOriginDescrs);
- StackOriginDescr[id] = descr + 4;
- StackOriginPC[id] = pc;
if (print)
- Printf("First time: id=%d %s %p \n", id, descr + 4, pc);
+ Printf("First time: idx=%d id=%d %s %p \n", idx, id, descr + 4, pc);
}
- id |= 1U << 31;
if (print)
Printf("__msan_set_alloca_origin: descr=%s id=%x\n", descr + 4, id);
__msan_set_origin(a, size, id);
}
-const char *__msan_get_origin_descr_if_stack(u32 id) {
- return GetOriginDescrIfStack(id, 0);
+u32 __msan_chain_origin(u32 id) {
+ GET_CALLER_PC_BP_SP;
+ (void)sp;
+ GET_STORE_STACK_TRACE_PC_BP(pc, bp);
+ return ChainOrigin(id, &stack);
}
u32 __msan_get_origin(const void *a) {
@@ -521,40 +556,50 @@ u32 __msan_get_umr_origin() {
u16 __sanitizer_unaligned_load16(const uu16 *p) {
__msan_retval_tls[0] = *(uu16 *)MEM_TO_SHADOW((uptr)p);
if (__msan_get_track_origins())
- __msan_retval_origin_tls = *(uu32 *)MEM_TO_ORIGIN((uptr)p);
+ __msan_retval_origin_tls = GetOriginIfPoisoned((uptr)p, sizeof(*p));
return *p;
}
u32 __sanitizer_unaligned_load32(const uu32 *p) {
__msan_retval_tls[0] = *(uu32 *)MEM_TO_SHADOW((uptr)p);
if (__msan_get_track_origins())
- __msan_retval_origin_tls = *(uu32 *)MEM_TO_ORIGIN((uptr)p);
+ __msan_retval_origin_tls = GetOriginIfPoisoned((uptr)p, sizeof(*p));
return *p;
}
u64 __sanitizer_unaligned_load64(const uu64 *p) {
__msan_retval_tls[0] = *(uu64 *)MEM_TO_SHADOW((uptr)p);
if (__msan_get_track_origins())
- __msan_retval_origin_tls = *(uu32 *)MEM_TO_ORIGIN((uptr)p);
+ __msan_retval_origin_tls = GetOriginIfPoisoned((uptr)p, sizeof(*p));
return *p;
}
void __sanitizer_unaligned_store16(uu16 *p, u16 x) {
- *(uu16 *)MEM_TO_SHADOW((uptr)p) = __msan_param_tls[1];
- if (__msan_get_track_origins())
- *(uu32 *)MEM_TO_ORIGIN((uptr)p) = __msan_param_origin_tls[1];
+ u16 s = __msan_param_tls[1];
+ *(uu16 *)MEM_TO_SHADOW((uptr)p) = s;
+ if (s && __msan_get_track_origins())
+ if (uu32 o = __msan_param_origin_tls[2])
+ SetOriginIfPoisoned((uptr)p, (uptr)&s, sizeof(s), o);
*p = x;
}
void __sanitizer_unaligned_store32(uu32 *p, u32 x) {
- *(uu32 *)MEM_TO_SHADOW((uptr)p) = __msan_param_tls[1];
- if (__msan_get_track_origins())
- *(uu32 *)MEM_TO_ORIGIN((uptr)p) = __msan_param_origin_tls[1];
+ u32 s = __msan_param_tls[1];
+ *(uu32 *)MEM_TO_SHADOW((uptr)p) = s;
+ if (s && __msan_get_track_origins())
+ if (uu32 o = __msan_param_origin_tls[2])
+ SetOriginIfPoisoned((uptr)p, (uptr)&s, sizeof(s), o);
*p = x;
}
void __sanitizer_unaligned_store64(uu64 *p, u64 x) {
- *(uu64 *)MEM_TO_SHADOW((uptr)p) = __msan_param_tls[1];
- if (__msan_get_track_origins())
- *(uu32 *)MEM_TO_ORIGIN((uptr)p) = __msan_param_origin_tls[1];
+ u64 s = __msan_param_tls[1];
+ *(uu64 *)MEM_TO_SHADOW((uptr)p) = s;
+ if (s && __msan_get_track_origins())
+ if (uu32 o = __msan_param_origin_tls[2])
+ SetOriginIfPoisoned((uptr)p, (uptr)&s, sizeof(s), o);
*p = x;
}
+void __msan_set_death_callback(void (*callback)(void)) {
+ death_callback = callback;
+}
+
#if !SANITIZER_SUPPORTS_WEAK_HOOKS
extern "C" {
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
@@ -562,3 +607,10 @@ const char* __msan_default_options() { return ""; }
} // extern "C"
#endif
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_print_stack_trace() {
+ GET_FATAL_STACK_TRACE_PC_BP(StackTrace::GetCurrentPc(), GET_CURRENT_FRAME());
+ stack.Print();
+}
+} // extern "C"
diff --git a/lib/msan/msan.h b/lib/msan/msan.h
index 4e6c6194505e..9bc1e4c6a447 100644
--- a/lib/msan/msan.h
+++ b/lib/msan/msan.h
@@ -25,15 +25,94 @@
# define MSAN_REPLACE_OPERATORS_NEW_AND_DELETE 1
#endif
-#define MEM_TO_SHADOW(mem) (((uptr)mem) & ~0x400000000000ULL)
-#define SHADOW_TO_ORIGIN(shadow) (((uptr)shadow) + 0x200000000000ULL)
-#define MEM_TO_ORIGIN(mem) (SHADOW_TO_ORIGIN(MEM_TO_SHADOW(mem)))
-#define MEM_IS_APP(mem) ((uptr)mem >= 0x600000000000ULL)
+/*
+C/C++ on FreeBSD
+0000 0000 0000 - 00ff ffff ffff: Low memory: main binary, MAP_32BIT mappings and modules
+0100 0000 0000 - 0fff ffff ffff: Bad1
+1000 0000 0000 - 30ff ffff ffff: Shadow
+3100 0000 0000 - 37ff ffff ffff: Bad2
+3800 0000 0000 - 58ff ffff ffff: Origins
+5900 0000 0000 - 5fff ffff ffff: Bad3
+6000 0000 0000 - 7fff ffff ffff: High memory: heap, modules and main thread stack
+
+C/C++ on Linux/PIE
+0000 0000 0000 - 1fff ffff ffff: Bad1
+2000 0000 0000 - 3fff ffff ffff: Shadow
+4000 0000 0000 - 5fff ffff ffff: Origins
+6000 0000 0000 - 7fff ffff ffff: Main memory
+
+C/C++ on Mips
+0000 0000 0000 - 009f ffff ffff: Bad1
+00a0 0000 0000 - 00bf ffff ffff: Shadow
+00c0 0000 0000 - 00df ffff ffff: Origins
+00e0 0000 0000 - 00ff ffff ffff: Main memory
+*/
+
+#if SANITIZER_LINUX && defined(__mips64)
+const uptr kLowMemBeg = 0;
+const uptr kLowMemSize = 0;
+const uptr kHighMemBeg = 0x00e000000000;
+const uptr kHighMemSize = 0x002000000000;
+const uptr kShadowBeg = 0x00a000000000;
+const uptr kShadowSize = 0x002000000000;
+const uptr kOriginsBeg = 0x00c000000000;
+# define MEM_TO_SHADOW(mem) (((uptr)(mem)) & ~0x4000000000ULL)
+#elif SANITIZER_FREEBSD && SANITIZER_WORDSIZE == 64
+const uptr kLowMemBeg = 0x000000000000;
+const uptr kLowMemSize = 0x010000000000;
+const uptr kHighMemBeg = 0x600000000000;
+const uptr kHighMemSize = 0x200000000000;
+const uptr kShadowBeg = 0x100000000000;
+const uptr kShadowSize = 0x210000000000;
+const uptr kOriginsBeg = 0x380000000000;
+// Maps low and high app ranges to contiguous space with zero base:
+// Low: 0000 0000 0000 - 00ff ffff ffff -> 2000 0000 0000 - 20ff ffff ffff
+// High: 6000 0000 0000 - 7fff ffff ffff -> 0000 0000 0000 - 1fff ffff ffff
+# define LINEARIZE_MEM(mem) \
+ (((uptr)(mem) & ~0xc00000000000ULL) ^ 0x200000000000ULL)
+# define MEM_TO_SHADOW(mem) (LINEARIZE_MEM((mem)) + 0x100000000000ULL)
+#elif SANITIZER_LINUX && SANITIZER_WORDSIZE == 64
+const uptr kLowMemBeg = 0;
+const uptr kLowMemSize = 0;
+const uptr kHighMemBeg = 0x600000000000;
+const uptr kHighMemSize = 0x200000000000;
+const uptr kShadowBeg = 0x200000000000;
+const uptr kShadowSize = 0x200000000000;
+const uptr kOriginsBeg = 0x400000000000;
+# define MEM_TO_SHADOW(mem) (((uptr)(mem)) & ~0x400000000000ULL)
+#else
+#error "Unsupported platform"
+#endif
+
+const uptr kBad1Beg = kLowMemBeg + kLowMemSize;
+const uptr kBad1Size = kShadowBeg - kBad1Beg;
+
+const uptr kBad2Beg = kShadowBeg + kShadowSize;
+const uptr kBad2Size = kOriginsBeg - kBad2Beg;
+
+const uptr kOriginsSize = kShadowSize;
+
+const uptr kBad3Beg = kOriginsBeg + kOriginsSize;
+const uptr kBad3Size = kHighMemBeg - kBad3Beg;
+
+#define SHADOW_TO_ORIGIN(shadow) \
+ (((uptr)(shadow)) + (kOriginsBeg - kShadowBeg))
+
+#define MEM_TO_ORIGIN(mem) (SHADOW_TO_ORIGIN(MEM_TO_SHADOW((mem))))
+
+#define MEM_IS_APP(mem) \
+ ((kLowMemSize > 0 && (uptr)(mem) < kLowMemSize) || \
+ (uptr)(mem) >= kHighMemBeg)
+
#define MEM_IS_SHADOW(mem) \
- ((uptr)mem >= 0x200000000000ULL && (uptr)mem <= 0x400000000000ULL)
+ ((uptr)(mem) >= kShadowBeg && (uptr)(mem) < kShadowBeg + kShadowSize)
-const int kMsanParamTlsSizeInWords = 100;
-const int kMsanRetvalTlsSizeInWords = 100;
+#define MEM_IS_ORIGIN(mem) \
+ ((uptr)(mem) >= kOriginsBeg && (uptr)(mem) < kOriginsBeg + kOriginsSize)
+
+// These constants must be kept in sync with the ones in MemorySanitizer.cc.
+const int kMsanParamTlsSize = 800;
+const int kMsanRetvalTlsSize = 800;
namespace __msan {
extern int msan_inited;
@@ -41,7 +120,7 @@ extern bool msan_init_is_running;
extern int msan_report_count;
bool ProtectRange(uptr beg, uptr end);
-bool InitShadow(bool prot1, bool prot2, bool map_shadow, bool init_origins);
+bool InitShadow(bool map_shadow, bool init_origins);
char *GetProcSelfMaps();
void InitializeInterceptors();
@@ -53,7 +132,7 @@ void InstallTrapHandler();
void InstallAtExitHandler();
void ReplaceOperatorsNewAndDelete();
-const char *GetOriginDescrIfStack(u32 id, uptr *pc);
+const char *GetStackOriginDescr(u32 id, uptr *pc);
void EnterSymbolizer();
void ExitSymbolizer();
@@ -64,31 +143,56 @@ struct SymbolizerScope {
~SymbolizerScope() { ExitSymbolizer(); }
};
-void EnterLoader();
-void ExitLoader();
-
void MsanDie();
void PrintWarning(uptr pc, uptr bp);
void PrintWarningWithOrigin(uptr pc, uptr bp, u32 origin);
-void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp,
+void GetStackTrace(BufferedStackTrace *stack, uptr max_s, uptr pc, uptr bp,
bool request_fast_unwind);
void ReportUMR(StackTrace *stack, u32 origin);
void ReportExpectedUMRNotFound(StackTrace *stack);
+void ReportStats();
void ReportAtExitStatistics();
+void DescribeMemoryRange(const void *x, uptr size);
+void ReportUMRInsideAddressRange(const char *what, const void *start, uptr size,
+ uptr offset);
// Unpoison first n function arguments.
void UnpoisonParam(uptr n);
void UnpoisonThreadLocalState();
-#define GET_MALLOC_STACK_TRACE \
- StackTrace stack; \
- stack.size = 0; \
- if (__msan_get_track_origins() && msan_inited) \
- GetStackTrace(&stack, common_flags()->malloc_context_size, \
- StackTrace::GetCurrentPc(), GET_CURRENT_FRAME(), \
- common_flags()->fast_unwind_on_malloc)
+u32 GetOriginIfPoisoned(uptr a, uptr size);
+void SetOriginIfPoisoned(uptr addr, uptr src_shadow, uptr size, u32 src_origin);
+void CopyOrigin(void *dst, const void *src, uptr size, StackTrace *stack);
+void MovePoison(void *dst, const void *src, uptr size, StackTrace *stack);
+void CopyPoison(void *dst, const void *src, uptr size, StackTrace *stack);
+
+// Returns a "chained" origin id, pointing to the given stack trace followed by
+// the previous origin id.
+u32 ChainOrigin(u32 id, StackTrace *stack);
+
+#define GET_MALLOC_STACK_TRACE \
+ BufferedStackTrace stack; \
+ if (__msan_get_track_origins() && msan_inited) \
+ GetStackTrace(&stack, common_flags()->malloc_context_size, \
+ StackTrace::GetCurrentPc(), GET_CURRENT_FRAME(), \
+ common_flags()->fast_unwind_on_malloc)
+
+#define GET_STORE_STACK_TRACE_PC_BP(pc, bp) \
+ BufferedStackTrace stack; \
+ if (__msan_get_track_origins() > 1 && msan_inited) \
+ GetStackTrace(&stack, flags()->store_context_size, pc, bp, \
+ common_flags()->fast_unwind_on_malloc)
+
+#define GET_FATAL_STACK_TRACE_PC_BP(pc, bp) \
+ BufferedStackTrace stack; \
+ if (msan_inited) \
+ GetStackTrace(&stack, kStackTraceMax, pc, bp, \
+ common_flags()->fast_unwind_on_fatal)
+
+#define GET_STORE_STACK_TRACE \
+ GET_STORE_STACK_TRACE_PC_BP(StackTrace::GetCurrentPc(), GET_CURRENT_FRAME())
class ScopedThreadLocalStateBackup {
public:
@@ -99,11 +203,19 @@ class ScopedThreadLocalStateBackup {
private:
u64 va_arg_overflow_size_tls;
};
+
+extern void (*death_callback)(void);
+
+void MsanTSDInit(void (*destructor)(void *tsd));
+void *MsanTSDGet();
+void MsanTSDSet(void *tsd);
+void MsanTSDDtor(void *tsd);
+
} // namespace __msan
#define MSAN_MALLOC_HOOK(ptr, size) \
- if (&__msan_malloc_hook) __msan_malloc_hook(ptr, size)
+ if (&__sanitizer_malloc_hook) __sanitizer_malloc_hook(ptr, size)
#define MSAN_FREE_HOOK(ptr) \
- if (&__msan_free_hook) __msan_free_hook(ptr)
+ if (&__sanitizer_free_hook) __sanitizer_free_hook(ptr)
#endif // MSAN_H
diff --git a/lib/msan/msan_allocator.cc b/lib/msan/msan_allocator.cc
index 2badf712188b..f21d71409ce2 100644
--- a/lib/msan/msan_allocator.cc
+++ b/lib/msan/msan_allocator.cc
@@ -13,8 +13,11 @@
//===----------------------------------------------------------------------===//
#include "sanitizer_common/sanitizer_allocator.h"
-#include "sanitizer_common/sanitizer_stackdepot.h"
+#include "sanitizer_common/sanitizer_allocator_interface.h"
#include "msan.h"
+#include "msan_allocator.h"
+#include "msan_origin.h"
+#include "msan_thread.h"
namespace __msan {
@@ -22,20 +25,47 @@ struct Metadata {
uptr requested_size;
};
-static const uptr kAllocatorSpace = 0x600000000000ULL;
-static const uptr kAllocatorSize = 0x80000000000; // 8T.
-static const uptr kMetadataSize = sizeof(Metadata);
-static const uptr kMaxAllowedMallocSize = 8UL << 30;
+struct MsanMapUnmapCallback {
+ void OnMap(uptr p, uptr size) const {}
+ void OnUnmap(uptr p, uptr size) const {
+ __msan_unpoison((void *)p, size);
-typedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize, kMetadataSize,
- DefaultSizeClassMap> PrimaryAllocator;
+ // We are about to unmap a chunk of user memory.
+ // Mark the corresponding shadow memory as not needed.
+ FlushUnneededShadowMemory(MEM_TO_SHADOW(p), size);
+ if (__msan_get_track_origins())
+ FlushUnneededShadowMemory(MEM_TO_ORIGIN(p), size);
+ }
+};
+
+#if defined(__mips64)
+ static const uptr kMaxAllowedMallocSize = 2UL << 30;
+ 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;
+#elif defined(__x86_64__)
+ static const uptr kAllocatorSpace = 0x600000000000ULL;
+ 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;
+#endif
typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache;
-typedef LargeMmapAllocator<> SecondaryAllocator;
+typedef LargeMmapAllocator<MsanMapUnmapCallback> SecondaryAllocator;
typedef CombinedAllocator<PrimaryAllocator, AllocatorCache,
SecondaryAllocator> Allocator;
-static THREADLOCAL AllocatorCache cache;
static Allocator allocator;
+static AllocatorCache fallback_allocator_cache;
+static SpinMutex fallback_mutex;
static int inited = 0;
@@ -46,42 +76,55 @@ static inline void Init() {
allocator.Init();
}
-void MsanAllocatorThreadFinish() {
- allocator.SwallowCache(&cache);
+AllocatorCache *GetAllocatorCache(MsanThreadLocalMallocStorage *ms) {
+ CHECK(ms);
+ CHECK_LE(sizeof(AllocatorCache), sizeof(ms->allocator_cache));
+ return reinterpret_cast<AllocatorCache *>(ms->allocator_cache);
}
-static void *MsanAllocate(StackTrace *stack, uptr size,
- uptr alignment, bool zeroise) {
+void MsanThreadLocalMallocStorage::CommitBack() {
+ allocator.SwallowCache(GetAllocatorCache(this));
+}
+
+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);
return AllocatorReturnNull();
}
- void *res = allocator.Allocate(&cache, size, alignment, false);
- Metadata *meta = reinterpret_cast<Metadata*>(allocator.GetMetaData(res));
+ MsanThread *t = GetCurrentThread();
+ void *allocated;
+ if (t) {
+ AllocatorCache *cache = GetAllocatorCache(&t->malloc_storage());
+ allocated = allocator.Allocate(cache, size, alignment, false);
+ } else {
+ SpinMutexLock l(&fallback_mutex);
+ AllocatorCache *cache = &fallback_allocator_cache;
+ allocated = allocator.Allocate(cache, size, alignment, false);
+ }
+ Metadata *meta =
+ reinterpret_cast<Metadata *>(allocator.GetMetaData(allocated));
meta->requested_size = size;
if (zeroise) {
- __msan_clear_and_unpoison(res, size);
+ __msan_clear_and_unpoison(allocated, size);
} else if (flags()->poison_in_malloc) {
- __msan_poison(res, size);
+ __msan_poison(allocated, size);
if (__msan_get_track_origins()) {
- u32 stack_id = StackDepotPut(stack->trace, stack->size);
- CHECK(stack_id);
- CHECK_EQ((stack_id >> 31),
- 0); // Higher bit is occupied by stack origins.
- __msan_set_origin(res, size, stack_id);
+ Origin o = Origin::CreateHeapOrigin(stack);
+ __msan_set_origin(allocated, size, o.raw_id());
}
}
- MSAN_MALLOC_HOOK(res, size);
- return res;
+ MSAN_MALLOC_HOOK(allocated, size);
+ return allocated;
}
void MsanDeallocate(StackTrace *stack, void *p) {
CHECK(p);
Init();
MSAN_FREE_HOOK(p);
- Metadata *meta = reinterpret_cast<Metadata*>(allocator.GetMetaData(p));
+ Metadata *meta = reinterpret_cast<Metadata *>(allocator.GetMetaData(p));
uptr size = meta->requested_size;
meta->requested_size = 0;
// This memory will not be reused by anyone else, so we are free to keep it
@@ -89,14 +132,19 @@ void MsanDeallocate(StackTrace *stack, void *p) {
if (flags()->poison_in_free) {
__msan_poison(p, size);
if (__msan_get_track_origins()) {
- u32 stack_id = StackDepotPut(stack->trace, stack->size);
- CHECK(stack_id);
- CHECK_EQ((stack_id >> 31),
- 0); // Higher bit is occupied by stack origins.
- __msan_set_origin(p, size, stack_id);
+ Origin o = Origin::CreateHeapOrigin(stack);
+ __msan_set_origin(p, size, o.raw_id());
}
}
- allocator.Deallocate(&cache, p);
+ MsanThread *t = GetCurrentThread();
+ if (t) {
+ AllocatorCache *cache = GetAllocatorCache(&t->malloc_storage());
+ allocator.Deallocate(cache, p);
+ } else {
+ SpinMutexLock l(&fallback_mutex);
+ AllocatorCache *cache = &fallback_allocator_cache;
+ allocator.Deallocate(cache, p);
+ }
}
void *MsanReallocate(StackTrace *stack, void *old_p, uptr new_size,
@@ -128,12 +176,10 @@ void *MsanReallocate(StackTrace *stack, void *old_p, uptr new_size,
}
static uptr AllocationSize(const void *p) {
- if (p == 0)
- return 0;
+ if (p == 0) return 0;
const void *beg = allocator.GetBlockBegin(p);
- if (beg != p)
- return 0;
- Metadata *b = (Metadata*)allocator.GetMetaData(p);
+ if (beg != p) return 0;
+ Metadata *b = (Metadata *)allocator.GetMetaData(p);
return b->requested_size;
}
@@ -141,38 +187,24 @@ static uptr AllocationSize(const void *p) {
using namespace __msan;
-uptr __msan_get_current_allocated_bytes() {
- u64 stats[AllocatorStatCount];
+uptr __sanitizer_get_current_allocated_bytes() {
+ uptr stats[AllocatorStatCount];
allocator.GetStats(stats);
- u64 m = stats[AllocatorStatMalloced];
- u64 f = stats[AllocatorStatFreed];
- return m >= f ? m - f : 1;
+ return stats[AllocatorStatAllocated];
}
-uptr __msan_get_heap_size() {
- u64 stats[AllocatorStatCount];
+uptr __sanitizer_get_heap_size() {
+ uptr stats[AllocatorStatCount];
allocator.GetStats(stats);
- u64 m = stats[AllocatorStatMmapped];
- u64 f = stats[AllocatorStatUnmapped];
- return m >= f ? m - f : 1;
+ return stats[AllocatorStatMapped];
}
-uptr __msan_get_free_bytes() {
- return 1;
-}
+uptr __sanitizer_get_free_bytes() { return 1; }
-uptr __msan_get_unmapped_bytes() {
- return 1;
-}
+uptr __sanitizer_get_unmapped_bytes() { return 1; }
-uptr __msan_get_estimated_allocated_size(uptr size) {
- return size;
-}
+uptr __sanitizer_get_estimated_allocated_size(uptr size) { return size; }
-int __msan_get_ownership(const void *p) {
- return AllocationSize(p) != 0;
-}
+int __sanitizer_get_ownership(const void *p) { return AllocationSize(p) != 0; }
-uptr __msan_get_allocated_size(const void *p) {
- return AllocationSize(p);
-}
+uptr __sanitizer_get_allocated_size(const void *p) { return AllocationSize(p); }
diff --git a/lib/msan/msan_allocator.h b/lib/msan/msan_allocator.h
new file mode 100644
index 000000000000..407942e54c1a
--- /dev/null
+++ b/lib/msan/msan_allocator.h
@@ -0,0 +1,33 @@
+//===-- msan_allocator.h ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of MemorySanitizer.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MSAN_ALLOCATOR_H
+#define MSAN_ALLOCATOR_H
+
+#include "sanitizer_common/sanitizer_common.h"
+
+namespace __msan {
+
+struct MsanThreadLocalMallocStorage {
+ uptr quarantine_cache[16];
+ // Allocator cache contains atomic_uint64_t which must be 8-byte aligned.
+ ALIGNED(8) uptr allocator_cache[96 * (512 * 8 + 16)]; // Opaque.
+ void CommitBack();
+
+ private:
+ // These objects are allocated via mmap() and are zero-initialized.
+ MsanThreadLocalMallocStorage() {}
+};
+
+} // namespace __msan
+#endif // MSAN_ALLOCATOR_H
diff --git a/lib/msan/msan_chained_origin_depot.cc b/lib/msan/msan_chained_origin_depot.cc
new file mode 100644
index 000000000000..c21e8e82746a
--- /dev/null
+++ b/lib/msan/msan_chained_origin_depot.cc
@@ -0,0 +1,126 @@
+//===-- msan_chained_origin_depot.cc -----------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// A storage for chained origins.
+//===----------------------------------------------------------------------===//
+
+#include "msan_chained_origin_depot.h"
+
+#include "sanitizer_common/sanitizer_stackdepotbase.h"
+
+namespace __msan {
+
+struct ChainedOriginDepotDesc {
+ u32 here_id;
+ u32 prev_id;
+};
+
+struct ChainedOriginDepotNode {
+ ChainedOriginDepotNode *link;
+ u32 id;
+ u32 here_id;
+ 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).
+
+ here_id is built of
+ * (1 bits) Reserved, zero.
+ * (8 bits) Part id = bits 13..20 of the hash value of here_id's key.
+ * (23 bits) Sequential number (each part has each own sequence).
+
+ prev_id has either the same distribution as here_id (but with 3:8:21)
+ split, or one of two reserved values (-1) or (-2). Either case can
+ dominate depending on the workload.
+ */
+ static u32 hash(const args_type &args) {
+ const u32 m = 0x5bd1e995;
+ const u32 seed = 0x9747b28c;
+ const u32 r = 24;
+ u32 h = seed;
+ u32 k = args.here_id;
+ k *= m;
+ k ^= k >> r;
+ k *= m;
+ h *= m;
+ h ^= k;
+
+ k = args.prev_id;
+ k *= m;
+ k ^= k >> r;
+ k *= m;
+ h *= m;
+ h ^= k;
+
+ h ^= h >> 13;
+ h *= m;
+ h ^= h >> 15;
+ return h;
+ }
+ static bool is_valid(const args_type &args) { return true; }
+ void store(const args_type &args, u32 other_hash) {
+ 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) {}
+ 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;
+};
+
+static StackDepotBase<ChainedOriginDepotNode, 4, 20> chainedOriginDepot;
+
+StackDepotStats *ChainedOriginDepotGetStats() {
+ return chainedOriginDepot.GetStats();
+}
+
+bool ChainedOriginDepotPut(u32 here_id, u32 prev_id, u32 *new_id) {
+ ChainedOriginDepotDesc desc = {here_id, prev_id};
+ bool inserted;
+ ChainedOriginDepotNode::Handle h = chainedOriginDepot.Put(desc, &inserted);
+ *new_id = h.valid() ? h.id() : 0;
+ return inserted;
+}
+
+// Retrieves a stored stack trace by the id.
+u32 ChainedOriginDepotGet(u32 id, u32 *other) {
+ ChainedOriginDepotDesc desc = chainedOriginDepot.Get(id);
+ *other = desc.prev_id;
+ return desc.here_id;
+}
+
+void ChainedOriginDepotLockAll() {
+ chainedOriginDepot.LockAll();
+}
+
+void ChainedOriginDepotUnlockAll() {
+ chainedOriginDepot.UnlockAll();
+}
+
+} // namespace __msan
diff --git a/lib/msan/msan_chained_origin_depot.h b/lib/msan/msan_chained_origin_depot.h
new file mode 100644
index 000000000000..f7a71cef205f
--- /dev/null
+++ b/lib/msan/msan_chained_origin_depot.h
@@ -0,0 +1,29 @@
+//===-- msan_chained_origin_depot.h --------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// A storage for chained origins.
+//===----------------------------------------------------------------------===//
+#ifndef MSAN_CHAINED_ORIGIN_DEPOT_H
+#define MSAN_CHAINED_ORIGIN_DEPOT_H
+
+#include "sanitizer_common/sanitizer_common.h"
+
+namespace __msan {
+
+StackDepotStats *ChainedOriginDepotGetStats();
+bool ChainedOriginDepotPut(u32 here_id, u32 prev_id, u32 *new_id);
+// Retrieves a stored stack trace by the id.
+u32 ChainedOriginDepotGet(u32 id, u32 *other);
+
+void ChainedOriginDepotLockAll();
+void ChainedOriginDepotUnlockAll();
+
+} // namespace __msan
+
+#endif // MSAN_CHAINED_ORIGIN_DEPOT_H
diff --git a/lib/msan/msan_flags.h b/lib/msan/msan_flags.h
index 93fa8a60dba0..9b93f118a985 100644
--- a/lib/msan/msan_flags.h
+++ b/lib/msan/msan_flags.h
@@ -19,13 +19,18 @@ namespace __msan {
// Flags.
struct Flags {
int exit_code;
+ int origin_history_size;
+ int origin_history_per_stack_limit;
bool poison_heap_with_zeroes; // default: false
bool poison_stack_with_zeroes; // default: false
bool poison_in_malloc; // default: true
bool poison_in_free; // default: true
bool report_umrs;
bool wrap_signals;
+ bool print_stats;
bool halt_on_error;
+ bool atexit;
+ int store_context_size; // like malloc_context_size, but for uninit stores
};
Flags *flags();
diff --git a/lib/msan/msan_interceptors.cc b/lib/msan/msan_interceptors.cc
index 15a8bec12f31..bbdf18e162a3 100644
--- a/lib/msan/msan_interceptors.cc
+++ b/lib/msan/msan_interceptors.cc
@@ -17,14 +17,19 @@
#include "interception/interception.h"
#include "msan.h"
+#include "msan_chained_origin_depot.h"
+#include "msan_origin.h"
+#include "msan_thread.h"
#include "sanitizer_common/sanitizer_platform_limits_posix.h"
#include "sanitizer_common/sanitizer_allocator.h"
+#include "sanitizer_common/sanitizer_allocator_interface.h"
#include "sanitizer_common/sanitizer_allocator_internal.h"
#include "sanitizer_common/sanitizer_atomic.h"
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_stackdepot.h"
#include "sanitizer_common/sanitizer_libc.h"
#include "sanitizer_common/sanitizer_linux.h"
+#include "sanitizer_common/sanitizer_tls_get_addr.h"
#include <stdarg.h>
// ACHTUNG! No other system header includes in this file.
@@ -37,11 +42,15 @@ using __sanitizer::atomic_load;
using __sanitizer::atomic_store;
using __sanitizer::atomic_uintptr_t;
-static unsigned g_thread_finalize_key;
+#if SANITIZER_FREEBSD
+#define __errno_location __error
+#endif
// True if this is a nested interceptor.
static THREADLOCAL int in_interceptor_scope;
+extern "C" int *__errno_location(void);
+
struct InterceptorScope {
InterceptorScope() { ++in_interceptor_scope; }
~InterceptorScope() { --in_interceptor_scope; }
@@ -59,22 +68,22 @@ bool IsInInterceptorScope() {
} while (0)
// Check that [x, x+n) range is unpoisoned.
-#define CHECK_UNPOISONED_0(x, n) \
- do { \
- sptr offset = __msan_test_shadow(x, n); \
- if (__msan::IsInSymbolizer()) break; \
- if (offset >= 0 && __msan::flags()->report_umrs) { \
- GET_CALLER_PC_BP_SP; \
- (void) sp; \
- Printf("UMR in %s at offset %d inside [%p, +%d) \n", __FUNCTION__, \
- offset, x, n); \
- __msan::PrintWarningWithOrigin(pc, bp, \
- __msan_get_origin((char *)x + offset)); \
- if (__msan::flags()->halt_on_error) { \
- Printf("Exiting\n"); \
- Die(); \
- } \
- } \
+#define CHECK_UNPOISONED_0(x, n) \
+ do { \
+ sptr offset = __msan_test_shadow(x, n); \
+ if (__msan::IsInSymbolizer()) \
+ break; \
+ if (offset >= 0 && __msan::flags()->report_umrs) { \
+ GET_CALLER_PC_BP_SP; \
+ (void) sp; \
+ ReportUMRInsideAddressRange(__func__, x, n, offset); \
+ __msan::PrintWarningWithOrigin( \
+ pc, bp, __msan_get_origin((const char *)x + offset)); \
+ if (__msan::flags()->halt_on_error) { \
+ Printf("Exiting\n"); \
+ Die(); \
+ } \
+ } \
} while (0)
// Check that [x, x+n) range is unpoisoned unless we are in a nested
@@ -84,9 +93,6 @@ bool IsInInterceptorScope() {
if (!IsInInterceptorScope()) CHECK_UNPOISONED_0(x, n); \
} while (0);
-static void *fast_memset(void *ptr, int c, SIZE_T n);
-static void *fast_memcpy(void *dst, const void *src, SIZE_T n);
-
INTERCEPTOR(SIZE_T, fread, void *ptr, SIZE_T size, SIZE_T nmemb, void *file) {
ENSURE_MSAN_INITED();
SIZE_T res = REAL(fread)(ptr, size, nmemb, file);
@@ -95,6 +101,7 @@ INTERCEPTOR(SIZE_T, fread, void *ptr, SIZE_T size, SIZE_T nmemb, void *file) {
return res;
}
+#if !SANITIZER_FREEBSD
INTERCEPTOR(SIZE_T, fread_unlocked, void *ptr, SIZE_T size, SIZE_T nmemb,
void *file) {
ENSURE_MSAN_INITED();
@@ -103,6 +110,10 @@ INTERCEPTOR(SIZE_T, fread_unlocked, void *ptr, SIZE_T size, SIZE_T nmemb,
__msan_unpoison(ptr, res *size);
return res;
}
+#define MSAN_MAYBE_INTERCEPT_FREAD_UNLOCKED INTERCEPT_FUNCTION(fread_unlocked)
+#else
+#define MSAN_MAYBE_INTERCEPT_FREAD_UNLOCKED
+#endif
INTERCEPTOR(SSIZE_T, readlink, const char *path, char *buf, SIZE_T bufsiz) {
ENSURE_MSAN_INITED();
@@ -152,12 +163,32 @@ INTERCEPTOR(int, posix_memalign, void **memptr, SIZE_T alignment, SIZE_T size) {
return 0;
}
+#if !SANITIZER_FREEBSD
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);
return ptr;
}
+#define MSAN_MAYBE_INTERCEPT_MEMALIGN INTERCEPT_FUNCTION(memalign)
+#else
+#define MSAN_MAYBE_INTERCEPT_MEMALIGN
+#endif
+
+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);
+ 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);
+ DTLS_on_libc_memalign(ptr, size * boundary);
+ return ptr;
+}
INTERCEPTOR(void *, valloc, SIZE_T size) {
GET_MALLOC_STACK_TRACE;
@@ -165,6 +196,7 @@ INTERCEPTOR(void *, valloc, SIZE_T size) {
return ptr;
}
+#if !SANITIZER_FREEBSD
INTERCEPTOR(void *, pvalloc, SIZE_T size) {
GET_MALLOC_STACK_TRACE;
uptr PageSize = GetPageSizeCached();
@@ -176,6 +208,10 @@ INTERCEPTOR(void *, pvalloc, SIZE_T size) {
void *ptr = MsanReallocate(&stack, 0, size, PageSize, false);
return ptr;
}
+#define MSAN_MAYBE_INTERCEPT_PVALLOC INTERCEPT_FUNCTION(pvalloc)
+#else
+#define MSAN_MAYBE_INTERCEPT_PVALLOC
+#endif
INTERCEPTOR(void, free, void *ptr) {
GET_MALLOC_STACK_TRACE;
@@ -183,7 +219,55 @@ INTERCEPTOR(void, free, void *ptr) {
MsanDeallocate(&stack, ptr);
}
+#if !SANITIZER_FREEBSD
+INTERCEPTOR(void, cfree, void *ptr) {
+ GET_MALLOC_STACK_TRACE;
+ if (ptr == 0) return;
+ MsanDeallocate(&stack, ptr);
+}
+#define MSAN_MAYBE_INTERCEPT_CFREE INTERCEPT_FUNCTION(cfree)
+#else
+#define MSAN_MAYBE_INTERCEPT_CFREE
+#endif
+
+INTERCEPTOR(uptr, malloc_usable_size, void *ptr) {
+ return __sanitizer_get_allocated_size(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.
+INTERCEPTOR(void, mallinfo, __sanitizer_mallinfo *sret) {
+ REAL(memset)(sret, 0, sizeof(*sret));
+ __msan_unpoison(sret, sizeof(*sret));
+}
+#define MSAN_MAYBE_INTERCEPT_MALLINFO INTERCEPT_FUNCTION(mallinfo)
+#else
+#define MSAN_MAYBE_INTERCEPT_MALLINFO
+#endif
+
+#if !SANITIZER_FREEBSD
+INTERCEPTOR(int, mallopt, int cmd, int value) {
+ return -1;
+}
+#define MSAN_MAYBE_INTERCEPT_MALLOPT INTERCEPT_FUNCTION(mallopt)
+#else
+#define MSAN_MAYBE_INTERCEPT_MALLOPT
+#endif
+
+#if !SANITIZER_FREEBSD
+INTERCEPTOR(void, malloc_stats, void) {
+ // FIXME: implement, but don't call REAL(malloc_stats)!
+}
+#define MSAN_MAYBE_INTERCEPT_MALLOC_STATS INTERCEPT_FUNCTION(malloc_stats)
+#else
+#define MSAN_MAYBE_INTERCEPT_MALLOC_STATS
+#endif
+
INTERCEPTOR(SIZE_T, strlen, const char *s) {
+ if (msan_init_is_running)
+ return REAL(strlen)(s);
ENSURE_MSAN_INITED();
SIZE_T res = REAL(strlen)(s);
CHECK_UNPOISONED(s, res + 1);
@@ -203,304 +287,261 @@ INTERCEPTOR(SIZE_T, strnlen, const char *s, SIZE_T n) {
INTERCEPTOR(char *, strcpy, char *dest, const char *src) { // NOLINT
ENSURE_MSAN_INITED();
+ GET_STORE_STACK_TRACE;
SIZE_T n = REAL(strlen)(src);
char *res = REAL(strcpy)(dest, src); // NOLINT
- __msan_copy_poison(dest, src, n + 1);
+ CopyPoison(dest, src, n + 1, &stack);
return res;
}
INTERCEPTOR(char *, strncpy, char *dest, const char *src, SIZE_T n) { // NOLINT
ENSURE_MSAN_INITED();
+ GET_STORE_STACK_TRACE;
SIZE_T copy_size = REAL(strnlen)(src, n);
if (copy_size < n)
copy_size++; // trailing \0
char *res = REAL(strncpy)(dest, src, n); // NOLINT
- __msan_copy_poison(dest, src, copy_size);
+ CopyPoison(dest, src, copy_size, &stack);
+ __msan_unpoison(dest + copy_size, n - copy_size);
return res;
}
INTERCEPTOR(char *, stpcpy, char *dest, const char *src) { // NOLINT
ENSURE_MSAN_INITED();
+ GET_STORE_STACK_TRACE;
SIZE_T n = REAL(strlen)(src);
char *res = REAL(stpcpy)(dest, src); // NOLINT
- __msan_copy_poison(dest, src, n + 1);
+ CopyPoison(dest, src, n + 1, &stack);
return res;
}
INTERCEPTOR(char *, strdup, char *src) {
ENSURE_MSAN_INITED();
+ GET_STORE_STACK_TRACE;
SIZE_T n = REAL(strlen)(src);
char *res = REAL(strdup)(src);
- __msan_copy_poison(res, src, n + 1);
+ CopyPoison(res, src, n + 1, &stack);
return res;
}
+#if !SANITIZER_FREEBSD
INTERCEPTOR(char *, __strdup, char *src) {
ENSURE_MSAN_INITED();
+ GET_STORE_STACK_TRACE;
SIZE_T n = REAL(strlen)(src);
char *res = REAL(__strdup)(src);
- __msan_copy_poison(res, src, n + 1);
+ CopyPoison(res, src, n + 1, &stack);
return res;
}
+#define MSAN_MAYBE_INTERCEPT___STRDUP INTERCEPT_FUNCTION(__strdup)
+#else
+#define MSAN_MAYBE_INTERCEPT___STRDUP
+#endif
INTERCEPTOR(char *, strndup, char *src, SIZE_T n) {
ENSURE_MSAN_INITED();
+ GET_STORE_STACK_TRACE;
SIZE_T copy_size = REAL(strnlen)(src, n);
char *res = REAL(strndup)(src, n);
- __msan_copy_poison(res, src, copy_size);
+ CopyPoison(res, src, copy_size, &stack);
__msan_unpoison(res + copy_size, 1); // \0
return res;
}
+#if !SANITIZER_FREEBSD
INTERCEPTOR(char *, __strndup, char *src, SIZE_T n) {
ENSURE_MSAN_INITED();
+ GET_STORE_STACK_TRACE;
SIZE_T copy_size = REAL(strnlen)(src, n);
char *res = REAL(__strndup)(src, n);
- __msan_copy_poison(res, src, copy_size);
+ CopyPoison(res, src, copy_size, &stack);
__msan_unpoison(res + copy_size, 1); // \0
return res;
}
+#define MSAN_MAYBE_INTERCEPT___STRNDUP INTERCEPT_FUNCTION(__strndup)
+#else
+#define MSAN_MAYBE_INTERCEPT___STRNDUP
+#endif
INTERCEPTOR(char *, gcvt, double number, SIZE_T ndigit, char *buf) {
ENSURE_MSAN_INITED();
char *res = REAL(gcvt)(number, ndigit, buf);
- // DynamoRio tool will take care of unpoisoning gcvt result for us.
- if (!__msan_has_dynamic_component()) {
- SIZE_T n = REAL(strlen)(buf);
- __msan_unpoison(buf, n + 1);
- }
+ SIZE_T n = REAL(strlen)(buf);
+ __msan_unpoison(buf, n + 1);
return res;
}
INTERCEPTOR(char *, strcat, char *dest, const char *src) { // NOLINT
ENSURE_MSAN_INITED();
+ GET_STORE_STACK_TRACE;
SIZE_T src_size = REAL(strlen)(src);
SIZE_T dest_size = REAL(strlen)(dest);
char *res = REAL(strcat)(dest, src); // NOLINT
- __msan_copy_poison(dest + dest_size, src, src_size + 1);
+ CopyPoison(dest + dest_size, src, src_size + 1, &stack);
return res;
}
INTERCEPTOR(char *, strncat, char *dest, const char *src, SIZE_T n) { // NOLINT
ENSURE_MSAN_INITED();
+ GET_STORE_STACK_TRACE;
SIZE_T dest_size = REAL(strlen)(dest);
- SIZE_T copy_size = REAL(strlen)(src);
- if (copy_size < n)
- copy_size++; // trailing \0
+ SIZE_T copy_size = REAL(strnlen)(src, n);
char *res = REAL(strncat)(dest, src, n); // NOLINT
- __msan_copy_poison(dest + dest_size, src, copy_size);
- return res;
-}
-
-INTERCEPTOR(long, strtol, const char *nptr, char **endptr, // NOLINT
- int base) {
- ENSURE_MSAN_INITED();
- long res = REAL(strtol)(nptr, endptr, base); // NOLINT
- if (!__msan_has_dynamic_component()) {
- __msan_unpoison(endptr, sizeof(*endptr));
- }
- return res;
-}
-
-INTERCEPTOR(long long, strtoll, const char *nptr, char **endptr, // NOLINT
- int base) {
- ENSURE_MSAN_INITED();
- long res = REAL(strtoll)(nptr, endptr, base); //NOLINT
- if (!__msan_has_dynamic_component()) {
- __msan_unpoison(endptr, sizeof(*endptr));
- }
- return res;
-}
-
-INTERCEPTOR(unsigned long, strtoul, const char *nptr, char **endptr, // NOLINT
- int base) {
- ENSURE_MSAN_INITED();
- unsigned long res = REAL(strtoul)(nptr, endptr, base); // NOLINT
- if (!__msan_has_dynamic_component()) {
- __msan_unpoison(endptr, sizeof(*endptr));
- }
- return res;
-}
-
-INTERCEPTOR(unsigned long long, strtoull, const char *nptr, // NOLINT
- char **endptr, int base) {
- ENSURE_MSAN_INITED();
- unsigned long res = REAL(strtoull)(nptr, endptr, base); // NOLINT
- if (!__msan_has_dynamic_component()) {
- __msan_unpoison(endptr, sizeof(*endptr));
- }
- return res;
-}
-
-INTERCEPTOR(double, strtod, const char *nptr, char **endptr) { // NOLINT
- ENSURE_MSAN_INITED();
- double res = REAL(strtod)(nptr, endptr); // NOLINT
- if (!__msan_has_dynamic_component()) {
- __msan_unpoison(endptr, sizeof(*endptr));
- }
- return res;
-}
-
-INTERCEPTOR(double, strtod_l, const char *nptr, char **endptr,
- void *loc) { // NOLINT
- ENSURE_MSAN_INITED();
- double res = REAL(strtod_l)(nptr, endptr, loc); // NOLINT
- if (!__msan_has_dynamic_component()) {
- __msan_unpoison(endptr, sizeof(*endptr));
- }
- return res;
-}
-
-INTERCEPTOR(double, __strtod_l, const char *nptr, char **endptr,
- void *loc) { // NOLINT
- ENSURE_MSAN_INITED();
- double res = REAL(__strtod_l)(nptr, endptr, loc); // NOLINT
- if (!__msan_has_dynamic_component()) {
- __msan_unpoison(endptr, sizeof(*endptr));
- }
- return res;
-}
-
-INTERCEPTOR(float, strtof, const char *nptr, char **endptr) { // NOLINT
- ENSURE_MSAN_INITED();
- float res = REAL(strtof)(nptr, endptr); // NOLINT
- if (!__msan_has_dynamic_component()) {
- __msan_unpoison(endptr, sizeof(*endptr));
- }
+ CopyPoison(dest + dest_size, src, copy_size, &stack);
+ __msan_unpoison(dest + dest_size + copy_size, 1); // \0
return res;
}
-INTERCEPTOR(float, strtof_l, const char *nptr, char **endptr,
- void *loc) { // NOLINT
- ENSURE_MSAN_INITED();
- float res = REAL(strtof_l)(nptr, endptr, loc); // NOLINT
- if (!__msan_has_dynamic_component()) {
- __msan_unpoison(endptr, sizeof(*endptr));
- }
+// Hack: always pass nptr and endptr as part of __VA_ARGS_ to avoid having to
+// deal with empty __VA_ARGS__ in the case of INTERCEPTOR_STRTO.
+#define INTERCEPTOR_STRTO_BODY(ret_type, func, ...) \
+ ENSURE_MSAN_INITED(); \
+ ret_type res = REAL(func)(__VA_ARGS__); \
+ __msan_unpoison(endptr, sizeof(*endptr)); \
return res;
-}
-INTERCEPTOR(float, __strtof_l, const char *nptr, char **endptr,
- void *loc) { // NOLINT
- ENSURE_MSAN_INITED();
- float res = REAL(__strtof_l)(nptr, endptr, loc); // NOLINT
- if (!__msan_has_dynamic_component()) {
- __msan_unpoison(endptr, sizeof(*endptr));
+#define INTERCEPTOR_STRTO(ret_type, func, char_type) \
+ INTERCEPTOR(ret_type, func, const char_type *nptr, char_type **endptr) { \
+ INTERCEPTOR_STRTO_BODY(ret_type, func, nptr, endptr); \
}
- return res;
-}
-INTERCEPTOR(long double, strtold, const char *nptr, char **endptr) { // NOLINT
- ENSURE_MSAN_INITED();
- long double res = REAL(strtold)(nptr, endptr); // NOLINT
- if (!__msan_has_dynamic_component()) {
- __msan_unpoison(endptr, sizeof(*endptr));
+#define INTERCEPTOR_STRTO_BASE(ret_type, func, char_type) \
+ INTERCEPTOR(ret_type, func, const char_type *nptr, char_type **endptr, \
+ int base) { \
+ INTERCEPTOR_STRTO_BODY(ret_type, func, nptr, endptr, base); \
}
- return res;
-}
-INTERCEPTOR(long double, strtold_l, const char *nptr, char **endptr,
- void *loc) { // NOLINT
- ENSURE_MSAN_INITED();
- long double res = REAL(strtold_l)(nptr, endptr, loc); // NOLINT
- if (!__msan_has_dynamic_component()) {
- __msan_unpoison(endptr, sizeof(*endptr));
+#define INTERCEPTOR_STRTO_LOC(ret_type, func, char_type) \
+ INTERCEPTOR(ret_type, func, const char_type *nptr, char_type **endptr, \
+ void *loc) { \
+ INTERCEPTOR_STRTO_BODY(ret_type, func, nptr, endptr, loc); \
}
- return res;
-}
-INTERCEPTOR(long double, __strtold_l, const char *nptr, char **endptr,
- void *loc) { // NOLINT
- ENSURE_MSAN_INITED();
- long double res = REAL(__strtold_l)(nptr, endptr, loc); // NOLINT
- if (!__msan_has_dynamic_component()) {
- __msan_unpoison(endptr, sizeof(*endptr));
+#define INTERCEPTOR_STRTO_BASE_LOC(ret_type, func, char_type) \
+ INTERCEPTOR(ret_type, func, const char_type *nptr, char_type **endptr, \
+ int base, void *loc) { \
+ INTERCEPTOR_STRTO_BODY(ret_type, func, nptr, endptr, base, loc); \
}
- return res;
-}
-INTERCEPTOR(int, vasprintf, char **strp, const char *format, va_list ap) {
+#define INTERCEPTORS_STRTO(ret_type, func, char_type) \
+ INTERCEPTOR_STRTO(ret_type, func, char_type) \
+ INTERCEPTOR_STRTO_LOC(ret_type, func##_l, char_type) \
+ INTERCEPTOR_STRTO_LOC(ret_type, __##func##_l, char_type) \
+ INTERCEPTOR_STRTO_LOC(ret_type, __##func##_internal, char_type)
+
+#define INTERCEPTORS_STRTO_BASE(ret_type, func, char_type) \
+ INTERCEPTOR_STRTO_BASE(ret_type, func, char_type) \
+ INTERCEPTOR_STRTO_BASE_LOC(ret_type, func##_l, char_type) \
+ INTERCEPTOR_STRTO_BASE_LOC(ret_type, __##func##_l, char_type) \
+ INTERCEPTOR_STRTO_BASE_LOC(ret_type, __##func##_internal, char_type)
+
+INTERCEPTORS_STRTO(double, strtod, char) // NOLINT
+INTERCEPTORS_STRTO(float, strtof, char) // NOLINT
+INTERCEPTORS_STRTO(long double, strtold, char) // NOLINT
+INTERCEPTORS_STRTO_BASE(long, strtol, char) // NOLINT
+INTERCEPTORS_STRTO_BASE(long long, strtoll, char) // NOLINT
+INTERCEPTORS_STRTO_BASE(unsigned long, strtoul, char) // NOLINT
+INTERCEPTORS_STRTO_BASE(unsigned long long, strtoull, char) // NOLINT
+
+INTERCEPTORS_STRTO(double, wcstod, wchar_t) // NOLINT
+INTERCEPTORS_STRTO(float, wcstof, wchar_t) // NOLINT
+INTERCEPTORS_STRTO(long double, wcstold, wchar_t) // NOLINT
+INTERCEPTORS_STRTO_BASE(long, wcstol, wchar_t) // NOLINT
+INTERCEPTORS_STRTO_BASE(long long, wcstoll, wchar_t) // NOLINT
+INTERCEPTORS_STRTO_BASE(unsigned long, wcstoul, wchar_t) // NOLINT
+INTERCEPTORS_STRTO_BASE(unsigned long long, wcstoull, wchar_t) // NOLINT
+
+#define INTERCEPT_STRTO(func) \
+ INTERCEPT_FUNCTION(func); \
+ INTERCEPT_FUNCTION(func##_l); \
+ INTERCEPT_FUNCTION(__##func##_l); \
+ INTERCEPT_FUNCTION(__##func##_internal);
+
+
+// FIXME: support *wprintf in common format interceptors.
+INTERCEPTOR(int, vswprintf, void *str, uptr size, void *format, va_list ap) {
ENSURE_MSAN_INITED();
- int res = REAL(vasprintf)(strp, format, ap);
- if (res >= 0 && !__msan_has_dynamic_component()) {
- __msan_unpoison(strp, sizeof(*strp));
- __msan_unpoison(*strp, res + 1);
+ int res = REAL(vswprintf)(str, size, format, ap);
+ if (res >= 0) {
+ __msan_unpoison(str, 4 * (res + 1));
}
return res;
}
-INTERCEPTOR(int, asprintf, char **strp, const char *format, ...) { // NOLINT
+INTERCEPTOR(int, swprintf, void *str, uptr size, void *format, ...) {
ENSURE_MSAN_INITED();
va_list ap;
va_start(ap, format);
- int res = vasprintf(strp, format, ap); // NOLINT
+ int res = vswprintf(str, size, format, ap);
va_end(ap);
return res;
}
-INTERCEPTOR(int, vsnprintf, char *str, uptr size,
- const char *format, va_list ap) {
+INTERCEPTOR(SIZE_T, strxfrm, char *dest, const char *src, SIZE_T n) {
ENSURE_MSAN_INITED();
- int res = REAL(vsnprintf)(str, size, format, ap);
- if (res >= 0 && !__msan_has_dynamic_component()) {
- __msan_unpoison(str, res + 1);
- }
+ CHECK_UNPOISONED(src, REAL(strlen)(src) + 1);
+ SIZE_T res = REAL(strxfrm)(dest, src, n);
+ if (res < n) __msan_unpoison(dest, res + 1);
return res;
}
-INTERCEPTOR(int, vsprintf, char *str, const char *format, va_list ap) {
+INTERCEPTOR(SIZE_T, strxfrm_l, char *dest, const char *src, SIZE_T n,
+ void *loc) {
ENSURE_MSAN_INITED();
- int res = REAL(vsprintf)(str, format, ap);
- if (res >= 0 && !__msan_has_dynamic_component()) {
- __msan_unpoison(str, res + 1);
- }
+ CHECK_UNPOISONED(src, REAL(strlen)(src) + 1);
+ SIZE_T res = REAL(strxfrm_l)(dest, src, n, loc);
+ if (res < n) __msan_unpoison(dest, res + 1);
return res;
}
-INTERCEPTOR(int, vswprintf, void *str, uptr size, void *format, va_list ap) {
- ENSURE_MSAN_INITED();
- int res = REAL(vswprintf)(str, size, format, ap);
- if (res >= 0 && !__msan_has_dynamic_component()) {
- __msan_unpoison(str, 4 * (res + 1));
- }
+#define INTERCEPTOR_STRFTIME_BODY(char_type, ret_type, func, s, ...) \
+ ENSURE_MSAN_INITED(); \
+ ret_type res = REAL(func)(s, __VA_ARGS__); \
+ if (s) __msan_unpoison(s, sizeof(char_type) * (res + 1)); \
return res;
-}
-INTERCEPTOR(int, sprintf, char *str, const char *format, ...) { // NOLINT
- ENSURE_MSAN_INITED();
- va_list ap;
- va_start(ap, format);
- int res = vsprintf(str, format, ap); // NOLINT
- va_end(ap);
- return res;
+INTERCEPTOR(SIZE_T, strftime, char *s, SIZE_T max, const char *format,
+ __sanitizer_tm *tm) {
+ INTERCEPTOR_STRFTIME_BODY(char, SIZE_T, strftime, s, max, format, tm);
}
-INTERCEPTOR(int, snprintf, char *str, uptr size, const char *format, ...) {
- ENSURE_MSAN_INITED();
- va_list ap;
- va_start(ap, format);
- int res = vsnprintf(str, size, format, ap);
- va_end(ap);
- return res;
+INTERCEPTOR(SIZE_T, strftime_l, char *s, SIZE_T max, const char *format,
+ __sanitizer_tm *tm, void *loc) {
+ INTERCEPTOR_STRFTIME_BODY(char, SIZE_T, strftime_l, s, max, format, tm, loc);
}
-INTERCEPTOR(int, swprintf, void *str, uptr size, void *format, ...) {
- ENSURE_MSAN_INITED();
- va_list ap;
- va_start(ap, format);
- int res = vswprintf(str, size, format, ap);
- va_end(ap);
- return res;
+#if !SANITIZER_FREEBSD
+INTERCEPTOR(SIZE_T, __strftime_l, char *s, SIZE_T max, const char *format,
+ __sanitizer_tm *tm, void *loc) {
+ INTERCEPTOR_STRFTIME_BODY(char, SIZE_T, __strftime_l, s, max, format, tm,
+ loc);
}
+#define MSAN_MAYBE_INTERCEPT___STRFTIME_L INTERCEPT_FUNCTION(__strftime_l)
+#else
+#define MSAN_MAYBE_INTERCEPT___STRFTIME_L
+#endif
-// SIZE_T strftime(char *s, SIZE_T max, const char *format,const struct tm *tm);
-INTERCEPTOR(SIZE_T, strftime, char *s, SIZE_T max, const char *format,
+INTERCEPTOR(SIZE_T, wcsftime, wchar_t *s, SIZE_T max, const wchar_t *format,
__sanitizer_tm *tm) {
- ENSURE_MSAN_INITED();
- SIZE_T res = REAL(strftime)(s, max, format, tm);
- if (res) __msan_unpoison(s, res + 1);
- return res;
+ INTERCEPTOR_STRFTIME_BODY(wchar_t, SIZE_T, wcsftime, s, max, format, tm);
+}
+
+INTERCEPTOR(SIZE_T, wcsftime_l, wchar_t *s, SIZE_T max, const wchar_t *format,
+ __sanitizer_tm *tm, void *loc) {
+ INTERCEPTOR_STRFTIME_BODY(wchar_t, SIZE_T, wcsftime_l, s, max, format, tm,
+ loc);
+}
+
+#if !SANITIZER_FREEBSD
+INTERCEPTOR(SIZE_T, __wcsftime_l, wchar_t *s, SIZE_T max, const wchar_t *format,
+ __sanitizer_tm *tm, void *loc) {
+ INTERCEPTOR_STRFTIME_BODY(wchar_t, SIZE_T, __wcsftime_l, s, max, format, tm,
+ loc);
}
+#define MSAN_MAYBE_INTERCEPT___WCSFTIME_L INTERCEPT_FUNCTION(__wcsftime_l)
+#else
+#define MSAN_MAYBE_INTERCEPT___WCSFTIME_L
+#endif
INTERCEPTOR(int, mbtowc, wchar_t *dest, const char *src, SIZE_T n) {
ENSURE_MSAN_INITED();
@@ -533,38 +574,42 @@ INTERCEPTOR(wchar_t *, wcschr, void *s, wchar_t wc, void *ps) {
// wchar_t *wcscpy(wchar_t *dest, const wchar_t *src);
INTERCEPTOR(wchar_t *, wcscpy, wchar_t *dest, const wchar_t *src) {
ENSURE_MSAN_INITED();
+ GET_STORE_STACK_TRACE;
wchar_t *res = REAL(wcscpy)(dest, src);
- __msan_copy_poison(dest, src, sizeof(wchar_t) * (REAL(wcslen)(src) + 1));
+ CopyPoison(dest, src, sizeof(wchar_t) * (REAL(wcslen)(src) + 1), &stack);
return res;
}
// wchar_t *wmemcpy(wchar_t *dest, const wchar_t *src, SIZE_T n);
INTERCEPTOR(wchar_t *, wmemcpy, wchar_t *dest, const wchar_t *src, SIZE_T n) {
ENSURE_MSAN_INITED();
+ GET_STORE_STACK_TRACE;
wchar_t *res = REAL(wmemcpy)(dest, src, n);
- __msan_copy_poison(dest, src, n * sizeof(wchar_t));
+ CopyPoison(dest, src, n * sizeof(wchar_t), &stack);
return res;
}
INTERCEPTOR(wchar_t *, wmempcpy, wchar_t *dest, const wchar_t *src, SIZE_T n) {
ENSURE_MSAN_INITED();
+ GET_STORE_STACK_TRACE;
wchar_t *res = REAL(wmempcpy)(dest, src, n);
- __msan_copy_poison(dest, src, n * sizeof(wchar_t));
+ CopyPoison(dest, src, n * sizeof(wchar_t), &stack);
return res;
}
INTERCEPTOR(wchar_t *, wmemset, wchar_t *s, wchar_t c, SIZE_T n) {
CHECK(MEM_IS_APP(s));
ENSURE_MSAN_INITED();
- wchar_t *res = (wchar_t *)fast_memset(s, c, n * sizeof(wchar_t));
+ wchar_t *res = REAL(wmemset)(s, c, n);
__msan_unpoison(s, n * sizeof(wchar_t));
return res;
}
INTERCEPTOR(wchar_t *, wmemmove, wchar_t *dest, const wchar_t *src, SIZE_T n) {
ENSURE_MSAN_INITED();
+ GET_STORE_STACK_TRACE;
wchar_t *res = REAL(wmemmove)(dest, src, n);
- __msan_move_poison(dest, src, n * sizeof(wchar_t));
+ MovePoison(dest, src, n * sizeof(wchar_t), &stack);
return res;
}
@@ -574,13 +619,6 @@ INTERCEPTOR(int, wcscmp, const wchar_t *s1, const wchar_t *s2) {
return res;
}
-INTERCEPTOR(double, wcstod, const wchar_t *nptr, wchar_t **endptr) {
- ENSURE_MSAN_INITED();
- double res = REAL(wcstod)(nptr, endptr);
- __msan_unpoison(endptr, sizeof(*endptr));
- return res;
-}
-
INTERCEPTOR(int, gettimeofday, void *tv, void *tz) {
ENSURE_MSAN_INITED();
int res = REAL(gettimeofday)(tv, tz);
@@ -594,20 +632,18 @@ INTERCEPTOR(int, gettimeofday, void *tv, void *tz) {
INTERCEPTOR(char *, fcvt, double x, int a, int *b, int *c) {
ENSURE_MSAN_INITED();
char *res = REAL(fcvt)(x, a, b, c);
- if (!__msan_has_dynamic_component()) {
- __msan_unpoison(b, sizeof(*b));
- __msan_unpoison(c, sizeof(*c));
- }
+ __msan_unpoison(b, sizeof(*b));
+ __msan_unpoison(c, sizeof(*c));
+ if (res) __msan_unpoison(res, REAL(strlen)(res) + 1);
return res;
}
INTERCEPTOR(char *, getenv, char *name) {
+ if (msan_init_is_running)
+ return REAL(getenv)(name);
ENSURE_MSAN_INITED();
char *res = REAL(getenv)(name);
- if (!__msan_has_dynamic_component()) {
- if (res)
- __msan_unpoison(res, REAL(strlen)(res) + 1);
- }
+ if (res) __msan_unpoison(res, REAL(strlen)(res) + 1);
return res;
}
@@ -637,6 +673,7 @@ INTERCEPTOR(int, putenv, char *string) {
return res;
}
+#if !SANITIZER_FREEBSD
INTERCEPTOR(int, __fxstat, int magic, int fd, void *buf) {
ENSURE_MSAN_INITED();
int res = REAL(__fxstat)(magic, fd, buf);
@@ -644,7 +681,12 @@ INTERCEPTOR(int, __fxstat, int magic, int fd, void *buf) {
__msan_unpoison(buf, __sanitizer::struct_stat_sz);
return res;
}
+#define MSAN_MAYBE_INTERCEPT___FXSTAT INTERCEPT_FUNCTION(__fxstat)
+#else
+#define MSAN_MAYBE_INTERCEPT___FXSTAT
+#endif
+#if !SANITIZER_FREEBSD
INTERCEPTOR(int, __fxstat64, int magic, int fd, void *buf) {
ENSURE_MSAN_INITED();
int res = REAL(__fxstat64)(magic, fd, buf);
@@ -652,7 +694,12 @@ INTERCEPTOR(int, __fxstat64, int magic, int fd, void *buf) {
__msan_unpoison(buf, __sanitizer::struct_stat64_sz);
return res;
}
+#define MSAN_MAYBE_INTERCEPT___FXSTAT64 INTERCEPT_FUNCTION(__fxstat64)
+#else
+#define MSAN_MAYBE_INTERCEPT___FXSTAT64
+#endif
+#if !SANITIZER_FREEBSD
INTERCEPTOR(int, __fxstatat, int magic, int fd, char *pathname, void *buf,
int flags) {
ENSURE_MSAN_INITED();
@@ -660,7 +707,12 @@ INTERCEPTOR(int, __fxstatat, int magic, int fd, char *pathname, void *buf,
if (!res) __msan_unpoison(buf, __sanitizer::struct_stat_sz);
return res;
}
+#define MSAN_MAYBE_INTERCEPT___FXSTATAT INTERCEPT_FUNCTION(__fxstatat)
+#else
+#define MSAN_MAYBE_INTERCEPT___FXSTATAT
+#endif
+#if !SANITIZER_FREEBSD
INTERCEPTOR(int, __fxstatat64, int magic, int fd, char *pathname, void *buf,
int flags) {
ENSURE_MSAN_INITED();
@@ -668,7 +720,12 @@ INTERCEPTOR(int, __fxstatat64, int magic, int fd, char *pathname, void *buf,
if (!res) __msan_unpoison(buf, __sanitizer::struct_stat64_sz);
return res;
}
+#define MSAN_MAYBE_INTERCEPT___FXSTATAT64 INTERCEPT_FUNCTION(__fxstatat64)
+#else
+#define MSAN_MAYBE_INTERCEPT___FXSTATAT64
+#endif
+#if !SANITIZER_FREEBSD
INTERCEPTOR(int, __xstat, int magic, char *path, void *buf) {
ENSURE_MSAN_INITED();
int res = REAL(__xstat)(magic, path, buf);
@@ -676,7 +733,12 @@ INTERCEPTOR(int, __xstat, int magic, char *path, void *buf) {
__msan_unpoison(buf, __sanitizer::struct_stat_sz);
return res;
}
+#define MSAN_MAYBE_INTERCEPT___XSTAT INTERCEPT_FUNCTION(__xstat)
+#else
+#define MSAN_MAYBE_INTERCEPT___XSTAT
+#endif
+#if !SANITIZER_FREEBSD
INTERCEPTOR(int, __xstat64, int magic, char *path, void *buf) {
ENSURE_MSAN_INITED();
int res = REAL(__xstat64)(magic, path, buf);
@@ -684,7 +746,12 @@ INTERCEPTOR(int, __xstat64, int magic, char *path, void *buf) {
__msan_unpoison(buf, __sanitizer::struct_stat64_sz);
return res;
}
+#define MSAN_MAYBE_INTERCEPT___XSTAT64 INTERCEPT_FUNCTION(__xstat64)
+#else
+#define MSAN_MAYBE_INTERCEPT___XSTAT64
+#endif
+#if !SANITIZER_FREEBSD
INTERCEPTOR(int, __lxstat, int magic, char *path, void *buf) {
ENSURE_MSAN_INITED();
int res = REAL(__lxstat)(magic, path, buf);
@@ -692,7 +759,12 @@ INTERCEPTOR(int, __lxstat, int magic, char *path, void *buf) {
__msan_unpoison(buf, __sanitizer::struct_stat_sz);
return res;
}
+#define MSAN_MAYBE_INTERCEPT___LXSTAT INTERCEPT_FUNCTION(__lxstat)
+#else
+#define MSAN_MAYBE_INTERCEPT___LXSTAT
+#endif
+#if !SANITIZER_FREEBSD
INTERCEPTOR(int, __lxstat64, int magic, char *path, void *buf) {
ENSURE_MSAN_INITED();
int res = REAL(__lxstat64)(magic, path, buf);
@@ -700,6 +772,10 @@ INTERCEPTOR(int, __lxstat64, int magic, char *path, void *buf) {
__msan_unpoison(buf, __sanitizer::struct_stat64_sz);
return res;
}
+#define MSAN_MAYBE_INTERCEPT___LXSTAT64 INTERCEPT_FUNCTION(__lxstat64)
+#else
+#define MSAN_MAYBE_INTERCEPT___LXSTAT64
+#endif
INTERCEPTOR(int, pipe, int pipefd[2]) {
if (msan_init_is_running)
@@ -735,6 +811,7 @@ INTERCEPTOR(char *, fgets, char *s, int size, void *stream) {
return res;
}
+#if !SANITIZER_FREEBSD
INTERCEPTOR(char *, fgets_unlocked, char *s, int size, void *stream) {
ENSURE_MSAN_INITED();
char *res = REAL(fgets_unlocked)(s, size, stream);
@@ -742,6 +819,10 @@ INTERCEPTOR(char *, fgets_unlocked, char *s, int size, void *stream) {
__msan_unpoison(s, REAL(strlen)(s) + 1);
return res;
}
+#define MSAN_MAYBE_INTERCEPT_FGETS_UNLOCKED INTERCEPT_FUNCTION(fgets_unlocked)
+#else
+#define MSAN_MAYBE_INTERCEPT_FGETS_UNLOCKED
+#endif
INTERCEPTOR(int, getrlimit, int resource, void *rlim) {
if (msan_init_is_running)
@@ -753,6 +834,7 @@ INTERCEPTOR(int, getrlimit, int resource, void *rlim) {
return res;
}
+#if !SANITIZER_FREEBSD
INTERCEPTOR(int, getrlimit64, int resource, void *rlim) {
if (msan_init_is_running)
return REAL(getrlimit64)(resource, rlim);
@@ -762,6 +844,10 @@ INTERCEPTOR(int, getrlimit64, int resource, void *rlim) {
__msan_unpoison(rlim, __sanitizer::struct_rlimit64_sz);
return res;
}
+#define MSAN_MAYBE_INTERCEPT_GETRLIMIT64 INTERCEPT_FUNCTION(getrlimit64)
+#else
+#define MSAN_MAYBE_INTERCEPT_GETRLIMIT64
+#endif
INTERCEPTOR(int, uname, void *utsname) {
ENSURE_MSAN_INITED();
@@ -784,6 +870,7 @@ INTERCEPTOR(int, gethostname, char *name, SIZE_T len) {
return res;
}
+#if !SANITIZER_FREEBSD
INTERCEPTOR(int, epoll_wait, int epfd, void *events, int maxevents,
int timeout) {
ENSURE_MSAN_INITED();
@@ -793,7 +880,12 @@ INTERCEPTOR(int, epoll_wait, int epfd, void *events, int maxevents,
}
return res;
}
+#define MSAN_MAYBE_INTERCEPT_EPOLL_WAIT INTERCEPT_FUNCTION(epoll_wait)
+#else
+#define MSAN_MAYBE_INTERCEPT_EPOLL_WAIT
+#endif
+#if !SANITIZER_FREEBSD
INTERCEPTOR(int, epoll_pwait, int epfd, void *events, int maxevents,
int timeout, void *sigmask) {
ENSURE_MSAN_INITED();
@@ -803,6 +895,10 @@ INTERCEPTOR(int, epoll_pwait, int epfd, void *events, int maxevents,
}
return res;
}
+#define MSAN_MAYBE_INTERCEPT_EPOLL_PWAIT INTERCEPT_FUNCTION(epoll_pwait)
+#else
+#define MSAN_MAYBE_INTERCEPT_EPOLL_PWAIT
+#endif
INTERCEPTOR(SSIZE_T, recv, int fd, void *buf, SIZE_T len, int flags) {
ENSURE_MSAN_INITED();
@@ -861,30 +957,51 @@ void __msan_allocated_memory(const void* data, uptr size) {
if (flags()->poison_in_malloc)
__msan_poison(data, size);
if (__msan_get_track_origins()) {
- u32 stack_id = StackDepotPut(stack.trace, stack.size);
- CHECK(stack_id);
- CHECK_EQ((stack_id >> 31), 0); // Higher bit is occupied by stack origins.
- __msan_set_origin(data, size, stack_id);
+ Origin o = Origin::CreateHeapOrigin(&stack);
+ __msan_set_origin(data, size, o.raw_id());
}
}
INTERCEPTOR(void *, mmap, void *addr, SIZE_T length, int prot, int flags,
int fd, OFF_T offset) {
- ENSURE_MSAN_INITED();
+ if (msan_init_is_running)
+ return REAL(mmap)(addr, length, prot, flags, fd, offset);
+ ENSURE_MSAN_INITED();
+ if (addr && !MEM_IS_APP(addr)) {
+ if (flags & map_fixed) {
+ *__errno_location() = errno_EINVAL;
+ return (void *)-1;
+ } else {
+ addr = 0;
+ }
+ }
void *res = REAL(mmap)(addr, length, prot, flags, fd, offset);
if (res != (void*)-1)
__msan_unpoison(res, RoundUpTo(length, GetPageSize()));
return res;
}
+#if !SANITIZER_FREEBSD
INTERCEPTOR(void *, mmap64, void *addr, SIZE_T length, int prot, int flags,
int fd, OFF64_T offset) {
ENSURE_MSAN_INITED();
+ if (addr && !MEM_IS_APP(addr)) {
+ if (flags & map_fixed) {
+ *__errno_location() = errno_EINVAL;
+ return (void *)-1;
+ } else {
+ addr = 0;
+ }
+ }
void *res = REAL(mmap64)(addr, length, prot, flags, fd, offset);
if (res != (void*)-1)
__msan_unpoison(res, RoundUpTo(length, GetPageSize()));
return res;
}
+#define MSAN_MAYBE_INTERCEPT_MMAP64 INTERCEPT_FUNCTION(mmap64)
+#else
+#define MSAN_MAYBE_INTERCEPT_MMAP64
+#endif
struct dlinfo {
char *dli_fname;
@@ -906,32 +1023,13 @@ INTERCEPTOR(int, dladdr, void *addr, dlinfo *info) {
return res;
}
-INTERCEPTOR(char *, dlerror) {
+INTERCEPTOR(char *, dlerror, int fake) {
ENSURE_MSAN_INITED();
- char *res = REAL(dlerror)();
+ char *res = REAL(dlerror)(fake);
if (res != 0) __msan_unpoison(res, REAL(strlen)(res) + 1);
return res;
}
-// dlopen() ultimately calls mmap() down inside the loader, which generally
-// doesn't participate in dynamic symbol resolution. Therefore we won't
-// intercept its calls to mmap, and we have to hook it here. The loader
-// initializes the module before returning, so without the dynamic component, we
-// won't be able to clear the shadow before the initializers. Fixing this would
-// require putting our own initializer first to clear the shadow.
-INTERCEPTOR(void *, dlopen, const char *filename, int flag) {
- ENSURE_MSAN_INITED();
- EnterLoader();
- link_map *map = (link_map *)REAL(dlopen)(filename, flag);
- ExitLoader();
- if (!__msan_has_dynamic_component() && map) {
- // If msandr didn't clear the shadow before the initializers ran, we do it
- // ourselves afterwards.
- ForEachMappedRegion(map, __msan_unpoison);
- }
- return (void *)map;
-}
-
typedef int (*dl_iterate_phdr_cb)(__sanitizer_dl_phdr_info *info, SIZE_T size,
void *data);
struct dl_iterate_phdr_data {
@@ -953,12 +1051,10 @@ static int msan_dl_iterate_phdr_cb(__sanitizer_dl_phdr_info *info, SIZE_T size,
INTERCEPTOR(int, dl_iterate_phdr, dl_iterate_phdr_cb callback, void *data) {
ENSURE_MSAN_INITED();
- EnterLoader();
dl_iterate_phdr_data cbdata;
cbdata.callback = callback;
cbdata.data = data;
int res = REAL(dl_iterate_phdr)(msan_dl_iterate_phdr_cb, (void *)&cbdata);
- ExitLoader();
return res;
}
@@ -971,6 +1067,18 @@ INTERCEPTOR(int, getrusage, int who, void *usage) {
return res;
}
+class SignalHandlerScope {
+ public:
+ SignalHandlerScope() {
+ if (MsanThread *t = GetCurrentThread())
+ t->EnterSignalHandler();
+ }
+ ~SignalHandlerScope() {
+ if (MsanThread *t = GetCurrentThread())
+ t->LeaveSignalHandler();
+ }
+};
+
// sigactions_mu guarantees atomicity of sigaction() and signal() calls.
// Access to sigactions[] is gone with relaxed atomics to avoid data race with
// the signal handler.
@@ -979,6 +1087,7 @@ static atomic_uintptr_t sigactions[kMaxSignals];
static StaticSpinMutex sigactions_mu;
static void SignalHandler(int signo) {
+ SignalHandlerScope signal_handler_scope;
ScopedThreadLocalStateBackup stlsb;
UnpoisonParam(1);
@@ -989,6 +1098,7 @@ static void SignalHandler(int signo) {
}
static void SignalAction(int signo, void *si, void *uc) {
+ SignalHandlerScope signal_handler_scope;
ScopedThreadLocalStateBackup stlsb;
UnpoisonParam(3);
__msan_unpoison(si, sizeof(__sanitizer_sigaction));
@@ -1013,21 +1123,21 @@ INTERCEPTOR(int, sigaction, int signo, const __sanitizer_sigaction *act,
__sanitizer_sigaction new_act;
__sanitizer_sigaction *pnew_act = act ? &new_act : 0;
if (act) {
- internal_memcpy(pnew_act, act, sizeof(__sanitizer_sigaction));
- uptr cb = (uptr)pnew_act->sa_sigaction;
+ REAL(memcpy)(pnew_act, act, sizeof(__sanitizer_sigaction));
+ uptr cb = (uptr)pnew_act->sigaction;
uptr new_cb = (pnew_act->sa_flags & __sanitizer::sa_siginfo)
? (uptr)SignalAction
: (uptr)SignalHandler;
if (cb != __sanitizer::sig_ign && cb != __sanitizer::sig_dfl) {
atomic_store(&sigactions[signo], cb, memory_order_relaxed);
- pnew_act->sa_sigaction = (void (*)(int, void *, void *))new_cb;
+ pnew_act->sigaction = (void (*)(int, void *, void *))new_cb;
}
}
res = REAL(sigaction)(signo, pnew_act, oldact);
if (res == 0 && oldact) {
- uptr cb = (uptr)oldact->sa_sigaction;
+ uptr cb = (uptr)oldact->sigaction;
if (cb != __sanitizer::sig_ign && cb != __sanitizer::sig_dfl) {
- oldact->sa_sigaction = (void (*)(int, void *, void *))old_cb;
+ oldact->sigaction = (void (*)(int, void *, void *))old_cb;
}
}
} else {
@@ -1057,38 +1167,11 @@ INTERCEPTOR(int, signal, int signo, uptr cb) {
extern "C" int pthread_attr_init(void *attr);
extern "C" int pthread_attr_destroy(void *attr);
-extern "C" int pthread_setspecific(unsigned key, const void *v);
-extern "C" int pthread_yield();
-
-static void thread_finalize(void *v) {
- uptr iter = (uptr)v;
- if (iter > 1) {
- if (pthread_setspecific(g_thread_finalize_key, (void*)(iter - 1))) {
- Printf("MemorySanitizer: failed to set thread key\n");
- Die();
- }
- return;
- }
- MsanAllocatorThreadFinish();
-}
-
-struct ThreadParam {
- void* (*callback)(void *arg);
- void *param;
- atomic_uintptr_t done;
-};
static void *MsanThreadStartFunc(void *arg) {
- ThreadParam *p = (ThreadParam *)arg;
- void* (*callback)(void *arg) = p->callback;
- void *param = p->param;
- if (pthread_setspecific(g_thread_finalize_key,
- (void *)kPthreadDestructorIterations)) {
- Printf("MemorySanitizer: failed to set thread key\n");
- Die();
- }
- atomic_store(&p->done, 1, memory_order_release);
- return callback(param);
+ MsanThread *t = (MsanThread *)arg;
+ SetCurrentThread(t);
+ return t->ThreadStart();
}
INTERCEPTOR(int, pthread_create, void *th, void *attr, void *(*callback)(void*),
@@ -1100,18 +1183,11 @@ INTERCEPTOR(int, pthread_create, void *th, void *attr, void *(*callback)(void*),
attr = &myattr;
}
- AdjustStackSizeLinux(attr);
+ AdjustStackSize(attr);
- ThreadParam p;
- p.callback = callback;
- p.param = param;
- atomic_store(&p.done, 0, memory_order_relaxed);
+ MsanThread *t = MsanThread::Create(callback, param);
- int res = REAL(pthread_create)(th, attr, MsanThreadStartFunc, (void *)&p);
- if (res == 0) {
- while (atomic_load(&p.done, memory_order_acquire) != 1)
- pthread_yield();
- }
+ int res = REAL(pthread_create)(th, attr, MsanThreadStartFunc, t);
if (attr == &myattr)
pthread_attr_destroy(&myattr);
@@ -1123,6 +1199,7 @@ INTERCEPTOR(int, pthread_create, void *th, void *attr, void *(*callback)(void*),
INTERCEPTOR(int, pthread_key_create, __sanitizer_pthread_key_t *key,
void (*dtor)(void *value)) {
+ if (msan_init_is_running) return REAL(pthread_key_create)(key, dtor);
ENSURE_MSAN_INITED();
int res = REAL(pthread_key_create)(key, dtor);
if (!res && key)
@@ -1140,9 +1217,9 @@ INTERCEPTOR(int, pthread_join, void *th, void **retval) {
extern char *tzname[2];
-INTERCEPTOR(void, tzset) {
+INTERCEPTOR(void, tzset, int fake) {
ENSURE_MSAN_INITED();
- REAL(tzset)();
+ REAL(tzset)(fake);
if (tzname[0])
__msan_unpoison(tzname[0], REAL(strlen)(tzname[0]) + 1);
if (tzname[1])
@@ -1189,34 +1266,22 @@ INTERCEPTOR(void *, shmat, int shmid, const void *shmaddr, int shmflg) {
return p;
}
-// Linux kernel has a bug that leads to kernel deadlock if a process
-// maps TBs of memory and then calls mlock().
-static void MlockIsUnsupported() {
- static atomic_uint8_t printed;
- if (atomic_exchange(&printed, 1, memory_order_relaxed))
- return;
- if (common_flags()->verbosity > 0)
- Printf("INFO: MemorySanitizer ignores mlock/mlockall/munlock/munlockall\n");
-}
-
-INTERCEPTOR(int, mlock, const void *addr, uptr len) {
- MlockIsUnsupported();
- return 0;
-}
-
-INTERCEPTOR(int, munlock, const void *addr, uptr len) {
- MlockIsUnsupported();
- return 0;
+static void BeforeFork() {
+ StackDepotLockAll();
+ ChainedOriginDepotLockAll();
}
-INTERCEPTOR(int, mlockall, int flags) {
- MlockIsUnsupported();
- return 0;
+static void AfterFork() {
+ ChainedOriginDepotUnlockAll();
+ StackDepotUnlockAll();
}
-INTERCEPTOR(int, munlockall, void) {
- MlockIsUnsupported();
- return 0;
+INTERCEPTOR(int, fork, void) {
+ ENSURE_MSAN_INITED();
+ BeforeFork();
+ int pid = REAL(fork)();
+ AfterFork();
+ return pid;
}
struct MSanInterceptorContext {
@@ -1232,8 +1297,6 @@ int OnExit() {
} // namespace __msan
-extern "C" int *__errno_location(void);
-
// A version of CHECK_UNPOISONED using a saved scope value. Used in common
// interceptors.
#define CHECK_UNPOISONED_CTX(ctx, x, n) \
@@ -1242,21 +1305,20 @@ extern "C" int *__errno_location(void);
CHECK_UNPOISONED_0(x, n); \
} while (0)
-#define MSAN_INTERCEPT_FUNC(name) \
- do { \
- if ((!INTERCEPT_FUNCTION(name) || !REAL(name)) && \
- common_flags()->verbosity > 0) \
- Report("MemorySanitizer: failed to intercept '" #name "'\n"); \
+#define MSAN_INTERCEPT_FUNC(name) \
+ do { \
+ if ((!INTERCEPT_FUNCTION(name) || !REAL(name))) \
+ VReport(1, "MemorySanitizer: failed to intercept '" #name "'\n"); \
} while (0)
#define COMMON_INTERCEPT_FUNCTION(name) MSAN_INTERCEPT_FUNC(name)
-#define COMMON_INTERCEPTOR_UNPOISON_PARAM(ctx, count) \
+#define COMMON_INTERCEPTOR_UNPOISON_PARAM(count) \
UnpoisonParam(count)
#define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \
__msan_unpoison(ptr, size)
#define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) \
CHECK_UNPOISONED_CTX(ctx, ptr, size)
-#define COMMON_INTERCEPTOR_INITIALIZE_RANGE(ctx, ptr, size) \
+#define COMMON_INTERCEPTOR_INITIALIZE_RANGE(ptr, size) \
__msan_unpoison(ptr, size)
#define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \
if (msan_init_is_running) return REAL(func)(__VA_ARGS__); \
@@ -1283,6 +1345,9 @@ extern "C" int *__errno_location(void);
} while (false) // FIXME
#define COMMON_INTERCEPTOR_BLOCK_REAL(name) REAL(name)
#define COMMON_INTERCEPTOR_ON_EXIT(ctx) OnExit()
+#define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, map) \
+ if (map) ForEachMappedRegion((link_map *)map, __msan_unpoison);
+
#include "sanitizer_common/sanitizer_common_interceptors.inc"
#define COMMON_SYSCALL_PRE_READ_RANGE(p, s) CHECK_UNPOISONED(p, s)
@@ -1295,155 +1360,204 @@ extern "C" int *__errno_location(void);
#define COMMON_SYSCALL_POST_WRITE_RANGE(p, s) __msan_unpoison(p, s)
#include "sanitizer_common/sanitizer_common_syscalls.inc"
-// static
-void *fast_memset(void *ptr, int c, SIZE_T n) {
- // hack until we have a really fast internal_memset
- if (sizeof(uptr) == 8 &&
- (n % 8) == 0 &&
- ((uptr)ptr % 8) == 0 &&
- (c == 0 || c == -1)) {
- // Printf("memset %p %zd %x\n", ptr, n, c);
- uptr to_store = c ? -1L : 0L;
- uptr *p = (uptr*)ptr;
- for (SIZE_T i = 0; i < n / 8; i++)
- p[i] = to_store;
- return ptr;
- }
- return internal_memset(ptr, c, n);
-}
-
-// static
-void *fast_memcpy(void *dst, const void *src, SIZE_T n) {
- // Same hack as in fast_memset above.
- if (sizeof(uptr) == 8 &&
- (n % 8) == 0 &&
- ((uptr)dst % 8) == 0 &&
- ((uptr)src % 8) == 0) {
- uptr *d = (uptr*)dst;
- uptr *s = (uptr*)src;
- for (SIZE_T i = 0; i < n / 8; i++)
- d[i] = s[i];
- return dst;
+static void PoisonShadow(uptr ptr, uptr size, u8 value) {
+ uptr PageSize = GetPageSizeCached();
+ uptr shadow_beg = MEM_TO_SHADOW(ptr);
+ uptr shadow_end = MEM_TO_SHADOW(ptr + size);
+ if (value ||
+ shadow_end - shadow_beg < common_flags()->clear_shadow_mmap_threshold) {
+ REAL(memset)((void*)shadow_beg, value, shadow_end - shadow_beg);
+ } else {
+ uptr page_beg = RoundUpTo(shadow_beg, PageSize);
+ uptr page_end = RoundDownTo(shadow_end, PageSize);
+
+ if (page_beg >= page_end) {
+ REAL(memset)((void *)shadow_beg, 0, shadow_end - shadow_beg);
+ } else {
+ if (page_beg != shadow_beg) {
+ REAL(memset)((void *)shadow_beg, 0, page_beg - shadow_beg);
+ }
+ if (page_end != shadow_end) {
+ REAL(memset)((void *)page_end, 0, shadow_end - page_end);
+ }
+ MmapFixedNoReserve(page_beg, page_end - page_beg);
+ }
}
- return internal_memcpy(dst, src, n);
}
// These interface functions reside here so that they can use
-// fast_memset, etc.
+// REAL(memset), etc.
void __msan_unpoison(const void *a, uptr size) {
if (!MEM_IS_APP(a)) return;
- fast_memset((void*)MEM_TO_SHADOW((uptr)a), 0, size);
+ PoisonShadow((uptr)a, size, 0);
}
void __msan_poison(const void *a, uptr size) {
if (!MEM_IS_APP(a)) return;
- fast_memset((void*)MEM_TO_SHADOW((uptr)a),
- __msan::flags()->poison_heap_with_zeroes ? 0 : -1, size);
+ PoisonShadow((uptr)a, size,
+ __msan::flags()->poison_heap_with_zeroes ? 0 : -1);
}
void __msan_poison_stack(void *a, uptr size) {
if (!MEM_IS_APP(a)) return;
- fast_memset((void*)MEM_TO_SHADOW((uptr)a),
- __msan::flags()->poison_stack_with_zeroes ? 0 : -1, size);
+ PoisonShadow((uptr)a, size,
+ __msan::flags()->poison_stack_with_zeroes ? 0 : -1);
}
void __msan_clear_and_unpoison(void *a, uptr size) {
- fast_memset(a, 0, size);
- fast_memset((void*)MEM_TO_SHADOW((uptr)a), 0, size);
+ REAL(memset)(a, 0, size);
+ PoisonShadow((uptr)a, size, 0);
+}
+
+void *__msan_memcpy(void *dest, const void *src, SIZE_T n) {
+ if (!msan_inited) return internal_memcpy(dest, src, n);
+ if (msan_init_is_running) return REAL(memcpy)(dest, src, n);
+ ENSURE_MSAN_INITED();
+ GET_STORE_STACK_TRACE;
+ void *res = REAL(memcpy)(dest, src, n);
+ CopyPoison(dest, src, n, &stack);
+ return res;
+}
+
+void *__msan_memset(void *s, int c, SIZE_T n) {
+ if (!msan_inited) return internal_memset(s, c, n);
+ if (msan_init_is_running) return REAL(memset)(s, c, n);
+ ENSURE_MSAN_INITED();
+ void *res = REAL(memset)(s, c, n);
+ __msan_unpoison(s, n);
+ return res;
+}
+
+void *__msan_memmove(void *dest, const void *src, SIZE_T n) {
+ if (!msan_inited) return internal_memmove(dest, src, n);
+ if (msan_init_is_running) return REAL(memmove)(dest, src, n);
+ ENSURE_MSAN_INITED();
+ GET_STORE_STACK_TRACE;
+ void *res = REAL(memmove)(dest, src, n);
+ MovePoison(dest, src, n, &stack);
+ return res;
+}
+
+void __msan_unpoison_string(const char* s) {
+ if (!MEM_IS_APP(s)) return;
+ __msan_unpoison(s, REAL(strlen)(s) + 1);
}
-u32 get_origin_if_poisoned(uptr a, uptr size) {
- unsigned char *s = (unsigned char *)MEM_TO_SHADOW(a);
+namespace __msan {
+
+u32 GetOriginIfPoisoned(uptr addr, uptr size) {
+ unsigned char *s = (unsigned char *)MEM_TO_SHADOW(addr);
for (uptr i = 0; i < size; ++i)
if (s[i])
- return *(u32 *)SHADOW_TO_ORIGIN((s + i) & ~3UL);
+ return *(u32 *)SHADOW_TO_ORIGIN(((uptr)s + i) & ~3UL);
return 0;
}
-void __msan_copy_origin(void *dst, const void *src, uptr size) {
+void SetOriginIfPoisoned(uptr addr, uptr src_shadow, uptr size,
+ u32 src_origin) {
+ uptr dst_s = MEM_TO_SHADOW(addr);
+ uptr src_s = src_shadow;
+ uptr src_s_end = src_s + size;
+
+ for (; src_s < src_s_end; ++dst_s, ++src_s)
+ if (*(u8 *)src_s) *(u32 *)SHADOW_TO_ORIGIN(dst_s &~3UL) = src_origin;
+}
+
+void CopyOrigin(void *dst, const void *src, uptr size, StackTrace *stack) {
if (!__msan_get_track_origins()) return;
if (!MEM_IS_APP(dst) || !MEM_IS_APP(src)) return;
+
uptr d = (uptr)dst;
uptr beg = d & ~3UL;
// Copy left unaligned origin if that memory is poisoned.
if (beg < d) {
- u32 o = get_origin_if_poisoned(beg, d - beg);
- if (o)
+ u32 o = GetOriginIfPoisoned((uptr)src, d - beg);
+ if (o) {
+ if (__msan_get_track_origins() > 1) o = ChainOrigin(o, stack);
*(u32 *)MEM_TO_ORIGIN(beg) = o;
+ }
beg += 4;
}
- uptr end = (d + size + 3) & ~3UL;
+ uptr end = (d + size) & ~3UL;
+ // If both ends fall into the same 4-byte slot, we are done.
+ if (end < beg) return;
+
// Copy right unaligned origin if that memory is poisoned.
- if (end > d + size) {
- u32 o = get_origin_if_poisoned(d + size, end - d - size);
- if (o)
- *(u32 *)MEM_TO_ORIGIN(end - 4) = o;
- end -= 4;
+ if (end < d + size) {
+ u32 o = GetOriginIfPoisoned((uptr)src + (end - d), (d + size) - end);
+ if (o) {
+ if (__msan_get_track_origins() > 1) o = ChainOrigin(o, stack);
+ *(u32 *)MEM_TO_ORIGIN(end) = o;
+ }
}
if (beg < end) {
// Align src up.
uptr s = ((uptr)src + 3) & ~3UL;
- fast_memcpy((void*)MEM_TO_ORIGIN(beg), (void*)MEM_TO_ORIGIN(s), end - beg);
+ // FIXME: factor out to msan_copy_origin_aligned
+ if (__msan_get_track_origins() > 1) {
+ u32 *src = (u32 *)MEM_TO_ORIGIN(s);
+ u32 *src_s = (u32 *)MEM_TO_SHADOW(s);
+ u32 *src_end = (u32 *)MEM_TO_ORIGIN(s + (end - beg));
+ u32 *dst = (u32 *)MEM_TO_ORIGIN(beg);
+ u32 src_o = 0;
+ u32 dst_o = 0;
+ for (; src < src_end; ++src, ++src_s, ++dst) {
+ if (!*src_s) continue;
+ if (*src != src_o) {
+ src_o = *src;
+ dst_o = ChainOrigin(src_o, stack);
+ }
+ *dst = dst_o;
+ }
+ } else {
+ REAL(memcpy)((void *)MEM_TO_ORIGIN(beg), (void *)MEM_TO_ORIGIN(s),
+ end - beg);
+ }
}
}
-void __msan_copy_poison(void *dst, const void *src, uptr size) {
+void MovePoison(void *dst, const void *src, uptr size, StackTrace *stack) {
if (!MEM_IS_APP(dst)) return;
if (!MEM_IS_APP(src)) return;
- fast_memcpy((void*)MEM_TO_SHADOW((uptr)dst),
- (void*)MEM_TO_SHADOW((uptr)src), size);
- __msan_copy_origin(dst, src, size);
+ if (src == dst) return;
+ REAL(memmove)((void *)MEM_TO_SHADOW((uptr)dst),
+ (void *)MEM_TO_SHADOW((uptr)src), size);
+ CopyOrigin(dst, src, size, stack);
}
-void __msan_move_poison(void *dst, const void *src, uptr size) {
+void CopyPoison(void *dst, const void *src, uptr size, StackTrace *stack) {
if (!MEM_IS_APP(dst)) return;
if (!MEM_IS_APP(src)) return;
- internal_memmove((void*)MEM_TO_SHADOW((uptr)dst),
- (void*)MEM_TO_SHADOW((uptr)src), size);
- __msan_copy_origin(dst, src, size);
-}
-
-void *__msan_memcpy(void *dest, const void *src, SIZE_T n) {
- ENSURE_MSAN_INITED();
- void *res = fast_memcpy(dest, src, n);
- __msan_copy_poison(dest, src, n);
- return res;
-}
-
-void *__msan_memset(void *s, int c, SIZE_T n) {
- ENSURE_MSAN_INITED();
- void *res = fast_memset(s, c, n);
- __msan_unpoison(s, n);
- return res;
-}
-
-void *__msan_memmove(void *dest, const void *src, SIZE_T n) {
- ENSURE_MSAN_INITED();
- void *res = REAL(memmove)(dest, src, n);
- __msan_move_poison(dest, src, n);
- return res;
+ REAL(memcpy)((void *)MEM_TO_SHADOW((uptr)dst),
+ (void *)MEM_TO_SHADOW((uptr)src), size);
+ CopyOrigin(dst, src, size, stack);
}
-namespace __msan {
void InitializeInterceptors() {
static int inited = 0;
CHECK_EQ(inited, 0);
- SANITIZER_COMMON_INTERCEPTORS_INIT;
+ InitializeCommonInterceptors();
INTERCEPT_FUNCTION(mmap);
- INTERCEPT_FUNCTION(mmap64);
+ MSAN_MAYBE_INTERCEPT_MMAP64;
INTERCEPT_FUNCTION(posix_memalign);
- INTERCEPT_FUNCTION(memalign);
+ MSAN_MAYBE_INTERCEPT_MEMALIGN;
+ INTERCEPT_FUNCTION(__libc_memalign);
INTERCEPT_FUNCTION(valloc);
- INTERCEPT_FUNCTION(pvalloc);
+ MSAN_MAYBE_INTERCEPT_PVALLOC;
INTERCEPT_FUNCTION(malloc);
INTERCEPT_FUNCTION(calloc);
INTERCEPT_FUNCTION(realloc);
INTERCEPT_FUNCTION(free);
+ MSAN_MAYBE_INTERCEPT_CFREE;
+ INTERCEPT_FUNCTION(malloc_usable_size);
+ MSAN_MAYBE_INTERCEPT_MALLINFO;
+ MSAN_MAYBE_INTERCEPT_MALLOPT;
+ MSAN_MAYBE_INTERCEPT_MALLOC_STATS;
INTERCEPT_FUNCTION(fread);
- INTERCEPT_FUNCTION(fread_unlocked);
+ MSAN_MAYBE_INTERCEPT_FREAD_UNLOCKED;
INTERCEPT_FUNCTION(readlink);
INTERCEPT_FUNCTION(memcpy);
INTERCEPT_FUNCTION(memccpy);
@@ -1458,73 +1572,73 @@ void InitializeInterceptors() {
INTERCEPT_FUNCTION(strcpy); // NOLINT
INTERCEPT_FUNCTION(stpcpy); // NOLINT
INTERCEPT_FUNCTION(strdup);
- INTERCEPT_FUNCTION(__strdup);
+ MSAN_MAYBE_INTERCEPT___STRDUP;
INTERCEPT_FUNCTION(strndup);
- INTERCEPT_FUNCTION(__strndup);
+ MSAN_MAYBE_INTERCEPT___STRNDUP;
INTERCEPT_FUNCTION(strncpy); // NOLINT
INTERCEPT_FUNCTION(strlen);
INTERCEPT_FUNCTION(strnlen);
INTERCEPT_FUNCTION(gcvt);
INTERCEPT_FUNCTION(strcat); // NOLINT
INTERCEPT_FUNCTION(strncat); // NOLINT
- INTERCEPT_FUNCTION(strtol);
- INTERCEPT_FUNCTION(strtoll);
- INTERCEPT_FUNCTION(strtoul);
- INTERCEPT_FUNCTION(strtoull);
- INTERCEPT_FUNCTION(strtod);
- INTERCEPT_FUNCTION(strtod_l);
- INTERCEPT_FUNCTION(__strtod_l);
- INTERCEPT_FUNCTION(strtof);
- INTERCEPT_FUNCTION(strtof_l);
- INTERCEPT_FUNCTION(__strtof_l);
- INTERCEPT_FUNCTION(strtold);
- INTERCEPT_FUNCTION(strtold_l);
- INTERCEPT_FUNCTION(__strtold_l);
- INTERCEPT_FUNCTION(vasprintf);
- INTERCEPT_FUNCTION(asprintf);
- INTERCEPT_FUNCTION(vsprintf);
- INTERCEPT_FUNCTION(vsnprintf);
+ INTERCEPT_STRTO(strtod);
+ INTERCEPT_STRTO(strtof);
+ INTERCEPT_STRTO(strtold);
+ INTERCEPT_STRTO(strtol);
+ INTERCEPT_STRTO(strtoul);
+ INTERCEPT_STRTO(strtoll);
+ INTERCEPT_STRTO(strtoull);
+ INTERCEPT_STRTO(wcstod);
+ INTERCEPT_STRTO(wcstof);
+ INTERCEPT_STRTO(wcstold);
+ INTERCEPT_STRTO(wcstol);
+ INTERCEPT_STRTO(wcstoul);
+ INTERCEPT_STRTO(wcstoll);
+ INTERCEPT_STRTO(wcstoull);
INTERCEPT_FUNCTION(vswprintf);
- INTERCEPT_FUNCTION(sprintf); // NOLINT
- INTERCEPT_FUNCTION(snprintf);
INTERCEPT_FUNCTION(swprintf);
+ INTERCEPT_FUNCTION(strxfrm);
+ INTERCEPT_FUNCTION(strxfrm_l);
INTERCEPT_FUNCTION(strftime);
+ INTERCEPT_FUNCTION(strftime_l);
+ MSAN_MAYBE_INTERCEPT___STRFTIME_L;
+ INTERCEPT_FUNCTION(wcsftime);
+ INTERCEPT_FUNCTION(wcsftime_l);
+ MSAN_MAYBE_INTERCEPT___WCSFTIME_L;
INTERCEPT_FUNCTION(mbtowc);
INTERCEPT_FUNCTION(mbrtowc);
INTERCEPT_FUNCTION(wcslen);
INTERCEPT_FUNCTION(wcschr);
INTERCEPT_FUNCTION(wcscpy);
INTERCEPT_FUNCTION(wcscmp);
- INTERCEPT_FUNCTION(wcstod);
INTERCEPT_FUNCTION(getenv);
INTERCEPT_FUNCTION(setenv);
INTERCEPT_FUNCTION(putenv);
INTERCEPT_FUNCTION(gettimeofday);
INTERCEPT_FUNCTION(fcvt);
- INTERCEPT_FUNCTION(__fxstat);
- INTERCEPT_FUNCTION(__fxstatat);
- INTERCEPT_FUNCTION(__xstat);
- INTERCEPT_FUNCTION(__lxstat);
- INTERCEPT_FUNCTION(__fxstat64);
- INTERCEPT_FUNCTION(__fxstatat64);
- INTERCEPT_FUNCTION(__xstat64);
- INTERCEPT_FUNCTION(__lxstat64);
+ MSAN_MAYBE_INTERCEPT___FXSTAT;
+ MSAN_MAYBE_INTERCEPT___FXSTATAT;
+ MSAN_MAYBE_INTERCEPT___XSTAT;
+ MSAN_MAYBE_INTERCEPT___LXSTAT;
+ MSAN_MAYBE_INTERCEPT___FXSTAT64;
+ MSAN_MAYBE_INTERCEPT___FXSTATAT64;
+ MSAN_MAYBE_INTERCEPT___XSTAT64;
+ MSAN_MAYBE_INTERCEPT___LXSTAT64;
INTERCEPT_FUNCTION(pipe);
INTERCEPT_FUNCTION(pipe2);
INTERCEPT_FUNCTION(socketpair);
INTERCEPT_FUNCTION(fgets);
- INTERCEPT_FUNCTION(fgets_unlocked);
+ MSAN_MAYBE_INTERCEPT_FGETS_UNLOCKED;
INTERCEPT_FUNCTION(getrlimit);
- INTERCEPT_FUNCTION(getrlimit64);
+ MSAN_MAYBE_INTERCEPT_GETRLIMIT64;
INTERCEPT_FUNCTION(uname);
INTERCEPT_FUNCTION(gethostname);
- INTERCEPT_FUNCTION(epoll_wait);
- INTERCEPT_FUNCTION(epoll_pwait);
+ MSAN_MAYBE_INTERCEPT_EPOLL_WAIT;
+ MSAN_MAYBE_INTERCEPT_EPOLL_PWAIT;
INTERCEPT_FUNCTION(recv);
INTERCEPT_FUNCTION(recvfrom);
INTERCEPT_FUNCTION(dladdr);
INTERCEPT_FUNCTION(dlerror);
- INTERCEPT_FUNCTION(dlopen);
INTERCEPT_FUNCTION(dl_iterate_phdr);
INTERCEPT_FUNCTION(getrusage);
INTERCEPT_FUNCTION(sigaction);
@@ -1535,11 +1649,7 @@ void InitializeInterceptors() {
INTERCEPT_FUNCTION(tzset);
INTERCEPT_FUNCTION(__cxa_atexit);
INTERCEPT_FUNCTION(shmat);
-
- if (REAL(pthread_key_create)(&g_thread_finalize_key, &thread_finalize)) {
- Printf("MemorySanitizer: failed to create thread key\n");
- Die();
- }
+ INTERCEPT_FUNCTION(fork);
inited = 1;
}
diff --git a/lib/msan/msan_interface_internal.h b/lib/msan/msan_interface_internal.h
index 794b3540f931..8641f814bc5f 100644
--- a/lib/msan/msan_interface_internal.h
+++ b/lib/msan/msan_interface_internal.h
@@ -38,8 +38,28 @@ SANITIZER_INTERFACE_ATTRIBUTE __attribute__((noreturn))
void __msan_warning_noreturn();
SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_maybe_warning_1(u8 s, u32 o);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_maybe_warning_2(u16 s, u32 o);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_maybe_warning_4(u32 s, u32 o);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_maybe_warning_8(u64 s, u32 o);
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_maybe_store_origin_1(u8 s, void *p, u32 o);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_maybe_store_origin_2(u16 s, void *p, u32 o);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_maybe_store_origin_4(u32 s, void *p, u32 o);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_maybe_store_origin_8(u64 s, void *p, u32 o);
+
+SANITIZER_INTERFACE_ATTRIBUTE
void __msan_unpoison(const void *a, uptr size);
SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_unpoison_string(const char *s);
+SANITIZER_INTERFACE_ATTRIBUTE
void __msan_clear_and_unpoison(void *a, uptr size);
SANITIZER_INTERFACE_ATTRIBUTE
void* __msan_memcpy(void *dst, const void *src, uptr size);
@@ -48,12 +68,6 @@ void* __msan_memset(void *s, int c, uptr n);
SANITIZER_INTERFACE_ATTRIBUTE
void* __msan_memmove(void* dest, const void* src, uptr n);
SANITIZER_INTERFACE_ATTRIBUTE
-void __msan_copy_poison(void *dst, const void *src, uptr size);
-SANITIZER_INTERFACE_ATTRIBUTE
-void __msan_copy_origin(void *dst, const void *src, uptr size);
-SANITIZER_INTERFACE_ATTRIBUTE
-void __msan_move_poison(void *dst, const void *src, uptr size);
-SANITIZER_INTERFACE_ATTRIBUTE
void __msan_poison(const void *a, uptr size);
SANITIZER_INTERFACE_ATTRIBUTE
void __msan_poison_stack(void *a, uptr size);
@@ -69,11 +83,16 @@ SANITIZER_INTERFACE_ATTRIBUTE
sptr __msan_test_shadow(const void *x, uptr size);
SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_check_mem_is_initialized(const void *x, uptr size);
+
+SANITIZER_INTERFACE_ATTRIBUTE
void __msan_set_origin(const void *a, uptr size, u32 origin);
SANITIZER_INTERFACE_ATTRIBUTE
-void __msan_set_alloca_origin(void *a, uptr size, const char *descr);
+void __msan_set_alloca_origin(void *a, uptr size, char *descr);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_set_alloca_origin4(void *a, uptr size, char *descr, uptr pc);
SANITIZER_INTERFACE_ATTRIBUTE
-void __msan_set_alloca_origin4(void *a, uptr size, const char *descr, uptr pc);
+u32 __msan_chain_origin(u32 id);
SANITIZER_INTERFACE_ATTRIBUTE
u32 __msan_get_origin(const void *a);
@@ -99,26 +118,14 @@ void __msan_set_expect_umr(int expect_umr);
SANITIZER_INTERFACE_ATTRIBUTE
void __msan_print_shadow(const void *x, uptr size);
SANITIZER_INTERFACE_ATTRIBUTE
-void __msan_print_param_shadow();
+void __msan_dump_shadow(const void *x, uptr size);
SANITIZER_INTERFACE_ATTRIBUTE
int __msan_has_dynamic_component();
-// Returns x such that %fs:x is the first byte of __msan_retval_tls.
-SANITIZER_INTERFACE_ATTRIBUTE
-int __msan_get_retval_tls_offset();
-SANITIZER_INTERFACE_ATTRIBUTE
-int __msan_get_param_tls_offset();
-
-// For intercepting mmap from ld.so in msandr.
-SANITIZER_INTERFACE_ATTRIBUTE
-bool __msan_is_in_loader();
-
// For testing.
SANITIZER_INTERFACE_ATTRIBUTE
u32 __msan_get_umr_origin();
SANITIZER_INTERFACE_ATTRIBUTE
-const char *__msan_get_origin_descr_if_stack(u32 id);
-SANITIZER_INTERFACE_ATTRIBUTE
void __msan_partial_poison(const void* data, void* shadow, uptr size);
// Tell MSan about newly allocated memory (ex.: custom allocator).
@@ -145,31 +152,7 @@ SANITIZER_INTERFACE_ATTRIBUTE
void __sanitizer_unaligned_store64(uu64 *p, u64 x);
SANITIZER_INTERFACE_ATTRIBUTE
-uptr __msan_get_estimated_allocated_size(uptr size);
-
-SANITIZER_INTERFACE_ATTRIBUTE
-int __msan_get_ownership(const void *p);
-
-SANITIZER_INTERFACE_ATTRIBUTE
-uptr __msan_get_allocated_size(const void *p);
-
-SANITIZER_INTERFACE_ATTRIBUTE
-uptr __msan_get_current_allocated_bytes();
-
-SANITIZER_INTERFACE_ATTRIBUTE
-uptr __msan_get_heap_size();
-
-SANITIZER_INTERFACE_ATTRIBUTE
-uptr __msan_get_free_bytes();
-
-SANITIZER_INTERFACE_ATTRIBUTE
-uptr __msan_get_unmapped_bytes();
-
-SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
-/* OPTIONAL */ void __msan_malloc_hook(void *ptr, uptr size);
-
-SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
-/* OPTIONAL */ void __msan_free_hook(void *ptr);
+void __msan_set_death_callback(void (*callback)(void));
} // extern "C"
#endif // MSAN_INTERFACE_INTERNAL_H
diff --git a/lib/msan/msan_linux.cc b/lib/msan/msan_linux.cc
index 46f501e488c5..0b67b531d51c 100644
--- a/lib/msan/msan_linux.cc
+++ b/lib/msan/msan_linux.cc
@@ -9,16 +9,18 @@
//
// This file is a part of MemorySanitizer.
//
-// Linux-specific code.
+// Linux- and FreeBSD-specific code.
//===----------------------------------------------------------------------===//
#include "sanitizer_common/sanitizer_platform.h"
-#if SANITIZER_LINUX
+#if SANITIZER_FREEBSD || SANITIZER_LINUX
#include "msan.h"
+#include "msan_thread.h"
#include <elf.h>
#include <link.h>
+#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
@@ -33,63 +35,117 @@
namespace __msan {
-static const uptr kMemBeg = 0x600000000000;
-static const uptr kMemEnd = 0x7fffffffffff;
-static const uptr kShadowBeg = MEM_TO_SHADOW(kMemBeg);
-static const uptr kShadowEnd = MEM_TO_SHADOW(kMemEnd);
-static const uptr kBad1Beg = 0x100000000; // 4G
-static const uptr kBad1End = kShadowBeg - 1;
-static const uptr kBad2Beg = kShadowEnd + 1;
-static const uptr kBad2End = kMemBeg - 1;
-static const uptr kOriginsBeg = kBad2Beg;
-static const uptr kOriginsEnd = kBad2End;
-
-bool InitShadow(bool prot1, bool prot2, bool map_shadow, bool init_origins) {
- if ((uptr) & InitShadow < kMemBeg) {
- Printf("FATAL: Code below application range: %p < %p. Non-PIE build?\n",
- &InitShadow, (void *)kMemBeg);
- return false;
+void ReportMapRange(const char *descr, uptr beg, uptr size) {
+ if (size > 0) {
+ uptr end = beg + size - 1;
+ VPrintf(1, "%s : %p - %p\n", descr, beg, end);
}
+}
- if (common_flags()->verbosity) {
- Printf("__msan_init %p\n", &__msan_init);
- Printf("Memory : %p %p\n", kMemBeg, kMemEnd);
- Printf("Bad2 : %p %p\n", kBad2Beg, kBad2End);
- Printf("Origins : %p %p\n", kOriginsBeg, kOriginsEnd);
- Printf("Shadow : %p %p\n", kShadowBeg, kShadowEnd);
- Printf("Bad1 : %p %p\n", kBad1Beg, kBad1End);
+static bool CheckMemoryRangeAvailability(uptr beg, uptr size) {
+ if (size > 0) {
+ uptr end = beg + size - 1;
+ if (!MemoryRangeIsAvailable(beg, end)) {
+ Printf("FATAL: Memory range %p - %p is not available.\n", beg, end);
+ return false;
+ }
}
+ return true;
+}
- if (!MemoryRangeIsAvailable(kShadowBeg,
- init_origins ? kOriginsEnd : kShadowEnd)) {
- Printf("FATAL: Shadow memory range is not available.\n");
+static bool ProtectMemoryRange(uptr beg, uptr size) {
+ if (size > 0) {
+ uptr end = beg + size - 1;
+ if (!Mprotect(beg, size)) {
+ Printf("FATAL: Cannot protect memory range %p - %p.\n", beg, end);
+ return false;
+ }
+ }
+ return true;
+}
+
+bool InitShadow(bool map_shadow, bool init_origins) {
+ // Let user know mapping parameters first.
+ VPrintf(1, "__msan_init %p\n", &__msan_init);
+ ReportMapRange("Low Memory ", kLowMemBeg, kLowMemSize);
+ ReportMapRange("Bad1 ", kBad1Beg, kBad1Size);
+ ReportMapRange("Shadow ", kShadowBeg, kShadowSize);
+ ReportMapRange("Bad2 ", kBad2Beg, kBad2Size);
+ ReportMapRange("Origins ", kOriginsBeg, kOriginsSize);
+ ReportMapRange("Bad3 ", kBad3Beg, kBad3Size);
+ ReportMapRange("High Memory", kHighMemBeg, kHighMemSize);
+
+ // Check mapping sanity (the invariant).
+ CHECK_EQ(kLowMemBeg, 0);
+ CHECK_EQ(kBad1Beg, kLowMemBeg + kLowMemSize);
+ CHECK_EQ(kShadowBeg, kBad1Beg + kBad1Size);
+ CHECK_GT(kShadowSize, 0);
+ CHECK_GE(kShadowSize, kLowMemSize + kHighMemSize);
+ CHECK_EQ(kBad2Beg, kShadowBeg + kShadowSize);
+ CHECK_EQ(kOriginsBeg, kBad2Beg + kBad2Size);
+ CHECK_EQ(kOriginsSize, kShadowSize);
+ CHECK_EQ(kBad3Beg, kOriginsBeg + kOriginsSize);
+ CHECK_EQ(kHighMemBeg, kBad3Beg + kBad3Size);
+ CHECK_GT(kHighMemSize, 0);
+ CHECK_GE(kHighMemBeg + kHighMemSize, kHighMemBeg); // Tests for no overflow.
+
+ if (kLowMemSize > 0) {
+ CHECK(MEM_IS_SHADOW(MEM_TO_SHADOW(kLowMemBeg)));
+ CHECK(MEM_IS_SHADOW(MEM_TO_SHADOW(kLowMemBeg + kLowMemSize - 1)));
+ CHECK(MEM_IS_ORIGIN(MEM_TO_ORIGIN(kLowMemBeg)));
+ CHECK(MEM_IS_ORIGIN(MEM_TO_ORIGIN(kLowMemBeg + kLowMemSize - 1)));
+ }
+ CHECK(MEM_IS_SHADOW(MEM_TO_SHADOW(kHighMemBeg)));
+ CHECK(MEM_IS_SHADOW(MEM_TO_SHADOW(kHighMemBeg + kHighMemSize - 1)));
+ CHECK(MEM_IS_ORIGIN(MEM_TO_ORIGIN(kHighMemBeg)));
+ CHECK(MEM_IS_ORIGIN(MEM_TO_ORIGIN(kHighMemBeg + kHighMemSize - 1)));
+
+ if (!MEM_IS_APP(&__msan_init)) {
+ Printf("FATAL: Code %p is out of application range. Non-PIE build?\n",
+ (uptr)&__msan_init);
return false;
}
- if (prot1 && !Mprotect(kBad1Beg, kBad1End - kBad1Beg))
+ if (!CheckMemoryRangeAvailability(kShadowBeg, kShadowSize) ||
+ (init_origins &&
+ !CheckMemoryRangeAvailability(kOriginsBeg, kOriginsSize)) ||
+ !CheckMemoryRangeAvailability(kBad1Beg, kBad1Size) ||
+ !CheckMemoryRangeAvailability(kBad2Beg, kBad2Size) ||
+ !CheckMemoryRangeAvailability(kBad3Beg, kBad3Size)) {
return false;
- if (prot2 && !Mprotect(kBad2Beg, kBad2End - kBad2Beg))
+ }
+
+ if (!ProtectMemoryRange(kBad1Beg, kBad1Size) ||
+ !ProtectMemoryRange(kBad2Beg, kBad2Size) ||
+ !ProtectMemoryRange(kBad3Beg, kBad3Size)) {
return false;
+ }
+
if (map_shadow) {
- void *shadow = MmapFixedNoReserve(kShadowBeg, kShadowEnd - kShadowBeg);
+ void *shadow = MmapFixedNoReserve(kShadowBeg, kShadowSize);
if (shadow != (void*)kShadowBeg) return false;
}
if (init_origins) {
- void *origins = MmapFixedNoReserve(kOriginsBeg, kOriginsEnd - kOriginsBeg);
+ void *origins = MmapFixedNoReserve(kOriginsBeg, kOriginsSize);
if (origins != (void*)kOriginsBeg) return false;
}
return true;
}
void MsanDie() {
+ if (common_flags()->coverage)
+ __sanitizer_cov_dump();
+ if (death_callback)
+ death_callback();
_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 (flags()->exit_code) _exit(flags()->exit_code);
}
}
@@ -97,6 +153,36 @@ void InstallAtExitHandler() {
atexit(MsanAtExit);
}
+// ---------------------- TSD ---------------- {{{1
+
+static pthread_key_t tsd_key;
+static bool tsd_key_inited = false;
+void MsanTSDInit(void (*destructor)(void *tsd)) {
+ CHECK(!tsd_key_inited);
+ tsd_key_inited = true;
+ CHECK_EQ(0, pthread_key_create(&tsd_key, destructor));
+}
+
+void *MsanTSDGet() {
+ CHECK(tsd_key_inited);
+ return pthread_getspecific(tsd_key);
+}
+
+void MsanTSDSet(void *tsd) {
+ CHECK(tsd_key_inited);
+ pthread_setspecific(tsd_key, tsd);
+}
+
+void MsanTSDDtor(void *tsd) {
+ MsanThread *t = (MsanThread*)tsd;
+ if (t->destructor_iterations_ > 1) {
+ t->destructor_iterations_--;
+ CHECK_EQ(0, pthread_setspecific(tsd_key, tsd));
+ return;
+ }
+ MsanThread::TSDDtor(tsd);
+}
+
} // namespace __msan
-#endif // __linux__
+#endif // SANITIZER_FREEBSD || SANITIZER_LINUX
diff --git a/lib/msan/msan_new_delete.cc b/lib/msan/msan_new_delete.cc
index 17687ddfc213..9a8e56e4a28a 100644
--- a/lib/msan/msan_new_delete.cc
+++ b/lib/msan/msan_new_delete.cc
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "msan.h"
+#include "interception/interception.h"
#if MSAN_REPLACE_OPERATORS_NEW_AND_DELETE
@@ -37,18 +38,26 @@ namespace std {
GET_MALLOC_STACK_TRACE; \
return MsanReallocate(&stack, 0, size, sizeof(u64), false)
+INTERCEPTOR_ATTRIBUTE
void *operator new(size_t size) { OPERATOR_NEW_BODY; }
+INTERCEPTOR_ATTRIBUTE
void *operator new[](size_t size) { OPERATOR_NEW_BODY; }
+INTERCEPTOR_ATTRIBUTE
void *operator new(size_t size, std::nothrow_t const&) { OPERATOR_NEW_BODY; }
+INTERCEPTOR_ATTRIBUTE
void *operator new[](size_t size, std::nothrow_t const&) { OPERATOR_NEW_BODY; }
#define OPERATOR_DELETE_BODY \
GET_MALLOC_STACK_TRACE; \
if (ptr) MsanDeallocate(&stack, ptr)
-void operator delete(void *ptr) { OPERATOR_DELETE_BODY; }
-void operator delete[](void *ptr) { OPERATOR_DELETE_BODY; }
+INTERCEPTOR_ATTRIBUTE
+void operator delete(void *ptr) throw() { OPERATOR_DELETE_BODY; }
+INTERCEPTOR_ATTRIBUTE
+void operator delete[](void *ptr) throw() { OPERATOR_DELETE_BODY; }
+INTERCEPTOR_ATTRIBUTE
void operator delete(void *ptr, std::nothrow_t const&) { OPERATOR_DELETE_BODY; }
+INTERCEPTOR_ATTRIBUTE
void operator delete[](void *ptr, std::nothrow_t const&) {
OPERATOR_DELETE_BODY;
}
diff --git a/lib/msan/msan_origin.h b/lib/msan/msan_origin.h
new file mode 100644
index 000000000000..1284c01bf2af
--- /dev/null
+++ b/lib/msan/msan_origin.h
@@ -0,0 +1,169 @@
+//===-- msan_origin.h ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Origin id utils.
+//===----------------------------------------------------------------------===//
+#ifndef MSAN_ORIGIN_H
+#define MSAN_ORIGIN_H
+
+#include "sanitizer_common/sanitizer_stackdepot.h"
+#include "msan_chained_origin_depot.h"
+
+namespace __msan {
+
+// Origin handling.
+//
+// Origin is a 32-bit identifier that is attached to any uninitialized value in
+// the program and describes, more or less exactly, how this memory came to be
+// uninitialized.
+//
+// There are 3 kinds of origin ids:
+// 1xxx xxxx xxxx xxxx heap origin id
+// 0000 xxxx xxxx xxxx stack origin id
+// 0zzz xxxx xxxx xxxx chained origin id
+//
+// Heap origin id describes a heap memory allocation and contains (in the xxx
+// part) a value of StackDepot.
+//
+// Stack origin id describes a stack memory allocation and contains (in the xxx
+// part) an index into StackOriginDescr and StackOriginPC. We don't store a
+// stack trace for such origins for performance reasons.
+//
+// Chained origin id describes an event of storing an uninitialized value to
+// memory. The xxx part is a value of ChainedOriginDepot, which is a mapping of
+// (stack_id, prev_id) -> id, where
+// * stack_id describes the event.
+// StackDepot keeps a mapping between those and corresponding stack traces.
+// * prev_id is another origin id that describes the earlier part of the
+// uninitialized value history.
+// Following a chain of prev_id provides the full recorded history of an
+// uninitialized value.
+//
+// This, effectively, defines a tree (or 2 trees, see below) where nodes are
+// points in value history marked with origin ids, and edges are events that are
+// marked with stack_id.
+//
+// The "zzz" bits of chained origin id are used to store the length (or depth)
+// of the origin chain.
+
+class Origin {
+ public:
+ static bool isValidId(u32 id) { return id != 0 && id != (u32)-1; }
+
+ u32 raw_id() const { return raw_id_; }
+ bool isHeapOrigin() const {
+ // 1xxx xxxx xxxx xxxx
+ return raw_id_ >> kHeapShift == 0;
+ }
+ bool isStackOrigin() const {
+ // 1000 xxxx xxxx xxxx
+ return (raw_id_ >> kDepthShift) == (1 << kDepthBits);
+ }
+ bool isChainedOrigin() const {
+ // 1zzz xxxx xxxx xxxx, zzz != 000
+ return (raw_id_ >> kDepthShift) > (1 << kDepthBits);
+ }
+ u32 getChainedId() const {
+ CHECK(isChainedOrigin());
+ return raw_id_ & kChainedIdMask;
+ }
+ u32 getStackId() const {
+ CHECK(isStackOrigin());
+ return raw_id_ & kChainedIdMask;
+ }
+ u32 getHeapId() const {
+ CHECK(isHeapOrigin());
+ return raw_id_ & kHeapIdMask;
+ }
+
+ // Returns the next origin in the chain and the current stack trace.
+ Origin getNextChainedOrigin(StackTrace *stack) const {
+ CHECK(isChainedOrigin());
+ u32 prev_id;
+ u32 stack_id = ChainedOriginDepotGet(getChainedId(), &prev_id);
+ *stack = StackDepotGet(stack_id);
+ return Origin(prev_id);
+ }
+
+ StackTrace getStackTraceForHeapOrigin() const {
+ return StackDepotGet(getHeapId());
+ }
+
+ static Origin CreateStackOrigin(u32 id) {
+ CHECK((id & kStackIdMask) == id);
+ return Origin((1 << kHeapShift) | id);
+ }
+
+ static Origin CreateHeapOrigin(StackTrace *stack) {
+ u32 stack_id = StackDepotPut(*stack);
+ CHECK(stack_id);
+ CHECK((stack_id & kHeapIdMask) == stack_id);
+ return Origin(stack_id);
+ }
+
+ static Origin CreateChainedOrigin(Origin prev, StackTrace *stack) {
+ int depth = prev.isChainedOrigin() ? prev.depth() : 0;
+ // depth is the length of the chain minus 1.
+ // origin_history_size of 0 means unlimited depth.
+ if (flags()->origin_history_size > 0) {
+ if (depth + 1 >= flags()->origin_history_size) {
+ return prev;
+ } else {
+ ++depth;
+ CHECK(depth < (1 << kDepthBits));
+ }
+ }
+
+ StackDepotHandle h = StackDepotPut_WithHandle(*stack);
+ if (!h.valid()) return prev;
+
+ if (flags()->origin_history_per_stack_limit > 0) {
+ int use_count = h.use_count();
+ if (use_count > flags()->origin_history_per_stack_limit) return prev;
+ }
+
+ u32 chained_id;
+ bool inserted = ChainedOriginDepotPut(h.id(), prev.raw_id(), &chained_id);
+ CHECK((chained_id & kChainedIdMask) == chained_id);
+
+ if (inserted && flags()->origin_history_per_stack_limit > 0)
+ h.inc_use_count_unsafe();
+
+ return Origin((1 << kHeapShift) | (depth << kDepthShift) | chained_id);
+ }
+
+ static Origin FromRawId(u32 id) {
+ return Origin(id);
+ }
+
+ private:
+ static const int kDepthBits = 3;
+ static const int kDepthShift = 32 - kDepthBits - 1;
+
+ static const int kHeapShift = 31;
+ static const u32 kChainedIdMask = ((u32)-1) >> (32 - kDepthShift);
+ static const u32 kStackIdMask = ((u32)-1) >> (32 - kDepthShift);
+ static const u32 kHeapIdMask = ((u32)-1) >> (32 - kHeapShift);
+
+ u32 raw_id_;
+
+ explicit Origin(u32 raw_id) : raw_id_(raw_id) {}
+
+ int depth() const {
+ CHECK(isChainedOrigin());
+ return (raw_id_ >> kDepthShift) & ((1 << kDepthBits) - 1);
+ }
+
+ public:
+ static const int kMaxDepth = (1 << kDepthBits) - 1;
+};
+
+} // namespace __msan
+
+#endif // MSAN_ORIGIN_H
diff --git a/lib/msan/msan_report.cc b/lib/msan/msan_report.cc
index e3ef99307940..717c4a958c8f 100644
--- a/lib/msan/msan_report.cc
+++ b/lib/msan/msan_report.cc
@@ -13,6 +13,8 @@
//===----------------------------------------------------------------------===//
#include "msan.h"
+#include "msan_chained_origin_depot.h"
+#include "msan_origin.h"
#include "sanitizer_common/sanitizer_allocator_internal.h"
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_flags.h"
@@ -25,44 +27,57 @@ using namespace __sanitizer;
namespace __msan {
-class Decorator: private __sanitizer::AnsiColorDecorator {
+class Decorator: public __sanitizer::SanitizerCommonDecorator {
public:
- Decorator() : __sanitizer::AnsiColorDecorator(PrintsToTtyCached()) { }
+ Decorator() : SanitizerCommonDecorator() { }
const char *Warning() { return Red(); }
const char *Origin() { return Magenta(); }
const char *Name() { return Green(); }
const char *End() { return Default(); }
};
-static void DescribeOrigin(u32 origin) {
+static void DescribeStackOrigin(const char *so, uptr pc) {
Decorator d;
- if (common_flags()->verbosity)
- Printf(" raw origin id: %d\n", origin);
- uptr pc;
- if (const char *so = GetOriginDescrIfStack(origin, &pc)) {
- char* s = internal_strdup(so);
- char* sep = internal_strchr(s, '@');
- CHECK(sep);
- *sep = '\0';
- Printf("%s", d.Origin());
- Printf(" %sUninitialized value was created by an allocation of '%s%s%s'"
- " in the stack frame of function '%s%s%s'%s\n",
- d.Origin(), d.Name(), s, d.Origin(), d.Name(),
- Symbolizer::Get()->Demangle(sep + 1), d.Origin(), d.End());
- InternalFree(s);
-
- if (pc) {
- // For some reason function address in LLVM IR is 1 less then the address
- // of the first instruction.
- pc += 1;
- StackTrace::PrintStack(&pc, 1);
- }
+ char *s = internal_strdup(so);
+ char *sep = internal_strchr(s, '@');
+ CHECK(sep);
+ *sep = '\0';
+ Printf("%s", d.Origin());
+ Printf(
+ " %sUninitialized value was created by an allocation of '%s%s%s'"
+ " in the stack frame of function '%s%s%s'%s\n",
+ d.Origin(), d.Name(), s, d.Origin(), d.Name(), sep + 1, d.Origin(),
+ d.End());
+ InternalFree(s);
+
+ if (pc) {
+ // For some reason function address in LLVM IR is 1 less then the address
+ // of the first instruction.
+ pc = StackTrace::GetNextInstructionPc(pc);
+ StackTrace(&pc, 1).Print();
+ }
+}
+
+static void DescribeOrigin(u32 id) {
+ VPrintf(1, " raw origin id: %d\n", id);
+ Decorator d;
+ Origin o = Origin::FromRawId(id);
+ while (o.isChainedOrigin()) {
+ StackTrace stack;
+ o = o.getNextChainedOrigin(&stack);
+ Printf(" %sUninitialized value was stored to memory at%s\n", d.Origin(),
+ d.End());
+ stack.Print();
+ }
+ if (o.isStackOrigin()) {
+ uptr pc;
+ const char *so = GetStackOriginDescr(o.getStackId(), &pc);
+ DescribeStackOrigin(so, pc);
} else {
- uptr size = 0;
- const uptr *trace = StackDepotGet(origin, &size);
+ StackTrace stack = o.getStackTraceForHeapOrigin();
Printf(" %sUninitialized value was created by a heap allocation%s\n",
d.Origin(), d.End());
- StackTrace::PrintStack(trace, size);
+ stack.Print();
}
}
@@ -75,7 +90,7 @@ void ReportUMR(StackTrace *stack, u32 origin) {
Printf("%s", d.Warning());
Report(" WARNING: MemorySanitizer: use-of-uninitialized-value\n");
Printf("%s", d.End());
- StackTrace::PrintStack(stack->trace, stack->size);
+ stack->Print();
if (origin) {
DescribeOrigin(origin);
}
@@ -86,16 +101,162 @@ void ReportExpectedUMRNotFound(StackTrace *stack) {
SpinMutexLock l(&CommonSanitizerReportMutex);
Printf(" WARNING: Expected use of uninitialized value not found\n");
- StackTrace::PrintStack(stack->trace, stack->size);
+ stack->Print();
+}
+
+void ReportStats() {
+ SpinMutexLock l(&CommonSanitizerReportMutex);
+
+ if (__msan_get_track_origins() > 0) {
+ StackDepotStats *stack_depot_stats = StackDepotGetStats();
+ // FIXME: we want this at normal exit, too!
+ // FIXME: but only with verbosity=1 or something
+ Printf("Unique heap origins: %zu\n", stack_depot_stats->n_uniq_ids);
+ Printf("Stack depot allocated bytes: %zu\n", stack_depot_stats->allocated);
+
+ StackDepotStats *chained_origin_depot_stats = ChainedOriginDepotGetStats();
+ Printf("Unique origin histories: %zu\n",
+ chained_origin_depot_stats->n_uniq_ids);
+ Printf("History depot allocated bytes: %zu\n",
+ chained_origin_depot_stats->allocated);
+ }
}
void ReportAtExitStatistics() {
SpinMutexLock l(&CommonSanitizerReportMutex);
+ if (msan_report_count > 0) {
+ Decorator d;
+ Printf("%s", d.Warning());
+ Printf("MemorySanitizer: %d warnings reported.\n", msan_report_count);
+ Printf("%s", d.End());
+ }
+}
+
+class OriginSet {
+ public:
+ OriginSet() : next_id_(0) {}
+ int insert(u32 o) {
+ // Scan from the end for better locality.
+ for (int i = next_id_ - 1; i >= 0; --i)
+ if (origins_[i] == o) return i;
+ if (next_id_ == kMaxSize_) return OVERFLOW;
+ int id = next_id_++;
+ origins_[id] = o;
+ return id;
+ }
+ int size() { return next_id_; }
+ u32 get(int id) { return origins_[id]; }
+ static char asChar(int id) {
+ switch (id) {
+ case MISSING:
+ return '.';
+ case OVERFLOW:
+ return '*';
+ default:
+ return 'A' + id;
+ }
+ }
+ static const int OVERFLOW = -1;
+ static const int MISSING = -2;
+
+ private:
+ static const int kMaxSize_ = 'Z' - 'A' + 1;
+ u32 origins_[kMaxSize_];
+ int next_id_;
+};
+
+void DescribeMemoryRange(const void *x, uptr size) {
+ // Real limits.
+ uptr start = MEM_TO_SHADOW(x);
+ uptr end = start + size;
+ // Scan limits: align start down to 4; align size up to 16.
+ uptr s = start & ~3UL;
+ size = end - s;
+ size = (size + 15) & ~15UL;
+ uptr e = s + size;
+
+ // Single letter names to origin id mapping.
+ OriginSet origin_set;
+
+ uptr pos = 0; // Offset from aligned start.
+ bool with_origins = __msan_get_track_origins();
+ // True if there is at least 1 poisoned bit in the last 4-byte group.
+ bool last_quad_poisoned;
+ int origin_ids[4]; // Single letter origin ids for the current line.
+
Decorator d;
Printf("%s", d.Warning());
- Printf("MemorySanitizer: %d warnings reported.\n", msan_report_count);
+ Printf("Shadow map of [%p, %p), %zu bytes:\n", start, end, end - start);
Printf("%s", d.End());
+ while (s < e) {
+ // Line start.
+ if (pos % 16 == 0) {
+ for (int i = 0; i < 4; ++i) origin_ids[i] = -1;
+ Printf("%p:", s);
+ }
+ // Group start.
+ if (pos % 4 == 0) {
+ Printf(" ");
+ last_quad_poisoned = false;
+ }
+ // Print shadow byte.
+ if (s < start || s >= end) {
+ Printf("..");
+ } else {
+ unsigned char v = *(unsigned char *)s;
+ if (v) last_quad_poisoned = true;
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+ Printf("%x%x", v & 0xf, v >> 4);
+#else
+ Printf("%x%x", v >> 4, v & 0xf);
+#endif
+ }
+ // Group end.
+ if (pos % 4 == 3 && with_origins) {
+ int id = OriginSet::MISSING;
+ if (last_quad_poisoned) {
+ u32 o = *(u32 *)SHADOW_TO_ORIGIN(s - 3);
+ id = origin_set.insert(o);
+ }
+ origin_ids[(pos % 16) / 4] = id;
+ }
+ // Line end.
+ if (pos % 16 == 15) {
+ if (with_origins) {
+ Printf(" |");
+ for (int i = 0; i < 4; ++i) {
+ char c = OriginSet::asChar(origin_ids[i]);
+ Printf("%c", c);
+ if (i != 3) Printf(" ");
+ }
+ Printf("|");
+ }
+ Printf("\n");
+ }
+ size--;
+ s++;
+ pos++;
+ }
+
+ Printf("\n");
+
+ for (int i = 0; i < origin_set.size(); ++i) {
+ u32 o = origin_set.get(i);
+ Printf("Origin %c (origin_id %x):\n", OriginSet::asChar(i), o);
+ DescribeOrigin(o);
+ }
+}
+
+void ReportUMRInsideAddressRange(const char *what, const void *start, uptr size,
+ uptr offset) {
+ Decorator d;
+ Printf("%s", d.Warning());
+ Printf("%sUninitialized bytes in %s%s%s at offset %zu inside [%p, %zu)%s\n",
+ d.Warning(), d.Name(), what, d.Warning(), offset, start, size,
+ d.End());
+ if (__sanitizer::common_flags()->verbosity > 0)
+ DescribeMemoryRange(start, size);
}
} // namespace __msan
diff --git a/lib/msan/msan_thread.cc b/lib/msan/msan_thread.cc
new file mode 100644
index 000000000000..f29a4b053a36
--- /dev/null
+++ b/lib/msan/msan_thread.cc
@@ -0,0 +1,93 @@
+
+#include "msan.h"
+#include "msan_thread.h"
+#include "msan_interface_internal.h"
+
+#include "sanitizer_common/sanitizer_tls_get_addr.h"
+
+namespace __msan {
+
+MsanThread *MsanThread::Create(thread_callback_t start_routine,
+ void *arg) {
+ uptr PageSize = GetPageSizeCached();
+ uptr size = RoundUpTo(sizeof(MsanThread), PageSize);
+ MsanThread *thread = (MsanThread*)MmapOrDie(size, __func__);
+ thread->start_routine_ = start_routine;
+ thread->arg_ = arg;
+ thread->destructor_iterations_ = kPthreadDestructorIterations;
+
+ return thread;
+}
+
+void MsanThread::SetThreadStackAndTls() {
+ uptr tls_size = 0;
+ uptr stack_size = 0;
+ GetThreadStackAndTls(IsMainThread(), &stack_bottom_, &stack_size,
+ &tls_begin_, &tls_size);
+ stack_top_ = stack_bottom_ + stack_size;
+ tls_end_ = tls_begin_ + tls_size;
+
+ int local;
+ CHECK(AddrIsInStack((uptr)&local));
+}
+
+void MsanThread::ClearShadowForThreadStackAndTLS() {
+ __msan_unpoison((void *)stack_bottom_, stack_top_ - stack_bottom_);
+ if (tls_begin_ != tls_end_)
+ __msan_unpoison((void *)tls_begin_, tls_end_ - tls_begin_);
+ DTLS *dtls = DTLS_Get();
+ CHECK_NE(dtls, 0);
+ for (uptr i = 0; i < dtls->dtv_size; ++i)
+ __msan_unpoison((void *)(dtls->dtv[i].beg), dtls->dtv[i].size);
+}
+
+void MsanThread::Init() {
+ SetThreadStackAndTls();
+ CHECK(MEM_IS_APP(stack_bottom_));
+ CHECK(MEM_IS_APP(stack_top_ - 1));
+ ClearShadowForThreadStackAndTLS();
+}
+
+void MsanThread::TSDDtor(void *tsd) {
+ MsanThread *t = (MsanThread*)tsd;
+ t->Destroy();
+}
+
+void MsanThread::Destroy() {
+ malloc_storage().CommitBack();
+ // We also clear the shadow on thread destruction because
+ // some code may still be executing in later TSD destructors
+ // and we don't want it to have any poisoned stack.
+ ClearShadowForThreadStackAndTLS();
+ uptr size = RoundUpTo(sizeof(MsanThread), GetPageSizeCached());
+ UnmapOrDie(this, size);
+ DTLS_Destroy();
+}
+
+thread_return_t MsanThread::ThreadStart() {
+ Init();
+
+ if (!start_routine_) {
+ // start_routine_ == 0 if we're on the main thread or on one of the
+ // OS X libdispatch worker threads. But nobody is supposed to call
+ // ThreadStart() for the worker threads.
+ return 0;
+ }
+
+ thread_return_t res = start_routine_(arg_);
+
+ return res;
+}
+
+MsanThread *GetCurrentThread() {
+ return reinterpret_cast<MsanThread *>(MsanTSDGet());
+}
+
+void SetCurrentThread(MsanThread *t) {
+ // Make sure we do not reset the current MsanThread.
+ CHECK_EQ(0, MsanTSDGet());
+ MsanTSDSet(t);
+ CHECK_EQ(t, MsanTSDGet());
+}
+
+} // namespace __msan
diff --git a/lib/msan/msan_thread.h b/lib/msan/msan_thread.h
new file mode 100644
index 000000000000..bc605b89a505
--- /dev/null
+++ b/lib/msan/msan_thread.h
@@ -0,0 +1,71 @@
+//===-- msan_thread.h -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of MemorySanitizer.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MSAN_THREAD_H
+#define MSAN_THREAD_H
+
+#include "msan_allocator.h"
+#include "sanitizer_common/sanitizer_common.h"
+
+namespace __msan {
+
+class MsanThread {
+ public:
+ static MsanThread *Create(thread_callback_t start_routine, void *arg);
+ static void TSDDtor(void *tsd);
+ void Destroy();
+
+ void Init(); // Should be called from the thread itself.
+ thread_return_t ThreadStart();
+
+ uptr stack_top() { return stack_top_; }
+ uptr stack_bottom() { return stack_bottom_; }
+ uptr tls_begin() { return tls_begin_; }
+ uptr tls_end() { return tls_end_; }
+ bool IsMainThread() { return start_routine_ == 0; }
+
+ bool AddrIsInStack(uptr addr) {
+ return addr >= stack_bottom_ && addr < stack_top_;
+ }
+
+ bool InSignalHandler() { return in_signal_handler_; }
+ void EnterSignalHandler() { in_signal_handler_++; }
+ void LeaveSignalHandler() { in_signal_handler_--; }
+
+ MsanThreadLocalMallocStorage &malloc_storage() { return malloc_storage_; }
+
+ int destructor_iterations_;
+
+ private:
+ // NOTE: There is no MsanThread constructor. It is allocated
+ // via mmap() and *must* be valid in zero-initialized state.
+ void SetThreadStackAndTls();
+ void ClearShadowForThreadStackAndTLS();
+ thread_callback_t start_routine_;
+ void *arg_;
+ uptr stack_top_;
+ uptr stack_bottom_;
+ uptr tls_begin_;
+ uptr tls_end_;
+
+ unsigned in_signal_handler_;
+
+ MsanThreadLocalMallocStorage malloc_storage_;
+};
+
+MsanThread *GetCurrentThread();
+void SetCurrentThread(MsanThread *t);
+
+} // namespace __msan
+
+#endif // MSAN_THREAD_H
diff --git a/lib/msan/tests/CMakeLists.txt b/lib/msan/tests/CMakeLists.txt
index 9c49f167fa19..53e1b549b70d 100644
--- a/lib/msan/tests/CMakeLists.txt
+++ b/lib/msan/tests/CMakeLists.txt
@@ -5,46 +5,24 @@ include(CompilerRTLink)
include_directories(..)
include_directories(../..)
-# Instrumented libcxx sources and build flags.
-file(GLOB MSAN_LIBCXX_SOURCES ${MSAN_LIBCXX_PATH}/src/*.cpp)
set(MSAN_LIBCXX_CFLAGS
- -I${MSAN_LIBCXX_PATH}/include
-fsanitize=memory
-fsanitize-memory-track-origins
- -fPIC
- -Wno-\#warnings
- -g
- -O2
- -std=c++0x
- -fstrict-aliasing
- -fno-exceptions
- -nostdinc++
- -fno-omit-frame-pointer
- -mno-omit-leaf-frame-pointer)
-set(MSAN_LIBCXX_LINK_FLAGS
- -nodefaultlibs
- -lpthread
- -lrt
- -lc
- -lstdc++
- -fsanitize=memory)
+ -Wno-pedantic)
# Unittest sources and build flags.
set(MSAN_UNITTEST_SOURCES msan_test.cc msan_test_main.cc)
set(MSAN_LOADABLE_SOURCE msan_loadable.cc)
set(MSAN_UNITTEST_HEADERS
msan_test_config.h
- msandr_test_so.h
../../../include/sanitizer/msan_interface.h
)
-set(MSANDR_UNITTEST_SOURCE msandr_test_so.cc)
set(MSAN_UNITTEST_COMMON_CFLAGS
- -I${MSAN_LIBCXX_PATH}/include
- ${COMPILER_RT_GTEST_INCLUDE_CFLAGS}
+ -I${COMPILER_RT_LIBCXX_PATH}/include
+ ${COMPILER_RT_GTEST_CFLAGS}
-I${COMPILER_RT_SOURCE_DIR}/include
-I${COMPILER_RT_SOURCE_DIR}/lib
-I${COMPILER_RT_SOURCE_DIR}/lib/msan
- -std=c++0x
-stdlib=libc++
-g
-O2
@@ -52,6 +30,9 @@ set(MSAN_UNITTEST_COMMON_CFLAGS
-fno-omit-frame-pointer
-mno-omit-leaf-frame-pointer
-Wno-deprecated-declarations
+ -Wno-unused-variable
+ -Wno-zero-length-array
+ -Werror=sign-compare
)
set(MSAN_UNITTEST_INSTRUMENTED_CFLAGS
${MSAN_UNITTEST_COMMON_CFLAGS}
@@ -61,10 +42,11 @@ set(MSAN_UNITTEST_INSTRUMENTED_CFLAGS
)
set(MSAN_UNITTEST_LINK_FLAGS
-fsanitize=memory
- -ldl
# 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
@@ -72,20 +54,27 @@ set(MSAN_LOADABLE_LINK_FLAGS
# Compile source for the given architecture, using compiler
# options in ${ARGN}, and add it to the object list.
-macro(msan_compile obj_list source arch)
+macro(msan_compile obj_list source arch kind)
get_filename_component(basename ${source} NAME)
- set(output_obj "${basename}.${arch}.o")
+ set(output_obj "${basename}.${arch}${kind}.o")
get_target_flags_for_arch(${arch} TARGET_CFLAGS)
+ set(COMPILE_DEPS ${MSAN_UNITTEST_HEADERS})
+ if(NOT COMPILER_RT_STANDALONE_BUILD)
+ list(APPEND COMPILE_DEPS gtest msan)
+ endif()
clang_compile(${output_obj} ${source}
CFLAGS ${ARGN} ${TARGET_CFLAGS}
- DEPS gtest ${MSAN_RUNTIME_LIBRARIES} ${MSAN_UNITTEST_HEADERS})
+ DEPS ${COMPILE_DEPS})
list(APPEND ${obj_list} ${output_obj})
endmacro()
-macro(msan_link_shared so_list so_name arch)
+macro(msan_link_shared so_list so_name arch kind)
parse_arguments(SOURCE "OBJECTS;LINKFLAGS;DEPS" "" ${ARGN})
- set(output_so "${CMAKE_CURRENT_BINARY_DIR}/${so_name}.${arch}.so")
+ set(output_so "${CMAKE_CURRENT_BINARY_DIR}/${so_name}.${arch}${kind}.so")
get_target_flags_for_arch(${arch} TARGET_LINKFLAGS)
+ if(NOT COMPILER_RT_STANDALONE_BUILD)
+ list(APPEND SOURCE_DEPS msan)
+ endif()
clang_link_shared(${output_so}
OBJECTS ${SOURCE_OBJECTS}
LINKFLAGS ${TARGET_LINKFLAGS} ${SOURCE_LINKFLAGS}
@@ -93,80 +82,62 @@ macro(msan_link_shared so_list so_name arch)
list(APPEND ${so_list} ${output_so})
endmacro()
-# Link MSan unit test for a given architecture from a set
-# of objects in ${ARGN}.
-macro(add_msan_test test_suite test_name arch)
- get_target_flags_for_arch(${arch} TARGET_LINK_FLAGS)
- add_compiler_rt_test(${test_suite} ${test_name}
- OBJECTS ${ARGN}
- DEPS ${MSAN_RUNTIME_LIBRARIES} ${ARGN}
- ${MSAN_LOADABLE_SO}
- LINK_FLAGS ${MSAN_UNITTEST_LINK_FLAGS}
- ${TARGET_LINK_FLAGS}
- "-Wl,-rpath=${CMAKE_CURRENT_BINARY_DIR}")
-endmacro()
-
# Main MemorySanitizer unit tests.
add_custom_target(MsanUnitTests)
set_target_properties(MsanUnitTests PROPERTIES FOLDER "MSan unit tests")
# Adds MSan unit tests and benchmarks for architecture.
-macro(add_msan_tests_for_arch arch)
+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}
- ${MSAN_UNITTEST_INSTRUMENTED_CFLAGS})
-
- # Build libcxx instrumented with MSan.
- set(MSAN_INST_LIBCXX_OBJECTS)
- foreach(SOURCE ${MSAN_LIBCXX_SOURCES})
- msan_compile(MSAN_INST_LIBCXX_OBJECTS ${SOURCE} ${arch}
- ${MSAN_LIBCXX_CFLAGS})
- endforeach(SOURCE)
-
- set(MSAN_INST_LIBCXX)
- msan_link_shared(MSAN_INST_LIBCXX "libcxx" ${arch}
- OBJECTS ${MSAN_INST_LIBCXX_OBJECTS}
- LINKFLAGS ${MSAN_LIBCXX_LINK_FLAGS}
- DEPS ${MSAN_INST_LIBCXX_OBJECTS} ${MSAN_RUNTIME_LIBRARIES})
+ msan_compile(MSAN_INST_GTEST ${COMPILER_RT_GTEST_SOURCE} ${arch} "${kind}"
+ ${MSAN_UNITTEST_INSTRUMENTED_CFLAGS} ${ARGN})
# Instrumented tests.
set(MSAN_INST_TEST_OBJECTS)
foreach (SOURCE ${MSAN_UNITTEST_SOURCES})
- msan_compile(MSAN_INST_TEST_OBJECTS ${SOURCE} ${arch}
- ${MSAN_UNITTEST_INSTRUMENTED_CFLAGS})
+ msan_compile(MSAN_INST_TEST_OBJECTS ${SOURCE} ${arch} "${kind}"
+ ${MSAN_UNITTEST_INSTRUMENTED_CFLAGS} ${ARGN})
endforeach(SOURCE)
# Instrumented loadable module objects.
set(MSAN_INST_LOADABLE_OBJECTS)
- msan_compile(MSAN_INST_LOADABLE_OBJECTS ${MSAN_LOADABLE_SOURCE} ${arch}
- ${MSAN_UNITTEST_INSTRUMENTED_CFLAGS})
-
- # Uninstrumented shared object for MSanDR tests.
- set(MSANDR_TEST_OBJECTS)
- msan_compile(MSANDR_TEST_OBJECTS ${MSANDR_UNITTEST_SOURCE} ${arch}
- ${MSAN_UNITTEST_COMMON_CFLAGS})
+ msan_compile(MSAN_INST_LOADABLE_OBJECTS ${MSAN_LOADABLE_SOURCE} ${arch} "${kind}"
+ ${MSAN_UNITTEST_INSTRUMENTED_CFLAGS} ${ARGN})
# Instrumented loadable library tests.
set(MSAN_LOADABLE_SO)
- msan_link_shared(MSAN_LOADABLE_SO "libmsan_loadable" ${arch}
+ msan_link_shared(MSAN_LOADABLE_SO "libmsan_loadable" ${arch} "${kind}"
OBJECTS ${MSAN_INST_LOADABLE_OBJECTS}
- DEPS ${MSAN_INST_LOADABLE_OBJECTS} ${MSAN_RUNTIME_LIBRARIES})
-
- # Uninstrumented shared library tests.
- set(MSANDR_TEST_SO)
- msan_link_shared(MSANDR_TEST_SO "libmsandr_test" ${arch}
- OBJECTS ${MSANDR_TEST_OBJECTS}
- DEPS ${MSANDR_TEST_OBJECTS} ${MSAN_RUNTIME_LIBRARIES})
+ DEPS ${MSAN_INST_LOADABLE_OBJECTS})
- # Link everything together.
- add_msan_test(MsanUnitTests "Msan-${arch}-Test" ${arch}
- ${MSAN_INST_TEST_OBJECTS} ${MSAN_INST_GTEST}
- ${MSAN_INST_LIBCXX} ${MSANDR_TEST_SO})
+ set(MSAN_TEST_OBJECTS ${MSAN_INST_TEST_OBJECTS} ${MSAN_INST_GTEST})
+ set(MSAN_TEST_DEPS ${MSAN_TEST_OBJECTS} libcxx_msan${kind}
+ ${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")
endmacro()
-if(COMPILER_RT_CAN_EXECUTE_TESTS AND MSAN_CAN_INSTRUMENT_LIBCXX)
+# 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)
if(CAN_TARGET_x86_64)
- add_msan_tests_for_arch(x86_64)
+ add_msan_tests_for_arch(x86_64 "")
+ add_msan_tests_for_arch(x86_64 "-with-call"
+ -mllvm -msan-instrumentation-with-call-threshold=0)
endif()
endif()
diff --git a/lib/msan/tests/msan_loadable.cc b/lib/msan/tests/msan_loadable.cc
index db3bf489853d..06e880f90dee 100644
--- a/lib/msan/tests/msan_loadable.cc
+++ b/lib/msan/tests/msan_loadable.cc
@@ -20,24 +20,6 @@ static void *dso_global;
// No name mangling.
extern "C" {
-__attribute__((constructor))
-void loadable_module_init(void) {
- if (!__msan_has_dynamic_component())
- return;
- // The real test is that this compare should not make an uninit.
- if (dso_global == NULL)
- dso_global = malloc(4);
-}
-
-__attribute__((destructor))
-void loadable_module_fini(void) {
- if (!__msan_has_dynamic_component())
- return;
- free(dso_global);
- // *Don't* overwrite it with NULL! That would unpoison it, but our test
- // relies on reloading at the same address and keeping the poison.
-}
-
void **get_dso_global() {
return &dso_global;
}
diff --git a/lib/msan/tests/msan_test.cc b/lib/msan/tests/msan_test.cc
index f95bb4e7c618..554265da6aa9 100644
--- a/lib/msan/tests/msan_test.cc
+++ b/lib/msan/tests/msan_test.cc
@@ -16,14 +16,15 @@
#include "msan_test_config.h"
#endif // MSAN_EXTERNAL_TEST_CONFIG
+#include "sanitizer_common/tests/sanitizer_test_utils.h"
+
+#include "sanitizer/allocator_interface.h"
#include "sanitizer/msan_interface.h"
-#include "msandr_test_so.h"
#include <inttypes.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
-#include <assert.h>
#include <wchar.h>
#include <math.h>
#include <malloc.h>
@@ -63,7 +64,11 @@
# define MSAN_HAS_M128 0
#endif
-static const int kPageSize = 4096;
+#ifdef __AVX2__
+# include <immintrin.h>
+#endif
+
+static const size_t kPageSize = 4096;
typedef unsigned char U1;
typedef unsigned short U2; // NOLINT
@@ -100,20 +105,6 @@ static bool TrackingOrigins() {
EXPECT_EQ(origin, __msan_get_umr_origin()); \
} while (0)
-#define EXPECT_UMR_S(action, stack_origin) \
- do { \
- __msan_set_expect_umr(1); \
- action; \
- __msan_set_expect_umr(0); \
- U4 id = __msan_get_umr_origin(); \
- const char *str = __msan_get_origin_descr_if_stack(id); \
- if (!str || strcmp(str, stack_origin)) { \
- fprintf(stderr, "EXPECT_POISONED_S: id=%u %s, %s", \
- id, stack_origin, str); \
- EXPECT_EQ(1, 0); \
- } \
- } while (0)
-
#define EXPECT_POISONED(x) ExpectPoisoned(x)
template<typename T>
@@ -131,21 +122,6 @@ void ExpectPoisonedWithOrigin(const T& t, unsigned origin) {
EXPECT_EQ(origin, __msan_get_origin((void*)&t));
}
-#define EXPECT_POISONED_S(x, stack_origin) \
- ExpectPoisonedWithStackOrigin(x, stack_origin)
-
-template<typename T>
-void ExpectPoisonedWithStackOrigin(const T& t, const char *stack_origin) {
- EXPECT_NE(-1, __msan_test_shadow((void*)&t, sizeof(t)));
- U4 id = __msan_get_origin((void*)&t);
- const char *str = __msan_get_origin_descr_if_stack(id);
- if (!str || strcmp(str, stack_origin)) {
- fprintf(stderr, "EXPECT_POISONED_S: id=%u %s, %s",
- id, stack_origin, str);
- EXPECT_EQ(1, 0);
- }
-}
-
#define EXPECT_NOT_POISONED(x) ExpectNotPoisoned(x)
template<typename T>
@@ -171,13 +147,10 @@ T *GetPoisonedO(int i, U4 origin, T val = 0) {
return res;
}
-// This function returns its parameter but in such a way that compiler
-// can not prove it.
-template<class T>
-NOINLINE
-static T Ident(T t) {
- volatile T ret = t;
- return ret;
+template<typename T>
+T Poisoned(T v = 0, T s = (T)(-1)) {
+ __msan_partial_poison(&v, &s, sizeof(T));
+ return v;
}
template<class T> NOINLINE T ReturnPoisoned() { return *GetPoisoned<T>(); }
@@ -277,7 +250,6 @@ TEST(MemorySanitizer, ArgTest) {
TEST(MemorySanitizer, CallAndRet) {
- if (!__msan_has_dynamic_component()) return;
ReturnPoisoned<S1>();
ReturnPoisoned<S2>();
ReturnPoisoned<S4>();
@@ -327,10 +299,27 @@ TEST(MemorySanitizer, Realloc) {
TEST(MemorySanitizer, Calloc) {
S4 *x = (int*)Ident(calloc(1, sizeof(S4)));
EXPECT_NOT_POISONED(*x); // Should not be poisoned.
- // EXPECT_EQ(0, *x);
+ EXPECT_EQ(0, *x);
free(x);
}
+TEST(MemorySanitizer, CallocReturnsZeroMem) {
+ size_t sizes[] = {16, 1000, 10000, 100000, 2100000};
+ for (size_t s = 0; s < sizeof(sizes)/sizeof(sizes[0]); s++) {
+ size_t size = sizes[s];
+ for (size_t iter = 0; iter < 5; iter++) {
+ char *x = Ident((char*)calloc(1, size));
+ EXPECT_EQ(x[0], 0);
+ EXPECT_EQ(x[size - 1], 0);
+ EXPECT_EQ(x[size / 2], 0);
+ EXPECT_EQ(x[size / 3], 0);
+ EXPECT_EQ(x[size / 4], 0);
+ memset(x, 0x42, size);
+ free(Ident(x));
+ }
+ }
+}
+
TEST(MemorySanitizer, AndOr) {
U4 *p = GetPoisoned<U4>();
// We poison two bytes in the midle of a 4-byte word to make the test
@@ -503,14 +492,12 @@ TEST(MemorySanitizer, DynMem) {
static char *DynRetTestStr;
TEST(MemorySanitizer, DynRet) {
- if (!__msan_has_dynamic_component()) return;
ReturnPoisoned<S8>();
EXPECT_NOT_POISONED(clearenv());
}
TEST(MemorySanitizer, DynRet1) {
- if (!__msan_has_dynamic_component()) return;
ReturnPoisoned<S8>();
}
@@ -573,39 +560,39 @@ TEST(MemorySanitizer, strerror_r) {
TEST(MemorySanitizer, fread) {
char *x = new char[32];
FILE *f = fopen("/proc/self/stat", "r");
- assert(f);
+ ASSERT_TRUE(f != NULL);
fread(x, 1, 32, f);
EXPECT_NOT_POISONED(x[0]);
EXPECT_NOT_POISONED(x[16]);
EXPECT_NOT_POISONED(x[31]);
fclose(f);
- delete x;
+ delete[] x;
}
TEST(MemorySanitizer, read) {
char *x = new char[32];
int fd = open("/proc/self/stat", O_RDONLY);
- assert(fd > 0);
+ ASSERT_GT(fd, 0);
int sz = read(fd, x, 32);
- assert(sz == 32);
+ ASSERT_EQ(sz, 32);
EXPECT_NOT_POISONED(x[0]);
EXPECT_NOT_POISONED(x[16]);
EXPECT_NOT_POISONED(x[31]);
close(fd);
- delete x;
+ delete[] x;
}
TEST(MemorySanitizer, pread) {
char *x = new char[32];
int fd = open("/proc/self/stat", O_RDONLY);
- assert(fd > 0);
+ ASSERT_GT(fd, 0);
int sz = pread(fd, x, 32, 0);
- assert(sz == 32);
+ ASSERT_EQ(sz, 32);
EXPECT_NOT_POISONED(x[0]);
EXPECT_NOT_POISONED(x[16]);
EXPECT_NOT_POISONED(x[31]);
close(fd);
- delete x;
+ delete[] x;
}
TEST(MemorySanitizer, readv) {
@@ -616,10 +603,11 @@ TEST(MemorySanitizer, readv) {
iov[1].iov_base = buf + 10;
iov[1].iov_len = 2000;
int fd = open("/proc/self/stat", O_RDONLY);
- assert(fd > 0);
+ ASSERT_GT(fd, 0);
int sz = readv(fd, iov, 2);
+ ASSERT_GE(sz, 0);
ASSERT_LT(sz, 5 + 2000);
- ASSERT_GT(sz, iov[0].iov_len);
+ ASSERT_GT((size_t)sz, iov[0].iov_len);
EXPECT_POISONED(buf[0]);
EXPECT_NOT_POISONED(buf[1]);
EXPECT_NOT_POISONED(buf[5]);
@@ -639,10 +627,11 @@ TEST(MemorySanitizer, preadv) {
iov[1].iov_base = buf + 10;
iov[1].iov_len = 2000;
int fd = open("/proc/self/stat", O_RDONLY);
- assert(fd > 0);
+ ASSERT_GT(fd, 0);
int sz = preadv(fd, iov, 2, 3);
+ ASSERT_GE(sz, 0);
ASSERT_LT(sz, 5 + 2000);
- ASSERT_GT(sz, iov[0].iov_len);
+ ASSERT_GT((size_t)sz, iov[0].iov_len);
EXPECT_POISONED(buf[0]);
EXPECT_NOT_POISONED(buf[1]);
EXPECT_NOT_POISONED(buf[5]);
@@ -672,7 +661,7 @@ TEST(MemorySanitizer, readlink) {
TEST(MemorySanitizer, stat) {
struct stat* st = new struct stat;
int res = stat("/proc/self/stat", st);
- assert(!res);
+ ASSERT_EQ(0, res);
EXPECT_NOT_POISONED(st->st_dev);
EXPECT_NOT_POISONED(st->st_mode);
EXPECT_NOT_POISONED(st->st_size);
@@ -681,9 +670,9 @@ TEST(MemorySanitizer, stat) {
TEST(MemorySanitizer, fstatat) {
struct stat* st = new struct stat;
int dirfd = open("/proc/self", O_RDONLY);
- assert(dirfd > 0);
+ ASSERT_GT(dirfd, 0);
int res = fstatat(dirfd, "stat", st, 0);
- assert(!res);
+ ASSERT_EQ(0, res);
EXPECT_NOT_POISONED(st->st_dev);
EXPECT_NOT_POISONED(st->st_mode);
EXPECT_NOT_POISONED(st->st_size);
@@ -693,7 +682,7 @@ TEST(MemorySanitizer, fstatat) {
TEST(MemorySanitizer, statfs) {
struct statfs st;
int res = statfs("/", &st);
- assert(!res);
+ ASSERT_EQ(0, res);
EXPECT_NOT_POISONED(st.f_type);
EXPECT_NOT_POISONED(st.f_bfree);
EXPECT_NOT_POISONED(st.f_namelen);
@@ -702,7 +691,7 @@ TEST(MemorySanitizer, statfs) {
TEST(MemorySanitizer, statvfs) {
struct statvfs st;
int res = statvfs("/", &st);
- assert(!res);
+ ASSERT_EQ(0, res);
EXPECT_NOT_POISONED(st.f_bsize);
EXPECT_NOT_POISONED(st.f_blocks);
EXPECT_NOT_POISONED(st.f_bfree);
@@ -713,7 +702,7 @@ TEST(MemorySanitizer, fstatvfs) {
struct statvfs st;
int fd = open("/", O_RDONLY | O_DIRECTORY);
int res = fstatvfs(fd, &st);
- assert(!res);
+ ASSERT_EQ(0, res);
EXPECT_NOT_POISONED(st.f_bsize);
EXPECT_NOT_POISONED(st.f_blocks);
EXPECT_NOT_POISONED(st.f_bfree);
@@ -724,7 +713,7 @@ TEST(MemorySanitizer, fstatvfs) {
TEST(MemorySanitizer, pipe) {
int* pipefd = new int[2];
int res = pipe(pipefd);
- assert(!res);
+ ASSERT_EQ(0, res);
EXPECT_NOT_POISONED(pipefd[0]);
EXPECT_NOT_POISONED(pipefd[1]);
close(pipefd[0]);
@@ -734,7 +723,7 @@ TEST(MemorySanitizer, pipe) {
TEST(MemorySanitizer, pipe2) {
int* pipefd = new int[2];
int res = pipe2(pipefd, O_NONBLOCK);
- assert(!res);
+ ASSERT_EQ(0, res);
EXPECT_NOT_POISONED(pipefd[0]);
EXPECT_NOT_POISONED(pipefd[1]);
close(pipefd[0]);
@@ -744,7 +733,7 @@ TEST(MemorySanitizer, pipe2) {
TEST(MemorySanitizer, socketpair) {
int sv[2];
int res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv);
- assert(!res);
+ ASSERT_EQ(0, res);
EXPECT_NOT_POISONED(sv[0]);
EXPECT_NOT_POISONED(sv[1]);
close(sv[0]);
@@ -823,7 +812,7 @@ TEST(MemorySanitizer, bind_getsockname) {
sai.sin_family = AF_UNIX;
int res = bind(sock, (struct sockaddr *)&sai, sizeof(sai));
- assert(!res);
+ ASSERT_EQ(0, res);
char buf[200];
socklen_t addrlen;
EXPECT_UMR(getsockname(sock, (struct sockaddr *)&buf, &addrlen));
@@ -908,10 +897,10 @@ TEST(MemorySanitizer, getnameinfo) {
EXPECT_NOT_POISONED(host[0]);
EXPECT_POISONED(host[sizeof(host) - 1]);
- ASSERT_NE(0, strlen(host));
+ ASSERT_NE(0U, strlen(host));
EXPECT_NOT_POISONED(serv[0]);
EXPECT_POISONED(serv[sizeof(serv) - 1]);
- ASSERT_NE(0, strlen(serv));
+ ASSERT_NE(0U, strlen(serv));
}
#define EXPECT_HOSTENT_NOT_POISONED(he) \
@@ -1061,6 +1050,26 @@ TEST(MemorySanitizer, gethostbyname_r) {
EXPECT_NOT_POISONED(err);
}
+TEST(MemorySanitizer, gethostbyname_r_bad_host_name) {
+ char buf[2000];
+ struct hostent he;
+ struct hostent *result;
+ int err;
+ int res = gethostbyname_r("bad-host-name", &he, buf, sizeof(buf), &result, &err);
+ ASSERT_EQ((struct hostent *)0, result);
+ EXPECT_NOT_POISONED(err);
+}
+
+TEST(MemorySanitizer, gethostbyname_r_erange) {
+ char buf[5];
+ struct hostent he;
+ struct hostent *result;
+ int err;
+ int res = gethostbyname_r("localhost", &he, buf, sizeof(buf), &result, &err);
+ ASSERT_EQ(ERANGE, res);
+ EXPECT_NOT_POISONED(err);
+}
+
TEST(MemorySanitizer, gethostbyname2_r) {
char buf[2000];
struct hostent he;
@@ -1105,20 +1114,20 @@ TEST(MemorySanitizer, getsockopt) {
TEST(MemorySanitizer, getcwd) {
char path[PATH_MAX + 1];
char* res = getcwd(path, sizeof(path));
- assert(res);
+ ASSERT_TRUE(res != NULL);
EXPECT_NOT_POISONED(path[0]);
}
TEST(MemorySanitizer, getcwd_gnu) {
char* res = getcwd(NULL, 0);
- assert(res);
+ ASSERT_TRUE(res != NULL);
EXPECT_NOT_POISONED(res[0]);
free(res);
}
TEST(MemorySanitizer, get_current_dir_name) {
char* res = get_current_dir_name();
- assert(res);
+ ASSERT_TRUE(res != NULL);
EXPECT_NOT_POISONED(res[0]);
free(res);
}
@@ -1209,7 +1218,7 @@ TEST(MemorySanitizer, confstr) {
TEST(MemorySanitizer, readdir) {
DIR *dir = opendir(".");
struct dirent *d = readdir(dir);
- assert(d);
+ ASSERT_TRUE(d != NULL);
EXPECT_NOT_POISONED(d->d_name[0]);
closedir(dir);
}
@@ -1219,7 +1228,7 @@ TEST(MemorySanitizer, readdir_r) {
struct dirent d;
struct dirent *pd;
int res = readdir_r(dir, &d, &pd);
- assert(!res);
+ ASSERT_EQ(0, res);
EXPECT_NOT_POISONED(pd);
EXPECT_NOT_POISONED(d.d_name[0]);
closedir(dir);
@@ -1229,7 +1238,7 @@ TEST(MemorySanitizer, realpath) {
const char* relpath = ".";
char path[PATH_MAX + 1];
char* res = realpath(relpath, path);
- assert(res);
+ ASSERT_TRUE(res != NULL);
EXPECT_NOT_POISONED(path[0]);
}
@@ -1237,7 +1246,7 @@ TEST(MemorySanitizer, realpath_null) {
const char* relpath = ".";
char* res = realpath(relpath, NULL);
printf("%d, %s\n", errno, strerror(errno));
- assert(res);
+ ASSERT_TRUE(res != NULL);
EXPECT_NOT_POISONED(res[0]);
free(res);
}
@@ -1245,7 +1254,7 @@ TEST(MemorySanitizer, realpath_null) {
TEST(MemorySanitizer, canonicalize_file_name) {
const char* relpath = ".";
char* res = canonicalize_file_name(relpath);
- assert(res);
+ ASSERT_TRUE(res != NULL);
EXPECT_NOT_POISONED(res[0]);
free(res);
}
@@ -1279,33 +1288,56 @@ TEST(MemorySanitizer, memcpy) {
EXPECT_POISONED(y[1]);
}
-void TestUnalignedMemcpy(int left, int right, bool src_is_aligned) {
- const int sz = 20;
+void TestUnalignedMemcpy(unsigned left, unsigned right, bool src_is_aligned,
+ bool src_is_poisoned, bool dst_is_poisoned) {
+ fprintf(stderr, "%s(%d, %d, %d, %d, %d)\n", __func__, left, right,
+ src_is_aligned, src_is_poisoned, dst_is_poisoned);
+
+ const unsigned sz = 20;
+ U4 dst_origin, src_origin;
char *dst = (char *)malloc(sz);
- U4 origin = __msan_get_origin(dst);
+ if (dst_is_poisoned)
+ dst_origin = __msan_get_origin(dst);
+ else
+ memset(dst, 0, sz);
char *src = (char *)malloc(sz);
- memset(src, 0, sz);
+ if (src_is_poisoned)
+ src_origin = __msan_get_origin(src);
+ else
+ memset(src, 0, sz);
memcpy(dst + left, src_is_aligned ? src + left : src, sz - left - right);
- for (int i = 0; i < left; ++i)
- EXPECT_POISONED_O(dst[i], origin);
- for (int i = 0; i < right; ++i)
- EXPECT_POISONED_O(dst[sz - i - 1], origin);
- EXPECT_NOT_POISONED(dst[left]);
- EXPECT_NOT_POISONED(dst[sz - right - 1]);
+
+ for (unsigned i = 0; i < (left & (~3U)); ++i)
+ if (dst_is_poisoned)
+ EXPECT_POISONED_O(dst[i], dst_origin);
+ else
+ EXPECT_NOT_POISONED(dst[i]);
+
+ for (unsigned i = 0; i < (right & (~3U)); ++i)
+ if (dst_is_poisoned)
+ EXPECT_POISONED_O(dst[sz - i - 1], dst_origin);
+ else
+ EXPECT_NOT_POISONED(dst[sz - i - 1]);
+
+ for (unsigned i = left; i < sz - right; ++i)
+ if (src_is_poisoned)
+ EXPECT_POISONED_O(dst[i], src_origin);
+ else
+ EXPECT_NOT_POISONED(dst[i]);
free(dst);
free(src);
}
TEST(MemorySanitizer, memcpy_unaligned) {
- for (int i = 0; i < 10; ++i) {
- for (int j = 0; j < 10; ++j) {
- TestUnalignedMemcpy(i, j, true);
- TestUnalignedMemcpy(i, j, false);
- }
- }
+ for (int i = 0; i < 10; ++i)
+ for (int j = 0; j < 10; ++j)
+ for (int aligned = 0; aligned < 2; ++aligned)
+ for (int srcp = 0; srcp < 2; ++srcp)
+ for (int dstp = 0; dstp < 2; ++dstp)
+ TestUnalignedMemcpy(i, j, aligned, srcp, dstp);
}
TEST(MemorySanitizer, memmove) {
@@ -1412,17 +1444,12 @@ TEST(MemorySanitizer, strndup_short) {
template<class T, int size>
void TestOverlapMemmove() {
T *x = new T[size];
- assert(size >= 3);
+ ASSERT_GE(size, 3);
x[2] = 0;
memmove(x, x + 1, (size - 1) * sizeof(T));
EXPECT_NOT_POISONED(x[1]);
- if (!__msan_has_dynamic_component()) {
- // FIXME: under DR we will lose this information
- // because accesses in memmove will unpoisin the shadow.
- // We need to use our own memove implementation instead of libc's.
- EXPECT_POISONED(x[0]);
- EXPECT_POISONED(x[2]);
- }
+ EXPECT_POISONED(x[0]);
+ EXPECT_POISONED(x[2]);
delete [] x;
}
@@ -1447,14 +1474,16 @@ TEST(MemorySanitizer, strcpy) { // NOLINT
TEST(MemorySanitizer, strncpy) { // NOLINT
char* x = new char[3];
- char* y = new char[3];
+ char* y = new char[5];
x[0] = 'a';
x[1] = *GetPoisoned<char>(1, 1);
- x[2] = 0;
- strncpy(y, x, 2); // NOLINT
+ x[2] = '\0';
+ strncpy(y, x, 4); // NOLINT
EXPECT_NOT_POISONED(y[0]);
EXPECT_POISONED(y[1]);
- EXPECT_POISONED(y[2]);
+ EXPECT_NOT_POISONED(y[2]);
+ EXPECT_NOT_POISONED(y[3]);
+ EXPECT_POISONED(y[4]);
}
TEST(MemorySanitizer, stpcpy) { // NOLINT
@@ -1470,71 +1499,144 @@ TEST(MemorySanitizer, stpcpy) { // NOLINT
EXPECT_NOT_POISONED(y[2]);
}
-TEST(MemorySanitizer, strtol) {
- char *e;
- assert(1 == strtol("1", &e, 10));
- EXPECT_NOT_POISONED((S8) e);
-}
+TEST(MemorySanitizer, strcat) { // NOLINT
+ char a[10];
+ char b[] = "def";
+ strcpy(a, "abc");
+ __msan_poison(b + 1, 1);
+ strcat(a, b);
+ EXPECT_NOT_POISONED(a[3]);
+ EXPECT_POISONED(a[4]);
+ EXPECT_NOT_POISONED(a[5]);
+ EXPECT_NOT_POISONED(a[6]);
+ EXPECT_POISONED(a[7]);
+}
+
+TEST(MemorySanitizer, strncat) { // NOLINT
+ char a[10];
+ char b[] = "def";
+ strcpy(a, "abc");
+ __msan_poison(b + 1, 1);
+ strncat(a, b, 5);
+ EXPECT_NOT_POISONED(a[3]);
+ EXPECT_POISONED(a[4]);
+ EXPECT_NOT_POISONED(a[5]);
+ EXPECT_NOT_POISONED(a[6]);
+ EXPECT_POISONED(a[7]);
+}
+
+TEST(MemorySanitizer, strncat_overflow) { // NOLINT
+ char a[10];
+ char b[] = "def";
+ strcpy(a, "abc");
+ __msan_poison(b + 1, 1);
+ strncat(a, b, 2);
+ EXPECT_NOT_POISONED(a[3]);
+ EXPECT_POISONED(a[4]);
+ EXPECT_NOT_POISONED(a[5]);
+ EXPECT_POISONED(a[6]);
+ EXPECT_POISONED(a[7]);
+}
+
+#define TEST_STRTO_INT(func_name, char_type, str_prefix) \
+ TEST(MemorySanitizer, func_name) { \
+ char_type *e; \
+ EXPECT_EQ(1U, func_name(str_prefix##"1", &e, 10)); \
+ EXPECT_NOT_POISONED((S8)e); \
+ }
-TEST(MemorySanitizer, strtoll) {
- char *e;
- assert(1 == strtoll("1", &e, 10));
- EXPECT_NOT_POISONED((S8) e);
-}
+#define TEST_STRTO_FLOAT(func_name, char_type, str_prefix) \
+ TEST(MemorySanitizer, func_name) { \
+ char_type *e; \
+ EXPECT_NE(0, func_name(str_prefix##"1.5", &e)); \
+ EXPECT_NOT_POISONED((S8)e); \
+ }
-TEST(MemorySanitizer, strtoul) {
- char *e;
- assert(1 == strtoul("1", &e, 10));
- EXPECT_NOT_POISONED((S8) e);
-}
+#define TEST_STRTO_FLOAT_LOC(func_name, char_type, str_prefix) \
+ TEST(MemorySanitizer, func_name) { \
+ locale_t loc = newlocale(LC_NUMERIC_MASK, "C", (locale_t)0); \
+ char_type *e; \
+ EXPECT_NE(0, func_name(str_prefix##"1.5", &e, loc)); \
+ EXPECT_NOT_POISONED((S8)e); \
+ freelocale(loc); \
+ }
+
+#define TEST_STRTO_INT_LOC(func_name, char_type, str_prefix) \
+ TEST(MemorySanitizer, func_name) { \
+ locale_t loc = newlocale(LC_NUMERIC_MASK, "C", (locale_t)0); \
+ char_type *e; \
+ ASSERT_EQ(1U, func_name(str_prefix##"1", &e, 10, loc)); \
+ EXPECT_NOT_POISONED((S8)e); \
+ freelocale(loc); \
+ }
+
+TEST_STRTO_INT(strtol, char, )
+TEST_STRTO_INT(strtoll, char, )
+TEST_STRTO_INT(strtoul, char, )
+TEST_STRTO_INT(strtoull, char, )
+
+TEST_STRTO_FLOAT(strtof, char, )
+TEST_STRTO_FLOAT(strtod, char, )
+TEST_STRTO_FLOAT(strtold, char, )
+
+TEST_STRTO_FLOAT_LOC(strtof_l, char, )
+TEST_STRTO_FLOAT_LOC(strtod_l, char, )
+TEST_STRTO_FLOAT_LOC(strtold_l, char, )
+
+TEST_STRTO_INT_LOC(strtol_l, char, )
+TEST_STRTO_INT_LOC(strtoll_l, char, )
+TEST_STRTO_INT_LOC(strtoul_l, char, )
+TEST_STRTO_INT_LOC(strtoull_l, char, )
+
+TEST_STRTO_INT(wcstol, wchar_t, L)
+TEST_STRTO_INT(wcstoll, wchar_t, L)
+TEST_STRTO_INT(wcstoul, wchar_t, L)
+TEST_STRTO_INT(wcstoull, wchar_t, L)
+
+TEST_STRTO_FLOAT(wcstof, wchar_t, L)
+TEST_STRTO_FLOAT(wcstod, wchar_t, L)
+TEST_STRTO_FLOAT(wcstold, wchar_t, L)
+
+TEST_STRTO_FLOAT_LOC(wcstof_l, wchar_t, L)
+TEST_STRTO_FLOAT_LOC(wcstod_l, wchar_t, L)
+TEST_STRTO_FLOAT_LOC(wcstold_l, wchar_t, L)
+
+TEST_STRTO_INT_LOC(wcstol_l, wchar_t, L)
+TEST_STRTO_INT_LOC(wcstoll_l, wchar_t, L)
+TEST_STRTO_INT_LOC(wcstoul_l, wchar_t, L)
+TEST_STRTO_INT_LOC(wcstoull_l, wchar_t, L)
-TEST(MemorySanitizer, strtoull) {
- char *e;
- assert(1 == strtoull("1", &e, 10));
- EXPECT_NOT_POISONED((S8) e);
-}
TEST(MemorySanitizer, strtoimax) {
char *e;
- assert(1 == strtoimax("1", &e, 10));
+ ASSERT_EQ(1, strtoimax("1", &e, 10));
EXPECT_NOT_POISONED((S8) e);
}
TEST(MemorySanitizer, strtoumax) {
char *e;
- assert(1 == strtoumax("1", &e, 10));
- EXPECT_NOT_POISONED((S8) e);
-}
-
-TEST(MemorySanitizer, strtod) {
- char *e;
- assert(0 != strtod("1.5", &e));
+ ASSERT_EQ(1U, strtoumax("1", &e, 10));
EXPECT_NOT_POISONED((S8) e);
}
#ifdef __GLIBC__
+extern "C" float __strtof_l(const char *nptr, char **endptr, locale_t loc);
+TEST_STRTO_FLOAT_LOC(__strtof_l, char, )
extern "C" double __strtod_l(const char *nptr, char **endptr, locale_t loc);
-TEST(MemorySanitizer, __strtod_l) {
- locale_t loc = newlocale(LC_NUMERIC_MASK, "C", (locale_t)0);
- char *e;
- assert(0 != __strtod_l("1.5", &e, loc));
- EXPECT_NOT_POISONED((S8) e);
- freelocale(loc);
-}
+TEST_STRTO_FLOAT_LOC(__strtod_l, char, )
+extern "C" long double __strtold_l(const char *nptr, char **endptr,
+ locale_t loc);
+TEST_STRTO_FLOAT_LOC(__strtold_l, char, )
+
+extern "C" float __wcstof_l(const wchar_t *nptr, wchar_t **endptr, locale_t loc);
+TEST_STRTO_FLOAT_LOC(__wcstof_l, wchar_t, L)
+extern "C" double __wcstod_l(const wchar_t *nptr, wchar_t **endptr, locale_t loc);
+TEST_STRTO_FLOAT_LOC(__wcstod_l, wchar_t, L)
+extern "C" long double __wcstold_l(const wchar_t *nptr, wchar_t **endptr,
+ locale_t loc);
+TEST_STRTO_FLOAT_LOC(__wcstold_l, wchar_t, L)
#endif // __GLIBC__
-TEST(MemorySanitizer, strtof) {
- char *e;
- assert(0 != strtof("1.5", &e));
- EXPECT_NOT_POISONED((S8) e);
-}
-
-TEST(MemorySanitizer, strtold) {
- char *e;
- assert(0 != strtold("1.5", &e));
- EXPECT_NOT_POISONED((S8) e);
-}
-
TEST(MemorySanitizer, modf) {
double x, y;
x = modf(2.1, &y);
@@ -1655,12 +1757,12 @@ TEST(MemorySanitizer, sprintf) { // NOLINT
break_optimization(buff);
EXPECT_POISONED(buff[0]);
int res = sprintf(buff, "%d", 1234567); // NOLINT
- assert(res == 7);
- assert(buff[0] == '1');
- assert(buff[1] == '2');
- assert(buff[2] == '3');
- assert(buff[6] == '7');
- assert(buff[7] == 0);
+ ASSERT_EQ(res, 7);
+ ASSERT_EQ(buff[0], '1');
+ ASSERT_EQ(buff[1], '2');
+ ASSERT_EQ(buff[2], '3');
+ ASSERT_EQ(buff[6], '7');
+ ASSERT_EQ(buff[7], 0);
EXPECT_POISONED(buff[8]);
}
@@ -1669,27 +1771,27 @@ TEST(MemorySanitizer, snprintf) {
break_optimization(buff);
EXPECT_POISONED(buff[0]);
int res = snprintf(buff, sizeof(buff), "%d", 1234567);
- assert(res == 7);
- assert(buff[0] == '1');
- assert(buff[1] == '2');
- assert(buff[2] == '3');
- assert(buff[6] == '7');
- assert(buff[7] == 0);
+ ASSERT_EQ(res, 7);
+ ASSERT_EQ(buff[0], '1');
+ ASSERT_EQ(buff[1], '2');
+ ASSERT_EQ(buff[2], '3');
+ ASSERT_EQ(buff[6], '7');
+ ASSERT_EQ(buff[7], 0);
EXPECT_POISONED(buff[8]);
}
TEST(MemorySanitizer, swprintf) {
wchar_t buff[10];
- assert(sizeof(wchar_t) == 4);
+ ASSERT_EQ(4U, sizeof(wchar_t));
break_optimization(buff);
EXPECT_POISONED(buff[0]);
int res = swprintf(buff, 9, L"%d", 1234567);
- assert(res == 7);
- assert(buff[0] == '1');
- assert(buff[1] == '2');
- assert(buff[2] == '3');
- assert(buff[6] == '7');
- assert(buff[7] == 0);
+ ASSERT_EQ(res, 7);
+ ASSERT_EQ(buff[0], '1');
+ ASSERT_EQ(buff[1], '2');
+ ASSERT_EQ(buff[2], '3');
+ ASSERT_EQ(buff[6], '7');
+ ASSERT_EQ(buff[7], 0);
EXPECT_POISONED(buff[8]);
}
@@ -1697,13 +1799,13 @@ TEST(MemorySanitizer, asprintf) { // NOLINT
char *pbuf;
EXPECT_POISONED(pbuf);
int res = asprintf(&pbuf, "%d", 1234567); // NOLINT
- assert(res == 7);
+ ASSERT_EQ(res, 7);
EXPECT_NOT_POISONED(pbuf);
- assert(pbuf[0] == '1');
- assert(pbuf[1] == '2');
- assert(pbuf[2] == '3');
- assert(pbuf[6] == '7');
- assert(pbuf[7] == 0);
+ ASSERT_EQ(pbuf[0], '1');
+ ASSERT_EQ(pbuf[1], '2');
+ ASSERT_EQ(pbuf[2], '3');
+ ASSERT_EQ(pbuf[6], '7');
+ ASSERT_EQ(pbuf[7], 0);
free(pbuf);
}
@@ -1758,6 +1860,16 @@ TEST(MemorySanitizer, wcsnrtombs) {
EXPECT_POISONED(buff[2]);
}
+TEST(MemorySanitizer, wmemset) {
+ wchar_t x[25];
+ break_optimization(x);
+ EXPECT_POISONED(x[0]);
+ wmemset(x, L'A', 10);
+ EXPECT_EQ(x[0], L'A');
+ EXPECT_EQ(x[9], L'A');
+ EXPECT_POISONED(x[10]);
+}
+
TEST(MemorySanitizer, mbtowc) {
const char *x = "abc";
wchar_t wx;
@@ -1776,18 +1888,29 @@ TEST(MemorySanitizer, mbrtowc) {
EXPECT_NOT_POISONED(wx);
}
+TEST(MemorySanitizer, wcsftime) {
+ wchar_t x[100];
+ time_t t = time(NULL);
+ struct tm tms;
+ struct tm *tmres = localtime_r(&t, &tms);
+ ASSERT_NE((void *)0, tmres);
+ size_t res = wcsftime(x, sizeof(x) / sizeof(x[0]), L"%Y-%m-%d", tmres);
+ EXPECT_GT(res, 0UL);
+ EXPECT_EQ(res, wcslen(x));
+}
+
TEST(MemorySanitizer, gettimeofday) {
struct timeval tv;
struct timezone tz;
break_optimization(&tv);
break_optimization(&tz);
- assert(sizeof(tv) == 16);
- assert(sizeof(tz) == 8);
+ ASSERT_EQ(16U, sizeof(tv));
+ ASSERT_EQ(8U, sizeof(tz));
EXPECT_POISONED(tv.tv_sec);
EXPECT_POISONED(tv.tv_usec);
EXPECT_POISONED(tz.tz_minuteswest);
EXPECT_POISONED(tz.tz_dsttime);
- assert(0 == gettimeofday(&tv, &tz));
+ ASSERT_EQ(0, gettimeofday(&tv, &tz));
EXPECT_NOT_POISONED(tv.tv_sec);
EXPECT_NOT_POISONED(tv.tv_usec);
EXPECT_NOT_POISONED(tz.tz_minuteswest);
@@ -1798,7 +1921,7 @@ TEST(MemorySanitizer, clock_gettime) {
struct timespec tp;
EXPECT_POISONED(tp.tv_sec);
EXPECT_POISONED(tp.tv_nsec);
- assert(0 == clock_gettime(CLOCK_REALTIME, &tp));
+ ASSERT_EQ(0, clock_gettime(CLOCK_REALTIME, &tp));
EXPECT_NOT_POISONED(tp.tv_sec);
EXPECT_NOT_POISONED(tp.tv_nsec);
}
@@ -1807,10 +1930,10 @@ TEST(MemorySanitizer, clock_getres) {
struct timespec tp;
EXPECT_POISONED(tp.tv_sec);
EXPECT_POISONED(tp.tv_nsec);
- assert(0 == clock_getres(CLOCK_REALTIME, 0));
+ ASSERT_EQ(0, clock_getres(CLOCK_REALTIME, 0));
EXPECT_POISONED(tp.tv_sec);
EXPECT_POISONED(tp.tv_nsec);
- assert(0 == clock_getres(CLOCK_REALTIME, &tp));
+ ASSERT_EQ(0, clock_getres(CLOCK_REALTIME, &tp));
EXPECT_NOT_POISONED(tp.tv_sec);
EXPECT_NOT_POISONED(tp.tv_nsec);
}
@@ -1823,7 +1946,7 @@ TEST(MemorySanitizer, getitimer) {
EXPECT_POISONED(it1.it_value.tv_sec);
EXPECT_POISONED(it1.it_value.tv_usec);
res = getitimer(ITIMER_VIRTUAL, &it1);
- assert(!res);
+ ASSERT_EQ(0, res);
EXPECT_NOT_POISONED(it1.it_interval.tv_sec);
EXPECT_NOT_POISONED(it1.it_interval.tv_usec);
EXPECT_NOT_POISONED(it1.it_value.tv_sec);
@@ -1833,7 +1956,7 @@ TEST(MemorySanitizer, getitimer) {
it1.it_interval.tv_usec = it1.it_value.tv_usec = 0;
res = setitimer(ITIMER_VIRTUAL, &it1, &it2);
- assert(!res);
+ ASSERT_EQ(0, res);
EXPECT_NOT_POISONED(it2.it_interval.tv_sec);
EXPECT_NOT_POISONED(it2.it_interval.tv_usec);
EXPECT_NOT_POISONED(it2.it_value.tv_sec);
@@ -1842,7 +1965,7 @@ TEST(MemorySanitizer, getitimer) {
// Check that old_value can be 0, and disable the timer.
memset(&it1, 0, sizeof(it1));
res = setitimer(ITIMER_VIRTUAL, &it1, 0);
- assert(!res);
+ ASSERT_EQ(0, res);
}
TEST(MemorySanitizer, setitimer_null) {
@@ -1856,14 +1979,14 @@ TEST(MemorySanitizer, time) {
time_t t;
EXPECT_POISONED(t);
time_t t2 = time(&t);
- assert(t2 != (time_t)-1);
+ ASSERT_NE(t2, (time_t)-1);
EXPECT_NOT_POISONED(t);
}
TEST(MemorySanitizer, strptime) {
struct tm time;
char *p = strptime("11/1/2013-05:39", "%m/%d/%Y-%H:%M", &time);
- assert(p != 0);
+ ASSERT_TRUE(p != NULL);
EXPECT_NOT_POISONED(time.tm_sec);
EXPECT_NOT_POISONED(time.tm_hour);
EXPECT_NOT_POISONED(time.tm_year);
@@ -1872,34 +1995,34 @@ TEST(MemorySanitizer, strptime) {
TEST(MemorySanitizer, localtime) {
time_t t = 123;
struct tm *time = localtime(&t);
- assert(time != 0);
+ ASSERT_TRUE(time != NULL);
EXPECT_NOT_POISONED(time->tm_sec);
EXPECT_NOT_POISONED(time->tm_hour);
EXPECT_NOT_POISONED(time->tm_year);
EXPECT_NOT_POISONED(time->tm_isdst);
- EXPECT_NE(0, strlen(time->tm_zone));
+ EXPECT_NE(0U, strlen(time->tm_zone));
}
TEST(MemorySanitizer, localtime_r) {
time_t t = 123;
struct tm time;
struct tm *res = localtime_r(&t, &time);
- assert(res != 0);
+ ASSERT_TRUE(res != NULL);
EXPECT_NOT_POISONED(time.tm_sec);
EXPECT_NOT_POISONED(time.tm_hour);
EXPECT_NOT_POISONED(time.tm_year);
EXPECT_NOT_POISONED(time.tm_isdst);
- EXPECT_NE(0, strlen(time.tm_zone));
+ EXPECT_NE(0U, strlen(time.tm_zone));
}
TEST(MemorySanitizer, getmntent) {
FILE *fp = setmntent("/etc/fstab", "r");
struct mntent *mnt = getmntent(fp);
- ASSERT_NE((void *)0, mnt);
- ASSERT_NE(0, strlen(mnt->mnt_fsname));
- ASSERT_NE(0, strlen(mnt->mnt_dir));
- ASSERT_NE(0, strlen(mnt->mnt_type));
- ASSERT_NE(0, strlen(mnt->mnt_opts));
+ ASSERT_TRUE(mnt != NULL);
+ ASSERT_NE(0U, strlen(mnt->mnt_fsname));
+ ASSERT_NE(0U, strlen(mnt->mnt_dir));
+ ASSERT_NE(0U, strlen(mnt->mnt_type));
+ ASSERT_NE(0U, strlen(mnt->mnt_opts));
EXPECT_NOT_POISONED(mnt->mnt_freq);
EXPECT_NOT_POISONED(mnt->mnt_passno);
fclose(fp);
@@ -1910,11 +2033,11 @@ TEST(MemorySanitizer, getmntent_r) {
struct mntent mntbuf;
char buf[1000];
struct mntent *mnt = getmntent_r(fp, &mntbuf, buf, sizeof(buf));
- ASSERT_NE((void *)0, mnt);
- ASSERT_NE(0, strlen(mnt->mnt_fsname));
- ASSERT_NE(0, strlen(mnt->mnt_dir));
- ASSERT_NE(0, strlen(mnt->mnt_type));
- ASSERT_NE(0, strlen(mnt->mnt_opts));
+ ASSERT_TRUE(mnt != NULL);
+ ASSERT_NE(0U, strlen(mnt->mnt_fsname));
+ ASSERT_NE(0U, strlen(mnt->mnt_dir));
+ ASSERT_NE(0U, strlen(mnt->mnt_type));
+ ASSERT_NE(0U, strlen(mnt->mnt_opts));
EXPECT_NOT_POISONED(mnt->mnt_freq);
EXPECT_NOT_POISONED(mnt->mnt_passno);
fclose(fp);
@@ -1931,12 +2054,12 @@ TEST(MemorySanitizer, ether) {
EXPECT_NOT_POISONED(addr);
char *s = ether_ntoa(&addr);
- ASSERT_NE(0, strlen(s));
+ ASSERT_NE(0U, strlen(s));
char buf[100];
s = ether_ntoa_r(&addr, buf);
ASSERT_EQ(s, buf);
- ASSERT_NE(0, strlen(buf));
+ ASSERT_NE(0U, strlen(buf));
}
TEST(MemorySanitizer, mmap) {
@@ -1969,6 +2092,56 @@ TEST(MemorySanitizer, fcvt) {
char *str = fcvt(12345.6789, 10, &a, &b);
EXPECT_NOT_POISONED(a);
EXPECT_NOT_POISONED(b);
+ ASSERT_NE(nullptr, str);
+ EXPECT_NOT_POISONED(str[0]);
+ ASSERT_NE(0U, strlen(str));
+}
+
+TEST(MemorySanitizer, fcvt_long) {
+ int a, b;
+ break_optimization(&a);
+ break_optimization(&b);
+ EXPECT_POISONED(a);
+ EXPECT_POISONED(b);
+ char *str = fcvt(111111112345.6789, 10, &a, &b);
+ EXPECT_NOT_POISONED(a);
+ EXPECT_NOT_POISONED(b);
+ ASSERT_NE(nullptr, str);
+ EXPECT_NOT_POISONED(str[0]);
+ ASSERT_NE(0U, strlen(str));
+}
+
+
+TEST(MemorySanitizer, memchr) {
+ char x[10];
+ break_optimization(x);
+ EXPECT_POISONED(x[0]);
+ x[2] = '2';
+ void *res;
+ EXPECT_UMR(res = memchr(x, '2', 10));
+ EXPECT_NOT_POISONED(res);
+ x[0] = '0';
+ x[1] = '1';
+ res = memchr(x, '2', 10);
+ EXPECT_EQ(&x[2], res);
+ EXPECT_UMR(res = memchr(x, '3', 10));
+ EXPECT_NOT_POISONED(res);
+}
+
+TEST(MemorySanitizer, memrchr) {
+ char x[10];
+ break_optimization(x);
+ EXPECT_POISONED(x[0]);
+ x[9] = '9';
+ void *res;
+ EXPECT_UMR(res = memrchr(x, '9', 10));
+ EXPECT_NOT_POISONED(res);
+ x[0] = '0';
+ x[1] = '1';
+ res = memrchr(x, '0', 2);
+ EXPECT_EQ(&x[0], res);
+ EXPECT_UMR(res = memrchr(x, '7', 10));
+ EXPECT_NOT_POISONED(res);
}
TEST(MemorySanitizer, frexp) {
@@ -1994,8 +2167,8 @@ namespace {
static int cnt;
void SigactionHandler(int signo, siginfo_t* si, void* uc) {
- assert(signo == SIGPROF);
- assert(si);
+ ASSERT_EQ(signo, SIGPROF);
+ ASSERT_TRUE(si != NULL);
EXPECT_NOT_POISONED(si->si_errno);
EXPECT_NOT_POISONED(si->si_pid);
#if __linux__
@@ -2308,6 +2481,41 @@ struct StructByVal {
int a, b, c, d, e, f;
};
+static void vaargsfn_structbyval(int guard, ...) {
+ va_list vl;
+ va_start(vl, guard);
+ {
+ StructByVal s = va_arg(vl, StructByVal);
+ EXPECT_NOT_POISONED(s.a);
+ EXPECT_POISONED(s.b);
+ EXPECT_NOT_POISONED(s.c);
+ EXPECT_POISONED(s.d);
+ EXPECT_NOT_POISONED(s.e);
+ EXPECT_POISONED(s.f);
+ }
+ {
+ StructByVal s = va_arg(vl, StructByVal);
+ EXPECT_NOT_POISONED(s.a);
+ EXPECT_POISONED(s.b);
+ EXPECT_NOT_POISONED(s.c);
+ EXPECT_POISONED(s.d);
+ EXPECT_NOT_POISONED(s.e);
+ EXPECT_POISONED(s.f);
+ }
+ va_end(vl);
+}
+
+TEST(MemorySanitizer, VAArgStructByVal) {
+ StructByVal s;
+ s.a = 1;
+ s.b = *GetPoisoned<int>();
+ s.c = 2;
+ s.d = *GetPoisoned<int>();
+ s.e = 3;
+ s.f = *GetPoisoned<int>();
+ vaargsfn_structbyval(0, s, s);
+}
+
NOINLINE void StructByValTestFunc(struct StructByVal s) {
EXPECT_NOT_POISONED(s.a);
EXPECT_POISONED(s.b);
@@ -2481,7 +2689,7 @@ TEST(MemorySanitizer, getrlimit) {
struct rlimit limit;
__msan_poison(&limit, sizeof(limit));
int result = getrlimit(RLIMIT_DATA, &limit);
- assert(result == 0);
+ ASSERT_EQ(result, 0);
EXPECT_NOT_POISONED(limit.rlim_cur);
EXPECT_NOT_POISONED(limit.rlim_max);
}
@@ -2490,7 +2698,7 @@ TEST(MemorySanitizer, getrusage) {
struct rusage usage;
__msan_poison(&usage, sizeof(usage));
int result = getrusage(RUSAGE_SELF, &usage);
- assert(result == 0);
+ ASSERT_EQ(result, 0);
EXPECT_NOT_POISONED(usage.ru_utime.tv_sec);
EXPECT_NOT_POISONED(usage.ru_utime.tv_usec);
EXPECT_NOT_POISONED(usage.ru_stime.tv_sec);
@@ -2516,7 +2724,7 @@ TEST(MemorySanitizer, dladdr) {
Dl_info info;
__msan_poison(&info, sizeof(info));
int result = dladdr((const void*)dladdr_testfn, &info);
- assert(result != 0);
+ ASSERT_NE(result, 0);
EXPECT_NOT_POISONED((unsigned long)info.dli_fname);
if (info.dli_fname)
EXPECT_NOT_POISONED(strlen(info.dli_fname));
@@ -2548,13 +2756,14 @@ static int PathToLoadable(char *buf, size_t sz) {
assert(last_slash);
int res =
snprintf(buf, sz, "%.*s/%s", int(last_slash - argv0), argv0, basename);
- return res < sz ? 0 : res;
+ assert(res >= 0);
+ return (size_t)res < sz ? 0 : res;
}
TEST(MemorySanitizer, dl_iterate_phdr) {
char path[4096];
int res = PathToLoadable(path, sizeof(path));
- assert(!res);
+ ASSERT_EQ(0, res);
// Having at least one dlopen'ed library in the process makes this more
// entertaining.
@@ -2563,7 +2772,7 @@ TEST(MemorySanitizer, dl_iterate_phdr) {
int count = 0;
int result = dl_iterate_phdr(dl_phdr_callback, &count);
- assert(count > 0);
+ ASSERT_GT(count, 0);
dlclose(lib);
}
@@ -2572,7 +2781,7 @@ TEST(MemorySanitizer, dl_iterate_phdr) {
TEST(MemorySanitizer, dlopen) {
char path[4096];
int res = PathToLoadable(path, sizeof(path));
- assert(!res);
+ ASSERT_EQ(0, res);
// We need to clear shadow for globals when doing dlopen. In order to test
// this, we have to poison the shadow for the DSO before we load it. In
@@ -2583,10 +2792,10 @@ TEST(MemorySanitizer, dlopen) {
void *lib = dlopen(path, RTLD_LAZY);
if (lib == NULL) {
printf("dlerror: %s\n", dlerror());
- assert(lib != NULL);
+ ASSERT_TRUE(lib != NULL);
}
void **(*get_dso_global)() = (void **(*)())dlsym(lib, "get_dso_global");
- assert(get_dso_global);
+ ASSERT_TRUE(get_dso_global != NULL);
void **dso_global = get_dso_global();
EXPECT_NOT_POISONED(*dso_global);
__msan_poison(dso_global, sizeof(*dso_global));
@@ -2599,7 +2808,7 @@ TEST(MemorySanitizer, dlopen) {
TEST(MemorySanitizer, dlopenFailed) {
const char *path = "/libmsan_loadable_does_not_exist.x86_64.so";
void *lib = dlopen(path, RTLD_LAZY);
- ASSERT_EQ(0, lib);
+ ASSERT_TRUE(lib == NULL);
}
#endif // MSAN_TEST_DISABLE_DLOPEN
@@ -2617,7 +2826,7 @@ TEST(MemorySanitizer, scanf) {
char* s = new char[7];
int res = sscanf(input, "%d %5s", d, s);
printf("res %d\n", res);
- assert(res == 2);
+ ASSERT_EQ(res, 2);
EXPECT_NOT_POISONED(*d);
EXPECT_NOT_POISONED(s[0]);
EXPECT_NOT_POISONED(s[1]);
@@ -2626,7 +2835,7 @@ TEST(MemorySanitizer, scanf) {
EXPECT_NOT_POISONED(s[4]);
EXPECT_NOT_POISONED(s[5]);
EXPECT_POISONED(s[6]);
- delete s;
+ delete[] s;
delete d;
}
@@ -2638,10 +2847,10 @@ TEST(MemorySanitizer, SimpleThread) {
pthread_t t;
void *p;
int res = pthread_create(&t, NULL, SimpleThread_threadfn, NULL);
- assert(!res);
+ ASSERT_EQ(0, res);
EXPECT_NOT_POISONED(t);
res = pthread_join(t, &p);
- assert(!res);
+ ASSERT_EQ(0, res);
EXPECT_NOT_POISONED(p);
delete (int*)p;
}
@@ -2667,22 +2876,22 @@ TEST(MemorySanitizer, SmallStackThread) {
ASSERT_EQ(0, res);
}
-TEST(MemorySanitizer, PreAllocatedStackThread) {
+TEST(MemorySanitizer, SmallPreAllocatedStackThread) {
pthread_attr_t attr;
pthread_t t;
int res;
res = pthread_attr_init(&attr);
ASSERT_EQ(0, res);
void *stack;
- const size_t kStackSize = 64 * 1024;
+ const size_t kStackSize = 16 * 1024;
res = posix_memalign(&stack, 4096, kStackSize);
ASSERT_EQ(0, res);
res = pthread_attr_setstack(&attr, stack, kStackSize);
ASSERT_EQ(0, res);
- // A small self-allocated stack can not be extended by the tool.
- // In this case pthread_create is expected to fail.
res = pthread_create(&t, &attr, SmallStackThread_threadfn, NULL);
- EXPECT_NE(0, res);
+ EXPECT_EQ(0, res);
+ res = pthread_join(t, NULL);
+ ASSERT_EQ(0, res);
res = pthread_attr_destroy(&attr);
ASSERT_EQ(0, res);
}
@@ -2764,10 +2973,10 @@ TEST(MemorySanitizer, pthread_getschedparam) {
TEST(MemorySanitizer, pthread_key_create) {
pthread_key_t key;
int res = pthread_key_create(&key, NULL);
- assert(!res);
+ ASSERT_EQ(0, res);
EXPECT_NOT_POISONED(key);
res = pthread_key_delete(key);
- assert(!res);
+ ASSERT_EQ(0, res);
}
namespace {
@@ -2801,14 +3010,14 @@ TEST(MemorySanitizer, pthread_cond_wait) {
pthread_t thr;
pthread_create(&thr, 0, SignalCond, &args);
int res = pthread_cond_wait(&cond, &mu);
- assert(!res);
+ ASSERT_EQ(0, res);
pthread_join(thr, 0);
// broadcast
args.broadcast = true;
pthread_create(&thr, 0, SignalCond, &args);
res = pthread_cond_wait(&cond, &mu);
- assert(!res);
+ ASSERT_EQ(0, res);
pthread_join(thr, 0);
pthread_mutex_unlock(&mu);
@@ -2854,12 +3063,12 @@ TEST(MemorySanitizer, valloc) {
TEST(MemorySanitizer, pvalloc) {
void *p = pvalloc(kPageSize + 100);
EXPECT_EQ(0U, (uintptr_t)p % kPageSize);
- EXPECT_EQ(2 * kPageSize, __msan_get_allocated_size(p));
+ EXPECT_EQ(2 * kPageSize, __sanitizer_get_allocated_size(p));
free(p);
p = pvalloc(0); // pvalloc(0) should allocate at least one page.
EXPECT_EQ(0U, (uintptr_t)p % kPageSize);
- EXPECT_EQ(kPageSize, __msan_get_allocated_size(p));
+ EXPECT_EQ(kPageSize, __sanitizer_get_allocated_size(p));
free(p);
}
@@ -2890,7 +3099,7 @@ TEST(MemorySanitizer, inet_aton) {
TEST(MemorySanitizer, uname) {
struct utsname u;
int res = uname(&u);
- assert(!res);
+ ASSERT_EQ(0, res);
EXPECT_NOT_POISONED(strlen(u.sysname));
EXPECT_NOT_POISONED(strlen(u.nodename));
EXPECT_NOT_POISONED(strlen(u.release));
@@ -2901,25 +3110,39 @@ TEST(MemorySanitizer, uname) {
TEST(MemorySanitizer, gethostname) {
char buf[100];
int res = gethostname(buf, 100);
- assert(!res);
+ ASSERT_EQ(0, res);
EXPECT_NOT_POISONED(strlen(buf));
}
TEST(MemorySanitizer, sysinfo) {
struct sysinfo info;
int res = sysinfo(&info);
- assert(!res);
+ ASSERT_EQ(0, res);
EXPECT_NOT_POISONED(info);
}
TEST(MemorySanitizer, getpwuid) {
struct passwd *p = getpwuid(0); // root
- assert(p);
+ ASSERT_TRUE(p != NULL);
EXPECT_NOT_POISONED(p->pw_name);
- assert(p->pw_name);
+ ASSERT_TRUE(p->pw_name != NULL);
EXPECT_NOT_POISONED(p->pw_name[0]);
EXPECT_NOT_POISONED(p->pw_uid);
- assert(p->pw_uid == 0);
+ ASSERT_EQ(0U, p->pw_uid);
+}
+
+TEST(MemorySanitizer, getpwuid_r) {
+ struct passwd pwd;
+ struct passwd *pwdres;
+ char buf[10000];
+ int res = getpwuid_r(0, &pwd, buf, sizeof(buf), &pwdres);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(pwd.pw_name);
+ ASSERT_TRUE(pwd.pw_name != NULL);
+ EXPECT_NOT_POISONED(pwd.pw_name[0]);
+ EXPECT_NOT_POISONED(pwd.pw_uid);
+ ASSERT_EQ(0U, pwd.pw_uid);
+ EXPECT_NOT_POISONED(pwdres);
}
TEST(MemorySanitizer, getpwnam_r) {
@@ -2927,12 +3150,13 @@ TEST(MemorySanitizer, getpwnam_r) {
struct passwd *pwdres;
char buf[10000];
int res = getpwnam_r("root", &pwd, buf, sizeof(buf), &pwdres);
- assert(!res);
+ ASSERT_EQ(0, res);
EXPECT_NOT_POISONED(pwd.pw_name);
- assert(pwd.pw_name);
+ ASSERT_TRUE(pwd.pw_name != NULL);
EXPECT_NOT_POISONED(pwd.pw_name[0]);
EXPECT_NOT_POISONED(pwd.pw_uid);
- assert(pwd.pw_uid == 0);
+ ASSERT_EQ(0U, pwd.pw_uid);
+ EXPECT_NOT_POISONED(pwdres);
}
TEST(MemorySanitizer, getpwnam_r_positive) {
@@ -2951,11 +3175,102 @@ TEST(MemorySanitizer, getgrnam_r) {
struct group *grpres;
char buf[10000];
int res = getgrnam_r("root", &grp, buf, sizeof(buf), &grpres);
- assert(!res);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(grp.gr_name);
+ ASSERT_TRUE(grp.gr_name != NULL);
+ EXPECT_NOT_POISONED(grp.gr_name[0]);
+ EXPECT_NOT_POISONED(grp.gr_gid);
+ EXPECT_NOT_POISONED(grpres);
+}
+
+TEST(MemorySanitizer, getpwent) {
+ setpwent();
+ struct passwd *p = getpwent();
+ ASSERT_TRUE(p != NULL);
+ EXPECT_NOT_POISONED(p->pw_name);
+ ASSERT_TRUE(p->pw_name != NULL);
+ EXPECT_NOT_POISONED(p->pw_name[0]);
+ EXPECT_NOT_POISONED(p->pw_uid);
+}
+
+TEST(MemorySanitizer, getpwent_r) {
+ struct passwd pwd;
+ struct passwd *pwdres;
+ char buf[10000];
+ setpwent();
+ int res = getpwent_r(&pwd, buf, sizeof(buf), &pwdres);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(pwd.pw_name);
+ ASSERT_TRUE(pwd.pw_name != NULL);
+ EXPECT_NOT_POISONED(pwd.pw_name[0]);
+ EXPECT_NOT_POISONED(pwd.pw_uid);
+ EXPECT_NOT_POISONED(pwdres);
+}
+
+TEST(MemorySanitizer, fgetpwent) {
+ FILE *fp = fopen("/etc/passwd", "r");
+ struct passwd *p = fgetpwent(fp);
+ ASSERT_TRUE(p != NULL);
+ EXPECT_NOT_POISONED(p->pw_name);
+ ASSERT_TRUE(p->pw_name != NULL);
+ EXPECT_NOT_POISONED(p->pw_name[0]);
+ EXPECT_NOT_POISONED(p->pw_uid);
+ fclose(fp);
+}
+
+TEST(MemorySanitizer, getgrent) {
+ setgrent();
+ struct group *p = getgrent();
+ ASSERT_TRUE(p != NULL);
+ EXPECT_NOT_POISONED(p->gr_name);
+ ASSERT_TRUE(p->gr_name != NULL);
+ EXPECT_NOT_POISONED(p->gr_name[0]);
+ EXPECT_NOT_POISONED(p->gr_gid);
+}
+
+TEST(MemorySanitizer, fgetgrent) {
+ FILE *fp = fopen("/etc/group", "r");
+ struct group *grp = fgetgrent(fp);
+ ASSERT_TRUE(grp != NULL);
+ EXPECT_NOT_POISONED(grp->gr_name);
+ ASSERT_TRUE(grp->gr_name != NULL);
+ EXPECT_NOT_POISONED(grp->gr_name[0]);
+ EXPECT_NOT_POISONED(grp->gr_gid);
+ for (char **p = grp->gr_mem; *p; ++p) {
+ EXPECT_NOT_POISONED((*p)[0]);
+ EXPECT_TRUE(strlen(*p) > 0);
+ }
+ fclose(fp);
+}
+
+TEST(MemorySanitizer, getgrent_r) {
+ struct group grp;
+ struct group *grpres;
+ char buf[10000];
+ setgrent();
+ int res = getgrent_r(&grp, buf, sizeof(buf), &grpres);
+ ASSERT_EQ(0, res);
EXPECT_NOT_POISONED(grp.gr_name);
- assert(grp.gr_name);
+ ASSERT_TRUE(grp.gr_name != NULL);
EXPECT_NOT_POISONED(grp.gr_name[0]);
EXPECT_NOT_POISONED(grp.gr_gid);
+ EXPECT_NOT_POISONED(grpres);
+}
+
+TEST(MemorySanitizer, fgetgrent_r) {
+ FILE *fp = fopen("/etc/group", "r");
+ struct group grp;
+ struct group *grpres;
+ char buf[10000];
+ setgrent();
+ int res = fgetgrent_r(fp, &grp, buf, sizeof(buf), &grpres);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(grp.gr_name);
+ ASSERT_TRUE(grp.gr_name != NULL);
+ EXPECT_NOT_POISONED(grp.gr_name[0]);
+ EXPECT_NOT_POISONED(grp.gr_gid);
+ EXPECT_NOT_POISONED(grpres);
+ fclose(fp);
}
TEST(MemorySanitizer, getgroups) {
@@ -2971,7 +3286,7 @@ TEST(MemorySanitizer, wordexp) {
wordexp_t w;
int res = wordexp("a b c", &w, 0);
ASSERT_EQ(0, res);
- ASSERT_EQ(3, w.we_wordc);
+ ASSERT_EQ(3U, w.we_wordc);
ASSERT_STREQ("a", w.we_wordv[0]);
ASSERT_STREQ("b", w.we_wordv[1]);
ASSERT_STREQ("c", w.we_wordv[2]);
@@ -3085,141 +3400,376 @@ TEST(MemorySanitizer, VolatileBitfield) {
TEST(MemorySanitizer, UnalignedLoad) {
char x[32];
+ U4 origin = __LINE__;
+ for (unsigned i = 0; i < sizeof(x) / 4; ++i)
+ __msan_set_origin(x + 4 * i, 4, origin + i);
+
memset(x + 8, 0, 16);
- EXPECT_POISONED(__sanitizer_unaligned_load16(x+6));
- EXPECT_POISONED(__sanitizer_unaligned_load16(x+7));
- EXPECT_NOT_POISONED(__sanitizer_unaligned_load16(x+8));
- EXPECT_NOT_POISONED(__sanitizer_unaligned_load16(x+9));
- EXPECT_NOT_POISONED(__sanitizer_unaligned_load16(x+22));
- EXPECT_POISONED(__sanitizer_unaligned_load16(x+23));
- EXPECT_POISONED(__sanitizer_unaligned_load16(x+24));
-
- EXPECT_POISONED(__sanitizer_unaligned_load32(x+4));
- EXPECT_POISONED(__sanitizer_unaligned_load32(x+7));
- EXPECT_NOT_POISONED(__sanitizer_unaligned_load32(x+8));
- EXPECT_NOT_POISONED(__sanitizer_unaligned_load32(x+9));
- EXPECT_NOT_POISONED(__sanitizer_unaligned_load32(x+20));
- EXPECT_POISONED(__sanitizer_unaligned_load32(x+21));
- EXPECT_POISONED(__sanitizer_unaligned_load32(x+24));
-
- EXPECT_POISONED(__sanitizer_unaligned_load64(x));
- EXPECT_POISONED(__sanitizer_unaligned_load64(x+1));
- EXPECT_POISONED(__sanitizer_unaligned_load64(x+7));
- EXPECT_NOT_POISONED(__sanitizer_unaligned_load64(x+8));
- EXPECT_NOT_POISONED(__sanitizer_unaligned_load64(x+9));
- EXPECT_NOT_POISONED(__sanitizer_unaligned_load64(x+16));
- EXPECT_POISONED(__sanitizer_unaligned_load64(x+17));
- EXPECT_POISONED(__sanitizer_unaligned_load64(x+21));
- EXPECT_POISONED(__sanitizer_unaligned_load64(x+24));
+ EXPECT_POISONED_O(__sanitizer_unaligned_load16(x + 6), origin + 1);
+ EXPECT_POISONED_O(__sanitizer_unaligned_load16(x + 7), origin + 1);
+ EXPECT_NOT_POISONED(__sanitizer_unaligned_load16(x + 8));
+ EXPECT_NOT_POISONED(__sanitizer_unaligned_load16(x + 9));
+ EXPECT_NOT_POISONED(__sanitizer_unaligned_load16(x + 22));
+ EXPECT_POISONED_O(__sanitizer_unaligned_load16(x + 23), origin + 6);
+ EXPECT_POISONED_O(__sanitizer_unaligned_load16(x + 24), origin + 6);
+
+ EXPECT_POISONED_O(__sanitizer_unaligned_load32(x + 4), origin + 1);
+ EXPECT_POISONED_O(__sanitizer_unaligned_load32(x + 7), origin + 1);
+ EXPECT_NOT_POISONED(__sanitizer_unaligned_load32(x + 8));
+ EXPECT_NOT_POISONED(__sanitizer_unaligned_load32(x + 9));
+ EXPECT_NOT_POISONED(__sanitizer_unaligned_load32(x + 20));
+ EXPECT_POISONED_O(__sanitizer_unaligned_load32(x + 21), origin + 6);
+ EXPECT_POISONED_O(__sanitizer_unaligned_load32(x + 24), origin + 6);
+
+ EXPECT_POISONED_O(__sanitizer_unaligned_load64(x), origin);
+ EXPECT_POISONED_O(__sanitizer_unaligned_load64(x + 1), origin);
+ EXPECT_POISONED_O(__sanitizer_unaligned_load64(x + 7), origin + 1);
+ EXPECT_NOT_POISONED(__sanitizer_unaligned_load64(x + 8));
+ EXPECT_NOT_POISONED(__sanitizer_unaligned_load64(x + 9));
+ EXPECT_NOT_POISONED(__sanitizer_unaligned_load64(x + 16));
+ EXPECT_POISONED_O(__sanitizer_unaligned_load64(x + 17), origin + 6);
+ EXPECT_POISONED_O(__sanitizer_unaligned_load64(x + 21), origin + 6);
+ EXPECT_POISONED_O(__sanitizer_unaligned_load64(x + 24), origin + 6);
}
TEST(MemorySanitizer, UnalignedStore16) {
char x[5];
- U2 y = 0;
- __msan_poison(&y, 1);
- __sanitizer_unaligned_store16(x + 1, y);
- EXPECT_POISONED(x[0]);
- EXPECT_POISONED(x[1]);
+ U2 y2 = 0;
+ U4 origin = __LINE__;
+ __msan_poison(&y2, 1);
+ __msan_set_origin(&y2, 1, origin);
+
+ __sanitizer_unaligned_store16(x + 1, y2);
+ EXPECT_POISONED_O(x[0], origin);
+ EXPECT_POISONED_O(x[1], origin);
EXPECT_NOT_POISONED(x[2]);
- EXPECT_POISONED(x[3]);
- EXPECT_POISONED(x[4]);
+ EXPECT_POISONED_O(x[3], origin);
+ EXPECT_POISONED_O(x[4], origin);
}
TEST(MemorySanitizer, UnalignedStore32) {
char x[8];
U4 y4 = 0;
+ U4 origin = __LINE__;
__msan_poison(&y4, 2);
- __sanitizer_unaligned_store32(x+3, y4);
- EXPECT_POISONED(x[0]);
- EXPECT_POISONED(x[1]);
- EXPECT_POISONED(x[2]);
- EXPECT_POISONED(x[3]);
- EXPECT_POISONED(x[4]);
+ __msan_set_origin(&y4, 2, origin);
+
+ __sanitizer_unaligned_store32(x + 3, y4);
+ EXPECT_POISONED_O(x[0], origin);
+ EXPECT_POISONED_O(x[1], origin);
+ EXPECT_POISONED_O(x[2], origin);
+ EXPECT_POISONED_O(x[3], origin);
+ EXPECT_POISONED_O(x[4], origin);
EXPECT_NOT_POISONED(x[5]);
EXPECT_NOT_POISONED(x[6]);
- EXPECT_POISONED(x[7]);
+ EXPECT_POISONED_O(x[7], origin);
}
TEST(MemorySanitizer, UnalignedStore64) {
char x[16];
- U8 y = 0;
- __msan_poison(&y, 3);
- __msan_poison(((char *)&y) + sizeof(y) - 2, 1);
- __sanitizer_unaligned_store64(x+3, y);
- EXPECT_POISONED(x[0]);
- EXPECT_POISONED(x[1]);
- EXPECT_POISONED(x[2]);
- EXPECT_POISONED(x[3]);
- EXPECT_POISONED(x[4]);
- EXPECT_POISONED(x[5]);
+ U8 y8 = 0;
+ U4 origin = __LINE__;
+ __msan_poison(&y8, 3);
+ __msan_poison(((char *)&y8) + sizeof(y8) - 2, 1);
+ __msan_set_origin(&y8, 8, origin);
+
+ __sanitizer_unaligned_store64(x + 3, y8);
+ EXPECT_POISONED_O(x[0], origin);
+ EXPECT_POISONED_O(x[1], origin);
+ EXPECT_POISONED_O(x[2], origin);
+ EXPECT_POISONED_O(x[3], origin);
+ EXPECT_POISONED_O(x[4], origin);
+ EXPECT_POISONED_O(x[5], origin);
EXPECT_NOT_POISONED(x[6]);
EXPECT_NOT_POISONED(x[7]);
EXPECT_NOT_POISONED(x[8]);
- EXPECT_POISONED(x[9]);
+ EXPECT_POISONED_O(x[9], origin);
EXPECT_NOT_POISONED(x[10]);
- EXPECT_POISONED(x[11]);
+ EXPECT_POISONED_O(x[11], origin);
}
-TEST(MemorySanitizerDr, StoreInDSOTest) {
- if (!__msan_has_dynamic_component()) return;
- char* s = new char[10];
- dso_memfill(s, 9);
- EXPECT_NOT_POISONED(s[5]);
- EXPECT_POISONED(s[9]);
+TEST(MemorySanitizer, UnalignedStore16_precise) {
+ char x[8];
+ U2 y = 0;
+ U4 originx1 = __LINE__;
+ U4 originx2 = __LINE__;
+ U4 originy = __LINE__;
+ __msan_poison(x, sizeof(x));
+ __msan_set_origin(x, 4, originx1);
+ __msan_set_origin(x + 4, 4, originx2);
+ __msan_poison(((char *)&y) + 1, 1);
+ __msan_set_origin(&y, sizeof(y), originy);
+
+ __sanitizer_unaligned_store16(x + 3, y);
+ EXPECT_POISONED_O(x[0], originx1);
+ EXPECT_POISONED_O(x[1], originx1);
+ EXPECT_POISONED_O(x[2], originx1);
+ EXPECT_NOT_POISONED(x[3]);
+ EXPECT_POISONED_O(x[4], originy);
+ EXPECT_POISONED_O(x[5], originy);
+ EXPECT_POISONED_O(x[6], originy);
+ EXPECT_POISONED_O(x[7], originy);
}
-int return_poisoned_int() {
- return ReturnPoisoned<U8>();
-}
+TEST(MemorySanitizer, UnalignedStore16_precise2) {
+ char x[8];
+ U2 y = 0;
+ U4 originx1 = __LINE__;
+ U4 originx2 = __LINE__;
+ U4 originy = __LINE__;
+ __msan_poison(x, sizeof(x));
+ __msan_set_origin(x, 4, originx1);
+ __msan_set_origin(x + 4, 4, originx2);
+ __msan_poison(((char *)&y), 1);
+ __msan_set_origin(&y, sizeof(y), originy);
+
+ __sanitizer_unaligned_store16(x + 3, y);
+ EXPECT_POISONED_O(x[0], originy);
+ EXPECT_POISONED_O(x[1], originy);
+ EXPECT_POISONED_O(x[2], originy);
+ EXPECT_POISONED_O(x[3], originy);
+ EXPECT_NOT_POISONED(x[4]);
+ EXPECT_POISONED_O(x[5], originx2);
+ EXPECT_POISONED_O(x[6], originx2);
+ EXPECT_POISONED_O(x[7], originx2);
+}
+
+TEST(MemorySanitizer, UnalignedStore64_precise) {
+ char x[12];
+ U8 y = 0;
+ U4 originx1 = __LINE__;
+ U4 originx2 = __LINE__;
+ U4 originx3 = __LINE__;
+ U4 originy = __LINE__;
+ __msan_poison(x, sizeof(x));
+ __msan_set_origin(x, 4, originx1);
+ __msan_set_origin(x + 4, 4, originx2);
+ __msan_set_origin(x + 8, 4, originx3);
+ __msan_poison(((char *)&y) + 1, 1);
+ __msan_poison(((char *)&y) + 7, 1);
+ __msan_set_origin(&y, sizeof(y), originy);
+
+ __sanitizer_unaligned_store64(x + 2, y);
+ EXPECT_POISONED_O(x[0], originy);
+ EXPECT_POISONED_O(x[1], originy);
+ EXPECT_NOT_POISONED(x[2]);
+ EXPECT_POISONED_O(x[3], originy);
+
+ EXPECT_NOT_POISONED(x[4]);
+ EXPECT_NOT_POISONED(x[5]);
+ EXPECT_NOT_POISONED(x[6]);
+ EXPECT_NOT_POISONED(x[7]);
-TEST(MemorySanitizerDr, ReturnFromDSOTest) {
- if (!__msan_has_dynamic_component()) return;
- EXPECT_NOT_POISONED(dso_callfn(return_poisoned_int));
+ EXPECT_NOT_POISONED(x[8]);
+ EXPECT_POISONED_O(x[9], originy);
+ EXPECT_POISONED_O(x[10], originy);
+ EXPECT_POISONED_O(x[11], originy);
}
-NOINLINE int TrashParamTLS(long long x, long long y, long long z) { //NOLINT
- EXPECT_POISONED(x);
- EXPECT_POISONED(y);
- EXPECT_POISONED(z);
- return 0;
+TEST(MemorySanitizer, UnalignedStore64_precise2) {
+ char x[12];
+ U8 y = 0;
+ U4 originx1 = __LINE__;
+ U4 originx2 = __LINE__;
+ U4 originx3 = __LINE__;
+ U4 originy = __LINE__;
+ __msan_poison(x, sizeof(x));
+ __msan_set_origin(x, 4, originx1);
+ __msan_set_origin(x + 4, 4, originx2);
+ __msan_set_origin(x + 8, 4, originx3);
+ __msan_poison(((char *)&y) + 3, 3);
+ __msan_set_origin(&y, sizeof(y), originy);
+
+ __sanitizer_unaligned_store64(x + 2, y);
+ EXPECT_POISONED_O(x[0], originx1);
+ EXPECT_POISONED_O(x[1], originx1);
+ EXPECT_NOT_POISONED(x[2]);
+ EXPECT_NOT_POISONED(x[3]);
+
+ EXPECT_NOT_POISONED(x[4]);
+ EXPECT_POISONED_O(x[5], originy);
+ EXPECT_POISONED_O(x[6], originy);
+ EXPECT_POISONED_O(x[7], originy);
+
+ EXPECT_NOT_POISONED(x[8]);
+ EXPECT_NOT_POISONED(x[9]);
+ EXPECT_POISONED_O(x[10], originx3);
+ EXPECT_POISONED_O(x[11], originx3);
}
-static int CheckParamTLS(long long x, long long y, long long z) { //NOLINT
- EXPECT_NOT_POISONED(x);
- EXPECT_NOT_POISONED(y);
- EXPECT_NOT_POISONED(z);
- return 0;
+#if defined(__clang__)
+namespace {
+typedef U1 V16x8 __attribute__((__vector_size__(16)));
+typedef U2 V8x16 __attribute__((__vector_size__(16)));
+typedef U4 V4x32 __attribute__((__vector_size__(16)));
+typedef U8 V2x64 __attribute__((__vector_size__(16)));
+typedef U4 V8x32 __attribute__((__vector_size__(32)));
+typedef U8 V4x64 __attribute__((__vector_size__(32)));
+typedef U4 V2x32 __attribute__((__vector_size__(8)));
+typedef U2 V4x16 __attribute__((__vector_size__(8)));
+typedef U1 V8x8 __attribute__((__vector_size__(8)));
+
+
+V8x16 shift_sse2_left_scalar(V8x16 x, U4 y) {
+ return _mm_slli_epi16(x, y);
+}
+
+V8x16 shift_sse2_left(V8x16 x, V8x16 y) {
+ return _mm_sll_epi16(x, y);
+}
+
+TEST(VectorShiftTest, sse2_left_scalar) {
+ V8x16 v = {Poisoned<U2>(0, 3), Poisoned<U2>(0, 7), 2, 3, 4, 5, 6, 7};
+ V8x16 u = shift_sse2_left_scalar(v, 2);
+ EXPECT_POISONED(u[0]);
+ EXPECT_POISONED(u[1]);
+ EXPECT_NOT_POISONED(u[0] | (3U << 2));
+ EXPECT_NOT_POISONED(u[1] | (7U << 2));
+ u[0] = u[1] = 0;
+ EXPECT_NOT_POISONED(u);
+}
+
+TEST(VectorShiftTest, sse2_left_scalar_by_uninit) {
+ V8x16 v = {0, 1, 2, 3, 4, 5, 6, 7};
+ V8x16 u = shift_sse2_left_scalar(v, Poisoned<U4>());
+ EXPECT_POISONED(u[0]);
+ EXPECT_POISONED(u[1]);
+ EXPECT_POISONED(u[2]);
+ EXPECT_POISONED(u[3]);
+ EXPECT_POISONED(u[4]);
+ EXPECT_POISONED(u[5]);
+ EXPECT_POISONED(u[6]);
+ EXPECT_POISONED(u[7]);
+}
+
+TEST(VectorShiftTest, sse2_left) {
+ V8x16 v = {Poisoned<U2>(0, 3), Poisoned<U2>(0, 7), 2, 3, 4, 5, 6, 7};
+ // Top 64 bits of shift count don't affect the result.
+ V2x64 s = {2, Poisoned<U8>()};
+ V8x16 u = shift_sse2_left(v, s);
+ EXPECT_POISONED(u[0]);
+ EXPECT_POISONED(u[1]);
+ EXPECT_NOT_POISONED(u[0] | (3U << 2));
+ EXPECT_NOT_POISONED(u[1] | (7U << 2));
+ u[0] = u[1] = 0;
+ EXPECT_NOT_POISONED(u);
+}
+
+TEST(VectorShiftTest, sse2_left_by_uninit) {
+ V8x16 v = {Poisoned<U2>(0, 3), Poisoned<U2>(0, 7), 2, 3, 4, 5, 6, 7};
+ V2x64 s = {Poisoned<U8>(), Poisoned<U8>()};
+ V8x16 u = shift_sse2_left(v, s);
+ EXPECT_POISONED(u[0]);
+ EXPECT_POISONED(u[1]);
+ EXPECT_POISONED(u[2]);
+ EXPECT_POISONED(u[3]);
+ EXPECT_POISONED(u[4]);
+ EXPECT_POISONED(u[5]);
+ EXPECT_POISONED(u[6]);
+ EXPECT_POISONED(u[7]);
+}
+
+#ifdef __AVX2__
+V4x32 shift_avx2_left(V4x32 x, V4x32 y) {
+ return _mm_sllv_epi32(x, y);
+}
+// This is variable vector shift that's only available starting with AVX2.
+// V4x32 shift_avx2_left(V4x32 x, V4x32 y) {
+TEST(VectorShiftTest, avx2_left) {
+ V4x32 v = {Poisoned<U2>(0, 3), Poisoned<U2>(0, 7), 2, 3};
+ V4x32 s = {2, Poisoned<U4>(), 3, Poisoned<U4>()};
+ V4x32 u = shift_avx2_left(v, s);
+ EXPECT_POISONED(u[0]);
+ EXPECT_NOT_POISONED(u[0] | (~7U));
+ EXPECT_POISONED(u[1]);
+ EXPECT_POISONED(u[1] | (~31U));
+ EXPECT_NOT_POISONED(u[2]);
+ EXPECT_POISONED(u[3]);
+ EXPECT_POISONED(u[3] | (~31U));
+}
+#endif // __AVX2__
+} // namespace
+
+TEST(VectorPackTest, sse2_packssdw_128) {
+ const unsigned S2_max = (1 << 15) - 1;
+ V4x32 a = {Poisoned<U4>(0, 0xFF0000), Poisoned<U4>(0, 0xFFFF0000),
+ S2_max + 100, 4};
+ V4x32 b = {Poisoned<U4>(0, 0xFF), S2_max + 10000, Poisoned<U4>(0, 0xFF00),
+ S2_max};
+
+ V8x16 c = _mm_packs_epi32(a, b);
+
+ EXPECT_POISONED(c[0]);
+ EXPECT_POISONED(c[1]);
+ EXPECT_NOT_POISONED(c[2]);
+ EXPECT_NOT_POISONED(c[3]);
+ EXPECT_POISONED(c[4]);
+ EXPECT_NOT_POISONED(c[5]);
+ EXPECT_POISONED(c[6]);
+ EXPECT_NOT_POISONED(c[7]);
+
+ EXPECT_EQ(c[2], S2_max);
+ EXPECT_EQ(c[3], 4);
+ EXPECT_EQ(c[5], S2_max);
+ EXPECT_EQ(c[7], S2_max);
}
-TEST(MemorySanitizerDr, CallFromDSOTest) {
- if (!__msan_has_dynamic_component()) return;
- S8* x = GetPoisoned<S8>();
- S8* y = GetPoisoned<S8>();
- S8* z = GetPoisoned<S8>();
- EXPECT_NOT_POISONED(TrashParamTLS(*x, *y, *z));
- EXPECT_NOT_POISONED(dso_callfn1(CheckParamTLS));
+TEST(VectorPackTest, mmx_packuswb) {
+ const unsigned U1_max = (1 << 8) - 1;
+ V4x16 a = {Poisoned<U2>(0, 0xFF00), Poisoned<U2>(0, 0xF000U), U1_max + 100,
+ 4};
+ V4x16 b = {Poisoned<U2>(0, 0xFF), U1_max - 1, Poisoned<U2>(0, 0xF), U1_max};
+ V8x8 c = _mm_packs_pu16(a, b);
+
+ EXPECT_POISONED(c[0]);
+ EXPECT_POISONED(c[1]);
+ EXPECT_NOT_POISONED(c[2]);
+ EXPECT_NOT_POISONED(c[3]);
+ EXPECT_POISONED(c[4]);
+ EXPECT_NOT_POISONED(c[5]);
+ EXPECT_POISONED(c[6]);
+ EXPECT_NOT_POISONED(c[7]);
+
+ EXPECT_EQ(c[2], U1_max);
+ EXPECT_EQ(c[3], 4);
+ EXPECT_EQ(c[5], U1_max - 1);
+ EXPECT_EQ(c[7], U1_max);
}
-static void StackStoreInDSOFn(int* x, int* y) {
- EXPECT_NOT_POISONED(*x);
- EXPECT_NOT_POISONED(*y);
+TEST(VectorSadTest, sse2_psad_bw) {
+ V16x8 a = {Poisoned<U1>(), 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
+ V16x8 b = {100, 101, 102, 103, 104, 105, 106, 107,
+ 108, 109, 110, 111, 112, 113, 114, 115};
+ V2x64 c = _mm_sad_epu8(a, b);
+
+ EXPECT_POISONED(c[0]);
+ EXPECT_NOT_POISONED(c[1]);
+
+ EXPECT_EQ(800U, c[1]);
}
-TEST(MemorySanitizerDr, StackStoreInDSOTest) {
- if (!__msan_has_dynamic_component()) return;
- dso_stack_store(StackStoreInDSOFn, 1);
+TEST(VectorMaddTest, mmx_pmadd_wd) {
+ V4x16 a = {Poisoned<U2>(), 1, 2, 3};
+ V4x16 b = {100, 101, 102, 103};
+ V2x32 c = _mm_madd_pi16(a, b);
+
+ EXPECT_POISONED(c[0]);
+ EXPECT_NOT_POISONED(c[1]);
+
+ EXPECT_EQ((unsigned)(2 * 102 + 3 * 103), c[1]);
}
+#endif // defined(__clang__)
TEST(MemorySanitizerOrigins, SetGet) {
EXPECT_EQ(TrackingOrigins(), __msan_get_track_origins());
if (!TrackingOrigins()) return;
int x;
__msan_set_origin(&x, sizeof(x), 1234);
- EXPECT_EQ(1234, __msan_get_origin(&x));
+ EXPECT_EQ(1234U, __msan_get_origin(&x));
__msan_set_origin(&x, sizeof(x), 5678);
- EXPECT_EQ(5678, __msan_get_origin(&x));
+ EXPECT_EQ(5678U, __msan_get_origin(&x));
__msan_set_origin(&x, sizeof(x), 0);
- EXPECT_EQ(0, __msan_get_origin(&x));
+ EXPECT_EQ(0U, __msan_get_origin(&x));
}
namespace {
@@ -3229,8 +3779,7 @@ struct S {
U2 b;
};
-// http://code.google.com/p/memory-sanitizer/issues/detail?id=6
-TEST(MemorySanitizerOrigins, DISABLED_InitializedStoreDoesNotChangeOrigin) {
+TEST(MemorySanitizerOrigins, InitializedStoreDoesNotChangeOrigin) {
if (!TrackingOrigins()) return;
S s;
@@ -3403,29 +3952,6 @@ TEST(MemorySanitizerOrigins, Select) {
EXPECT_POISONED_O(g_0 ? 1 : *GetPoisonedO<S4>(0, __LINE__), __LINE__);
}
-extern "C"
-NOINLINE char AllocaTO() {
- int ar[100];
- break_optimization(ar);
- return ar[10];
- // fprintf(stderr, "Descr: %s\n",
- // __msan_get_origin_descr_if_stack(__msan_get_origin_tls()));
-}
-
-TEST(MemorySanitizerOrigins, Alloca) {
- if (!TrackingOrigins()) return;
- EXPECT_POISONED_S(AllocaTO(), "ar@AllocaTO");
- EXPECT_POISONED_S(AllocaTO(), "ar@AllocaTO");
- EXPECT_POISONED_S(AllocaTO(), "ar@AllocaTO");
- EXPECT_POISONED_S(AllocaTO(), "ar@AllocaTO");
-}
-
-// FIXME: replace with a lit-like test.
-TEST(MemorySanitizerOrigins, DISABLED_AllocaDeath) {
- if (!TrackingOrigins()) return;
- EXPECT_DEATH(AllocaTO(), "ORIGIN: stack allocation: ar@AllocaTO");
-}
-
NOINLINE int RetvalOriginTest(U4 origin) {
int *a = new int;
break_optimization(a);
@@ -3513,6 +4039,26 @@ TEST(MemorySanitizer, Select) {
EXPECT_POISONED(z);
}
+TEST(MemorySanitizer, SelectPartial) {
+ // Precise instrumentation of select.
+ // Some bits of the result do not depend on select condition, and must stay
+ // initialized even if select condition is not. These are the bits that are
+ // equal and initialized in both left and right select arguments.
+ U4 x = 0xFFFFABCDU;
+ U4 x_s = 0xFFFF0000U;
+ __msan_partial_poison(&x, &x_s, sizeof(x));
+ U4 y = 0xAB00U;
+ U1 cond = true;
+ __msan_poison(&cond, sizeof(cond));
+ U4 z = cond ? x : y;
+ __msan_print_shadow(&z, sizeof(z));
+ EXPECT_POISONED(z & 0xFFU);
+ EXPECT_NOT_POISONED(z & 0xFF00U);
+ EXPECT_POISONED(z & 0xFF0000U);
+ EXPECT_POISONED(z & 0xFF000000U);
+ EXPECT_EQ(0xAB00U, z & 0xFF00U);
+}
+
TEST(MemorySanitizerStress, DISABLED_MallocStackTrace) {
RecursiveMalloc(22);
}
@@ -3520,7 +4066,7 @@ TEST(MemorySanitizerStress, DISABLED_MallocStackTrace) {
TEST(MemorySanitizerAllocator, get_estimated_allocated_size) {
size_t sizes[] = {0, 20, 5000, 1<<20};
for (size_t i = 0; i < sizeof(sizes) / sizeof(*sizes); ++i) {
- size_t alloc_size = __msan_get_estimated_allocated_size(sizes[i]);
+ size_t alloc_size = __sanitizer_get_estimated_allocated_size(sizes[i]);
EXPECT_EQ(alloc_size, sizes[i]);
}
}
@@ -3529,26 +4075,26 @@ TEST(MemorySanitizerAllocator, get_allocated_size_and_ownership) {
char *array = reinterpret_cast<char*>(malloc(100));
int *int_ptr = new int;
- EXPECT_TRUE(__msan_get_ownership(array));
- EXPECT_EQ(100, __msan_get_allocated_size(array));
+ EXPECT_TRUE(__sanitizer_get_ownership(array));
+ EXPECT_EQ(100U, __sanitizer_get_allocated_size(array));
- EXPECT_TRUE(__msan_get_ownership(int_ptr));
- EXPECT_EQ(sizeof(*int_ptr), __msan_get_allocated_size(int_ptr));
+ EXPECT_TRUE(__sanitizer_get_ownership(int_ptr));
+ EXPECT_EQ(sizeof(*int_ptr), __sanitizer_get_allocated_size(int_ptr));
void *wild_addr = reinterpret_cast<void*>(0x1);
- EXPECT_FALSE(__msan_get_ownership(wild_addr));
- EXPECT_EQ(0, __msan_get_allocated_size(wild_addr));
+ EXPECT_FALSE(__sanitizer_get_ownership(wild_addr));
+ EXPECT_EQ(0U, __sanitizer_get_allocated_size(wild_addr));
- EXPECT_FALSE(__msan_get_ownership(array + 50));
- EXPECT_EQ(0, __msan_get_allocated_size(array + 50));
+ EXPECT_FALSE(__sanitizer_get_ownership(array + 50));
+ EXPECT_EQ(0U, __sanitizer_get_allocated_size(array + 50));
+
+ // NULL is a valid argument for GetAllocatedSize but is not owned.
+ EXPECT_FALSE(__sanitizer_get_ownership(NULL));
+ EXPECT_EQ(0U, __sanitizer_get_allocated_size(NULL));
- // NULL is a valid argument for GetAllocatedSize but is not owned.
- EXPECT_FALSE(__msan_get_ownership(NULL));
- EXPECT_EQ(0, __msan_get_allocated_size(NULL));
-
free(array);
- EXPECT_FALSE(__msan_get_ownership(array));
- EXPECT_EQ(0, __msan_get_allocated_size(array));
+ EXPECT_FALSE(__sanitizer_get_ownership(array));
+ EXPECT_EQ(0U, __sanitizer_get_allocated_size(array));
delete int_ptr;
}
@@ -3559,3 +4105,39 @@ TEST(MemorySanitizer, MlockTest) {
EXPECT_EQ(0, munlockall());
EXPECT_EQ(0, munlock((void*)0x987, 0x654));
}
+
+// Test that LargeAllocator unpoisons memory before releasing it to the OS.
+TEST(MemorySanitizer, LargeAllocatorUnpoisonsOnFree) {
+ void *p = malloc(1024 * 1024);
+ free(p);
+
+ typedef void *(*mmap_fn)(void *, size_t, int, int, int, off_t);
+ mmap_fn real_mmap = (mmap_fn)dlsym(RTLD_NEXT, "mmap");
+
+ // Allocate the page that was released to the OS in free() with the real mmap,
+ // bypassing the interceptor.
+ char *q = (char *)real_mmap(p, 4096, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
+ ASSERT_NE((char *)0, q);
+
+ ASSERT_TRUE(q <= p);
+ ASSERT_TRUE(q + 4096 > p);
+
+ EXPECT_NOT_POISONED(q[0]);
+ EXPECT_NOT_POISONED(q[10]);
+ EXPECT_NOT_POISONED(q[100]);
+
+ munmap(q, 4096);
+}
+
+#if SANITIZER_TEST_HAS_MALLOC_USABLE_SIZE
+TEST(MemorySanitizer, MallocUsableSizeTest) {
+ const size_t kArraySize = 100;
+ char *array = Ident((char*)malloc(kArraySize));
+ int *int_ptr = Ident(new int);
+ EXPECT_EQ(0U, malloc_usable_size(NULL));
+ EXPECT_EQ(kArraySize, malloc_usable_size(array));
+ EXPECT_EQ(sizeof(int), malloc_usable_size(int_ptr));
+ free(array);
+ delete int_ptr;
+}
+#endif // SANITIZER_TEST_HAS_MALLOC_USABLE_SIZE
diff --git a/lib/msan/tests/msandr_test_so.cc b/lib/msan/tests/msandr_test_so.cc
deleted file mode 100644
index eb605d4dba12..000000000000
--- a/lib/msan/tests/msandr_test_so.cc
+++ /dev/null
@@ -1,38 +0,0 @@
-//===-- msandr_test_so.cc ------------------------------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file is a part of MemorySanitizer.
-//
-// MemorySanitizer unit tests.
-//===----------------------------------------------------------------------===//
-
-#include "msandr_test_so.h"
-
-void dso_memfill(char* s, unsigned n) {
- for (unsigned i = 0; i < n; ++i)
- s[i] = i;
-}
-
-int dso_callfn(int (*fn)(void)) {
- volatile int x = fn();
- return x;
-}
-
-int dso_callfn1(int (*fn)(long long, long long, long long)) { //NOLINT
- volatile int x = fn(1, 2, 3);
- return x;
-}
-
-int dso_stack_store(void (*fn)(int*, int*), int x) {
- int y = x + 1;
- fn(&x, &y);
- return y;
-}
-
-void break_optimization(void *x) {}
diff --git a/lib/msan/tests/msandr_test_so.h b/lib/msan/tests/msandr_test_so.h
deleted file mode 100644
index cd75ff34f387..000000000000
--- a/lib/msan/tests/msandr_test_so.h
+++ /dev/null
@@ -1,24 +0,0 @@
-//===-- msandr_test_so.h ----------------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file is a part of MemorySanitizer.
-//
-// MemorySanitizer unit tests.
-//===----------------------------------------------------------------------===//
-
-#ifndef MSANDR_MSANDR_TEST_SO_H
-#define MSANDR_MSANDR_TEST_SO_H
-
-void dso_memfill(char* s, unsigned n);
-int dso_callfn(int (*fn)(void));
-int dso_callfn1(int (*fn)(long long, long long, long long)); //NOLINT
-int dso_stack_store(void (*fn)(int*, int*), int x);
-void break_optimization(void *x);
-
-#endif
diff --git a/lib/msandr/CMakeLists.txt b/lib/msandr/CMakeLists.txt
deleted file mode 100644
index 5a96a9dcc9e9..000000000000
--- a/lib/msandr/CMakeLists.txt
+++ /dev/null
@@ -1,26 +0,0 @@
-
-if(DynamoRIO_DIR AND DrMemoryFramework_DIR)
- set(CMAKE_COMPILER_IS_GNUCC 1)
- find_package(DynamoRIO)
- find_package(DrMemoryFramework)
-
- set(arch "x86_64")
- add_library(clang_rt.msandr-${arch} SHARED msandr.cc)
- configure_DynamoRIO_client(clang_rt.msandr-${arch})
-
- function(append_target_cflags tgt cflags)
- get_property(old_cflags TARGET clang_rt.msandr-${arch} PROPERTY COMPILE_FLAGS)
- set_property(TARGET clang_rt.msandr-${arch} PROPERTY COMPILE_FLAGS "${old_cflags} ${cflags}")
- endfunction(append_target_cflags)
-
- append_target_cflags(clang_rt.msandr-${arch} "-Wno-c++11-extensions")
-
- use_DynamoRIO_extension(clang_rt.msandr-${arch} drutil)
- use_DynamoRIO_extension(clang_rt.msandr-${arch} drmgr)
- use_DynamoRIO_extension(clang_rt.msandr-${arch} drsyscall)
-
- set_target_properties(clang_rt.msandr-${arch} PROPERTIES
- LIBRARY_OUTPUT_DIRECTORY ${COMPILER_RT_LIBRARY_OUTPUT_DIR})
- install(TARGETS clang_rt.msandr-${arch}
- LIBRARY DESTINATION ${COMPILER_RT_LIBRARY_INSTALL_DIR})
-endif()
diff --git a/lib/msandr/README.txt b/lib/msandr/README.txt
deleted file mode 100644
index 81a87c694083..000000000000
--- a/lib/msandr/README.txt
+++ /dev/null
@@ -1,40 +0,0 @@
-Experimental DynamoRIO-MSAN plugin (codename "MSanDR").
-Supports Linux/x86_64 only.
-
-Building:
- 1. First, download and build DynamoRIO:
- (svn co https://dynamorio.googlecode.com/svn/trunk dr && \
- cd dr && mkdir build && cd build && \
- cmake -DDR_EXT_DRMGR_STATIC=ON -DDR_EXT_DRSYMS_STATIC=ON \
- -DDR_EXT_DRUTIL_STATIC=ON -DDR_EXT_DRWRAP_STATIC=ON \
- -DDR_EXT_DRX_STATIC=ON .. && \
- make -j10 && make install)
-
- 2. Download and build DrMemory (for DrSyscall extension)
- (svn co http://drmemory.googlecode.com/svn/trunk/ drmemory && \
- cd drmemory && mkdir build && cd build && \
- cmake -DDynamoRIO_DIR=`pwd`/../../dr/exports/cmake .. && \
- make -j10 && make install)
-
- NOTE: The line above will build a shared DrSyscall library in a non-standard
- location. This will require the use of LD_LIBRARY_PATH when running MSanDR.
- To build a static DrSyscall library (and link it into MSanDR), add
- -DDR_EXT_DRSYSCALL_STATIC=ON to the CMake invocation above, but
- beware: DrSyscall is LGPL.
-
- 3. Now, build LLVM with two extra CMake flags:
- -DDynamoRIO_DIR=<path_to_dynamorio>/exports/cmake
- -DDrMemoryFramework_DIR=<path_to_drmemory>/exports64/drmf
-
- This will build a lib/clang/$VERSION/lib/linux/libclang_rt.msandr-x86_64.so
-
-Running:
- <path_to_dynamorio>/exports/bin64/drrun -c lib/clang/$VERSION/lib/linux/libclang_rt.msandr-x86_64.so -- test_binary
-
-MSan unit tests contain several tests for MSanDR (use MemorySanitizerDr.* gtest filter).
-
-Debugging:
- Add -DCMAKE_BUILD_TYPE=Debug to the first and/or second cmake invocation(s).
- Add -debug -v to drrun invocation line (right before -c).
- Add -checklevel 1 to drrun (as the first argument) to make debug DR faster.
-
diff --git a/lib/msandr/msandr.cc b/lib/msandr/msandr.cc
deleted file mode 100644
index 6c9d7c675aca..000000000000
--- a/lib/msandr/msandr.cc
+++ /dev/null
@@ -1,871 +0,0 @@
-//===-- msandr.cc ---------------------------------------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file is a part of MemorySanitizer.
-//
-// DynamoRio client for MemorySanitizer.
-//
-// MemorySanitizer requires that all program code is instrumented. Any memory
-// store that can turn an uninitialized value into an initialized value must be
-// observed by the tool, otherwise we risk reporting a false UMR.
-//
-// This also includes any libraries that the program depends on.
-//
-// In the case when rebuilding all program dependencies with MemorySanitizer is
-// problematic, an experimental MSanDR tool (the code you are currently looking
-// at) can be used. It is a DynamoRio-based tool that uses dynamic
-// instrumentation to
-// * Unpoison all memory stores.
-// * Unpoison TLS slots used by MemorySanitizer to pass function arguments and
-// return value shadow on anything that looks like a function call or a return
-// from a function.
-//
-// This tool does not detect the use of uninitialized values in uninstrumented
-// libraries. It merely gets rid of false positives by marking all data that
-// passes through uninstrumented code as fully initialized.
-//===----------------------------------------------------------------------===//
-
-#include <dr_api.h>
-#include <drutil.h>
-#include <drmgr.h>
-#include <drsyscall.h>
-
-#include <sys/mman.h>
-#include <sys/syscall.h> /* for SYS_mmap */
-
-#include <algorithm>
-#include <string>
-#include <set>
-#include <vector>
-#include <string.h>
-
-#define TESTALL(mask, var) (((mask) & (var)) == (mask))
-#define TESTANY(mask, var) (((mask) & (var)) != 0)
-
-#define CHECK_IMPL(condition, file, line) \
- do { \
- if (!(condition)) { \
- dr_printf("Check failed: `%s`\nat %s:%d\n", #condition, file, line); \
- dr_abort(); \
- } \
- } while (0) // TODO: stacktrace
-
-#define CHECK(condition) CHECK_IMPL(condition, __FILE__, __LINE__)
-
-#define VERBOSITY 0
-
-// XXX: it seems setting macro in CMakeLists.txt does not work,
-// so manually set it here now.
-
-// Building msandr client for running in DynamoRIO hybrid mode,
-// which allows some module running natively.
-// TODO: turn it on by default when hybrid is stable enough
-// #define MSANDR_NATIVE_EXEC
-
-// Building msandr client for standalone test that does not need to
-// run with msan build executables. Disable by default.
-// #define MSANDR_STANDALONE_TEST
-
-#define NUM_TLS_RETVAL 1
-#define NUM_TLS_PARAM 6
-
-#ifdef MSANDR_STANDALONE_TEST
-// For testing purpose, we map app to shadow memory at [0x100000, 0x20000).
-// Normally, the app starts at 0x400000:
-// 00400000-004e0000 r-xp 00000000 fc:00 524343 /bin/bash
-// so there should be no problem.
-# define SHADOW_MEMORY_BASE ((void *)0x100000)
-# define SHADOW_MEMORY_SIZE (0x100000)
-# define SHADOW_MEMORY_MASK (SHADOW_MEMORY_SIZE - 4 /* to avoid overflow */)
-#else
-// shadow memory range [0x200000000000, 0x400000000000)
-// assuming no app memory below 0x200000000000
-# define SHADOW_MEMORY_MASK 0x3fffffffffffULL
-#endif /* MSANDR_STANDALONE_TEST */
-
-namespace {
-
-std::string g_app_path;
-
-int msan_retval_tls_offset;
-int msan_param_tls_offset;
-
-#ifndef MSANDR_NATIVE_EXEC
-class ModuleData {
-public:
- ModuleData();
- ModuleData(const module_data_t *info);
- // Yes, we want default copy, assign, and dtor semantics.
-
-public:
- app_pc start_;
- app_pc end_;
- // Full path to the module.
- std::string path_;
- module_handle_t handle_;
- bool should_instrument_;
- bool executed_;
-};
-
-// A vector of loaded modules sorted by module bounds. We lookup the current PC
-// in here from the bb event. This is better than an rb tree because the lookup
-// is faster and the bb event occurs far more than the module load event.
-std::vector<ModuleData> g_module_list;
-
-ModuleData::ModuleData()
- : start_(NULL), end_(NULL), path_(""), handle_(NULL),
- should_instrument_(false), executed_(false) {
-}
-
-ModuleData::ModuleData(const module_data_t *info)
- : start_(info->start), end_(info->end), path_(info->full_path),
- handle_(info->handle),
- // We'll check the black/white lists later and adjust this.
- should_instrument_(true), executed_(false) {
-}
-#endif /* !MSANDR_NATIVE_EXEC */
-
-int(*__msan_get_retval_tls_offset)();
-int(*__msan_get_param_tls_offset)();
-void (*__msan_unpoison)(void *base, size_t size);
-bool (*__msan_is_in_loader)();
-
-#ifdef MSANDR_STANDALONE_TEST
-uint mock_msan_retval_tls_offset;
-uint mock_msan_param_tls_offset;
-static int mock_msan_get_retval_tls_offset() {
- return (int)mock_msan_retval_tls_offset;
-}
-
-static int mock_msan_get_param_tls_offset() {
- return (int)mock_msan_param_tls_offset;
-}
-
-static void mock_msan_unpoison(void *base, size_t size) {
- /* do nothing */
-}
-
-static bool mock_msan_is_in_loader() {
- return false;
-}
-#endif /* MSANDR_STANDALONE_TEST */
-
-static generic_func_t LookupCallback(module_data_t *app, const char *name) {
-#ifdef MSANDR_STANDALONE_TEST
- if (strcmp("__msan_get_retval_tls_offset", name) == 0) {
- return (generic_func_t)mock_msan_get_retval_tls_offset;
- } else if (strcmp("__msan_get_param_tls_offset", name) == 0) {
- return (generic_func_t)mock_msan_get_param_tls_offset;
- } else if (strcmp("__msan_unpoison", name) == 0) {
- return (generic_func_t)mock_msan_unpoison;
- } else if (strcmp("__msan_is_in_loader", name) == 0) {
- return (generic_func_t)mock_msan_is_in_loader;
- }
- CHECK(false);
- return NULL;
-#else /* !MSANDR_STANDALONE_TEST */
- generic_func_t callback = dr_get_proc_address(app->handle, name);
- if (callback == NULL) {
- dr_printf("Couldn't find `%s` in %s\n", name, app->full_path);
- CHECK(callback);
- }
- return callback;
-#endif /* !MSANDR_STANDALONE_TEST */
-}
-
-void InitializeMSanCallbacks() {
- module_data_t *app = dr_lookup_module_by_name(dr_get_application_name());
- if (!app) {
- dr_printf("%s - oops, dr_lookup_module_by_name failed!\n",
- dr_get_application_name());
- CHECK(app);
- }
- g_app_path = app->full_path;
-
- __msan_get_retval_tls_offset = (int (*)())
- LookupCallback(app, "__msan_get_retval_tls_offset");
- __msan_get_param_tls_offset = (int (*)())
- LookupCallback(app, "__msan_get_param_tls_offset");
- __msan_unpoison = (void(*)(void *, size_t))
- LookupCallback(app, "__msan_unpoison");
- __msan_is_in_loader = (bool (*)())
- LookupCallback(app, "__msan_is_in_loader");
-
- dr_free_module_data(app);
-}
-
-// FIXME: Handle absolute addresses and PC-relative addresses.
-// FIXME: Handle TLS accesses via FS or GS. DR assumes all other segments have
-// a zero base anyway.
-bool OperandIsInteresting(opnd_t opnd) {
- return (opnd_is_base_disp(opnd) && opnd_get_segment(opnd) != DR_SEG_FS &&
- opnd_get_segment(opnd) != DR_SEG_GS);
-}
-
-bool WantToInstrument(instr_t *instr) {
- // TODO: skip push instructions?
- switch (instr_get_opcode(instr)) {
- // FIXME: support the instructions excluded below:
- case OP_rep_cmps:
- // f3 a6 rep cmps %ds:(%rsi) %es:(%rdi) %rsi %rdi %rcx -> %rsi %rdi %rcx
- return false;
- }
-
- // Labels appear due to drutil_expand_rep_string()
- if (instr_is_label(instr))
- return false;
-
- CHECK(instr_ok_to_mangle(instr) == true);
-
- if (instr_writes_memory(instr)) {
- for (int d = 0; d < instr_num_dsts(instr); d++) {
- opnd_t op = instr_get_dst(instr, d);
- if (OperandIsInteresting(op))
- return true;
- }
- }
-
- return false;
-}
-
-#define PRE(at, what) instrlist_meta_preinsert(bb, at, INSTR_CREATE_##what);
-#define PREF(at, what) instrlist_meta_preinsert(bb, at, what);
-
-void InstrumentMops(void *drcontext, instrlist_t *bb, instr_t *instr, opnd_t op,
- bool is_write) {
- bool need_to_restore_eflags = false;
- uint flags = instr_get_arith_flags(instr);
- // TODO: do something smarter with flags and spills in general?
- // For example, spill them only once for a sequence of instrumented
- // instructions that don't change/read flags.
-
- if (!TESTALL(EFLAGS_WRITE_6, flags) || TESTANY(EFLAGS_READ_6, flags)) {
- if (VERBOSITY > 1)
- dr_printf("Spilling eflags...\n");
- need_to_restore_eflags = true;
- // TODO: Maybe sometimes don't need to 'seto'.
- // TODO: Maybe sometimes don't want to spill XAX here?
- // TODO: No need to spill XAX here if XAX is not used in the BB.
- dr_save_reg(drcontext, bb, instr, DR_REG_XAX, SPILL_SLOT_1);
- dr_save_arith_flags_to_xax(drcontext, bb, instr);
- dr_save_reg(drcontext, bb, instr, DR_REG_XAX, SPILL_SLOT_3);
- dr_restore_reg(drcontext, bb, instr, DR_REG_XAX, SPILL_SLOT_1);
- }
-
-#if 0
- dr_printf("==DRMSAN== DEBUG: %d %d %d %d %d %d\n",
- opnd_is_memory_reference(op), opnd_is_base_disp(op),
- opnd_is_base_disp(op) ? opnd_get_index(op) : -1,
- opnd_is_far_memory_reference(op), opnd_is_reg_pointer_sized(op),
- opnd_is_base_disp(op) ? opnd_get_disp(op) : -1);
-#endif
-
- reg_id_t R1;
- bool address_in_R1 = false;
- if (opnd_is_base_disp(op) && opnd_get_index(op) == DR_REG_NULL &&
- opnd_get_disp(op) == 0) {
- // If this is a simple access with no offset or index, we can just use the
- // base for R1.
- address_in_R1 = true;
- R1 = opnd_get_base(op);
- } else {
- // Otherwise, we need to compute the addr into R1.
- // TODO: reuse some spare register? e.g. r15 on x64
- // TODO: might be used as a non-mem-ref register?
- R1 = DR_REG_XAX;
- }
- CHECK(reg_is_pointer_sized(R1)); // otherwise R2 may be wrong.
-
- // Pick R2 from R8 to R15.
- // It's OK if the instr uses R2 elsewhere, since we'll restore it before instr.
- reg_id_t R2;
- for (R2 = DR_REG_R8; R2 <= DR_REG_R15; R2++) {
- if (!opnd_uses_reg(op, R2))
- break;
- }
- CHECK((R2 <= DR_REG_R15) && R1 != R2);
-
- // Save the current values of R1 and R2.
- dr_save_reg(drcontext, bb, instr, R1, SPILL_SLOT_1);
- // TODO: Something smarter than spilling a "fixed" register R2?
- dr_save_reg(drcontext, bb, instr, R2, SPILL_SLOT_2);
-
- if (!address_in_R1)
- CHECK(drutil_insert_get_mem_addr(drcontext, bb, instr, op, R1, R2));
- PRE(instr, mov_imm(drcontext, opnd_create_reg(R2),
- OPND_CREATE_INT64(SHADOW_MEMORY_MASK)));
- PRE(instr, and(drcontext, opnd_create_reg(R1), opnd_create_reg(R2)));
-#ifdef MSANDR_STANDALONE_TEST
- PRE(instr, add(drcontext, opnd_create_reg(R1),
- OPND_CREATE_INT32(SHADOW_MEMORY_BASE)));
-#endif
- // There is no mov_st of a 64-bit immediate, so...
- opnd_size_t op_size = opnd_get_size(op);
- CHECK(op_size != OPSZ_NA);
- uint access_size = opnd_size_in_bytes(op_size);
- if (access_size <= 4 || op_size == OPSZ_PTR /* x64 support sign extension */) {
- instr_t *label = INSTR_CREATE_label(drcontext);
- opnd_t immed;
- if (op_size == OPSZ_PTR || op_size == OPSZ_4)
- immed = OPND_CREATE_INT32(0);
- else
- immed = opnd_create_immed_int((ptr_int_t) 0, op_size);
- // we check if target is 0 before write to reduce unnecessary memory stores.
- PRE(instr, cmp(drcontext,
- opnd_create_base_disp(R1, DR_REG_NULL, 0, 0, op_size),
- immed));
- PRE(instr, jcc(drcontext, OP_je, opnd_create_instr(label)));
- PRE(instr, mov_st(drcontext,
- opnd_create_base_disp(R1, DR_REG_NULL, 0, 0, op_size),
- immed));
- PREF(instr, label);
- } else {
- // FIXME: tail?
- for (uint ofs = 0; ofs < access_size; ofs += 4) {
- instr_t *label = INSTR_CREATE_label(drcontext);
- opnd_t immed = OPND_CREATE_INT32(0);
- PRE(instr, cmp(drcontext, OPND_CREATE_MEM32(R1, ofs), immed));
- PRE(instr, jcc(drcontext, OP_je, opnd_create_instr(label)));
- PRE(instr, mov_st(drcontext, OPND_CREATE_MEM32(R1, ofs), immed));
- PREF(instr, label)
- }
- }
-
- // Restore the registers and flags.
- dr_restore_reg(drcontext, bb, instr, R1, SPILL_SLOT_1);
- dr_restore_reg(drcontext, bb, instr, R2, SPILL_SLOT_2);
-
- // TODO: move aflags save/restore to per instr instead of per opnd
- if (need_to_restore_eflags) {
- if (VERBOSITY > 1)
- dr_printf("Restoring eflags\n");
- // TODO: Check if it's reverse to the dr_restore_reg above and optimize.
- dr_save_reg(drcontext, bb, instr, DR_REG_XAX, SPILL_SLOT_1);
- dr_restore_reg(drcontext, bb, instr, DR_REG_XAX, SPILL_SLOT_3);
- dr_restore_arith_flags_from_xax(drcontext, bb, instr);
- dr_restore_reg(drcontext, bb, instr, DR_REG_XAX, SPILL_SLOT_1);
- }
-
- // The original instruction is left untouched. The above instrumentation is just
- // a prefix.
-}
-
-void InstrumentReturn(void *drcontext, instrlist_t *bb, instr_t *instr) {
-#ifdef MSANDR_STANDALONE_TEST
- PRE(instr,
- mov_st(drcontext,
- opnd_create_far_base_disp(DR_SEG_GS /* DR's TLS */,
- DR_REG_NULL, DR_REG_NULL,
- 0, msan_retval_tls_offset,
- OPSZ_PTR),
- OPND_CREATE_INT32(0)));
-#else /* !MSANDR_STANDALONE_TEST */
- /* XXX: the code below only works if -mangle_app_seg and -private_loader,
- * which is turned of for optimized native exec
- */
- dr_save_reg(drcontext, bb, instr, DR_REG_XAX, SPILL_SLOT_1);
-
- // Clobbers nothing except xax.
- bool res =
- dr_insert_get_seg_base(drcontext, bb, instr, DR_SEG_FS, DR_REG_XAX);
- CHECK(res);
-
- // TODO: unpoison more bytes?
- PRE(instr,
- mov_st(drcontext, OPND_CREATE_MEM64(DR_REG_XAX, msan_retval_tls_offset),
- OPND_CREATE_INT32(0)));
-
- dr_restore_reg(drcontext, bb, instr, DR_REG_XAX, SPILL_SLOT_1);
-
- // The original instruction is left untouched. The above instrumentation is just
- // a prefix.
-#endif /* !MSANDR_STANDALONE_TEST */
-}
-
-void InstrumentIndirectBranch(void *drcontext, instrlist_t *bb,
- instr_t *instr) {
-#ifdef MSANDR_STANDALONE_TEST
- for (int i = 0; i < NUM_TLS_PARAM; ++i) {
- PRE(instr,
- mov_st(drcontext,
- opnd_create_far_base_disp(DR_SEG_GS /* DR's TLS */,
- DR_REG_NULL, DR_REG_NULL,
- 0,
- msan_param_tls_offset +
- i * sizeof(void *),
- OPSZ_PTR),
- OPND_CREATE_INT32(0)));
- }
-#else /* !MSANDR_STANDALONE_TEST */
- /* XXX: the code below only works if -mangle_app_seg and -private_loader,
- * which is turned off for optimized native exec
- */
- dr_save_reg(drcontext, bb, instr, DR_REG_XAX, SPILL_SLOT_1);
-
- // Clobbers nothing except xax.
- bool res =
- dr_insert_get_seg_base(drcontext, bb, instr, DR_SEG_FS, DR_REG_XAX);
- CHECK(res);
-
- // TODO: unpoison more bytes?
- for (int i = 0; i < NUM_TLS_PARAM; ++i) {
- PRE(instr,
- mov_st(drcontext, OPND_CREATE_MEMPTR(DR_REG_XAX, msan_param_tls_offset +
- i * sizeof(void *)),
- OPND_CREATE_INT32(0)));
- }
-
- dr_restore_reg(drcontext, bb, instr, DR_REG_XAX, SPILL_SLOT_1);
-
- // The original instruction is left untouched. The above instrumentation is just
- // a prefix.
-#endif /* !MSANDR_STANDALONE_TEST */
-}
-
-#ifndef MSANDR_NATIVE_EXEC
-// For use with binary search. Modules shouldn't overlap, so we shouldn't have
-// to look at end_. If that can happen, we won't support such an application.
-bool ModuleDataCompareStart(const ModuleData &left, const ModuleData &right) {
- return left.start_ < right.start_;
-}
-
-// Look up the module containing PC. Should be relatively fast, as its called
-// for each bb instrumentation.
-ModuleData *LookupModuleByPC(app_pc pc) {
- ModuleData fake_mod_data;
- fake_mod_data.start_ = pc;
- std::vector<ModuleData>::iterator it =
- lower_bound(g_module_list.begin(), g_module_list.end(), fake_mod_data,
- ModuleDataCompareStart);
- // if (it == g_module_list.end())
- // return NULL;
- if (it == g_module_list.end() || pc < it->start_)
- --it;
- CHECK(it->start_ <= pc);
- if (pc >= it->end_) {
- // We're past the end of this module. We shouldn't be in the next module,
- // or lower_bound lied to us.
- ++it;
- CHECK(it == g_module_list.end() || pc < it->start_);
- return NULL;
- }
-
- // OK, we found the module.
- return &*it;
-}
-
-bool ShouldInstrumentNonModuleCode() { return true; }
-
-bool ShouldInstrumentModule(ModuleData *mod_data) {
- // TODO(rnk): Flags for blacklist would get wired in here.
- generic_func_t p =
- dr_get_proc_address(mod_data->handle_, "__msan_track_origins");
- return !p;
-}
-
-bool ShouldInstrumentPc(app_pc pc, ModuleData **pmod_data) {
- ModuleData *mod_data = LookupModuleByPC(pc);
- if (pmod_data)
- *pmod_data = mod_data;
- if (mod_data != NULL) {
- // This module is on a blacklist.
- if (!mod_data->should_instrument_) {
- return false;
- }
- } else if (!ShouldInstrumentNonModuleCode()) {
- return false;
- }
- return true;
-}
-#endif /* !MSANDR_NATIVE_CLIENT */
-
-// TODO(rnk): Make sure we instrument after __msan_init.
-dr_emit_flags_t
-event_basic_block_app2app(void *drcontext, void *tag, instrlist_t *bb,
- bool for_trace, bool translating) {
-#ifndef MSANDR_NATIVE_EXEC
- app_pc pc = dr_fragment_app_pc(tag);
- if (ShouldInstrumentPc(pc, NULL))
- CHECK(drutil_expand_rep_string(drcontext, bb));
-#else /* MSANDR_NATIVE_EXEC */
- CHECK(drutil_expand_rep_string(drcontext, bb));
-#endif /* MSANDR_NATIVE_EXEC */
- return DR_EMIT_PERSISTABLE;
-}
-
-dr_emit_flags_t event_basic_block(void *drcontext, void *tag, instrlist_t *bb,
- bool for_trace, bool translating) {
- app_pc pc = dr_fragment_app_pc(tag);
-#ifndef MSANDR_NATIVE_EXEC
- ModuleData *mod_data;
-
- if (!ShouldInstrumentPc(pc, &mod_data))
- return DR_EMIT_PERSISTABLE;
-
- if (VERBOSITY > 1)
- dr_printf("============================================================\n");
- if (VERBOSITY > 0) {
- std::string mod_path = (mod_data ? mod_data->path_ : "<no module, JITed?>");
- if (mod_data && !mod_data->executed_) {
- mod_data->executed_ = true; // Nevermind this race.
- dr_printf("Executing from new module: %s\n", mod_path.c_str());
- }
- dr_printf("BB to be instrumented: %p [from %s]; translating = %s\n", pc,
- mod_path.c_str(), translating ? "true" : "false");
- if (mod_data) {
- // Match standard sanitizer trace format for free symbols.
- // #0 0x7f6e35cf2e45 (/blah/foo.so+0x11fe45)
- dr_printf(" #0 %p (%s+%p)\n", pc, mod_data->path_.c_str(),
- pc - mod_data->start_);
- }
- }
-#endif /* !MSANDR_NATIVE_EXEC */
-
- if (VERBOSITY > 1) {
- instrlist_disassemble(drcontext, pc, bb, STDOUT);
- instr_t *instr;
- for (instr = instrlist_first(bb); instr; instr = instr_get_next(instr)) {
- dr_printf("opcode: %d\n", instr_get_opcode(instr));
- }
- }
-
- for (instr_t *i = instrlist_first(bb); i != NULL; i = instr_get_next(i)) {
- int opcode = instr_get_opcode(i);
- if (opcode == OP_ret || opcode == OP_ret_far) {
- InstrumentReturn(drcontext, bb, i);
- continue;
- }
-
- // These instructions hopefully cover all cases where control is transferred
- // to a function in a different module (we only care about calls into
- // compiler-instrumented modules).
- // * call_ind is used for normal indirect calls.
- // * jmp_ind is used for indirect tail calls, and calls through PLT (PLT
- // stub includes a jump to an address from GOT).
- if (opcode == OP_call_ind || opcode == OP_call_far_ind ||
- opcode == OP_jmp_ind || opcode == OP_jmp_far_ind) {
- InstrumentIndirectBranch(drcontext, bb, i);
- continue;
- }
-
- if (!WantToInstrument(i))
- continue;
-
- if (VERBOSITY > 1) {
- app_pc orig_pc = dr_fragment_app_pc(tag);
- uint flags = instr_get_arith_flags(i);
- dr_printf("+%d -> to be instrumented! [opcode=%d, flags = 0x%08X]\n",
- instr_get_app_pc(i) - orig_pc, instr_get_opcode(i), flags);
- }
-
- if (instr_writes_memory(i)) {
- // Instrument memory writes
- // bool instrumented_anything = false;
- for (int d = 0; d < instr_num_dsts(i); d++) {
- opnd_t op = instr_get_dst(i, d);
- if (!OperandIsInteresting(op))
- continue;
-
- // CHECK(!instrumented_anything);
- // instrumented_anything = true;
- InstrumentMops(drcontext, bb, i, op, true);
- break; // only instrumenting the first dst
- }
- }
- }
-
-// TODO: optimize away redundant restore-spill pairs?
-
- if (VERBOSITY > 1) {
- pc = dr_fragment_app_pc(tag);
- dr_printf("\nFinished instrumenting dynamorio_basic_block(PC=" PFX ")\n", pc);
- instrlist_disassemble(drcontext, pc, bb, STDOUT);
- }
- return DR_EMIT_PERSISTABLE;
-}
-
-#ifndef MSANDR_NATIVE_EXEC
-void event_module_load(void *drcontext, const module_data_t *info,
- bool loaded) {
- // Insert the module into the list while maintaining the ordering.
- ModuleData mod_data(info);
- std::vector<ModuleData>::iterator it =
- upper_bound(g_module_list.begin(), g_module_list.end(), mod_data,
- ModuleDataCompareStart);
- it = g_module_list.insert(it, mod_data);
- // Check if we should instrument this module.
- it->should_instrument_ = ShouldInstrumentModule(&*it);
- dr_module_set_should_instrument(info->handle, it->should_instrument_);
-
- if (VERBOSITY > 0)
- dr_printf("==DRMSAN== Loaded module: %s [%p...%p], instrumentation is %s\n",
- info->full_path, info->start, info->end,
- it->should_instrument_ ? "on" : "off");
-}
-
-void event_module_unload(void *drcontext, const module_data_t *info) {
- if (VERBOSITY > 0)
- dr_printf("==DRMSAN== Unloaded module: %s [%p...%p]\n", info->full_path,
- info->start, info->end);
-
- // Remove the module from the list.
- ModuleData mod_data(info);
- std::vector<ModuleData>::iterator it =
- lower_bound(g_module_list.begin(), g_module_list.end(), mod_data,
- ModuleDataCompareStart);
- // It's a bug if we didn't actually find the module.
- CHECK(it != g_module_list.end() && it->start_ == mod_data.start_ &&
- it->end_ == mod_data.end_ && it->path_ == mod_data.path_);
- g_module_list.erase(it);
-}
-#endif /* !MSANDR_NATIVE_EXEC */
-
-void event_exit() {
- // Clean up so DR doesn't tell us we're leaking memory.
- drsys_exit();
- drutil_exit();
- drmgr_exit();
-
-#ifdef MSANDR_STANDALONE_TEST
- /* free tls */
- bool res;
- res = dr_raw_tls_cfree(msan_retval_tls_offset, NUM_TLS_RETVAL);
- CHECK(res);
- res = dr_raw_tls_cfree(msan_param_tls_offset, NUM_TLS_PARAM);
- CHECK(res);
- /* we do not bother to free the shadow memory */
-#endif /* !MSANDR_STANDALONE_TEST */
- if (VERBOSITY > 0)
- dr_printf("==DRMSAN== DONE\n");
-}
-
-bool event_filter_syscall(void *drcontext, int sysnum) {
- // FIXME: only intercept syscalls with memory effects.
- return true; /* intercept everything */
-}
-
-bool drsys_iter_memarg_cb(drsys_arg_t *arg, void *user_data) {
- CHECK(arg->valid);
-
- if (arg->pre)
- return true;
- if (!TESTANY(DRSYS_PARAM_OUT, arg->mode))
- return true;
-
- size_t sz = arg->size;
-
- if (sz > 0xFFFFFFFF) {
- drmf_status_t res;
- drsys_syscall_t *syscall = (drsys_syscall_t *)user_data;
- const char *name;
- res = drsys_syscall_name(syscall, &name);
- CHECK(res == DRMF_SUCCESS);
-
- dr_printf("SANITY: syscall '%s' arg %d writes %llu bytes memory?!"
- " Clipping to %llu.\n",
- name, arg->ordinal, (unsigned long long) sz,
- (unsigned long long)(sz & 0xFFFFFFFF));
- }
-
- if (VERBOSITY > 0) {
- drmf_status_t res;
- drsys_syscall_t *syscall = (drsys_syscall_t *)user_data;
- const char *name;
- res = drsys_syscall_name(syscall, &name);
- CHECK(res == DRMF_SUCCESS);
- dr_printf("drsyscall: syscall '%s' arg %d wrote range [%p, %p)\n",
- name, arg->ordinal, arg->start_addr,
- (char *)arg->start_addr + sz);
- }
-
- // We don't switch to the app context because __msan_unpoison() doesn't need
- // TLS segments.
- __msan_unpoison(arg->start_addr, sz);
-
- return true; /* keep going */
-}
-
-bool event_pre_syscall(void *drcontext, int sysnum) {
- drsys_syscall_t *syscall;
- drsys_sysnum_t sysnum_full;
- bool known;
- drsys_param_type_t ret_type;
- drmf_status_t res;
- const char *name;
-
- res = drsys_cur_syscall(drcontext, &syscall);
- CHECK(res == DRMF_SUCCESS);
-
- res = drsys_syscall_number(syscall, &sysnum_full);
- CHECK(res == DRMF_SUCCESS);
- CHECK(sysnum == sysnum_full.number);
-
- res = drsys_syscall_is_known(syscall, &known);
- CHECK(res == DRMF_SUCCESS);
-
- res = drsys_syscall_name(syscall, &name);
- CHECK(res == DRMF_SUCCESS);
-
- res = drsys_syscall_return_type(syscall, &ret_type);
- CHECK(res == DRMF_SUCCESS);
- CHECK(ret_type != DRSYS_TYPE_INVALID);
- CHECK(!known || ret_type != DRSYS_TYPE_UNKNOWN);
-
- res = drsys_iterate_memargs(drcontext, drsys_iter_memarg_cb, NULL);
- CHECK(res == DRMF_SUCCESS);
-
- return true;
-}
-
-static bool IsInLoader(void *drcontext) {
- // TODO: This segment swap is inefficient. DR should just let us query the
- // app segment base, which it has. Alternatively, if we disable
- // -mangle_app_seg, then we won't need the swap.
- bool need_swap = !dr_using_app_state(drcontext);
- if (need_swap)
- dr_switch_to_app_state(drcontext);
- bool is_in_loader = __msan_is_in_loader();
- if (need_swap)
- dr_switch_to_dr_state(drcontext);
- return is_in_loader;
-}
-
-void event_post_syscall(void *drcontext, int sysnum) {
- drsys_syscall_t *syscall;
- drsys_sysnum_t sysnum_full;
- bool success = false;
- drmf_status_t res;
-
- res = drsys_cur_syscall(drcontext, &syscall);
- CHECK(res == DRMF_SUCCESS);
-
- res = drsys_syscall_number(syscall, &sysnum_full);
- CHECK(res == DRMF_SUCCESS);
- CHECK(sysnum == sysnum_full.number);
-
- res = drsys_syscall_succeeded(syscall, dr_syscall_get_result(drcontext),
- &success);
- CHECK(res == DRMF_SUCCESS);
-
- if (success) {
- res =
- drsys_iterate_memargs(drcontext, drsys_iter_memarg_cb, (void *)syscall);
- CHECK(res == DRMF_SUCCESS);
- }
-
- // Our normal mmap interceptor can't intercept calls from the loader itself.
- // This means we don't clear the shadow for calls to dlopen. For now, we
- // solve this by intercepting mmap from ld.so here, but ideally we'd have a
- // solution that doesn't rely on msandr.
- //
- // Be careful not to intercept maps done by the msan rtl. Otherwise we end up
- // unpoisoning vast regions of memory and OOMing.
- // TODO: __msan_unpoison() could "flush" large regions of memory like tsan
- // does instead of doing a large memset. However, we need the memory to be
- // zeroed, where as tsan does not, so plain madvise is not enough.
- if (success && (sysnum == SYS_mmap IF_NOT_X64(|| sysnum == SYS_mmap2))) {
- if (IsInLoader(drcontext)) {
- app_pc base = (app_pc)dr_syscall_get_result(drcontext);
- ptr_uint_t size;
- drmf_status_t res = drsys_pre_syscall_arg(drcontext, 1, &size);
- CHECK(res == DRMF_SUCCESS);
- if (VERBOSITY > 0)
- dr_printf("unpoisoning for dlopen: [%p-%p]\n", base, base + size);
- // We don't switch to the app context because __msan_unpoison() doesn't
- // need TLS segments.
- __msan_unpoison(base, size);
- }
- }
-}
-
-} // namespace
-
-DR_EXPORT void dr_init(client_id_t id) {
- drmf_status_t res;
-
- drmgr_init();
- drutil_init();
-
- std::string app_name = dr_get_application_name();
- // This blacklist will still run these apps through DR's code cache. On the
- // other hand, we are able to follow children of these apps.
- // FIXME: Once DR has detach, we could just detach here. Alternatively,
- // if DR had a fork or exec hook to let us decide there, that would be nice.
- // FIXME: make the blacklist cmd-adjustable.
- if (app_name == "python" || app_name == "python2.7" || app_name == "bash" ||
- app_name == "sh" || app_name == "true" || app_name == "exit" ||
- app_name == "yes" || app_name == "echo")
- return;
-
- drsys_options_t ops;
- memset(&ops, 0, sizeof(ops));
- ops.struct_size = sizeof(ops);
- ops.analyze_unknown_syscalls = false;
-
- res = drsys_init(id, &ops);
- CHECK(res == DRMF_SUCCESS);
-
- dr_register_filter_syscall_event(event_filter_syscall);
- drmgr_register_pre_syscall_event(event_pre_syscall);
- drmgr_register_post_syscall_event(event_post_syscall);
- res = drsys_filter_all_syscalls();
- CHECK(res == DRMF_SUCCESS);
-
-#ifdef MSANDR_STANDALONE_TEST
- reg_id_t reg_seg;
- /* alloc tls */
- if (!dr_raw_tls_calloc(&reg_seg, &mock_msan_retval_tls_offset, NUM_TLS_RETVAL, 0))
- CHECK(false);
- CHECK(reg_seg == DR_SEG_GS /* x64 only! */);
- if (!dr_raw_tls_calloc(&reg_seg, &mock_msan_param_tls_offset, NUM_TLS_PARAM, 0))
- CHECK(false);
- CHECK(reg_seg == DR_SEG_GS /* x64 only! */);
- /* alloc shadow memory */
- if (mmap(SHADOW_MEMORY_BASE, SHADOW_MEMORY_SIZE, PROT_READ|PROT_WRITE,
- MAP_PRIVATE | MAP_ANON, -1, 0) != SHADOW_MEMORY_BASE) {
- CHECK(false);
- }
-#endif /* MSANDR_STANDALONE_TEST */
- InitializeMSanCallbacks();
-
- // FIXME: the shadow is initialized earlier when DR calls one of our wrapper
- // functions. This may change one day.
- // TODO: make this more robust.
-
- void *drcontext = dr_get_current_drcontext();
-
- dr_switch_to_app_state(drcontext);
- msan_retval_tls_offset = __msan_get_retval_tls_offset();
- msan_param_tls_offset = __msan_get_param_tls_offset();
- dr_switch_to_dr_state(drcontext);
- if (VERBOSITY > 0) {
- dr_printf("__msan_retval_tls offset: %d\n", msan_retval_tls_offset);
- dr_printf("__msan_param_tls offset: %d\n", msan_param_tls_offset);
- }
-
- // Standard DR events.
- dr_register_exit_event(event_exit);
-
- drmgr_priority_t priority = {
- sizeof(priority), /* size of struct */
- "msandr", /* name of our operation */
- NULL, /* optional name of operation we should precede */
- NULL, /* optional name of operation we should follow */
- 0
- }; /* numeric priority */
-
- drmgr_register_bb_app2app_event(event_basic_block_app2app, &priority);
- drmgr_register_bb_instru2instru_event(event_basic_block, &priority);
-#ifndef MSANDR_NATIVE_EXEC
- drmgr_register_module_load_event(event_module_load);
- drmgr_register_module_unload_event(event_module_unload);
-#endif /* MSANDR_NATIVE_EXEC */
- if (VERBOSITY > 0)
- dr_printf("==MSANDR== Starting!\n");
-}
diff --git a/lib/muldc3.c b/lib/muldc3.c
deleted file mode 100644
index 5f4a6d16ebf0..000000000000
--- a/lib/muldc3.c
+++ /dev/null
@@ -1,73 +0,0 @@
-/* ===-- muldc3.c - Implement __muldc3 -------------------------------------===
- *
- * 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 __muldc3 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-#include "int_math.h"
-
-/* Returns: the product of a + ib and c + id */
-
-double _Complex
-__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))
- {
- int __recalc = 0;
- if (crt_isinf(__a) || crt_isinf(__b))
- {
- __a = crt_copysign(crt_isinf(__a) ? 1 : 0, __a);
- __b = crt_copysign(crt_isinf(__b) ? 1 : 0, __b);
- if (crt_isnan(__c))
- __c = crt_copysign(0, __c);
- if (crt_isnan(__d))
- __d = crt_copysign(0, __d);
- __recalc = 1;
- }
- if (crt_isinf(__c) || crt_isinf(__d))
- {
- __c = crt_copysign(crt_isinf(__c) ? 1 : 0, __c);
- __d = crt_copysign(crt_isinf(__d) ? 1 : 0, __d);
- if (crt_isnan(__a))
- __a = crt_copysign(0, __a);
- if (crt_isnan(__b))
- __b = crt_copysign(0, __b);
- __recalc = 1;
- }
- if (!__recalc && (crt_isinf(__ac) || crt_isinf(__bd) ||
- crt_isinf(__ad) || crt_isinf(__bc)))
- {
- if (crt_isnan(__a))
- __a = crt_copysign(0, __a);
- if (crt_isnan(__b))
- __b = crt_copysign(0, __b);
- if (crt_isnan(__c))
- __c = crt_copysign(0, __c);
- if (crt_isnan(__d))
- __d = crt_copysign(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/muldf3.c b/lib/muldf3.c
deleted file mode 100644
index c38edba90cf2..000000000000
--- a/lib/muldf3.c
+++ /dev/null
@@ -1,122 +0,0 @@
-//===-- lib/muldf3.c - Double-precision multiplication ------------*- 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 double-precision soft-float multiplication
-// with the IEEE-754 default rounding (to nearest, ties to even).
-//
-//===----------------------------------------------------------------------===//
-
-#define DOUBLE_PRECISION
-#include "fp_lib.h"
-
-ARM_EABI_FNALIAS(dmul, muldf3)
-
-COMPILER_RT_ABI fp_t
-__muldf3(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;
-
- rep_t aSignificand = toRep(a) & significandMask;
- rep_t bSignificand = toRep(b) & significandMask;
- int scale = 0;
-
- // Detect if a or b is zero, denormal, infinity, or NaN.
- if (aExponent-1U >= maxExponent-1U || bExponent-1U >= maxExponent-1U) {
-
- const rep_t aAbs = toRep(a) & absMask;
- const rep_t bAbs = toRep(b) & absMask;
-
- // NaN * anything = qNaN
- if (aAbs > infRep) return fromRep(toRep(a) | quietBit);
- // anything * NaN = qNaN
- if (bAbs > infRep) return fromRep(toRep(b) | quietBit);
-
- if (aAbs == infRep) {
- // infinity * non-zero = +/- infinity
- if (bAbs) return fromRep(aAbs | productSign);
- // infinity * zero = NaN
- else return fromRep(qnanRep);
- }
-
- if (bAbs == infRep) {
- // non-zero * infinity = +/- infinity
- if (aAbs) return fromRep(bAbs | productSign);
- // zero * infinity = NaN
- else return fromRep(qnanRep);
- }
-
- // zero * anything = +/- zero
- if (!aAbs) return fromRep(productSign);
- // anything * zero = +/- zero
- if (!bAbs) return fromRep(productSign);
-
- // one or both of a or b is denormal, the other (if applicable) is a
- // normal number. Renormalize one or both of a and b, and set scale to
- // include the necessary exponent adjustment.
- if (aAbs < implicitBit) scale += normalize(&aSignificand);
- if (bAbs < implicitBit) scale += normalize(&bSignificand);
- }
-
- // Or in the implicit significand bit. (If we fell through from the
- // denormal path it was already set by normalize( ), but setting it twice
- // won't hurt anything.)
- aSignificand |= implicitBit;
- bSignificand |= implicitBit;
-
- // Get the significand of a*b. Before multiplying the significands, shift
- // one of them left to left-align it in the field. Thus, the product will
- // have (exponentBits + 2) integral digits, all but two of which must be
- // zero. Normalizing this result is just a conditional left-shift by one
- // and bumping the exponent accordingly.
- rep_t productHi, productLo;
- wideMultiply(aSignificand, bSignificand << exponentBits,
- &productHi, &productLo);
-
- int productExponent = aExponent + bExponent - exponentBias + scale;
-
- // Normalize the significand, adjust exponent if needed.
- if (productHi & implicitBit) productExponent++;
- else wideLeftShift(&productHi, &productLo, 1);
-
- // If we have overflowed the type, return +/- infinity.
- if (productExponent >= maxExponent) return fromRep(infRep | productSign);
-
- if (productExponent <= 0) {
- // Result is denormal before rounding
- //
- // If the result is so small that it just underflows to zero, return
- // a zero of the appropriate sign. Mathematically there is no need to
- // handle this case separately, but we make it a special case to
- // simplify the shift logic.
- const unsigned int shift = 1U - (unsigned int)productExponent;
- if (shift >= typeWidth) return fromRep(productSign);
-
- // Otherwise, shift the significand of the result so that the round
- // bit is the high bit of productLo.
- wideRightShiftWithSticky(&productHi, &productLo, shift);
- }
-
- else {
- // Result is normal before rounding; insert the exponent.
- productHi &= significandMask;
- productHi |= (rep_t)productExponent << significandBits;
- }
-
- // Insert the sign of the result:
- productHi |= productSign;
-
- // Final rounding. The final result may overflow to infinity, or underflow
- // to zero, but those are the correct results in those cases. We use the
- // default IEEE-754 round-to-nearest, ties-to-even rounding mode.
- if (productLo > signBit) productHi++;
- if (productLo == signBit) productHi += productHi & 1;
- return fromRep(productHi);
-}
diff --git a/lib/mulodi4.c b/lib/mulodi4.c
deleted file mode 100644
index 0c1b5cdae768..000000000000
--- a/lib/mulodi4.c
+++ /dev/null
@@ -1,58 +0,0 @@
-/*===-- mulodi4.c - Implement __mulodi4 -----------------------------------===
- *
- * 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 __mulodi4 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-/* Returns: a * b */
-
-/* Effects: sets *overflow to 1 if a * b overflows */
-
-di_int
-__mulodi4(di_int a, di_int b, int* overflow)
-{
- const int N = (int)(sizeof(di_int) * CHAR_BIT);
- const di_int MIN = (di_int)1 << (N-1);
- const di_int MAX = ~MIN;
- *overflow = 0;
- di_int result = a * b;
- if (a == MIN)
- {
- if (b != 0 && b != 1)
- *overflow = 1;
- return result;
- }
- if (b == MIN)
- {
- if (a != 0 && a != 1)
- *overflow = 1;
- return result;
- }
- di_int sa = a >> (N - 1);
- di_int abs_a = (a ^ sa) - sa;
- di_int sb = b >> (N - 1);
- di_int abs_b = (b ^ sb) - sb;
- if (abs_a < 2 || abs_b < 2)
- return result;
- if (sa == sb)
- {
- if (abs_a > MAX / abs_b)
- *overflow = 1;
- }
- else
- {
- if (abs_a > MIN / -abs_b)
- *overflow = 1;
- }
- return result;
-}
diff --git a/lib/mulosi4.c b/lib/mulosi4.c
deleted file mode 100644
index f3398d1fc7bd..000000000000
--- a/lib/mulosi4.c
+++ /dev/null
@@ -1,58 +0,0 @@
-/*===-- mulosi4.c - Implement __mulosi4 -----------------------------------===
- *
- * 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 __mulosi4 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-/* Returns: a * b */
-
-/* Effects: sets *overflow to 1 if a * b overflows */
-
-si_int
-__mulosi4(si_int a, si_int b, int* overflow)
-{
- const int N = (int)(sizeof(si_int) * CHAR_BIT);
- const si_int MIN = (si_int)1 << (N-1);
- const si_int MAX = ~MIN;
- *overflow = 0;
- si_int result = a * b;
- if (a == MIN)
- {
- if (b != 0 && b != 1)
- *overflow = 1;
- return result;
- }
- if (b == MIN)
- {
- if (a != 0 && a != 1)
- *overflow = 1;
- return result;
- }
- si_int sa = a >> (N - 1);
- si_int abs_a = (a ^ sa) - sa;
- si_int sb = b >> (N - 1);
- si_int abs_b = (b ^ sb) - sb;
- if (abs_a < 2 || abs_b < 2)
- return result;
- if (sa == sb)
- {
- if (abs_a > MAX / abs_b)
- *overflow = 1;
- }
- else
- {
- if (abs_a > MIN / -abs_b)
- *overflow = 1;
- }
- return result;
-}
diff --git a/lib/muloti4.c b/lib/muloti4.c
deleted file mode 100644
index f58dd074eea9..000000000000
--- a/lib/muloti4.c
+++ /dev/null
@@ -1,62 +0,0 @@
-/*===-- muloti4.c - Implement __muloti4 -----------------------------------===
- *
- * 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 __muloti4 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-#if __x86_64
-
-/* Returns: a * b */
-
-/* Effects: sets *overflow to 1 if a * b overflows */
-
-ti_int
-__muloti4(ti_int a, ti_int b, int* overflow)
-{
- const int N = (int)(sizeof(ti_int) * CHAR_BIT);
- const ti_int MIN = (ti_int)1 << (N-1);
- const ti_int MAX = ~MIN;
- *overflow = 0;
- ti_int result = a * b;
- if (a == MIN)
- {
- if (b != 0 && b != 1)
- *overflow = 1;
- return result;
- }
- if (b == MIN)
- {
- if (a != 0 && a != 1)
- *overflow = 1;
- return result;
- }
- ti_int sa = a >> (N - 1);
- ti_int abs_a = (a ^ sa) - sa;
- ti_int sb = b >> (N - 1);
- ti_int abs_b = (b ^ sb) - sb;
- if (abs_a < 2 || abs_b < 2)
- return result;
- if (sa == sb)
- {
- if (abs_a > MAX / abs_b)
- *overflow = 1;
- }
- else
- {
- if (abs_a > MIN / -abs_b)
- *overflow = 1;
- }
- return result;
-}
-
-#endif
diff --git a/lib/mulsc3.c b/lib/mulsc3.c
deleted file mode 100644
index 6d433fbc45f9..000000000000
--- a/lib/mulsc3.c
+++ /dev/null
@@ -1,73 +0,0 @@
-/* ===-- mulsc3.c - Implement __mulsc3 -------------------------------------===
- *
- * 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 __mulsc3 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-#include "int_math.h"
-
-/* Returns: the product of a + ib and c + id */
-
-float _Complex
-__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))
- {
- int __recalc = 0;
- if (crt_isinf(__a) || crt_isinf(__b))
- {
- __a = crt_copysignf(crt_isinf(__a) ? 1 : 0, __a);
- __b = crt_copysignf(crt_isinf(__b) ? 1 : 0, __b);
- if (crt_isnan(__c))
- __c = crt_copysignf(0, __c);
- if (crt_isnan(__d))
- __d = crt_copysignf(0, __d);
- __recalc = 1;
- }
- if (crt_isinf(__c) || crt_isinf(__d))
- {
- __c = crt_copysignf(crt_isinf(__c) ? 1 : 0, __c);
- __d = crt_copysignf(crt_isinf(__d) ? 1 : 0, __d);
- if (crt_isnan(__a))
- __a = crt_copysignf(0, __a);
- if (crt_isnan(__b))
- __b = crt_copysignf(0, __b);
- __recalc = 1;
- }
- if (!__recalc && (crt_isinf(__ac) || crt_isinf(__bd) ||
- crt_isinf(__ad) || crt_isinf(__bc)))
- {
- if (crt_isnan(__a))
- __a = crt_copysignf(0, __a);
- if (crt_isnan(__b))
- __b = crt_copysignf(0, __b);
- if (crt_isnan(__c))
- __c = crt_copysignf(0, __c);
- if (crt_isnan(__d))
- __d = crt_copysignf(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/mulsf3.c b/lib/mulsf3.c
deleted file mode 100644
index 861a9ba5f90d..000000000000
--- a/lib/mulsf3.c
+++ /dev/null
@@ -1,112 +0,0 @@
-//===-- lib/mulsf3.c - Single-precision multiplication ------------*- 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 single-precision soft-float multiplication
-// with the IEEE-754 default rounding (to nearest, ties to even).
-//
-//===----------------------------------------------------------------------===//
-
-#define SINGLE_PRECISION
-#include "fp_lib.h"
-
-ARM_EABI_FNALIAS(fmul, mulsf3)
-
-COMPILER_RT_ABI fp_t
-__mulsf3(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;
-
- rep_t aSignificand = toRep(a) & significandMask;
- rep_t bSignificand = toRep(b) & significandMask;
- int scale = 0;
-
- // Detect if a or b is zero, denormal, infinity, or NaN.
- if (aExponent-1U >= maxExponent-1U || bExponent-1U >= maxExponent-1U) {
-
- const rep_t aAbs = toRep(a) & absMask;
- const rep_t bAbs = toRep(b) & absMask;
-
- // NaN * anything = qNaN
- if (aAbs > infRep) return fromRep(toRep(a) | quietBit);
- // anything * NaN = qNaN
- if (bAbs > infRep) return fromRep(toRep(b) | quietBit);
-
- if (aAbs == infRep) {
- // infinity * non-zero = +/- infinity
- if (bAbs) return fromRep(aAbs | productSign);
- // infinity * zero = NaN
- else return fromRep(qnanRep);
- }
-
- if (bAbs == infRep) {
- // non-zero * infinity = +/- infinity
- if (aAbs) return fromRep(bAbs | productSign);
- // zero * infinity = NaN
- else return fromRep(qnanRep);
- }
-
- // zero * anything = +/- zero
- if (!aAbs) return fromRep(productSign);
- // anything * zero = +/- zero
- if (!bAbs) return fromRep(productSign);
-
- // one or both of a or b is denormal, the other (if applicable) is a
- // normal number. Renormalize one or both of a and b, and set scale to
- // include the necessary exponent adjustment.
- if (aAbs < implicitBit) scale += normalize(&aSignificand);
- if (bAbs < implicitBit) scale += normalize(&bSignificand);
- }
-
- // Or in the implicit significand bit. (If we fell through from the
- // denormal path it was already set by normalize( ), but setting it twice
- // won't hurt anything.)
- aSignificand |= implicitBit;
- bSignificand |= implicitBit;
-
- // Get the significand of a*b. Before multiplying the significands, shift
- // one of them left to left-align it in the field. Thus, the product will
- // have (exponentBits + 2) integral digits, all but two of which must be
- // zero. Normalizing this result is just a conditional left-shift by one
- // and bumping the exponent accordingly.
- rep_t productHi, productLo;
- wideMultiply(aSignificand, bSignificand << exponentBits,
- &productHi, &productLo);
-
- int productExponent = aExponent + bExponent - exponentBias + scale;
-
- // Normalize the significand, adjust exponent if needed.
- if (productHi & implicitBit) productExponent++;
- else wideLeftShift(&productHi, &productLo, 1);
-
- // If we have overflowed the type, return +/- infinity.
- if (productExponent >= maxExponent) return fromRep(infRep | productSign);
-
- if (productExponent <= 0) {
- // Result is denormal before rounding, the exponent is zero and we
- // need to shift the significand.
- wideRightShiftWithSticky(&productHi, &productLo, 1U - (unsigned)productExponent);
- }
-
- else {
- // Result is normal before rounding; insert the exponent.
- productHi &= significandMask;
- productHi |= (rep_t)productExponent << significandBits;
- }
-
- // Insert the sign of the result:
- productHi |= productSign;
-
- // Final rounding. The final result may overflow to infinity, or underflow
- // to zero, but those are the correct results in those cases.
- if (productLo > signBit) productHi++;
- if (productLo == signBit) productHi += productHi & 1;
- return fromRep(productHi);
-}
diff --git a/lib/multi3.c b/lib/multi3.c
deleted file mode 100644
index 0b8730f08cec..000000000000
--- a/lib/multi3.c
+++ /dev/null
@@ -1,58 +0,0 @@
-/* ===-- multi3.c - Implement __multi3 -------------------------------------===
- *
- * 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 __multi3 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-#if __x86_64
-
-/* Returns: a * b */
-
-static
-ti_int
-__mulddi3(du_int a, du_int b)
-{
- twords r;
- const int bits_in_dword_2 = (int)(sizeof(di_int) * CHAR_BIT) / 2;
- const du_int lower_mask = (du_int)~0 >> bits_in_dword_2;
- r.s.low = (a & lower_mask) * (b & lower_mask);
- du_int t = r.s.low >> bits_in_dword_2;
- r.s.low &= lower_mask;
- t += (a >> bits_in_dword_2) * (b & lower_mask);
- r.s.low += (t & lower_mask) << bits_in_dword_2;
- r.s.high = t >> bits_in_dword_2;
- t = r.s.low >> bits_in_dword_2;
- r.s.low &= lower_mask;
- t += (b >> bits_in_dword_2) * (a & lower_mask);
- r.s.low += (t & lower_mask) << bits_in_dword_2;
- r.s.high += t >> bits_in_dword_2;
- r.s.high += (a >> bits_in_dword_2) * (b >> bits_in_dword_2);
- return r.all;
-}
-
-/* Returns: a * b */
-
-ti_int
-__multi3(ti_int a, ti_int b)
-{
- twords x;
- x.all = a;
- twords y;
- y.all = b;
- twords r;
- r.all = __mulddi3(x.s.low, y.s.low);
- r.s.high += x.s.high * y.s.low + x.s.low * y.s.high;
- return r.all;
-}
-
-#endif /* __x86_64 */
diff --git a/lib/mulvdi3.c b/lib/mulvdi3.c
deleted file mode 100644
index bcc8e659be48..000000000000
--- a/lib/mulvdi3.c
+++ /dev/null
@@ -1,56 +0,0 @@
-/*===-- mulvdi3.c - Implement __mulvdi3 -----------------------------------===
- *
- * 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 __mulvdi3 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-/* Returns: a * b */
-
-/* Effects: aborts if a * b overflows */
-
-di_int
-__mulvdi3(di_int a, di_int b)
-{
- const int N = (int)(sizeof(di_int) * CHAR_BIT);
- const di_int MIN = (di_int)1 << (N-1);
- const di_int MAX = ~MIN;
- if (a == MIN)
- {
- if (b == 0 || b == 1)
- return a * b;
- compilerrt_abort();
- }
- if (b == MIN)
- {
- if (a == 0 || a == 1)
- return a * b;
- compilerrt_abort();
- }
- di_int sa = a >> (N - 1);
- di_int abs_a = (a ^ sa) - sa;
- di_int sb = b >> (N - 1);
- di_int abs_b = (b ^ sb) - sb;
- if (abs_a < 2 || abs_b < 2)
- return a * b;
- if (sa == sb)
- {
- if (abs_a > MAX / abs_b)
- compilerrt_abort();
- }
- else
- {
- if (abs_a > MIN / -abs_b)
- compilerrt_abort();
- }
- return a * b;
-}
diff --git a/lib/mulvsi3.c b/lib/mulvsi3.c
deleted file mode 100644
index d372b20175ed..000000000000
--- a/lib/mulvsi3.c
+++ /dev/null
@@ -1,56 +0,0 @@
-/* ===-- mulvsi3.c - Implement __mulvsi3 -----------------------------------===
- *
- * 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 __mulvsi3 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-/* Returns: a * b */
-
-/* Effects: aborts if a * b overflows */
-
-si_int
-__mulvsi3(si_int a, si_int b)
-{
- const int N = (int)(sizeof(si_int) * CHAR_BIT);
- const si_int MIN = (si_int)1 << (N-1);
- const si_int MAX = ~MIN;
- if (a == MIN)
- {
- if (b == 0 || b == 1)
- return a * b;
- compilerrt_abort();
- }
- if (b == MIN)
- {
- if (a == 0 || a == 1)
- return a * b;
- compilerrt_abort();
- }
- si_int sa = a >> (N - 1);
- si_int abs_a = (a ^ sa) - sa;
- si_int sb = b >> (N - 1);
- si_int abs_b = (b ^ sb) - sb;
- if (abs_a < 2 || abs_b < 2)
- return a * b;
- if (sa == sb)
- {
- if (abs_a > MAX / abs_b)
- compilerrt_abort();
- }
- else
- {
- if (abs_a > MIN / -abs_b)
- compilerrt_abort();
- }
- return a * b;
-}
diff --git a/lib/mulvti3.c b/lib/mulvti3.c
deleted file mode 100644
index 31f7d2fd3746..000000000000
--- a/lib/mulvti3.c
+++ /dev/null
@@ -1,60 +0,0 @@
-/* ===-- mulvti3.c - Implement __mulvti3 -----------------------------------===
- *
- * 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 __mulvti3 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-#if __x86_64
-
-/* Returns: a * b */
-
-/* Effects: aborts if a * b overflows */
-
-ti_int
-__mulvti3(ti_int a, ti_int b)
-{
- const int N = (int)(sizeof(ti_int) * CHAR_BIT);
- const ti_int MIN = (ti_int)1 << (N-1);
- const ti_int MAX = ~MIN;
- if (a == MIN)
- {
- if (b == 0 || b == 1)
- return a * b;
- compilerrt_abort();
- }
- if (b == MIN)
- {
- if (a == 0 || a == 1)
- return a * b;
- compilerrt_abort();
- }
- ti_int sa = a >> (N - 1);
- ti_int abs_a = (a ^ sa) - sa;
- ti_int sb = b >> (N - 1);
- ti_int abs_b = (b ^ sb) - sb;
- if (abs_a < 2 || abs_b < 2)
- return a * b;
- if (sa == sb)
- {
- if (abs_a > MAX / abs_b)
- compilerrt_abort();
- }
- else
- {
- if (abs_a > MIN / -abs_b)
- compilerrt_abort();
- }
- return a * b;
-}
-
-#endif
diff --git a/lib/mulxc3.c b/lib/mulxc3.c
deleted file mode 100644
index cec0573688ad..000000000000
--- a/lib/mulxc3.c
+++ /dev/null
@@ -1,77 +0,0 @@
-/* ===-- mulxc3.c - Implement __mulxc3 -------------------------------------===
- *
- * 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 __mulxc3 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#if !_ARCH_PPC
-
-#include "int_lib.h"
-#include "int_math.h"
-
-/* Returns: the product of a + ib and c + id */
-
-long double _Complex
-__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))
- {
- 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;
-}
-
-#endif
diff --git a/lib/negdf2.c b/lib/negdf2.c
deleted file mode 100644
index 4e17513a9d00..000000000000
--- a/lib/negdf2.c
+++ /dev/null
@@ -1,21 +0,0 @@
-//===-- lib/negdf2.c - double-precision negation ------------------*- 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 double-precision soft-float negation.
-//
-//===----------------------------------------------------------------------===//
-
-#define DOUBLE_PRECISION
-#include "fp_lib.h"
-
-ARM_EABI_FNALIAS(dneg, negdf2)
-
-fp_t __negdf2(fp_t a) {
- return fromRep(toRep(a) ^ signBit);
-}
diff --git a/lib/negdi2.c b/lib/negdi2.c
deleted file mode 100644
index b000dda3b83d..000000000000
--- a/lib/negdi2.c
+++ /dev/null
@@ -1,26 +0,0 @@
-/* ===-- negdi2.c - Implement __negdi2 -------------------------------------===
- *
- * 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 __negdi2 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-/* Returns: -a */
-
-di_int
-__negdi2(di_int a)
-{
- /* Note: this routine is here for API compatibility; any sane compiler
- * should expand it inline.
- */
- return -a;
-}
diff --git a/lib/negti2.c b/lib/negti2.c
deleted file mode 100644
index f7e4ad3b94af..000000000000
--- a/lib/negti2.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/* ===-- negti2.c - Implement __negti2 -------------------------------------===
- *
- * 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 __negti2 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-#if __x86_64
-
-/* Returns: -a */
-
-ti_int
-__negti2(ti_int a)
-{
- /* Note: this routine is here for API compatibility; any sane compiler
- * should expand it inline.
- */
- return -a;
-}
-
-#endif
diff --git a/lib/negvti2.c b/lib/negvti2.c
deleted file mode 100644
index 05df6152fcdf..000000000000
--- a/lib/negvti2.c
+++ /dev/null
@@ -1,32 +0,0 @@
-/*===-- negvti2.c - Implement __negvti2 -----------------------------------===
- *
- * 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 __negvti2 for the compiler_rt library.
- *
- *===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-#if __x86_64
-
-/* Returns: -a */
-
-/* Effects: aborts if -a overflows */
-
-ti_int
-__negvti2(ti_int a)
-{
- const ti_int MIN = (ti_int)1 << ((int)(sizeof(ti_int) * CHAR_BIT)-1);
- if (a == MIN)
- compilerrt_abort();
- return -a;
-}
-
-#endif
diff --git a/lib/paritydi2.c b/lib/paritydi2.c
deleted file mode 100644
index 2ded54c90b93..000000000000
--- a/lib/paritydi2.c
+++ /dev/null
@@ -1,27 +0,0 @@
-/* ===-- paritydi2.c - Implement __paritydi2 -------------------------------===
- *
- * 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 __paritydi2 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-/* Returns: 1 if number of bits is odd else returns 0 */
-
-si_int COMPILER_RT_ABI __paritysi2(si_int a);
-
-COMPILER_RT_ABI si_int
-__paritydi2(di_int a)
-{
- dwords x;
- x.all = a;
- return __paritysi2(x.s.high ^ x.s.low);
-}
diff --git a/lib/parityti2.c b/lib/parityti2.c
deleted file mode 100644
index a1f47b1d931b..000000000000
--- a/lib/parityti2.c
+++ /dev/null
@@ -1,31 +0,0 @@
-/* ===-- parityti2.c - Implement __parityti2 -------------------------------===
- *
- * 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 __parityti2 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-#if __x86_64
-
-/* Returns: 1 if number of bits is odd else returns 0 */
-
-si_int __paritydi2(di_int a);
-
-si_int
-__parityti2(ti_int a)
-{
- twords x;
- x.all = a;
- return __paritydi2(x.s.high ^ x.s.low);
-}
-
-#endif
diff --git a/lib/popcountti2.c b/lib/popcountti2.c
deleted file mode 100644
index 95666738f721..000000000000
--- a/lib/popcountti2.c
+++ /dev/null
@@ -1,44 +0,0 @@
-/* ===-- popcountti2.c - Implement __popcountti2 ----------------------------===
- *
- * 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 __popcountti2 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-#if __x86_64
-
-/* Returns: count of 1 bits */
-
-si_int
-__popcountti2(ti_int a)
-{
- tu_int x3 = (tu_int)a;
- x3 = x3 - ((x3 >> 1) & (((tu_int)0x5555555555555555uLL << 64) |
- 0x5555555555555555uLL));
- /* Every 2 bits holds the sum of every pair of bits (64) */
- x3 = ((x3 >> 2) & (((tu_int)0x3333333333333333uLL << 64) | 0x3333333333333333uLL))
- + (x3 & (((tu_int)0x3333333333333333uLL << 64) | 0x3333333333333333uLL));
- /* Every 4 bits holds the sum of every 4-set of bits (3 significant bits) (32) */
- x3 = (x3 + (x3 >> 4))
- & (((tu_int)0x0F0F0F0F0F0F0F0FuLL << 64) | 0x0F0F0F0F0F0F0F0FuLL);
- /* Every 8 bits holds the sum of every 8-set of bits (4 significant bits) (16) */
- du_int x2 = (du_int)(x3 + (x3 >> 64));
- /* Every 8 bits holds the sum of every 8-set of bits (5 significant bits) (8) */
- su_int x = (su_int)(x2 + (x2 >> 32));
- /* Every 8 bits holds the sum of every 8-set of bits (6 significant bits) (4) */
- x = x + (x >> 16);
- /* Every 8 bits holds the sum of every 8-set of bits (7 significant bits) (2) */
- /* Upper 16 bits are garbage */
- return (x + (x >> 8)) & 0xFF; /* (8 significant bits) */
-}
-
-#endif
diff --git a/lib/powitf2.c b/lib/powitf2.c
deleted file mode 100644
index d3b934924f3e..000000000000
--- a/lib/powitf2.c
+++ /dev/null
@@ -1,38 +0,0 @@
-/* ===-- powitf2.cpp - Implement __powitf2 ---------------------------------===
- *
- * 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 __powitf2 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-#if _ARCH_PPC
-
-/* Returns: a ^ b */
-
-long double
-__powitf2(long double a, si_int b)
-{
- const int recip = b < 0;
- long double r = 1;
- while (1)
- {
- if (b & 1)
- r *= a;
- b /= 2;
- if (b == 0)
- break;
- a *= a;
- }
- return recip ? 1/r : r;
-}
-
-#endif
diff --git a/lib/powixf2.c b/lib/powixf2.c
deleted file mode 100644
index f050964d3597..000000000000
--- a/lib/powixf2.c
+++ /dev/null
@@ -1,38 +0,0 @@
-/* ===-- powixf2.cpp - Implement __powixf2 ---------------------------------===
- *
- * 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 __powixf2 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#if !_ARCH_PPC
-
-#include "int_lib.h"
-
-/* Returns: a ^ b */
-
-long double
-__powixf2(long double a, si_int b)
-{
- const int recip = b < 0;
- long double r = 1;
- while (1)
- {
- if (b & 1)
- r *= a;
- b /= 2;
- if (b == 0)
- break;
- a *= a;
- }
- return recip ? 1/r : r;
-}
-
-#endif
diff --git a/lib/ppc/DD.h b/lib/ppc/DD.h
deleted file mode 100644
index 13862dc98404..000000000000
--- a/lib/ppc/DD.h
+++ /dev/null
@@ -1,46 +0,0 @@
-#ifndef __DD_HEADER
-#define __DD_HEADER
-
-#include "../int_lib.h"
-
-typedef union {
- long double ld;
- struct {
- double hi;
- double lo;
- }s;
-}DD;
-
-typedef union {
- double d;
- uint64_t x;
-} doublebits;
-
-#define LOWORDER(xy,xHi,xLo,yHi,yLo) \
- (((((xHi)*(yHi) - (xy)) + (xHi)*(yLo)) + (xLo)*(yHi)) + (xLo)*(yLo))
-
-static inline double __attribute__((always_inline))
-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 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;
-}
-
-#endif /* __DD_HEADER */
diff --git a/lib/ppc/Makefile.mk b/lib/ppc/Makefile.mk
deleted file mode 100644
index b78d3860c53c..000000000000
--- a/lib/ppc/Makefile.mk
+++ /dev/null
@@ -1,20 +0,0 @@
-#===- lib/ppc/Makefile.mk ----------------------------------*- Makefile -*--===#
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-#===------------------------------------------------------------------------===#
-
-ModuleName := builtins
-SubDirs :=
-OnlyArchs := ppc
-
-AsmSources := $(foreach file,$(wildcard $(Dir)/*.S),$(notdir $(file)))
-Sources := $(foreach file,$(wildcard $(Dir)/*.c),$(notdir $(file)))
-ObjNames := $(Sources:%.c=%.o) $(AsmSources:%.S=%.o)
-Implementation := Optimized
-
-# FIXME: use automatic dependencies?
-Dependencies := $(wildcard lib/*.h $(Dir)/*.h)
diff --git a/lib/ppc/fixtfdi.c b/lib/ppc/fixtfdi.c
deleted file mode 100644
index 56e7b3fbf3e5..000000000000
--- a/lib/ppc/fixtfdi.c
+++ /dev/null
@@ -1,104 +0,0 @@
-/* This file is distributed under the University of Illinois Open Source
- * License. See LICENSE.TXT for details.
- */
-
-/* int64_t __fixunstfdi(long double x);
- * This file implements the PowerPC 128-bit double-double -> int64_t conversion
- */
-
-#include "DD.h"
-#include "../int_math.h"
-
-uint64_t __fixtfdi(long double input)
-{
- const DD x = { .ld = input };
- const doublebits hibits = { .d = x.s.hi };
-
- const uint32_t absHighWord = (uint32_t)(hibits.x >> 32) & UINT32_C(0x7fffffff);
- const uint32_t absHighWordMinusOne = absHighWord - UINT32_C(0x3ff00000);
-
- /* If (1.0 - tiny) <= input < 0x1.0p63: */
- if (UINT32_C(0x03f00000) > absHighWordMinusOne)
- {
- /* Do an unsigned conversion of the absolute value, then restore the sign. */
- const int unbiasedHeadExponent = absHighWordMinusOne >> 20;
-
- int64_t result = hibits.x & INT64_C(0x000fffffffffffff); /* mantissa(hi) */
- result |= INT64_C(0x0010000000000000); /* matissa(hi) with implicit bit */
- result <<= 10; /* mantissa(hi) with one zero preceeding bit. */
-
- const int64_t hiNegationMask = ((int64_t)(hibits.x)) >> 63;
-
- /* If the tail is non-zero, we need to patch in the tail bits. */
- if (0.0 != x.s.lo)
- {
- const doublebits lobits = { .d = x.s.lo };
- int64_t tailMantissa = lobits.x & INT64_C(0x000fffffffffffff);
- tailMantissa |= INT64_C(0x0010000000000000);
-
- /* At this point we have the mantissa of |tail| */
- /* We need to negate it if head and tail have different signs. */
- const int64_t loNegationMask = ((int64_t)(lobits.x)) >> 63;
- const int64_t negationMask = loNegationMask ^ hiNegationMask;
- tailMantissa = (tailMantissa ^ negationMask) - negationMask;
-
- /* Now we have the mantissa of tail as a signed 2s-complement integer */
-
- const int biasedTailExponent = (int)(lobits.x >> 52) & 0x7ff;
-
- /* Shift the tail mantissa into the right position, accounting for the
- * bias of 10 that we shifted the head mantissa by.
- */
- tailMantissa >>= (unbiasedHeadExponent - (biasedTailExponent - (1023 - 10)));
-
- result += tailMantissa;
- }
-
- result >>= (62 - unbiasedHeadExponent);
-
- /* Restore the sign of the result and return */
- result = (result ^ hiNegationMask) - hiNegationMask;
- return result;
-
- }
-
- /* Edge cases handled here: */
-
- /* |x| < 1, result is zero. */
- if (1.0 > crt_fabs(x.s.hi))
- return INT64_C(0);
-
- /* x very close to INT64_MIN, care must be taken to see which side we are on. */
- if (x.s.hi == -0x1.0p63) {
-
- int64_t result = INT64_MIN;
-
- if (0.0 < x.s.lo)
- {
- /* If the tail is positive, the correct result is something other than INT64_MIN.
- * we'll need to figure out what it is.
- */
-
- const doublebits lobits = { .d = x.s.lo };
- int64_t tailMantissa = lobits.x & INT64_C(0x000fffffffffffff);
- tailMantissa |= INT64_C(0x0010000000000000);
-
- /* Now we negate the tailMantissa */
- tailMantissa = (tailMantissa ^ INT64_C(-1)) + INT64_C(1);
-
- /* And shift it by the appropriate amount */
- const int biasedTailExponent = (int)(lobits.x >> 52) & 0x7ff;
- tailMantissa >>= 1075 - biasedTailExponent;
-
- result -= tailMantissa;
- }
-
- return result;
- }
-
- /* Signed overflows, infinities, and NaNs */
- if (x.s.hi > 0.0)
- return INT64_MAX;
- else
- return INT64_MIN;
-}
diff --git a/lib/ppc/gcc_qadd.c b/lib/ppc/gcc_qadd.c
deleted file mode 100644
index c388c7e99c6e..000000000000
--- a/lib/ppc/gcc_qadd.c
+++ /dev/null
@@ -1,76 +0,0 @@
-/* This file is distributed under the University of Illinois Open Source
- * License. See LICENSE.TXT for details.
- */
-
-/* long double __gcc_qadd(long double x, long double y);
- * This file implements the PowerPC 128-bit double-double add operation.
- * This implementation is shamelessly cribbed from Apple's DDRT, circa 1993(!)
- */
-
-#include "DD.h"
-
-long double __gcc_qadd(long double x, long double y)
-{
- static const uint32_t infinityHi = UINT32_C(0x7ff00000);
-
- DD dst = { .ld = x }, src = { .ld = y };
-
- register double A = dst.s.hi, a = dst.s.lo,
- B = src.s.hi, b = src.s.lo;
-
- /* If both operands are zero: */
- if ((A == 0.0) && (B == 0.0)) {
- dst.s.hi = A + B;
- dst.s.lo = 0.0;
- return dst.ld;
- }
-
- /* If either operand is NaN or infinity: */
- const doublebits abits = { .d = A };
- const doublebits bbits = { .d = B };
- if ((((uint32_t)(abits.x >> 32) & infinityHi) == infinityHi) ||
- (((uint32_t)(bbits.x >> 32) & infinityHi) == infinityHi)) {
- dst.s.hi = A + B;
- dst.s.lo = 0.0;
- return dst.ld;
- }
-
- /* If the computation overflows: */
- /* This may be playing things a little bit fast and loose, but it will do for a start. */
- const double testForOverflow = A + (B + (a + b));
- const doublebits testbits = { .d = testForOverflow };
- if (((uint32_t)(testbits.x >> 32) & infinityHi) == infinityHi) {
- dst.s.hi = testForOverflow;
- dst.s.lo = 0.0;
- return dst.ld;
- }
-
- double H, h;
- double T, t;
- double W, w;
- double Y;
-
- H = B + (A - (A + B));
- T = b + (a - (a + b));
- h = A + (B - (A + B));
- t = a + (b - (a + b));
-
- if (fabs(A) <= fabs(B))
- w = (a + b) + h;
- else
- w = (a + b) + H;
-
- W = (A + B) + w;
- Y = (A + B) - W;
- Y += w;
-
- if (fabs(a) <= fabs(b))
- w = t + Y;
- else
- w = T + Y;
-
- dst.s.hi = Y = W + w;
- dst.s.lo = (W - Y) + w;
-
- return dst.ld;
-}
diff --git a/lib/ppc/gcc_qsub.c b/lib/ppc/gcc_qsub.c
deleted file mode 100644
index 4f1f7ac70f3c..000000000000
--- a/lib/ppc/gcc_qsub.c
+++ /dev/null
@@ -1,76 +0,0 @@
-/* This file is distributed under the University of Illinois Open Source
- * License. See LICENSE.TXT for details.
- */
-
-/* long double __gcc_qsub(long double x, long double y);
- * This file implements the PowerPC 128-bit double-double add operation.
- * This implementation is shamelessly cribbed from Apple's DDRT, circa 1993(!)
- */
-
-#include "DD.h"
-
-long double __gcc_qsub(long double x, long double y)
-{
- static const uint32_t infinityHi = UINT32_C(0x7ff00000);
-
- DD dst = { .ld = x }, src = { .ld = y };
-
- register double A = dst.s.hi, a = dst.s.lo,
- B = -src.s.hi, b = -src.s.lo;
-
- /* If both operands are zero: */
- if ((A == 0.0) && (B == 0.0)) {
- dst.s.hi = A + B;
- dst.s.lo = 0.0;
- return dst.ld;
- }
-
- /* If either operand is NaN or infinity: */
- const doublebits abits = { .d = A };
- const doublebits bbits = { .d = B };
- if ((((uint32_t)(abits.x >> 32) & infinityHi) == infinityHi) ||
- (((uint32_t)(bbits.x >> 32) & infinityHi) == infinityHi)) {
- dst.s.hi = A + B;
- dst.s.lo = 0.0;
- return dst.ld;
- }
-
- /* If the computation overflows: */
- /* This may be playing things a little bit fast and loose, but it will do for a start. */
- const double testForOverflow = A + (B + (a + b));
- const doublebits testbits = { .d = testForOverflow };
- if (((uint32_t)(testbits.x >> 32) & infinityHi) == infinityHi) {
- dst.s.hi = testForOverflow;
- dst.s.lo = 0.0;
- return dst.ld;
- }
-
- double H, h;
- double T, t;
- double W, w;
- double Y;
-
- H = B + (A - (A + B));
- T = b + (a - (a + b));
- h = A + (B - (A + B));
- t = a + (b - (a + b));
-
- if (fabs(A) <= fabs(B))
- w = (a + b) + h;
- else
- w = (a + b) + H;
-
- W = (A + B) + w;
- Y = (A + B) - W;
- Y += w;
-
- if (fabs(a) <= fabs(b))
- w = t + Y;
- else
- w = T + Y;
-
- dst.s.hi = Y = W + w;
- dst.s.lo = (W - Y) + w;
-
- return dst.ld;
-}
diff --git a/lib/profile/CMakeLists.txt b/lib/profile/CMakeLists.txt
index bb4fd9e23a7e..420d7660ee36 100644
--- a/lib/profile/CMakeLists.txt
+++ b/lib/profile/CMakeLists.txt
@@ -1,16 +1,26 @@
-set(PROFILE_SOURCES
- GCDAProfiling.c)
+add_custom_target(profile)
-filter_available_targets(PROFILE_SUPPORTED_ARCH x86_64 i386)
+set(PROFILE_SOURCES
+ GCDAProfiling.c
+ InstrProfiling.c
+ InstrProfilingBuffer.c
+ InstrProfilingFile.c
+ InstrProfilingPlatformDarwin.c
+ InstrProfilingPlatformOther.c
+ InstrProfilingRuntime.cc)
if(APPLE)
add_compiler_rt_osx_static_runtime(clang_rt.profile_osx
ARCH ${PROFILE_SUPPORTED_ARCH}
SOURCES ${PROFILE_SOURCES})
+ add_dependencies(profile clang_rt.profile_osx)
else()
foreach(arch ${PROFILE_SUPPORTED_ARCH})
- add_compiler_rt_static_runtime(clang_rt.profile-${arch}
- ${arch}
+ add_compiler_rt_runtime(clang_rt.profile-${arch} ${arch} STATIC
+ CFLAGS -fPIC
SOURCES ${PROFILE_SOURCES})
+ add_dependencies(profile clang_rt.profile-${arch})
endforeach()
endif()
+
+add_dependencies(compiler-rt profile)
diff --git a/lib/profile/GCDAProfiling.c b/lib/profile/GCDAProfiling.c
index 7edf6829b4a5..45fbd07e544b 100644
--- a/lib/profile/GCDAProfiling.c
+++ b/lib/profile/GCDAProfiling.c
@@ -25,18 +25,33 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <sys/stat.h>
#include <sys/mman.h>
-#include <sys/types.h>
#ifdef _WIN32
#include <direct.h>
#endif
-#ifndef _MSC_VER
+#define I386_FREEBSD (defined(__FreeBSD__) && defined(__i386__))
+
+#if !I386_FREEBSD
+#include <sys/stat.h>
+#include <sys/types.h>
+#endif
+
+#if !defined(_MSC_VER) && !I386_FREEBSD
#include <stdint.h>
-#else
+#endif
+
+#if defined(_MSC_VER)
typedef unsigned int uint32_t;
-typedef unsigned int uint64_t;
+typedef unsigned long long uint64_t;
+#elif I386_FREEBSD
+/* System headers define 'size_t' incorrectly on x64 FreeBSD (prior to
+ * FreeBSD 10, r232261) when compiled in 32-bit mode.
+ */
+typedef unsigned char uint8_t;
+typedef unsigned int uint32_t;
+typedef unsigned long long uint64_t;
+int mkdir(const char*, unsigned short);
#endif
/* #define DEBUG_GCDAPROFILING */
@@ -150,15 +165,15 @@ static uint64_t read_64bit_value() {
}
static char *mangle_filename(const char *orig_filename) {
- char *filename = 0;
- int prefix_len = 0;
- int prefix_strip = 0;
+ char *new_filename;
+ size_t filename_len, prefix_len;
+ int prefix_strip;
int level = 0;
- const char *fname = orig_filename, *ptr = NULL;
+ const char *fname, *ptr;
const char *prefix = getenv("GCOV_PREFIX");
const char *prefix_strip_str = getenv("GCOV_PREFIX_STRIP");
- if (!prefix)
+ if (prefix == NULL || prefix[0] == '\0')
return strdup(orig_filename);
if (prefix_strip_str) {
@@ -167,38 +182,44 @@ static char *mangle_filename(const char *orig_filename) {
/* Negative GCOV_PREFIX_STRIP values are ignored */
if (prefix_strip < 0)
prefix_strip = 0;
+ } else {
+ prefix_strip = 0;
}
- prefix_len = strlen(prefix);
- filename = malloc(prefix_len + 1 + strlen(orig_filename) + 1);
- strcpy(filename, prefix);
-
- if (prefix[prefix_len - 1] != '/')
- strcat(filename, "/");
-
- for (ptr = fname + 1; *ptr != '\0' && level < prefix_strip; ++ptr) {
- if (*ptr != '/') continue;
+ fname = orig_filename;
+ for (level = 0, ptr = fname + 1; level < prefix_strip; ++ptr) {
+ if (*ptr == '\0')
+ break;
+ if (*ptr != '/')
+ continue;
fname = ptr;
++level;
}
- strcat(filename, fname);
+ filename_len = strlen(fname);
+ prefix_len = strlen(prefix);
+ new_filename = malloc(prefix_len + 1 + filename_len + 1);
+ memcpy(new_filename, prefix, prefix_len);
- return filename;
+ if (prefix[prefix_len - 1] != '/')
+ new_filename[prefix_len++] = '/';
+ memcpy(new_filename + prefix_len, fname, filename_len + 1);
+
+ return new_filename;
}
-static void recursive_mkdir(char *filename) {
+static void recursive_mkdir(char *path) {
int i;
- for (i = 1; filename[i] != '\0'; ++i) {
- if (filename[i] != '/') continue;
- filename[i] = '\0';
+ for (i = 1; path[i] != '\0'; ++i) {
+ if (path[i] != '/') continue;
+ path[i] = '\0';
#ifdef _WIN32
- _mkdir(filename);
+ _mkdir(path);
#else
- mkdir(filename, 0755); /* Some of these will fail, ignore it. */
+ mkdir(path, 0755); /* Some of these will fail, ignore it. */
#endif
- filename[i] = '/';
+ path[i] = '/';
}
}
@@ -245,7 +266,8 @@ static void unmap_file() {
* profiling enabled will emit to a different file. Only one file may be
* started at a time.
*/
-void llvm_gcda_start_file(const char *orig_filename, const char version[4]) {
+void llvm_gcda_start_file(const char *orig_filename, const char version[4],
+ uint32_t checksum) {
const char *mode = "r+b";
filename = mangle_filename(orig_filename);
@@ -293,10 +315,10 @@ void llvm_gcda_start_file(const char *orig_filename, const char version[4]) {
}
}
- /* gcda file, version, stamp LLVM. */
+ /* gcda file, version, stamp checksum. */
write_bytes("adcg", 4);
write_bytes(version, 4);
- write_bytes("MVLL", 4);
+ write_32bit_value(checksum);
#ifdef DEBUG_GCDAPROFILING
fprintf(stderr, "llvmgcda: [%s]\n", orig_filename);
@@ -329,7 +351,8 @@ void llvm_gcda_increment_indirect_counter(uint32_t *predecessor,
}
void llvm_gcda_emit_function(uint32_t ident, const char *function_name,
- uint8_t use_extra_checksum) {
+ uint32_t func_checksum, uint8_t use_extra_checksum,
+ uint32_t cfg_checksum) {
uint32_t len = 2;
if (use_extra_checksum)
@@ -346,9 +369,9 @@ void llvm_gcda_emit_function(uint32_t ident, const char *function_name,
len += 1 + length_of_string(function_name);
write_32bit_value(len);
write_32bit_value(ident);
- write_32bit_value(0);
+ write_32bit_value(func_checksum);
if (use_extra_checksum)
- write_32bit_value(0);
+ write_32bit_value(cfg_checksum);
if (function_name)
write_string(function_name);
}
@@ -366,13 +389,17 @@ void llvm_gcda_emit_arcs(uint32_t num_counters, uint64_t *counters) {
if (val != (uint32_t)-1) {
/* There are counters present in the file. Merge them. */
if (val != 0x01a10000) {
- fprintf(stderr, "profiling:invalid arc tag (0x%08x)\n", val);
+ fprintf(stderr, "profiling: %s: cannot merge previous GCDA file: "
+ "corrupt arc tag (0x%08x)\n",
+ filename, val);
return;
}
val = read_32bit_value();
if (val == (uint32_t)-1 || val / 2 != num_counters) {
- fprintf(stderr, "profiling:invalid number of counters (%d)\n", val);
+ fprintf(stderr, "profiling: %s: cannot merge previous GCDA file: "
+ "mismatched number of counters (%d)\n",
+ filename, val);
return;
}
@@ -401,7 +428,7 @@ void llvm_gcda_emit_arcs(uint32_t num_counters, uint64_t *counters) {
}
void llvm_gcda_summary_info() {
- const int obj_summary_len = 9; // length for gcov compatibility
+ const uint32_t obj_summary_len = 9; /* Length for gcov compatibility. */
uint32_t i;
uint32_t runs = 1;
uint32_t val = 0;
@@ -414,19 +441,23 @@ void llvm_gcda_summary_info() {
if (val != (uint32_t)-1) {
/* There are counters present in the file. Merge them. */
if (val != 0xa1000000) {
- fprintf(stderr, "profiling:invalid object tag (0x%08x)\n", val);
+ fprintf(stderr, "profiling: %s: cannot merge previous run count: "
+ "corrupt object tag (0x%08x)\n",
+ filename, val);
return;
}
- val = read_32bit_value(); // length
+ val = read_32bit_value(); /* length */
if (val != obj_summary_len) {
- fprintf(stderr, "profiling:invalid object length (%d)\n", val); // length
+ fprintf(stderr, "profiling: %s: cannot merge previous run count: "
+ "mismatched object length (%d)\n",
+ filename, val);
return;
}
- read_32bit_value(); // checksum, unused
- read_32bit_value(); // num, unused
- runs += read_32bit_value(); // add previous run count to new counter
+ read_32bit_value(); /* checksum, unused */
+ read_32bit_value(); /* num, unused */
+ runs += read_32bit_value(); /* Add previous run count to new counter. */
}
cur_pos = save_cur_pos;
@@ -434,15 +465,15 @@ void llvm_gcda_summary_info() {
/* Object summary tag */
write_bytes("\0\0\0\xa1", 4);
write_32bit_value(obj_summary_len);
- write_32bit_value(0); // checksum, unused
- write_32bit_value(0); // num, unused
+ write_32bit_value(0); /* checksum, unused */
+ write_32bit_value(0); /* num, unused */
write_32bit_value(runs);
- for (i = 3; i < obj_summary_len; ++i)
+ for (i = 3; i < obj_summary_len; ++i)
write_32bit_value(0);
/* Program summary tag */
- write_bytes("\0\0\0\xa3", 4); // tag indicates 1 program
- write_32bit_value(0); // 0 length
+ write_bytes("\0\0\0\xa3", 4); /* tag indicates 1 program */
+ write_32bit_value(0); /* 0 length */
#ifdef DEBUG_GCDAPROFILING
fprintf(stderr, "llvmgcda: %u runs\n", runs);
diff --git a/lib/profile/InstrProfiling.c b/lib/profile/InstrProfiling.c
new file mode 100644
index 000000000000..8d010df28f18
--- /dev/null
+++ b/lib/profile/InstrProfiling.c
@@ -0,0 +1,48 @@
+/*===- InstrProfiling.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 <string.h>
+
+__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;
+}
+
+__attribute__((visibility("hidden")))
+uint64_t __llvm_profile_get_version(void) {
+ /* This should be bumped any time the output format changes. */
+ return 1;
+}
+
+__attribute__((visibility("hidden")))
+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));
+}
diff --git a/lib/profile/InstrProfiling.h b/lib/profile/InstrProfiling.h
new file mode 100644
index 000000000000..2b1bd003668e
--- /dev/null
+++ b/lib/profile/InstrProfiling.h
@@ -0,0 +1,92 @@
+/*===- InstrProfiling.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_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__) */
+
+#define PROFILE_HEADER_SIZE 7
+
+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 required size for profile buffer.
+ */
+uint64_t __llvm_profile_get_size_for_buffer(void);
+
+/*!
+ * \brief Write instrumentation data to the given buffer.
+ *
+ * \pre \c Buffer is the start of a buffer at least as big as \a
+ * __llvm_profile_get_size_for_buffer().
+ */
+int __llvm_profile_write_buffer(char *Buffer);
+
+const __llvm_profile_data *__llvm_profile_begin_data(void);
+const __llvm_profile_data *__llvm_profile_end_data(void);
+const char *__llvm_profile_begin_names(void);
+const char *__llvm_profile_end_names(void);
+uint64_t *__llvm_profile_begin_counters(void);
+uint64_t *__llvm_profile_end_counters(void);
+
+/*!
+ * \brief Write instrumentation data to the current file.
+ *
+ * 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, \c "default.profdata".
+ */
+int __llvm_profile_write_file(void);
+
+/*!
+ * \brief Set the filename for writing instrumentation data.
+ *
+ * Sets the filename to be used for subsequent calls to
+ * \a __llvm_profile_write_file().
+ *
+ * \c Name is not copied, so it must remain valid. Passing NULL resets the
+ * filename logic to the default behaviour.
+ */
+void __llvm_profile_set_filename(const char *Name);
+
+/*! \brief Register to write instrumentation data to file at exit. */
+int __llvm_profile_register_write_file_atexit(void);
+
+/*! \brief Initialize file handling. */
+void __llvm_profile_initialize_file(void);
+
+/*! \brief Get the magic token for the file format. */
+uint64_t __llvm_profile_get_magic(void);
+
+/*! \brief Get the version of the file format. */
+uint64_t __llvm_profile_get_version(void);
+
+#endif /* PROFILE_INSTRPROFILING_H_ */
diff --git a/lib/profile/InstrProfilingBuffer.c b/lib/profile/InstrProfilingBuffer.c
new file mode 100644
index 000000000000..3c429c8a85ea
--- /dev/null
+++ b/lib/profile/InstrProfilingBuffer.c
@@ -0,0 +1,104 @@
+/*===- InstrProfilingBuffer.c - Write instrumentation to a memory 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>
+
+__attribute__((visibility("hidden")))
+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();
+ 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_get_size_for_buffer_internal(
+ DataBegin, DataEnd, CountersBegin, CountersEnd, NamesBegin, NamesEnd);
+}
+
+#define PROFILE_RANGE_SIZE(Range) (Range##End - Range##Begin)
+
+__attribute__((visibility("hidden")))
+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) {
+ /* 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;
+}
+
+__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);
+}
+
+__attribute__((visibility("hidden")))
+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;
+}
diff --git a/lib/profile/InstrProfilingFile.c b/lib/profile/InstrProfilingFile.c
new file mode 100644
index 000000000000..5aef3904b56d
--- /dev/null
+++ b/lib/profile/InstrProfilingFile.c
@@ -0,0 +1,194 @@
+/*===- InstrProfilingFile.c - Write instrumentation to a file -------------===*\
+|*
+|* 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#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 0;
+}
+
+static int writeFileWithName(const char *OutputName) {
+ int RetVal;
+ FILE *OutputFile;
+ if (!OutputName || !OutputName[0])
+ return -1;
+
+ /* Append to the file to support profiling multiple shared objects. */
+ OutputFile = fopen(OutputName, "a");
+ if (!OutputFile)
+ return -1;
+
+ RetVal = writeFile(OutputFile);
+
+ fclose(OutputFile);
+ return RetVal;
+}
+
+__attribute__((weak)) int __llvm_profile_OwnsFilename = 0;
+__attribute__((weak)) const char *__llvm_profile_CurrentFilename = NULL;
+
+static void setFilename(const char *Filename, int OwnsFilename) {
+ if (__llvm_profile_OwnsFilename)
+ free(UNCONST(__llvm_profile_CurrentFilename));
+
+ __llvm_profile_CurrentFilename = Filename;
+ __llvm_profile_OwnsFilename = OwnsFilename;
+}
+
+static void truncateCurrentFile(void) {
+ const char *Filename = __llvm_profile_CurrentFilename;
+ if (!Filename || !Filename[0])
+ return;
+
+ /* Truncate the file. Later we'll reopen and append. */
+ FILE *File = fopen(Filename, "w");
+ if (!File)
+ return;
+ fclose(File);
+}
+
+static void setDefaultFilename(void) { setFilename("default.profraw", 0); }
+
+int getpid(void);
+static int setFilenameFromEnvironment(void) {
+ const char *Filename = getenv("LLVM_PROFILE_FILE");
+ if (!Filename || !Filename[0])
+ return -1;
+
+ /* Check the filename for "%p", which indicates a pid-substitution. */
+#define MAX_PID_SIZE 16
+ char PidChars[MAX_PID_SIZE] = {0};
+ int NumPids = 0;
+ int PidLength = 0;
+ int I;
+ for (I = 0; Filename[I]; ++I)
+ if (Filename[I] == '%' && Filename[++I] == 'p')
+ if (!NumPids++) {
+ PidLength = snprintf(PidChars, MAX_PID_SIZE, "%d", getpid());
+ if (PidLength <= 0)
+ return -1;
+ }
+ if (!NumPids) {
+ setFilename(Filename, 0);
+ return 0;
+ }
+
+ /* Allocate enough space for the substituted filename. */
+ char *Allocated = (char*)malloc(I + NumPids*(PidLength - 2) + 1);
+ if (!Allocated)
+ return -1;
+
+ /* Construct the new filename. */
+ int J;
+ for (I = 0, J = 0; Filename[I]; ++I)
+ if (Filename[I] == '%') {
+ if (Filename[++I] == 'p') {
+ memcpy(Allocated + J, PidChars, PidLength);
+ J += PidLength;
+ }
+ /* Drop any unknown substitutions. */
+ } else
+ Allocated[J++] = Filename[I];
+ Allocated[J] = 0;
+
+ /* Use the computed name. */
+ setFilename(Allocated, 1);
+ return 0;
+}
+
+static void setFilenameAutomatically(void) {
+ if (!setFilenameFromEnvironment())
+ return;
+
+ setDefaultFilename();
+}
+
+__attribute__((visibility("hidden")))
+void __llvm_profile_initialize_file(void) {
+ /* Check if the filename has been initialized. */
+ if (__llvm_profile_CurrentFilename)
+ return;
+
+ /* Detect the filename and truncate. */
+ setFilenameAutomatically();
+ truncateCurrentFile();
+}
+
+__attribute__((visibility("hidden")))
+void __llvm_profile_set_filename(const char *Filename) {
+ setFilename(Filename, 0);
+ truncateCurrentFile();
+}
+
+__attribute__((visibility("hidden")))
+int __llvm_profile_write_file(void) {
+ /* Check the filename. */
+ if (!__llvm_profile_CurrentFilename)
+ return -1;
+
+ /* Write the file. */
+ return writeFileWithName(__llvm_profile_CurrentFilename);
+}
+
+static void writeFileWithoutReturn(void) {
+ __llvm_profile_write_file();
+}
+
+__attribute__((visibility("hidden")))
+int __llvm_profile_register_write_file_atexit(void) {
+ static int HasBeenRegistered = 0;
+
+ if (HasBeenRegistered)
+ return 0;
+
+ HasBeenRegistered = 1;
+ return atexit(writeFileWithoutReturn);
+}
diff --git a/lib/profile/InstrProfilingInternal.h b/lib/profile/InstrProfilingInternal.h
new file mode 100644
index 000000000000..ede39cd9d713
--- /dev/null
+++ b/lib/profile/InstrProfilingInternal.h
@@ -0,0 +1,40 @@
+/*===- InstrProfiling.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_INTERNALH_
+#define PROFILE_INSTRPROFILING_INTERNALH_
+
+#include "InstrProfiling.h"
+
+/*!
+ * \brief Write instrumentation data to the given buffer, given explicit
+ * pointers to the live data in memory. This function is probably not what you
+ * want. Use __llvm_profile_get_size_for_buffer instead. Use this function if
+ * your program has a custom memory layout.
+ */
+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);
+
+/*!
+ * \brief Write instrumentation data to the given buffer, given explicit
+ * pointers to the live data in memory. This function is probably not what you
+ * want. Use __llvm_profile_write_buffer instead. Use this function if your
+ * program has a custom memory layout.
+ *
+ * \pre \c Buffer is the start of a buffer at least as big as \a
+ * __llvm_profile_get_size_for_buffer_internal().
+ */
+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);
+
+#endif
diff --git a/lib/profile/InstrProfilingPlatformDarwin.c b/lib/profile/InstrProfilingPlatformDarwin.c
new file mode 100644
index 000000000000..02299cc4630c
--- /dev/null
+++ b/lib/profile/InstrProfilingPlatformDarwin.c
@@ -0,0 +1,43 @@
+/*===- InstrProfilingPlatformDarwin.c - Profile data on Darwin ------------===*\
+|*
+|* 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(__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");
+
+__attribute__((visibility("hidden")))
+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")))
+const char *__llvm_profile_begin_names(void) { return &NamesStart; }
+__attribute__((visibility("hidden")))
+const char *__llvm_profile_end_names(void) { return &NamesEnd; }
+__attribute__((visibility("hidden")))
+uint64_t *__llvm_profile_begin_counters(void) { return &CountersStart; }
+__attribute__((visibility("hidden")))
+uint64_t *__llvm_profile_end_counters(void) { return &CountersEnd; }
+#endif
diff --git a/lib/profile/InstrProfilingPlatformOther.c b/lib/profile/InstrProfilingPlatformOther.c
new file mode 100644
index 000000000000..548d6a396b76
--- /dev/null
+++ b/lib/profile/InstrProfilingPlatformOther.c
@@ -0,0 +1,74 @@
+/*===- InstrProfilingPlatformOther.c - Profile data default 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(__APPLE__)
+#include <stdlib.h>
+
+static const __llvm_profile_data *DataFirst = NULL;
+static const __llvm_profile_data *DataLast = NULL;
+static const char *NamesFirst = NULL;
+static const char *NamesLast = NULL;
+static uint64_t *CountersFirst = NULL;
+static uint64_t *CountersLast = NULL;
+
+/*!
+ * \brief Register an instrumented function.
+ *
+ * Calls to this are emitted by clang with -fprofile-instr-generate. Such
+ * 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")))
+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_;
+ if (!DataFirst) {
+ DataFirst = Data;
+ DataLast = Data + 1;
+ NamesFirst = Data->Name;
+ NamesLast = Data->Name + Data->NameSize;
+ CountersFirst = Data->Counters;
+ CountersLast = Data->Counters + Data->NumCounters;
+ return;
+ }
+
+#define UPDATE_FIRST(First, New) \
+ First = New < First ? New : First
+ UPDATE_FIRST(DataFirst, Data);
+ UPDATE_FIRST(NamesFirst, Data->Name);
+ UPDATE_FIRST(CountersFirst, Data->Counters);
+#undef UPDATE_FIRST
+
+#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);
+#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")))
+const char *__llvm_profile_begin_names(void) { return NamesFirst; }
+__attribute__((visibility("hidden")))
+const char *__llvm_profile_end_names(void) { return NamesLast; }
+__attribute__((visibility("hidden")))
+uint64_t *__llvm_profile_begin_counters(void) { return CountersFirst; }
+__attribute__((visibility("hidden")))
+uint64_t *__llvm_profile_end_counters(void) { return CountersLast; }
+#endif
diff --git a/lib/profile/InstrProfilingRuntime.cc b/lib/profile/InstrProfilingRuntime.cc
new file mode 100644
index 000000000000..081ecb29e987
--- /dev/null
+++ b/lib/profile/InstrProfilingRuntime.cc
@@ -0,0 +1,30 @@
+//===- InstrProfilingRuntime.cpp - PGO runtime initialization -------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+extern "C" {
+
+#include "InstrProfiling.h"
+
+__attribute__((visibility("hidden"))) int __llvm_profile_runtime;
+
+}
+
+namespace {
+
+class RegisterRuntime {
+public:
+ RegisterRuntime() {
+ __llvm_profile_register_write_file_atexit();
+ __llvm_profile_initialize_file();
+ }
+};
+
+RegisterRuntime Registration;
+
+}
diff --git a/lib/profile/Makefile.mk b/lib/profile/Makefile.mk
index 7689c9a068c1..dd3a36faf3b0 100644
--- a/lib/profile/Makefile.mk
+++ b/lib/profile/Makefile.mk
@@ -10,8 +10,8 @@
ModuleName := profile
SubDirs :=
-Sources := $(foreach file,$(wildcard $(Dir)/*.c),$(notdir $(file)))
-ObjNames := $(Sources:%.c=%.o)
+Sources := $(foreach file,$(wildcard $(Dir)/*.c $(Dir)/*.cc),$(notdir $(file)))
+ObjNames := $(patsubst %.c,%.o,$(patsubst %.cc,%.o,$(Sources)))
Implementation := Generic
# FIXME: use automatic dependencies?
diff --git a/lib/sanitizer_common/CMakeLists.txt b/lib/sanitizer_common/CMakeLists.txt
index 84c1e67dc806..fe4418cd3cfa 100644
--- a/lib/sanitizer_common/CMakeLists.txt
+++ b/lib/sanitizer_common/CMakeLists.txt
@@ -4,47 +4,65 @@
set(SANITIZER_SOURCES
sanitizer_allocator.cc
sanitizer_common.cc
- sanitizer_coverage.cc
+ sanitizer_deadlock_detector1.cc
+ sanitizer_deadlock_detector2.cc
sanitizer_flags.cc
sanitizer_libc.cc
sanitizer_libignore.cc
sanitizer_linux.cc
sanitizer_mac.cc
+ sanitizer_persistent_allocator.cc
sanitizer_platform_limits_linux.cc
sanitizer_platform_limits_posix.cc
sanitizer_posix.cc
sanitizer_printf.cc
+ sanitizer_procmaps_common.cc
+ sanitizer_procmaps_freebsd.cc
+ sanitizer_procmaps_linux.cc
+ sanitizer_procmaps_mac.cc
sanitizer_stackdepot.cc
sanitizer_stacktrace.cc
+ sanitizer_stacktrace_printer.cc
sanitizer_suppressions.cc
sanitizer_symbolizer.cc
+ sanitizer_symbolizer_libbacktrace.cc
sanitizer_symbolizer_win.cc
+ sanitizer_tls_get_addr.cc
sanitizer_thread_registry.cc
sanitizer_win.cc)
set(SANITIZER_LIBCDEP_SOURCES
sanitizer_common_libcdep.cc
+ sanitizer_coverage_libcdep.cc
+ sanitizer_coverage_mapping_libcdep.cc
sanitizer_linux_libcdep.cc
sanitizer_posix_libcdep.cc
sanitizer_stacktrace_libcdep.cc
sanitizer_stoptheworld_linux_libcdep.cc
sanitizer_symbolizer_libcdep.cc
- sanitizer_symbolizer_posix_libcdep.cc)
+ sanitizer_symbolizer_posix_libcdep.cc
+ sanitizer_unwind_posix_libcdep.cc)
# Explicitly list all sanitizer_common headers. Not all of these are
# included in sanitizer_common source files, but we need to depend on
# headers when building our custom unit tests.
set(SANITIZER_HEADERS
+ sanitizer_addrhashmap.h
sanitizer_allocator.h
+ sanitizer_allocator_interface.h
sanitizer_allocator_internal.h
+ sanitizer_atomic.h
sanitizer_atomic_clang.h
sanitizer_atomic_msvc.h
- sanitizer_atomic.h
+ sanitizer_bitvector.h
+ sanitizer_bvgraph.h
sanitizer_common.h
sanitizer_common_interceptors.inc
sanitizer_common_interceptors_ioctl.inc
- sanitizer_common_interceptors_scanf.inc
+ sanitizer_common_interceptors_format.inc
sanitizer_common_syscalls.inc
+ sanitizer_deadlock_detector.h
+ sanitizer_deadlock_detector_interface.h
sanitizer_flags.h
sanitizer_internal_defs.h
sanitizer_lfstack.h
@@ -52,31 +70,48 @@ set(SANITIZER_HEADERS
sanitizer_libignore.h
sanitizer_linux.h
sanitizer_list.h
+ sanitizer_mac.h
sanitizer_mutex.h
+ sanitizer_persistent_allocator.h
sanitizer_placement_new.h
+ sanitizer_platform.h
sanitizer_platform_interceptors.h
+ sanitizer_platform_limits_posix.h
sanitizer_procmaps.h
sanitizer_quarantine.h
sanitizer_report_decorator.h
sanitizer_stackdepot.h
+ sanitizer_stackdepotbase.h
sanitizer_stacktrace.h
+ sanitizer_stacktrace_printer.h
+ sanitizer_stoptheworld.h
+ sanitizer_suppressions.h
sanitizer_symbolizer.h
+ sanitizer_symbolizer_libbacktrace.h
+ sanitizer_syscall_generic.inc
+ sanitizer_syscall_linux_x86_64.inc
sanitizer_thread_registry.h)
-if (NOT MSVC)
- set(SANITIZER_CFLAGS
- ${SANITIZER_COMMON_CFLAGS}
- -fno-rtti)
+set(SANITIZER_COMMON_DEFINITIONS)
+
+if(MSVC)
+ list(APPEND SANITIZER_COMMON_DEFINITIONS
+ SANITIZER_NEEDS_SEGV=0)
else()
- set(SANITIZER_CFLAGS
- ${SANITIZER_COMMON_CFLAGS}
- /GR-)
+ list(APPEND SANITIZER_COMMON_DEFINITIONS
+ SANITIZER_NEEDS_SEGV=1)
endif()
-if(SUPPORTS_GLOBAL_CONSTRUCTORS_FLAG)
- list(APPEND SANITIZER_CFLAGS -Wglobal-constructors)
+set(SANITIZER_CFLAGS ${SANITIZER_COMMON_CFLAGS})
+append_no_rtti_flag(SANITIZER_CFLAGS)
+
+# Stack frames on PowerPC are much larger than anticipated.
+if(NOT ${LLVM_NATIVE_ARCH} STREQUAL "PowerPC")
+ append_list_if(COMPILER_RT_HAS_WFRAME_LARGER_THAN_FLAG -Wframe-larger-than=512 SANITIZER_CFLAGS)
endif()
+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.
@@ -84,32 +119,33 @@ if(APPLE)
add_compiler_rt_darwin_object_library(RTSanitizerCommon ${os}
ARCH ${SANITIZER_COMMON_SUPPORTED_ARCH}
SOURCES ${SANITIZER_SOURCES} ${SANITIZER_LIBCDEP_SOURCES}
- CFLAGS ${SANITIZER_CFLAGS})
+ CFLAGS ${SANITIZER_CFLAGS}
+ DEFS ${SANITIZER_COMMON_DEFINITIONS})
list(APPEND SANITIZER_RUNTIME_LIBRARIES RTSanitizerCommon.${os})
endforeach()
-elseif(ANDROID)
- add_library(RTSanitizerCommon.arm.android OBJECT
- ${SANITIZER_SOURCES} ${SANITIZER_LIBCDEP_SOURCES})
- set_target_compile_flags(RTSanitizerCommon.arm.android
- ${SANITIZER_CFLAGS})
- list(APPEND SANITIZER_RUNTIME_LIBRARIES RTSanitizerCommon.arm.android)
else()
# Otherwise, build separate libraries for each target.
foreach(arch ${SANITIZER_COMMON_SUPPORTED_ARCH})
add_compiler_rt_object_library(RTSanitizerCommon ${arch}
- SOURCES ${SANITIZER_SOURCES} CFLAGS ${SANITIZER_CFLAGS})
+ SOURCES ${SANITIZER_SOURCES} CFLAGS ${SANITIZER_CFLAGS}
+ DEFS ${SANITIZER_COMMON_DEFINITIONS})
add_compiler_rt_object_library(RTSanitizerCommonLibc ${arch}
- SOURCES ${SANITIZER_LIBCDEP_SOURCES} CFLAGS ${SANITIZER_CFLAGS})
- add_compiler_rt_static_runtime(clang_rt.san-${arch} ${arch}
- SOURCES $<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
- $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>
- CFLAGS ${SANITIZER_CFLAGS})
+ SOURCES ${SANITIZER_LIBCDEP_SOURCES} CFLAGS ${SANITIZER_CFLAGS}
+ DEFS ${SANITIZER_COMMON_DEFINITIONS})
list(APPEND SANITIZER_RUNTIME_LIBRARIES RTSanitizerCommon.${arch}
RTSanitizerCommonLibc.${arch})
+ add_compiler_rt_runtime(clang_rt.san-${arch} ${arch} STATIC
+ SOURCES $<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
+ $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>
+ CFLAGS ${SANITIZER_CFLAGS}
+ DEFS ${SANITIZER_COMMON_DEFINITIONS})
+ add_dependencies(sanitizer_common clang_rt.san-${arch})
endforeach()
endif()
+add_dependencies(compiler-rt sanitizer_common)
+
# Unit tests for common sanitizer runtime.
-if(LLVM_INCLUDE_TESTS)
+if(COMPILER_RT_INCLUDE_TESTS)
add_subdirectory(tests)
endif()
diff --git a/lib/sanitizer_common/sanitizer_addrhashmap.h b/lib/sanitizer_common/sanitizer_addrhashmap.h
new file mode 100644
index 000000000000..acf4ff020939
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_addrhashmap.h
@@ -0,0 +1,342 @@
+//===-- sanitizer_addrhashmap.h ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Concurrent uptr->T hashmap.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_ADDRHASHMAP_H
+#define SANITIZER_ADDRHASHMAP_H
+
+#include "sanitizer_common.h"
+#include "sanitizer_mutex.h"
+#include "sanitizer_atomic.h"
+#include "sanitizer_allocator_internal.h"
+
+namespace __sanitizer {
+
+// Concurrent uptr->T hashmap.
+// T must be a POD type, kSize is preferably a prime but can be any number.
+// Usage example:
+//
+// typedef AddrHashMap<uptr, 11> Map;
+// Map m;
+// {
+// Map::Handle h(&m, addr);
+// use h.operator->() to access the data
+// if h.created() then the element was just created, and the current thread
+// has exclusive access to it
+// otherwise the current thread has only read access to the data
+// }
+// {
+// Map::Handle h(&m, addr, true);
+// this will remove the data from the map in Handle dtor
+// the current thread has exclusive access to the data
+// if !h.exists() then the element never existed
+// }
+template<typename T, uptr kSize>
+class AddrHashMap {
+ private:
+ struct Cell {
+ atomic_uintptr_t addr;
+ T val;
+ };
+
+ struct AddBucket {
+ uptr cap;
+ uptr size;
+ Cell cells[1]; // variable len
+ };
+
+ static const uptr kBucketSize = 3;
+
+ struct Bucket {
+ RWMutex mtx;
+ atomic_uintptr_t add;
+ Cell cells[kBucketSize];
+ };
+
+ public:
+ AddrHashMap();
+
+ class Handle {
+ public:
+ Handle(AddrHashMap<T, kSize> *map, uptr addr);
+ Handle(AddrHashMap<T, kSize> *map, uptr addr, bool remove);
+ Handle(AddrHashMap<T, kSize> *map, uptr addr, bool remove, bool create);
+
+ ~Handle();
+ T *operator->();
+ bool created() const;
+ bool exists() const;
+
+ private:
+ friend AddrHashMap<T, kSize>;
+ AddrHashMap<T, kSize> *map_;
+ Bucket *bucket_;
+ Cell *cell_;
+ uptr addr_;
+ uptr addidx_;
+ bool created_;
+ bool remove_;
+ bool create_;
+ };
+
+ private:
+ friend class Handle;
+ Bucket *table_;
+
+ void acquire(Handle *h);
+ void release(Handle *h);
+ uptr calcHash(uptr addr);
+};
+
+template<typename T, uptr kSize>
+AddrHashMap<T, kSize>::Handle::Handle(AddrHashMap<T, kSize> *map, uptr addr) {
+ map_ = map;
+ addr_ = addr;
+ remove_ = false;
+ create_ = true;
+ map_->acquire(this);
+}
+
+template<typename T, uptr kSize>
+AddrHashMap<T, kSize>::Handle::Handle(AddrHashMap<T, kSize> *map, uptr addr,
+ bool remove) {
+ map_ = map;
+ addr_ = addr;
+ remove_ = remove;
+ create_ = true;
+ map_->acquire(this);
+}
+
+template<typename T, uptr kSize>
+AddrHashMap<T, kSize>::Handle::Handle(AddrHashMap<T, kSize> *map, uptr addr,
+ bool remove, bool create) {
+ map_ = map;
+ addr_ = addr;
+ remove_ = remove;
+ create_ = create;
+ map_->acquire(this);
+}
+
+template<typename T, uptr kSize>
+AddrHashMap<T, kSize>::Handle::~Handle() {
+ map_->release(this);
+}
+
+template <typename T, uptr kSize>
+T *AddrHashMap<T, kSize>::Handle::operator->() {
+ return &cell_->val;
+}
+
+template<typename T, uptr kSize>
+bool AddrHashMap<T, kSize>::Handle::created() const {
+ return created_;
+}
+
+template<typename T, uptr kSize>
+bool AddrHashMap<T, kSize>::Handle::exists() const {
+ return cell_ != 0;
+}
+
+template<typename T, uptr kSize>
+AddrHashMap<T, kSize>::AddrHashMap() {
+ table_ = (Bucket*)MmapOrDie(kSize * sizeof(table_[0]), "AddrHashMap");
+}
+
+template<typename T, uptr kSize>
+void AddrHashMap<T, kSize>::acquire(Handle *h) {
+ uptr addr = h->addr_;
+ uptr hash = calcHash(addr);
+ Bucket *b = &table_[hash];
+
+ h->created_ = false;
+ h->addidx_ = -1U;
+ h->bucket_ = b;
+ h->cell_ = 0;
+
+ // If we want to remove the element, we need exclusive access to the bucket,
+ // so skip the lock-free phase.
+ if (h->remove_)
+ goto locked;
+
+ retry:
+ // First try to find an existing element w/o read mutex.
+ CHECK(!h->remove_);
+ // Check the embed cells.
+ for (uptr i = 0; i < kBucketSize; i++) {
+ Cell *c = &b->cells[i];
+ uptr addr1 = atomic_load(&c->addr, memory_order_acquire);
+ if (addr1 == addr) {
+ h->cell_ = c;
+ return;
+ }
+ }
+
+ // Check the add cells with read lock.
+ if (atomic_load(&b->add, memory_order_relaxed)) {
+ b->mtx.ReadLock();
+ AddBucket *add = (AddBucket*)atomic_load(&b->add, memory_order_relaxed);
+ for (uptr i = 0; i < add->size; i++) {
+ Cell *c = &add->cells[i];
+ uptr addr1 = atomic_load(&c->addr, memory_order_relaxed);
+ if (addr1 == addr) {
+ h->addidx_ = i;
+ h->cell_ = c;
+ return;
+ }
+ }
+ b->mtx.ReadUnlock();
+ }
+
+ locked:
+ // Re-check existence under write lock.
+ // Embed cells.
+ b->mtx.Lock();
+ for (uptr i = 0; i < kBucketSize; i++) {
+ Cell *c = &b->cells[i];
+ uptr addr1 = atomic_load(&c->addr, memory_order_relaxed);
+ if (addr1 == addr) {
+ if (h->remove_) {
+ h->cell_ = c;
+ return;
+ }
+ b->mtx.Unlock();
+ goto retry;
+ }
+ }
+
+ // Add cells.
+ AddBucket *add = (AddBucket*)atomic_load(&b->add, memory_order_relaxed);
+ if (add) {
+ for (uptr i = 0; i < add->size; i++) {
+ Cell *c = &add->cells[i];
+ uptr addr1 = atomic_load(&c->addr, memory_order_relaxed);
+ if (addr1 == addr) {
+ if (h->remove_) {
+ h->addidx_ = i;
+ h->cell_ = c;
+ return;
+ }
+ b->mtx.Unlock();
+ goto retry;
+ }
+ }
+ }
+
+ // The element does not exist, no need to create it if we want to remove.
+ if (h->remove_ || !h->create_) {
+ b->mtx.Unlock();
+ return;
+ }
+
+ // Now try to create it under the mutex.
+ h->created_ = true;
+ // See if we have a free embed cell.
+ for (uptr i = 0; i < kBucketSize; i++) {
+ Cell *c = &b->cells[i];
+ uptr addr1 = atomic_load(&c->addr, memory_order_relaxed);
+ if (addr1 == 0) {
+ h->cell_ = c;
+ return;
+ }
+ }
+
+ // Store in the add cells.
+ if (add == 0) {
+ // Allocate a new add array.
+ const uptr kInitSize = 64;
+ add = (AddBucket*)InternalAlloc(kInitSize);
+ internal_memset(add, 0, kInitSize);
+ add->cap = (kInitSize - sizeof(*add)) / sizeof(add->cells[0]) + 1;
+ add->size = 0;
+ atomic_store(&b->add, (uptr)add, memory_order_relaxed);
+ }
+ if (add->size == add->cap) {
+ // Grow existing add array.
+ uptr oldsize = sizeof(*add) + (add->cap - 1) * sizeof(add->cells[0]);
+ uptr newsize = oldsize * 2;
+ AddBucket *add1 = (AddBucket*)InternalAlloc(newsize);
+ internal_memset(add1, 0, newsize);
+ add1->cap = (newsize - sizeof(*add)) / sizeof(add->cells[0]) + 1;
+ add1->size = add->size;
+ internal_memcpy(add1->cells, add->cells, add->size * sizeof(add->cells[0]));
+ InternalFree(add);
+ atomic_store(&b->add, (uptr)add1, memory_order_relaxed);
+ add = add1;
+ }
+ // Store.
+ uptr i = add->size++;
+ Cell *c = &add->cells[i];
+ CHECK_EQ(atomic_load(&c->addr, memory_order_relaxed), 0);
+ h->addidx_ = i;
+ h->cell_ = c;
+}
+
+template<typename T, uptr kSize>
+void AddrHashMap<T, kSize>::release(Handle *h) {
+ if (h->cell_ == 0)
+ return;
+ Bucket *b = h->bucket_;
+ Cell *c = h->cell_;
+ uptr addr1 = atomic_load(&c->addr, memory_order_relaxed);
+ if (h->created_) {
+ // Denote completion of insertion.
+ CHECK_EQ(addr1, 0);
+ // After the following store, the element becomes available
+ // for lock-free reads.
+ atomic_store(&c->addr, h->addr_, memory_order_release);
+ b->mtx.Unlock();
+ } else if (h->remove_) {
+ // Denote that the cell is empty now.
+ CHECK_EQ(addr1, h->addr_);
+ atomic_store(&c->addr, 0, memory_order_release);
+ // See if we need to compact the bucket.
+ AddBucket *add = (AddBucket*)atomic_load(&b->add, memory_order_relaxed);
+ if (h->addidx_ == -1U) {
+ // Removed from embed array, move an add element into the freed cell.
+ if (add && add->size != 0) {
+ uptr last = --add->size;
+ Cell *c1 = &add->cells[last];
+ c->val = c1->val;
+ uptr addr1 = atomic_load(&c1->addr, memory_order_relaxed);
+ atomic_store(&c->addr, addr1, memory_order_release);
+ atomic_store(&c1->addr, 0, memory_order_release);
+ }
+ } else {
+ // Removed from add array, compact it.
+ uptr last = --add->size;
+ Cell *c1 = &add->cells[last];
+ if (c != c1) {
+ *c = *c1;
+ atomic_store(&c1->addr, 0, memory_order_relaxed);
+ }
+ }
+ if (add && add->size == 0) {
+ // FIXME(dvyukov): free add?
+ }
+ b->mtx.Unlock();
+ } else {
+ CHECK_EQ(addr1, h->addr_);
+ if (h->addidx_ != -1U)
+ b->mtx.ReadUnlock();
+ }
+}
+
+template<typename T, uptr kSize>
+uptr AddrHashMap<T, kSize>::calcHash(uptr addr) {
+ addr += addr << 10;
+ addr ^= addr >> 6;
+ return addr % kSize;
+}
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_ADDRHASHMAP_H
diff --git a/lib/sanitizer_common/sanitizer_allocator.cc b/lib/sanitizer_common/sanitizer_allocator.cc
index daaf7e1ce055..47509f83665b 100644
--- a/lib/sanitizer_common/sanitizer_allocator.cc
+++ b/lib/sanitizer_common/sanitizer_allocator.cc
@@ -19,7 +19,7 @@
namespace __sanitizer {
// ThreadSanitizer for Go uses libc malloc/free.
-#if defined(SANITIZER_GO)
+#if defined(SANITIZER_GO) || defined(SANITIZER_USE_MALLOC)
# if SANITIZER_LINUX && !SANITIZER_ANDROID
extern "C" void *__libc_malloc(uptr size);
extern "C" void __libc_free(void *ptr);
@@ -117,7 +117,7 @@ void *LowLevelAllocator::Allocate(uptr size) {
if (allocated_end_ - allocated_current_ < (sptr)size) {
uptr size_to_allocate = Max(size, GetPageSizeCached());
allocated_current_ =
- (char*)MmapOrDie(size_to_allocate, __FUNCTION__);
+ (char*)MmapOrDie(size_to_allocate, __func__);
allocated_end_ = allocated_current_ + size_to_allocate;
if (low_level_alloc_callback) {
low_level_alloc_callback((uptr)allocated_current_,
diff --git a/lib/sanitizer_common/sanitizer_allocator.h b/lib/sanitizer_common/sanitizer_allocator.h
index 6075cfe92aac..23218016b791 100644
--- a/lib/sanitizer_common/sanitizer_allocator.h
+++ b/lib/sanitizer_common/sanitizer_allocator.h
@@ -198,14 +198,12 @@ template<class SizeClassAllocator> struct SizeClassAllocatorLocalCache;
// Memory allocator statistics
enum AllocatorStat {
- AllocatorStatMalloced,
- AllocatorStatFreed,
- AllocatorStatMmapped,
- AllocatorStatUnmapped,
+ AllocatorStatAllocated,
+ AllocatorStatMapped,
AllocatorStatCount
};
-typedef u64 AllocatorStatCounters[AllocatorStatCount];
+typedef uptr AllocatorStatCounters[AllocatorStatCount];
// Per-thread stats, live in per-thread cache.
class AllocatorStats {
@@ -214,16 +212,21 @@ class AllocatorStats {
internal_memset(this, 0, sizeof(*this));
}
- void Add(AllocatorStat i, u64 v) {
+ void Add(AllocatorStat i, uptr v) {
v += atomic_load(&stats_[i], memory_order_relaxed);
atomic_store(&stats_[i], v, memory_order_relaxed);
}
- void Set(AllocatorStat i, u64 v) {
+ void Sub(AllocatorStat i, uptr v) {
+ v = atomic_load(&stats_[i], memory_order_relaxed) - v;
atomic_store(&stats_[i], v, memory_order_relaxed);
}
- u64 Get(AllocatorStat i) const {
+ void Set(AllocatorStat i, uptr v) {
+ atomic_store(&stats_[i], v, memory_order_relaxed);
+ }
+
+ uptr Get(AllocatorStat i) const {
return atomic_load(&stats_[i], memory_order_relaxed);
}
@@ -231,7 +234,7 @@ class AllocatorStats {
friend class AllocatorGlobalStats;
AllocatorStats *next_;
AllocatorStats *prev_;
- atomic_uint64_t stats_[AllocatorStatCount];
+ atomic_uintptr_t stats_[AllocatorStatCount];
};
// Global stats, used for aggregation and querying.
@@ -260,7 +263,7 @@ class AllocatorGlobalStats : public AllocatorStats {
}
void Get(AllocatorStatCounters s) const {
- internal_memset(s, 0, AllocatorStatCount * sizeof(u64));
+ internal_memset(s, 0, AllocatorStatCount * sizeof(uptr));
SpinMutexLock l(&mu_);
const AllocatorStats *stats = this;
for (;;) {
@@ -270,6 +273,9 @@ class AllocatorGlobalStats : public AllocatorStats {
if (stats == this)
break;
}
+ // All stats must be non-negative.
+ for (int i = 0; i < AllocatorStatCount; i++)
+ s[i] = ((sptr)s[i]) >= 0 ? s[i] : 0;
}
private:
@@ -455,6 +461,11 @@ class SizeClassAllocator64 {
}
}
+ static uptr AdditionalSize() {
+ return RoundUpTo(sizeof(RegionInfo) * kNumClassesRounded,
+ GetPageSizeCached());
+ }
+
typedef SizeClassMap SizeClassMapT;
static const uptr kNumClasses = SizeClassMap::kNumClasses;
static const uptr kNumClassesRounded = SizeClassMap::kNumClassesRounded;
@@ -484,11 +495,6 @@ class SizeClassAllocator64 {
};
COMPILER_CHECK(sizeof(RegionInfo) >= kCacheLineSize);
- static uptr AdditionalSize() {
- return RoundUpTo(sizeof(RegionInfo) * kNumClassesRounded,
- GetPageSizeCached());
- }
-
RegionInfo *GetRegionInfo(uptr class_id) {
CHECK_LT(class_id, kNumClasses);
RegionInfo *regions = reinterpret_cast<RegionInfo*>(kSpaceBeg + kSpaceSize);
@@ -522,7 +528,7 @@ class SizeClassAllocator64 {
map_size += kUserMapSize;
CHECK_GE(region->mapped_user + map_size, end_idx);
MapWithCallback(region_beg + region->mapped_user, map_size);
- stat->Add(AllocatorStatMmapped, map_size);
+ stat->Add(AllocatorStatMapped, map_size);
region->mapped_user += map_size;
}
uptr total_count = (region->mapped_user - beg_idx - size)
@@ -587,7 +593,69 @@ class FlatByteMap {
u8 map_[kSize];
};
-// FIXME: Also implement TwoLevelByteMap.
+// TwoLevelByteMap maps integers in range [0, kSize1*kSize2) to u8 values.
+// It is implemented as a two-dimensional array: array of kSize1 pointers
+// to kSize2-byte arrays. The secondary arrays are mmaped on demand.
+// Each value is initially zero and can be set to something else only once.
+// Setting and getting values from multiple threads is safe w/o extra locking.
+template <u64 kSize1, u64 kSize2, class MapUnmapCallback = NoOpMapUnmapCallback>
+class TwoLevelByteMap {
+ public:
+ void TestOnlyInit() {
+ internal_memset(map1_, 0, sizeof(map1_));
+ mu_.Init();
+ }
+ void TestOnlyUnmap() {
+ for (uptr i = 0; i < kSize1; i++) {
+ u8 *p = Get(i);
+ if (!p) continue;
+ MapUnmapCallback().OnUnmap(reinterpret_cast<uptr>(p), kSize2);
+ UnmapOrDie(p, kSize2);
+ }
+ }
+
+ uptr size() const { return kSize1 * kSize2; }
+ uptr size1() const { return kSize1; }
+ uptr size2() const { return kSize2; }
+
+ void set(uptr idx, u8 val) {
+ CHECK_LT(idx, kSize1 * kSize2);
+ u8 *map2 = GetOrCreate(idx / kSize2);
+ CHECK_EQ(0U, map2[idx % kSize2]);
+ map2[idx % kSize2] = val;
+ }
+
+ u8 operator[] (uptr idx) const {
+ CHECK_LT(idx, kSize1 * kSize2);
+ u8 *map2 = Get(idx / kSize2);
+ if (!map2) return 0;
+ return map2[idx % kSize2];
+ }
+
+ private:
+ u8 *Get(uptr idx) const {
+ CHECK_LT(idx, kSize1);
+ return reinterpret_cast<u8 *>(
+ atomic_load(&map1_[idx], memory_order_acquire));
+ }
+
+ u8 *GetOrCreate(uptr idx) {
+ u8 *res = Get(idx);
+ if (!res) {
+ SpinMutexLock l(&mu_);
+ if (!(res = Get(idx))) {
+ res = (u8*)MmapOrDie(kSize2, "TwoLevelByteMap");
+ MapUnmapCallback().OnMap(reinterpret_cast<uptr>(res), kSize2);
+ atomic_store(&map1_[idx], reinterpret_cast<uptr>(res),
+ memory_order_release);
+ }
+ }
+ return res;
+ }
+
+ atomic_uintptr_t map1_[kSize1];
+ StaticSpinMutex mu_;
+};
// SizeClassAllocator32 -- allocator for 32-bit address space.
// This allocator can theoretically be used on 64-bit arch, but there it is less
@@ -779,7 +847,7 @@ class SizeClassAllocator32 {
uptr res = reinterpret_cast<uptr>(MmapAlignedOrDie(kRegionSize, kRegionSize,
"SizeClassAllocator32"));
MapUnmapCallback().OnMap(res, kRegionSize);
- stat->Add(AllocatorStatMmapped, kRegionSize);
+ stat->Add(AllocatorStatMapped, kRegionSize);
CHECK_EQ(0U, (res & (kRegionSize - 1)));
possible_regions.set(ComputeRegionId(res), static_cast<u8>(class_id));
return res;
@@ -845,7 +913,7 @@ struct SizeClassAllocatorLocalCache {
void *Allocate(SizeClassAllocator *allocator, uptr class_id) {
CHECK_NE(class_id, 0UL);
CHECK_LT(class_id, kNumClasses);
- stats_.Add(AllocatorStatMalloced, SizeClassMap::Size(class_id));
+ stats_.Add(AllocatorStatAllocated, SizeClassMap::Size(class_id));
PerClass *c = &per_class_[class_id];
if (UNLIKELY(c->count == 0))
Refill(allocator, class_id);
@@ -860,7 +928,7 @@ struct SizeClassAllocatorLocalCache {
// If the first allocator call on a new thread is a deallocation, then
// max_count will be zero, leading to check failure.
InitCache();
- stats_.Add(AllocatorStatFreed, SizeClassMap::Size(class_id));
+ stats_.Sub(AllocatorStatAllocated, SizeClassMap::Size(class_id));
PerClass *c = &per_class_[class_id];
CHECK_NE(c->max_count, 0UL);
if (UNLIKELY(c->count == c->max_count))
@@ -947,12 +1015,15 @@ class LargeMmapAllocator {
if (map_size < size) return AllocatorReturnNull(); // Overflow.
uptr map_beg = reinterpret_cast<uptr>(
MmapOrDie(map_size, "LargeMmapAllocator"));
+ CHECK(IsAligned(map_beg, page_size_));
MapUnmapCallback().OnMap(map_beg, map_size);
uptr map_end = map_beg + map_size;
uptr res = map_beg + page_size_;
if (res & (alignment - 1)) // Align.
res += alignment - (res & (alignment - 1));
- CHECK_EQ(0, res & (alignment - 1));
+ CHECK(IsAligned(res, alignment));
+ CHECK(IsAligned(res, page_size_));
+ CHECK_GE(res + size, map_beg);
CHECK_LE(res + size, map_end);
Header *h = GetHeader(res);
h->size = size;
@@ -971,8 +1042,8 @@ class LargeMmapAllocator {
stats.currently_allocated += map_size;
stats.max_allocated = Max(stats.max_allocated, stats.currently_allocated);
stats.by_size_log[size_log]++;
- stat->Add(AllocatorStatMalloced, map_size);
- stat->Add(AllocatorStatMmapped, map_size);
+ stat->Add(AllocatorStatAllocated, map_size);
+ stat->Add(AllocatorStatMapped, map_size);
}
return reinterpret_cast<void*>(res);
}
@@ -990,8 +1061,8 @@ class LargeMmapAllocator {
chunks_sorted_ = false;
stats.n_frees++;
stats.currently_allocated -= h->map_size;
- stat->Add(AllocatorStatFreed, h->map_size);
- stat->Add(AllocatorStatUnmapped, h->map_size);
+ stat->Sub(AllocatorStatAllocated, h->map_size);
+ stat->Sub(AllocatorStatMapped, h->map_size);
}
MapUnmapCallback().OnUnmap(h->map_beg, h->map_size);
UnmapOrDie(reinterpret_cast<void*>(h->map_beg), h->map_size);
@@ -1184,14 +1255,15 @@ class CombinedAllocator {
if (alignment > 8)
size = RoundUpTo(size, alignment);
void *res;
- if (primary_.CanAllocate(size, alignment))
+ bool from_primary = primary_.CanAllocate(size, alignment);
+ if (from_primary)
res = cache->Allocate(&primary_, primary_.ClassID(size));
else
res = secondary_.Allocate(&stats_, size, alignment);
if (alignment > 8)
CHECK_EQ(reinterpret_cast<uptr>(res) & (alignment - 1), 0);
- if (cleared && res)
- internal_memset(res, 0, size);
+ if (cleared && res && from_primary)
+ internal_bzero_aligned16(res, RoundUpTo(size, 16));
return res;
}
diff --git a/lib/sanitizer_common/sanitizer_allocator_interface.h b/lib/sanitizer_common/sanitizer_allocator_interface.h
new file mode 100644
index 000000000000..2cd924c99781
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_allocator_interface.h
@@ -0,0 +1,38 @@
+//===-- sanitizer_allocator_interface.h ------------------------- C++ -----===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Re-declaration of functions from public sanitizer allocator interface.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_ALLOCATOR_INTERFACE_H
+#define SANITIZER_ALLOCATOR_INTERFACE_H
+
+#include "sanitizer_internal_defs.h"
+
+using __sanitizer::uptr;
+
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE
+uptr __sanitizer_get_estimated_allocated_size(uptr size);
+SANITIZER_INTERFACE_ATTRIBUTE int __sanitizer_get_ownership(const void *p);
+SANITIZER_INTERFACE_ATTRIBUTE uptr
+__sanitizer_get_allocated_size(const void *p);
+SANITIZER_INTERFACE_ATTRIBUTE uptr __sanitizer_get_current_allocated_bytes();
+SANITIZER_INTERFACE_ATTRIBUTE uptr __sanitizer_get_heap_size();
+SANITIZER_INTERFACE_ATTRIBUTE uptr __sanitizer_get_free_bytes();
+SANITIZER_INTERFACE_ATTRIBUTE uptr __sanitizer_get_unmapped_bytes();
+
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+ /* OPTIONAL */ void __sanitizer_malloc_hook(void *ptr, uptr size);
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+ /* OPTIONAL */ void __sanitizer_free_hook(void *ptr);
+} // extern "C"
+
+#endif // SANITIZER_ALLOCATOR_INTERFACE_H
diff --git a/lib/sanitizer_common/sanitizer_allocator_internal.h b/lib/sanitizer_common/sanitizer_allocator_internal.h
index 5b24bfdafa36..4409fd65bf31 100644
--- a/lib/sanitizer_common/sanitizer_allocator_internal.h
+++ b/lib/sanitizer_common/sanitizer_allocator_internal.h
@@ -24,36 +24,26 @@ namespace __sanitizer {
typedef CompactSizeClassMap InternalSizeClassMap;
static const uptr kInternalAllocatorSpace = 0;
-#if SANITIZER_WORDSIZE == 32
-static const u64 kInternalAllocatorSize = (1ULL << 32);
+static const u64 kInternalAllocatorSize = SANITIZER_MMAP_RANGE_SIZE;
static const uptr kInternalAllocatorRegionSizeLog = 20;
+#if SANITIZER_WORDSIZE == 32
+static const uptr kInternalAllocatorNumRegions =
+ kInternalAllocatorSize >> kInternalAllocatorRegionSizeLog;
+typedef FlatByteMap<kInternalAllocatorNumRegions> ByteMap;
#else
-static const u64 kInternalAllocatorSize = (1ULL << 47);
-static const uptr kInternalAllocatorRegionSizeLog = 24;
-#endif
-static const uptr kInternalAllocatorFlatByteMapSize =
+static const uptr kInternalAllocatorNumRegions =
kInternalAllocatorSize >> kInternalAllocatorRegionSizeLog;
+typedef TwoLevelByteMap<(kInternalAllocatorNumRegions >> 12), 1 << 12> ByteMap;
+#endif
typedef SizeClassAllocator32<
- kInternalAllocatorSpace, kInternalAllocatorSize, 16, InternalSizeClassMap,
- kInternalAllocatorRegionSizeLog,
- FlatByteMap<kInternalAllocatorFlatByteMapSize> > PrimaryInternalAllocator;
+ kInternalAllocatorSpace, kInternalAllocatorSize, 0, InternalSizeClassMap,
+ kInternalAllocatorRegionSizeLog, ByteMap> PrimaryInternalAllocator;
typedef SizeClassAllocatorLocalCache<PrimaryInternalAllocator>
InternalAllocatorCache;
-// We don't want our internal allocator to do any map/unmap operations.
-struct CrashOnMapUnmap {
- void OnMap(uptr p, uptr size) const {
- RAW_CHECK_MSG(0, "Unexpected mmap in InternalAllocator!");
- }
- void OnUnmap(uptr p, uptr size) const {
- RAW_CHECK_MSG(0, "Unexpected munmap in InternalAllocator!");
- }
-};
-
typedef CombinedAllocator<PrimaryInternalAllocator, InternalAllocatorCache,
- LargeMmapAllocator<CrashOnMapUnmap> >
- InternalAllocator;
+ LargeMmapAllocator<> > InternalAllocator;
void *InternalAlloc(uptr size, InternalAllocatorCache *cache = 0);
void InternalFree(void *p, InternalAllocatorCache *cache = 0);
diff --git a/lib/sanitizer_common/sanitizer_asm.h b/lib/sanitizer_common/sanitizer_asm.h
new file mode 100644
index 000000000000..906012a96f11
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_asm.h
@@ -0,0 +1,40 @@
+//===-- sanitizer_asm.h -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Various support for assemebler.
+//
+//===----------------------------------------------------------------------===//
+
+// Some toolchains do not support .cfi asm directives, so we have to hide
+// them inside macros.
+#if defined(__clang__) || \
+ (defined(__GNUC__) && defined(__GCC_HAVE_DWARF2_CFI_ASM))
+ // GCC defined __GCC_HAVE_DWARF2_CFI_ASM if it supports CFI.
+ // Clang seems to support CFI by default (or not?).
+ // We need two versions of macros: for inline asm and standalone asm files.
+# define CFI_INL_ADJUST_CFA_OFFSET(n) ".cfi_adjust_cfa_offset " #n ";"
+
+# define CFI_STARTPROC .cfi_startproc
+# define CFI_ENDPROC .cfi_endproc
+# define CFI_ADJUST_CFA_OFFSET(n) .cfi_adjust_cfa_offset n
+# define CFI_REL_OFFSET(reg, n) .cfi_rel_offset reg, n
+# define CFI_DEF_CFA_REGISTER(reg) .cfi_def_cfa_register reg
+# define CFI_RESTORE(reg) .cfi_restore reg
+
+#else // No CFI
+# define CFI_INL_ADJUST_CFA_OFFSET(n)
+# define CFI_STARTPROC
+# define CFI_ENDPROC
+# define CFI_ADJUST_CFA_OFFSET(n)
+# define CFI_REL_OFFSET(reg, n)
+# define CFI_DEF_CFA_REGISTER(reg)
+# define CFI_RESTORE(reg)
+#endif
+
+
diff --git a/lib/sanitizer_common/sanitizer_atomic.h b/lib/sanitizer_common/sanitizer_atomic.h
index 61e6dfd59f99..6643c5494393 100644
--- a/lib/sanitizer_common/sanitizer_atomic.h
+++ b/lib/sanitizer_common/sanitizer_atomic.h
@@ -44,7 +44,8 @@ struct atomic_uint32_t {
struct atomic_uint64_t {
typedef u64 Type;
- volatile Type val_dont_use;
+ // On 32-bit platforms u64 is not necessary aligned on 8 bytes.
+ volatile ALIGNED(8) Type val_dont_use;
};
struct atomic_uintptr_t {
diff --git a/lib/sanitizer_common/sanitizer_atomic_clang.h b/lib/sanitizer_common/sanitizer_atomic_clang.h
index c5aa939b58c4..38363e875560 100644
--- a/lib/sanitizer_common/sanitizer_atomic_clang.h
+++ b/lib/sanitizer_common/sanitizer_atomic_clang.h
@@ -15,8 +15,26 @@
#ifndef SANITIZER_ATOMIC_CLANG_H
#define SANITIZER_ATOMIC_CLANG_H
+#if defined(__i386__) || defined(__x86_64__)
+# include "sanitizer_atomic_clang_x86.h"
+#else
+# include "sanitizer_atomic_clang_other.h"
+#endif
+
namespace __sanitizer {
+// We would like to just use compiler builtin atomic operations
+// for loads and stores, but they are mostly broken in clang:
+// - they lead to vastly inefficient code generation
+// (http://llvm.org/bugs/show_bug.cgi?id=17281)
+// - 64-bit atomic operations are not implemented on x86_32
+// (http://llvm.org/bugs/show_bug.cgi?id=15034)
+// - they are not implemented on ARM
+// error: undefined reference to '__atomic_load_4'
+
+// See http://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html
+// for mappings of the memory model to different processors.
+
INLINE void atomic_signal_fence(memory_order) {
__asm__ __volatile__("" ::: "memory");
}
@@ -25,59 +43,6 @@ INLINE void atomic_thread_fence(memory_order) {
__sync_synchronize();
}
-INLINE void proc_yield(int cnt) {
- __asm__ __volatile__("" ::: "memory");
-#if defined(__i386__) || defined(__x86_64__)
- for (int i = 0; i < cnt; i++)
- __asm__ __volatile__("pause");
-#endif
- __asm__ __volatile__("" ::: "memory");
-}
-
-template<typename T>
-INLINE typename T::Type atomic_load(
- const volatile T *a, memory_order mo) {
- DCHECK(mo & (memory_order_relaxed | memory_order_consume
- | memory_order_acquire | memory_order_seq_cst));
- DCHECK(!((uptr)a % sizeof(*a)));
- typename T::Type v;
- // FIXME:
- // 64-bit atomic operations are not atomic on 32-bit platforms.
- // The implementation lacks necessary memory fences on ARM/PPC.
- // We would like to use compiler builtin atomic operations,
- // but they are mostly broken:
- // - they lead to vastly inefficient code generation
- // (http://llvm.org/bugs/show_bug.cgi?id=17281)
- // - 64-bit atomic operations are not implemented on x86_32
- // (http://llvm.org/bugs/show_bug.cgi?id=15034)
- // - they are not implemented on ARM
- // error: undefined reference to '__atomic_load_4'
- if (mo == memory_order_relaxed) {
- v = a->val_dont_use;
- } else {
- atomic_signal_fence(memory_order_seq_cst);
- v = a->val_dont_use;
- atomic_signal_fence(memory_order_seq_cst);
- }
- return v;
-}
-
-template<typename T>
-INLINE void atomic_store(volatile T *a, typename T::Type v, memory_order mo) {
- DCHECK(mo & (memory_order_relaxed | memory_order_release
- | memory_order_seq_cst));
- DCHECK(!((uptr)a % sizeof(*a)));
- if (mo == memory_order_relaxed) {
- a->val_dont_use = v;
- } else {
- atomic_signal_fence(memory_order_seq_cst);
- a->val_dont_use = v;
- atomic_signal_fence(memory_order_seq_cst);
- }
- if (mo == memory_order_seq_cst)
- atomic_thread_fence(memory_order_seq_cst);
-}
-
template<typename T>
INLINE typename T::Type atomic_fetch_add(volatile T *a,
typename T::Type v, memory_order mo) {
diff --git a/lib/sanitizer_common/sanitizer_atomic_clang_other.h b/lib/sanitizer_common/sanitizer_atomic_clang_other.h
new file mode 100644
index 000000000000..099b9f7ec8c6
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_atomic_clang_other.h
@@ -0,0 +1,97 @@
+//===-- sanitizer_atomic_clang_other.h --------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of ThreadSanitizer/AddressSanitizer runtime.
+// Not intended for direct inclusion. Include sanitizer_atomic.h.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_ATOMIC_CLANG_OTHER_H
+#define SANITIZER_ATOMIC_CLANG_OTHER_H
+
+namespace __sanitizer {
+
+INLINE void proc_yield(int cnt) {
+ __asm__ __volatile__("" ::: "memory");
+}
+
+template<typename T>
+INLINE typename T::Type atomic_load(
+ const volatile T *a, memory_order mo) {
+ DCHECK(mo & (memory_order_relaxed | memory_order_consume
+ | memory_order_acquire | memory_order_seq_cst));
+ DCHECK(!((uptr)a % sizeof(*a)));
+ typename T::Type v;
+
+ if (sizeof(*a) < 8 || sizeof(void*) == 8) {
+ // Assume that aligned loads are atomic.
+ if (mo == memory_order_relaxed) {
+ v = a->val_dont_use;
+ } else if (mo == memory_order_consume) {
+ // Assume that processor respects data dependencies
+ // (and that compiler won't break them).
+ __asm__ __volatile__("" ::: "memory");
+ v = a->val_dont_use;
+ __asm__ __volatile__("" ::: "memory");
+ } else if (mo == memory_order_acquire) {
+ __asm__ __volatile__("" ::: "memory");
+ v = a->val_dont_use;
+ __sync_synchronize();
+ } else { // seq_cst
+ // E.g. on POWER we need a hw fence even before the store.
+ __sync_synchronize();
+ v = a->val_dont_use;
+ __sync_synchronize();
+ }
+ } else {
+ // 64-bit load on 32-bit platform.
+ // Gross, but simple and reliable.
+ // Assume that it is not in read-only memory.
+ v = __sync_fetch_and_add(
+ const_cast<typename T::Type volatile *>(&a->val_dont_use), 0);
+ }
+ return v;
+}
+
+template<typename T>
+INLINE void atomic_store(volatile T *a, typename T::Type v, memory_order mo) {
+ DCHECK(mo & (memory_order_relaxed | memory_order_release
+ | memory_order_seq_cst));
+ DCHECK(!((uptr)a % sizeof(*a)));
+
+ if (sizeof(*a) < 8 || sizeof(void*) == 8) {
+ // Assume that aligned loads are atomic.
+ if (mo == memory_order_relaxed) {
+ a->val_dont_use = v;
+ } else if (mo == memory_order_release) {
+ __sync_synchronize();
+ a->val_dont_use = v;
+ __asm__ __volatile__("" ::: "memory");
+ } else { // seq_cst
+ __sync_synchronize();
+ a->val_dont_use = v;
+ __sync_synchronize();
+ }
+ } else {
+ // 64-bit store on 32-bit platform.
+ // Gross, but simple and reliable.
+ typename T::Type cmp = a->val_dont_use;
+ typename T::Type cur;
+ for (;;) {
+ cur = __sync_val_compare_and_swap(&a->val_dont_use, cmp, v);
+ if (cmp == v)
+ break;
+ cmp = cur;
+ }
+ }
+}
+
+} // namespace __sanitizer
+
+#endif // #ifndef SANITIZER_ATOMIC_CLANG_OTHER_H
diff --git a/lib/sanitizer_common/sanitizer_atomic_clang_x86.h b/lib/sanitizer_common/sanitizer_atomic_clang_x86.h
new file mode 100644
index 000000000000..38feb29287f1
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_atomic_clang_x86.h
@@ -0,0 +1,116 @@
+//===-- sanitizer_atomic_clang_x86.h ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of ThreadSanitizer/AddressSanitizer runtime.
+// Not intended for direct inclusion. Include sanitizer_atomic.h.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_ATOMIC_CLANG_X86_H
+#define SANITIZER_ATOMIC_CLANG_X86_H
+
+namespace __sanitizer {
+
+INLINE void proc_yield(int cnt) {
+ __asm__ __volatile__("" ::: "memory");
+ for (int i = 0; i < cnt; i++)
+ __asm__ __volatile__("pause");
+ __asm__ __volatile__("" ::: "memory");
+}
+
+template<typename T>
+INLINE typename T::Type atomic_load(
+ const volatile T *a, memory_order mo) {
+ DCHECK(mo & (memory_order_relaxed | memory_order_consume
+ | memory_order_acquire | memory_order_seq_cst));
+ DCHECK(!((uptr)a % sizeof(*a)));
+ typename T::Type v;
+
+ if (sizeof(*a) < 8 || sizeof(void*) == 8) {
+ // Assume that aligned loads are atomic.
+ if (mo == memory_order_relaxed) {
+ v = a->val_dont_use;
+ } else if (mo == memory_order_consume) {
+ // Assume that processor respects data dependencies
+ // (and that compiler won't break them).
+ __asm__ __volatile__("" ::: "memory");
+ v = a->val_dont_use;
+ __asm__ __volatile__("" ::: "memory");
+ } else if (mo == memory_order_acquire) {
+ __asm__ __volatile__("" ::: "memory");
+ v = a->val_dont_use;
+ // On x86 loads are implicitly acquire.
+ __asm__ __volatile__("" ::: "memory");
+ } else { // seq_cst
+ // On x86 plain MOV is enough for seq_cst store.
+ __asm__ __volatile__("" ::: "memory");
+ v = a->val_dont_use;
+ __asm__ __volatile__("" ::: "memory");
+ }
+ } else {
+ // 64-bit load on 32-bit platform.
+ __asm__ __volatile__(
+ "movq %1, %%mm0;" // Use mmx reg for 64-bit atomic moves
+ "movq %%mm0, %0;" // (ptr could be read-only)
+ "emms;" // Empty mmx state/Reset FP regs
+ : "=m" (v)
+ : "m" (a->val_dont_use)
+ : // mark the FP stack and mmx registers as clobbered
+ "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)",
+#ifdef __MMX__
+ "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
+#endif // #ifdef __MMX__
+ "memory");
+ }
+ return v;
+}
+
+template<typename T>
+INLINE void atomic_store(volatile T *a, typename T::Type v, memory_order mo) {
+ DCHECK(mo & (memory_order_relaxed | memory_order_release
+ | memory_order_seq_cst));
+ DCHECK(!((uptr)a % sizeof(*a)));
+
+ if (sizeof(*a) < 8 || sizeof(void*) == 8) {
+ // Assume that aligned loads are atomic.
+ if (mo == memory_order_relaxed) {
+ a->val_dont_use = v;
+ } else if (mo == memory_order_release) {
+ // On x86 stores are implicitly release.
+ __asm__ __volatile__("" ::: "memory");
+ a->val_dont_use = v;
+ __asm__ __volatile__("" ::: "memory");
+ } else { // seq_cst
+ // On x86 stores are implicitly release.
+ __asm__ __volatile__("" ::: "memory");
+ a->val_dont_use = v;
+ __sync_synchronize();
+ }
+ } else {
+ // 64-bit store on 32-bit platform.
+ __asm__ __volatile__(
+ "movq %1, %%mm0;" // Use mmx reg for 64-bit atomic moves
+ "movq %%mm0, %0;"
+ "emms;" // Empty mmx state/Reset FP regs
+ : "=m" (a->val_dont_use)
+ : "m" (v)
+ : // mark the FP stack and mmx registers as clobbered
+ "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)",
+#ifdef __MMX__
+ "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
+#endif // #ifdef __MMX__
+ "memory");
+ if (mo == memory_order_seq_cst)
+ __sync_synchronize();
+ }
+}
+
+} // namespace __sanitizer
+
+#endif // #ifndef SANITIZER_ATOMIC_CLANG_X86_H
diff --git a/lib/sanitizer_common/sanitizer_atomic_msvc.h b/lib/sanitizer_common/sanitizer_atomic_msvc.h
index dc22ef05e589..12ffef3ba105 100644
--- a/lib/sanitizer_common/sanitizer_atomic_msvc.h
+++ b/lib/sanitizer_common/sanitizer_atomic_msvc.h
@@ -24,30 +24,29 @@ extern "C" void _mm_pause();
extern "C" long _InterlockedExchangeAdd( // NOLINT
long volatile * Addend, long Value); // NOLINT
#pragma intrinsic(_InterlockedExchangeAdd)
-
-#ifdef _WIN64
+extern "C" short _InterlockedCompareExchange16( // NOLINT
+ short volatile *Destination, // NOLINT
+ short Exchange, short Comparand); // NOLINT
+#pragma intrinsic(_InterlockedCompareExchange16)
+extern "C"
+long long _InterlockedCompareExchange64( // NOLINT
+ long long volatile *Destination, // NOLINT
+ long long Exchange, long long Comparand); // NOLINT
+#pragma intrinsic(_InterlockedCompareExchange64)
extern "C" void *_InterlockedCompareExchangePointer(
void *volatile *Destination,
void *Exchange, void *Comparand);
#pragma intrinsic(_InterlockedCompareExchangePointer)
-#else
-// There's no _InterlockedCompareExchangePointer intrinsic on x86,
-// so call _InterlockedCompareExchange instead.
extern "C"
long __cdecl _InterlockedCompareExchange( // NOLINT
long volatile *Destination, // NOLINT
long Exchange, long Comparand); // NOLINT
#pragma intrinsic(_InterlockedCompareExchange)
-inline static void *_InterlockedCompareExchangePointer(
- void *volatile *Destination,
- void *Exchange, void *Comparand) {
- return reinterpret_cast<void*>(
- _InterlockedCompareExchange(
- reinterpret_cast<long volatile*>(Destination), // NOLINT
- reinterpret_cast<long>(Exchange), // NOLINT
- reinterpret_cast<long>(Comparand))); // NOLINT
-}
+#ifdef _WIN64
+extern "C" long long _InterlockedExchangeAdd64( // NOLINT
+ long long volatile * Addend, long long Value); // NOLINT
+#pragma intrinsic(_InterlockedExchangeAdd64)
#endif
namespace __sanitizer {
@@ -108,6 +107,40 @@ INLINE u32 atomic_fetch_add(volatile atomic_uint32_t *a,
(volatile long*)&a->val_dont_use, (long)v); // NOLINT
}
+INLINE uptr atomic_fetch_add(volatile atomic_uintptr_t *a,
+ uptr v, memory_order mo) {
+ (void)mo;
+ DCHECK(!((uptr)a % sizeof(*a)));
+#ifdef _WIN64
+ return (uptr)_InterlockedExchangeAdd64(
+ (volatile long long*)&a->val_dont_use, (long long)v); // NOLINT
+#else
+ return (uptr)_InterlockedExchangeAdd(
+ (volatile long*)&a->val_dont_use, (long)v); // NOLINT
+#endif
+}
+
+INLINE u32 atomic_fetch_sub(volatile atomic_uint32_t *a,
+ u32 v, memory_order mo) {
+ (void)mo;
+ DCHECK(!((uptr)a % sizeof(*a)));
+ return (u32)_InterlockedExchangeAdd(
+ (volatile long*)&a->val_dont_use, -(long)v); // NOLINT
+}
+
+INLINE uptr atomic_fetch_sub(volatile atomic_uintptr_t *a,
+ uptr v, memory_order mo) {
+ (void)mo;
+ DCHECK(!((uptr)a % sizeof(*a)));
+#ifdef _WIN64
+ return (uptr)_InterlockedExchangeAdd64(
+ (volatile long long*)&a->val_dont_use, -(long long)v); // NOLINT
+#else
+ return (uptr)_InterlockedExchangeAdd(
+ (volatile long*)&a->val_dont_use, -(long)v); // NOLINT
+#endif
+}
+
INLINE u8 atomic_exchange(volatile atomic_uint8_t *a,
u8 v, memory_order mo) {
(void)mo;
@@ -168,6 +201,45 @@ INLINE bool atomic_compare_exchange_strong(volatile atomic_uintptr_t *a,
return false;
}
+INLINE bool atomic_compare_exchange_strong(volatile atomic_uint16_t *a,
+ u16 *cmp,
+ u16 xchg,
+ memory_order mo) {
+ u16 cmpv = *cmp;
+ u16 prev = (u16)_InterlockedCompareExchange16(
+ (volatile short*)&a->val_dont_use, (short)xchg, (short)cmpv);
+ if (prev == cmpv)
+ return true;
+ *cmp = prev;
+ return false;
+}
+
+INLINE bool atomic_compare_exchange_strong(volatile atomic_uint32_t *a,
+ u32 *cmp,
+ u32 xchg,
+ memory_order mo) {
+ u32 cmpv = *cmp;
+ u32 prev = (u32)_InterlockedCompareExchange(
+ (volatile long*)&a->val_dont_use, (long)xchg, (long)cmpv);
+ if (prev == cmpv)
+ return true;
+ *cmp = prev;
+ return false;
+}
+
+INLINE bool atomic_compare_exchange_strong(volatile atomic_uint64_t *a,
+ u64 *cmp,
+ u64 xchg,
+ memory_order mo) {
+ u64 cmpv = *cmp;
+ u64 prev = (u64)_InterlockedCompareExchange64(
+ (volatile long long*)&a->val_dont_use, (long long)xchg, (long long)cmpv);
+ if (prev == cmpv)
+ return true;
+ *cmp = prev;
+ return false;
+}
+
template<typename T>
INLINE bool atomic_compare_exchange_weak(volatile T *a,
typename T::Type *cmp,
diff --git a/lib/sanitizer_common/sanitizer_bitvector.h b/lib/sanitizer_common/sanitizer_bitvector.h
new file mode 100644
index 000000000000..d8472732ff21
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_bitvector.h
@@ -0,0 +1,351 @@
+//===-- sanitizer_bitvector.h -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Specializer BitVector implementation.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_BITVECTOR_H
+#define SANITIZER_BITVECTOR_H
+
+#include "sanitizer_common.h"
+
+namespace __sanitizer {
+
+// Fixed size bit vector based on a single basic integer.
+template <class basic_int_t = uptr>
+class BasicBitVector {
+ public:
+ enum SizeEnum { kSize = sizeof(basic_int_t) * 8 };
+
+ uptr size() const { return kSize; }
+ // No CTOR.
+ void clear() { bits_ = 0; }
+ void setAll() { bits_ = ~(basic_int_t)0; }
+ bool empty() const { return bits_ == 0; }
+
+ // Returns true if the bit has changed from 0 to 1.
+ bool setBit(uptr idx) {
+ basic_int_t old = bits_;
+ bits_ |= mask(idx);
+ return bits_ != old;
+ }
+
+ // Returns true if the bit has changed from 1 to 0.
+ bool clearBit(uptr idx) {
+ basic_int_t old = bits_;
+ bits_ &= ~mask(idx);
+ return bits_ != old;
+ }
+
+ bool getBit(uptr idx) const { return (bits_ & mask(idx)) != 0; }
+
+ uptr getAndClearFirstOne() {
+ CHECK(!empty());
+ uptr idx = LeastSignificantSetBitIndex(bits_);
+ clearBit(idx);
+ return idx;
+ }
+
+ // Do "this |= v" and return whether new bits have been added.
+ bool setUnion(const BasicBitVector &v) {
+ basic_int_t old = bits_;
+ bits_ |= v.bits_;
+ return bits_ != old;
+ }
+
+ // Do "this &= v" and return whether any bits have been removed.
+ bool setIntersection(const BasicBitVector &v) {
+ basic_int_t old = bits_;
+ bits_ &= v.bits_;
+ return bits_ != old;
+ }
+
+ // Do "this &= ~v" and return whether any bits have been removed.
+ bool setDifference(const BasicBitVector &v) {
+ basic_int_t old = bits_;
+ bits_ &= ~v.bits_;
+ return bits_ != old;
+ }
+
+ void copyFrom(const BasicBitVector &v) { bits_ = v.bits_; }
+
+ // Returns true if 'this' intersects with 'v'.
+ bool intersectsWith(const BasicBitVector &v) const {
+ return (bits_ & v.bits_) != 0;
+ }
+
+ // for (BasicBitVector<>::Iterator it(bv); it.hasNext();) {
+ // uptr idx = it.next();
+ // use(idx);
+ // }
+ class Iterator {
+ public:
+ Iterator() { }
+ explicit Iterator(const BasicBitVector &bv) : bv_(bv) {}
+ bool hasNext() const { return !bv_.empty(); }
+ uptr next() { return bv_.getAndClearFirstOne(); }
+ void clear() { bv_.clear(); }
+ private:
+ BasicBitVector bv_;
+ };
+
+ private:
+ basic_int_t mask(uptr idx) const {
+ CHECK_LT(idx, size());
+ return (basic_int_t)1UL << idx;
+ }
+ basic_int_t bits_;
+};
+
+// Fixed size bit vector of (kLevel1Size*BV::kSize**2) bits.
+// The implementation is optimized for better performance on
+// sparse bit vectors, i.e. the those with few set bits.
+template <uptr kLevel1Size = 1, class BV = BasicBitVector<> >
+class TwoLevelBitVector {
+ // This is essentially a 2-level bit vector.
+ // Set bit in the first level BV indicates that there are set bits
+ // in the corresponding BV of the second level.
+ // This structure allows O(kLevel1Size) time for clear() and empty(),
+ // as well fast handling of sparse BVs.
+ public:
+ enum SizeEnum { kSize = BV::kSize * BV::kSize * kLevel1Size };
+ // No CTOR.
+
+ uptr size() const { return kSize; }
+
+ void clear() {
+ for (uptr i = 0; i < kLevel1Size; i++)
+ l1_[i].clear();
+ }
+
+ void setAll() {
+ for (uptr i0 = 0; i0 < kLevel1Size; i0++) {
+ l1_[i0].setAll();
+ for (uptr i1 = 0; i1 < BV::kSize; i1++)
+ l2_[i0][i1].setAll();
+ }
+ }
+
+ bool empty() const {
+ for (uptr i = 0; i < kLevel1Size; i++)
+ if (!l1_[i].empty())
+ return false;
+ return true;
+ }
+
+ // Returns true if the bit has changed from 0 to 1.
+ bool setBit(uptr idx) {
+ check(idx);
+ uptr i0 = idx0(idx);
+ uptr i1 = idx1(idx);
+ uptr i2 = idx2(idx);
+ if (!l1_[i0].getBit(i1)) {
+ l1_[i0].setBit(i1);
+ l2_[i0][i1].clear();
+ }
+ bool res = l2_[i0][i1].setBit(i2);
+ // Printf("%s: %zd => %zd %zd %zd; %d\n", __func__,
+ // idx, i0, i1, i2, res);
+ return res;
+ }
+
+ bool clearBit(uptr idx) {
+ check(idx);
+ uptr i0 = idx0(idx);
+ uptr i1 = idx1(idx);
+ uptr i2 = idx2(idx);
+ bool res = false;
+ if (l1_[i0].getBit(i1)) {
+ res = l2_[i0][i1].clearBit(i2);
+ if (l2_[i0][i1].empty())
+ l1_[i0].clearBit(i1);
+ }
+ return res;
+ }
+
+ bool getBit(uptr idx) const {
+ check(idx);
+ uptr i0 = idx0(idx);
+ uptr i1 = idx1(idx);
+ uptr i2 = idx2(idx);
+ // Printf("%s: %zd => %zd %zd %zd\n", __func__, idx, i0, i1, i2);
+ return l1_[i0].getBit(i1) && l2_[i0][i1].getBit(i2);
+ }
+
+ uptr getAndClearFirstOne() {
+ for (uptr i0 = 0; i0 < kLevel1Size; i0++) {
+ if (l1_[i0].empty()) continue;
+ uptr i1 = l1_[i0].getAndClearFirstOne();
+ uptr i2 = l2_[i0][i1].getAndClearFirstOne();
+ if (!l2_[i0][i1].empty())
+ l1_[i0].setBit(i1);
+ uptr res = i0 * BV::kSize * BV::kSize + i1 * BV::kSize + i2;
+ // Printf("getAndClearFirstOne: %zd %zd %zd => %zd\n", i0, i1, i2, res);
+ return res;
+ }
+ CHECK(0);
+ return 0;
+ }
+
+ // Do "this |= v" and return whether new bits have been added.
+ bool setUnion(const TwoLevelBitVector &v) {
+ bool res = false;
+ for (uptr i0 = 0; i0 < kLevel1Size; i0++) {
+ BV t = v.l1_[i0];
+ while (!t.empty()) {
+ uptr i1 = t.getAndClearFirstOne();
+ if (l1_[i0].setBit(i1))
+ l2_[i0][i1].clear();
+ if (l2_[i0][i1].setUnion(v.l2_[i0][i1]))
+ res = true;
+ }
+ }
+ return res;
+ }
+
+ // Do "this &= v" and return whether any bits have been removed.
+ bool setIntersection(const TwoLevelBitVector &v) {
+ bool res = false;
+ for (uptr i0 = 0; i0 < kLevel1Size; i0++) {
+ if (l1_[i0].setIntersection(v.l1_[i0]))
+ res = true;
+ if (!l1_[i0].empty()) {
+ BV t = l1_[i0];
+ while (!t.empty()) {
+ uptr i1 = t.getAndClearFirstOne();
+ if (l2_[i0][i1].setIntersection(v.l2_[i0][i1]))
+ res = true;
+ if (l2_[i0][i1].empty())
+ l1_[i0].clearBit(i1);
+ }
+ }
+ }
+ return res;
+ }
+
+ // Do "this &= ~v" and return whether any bits have been removed.
+ bool setDifference(const TwoLevelBitVector &v) {
+ bool res = false;
+ for (uptr i0 = 0; i0 < kLevel1Size; i0++) {
+ BV t = l1_[i0];
+ t.setIntersection(v.l1_[i0]);
+ while (!t.empty()) {
+ uptr i1 = t.getAndClearFirstOne();
+ if (l2_[i0][i1].setDifference(v.l2_[i0][i1]))
+ res = true;
+ if (l2_[i0][i1].empty())
+ l1_[i0].clearBit(i1);
+ }
+ }
+ return res;
+ }
+
+ void copyFrom(const TwoLevelBitVector &v) {
+ clear();
+ setUnion(v);
+ }
+
+ // Returns true if 'this' intersects with 'v'.
+ bool intersectsWith(const TwoLevelBitVector &v) const {
+ for (uptr i0 = 0; i0 < kLevel1Size; i0++) {
+ BV t = l1_[i0];
+ t.setIntersection(v.l1_[i0]);
+ while (!t.empty()) {
+ uptr i1 = t.getAndClearFirstOne();
+ if (!v.l1_[i0].getBit(i1)) continue;
+ if (l2_[i0][i1].intersectsWith(v.l2_[i0][i1]))
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // for (TwoLevelBitVector<>::Iterator it(bv); it.hasNext();) {
+ // uptr idx = it.next();
+ // use(idx);
+ // }
+ class Iterator {
+ public:
+ Iterator() { }
+ explicit Iterator(const TwoLevelBitVector &bv) : bv_(bv), i0_(0), i1_(0) {
+ it1_.clear();
+ it2_.clear();
+ }
+
+ bool hasNext() const {
+ if (it1_.hasNext()) return true;
+ for (uptr i = i0_; i < kLevel1Size; i++)
+ if (!bv_.l1_[i].empty()) return true;
+ return false;
+ }
+
+ uptr next() {
+ // Printf("++++: %zd %zd; %d %d; size %zd\n", i0_, i1_, it1_.hasNext(),
+ // it2_.hasNext(), kSize);
+ if (!it1_.hasNext() && !it2_.hasNext()) {
+ for (; i0_ < kLevel1Size; i0_++) {
+ if (bv_.l1_[i0_].empty()) continue;
+ it1_ = typename BV::Iterator(bv_.l1_[i0_]);
+ // Printf("+i0: %zd %zd; %d %d; size %zd\n", i0_, i1_, it1_.hasNext(),
+ // it2_.hasNext(), kSize);
+ break;
+ }
+ }
+ if (!it2_.hasNext()) {
+ CHECK(it1_.hasNext());
+ i1_ = it1_.next();
+ it2_ = typename BV::Iterator(bv_.l2_[i0_][i1_]);
+ // Printf("++i1: %zd %zd; %d %d; size %zd\n", i0_, i1_, it1_.hasNext(),
+ // it2_.hasNext(), kSize);
+ }
+ CHECK(it2_.hasNext());
+ uptr i2 = it2_.next();
+ uptr res = i0_ * BV::kSize * BV::kSize + i1_ * BV::kSize + i2;
+ // Printf("+ret: %zd %zd; %d %d; size %zd; res: %zd\n", i0_, i1_,
+ // it1_.hasNext(), it2_.hasNext(), kSize, res);
+ if (!it1_.hasNext() && !it2_.hasNext())
+ i0_++;
+ return res;
+ }
+
+ private:
+ const TwoLevelBitVector &bv_;
+ uptr i0_, i1_;
+ typename BV::Iterator it1_, it2_;
+ };
+
+ private:
+ void check(uptr idx) const { CHECK_LE(idx, size()); }
+
+ uptr idx0(uptr idx) const {
+ uptr res = idx / (BV::kSize * BV::kSize);
+ CHECK_LE(res, kLevel1Size);
+ return res;
+ }
+
+ uptr idx1(uptr idx) const {
+ uptr res = (idx / BV::kSize) % BV::kSize;
+ CHECK_LE(res, BV::kSize);
+ return res;
+ }
+
+ uptr idx2(uptr idx) const {
+ uptr res = idx % BV::kSize;
+ CHECK_LE(res, BV::kSize);
+ return res;
+ }
+
+ BV l1_[kLevel1Size];
+ BV l2_[kLevel1Size][BV::kSize];
+};
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_BITVECTOR_H
diff --git a/lib/sanitizer_common/sanitizer_bvgraph.h b/lib/sanitizer_common/sanitizer_bvgraph.h
new file mode 100644
index 000000000000..df72f1c2d471
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_bvgraph.h
@@ -0,0 +1,165 @@
+//===-- sanitizer_bvgraph.h -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of Sanitizer runtime.
+// BVGraph -- a directed graph.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_BVGRAPH_H
+#define SANITIZER_BVGRAPH_H
+
+#include "sanitizer_common.h"
+#include "sanitizer_bitvector.h"
+
+namespace __sanitizer {
+
+// Directed graph of fixed size implemented as an array of bit vectors.
+// Not thread-safe, all accesses should be protected by an external lock.
+template<class BV>
+class BVGraph {
+ public:
+ enum SizeEnum { kSize = BV::kSize };
+ uptr size() const { return kSize; }
+ // No CTOR.
+ void clear() {
+ for (uptr i = 0; i < size(); i++)
+ v[i].clear();
+ }
+
+ bool empty() const {
+ for (uptr i = 0; i < size(); i++)
+ if (!v[i].empty())
+ return false;
+ return true;
+ }
+
+ // Returns true if a new edge was added.
+ bool addEdge(uptr from, uptr to) {
+ check(from, to);
+ return v[from].setBit(to);
+ }
+
+ // Returns true if at least one new edge was added.
+ uptr addEdges(const BV &from, uptr to, uptr added_edges[],
+ uptr max_added_edges) {
+ uptr res = 0;
+ t1.copyFrom(from);
+ while (!t1.empty()) {
+ uptr node = t1.getAndClearFirstOne();
+ if (v[node].setBit(to))
+ if (res < max_added_edges)
+ added_edges[res++] = node;
+ }
+ return res;
+ }
+
+ // *EXPERIMENTAL*
+ // Returns true if an edge from=>to exist.
+ // This function does not use any global state except for 'this' itself,
+ // and thus can be called from different threads w/o locking.
+ // This would be racy.
+ // FIXME: investigate how much we can prove about this race being "benign".
+ bool hasEdge(uptr from, uptr to) { return v[from].getBit(to); }
+
+ // Returns true if the edge from=>to was removed.
+ bool removeEdge(uptr from, uptr to) {
+ return v[from].clearBit(to);
+ }
+
+ // Returns true if at least one edge *=>to was removed.
+ bool removeEdgesTo(const BV &to) {
+ bool res = 0;
+ for (uptr from = 0; from < size(); from++) {
+ if (v[from].setDifference(to))
+ res = true;
+ }
+ return res;
+ }
+
+ // Returns true if at least one edge from=>* was removed.
+ bool removeEdgesFrom(const BV &from) {
+ bool res = false;
+ t1.copyFrom(from);
+ while (!t1.empty()) {
+ uptr idx = t1.getAndClearFirstOne();
+ if (!v[idx].empty()) {
+ v[idx].clear();
+ res = true;
+ }
+ }
+ return res;
+ }
+
+ void removeEdgesFrom(uptr from) {
+ return v[from].clear();
+ }
+
+ bool hasEdge(uptr from, uptr to) const {
+ check(from, to);
+ return v[from].getBit(to);
+ }
+
+ // Returns true if there is a path from the node 'from'
+ // to any of the nodes in 'targets'.
+ bool isReachable(uptr from, const BV &targets) {
+ BV &to_visit = t1,
+ &visited = t2;
+ to_visit.copyFrom(v[from]);
+ visited.clear();
+ visited.setBit(from);
+ while (!to_visit.empty()) {
+ uptr idx = to_visit.getAndClearFirstOne();
+ if (visited.setBit(idx))
+ to_visit.setUnion(v[idx]);
+ }
+ return targets.intersectsWith(visited);
+ }
+
+ // Finds a path from 'from' to one of the nodes in 'target',
+ // stores up to 'path_size' items of the path into 'path',
+ // returns the path length, or 0 if there is no path of size 'path_size'.
+ uptr findPath(uptr from, const BV &targets, uptr *path, uptr path_size) {
+ if (path_size == 0)
+ return 0;
+ path[0] = from;
+ if (targets.getBit(from))
+ return 1;
+ // The function is recursive, so we don't want to create BV on stack.
+ // Instead of a getAndClearFirstOne loop we use the slower iterator.
+ for (typename BV::Iterator it(v[from]); it.hasNext(); ) {
+ uptr idx = it.next();
+ if (uptr res = findPath(idx, targets, path + 1, path_size - 1))
+ return res + 1;
+ }
+ return 0;
+ }
+
+ // Same as findPath, but finds a shortest path.
+ uptr findShortestPath(uptr from, const BV &targets, uptr *path,
+ uptr path_size) {
+ for (uptr p = 1; p <= path_size; p++)
+ if (findPath(from, targets, path, p) == p)
+ return p;
+ return 0;
+ }
+
+ private:
+ void check(uptr idx1, uptr idx2) const {
+ CHECK_LT(idx1, size());
+ CHECK_LT(idx2, size());
+ }
+ BV v[kSize];
+ // Keep temporary vectors here since we can not create large objects on stack.
+ BV t1, t2;
+};
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_BVGRAPH_H
diff --git a/lib/sanitizer_common/sanitizer_common.cc b/lib/sanitizer_common/sanitizer_common.cc
index 7e870ff65455..c3740f24a366 100644
--- a/lib/sanitizer_common/sanitizer_common.cc
+++ b/lib/sanitizer_common/sanitizer_common.cc
@@ -14,8 +14,6 @@
#include "sanitizer_common.h"
#include "sanitizer_flags.h"
#include "sanitizer_libc.h"
-#include "sanitizer_stacktrace.h"
-#include "sanitizer_symbolizer.h"
namespace __sanitizer {
@@ -28,19 +26,73 @@ uptr GetPageSizeCached() {
return PageSize;
}
+StaticSpinMutex report_file_mu;
+ReportFile report_file = {&report_file_mu, kStderrFd, "", "", 0};
-// By default, dump to stderr. If |log_to_file| is true and |report_fd_pid|
-// isn't equal to the current PID, try to obtain file descriptor by opening
-// file "report_path_prefix.<PID>".
-fd_t report_fd = kStderrFd;
+void RawWrite(const char *buffer) {
+ report_file.Write(buffer, internal_strlen(buffer));
+}
+
+void ReportFile::ReopenIfNecessary() {
+ mu->CheckLocked();
+ if (fd == kStdoutFd || fd == kStderrFd) return;
+
+ uptr pid = internal_getpid();
+ // If in tracer, use the parent's file.
+ if (pid == stoptheworld_tracer_pid)
+ pid = stoptheworld_tracer_ppid;
+ if (fd != kInvalidFd) {
+ // If the report file is already opened by the current process,
+ // do nothing. Otherwise the report file was opened by the parent
+ // process, close it now.
+ if (fd_pid == pid)
+ return;
+ else
+ internal_close(fd);
+ }
+
+ internal_snprintf(full_path, kMaxPathLength, "%s.%zu", path_prefix, pid);
+ uptr openrv = OpenFile(full_path, true);
+ if (internal_iserror(openrv)) {
+ const char *ErrorMsgPrefix = "ERROR: Can't open file: ";
+ internal_write(kStderrFd, ErrorMsgPrefix, internal_strlen(ErrorMsgPrefix));
+ internal_write(kStderrFd, full_path, internal_strlen(full_path));
+ Die();
+ }
+ fd = openrv;
+ fd_pid = pid;
+}
+
+void ReportFile::SetReportPath(const char *path) {
+ if (!path)
+ return;
+ uptr len = internal_strlen(path);
+ if (len > sizeof(path_prefix) - 100) {
+ Report("ERROR: Path is too long: %c%c%c%c%c%c%c%c...\n",
+ path[0], path[1], path[2], path[3],
+ path[4], path[5], path[6], path[7]);
+ Die();
+ }
-// Set via __sanitizer_set_report_path.
-bool log_to_file = false;
-char report_path_prefix[sizeof(report_path_prefix)];
+ SpinMutexLock l(mu);
+ if (fd != kStdoutFd && fd != kStderrFd && fd != kInvalidFd)
+ internal_close(fd);
+ fd = kInvalidFd;
+ if (internal_strcmp(path, "stdout") == 0) {
+ fd = kStdoutFd;
+ } else if (internal_strcmp(path, "stderr") == 0) {
+ fd = kStderrFd;
+ } else {
+ internal_snprintf(path_prefix, kMaxPathLength, "%s", path);
+ }
+}
-// PID of process that opened |report_fd|. If a fork() occurs, the PID of the
-// child thread will be different from |report_fd_pid|.
-uptr report_fd_pid = 0;
+// PID of the tracer task in StopTheWorld. It shares the address space with the
+// main process, but has a different PID and thus requires special handling.
+uptr stoptheworld_tracer_pid = 0;
+// Cached pid of parent process - if the parent process dies, we want to keep
+// writing to the same log file.
+uptr stoptheworld_tracer_ppid = 0;
static DieCallbackType DieCallback;
void SetDieCallback(DieCallbackType callback) {
@@ -86,7 +138,7 @@ uptr ReadFileToBuffer(const char *file_name, char **buff,
if (internal_iserror(openrv)) return 0;
fd_t fd = openrv;
UnmapOrDie(*buff, *buff_size);
- *buff = (char*)MmapOrDie(size, __FUNCTION__);
+ *buff = (char*)MmapOrDie(size, __func__);
*buff_size = size;
// Read up to one page at a time.
read_len = 0;
@@ -150,31 +202,19 @@ const char *StripPathPrefix(const char *filepath,
return pos;
}
-void PrintSourceLocation(InternalScopedString *buffer, const char *file,
- int line, int column) {
- CHECK(file);
- buffer->append("%s",
- StripPathPrefix(file, common_flags()->strip_path_prefix));
- if (line > 0) {
- buffer->append(":%d", line);
- if (column > 0)
- buffer->append(":%d", column);
- }
-}
-
-void PrintModuleAndOffset(InternalScopedString *buffer, const char *module,
- uptr offset) {
- buffer->append("(%s+0x%zx)",
- StripPathPrefix(module, common_flags()->strip_path_prefix),
- offset);
+const char *StripModuleName(const char *module) {
+ if (module == 0)
+ return 0;
+ if (const char *slash_pos = internal_strrchr(module, '/'))
+ return slash_pos + 1;
+ return module;
}
void ReportErrorSummary(const char *error_message) {
if (!common_flags()->print_summary)
return;
- InternalScopedBuffer<char> buff(kMaxSummaryLength);
- internal_snprintf(buff.data(), buff.size(),
- "SUMMARY: %s: %s", SanitizerToolName, error_message);
+ InternalScopedString buff(kMaxSummaryLength);
+ buff.append("SUMMARY: %s: %s", SanitizerToolName, error_message);
__sanitizer_report_error_summary(buff.data());
}
@@ -182,39 +222,25 @@ void ReportErrorSummary(const char *error_type, const char *file,
int line, const char *function) {
if (!common_flags()->print_summary)
return;
- InternalScopedBuffer<char> buff(kMaxSummaryLength);
- internal_snprintf(
- buff.data(), buff.size(), "%s %s:%d %s", error_type,
- file ? StripPathPrefix(file, common_flags()->strip_path_prefix) : "??",
- line, function ? function : "??");
+ InternalScopedString buff(kMaxSummaryLength);
+ buff.append("%s %s:%d %s", error_type,
+ file ? StripPathPrefix(file, common_flags()->strip_path_prefix)
+ : "??",
+ line, function ? function : "??");
ReportErrorSummary(buff.data());
}
-void ReportErrorSummary(const char *error_type, StackTrace *stack) {
- if (!common_flags()->print_summary)
- return;
- AddressInfo ai;
-#if !SANITIZER_GO
- if (stack->size > 0 && Symbolizer::Get()->IsAvailable()) {
- // Currently, we include the first stack frame into the report summary.
- // Maybe sometimes we need to choose another frame (e.g. skip memcpy/etc).
- uptr pc = StackTrace::GetPreviousInstructionPc(stack->trace[0]);
- Symbolizer::Get()->SymbolizeCode(pc, &ai, 1);
- }
-#endif
- ReportErrorSummary(error_type, ai.file, ai.line, ai.function);
-}
-
LoadedModule::LoadedModule(const char *module_name, uptr base_address) {
full_name_ = internal_strdup(module_name);
base_address_ = base_address;
n_ranges_ = 0;
}
-void LoadedModule::addAddressRange(uptr beg, uptr end) {
+void LoadedModule::addAddressRange(uptr beg, uptr end, bool executable) {
CHECK_LT(n_ranges_, kMaxNumberOfAddressRanges);
ranges_[n_ranges_].beg = beg;
ranges_[n_ranges_].end = end;
+ exec_[n_ranges_] = executable;
n_ranges_++;
}
@@ -226,15 +252,20 @@ bool LoadedModule::containsAddress(uptr address) const {
return false;
}
-char *StripModuleName(const char *module) {
- if (module == 0)
- return 0;
- const char *short_module_name = internal_strrchr(module, '/');
- if (short_module_name)
- short_module_name += 1;
- else
- short_module_name = module;
- return internal_strdup(short_module_name);
+static atomic_uintptr_t g_total_mmaped;
+
+void IncreaseTotalMmap(uptr size) {
+ if (!common_flags()->mmap_limit_mb) return;
+ uptr total_mmaped =
+ atomic_fetch_add(&g_total_mmaped, size, memory_order_relaxed) + size;
+ // Since for now mmap_limit_mb is not a user-facing flag, just kill
+ // a program. Use RAW_CHECK to avoid extra mmaps in reporting.
+ RAW_CHECK((total_mmaped >> 20) < common_flags()->mmap_limit_mb);
+}
+
+void DecreaseTotalMmap(uptr size) {
+ if (!common_flags()->mmap_limit_mb) return;
+ atomic_fetch_sub(&g_total_mmaped, size, memory_order_relaxed);
}
} // namespace __sanitizer
@@ -243,35 +274,7 @@ using namespace __sanitizer; // NOLINT
extern "C" {
void __sanitizer_set_report_path(const char *path) {
- if (!path)
- return;
- uptr len = internal_strlen(path);
- if (len > sizeof(report_path_prefix) - 100) {
- Report("ERROR: Path is too long: %c%c%c%c%c%c%c%c...\n",
- path[0], path[1], path[2], path[3],
- path[4], path[5], path[6], path[7]);
- Die();
- }
- if (report_fd != kStdoutFd &&
- report_fd != kStderrFd &&
- report_fd != kInvalidFd)
- internal_close(report_fd);
- report_fd = kInvalidFd;
- log_to_file = false;
- if (internal_strcmp(path, "stdout") == 0) {
- report_fd = kStdoutFd;
- } else if (internal_strcmp(path, "stderr") == 0) {
- report_fd = kStderrFd;
- } else {
- internal_strncpy(report_path_prefix, path, sizeof(report_path_prefix));
- report_path_prefix[len] = '\0';
- log_to_file = true;
- }
-}
-
-void NOINLINE __sanitizer_sandbox_on_notify(void *reserved) {
- (void)reserved;
- PrepareForSandboxing();
+ report_file.SetReportPath(path);
}
void __sanitizer_report_error_summary(const char *error_summary) {
diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h
index cf8a12d65a09..c00dce66bb07 100644
--- a/lib/sanitizer_common/sanitizer_common.h
+++ b/lib/sanitizer_common/sanitizer_common.h
@@ -19,6 +19,7 @@
#include "sanitizer_internal_defs.h"
#include "sanitizer_libc.h"
#include "sanitizer_mutex.h"
+#include "sanitizer_flags.h"
namespace __sanitizer {
struct StackTrace;
@@ -28,12 +29,14 @@ const uptr kWordSize = SANITIZER_WORDSIZE / 8;
const uptr kWordSizeInBits = 8 * kWordSize;
#if defined(__powerpc__) || defined(__powerpc64__)
-const uptr kCacheLineSize = 128;
+ const uptr kCacheLineSize = 128;
#else
-const uptr kCacheLineSize = 64;
+ const uptr kCacheLineSize = 64;
#endif
-const uptr kMaxPathLength = 512;
+const uptr kMaxPathLength = 4096;
+
+const uptr kMaxThreadStackSize = 1 << 30; // 1Gb
extern const char *SanitizerToolName; // Can be changed by the tool.
@@ -53,6 +56,7 @@ void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
void *MmapOrDie(uptr size, const char *mem_type);
void UnmapOrDie(void *addr, uptr size);
void *MmapFixedNoReserve(uptr fixed_addr, uptr size);
+void *MmapNoReserveOrDie(uptr size, const char *mem_type);
void *MmapFixedOrDie(uptr fixed_addr, uptr size);
void *Mprotect(uptr fixed_addr, uptr size);
// Map aligned chunk of address space; size and alignment are powers of two.
@@ -60,6 +64,9 @@ void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type);
// Used to check if we can map shadow memory to a fixed location.
bool MemoryRangeIsAvailable(uptr range_start, uptr range_end);
void FlushUnneededShadowMemory(uptr addr, uptr size);
+void IncreaseTotalMmap(uptr size);
+void DecreaseTotalMmap(uptr size);
+uptr GetRSS();
// InternalScopedBuffer can be used instead of large stack arrays to
// keep frame size low.
@@ -122,20 +129,50 @@ void SetLowLevelAllocateCallback(LowLevelAllocateCallback callback);
// IO
void RawWrite(const char *buffer);
-bool PrintsToTty();
-// Caching version of PrintsToTty(). Not thread-safe.
-bool PrintsToTtyCached();
+bool ColorizeReports();
void Printf(const char *format, ...);
void Report(const char *format, ...);
void SetPrintfAndReportCallback(void (*callback)(const char *));
+#define VReport(level, ...) \
+ do { \
+ if ((uptr)common_flags()->verbosity >= (level)) Report(__VA_ARGS__); \
+ } while (0)
+#define VPrintf(level, ...) \
+ do { \
+ if ((uptr)common_flags()->verbosity >= (level)) Printf(__VA_ARGS__); \
+ } while (0)
// Can be used to prevent mixing error reports from different sanitizers.
extern StaticSpinMutex CommonSanitizerReportMutex;
-void MaybeOpenReportFile();
-extern fd_t report_fd;
-extern bool log_to_file;
-extern char report_path_prefix[4096];
-extern uptr report_fd_pid;
+
+struct ReportFile {
+ void Write(const char *buffer, uptr length);
+ bool PrintsToTty();
+ void SetReportPath(const char *path);
+
+ // Don't use fields directly. They are only declared public to allow
+ // aggregate initialization.
+
+ // Protects fields below.
+ StaticSpinMutex *mu;
+ // Opened file descriptor. Defaults to stderr. It may be equal to
+ // kInvalidFd, in which case new file will be opened when necessary.
+ fd_t fd;
+ // Path prefix of report file, set via __sanitizer_set_report_path.
+ char path_prefix[kMaxPathLength];
+ // Full path to report, obtained as <path_prefix>.PID
+ char full_path[kMaxPathLength];
+ // PID of the process that opened fd. If a fork() occurs,
+ // the PID of child will be different from fd_pid.
+ uptr fd_pid;
+
+ private:
+ void ReopenIfNecessary();
+};
+extern ReportFile report_file;
+
+extern uptr stoptheworld_tracer_pid;
+extern uptr stoptheworld_tracer_ppid;
uptr OpenFile(const char *filename, bool write);
// Opens the file 'file_name" and reads up to 'max_len' bytes.
@@ -148,17 +185,18 @@ uptr ReadFileToBuffer(const char *file_name, char **buff,
// (or NULL if the mapping failes). Stores the size of mmaped region
// in '*buff_size'.
void *MapFileToMemory(const char *file_name, uptr *buff_size);
+void *MapWritableFileToMemory(void *addr, uptr size, uptr fd, uptr offset);
+
+bool IsAccessibleMemoryRange(uptr beg, uptr size);
// Error report formatting.
const char *StripPathPrefix(const char *filepath,
const char *strip_file_prefix);
-void PrintSourceLocation(InternalScopedString *buffer, const char *file,
- int line, int column);
-void PrintModuleAndOffset(InternalScopedString *buffer,
- const char *module, uptr offset);
+// Strip the directories from the module name.
+const char *StripModuleName(const char *module);
// OS
-void DisableCoreDumper();
+void DisableCoreDumperIfNecessary();
void DumpProcessMap();
bool FileExists(const char *filename);
const char *GetEnv(const char *name);
@@ -169,7 +207,16 @@ u32 GetUid();
void ReExec();
bool StackSizeIsUnlimited();
void SetStackSizeLimitInBytes(uptr limit);
-void PrepareForSandboxing();
+bool AddressSpaceIsUnlimited();
+void SetAddressSpaceUnlimited();
+void AdjustStackSize(void *attr);
+void PrepareForSandboxing(__sanitizer_sandbox_arguments *args);
+void CovPrepareForSandboxing(__sanitizer_sandbox_arguments *args);
+void SetSandboxingCallback(void (*f)());
+
+void CovUpdateMapping(uptr caller_pc = 0);
+void CovBeforeFork();
+void CovAfterFork(int child_pid);
void InitTlsSize();
uptr GetTlsSize();
@@ -180,9 +227,6 @@ void SleepForMillis(int millis);
u64 NanoTime();
int Atexit(void (*function)(void));
void SortArray(uptr *array, uptr size);
-// Strip the directories from the module name, return a new string allocated
-// with internal_strdup.
-char *StripModuleName(const char *module);
// Exit
void NORETURN Abort();
@@ -206,6 +250,14 @@ typedef void (*CheckFailedCallbackType)(const char *, int, const char *,
u64, u64);
void SetCheckFailedCallback(CheckFailedCallbackType callback);
+// Functions related to signal handling.
+typedef void (*SignalHandlerType)(int, void *, void *);
+bool IsDeadlySignal(int signum);
+void InstallDeadlySignalHandlers(SignalHandlerType handler);
+// Alternative signal stack (POSIX-only).
+void SetAlternateSignalStack();
+void UnsetAlternateSignalStack();
+
// We don't want a summary too long.
const int kMaxSummaryLength = 1024;
// Construct a one-line string:
@@ -213,7 +265,7 @@ const int kMaxSummaryLength = 1024;
// and pass it to __sanitizer_report_error_summary.
void ReportErrorSummary(const char *error_message);
// Same as above, but construct error_message as:
-// error_type: file:line function
+// error_type file:line function
void ReportErrorSummary(const char *error_type, const char *file,
int line, const char *function);
void ReportErrorSummary(const char *error_type, StackTrace *trace);
@@ -243,6 +295,19 @@ INLINE uptr MostSignificantSetBitIndex(uptr x) {
return up;
}
+INLINE uptr LeastSignificantSetBitIndex(uptr x) {
+ CHECK_NE(x, 0U);
+ unsigned long up; // NOLINT
+#if !SANITIZER_WINDOWS || defined(__clang__) || defined(__GNUC__)
+ up = __builtin_ctzl(x);
+#elif defined(_WIN64)
+ _BitScanForward64(&up, x);
+#else
+ _BitScanForward(&up, x);
+#endif
+ return up;
+}
+
INLINE bool IsPowerOfTwo(uptr x) {
return (x & (x - 1)) == 0;
}
@@ -307,12 +372,6 @@ INLINE int ToLower(int c) {
return (c >= 'A' && c <= 'Z') ? (c + 'a' - 'A') : c;
}
-#if SANITIZER_WORDSIZE == 64
-# define FIRST_32_SECOND_64(a, b) (b)
-#else
-# define FIRST_32_SECOND_64(a, b) (a)
-#endif
-
// A low-level vector based on mmap. May incur a significant memory overhead for
// small vectors.
// WARNING: The current implementation supports only POD types.
@@ -320,8 +379,7 @@ template<typename T>
class InternalMmapVector {
public:
explicit InternalMmapVector(uptr initial_capacity) {
- CHECK_GT(initial_capacity, 0);
- capacity_ = initial_capacity;
+ capacity_ = Max(initial_capacity, (uptr)1);
size_ = 0;
data_ = (T *)MmapOrDie(capacity_ * sizeof(T), "InternalMmapVector");
}
@@ -443,12 +501,17 @@ uptr InternalBinarySearch(const Container &v, uptr first, uptr last,
class LoadedModule {
public:
LoadedModule(const char *module_name, uptr base_address);
- void addAddressRange(uptr beg, uptr end);
+ void addAddressRange(uptr beg, uptr end, bool executable);
bool containsAddress(uptr address) const;
const char *full_name() const { return full_name_; }
uptr base_address() const { return base_address_; }
+ uptr n_ranges() const { return n_ranges_; }
+ uptr address_range_start(int i) const { return ranges_[i].beg; }
+ uptr address_range_end(int i) const { return ranges_[i].end; }
+ bool address_range_executable(int i) const { return exec_[i]; }
+
private:
struct AddressRange {
uptr beg;
@@ -458,6 +521,7 @@ class LoadedModule {
uptr base_address_;
static const uptr kMaxNumberOfAddressRanges = 6;
AddressRange ranges_[kMaxNumberOfAddressRanges];
+ bool exec_[kMaxNumberOfAddressRanges];
uptr n_ranges_;
};
@@ -478,6 +542,33 @@ const uptr kPthreadDestructorIterations = 0;
// Callback type for iterating over a set of memory ranges.
typedef void (*RangeIteratorCallback)(uptr begin, uptr end, void *arg);
+
+#if SANITIZER_ANDROID
+// Initialize Android logging. Any writes before this are silently lost.
+void AndroidLogInit();
+void AndroidLogWrite(const char *buffer);
+void GetExtraActivationFlags(char *buf, uptr size);
+void SanitizerInitializeUnwinder();
+#else
+INLINE void AndroidLogInit() {}
+INLINE void AndroidLogWrite(const char *buffer_unused) {}
+INLINE void GetExtraActivationFlags(char *buf, uptr size) { *buf = '\0'; }
+INLINE void SanitizerInitializeUnwinder() {}
+#endif
+
+// Make the compiler think that something is going on there.
+// Use this inside a loop that looks like memset/memcpy/etc to prevent the
+// compiler from recognising it and turning it into an actual call to
+// memset/memcpy/etc.
+static inline void SanitizerBreakOptimization(void *arg) {
+#if _MSC_VER
+ // FIXME: make sure this is actually enough.
+ __asm;
+#else
+ __asm__ __volatile__("" : : "r" (arg) : "memory");
+#endif
+}
+
} // namespace __sanitizer
inline void *operator new(__sanitizer::operator_new_size_type size,
@@ -485,4 +576,9 @@ inline void *operator new(__sanitizer::operator_new_size_type size,
return alloc.Allocate(size);
}
+struct StackDepotStats {
+ uptr n_uniq_ids;
+ uptr allocated;
+};
+
#endif // SANITIZER_COMMON_H
diff --git a/lib/sanitizer_common/sanitizer_common_interceptors.inc b/lib/sanitizer_common/sanitizer_common_interceptors.inc
index d1c8976781c7..274e87c3d67d 100644
--- a/lib/sanitizer_common/sanitizer_common_interceptors.inc
+++ b/lib/sanitizer_common/sanitizer_common_interceptors.inc
@@ -13,6 +13,7 @@
// This file should be included into the tool's interceptor file,
// which has to define it's own macros:
// COMMON_INTERCEPTOR_ENTER
+// COMMON_INTERCEPTOR_ENTER_NOIGNORE
// COMMON_INTERCEPTOR_READ_RANGE
// COMMON_INTERCEPTOR_WRITE_RANGE
// COMMON_INTERCEPTOR_INITIALIZE_RANGE
@@ -25,18 +26,31 @@
// COMMON_INTERCEPTOR_MUTEX_UNLOCK
// COMMON_INTERCEPTOR_MUTEX_REPAIR
// COMMON_INTERCEPTOR_SET_PTHREAD_NAME
+// COMMON_INTERCEPTOR_HANDLE_RECVMSG
+// COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED
//===----------------------------------------------------------------------===//
#include "interception/interception.h"
+#include "sanitizer_addrhashmap.h"
+#include "sanitizer_placement_new.h"
#include "sanitizer_platform_interceptors.h"
+#include "sanitizer_tls_get_addr.h"
#include <stdarg.h>
-#if SANITIZER_WINDOWS
+#if SANITIZER_WINDOWS && !defined(va_copy)
#define va_copy(dst, src) ((dst) = (src))
#endif // _WIN32
+#if SANITIZER_FREEBSD
+#define pthread_setname_np pthread_set_name_np
+#endif
+
#ifndef COMMON_INTERCEPTOR_INITIALIZE_RANGE
-#define COMMON_INTERCEPTOR_INITIALIZE_RANGE(ctx, p, size) {}
+#define COMMON_INTERCEPTOR_INITIALIZE_RANGE(p, size) {}
+#endif
+
+#ifndef COMMON_INTERCEPTOR_UNPOISON_PARAM
+#define COMMON_INTERCEPTOR_UNPOISON_PARAM(count) {}
#endif
#ifndef COMMON_INTERCEPTOR_FD_ACCESS
@@ -55,6 +69,99 @@
#define COMMON_INTERCEPTOR_MUTEX_REPAIR(ctx, m) {}
#endif
+#ifndef COMMON_INTERCEPTOR_HANDLE_RECVMSG
+#define COMMON_INTERCEPTOR_HANDLE_RECVMSG(ctx, msg) ((void)(msg))
+#endif
+
+#ifndef COMMON_INTERCEPTOR_FILE_OPEN
+#define COMMON_INTERCEPTOR_FILE_OPEN(ctx, file, path) {}
+#endif
+
+#ifndef COMMON_INTERCEPTOR_FILE_CLOSE
+#define COMMON_INTERCEPTOR_FILE_CLOSE(ctx, file) {}
+#endif
+
+#ifndef COMMON_INTERCEPTOR_LIBRARY_LOADED
+#define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, map) {}
+#endif
+
+#ifndef COMMON_INTERCEPTOR_LIBRARY_UNLOADED
+#define COMMON_INTERCEPTOR_LIBRARY_UNLOADED() {}
+#endif
+
+#ifndef COMMON_INTERCEPTOR_ENTER_NOIGNORE
+#define COMMON_INTERCEPTOR_ENTER_NOIGNORE(ctx, ...) \
+ COMMON_INTERCEPTOR_ENTER(ctx, __VA_ARGS__)
+#endif
+
+#ifndef COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED
+#define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED (0)
+#endif
+
+struct FileMetadata {
+ // For open_memstream().
+ char **addr;
+ SIZE_T *size;
+};
+
+struct CommonInterceptorMetadata {
+ enum {
+ CIMT_INVALID = 0,
+ CIMT_FILE
+ } type;
+ union {
+ FileMetadata file;
+ };
+};
+
+typedef AddrHashMap<CommonInterceptorMetadata, 31051> MetadataHashMap;
+
+static MetadataHashMap *interceptor_metadata_map;
+
+#if SI_NOT_WINDOWS
+UNUSED static void SetInterceptorMetadata(__sanitizer_FILE *addr,
+ const FileMetadata &file) {
+ MetadataHashMap::Handle h(interceptor_metadata_map, (uptr)addr);
+ CHECK(h.created());
+ h->type = CommonInterceptorMetadata::CIMT_FILE;
+ h->file = file;
+}
+
+UNUSED static const FileMetadata *GetInterceptorMetadata(
+ __sanitizer_FILE *addr) {
+ MetadataHashMap::Handle h(interceptor_metadata_map, (uptr)addr,
+ /* remove */ false,
+ /* create */ false);
+ if (h.exists()) {
+ CHECK(!h.created());
+ CHECK(h->type == CommonInterceptorMetadata::CIMT_FILE);
+ return &h->file;
+ } else {
+ return 0;
+ }
+}
+
+UNUSED static void DeleteInterceptorMetadata(void *addr) {
+ MetadataHashMap::Handle h(interceptor_metadata_map, (uptr)addr, true);
+ CHECK(h.exists());
+}
+#endif // SI_NOT_WINDOWS
+
+#if SANITIZER_INTERCEPT_TEXTDOMAIN
+INTERCEPTOR(char*, textdomain, const char *domainname) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, textdomain, domainname);
+ char* domain = REAL(textdomain)(domainname);
+ if (domain) {
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(domain, REAL(strlen)(domain) + 1);
+ }
+ return domain;
+}
+#define INIT_TEXTDOMAIN COMMON_INTERCEPT_FUNCTION(textdomain)
+#else
+#define INIT_TEXTDOMAIN
+#endif
+
#if SANITIZER_INTERCEPT_STRCMP
static inline int CharCmpX(unsigned char c1, unsigned char c2) {
return (c1 == c2) ? 0 : (c1 < c2) ? -1 : 1;
@@ -76,6 +183,8 @@ INTERCEPTOR(int, strcmp, const char *s1, const char *s2) {
}
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);
unsigned char c1 = 0, c2 = 0;
@@ -141,12 +250,41 @@ INTERCEPTOR(int, strncasecmp, const char *s1, const char *s2, SIZE_T n) {
#define INIT_STRNCASECMP
#endif
+#if SANITIZER_INTERCEPT_MEMCHR
+INTERCEPTOR(void*, memchr, const void *s, int c, SIZE_T n) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, memchr, s, c, n);
+ void *res = REAL(memchr)(s, c, n);
+ uptr len = res ? (char *)res - (const char *)s + 1 : n;
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, s, len);
+ return res;
+}
+
+#define INIT_MEMCHR COMMON_INTERCEPT_FUNCTION(memchr)
+#else
+#define INIT_MEMCHR
+#endif
+
+#if SANITIZER_INTERCEPT_MEMRCHR
+INTERCEPTOR(void*, memrchr, const void *s, int c, SIZE_T n) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, memrchr, s, c, n);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, s, n);
+ return REAL(memrchr)(s, c, n);
+}
+
+#define INIT_MEMRCHR COMMON_INTERCEPT_FUNCTION(memrchr)
+#else
+#define INIT_MEMRCHR
+#endif
+
#if SANITIZER_INTERCEPT_FREXP
INTERCEPTOR(double, frexp, double x, int *exp) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, frexp, x, exp);
- double res = REAL(frexp)(x, exp);
+ // Assuming frexp() always writes to |exp|.
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, exp, sizeof(*exp));
+ double res = REAL(frexp)(x, exp);
return res;
}
@@ -159,6 +297,9 @@ INTERCEPTOR(double, frexp, double x, int *exp) {
INTERCEPTOR(float, frexpf, float x, int *exp) {
void *ctx;
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.
float res = REAL(frexpf)(x, exp);
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, exp, sizeof(*exp));
return res;
@@ -167,6 +308,9 @@ INTERCEPTOR(float, frexpf, float x, int *exp) {
INTERCEPTOR(long double, frexpl, long double x, int *exp) {
void *ctx;
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.
long double res = REAL(frexpl)(x, exp);
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, exp, sizeof(*exp));
return res;
@@ -205,6 +349,9 @@ INTERCEPTOR(SSIZE_T, read, int fd, void *ptr, SIZE_T count) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, read, fd, ptr, 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.
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);
@@ -220,6 +367,9 @@ INTERCEPTOR(SSIZE_T, pread, int fd, void *ptr, SIZE_T count, OFF_T offset) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, pread, fd, ptr, count, 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.
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);
@@ -235,6 +385,9 @@ INTERCEPTOR(SSIZE_T, pread64, int fd, void *ptr, SIZE_T count, OFF64_T offset) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, pread64, fd, ptr, count, 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.
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);
@@ -413,9 +566,11 @@ INTERCEPTOR(int, prctl, int option, unsigned long arg2,
INTERCEPTOR(unsigned long, time, unsigned long *t) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, time, t);
- unsigned long res = REAL(time)(t);
+ unsigned long local_t;
+ unsigned long res = REAL(time)(&local_t);
if (t && res != (unsigned long)-1) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, t, sizeof(*t));
+ *t = local_t;
}
return res;
}
@@ -430,7 +585,7 @@ static void unpoison_tm(void *ctx, __sanitizer_tm *tm) {
if (tm->tm_zone) {
// Can not use COMMON_INTERCEPTOR_WRITE_RANGE here, because tm->tm_zone
// can point to shared memory and tsan would report a data race.
- COMMON_INTERCEPTOR_INITIALIZE_RANGE(ctx, tm->tm_zone,
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(tm->tm_zone,
REAL(strlen(tm->tm_zone)) + 1);
}
}
@@ -477,6 +632,9 @@ INTERCEPTOR(__sanitizer_tm *, gmtime_r, unsigned long *timep, void *result) {
INTERCEPTOR(char *, ctime, unsigned long *timep) {
void *ctx;
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.
char *res = REAL(ctime)(timep);
if (res) {
COMMON_INTERCEPTOR_READ_RANGE(ctx, timep, sizeof(*timep));
@@ -487,6 +645,9 @@ INTERCEPTOR(char *, ctime, unsigned long *timep) {
INTERCEPTOR(char *, ctime_r, unsigned long *timep, char *result) {
void *ctx;
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.
char *res = REAL(ctime_r)(timep, result);
if (res) {
COMMON_INTERCEPTOR_READ_RANGE(ctx, timep, sizeof(*timep));
@@ -497,6 +658,9 @@ INTERCEPTOR(char *, ctime_r, unsigned long *timep, char *result) {
INTERCEPTOR(char *, asctime, __sanitizer_tm *tm) {
void *ctx;
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.
char *res = REAL(asctime)(tm);
if (res) {
COMMON_INTERCEPTOR_READ_RANGE(ctx, tm, sizeof(*tm));
@@ -507,6 +671,9 @@ INTERCEPTOR(char *, asctime, __sanitizer_tm *tm) {
INTERCEPTOR(char *, asctime_r, __sanitizer_tm *tm, char *result) {
void *ctx;
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.
char *res = REAL(asctime_r)(tm, result);
if (res) {
COMMON_INTERCEPTOR_READ_RANGE(ctx, tm, sizeof(*tm));
@@ -514,6 +681,20 @@ INTERCEPTOR(char *, asctime_r, __sanitizer_tm *tm, char *result) {
}
return res;
}
+INTERCEPTOR(long, mktime, __sanitizer_tm *tm) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, mktime, tm);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, &tm->tm_sec, sizeof(tm->tm_sec));
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, &tm->tm_min, sizeof(tm->tm_min));
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, &tm->tm_hour, sizeof(tm->tm_hour));
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, &tm->tm_mday, sizeof(tm->tm_mday));
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, &tm->tm_mon, sizeof(tm->tm_mon));
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, &tm->tm_year, sizeof(tm->tm_year));
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, &tm->tm_isdst, sizeof(tm->tm_isdst));
+ long res = REAL(mktime)(tm);
+ if (res != -1) unpoison_tm(ctx, tm);
+ return res;
+}
#define INIT_LOCALTIME_AND_FRIENDS \
COMMON_INTERCEPT_FUNCTION(localtime); \
COMMON_INTERCEPT_FUNCTION(localtime_r); \
@@ -522,7 +703,8 @@ INTERCEPTOR(char *, asctime_r, __sanitizer_tm *tm, char *result) {
COMMON_INTERCEPT_FUNCTION(ctime); \
COMMON_INTERCEPT_FUNCTION(ctime_r); \
COMMON_INTERCEPT_FUNCTION(asctime); \
- COMMON_INTERCEPT_FUNCTION(asctime_r);
+ COMMON_INTERCEPT_FUNCTION(asctime_r); \
+ COMMON_INTERCEPT_FUNCTION(mktime);
#else
#define INIT_LOCALTIME_AND_FRIENDS
#endif // SANITIZER_INTERCEPT_LOCALTIME_AND_FRIENDS
@@ -533,6 +715,9 @@ INTERCEPTOR(char *, strptime, char *s, char *format, __sanitizer_tm *tm) {
COMMON_INTERCEPTOR_ENTER(ctx, strptime, s, format, tm);
if (format)
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.
char *res = REAL(strptime)(s, format, tm);
if (res) {
COMMON_INTERCEPTOR_READ_RANGE(ctx, s, res - s);
@@ -548,9 +733,23 @@ INTERCEPTOR(char *, strptime, char *s, char *format, __sanitizer_tm *tm) {
#define INIT_STRPTIME
#endif
-#if SANITIZER_INTERCEPT_SCANF
+#if SANITIZER_INTERCEPT_SCANF || SANITIZER_INTERCEPT_PRINTF
+#include "sanitizer_common_interceptors_format.inc"
+
+#define FORMAT_INTERCEPTOR_IMPL(name, vname, ...) \
+ { \
+ void *ctx; \
+ va_list ap; \
+ va_start(ap, format); \
+ COMMON_INTERCEPTOR_ENTER(ctx, vname, __VA_ARGS__, ap); \
+ int res = WRAP(vname)(__VA_ARGS__, ap); \
+ va_end(ap); \
+ return res; \
+ }
+
+#endif
-#include "sanitizer_common_interceptors_scanf.inc"
+#if SANITIZER_INTERCEPT_SCANF
#define VSCANF_INTERCEPTOR_IMPL(vname, allowGnuMalloc, ...) \
{ \
@@ -586,35 +785,24 @@ INTERCEPTOR(int, __isoc99_vfscanf, void *stream, const char *format, va_list ap)
VSCANF_INTERCEPTOR_IMPL(__isoc99_vfscanf, false, stream, format, ap)
#endif // SANITIZER_INTERCEPT_ISOC99_SCANF
-#define SCANF_INTERCEPTOR_IMPL(name, vname, ...) \
- { \
- void *ctx; \
- va_list ap; \
- va_start(ap, format); \
- COMMON_INTERCEPTOR_ENTER(ctx, vname, __VA_ARGS__, ap); \
- int res = vname(__VA_ARGS__, ap); \
- va_end(ap); \
- return res; \
- }
-
INTERCEPTOR(int, scanf, const char *format, ...)
-SCANF_INTERCEPTOR_IMPL(scanf, vscanf, format)
+FORMAT_INTERCEPTOR_IMPL(scanf, vscanf, format)
INTERCEPTOR(int, fscanf, void *stream, const char *format, ...)
-SCANF_INTERCEPTOR_IMPL(fscanf, vfscanf, stream, format)
+FORMAT_INTERCEPTOR_IMPL(fscanf, vfscanf, stream, format)
INTERCEPTOR(int, sscanf, const char *str, const char *format, ...)
-SCANF_INTERCEPTOR_IMPL(sscanf, vsscanf, str, format)
+FORMAT_INTERCEPTOR_IMPL(sscanf, vsscanf, str, format)
#if SANITIZER_INTERCEPT_ISOC99_SCANF
INTERCEPTOR(int, __isoc99_scanf, const char *format, ...)
-SCANF_INTERCEPTOR_IMPL(__isoc99_scanf, __isoc99_vscanf, format)
+FORMAT_INTERCEPTOR_IMPL(__isoc99_scanf, __isoc99_vscanf, format)
INTERCEPTOR(int, __isoc99_fscanf, void *stream, const char *format, ...)
-SCANF_INTERCEPTOR_IMPL(__isoc99_fscanf, __isoc99_vfscanf, stream, format)
+FORMAT_INTERCEPTOR_IMPL(__isoc99_fscanf, __isoc99_vfscanf, stream, format)
INTERCEPTOR(int, __isoc99_sscanf, const char *str, const char *format, ...)
-SCANF_INTERCEPTOR_IMPL(__isoc99_sscanf, __isoc99_vsscanf, str, format)
+FORMAT_INTERCEPTOR_IMPL(__isoc99_sscanf, __isoc99_vsscanf, str, format)
#endif
#endif
@@ -643,6 +831,180 @@ SCANF_INTERCEPTOR_IMPL(__isoc99_sscanf, __isoc99_vsscanf, str, format)
#define INIT_ISOC99_SCANF
#endif
+#if SANITIZER_INTERCEPT_PRINTF
+
+#define VPRINTF_INTERCEPTOR_ENTER(vname, ...) \
+ void *ctx; \
+ COMMON_INTERCEPTOR_ENTER(ctx, vname, __VA_ARGS__); \
+ va_list aq; \
+ va_copy(aq, ap);
+
+#define VPRINTF_INTERCEPTOR_RETURN() \
+ va_end(aq);
+
+#define VPRINTF_INTERCEPTOR_IMPL(vname, ...) \
+ { \
+ VPRINTF_INTERCEPTOR_ENTER(vname, __VA_ARGS__); \
+ if (common_flags()->check_printf) \
+ printf_common(ctx, format, aq); \
+ int res = REAL(vname)(__VA_ARGS__); \
+ VPRINTF_INTERCEPTOR_RETURN(); \
+ return res; \
+ }
+
+// 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.
+#define VSPRINTF_INTERCEPTOR_IMPL(vname, str, ...) \
+ { \
+ VPRINTF_INTERCEPTOR_ENTER(vname, str, __VA_ARGS__) \
+ if (common_flags()->check_printf) { \
+ printf_common(ctx, format, aq); \
+ } \
+ int res = REAL(vname)(str, __VA_ARGS__); \
+ if (res >= 0) { \
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, str, res + 1); \
+ } \
+ VPRINTF_INTERCEPTOR_RETURN(); \
+ return res; \
+ }
+
+// 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.
+#define VSNPRINTF_INTERCEPTOR_IMPL(vname, str, size, ...) \
+ { \
+ VPRINTF_INTERCEPTOR_ENTER(vname, str, size, __VA_ARGS__) \
+ if (common_flags()->check_printf) { \
+ printf_common(ctx, format, aq); \
+ } \
+ int res = REAL(vname)(str, size, __VA_ARGS__); \
+ if (res >= 0) { \
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, str, Min(size, (SIZE_T)(res + 1))); \
+ } \
+ VPRINTF_INTERCEPTOR_RETURN(); \
+ return res; \
+ }
+
+// 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.
+#define VASPRINTF_INTERCEPTOR_IMPL(vname, strp, ...) \
+ { \
+ VPRINTF_INTERCEPTOR_ENTER(vname, strp, __VA_ARGS__) \
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, strp, sizeof(char *)); \
+ if (common_flags()->check_printf) { \
+ printf_common(ctx, format, aq); \
+ } \
+ int res = REAL(vname)(strp, __VA_ARGS__); \
+ if (res >= 0) { \
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *strp, res + 1); \
+ } \
+ VPRINTF_INTERCEPTOR_RETURN(); \
+ return res; \
+ }
+
+INTERCEPTOR(int, vprintf, const char *format, va_list ap)
+VPRINTF_INTERCEPTOR_IMPL(vprintf, format, ap)
+
+INTERCEPTOR(int, vfprintf, __sanitizer_FILE *stream, const char *format,
+ va_list ap)
+VPRINTF_INTERCEPTOR_IMPL(vfprintf, stream, format, ap)
+
+INTERCEPTOR(int, vsnprintf, char *str, SIZE_T size, const char *format,
+ va_list ap)
+VSNPRINTF_INTERCEPTOR_IMPL(vsnprintf, str, size, format, ap)
+
+INTERCEPTOR(int, vsprintf, char *str, const char *format, va_list ap)
+VSPRINTF_INTERCEPTOR_IMPL(vsprintf, str, format, ap)
+
+INTERCEPTOR(int, vasprintf, char **strp, const char *format, va_list ap)
+VASPRINTF_INTERCEPTOR_IMPL(vasprintf, strp, format, ap)
+
+#if SANITIZER_INTERCEPT_ISOC99_PRINTF
+INTERCEPTOR(int, __isoc99_vprintf, const char *format, va_list ap)
+VPRINTF_INTERCEPTOR_IMPL(__isoc99_vprintf, format, ap)
+
+INTERCEPTOR(int, __isoc99_vfprintf, __sanitizer_FILE *stream,
+ const char *format, va_list ap)
+VPRINTF_INTERCEPTOR_IMPL(__isoc99_vfprintf, stream, format, ap)
+
+INTERCEPTOR(int, __isoc99_vsnprintf, char *str, SIZE_T size, const char *format,
+ va_list ap)
+VSNPRINTF_INTERCEPTOR_IMPL(__isoc99_vsnprintf, str, size, format, ap)
+
+INTERCEPTOR(int, __isoc99_vsprintf, char *str, const char *format,
+ va_list ap)
+VSPRINTF_INTERCEPTOR_IMPL(__isoc99_vsprintf, str, format,
+ ap)
+
+#endif // SANITIZER_INTERCEPT_ISOC99_PRINTF
+
+INTERCEPTOR(int, printf, const char *format, ...)
+FORMAT_INTERCEPTOR_IMPL(printf, vprintf, format)
+
+INTERCEPTOR(int, fprintf, __sanitizer_FILE *stream, const char *format, ...)
+FORMAT_INTERCEPTOR_IMPL(fprintf, vfprintf, stream, format)
+
+INTERCEPTOR(int, sprintf, char *str, const char *format, ...) // NOLINT
+FORMAT_INTERCEPTOR_IMPL(sprintf, vsprintf, str, format) // NOLINT
+
+INTERCEPTOR(int, snprintf, char *str, SIZE_T size, const char *format, ...)
+FORMAT_INTERCEPTOR_IMPL(snprintf, vsnprintf, str, size, format)
+
+INTERCEPTOR(int, asprintf, char **strp, const char *format, ...)
+FORMAT_INTERCEPTOR_IMPL(asprintf, vasprintf, strp, format)
+
+#if SANITIZER_INTERCEPT_ISOC99_PRINTF
+INTERCEPTOR(int, __isoc99_printf, const char *format, ...)
+FORMAT_INTERCEPTOR_IMPL(__isoc99_printf, __isoc99_vprintf, format)
+
+INTERCEPTOR(int, __isoc99_fprintf, __sanitizer_FILE *stream, const char *format,
+ ...)
+FORMAT_INTERCEPTOR_IMPL(__isoc99_fprintf, __isoc99_vfprintf, stream, format)
+
+INTERCEPTOR(int, __isoc99_sprintf, char *str, const char *format, ...)
+FORMAT_INTERCEPTOR_IMPL(__isoc99_sprintf, __isoc99_vsprintf, str, format)
+
+INTERCEPTOR(int, __isoc99_snprintf, char *str, SIZE_T size,
+ const char *format, ...)
+FORMAT_INTERCEPTOR_IMPL(__isoc99_snprintf, __isoc99_vsnprintf, str, size,
+ format)
+
+#endif // SANITIZER_INTERCEPT_ISOC99_PRINTF
+
+#endif // SANITIZER_INTERCEPT_PRINTF
+
+#if SANITIZER_INTERCEPT_PRINTF
+#define INIT_PRINTF \
+ COMMON_INTERCEPT_FUNCTION(printf); \
+ COMMON_INTERCEPT_FUNCTION(sprintf); \
+ COMMON_INTERCEPT_FUNCTION(snprintf); \
+ COMMON_INTERCEPT_FUNCTION(asprintf); \
+ COMMON_INTERCEPT_FUNCTION(fprintf); \
+ COMMON_INTERCEPT_FUNCTION(vprintf); \
+ COMMON_INTERCEPT_FUNCTION(vsprintf); \
+ COMMON_INTERCEPT_FUNCTION(vsnprintf); \
+ COMMON_INTERCEPT_FUNCTION(vasprintf); \
+ COMMON_INTERCEPT_FUNCTION(vfprintf);
+#else
+#define INIT_PRINTF
+#endif
+
+#if SANITIZER_INTERCEPT_ISOC99_PRINTF
+#define INIT_ISOC99_PRINTF \
+ COMMON_INTERCEPT_FUNCTION(__isoc99_printf); \
+ COMMON_INTERCEPT_FUNCTION(__isoc99_sprintf); \
+ COMMON_INTERCEPT_FUNCTION(__isoc99_snprintf); \
+ COMMON_INTERCEPT_FUNCTION(__isoc99_fprintf); \
+ COMMON_INTERCEPT_FUNCTION(__isoc99_vprintf); \
+ COMMON_INTERCEPT_FUNCTION(__isoc99_vsprintf); \
+ COMMON_INTERCEPT_FUNCTION(__isoc99_vsnprintf); \
+ COMMON_INTERCEPT_FUNCTION(__isoc99_vfprintf);
+#else
+#define INIT_ISOC99_PRINTF
+#endif
+
#if SANITIZER_INTERCEPT_IOCTL
#include "sanitizer_common_interceptors_ioctl.inc"
INTERCEPTOR(int, ioctl, int d, unsigned request, void *arg) {
@@ -656,7 +1018,14 @@ INTERCEPTOR(int, ioctl, int d, unsigned request, void *arg) {
if (!common_flags()->handle_ioctl) return REAL(ioctl)(d, request, arg);
const ioctl_desc *desc = ioctl_lookup(request);
- if (!desc) Printf("WARNING: unknown ioctl %x\n", request);
+ ioctl_desc decoded_desc;
+ if (!desc) {
+ VPrintf(2, "Decoding unknown ioctl 0x%x\n", request);
+ if (!ioctl_decode(request, &decoded_desc))
+ Printf("WARNING: failed decoding unknown ioctl 0x%x\n", request);
+ else
+ desc = &decoded_desc;
+ }
if (desc) ioctl_common_pre(ctx, desc, d, request, arg);
int res = REAL(ioctl)(d, request, arg);
@@ -671,35 +1040,88 @@ INTERCEPTOR(int, ioctl, int d, unsigned request, void *arg) {
#define INIT_IOCTL
#endif
+#if SANITIZER_INTERCEPT_GETPWNAM_AND_FRIENDS || \
+ SANITIZER_INTERCEPT_GETPWENT || SANITIZER_INTERCEPT_FGETPWENT || \
+ SANITIZER_INTERCEPT_GETPWENT_R || SANITIZER_INTERCEPT_GETPWNAM_R_AND_FRIENDS
+static void unpoison_passwd(void *ctx, __sanitizer_passwd *pwd) {
+ if (pwd) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwd, sizeof(*pwd));
+ if (pwd->pw_name)
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(pwd->pw_name,
+ REAL(strlen)(pwd->pw_name) + 1);
+ if (pwd->pw_passwd)
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(pwd->pw_passwd,
+ REAL(strlen)(pwd->pw_passwd) + 1);
+#if !SANITIZER_ANDROID
+ if (pwd->pw_gecos)
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(pwd->pw_gecos,
+ REAL(strlen)(pwd->pw_gecos) + 1);
+#endif
+#if SANITIZER_MAC
+ if (pwd->pw_class)
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(pwd->pw_class,
+ REAL(strlen)(pwd->pw_class) + 1);
+#endif
+ if (pwd->pw_dir)
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(pwd->pw_dir,
+ REAL(strlen)(pwd->pw_dir) + 1);
+ if (pwd->pw_shell)
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(pwd->pw_shell,
+ REAL(strlen)(pwd->pw_shell) + 1);
+ }
+}
+
+static void unpoison_group(void *ctx, __sanitizer_group *grp) {
+ if (grp) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, grp, sizeof(*grp));
+ if (grp->gr_name)
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(grp->gr_name,
+ REAL(strlen)(grp->gr_name) + 1);
+ if (grp->gr_passwd)
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(grp->gr_passwd,
+ REAL(strlen)(grp->gr_passwd) + 1);
+ char **p = grp->gr_mem;
+ for (; *p; ++p) {
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(*p, REAL(strlen)(*p) + 1);
+ }
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(grp->gr_mem,
+ (p - grp->gr_mem + 1) * sizeof(*p));
+ }
+}
+#endif // SANITIZER_INTERCEPT_GETPWNAM_AND_FRIENDS ||
+ // SANITIZER_INTERCEPT_GETPWENT || SANITIZER_INTERCEPT_FGETPWENT ||
+ // SANITIZER_INTERCEPT_GETPWENT_R ||
+ // SANITIZER_INTERCEPT_GETPWNAM_R_AND_FRIENDS
+
#if SANITIZER_INTERCEPT_GETPWNAM_AND_FRIENDS
-INTERCEPTOR(void *, getpwnam, const char *name) {
+INTERCEPTOR(__sanitizer_passwd *, getpwnam, const char *name) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, getpwnam, name);
COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1);
- void *res = REAL(getpwnam)(name);
- if (res != 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_passwd_sz);
+ __sanitizer_passwd *res = REAL(getpwnam)(name);
+ if (res != 0) unpoison_passwd(ctx, res);
return res;
}
-INTERCEPTOR(void *, getpwuid, u32 uid) {
+INTERCEPTOR(__sanitizer_passwd *, getpwuid, u32 uid) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, getpwuid, uid);
- void *res = REAL(getpwuid)(uid);
- if (res != 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_passwd_sz);
+ __sanitizer_passwd *res = REAL(getpwuid)(uid);
+ if (res != 0) unpoison_passwd(ctx, res);
return res;
}
-INTERCEPTOR(void *, getgrnam, const char *name) {
+INTERCEPTOR(__sanitizer_group *, getgrnam, const char *name) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, getgrnam, name);
COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1);
- void *res = REAL(getgrnam)(name);
- if (res != 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_group_sz);
+ __sanitizer_group *res = REAL(getgrnam)(name);
+ if (res != 0) unpoison_group(ctx, res);
return res;
}
-INTERCEPTOR(void *, getgrgid, u32 gid) {
+INTERCEPTOR(__sanitizer_group *, getgrgid, u32 gid) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, getgrgid, gid);
- void *res = REAL(getgrgid)(gid);
- if (res != 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_group_sz);
+ __sanitizer_group *res = REAL(getgrgid)(gid);
+ if (res != 0) unpoison_group(ctx, res);
return res;
}
#define INIT_GETPWNAM_AND_FRIENDS \
@@ -712,50 +1134,66 @@ INTERCEPTOR(void *, getgrgid, u32 gid) {
#endif
#if SANITIZER_INTERCEPT_GETPWNAM_R_AND_FRIENDS
-INTERCEPTOR(int, getpwnam_r, const char *name, void *pwd, char *buf,
- SIZE_T buflen, void **result) {
+INTERCEPTOR(int, getpwnam_r, const char *name, __sanitizer_passwd *pwd,
+ char *buf, SIZE_T buflen, __sanitizer_passwd **result) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, getpwnam_r, name, pwd, buf, buflen, result);
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.
int res = REAL(getpwnam_r)(name, pwd, buf, buflen, result);
if (!res) {
- COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwd, struct_passwd_sz);
+ if (result && *result) unpoison_passwd(ctx, *result);
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, buflen);
}
+ if (result) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
return res;
}
-INTERCEPTOR(int, getpwuid_r, u32 uid, void *pwd, char *buf, SIZE_T buflen,
- void **result) {
+INTERCEPTOR(int, getpwuid_r, u32 uid, __sanitizer_passwd *pwd, char *buf,
+ SIZE_T buflen, __sanitizer_passwd **result) {
void *ctx;
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.
int res = REAL(getpwuid_r)(uid, pwd, buf, buflen, result);
if (!res) {
- COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwd, struct_passwd_sz);
+ if (result && *result) unpoison_passwd(ctx, *result);
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, buflen);
}
+ if (result) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
return res;
}
-INTERCEPTOR(int, getgrnam_r, const char *name, void *grp, char *buf,
- SIZE_T buflen, void **result) {
+INTERCEPTOR(int, getgrnam_r, const char *name, __sanitizer_group *grp,
+ char *buf, SIZE_T buflen, __sanitizer_group **result) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, getgrnam_r, name, grp, buf, buflen, result);
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.
int res = REAL(getgrnam_r)(name, grp, buf, buflen, result);
if (!res) {
- COMMON_INTERCEPTOR_WRITE_RANGE(ctx, grp, struct_group_sz);
+ if (result && *result) unpoison_group(ctx, *result);
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, buflen);
}
+ if (result) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
return res;
}
-INTERCEPTOR(int, getgrgid_r, u32 gid, void *grp, char *buf, SIZE_T buflen,
- void **result) {
+INTERCEPTOR(int, getgrgid_r, u32 gid, __sanitizer_group *grp, char *buf,
+ SIZE_T buflen, __sanitizer_group **result) {
void *ctx;
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.
int res = REAL(getgrgid_r)(gid, grp, buf, buflen, result);
if (!res) {
- COMMON_INTERCEPTOR_WRITE_RANGE(ctx, grp, struct_group_sz);
+ if (result && *result) unpoison_group(ctx, *result);
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, buflen);
}
+ if (result) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
return res;
}
#define INIT_GETPWNAM_R_AND_FRIENDS \
@@ -767,10 +1205,160 @@ INTERCEPTOR(int, getgrgid_r, u32 gid, void *grp, char *buf, SIZE_T buflen,
#define INIT_GETPWNAM_R_AND_FRIENDS
#endif
+#if SANITIZER_INTERCEPT_GETPWENT
+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);
+ 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);;
+ return res;
+}
+#define INIT_GETPWENT \
+ COMMON_INTERCEPT_FUNCTION(getpwent); \
+ COMMON_INTERCEPT_FUNCTION(getgrent);
+#else
+#define INIT_GETPWENT
+#endif
+
+#if SANITIZER_INTERCEPT_FGETPWENT
+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);
+ 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);
+ return res;
+}
+#define INIT_FGETPWENT \
+ COMMON_INTERCEPT_FUNCTION(fgetpwent); \
+ COMMON_INTERCEPT_FUNCTION(fgetgrent);
+#else
+#define INIT_FGETPWENT
+#endif
+
+#if SANITIZER_INTERCEPT_GETPWENT_R
+INTERCEPTOR(int, getpwent_r, __sanitizer_passwd *pwbuf, char *buf,
+ SIZE_T buflen, __sanitizer_passwd **pwbufp) {
+ void *ctx;
+ 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.
+ int res = REAL(getpwent_r)(pwbuf, buf, buflen, pwbufp);
+ if (!res) {
+ if (pwbufp && *pwbufp) unpoison_passwd(ctx, *pwbufp);
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, buflen);
+ }
+ if (pwbufp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwbufp, sizeof(*pwbufp));
+ return res;
+}
+INTERCEPTOR(int, fgetpwent_r, void *fp, __sanitizer_passwd *pwbuf, char *buf,
+ SIZE_T buflen, __sanitizer_passwd **pwbufp) {
+ void *ctx;
+ 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.
+ int res = REAL(fgetpwent_r)(fp, pwbuf, buf, buflen, pwbufp);
+ if (!res) {
+ if (pwbufp && *pwbufp) unpoison_passwd(ctx, *pwbufp);
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, buflen);
+ }
+ if (pwbufp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwbufp, sizeof(*pwbufp));
+ return res;
+}
+INTERCEPTOR(int, getgrent_r, __sanitizer_group *pwbuf, char *buf, SIZE_T buflen,
+ __sanitizer_group **pwbufp) {
+ void *ctx;
+ 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.
+ int res = REAL(getgrent_r)(pwbuf, buf, buflen, pwbufp);
+ if (!res) {
+ if (pwbufp && *pwbufp) unpoison_group(ctx, *pwbufp);
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, buflen);
+ }
+ if (pwbufp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwbufp, sizeof(*pwbufp));
+ return res;
+}
+INTERCEPTOR(int, fgetgrent_r, void *fp, __sanitizer_group *pwbuf, char *buf,
+ SIZE_T buflen, __sanitizer_group **pwbufp) {
+ void *ctx;
+ 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.
+ int res = REAL(fgetgrent_r)(fp, pwbuf, buf, buflen, pwbufp);
+ if (!res) {
+ if (pwbufp && *pwbufp) unpoison_group(ctx, *pwbufp);
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, buflen);
+ }
+ if (pwbufp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwbufp, sizeof(*pwbufp));
+ return res;
+}
+#define INIT_GETPWENT_R \
+ COMMON_INTERCEPT_FUNCTION(getpwent_r); \
+ COMMON_INTERCEPT_FUNCTION(fgetpwent_r); \
+ COMMON_INTERCEPT_FUNCTION(getgrent_r); \
+ COMMON_INTERCEPT_FUNCTION(fgetgrent_r);
+#else
+#define INIT_GETPWENT_R
+#endif
+
+#if SANITIZER_INTERCEPT_SETPWENT
+// The only thing these interceptors do is disable any nested interceptors.
+// These functions may open nss modules and call uninstrumented functions from
+// them, and we don't want things like strlen() to trigger.
+INTERCEPTOR(void, setpwent, int dummy) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, setpwent, dummy);
+ REAL(setpwent)(dummy);
+}
+INTERCEPTOR(void, endpwent, int dummy) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, endpwent, dummy);
+ REAL(endpwent)(dummy);
+}
+INTERCEPTOR(void, setgrent, int dummy) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, setgrent, dummy);
+ REAL(setgrent)(dummy);
+}
+INTERCEPTOR(void, endgrent, int dummy) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, endgrent, dummy);
+ REAL(endgrent)(dummy);
+}
+#define INIT_SETPWENT \
+ COMMON_INTERCEPT_FUNCTION(setpwent); \
+ COMMON_INTERCEPT_FUNCTION(endpwent); \
+ COMMON_INTERCEPT_FUNCTION(setgrent); \
+ COMMON_INTERCEPT_FUNCTION(endgrent);
+#else
+#define INIT_SETPWENT
+#endif
+
#if SANITIZER_INTERCEPT_CLOCK_GETTIME
INTERCEPTOR(int, clock_getres, u32 clk_id, void *tp) {
void *ctx;
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.
int res = REAL(clock_getres)(clk_id, tp);
if (!res && tp) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tp, struct_timespec_sz);
@@ -780,6 +1368,9 @@ INTERCEPTOR(int, clock_getres, u32 clk_id, void *tp) {
INTERCEPTOR(int, clock_gettime, u32 clk_id, void *tp) {
void *ctx;
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.
int res = REAL(clock_gettime)(clk_id, tp);
if (!res) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tp, struct_timespec_sz);
@@ -804,6 +1395,9 @@ INTERCEPTOR(int, clock_settime, u32 clk_id, const void *tp) {
INTERCEPTOR(int, getitimer, int which, void *curr_value) {
void *ctx;
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.
int res = REAL(getitimer)(which, curr_value);
if (!res && curr_value) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, curr_value, struct_itimerval_sz);
@@ -815,6 +1409,9 @@ INTERCEPTOR(int, setitimer, int which, const void *new_value, void *old_value) {
COMMON_INTERCEPTOR_ENTER(ctx, setitimer, which, new_value, old_value);
if (new_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.
int res = REAL(setitimer)(which, new_value, old_value);
if (!res && old_value) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, old_value, struct_itimerval_sz);
@@ -842,33 +1439,32 @@ static void unpoison_glob_t(void *ctx, __sanitizer_glob_t *pglob) {
}
static THREADLOCAL __sanitizer_glob_t *pglob_copy;
-static THREADLOCAL void *glob_ctx;
static void wrapped_gl_closedir(void *dir) {
- COMMON_INTERCEPTOR_UNPOISON_PARAM(glob_ctx, 1);
+ COMMON_INTERCEPTOR_UNPOISON_PARAM(1);
pglob_copy->gl_closedir(dir);
}
static void *wrapped_gl_readdir(void *dir) {
- COMMON_INTERCEPTOR_UNPOISON_PARAM(glob_ctx, 1);
+ COMMON_INTERCEPTOR_UNPOISON_PARAM(1);
return pglob_copy->gl_readdir(dir);
}
static void *wrapped_gl_opendir(const char *s) {
- COMMON_INTERCEPTOR_UNPOISON_PARAM(glob_ctx, 1);
- COMMON_INTERCEPTOR_WRITE_RANGE(glob_ctx, s, REAL(strlen)(s) + 1);
+ COMMON_INTERCEPTOR_UNPOISON_PARAM(1);
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(s, REAL(strlen)(s) + 1);
return pglob_copy->gl_opendir(s);
}
static int wrapped_gl_lstat(const char *s, void *st) {
- COMMON_INTERCEPTOR_UNPOISON_PARAM(glob_ctx, 2);
- COMMON_INTERCEPTOR_WRITE_RANGE(glob_ctx, s, REAL(strlen)(s) + 1);
+ COMMON_INTERCEPTOR_UNPOISON_PARAM(2);
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(s, REAL(strlen)(s) + 1);
return pglob_copy->gl_lstat(s, st);
}
static int wrapped_gl_stat(const char *s, void *st) {
- COMMON_INTERCEPTOR_UNPOISON_PARAM(glob_ctx, 2);
- COMMON_INTERCEPTOR_WRITE_RANGE(glob_ctx, s, REAL(strlen)(s) + 1);
+ COMMON_INTERCEPTOR_UNPOISON_PARAM(2);
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(s, REAL(strlen)(s) + 1);
return pglob_copy->gl_stat(s, st);
}
@@ -888,7 +1484,6 @@ INTERCEPTOR(int, glob, const char *pattern, int flags,
Swap(pglob->gl_lstat, glob_copy.gl_lstat);
Swap(pglob->gl_stat, glob_copy.gl_stat);
pglob_copy = &glob_copy;
- glob_ctx = ctx;
}
int res = REAL(glob)(pattern, flags, errfunc, pglob);
if (flags & glob_altdirfunc) {
@@ -899,7 +1494,6 @@ INTERCEPTOR(int, glob, const char *pattern, int flags,
Swap(pglob->gl_stat, glob_copy.gl_stat);
}
pglob_copy = 0;
- glob_ctx = 0;
if ((!res || res == glob_nomatch) && pglob) unpoison_glob_t(ctx, pglob);
return res;
}
@@ -920,7 +1514,6 @@ INTERCEPTOR(int, glob64, const char *pattern, int flags,
Swap(pglob->gl_lstat, glob_copy.gl_lstat);
Swap(pglob->gl_stat, glob_copy.gl_stat);
pglob_copy = &glob_copy;
- glob_ctx = ctx;
}
int res = REAL(glob64)(pattern, flags, errfunc, pglob);
if (flags & glob_altdirfunc) {
@@ -931,7 +1524,6 @@ INTERCEPTOR(int, glob64, const char *pattern, int flags,
Swap(pglob->gl_stat, glob_copy.gl_stat);
}
pglob_copy = 0;
- glob_ctx = 0;
if ((!res || res == glob_nomatch) && pglob) unpoison_glob_t(ctx, pglob);
return res;
}
@@ -949,15 +1541,27 @@ INTERCEPTOR(int, glob64, const char *pattern, int flags,
INTERCEPTOR_WITH_SUFFIX(int, wait, int *status) {
void *ctx;
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.
int res = REAL(wait)(status);
if (res != -1 && status)
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status));
return res;
}
+// On FreeBSD id_t is always 64-bit wide.
+#if SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32)
+INTERCEPTOR_WITH_SUFFIX(int, waitid, int idtype, long long id, void *infop,
+ int options) {
+#else
INTERCEPTOR_WITH_SUFFIX(int, waitid, int idtype, int id, void *infop,
int options) {
+#endif
void *ctx;
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.
int res = REAL(waitid)(idtype, id, infop, options);
if (res != -1 && infop)
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, infop, siginfo_t_sz);
@@ -966,6 +1570,9 @@ INTERCEPTOR_WITH_SUFFIX(int, waitid, int idtype, int id, void *infop,
INTERCEPTOR_WITH_SUFFIX(int, waitpid, int pid, int *status, int options) {
void *ctx;
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.
int res = REAL(waitpid)(pid, status, options);
if (res != -1 && status)
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status));
@@ -974,6 +1581,9 @@ INTERCEPTOR_WITH_SUFFIX(int, waitpid, int pid, int *status, int options) {
INTERCEPTOR(int, wait3, int *status, int options, void *rusage) {
void *ctx;
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.
int res = REAL(wait3)(status, options, rusage);
if (res != -1) {
if (status) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status));
@@ -981,9 +1591,28 @@ INTERCEPTOR(int, wait3, int *status, int options, void *rusage) {
}
return res;
}
+#if SANITIZER_ANDROID
+INTERCEPTOR(int, __wait4, int pid, int *status, int options, void *rusage) {
+ void *ctx;
+ 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.
+ int res = REAL(__wait4)(pid, status, options, rusage);
+ if (res != -1) {
+ if (status) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status));
+ if (rusage) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, rusage, struct_rusage_sz);
+ }
+ return res;
+}
+#define INIT_WAIT4 COMMON_INTERCEPT_FUNCTION(__wait4);
+#else
INTERCEPTOR(int, wait4, int pid, int *status, int options, void *rusage) {
void *ctx;
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.
int res = REAL(wait4)(pid, status, options, rusage);
if (res != -1) {
if (status) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status));
@@ -991,14 +1620,16 @@ INTERCEPTOR(int, wait4, int pid, int *status, int options, void *rusage) {
}
return res;
}
+#define INIT_WAIT4 COMMON_INTERCEPT_FUNCTION(wait4);
+#endif // SANITIZER_ANDROID
#define INIT_WAIT \
COMMON_INTERCEPT_FUNCTION(wait); \
COMMON_INTERCEPT_FUNCTION(waitid); \
COMMON_INTERCEPT_FUNCTION(waitpid); \
- COMMON_INTERCEPT_FUNCTION(wait3); \
- COMMON_INTERCEPT_FUNCTION(wait4);
+ COMMON_INTERCEPT_FUNCTION(wait3);
#else
#define INIT_WAIT
+#define INIT_WAIT4
#endif
#if SANITIZER_INTERCEPT_INET
@@ -1008,6 +1639,9 @@ INTERCEPTOR(char *, inet_ntop, int af, const void *src, char *dst, u32 size) {
uptr sz = __sanitizer_in_addr_sz(af);
if (sz) COMMON_INTERCEPTOR_READ_RANGE(ctx, src, sz);
// 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.
char *res = REAL(inet_ntop)(af, src, dst, size);
if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
return res;
@@ -1016,6 +1650,9 @@ INTERCEPTOR(int, inet_pton, int af, const char *src, void *dst) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, inet_pton, af, src, 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.
int res = REAL(inet_pton)(af, src, dst);
if (res == 1) {
uptr sz = __sanitizer_in_addr_sz(af);
@@ -1035,6 +1672,9 @@ INTERCEPTOR(int, inet_aton, const char *cp, void *dst) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, inet_aton, cp, 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.
int res = REAL(inet_aton)(cp, dst);
if (res != 0) {
uptr sz = __sanitizer_in_addr_sz(af_inet);
@@ -1051,6 +1691,9 @@ INTERCEPTOR(int, inet_aton, const char *cp, void *dst) {
INTERCEPTOR(int, pthread_getschedparam, uptr thread, int *policy, int *param) {
void *ctx;
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.
int res = REAL(pthread_getschedparam)(thread, policy, param);
if (res == 0) {
if (policy) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, policy, sizeof(*policy));
@@ -1075,6 +1718,9 @@ INTERCEPTOR(int, getaddrinfo, char *node, char *service,
COMMON_INTERCEPTOR_READ_RANGE(ctx, service, REAL(strlen)(service) + 1);
if (hints)
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.
int res = REAL(getaddrinfo)(node, service, hints, out);
if (res == 0 && out) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, out, sizeof(*out));
@@ -1104,6 +1750,9 @@ INTERCEPTOR(int, getnameinfo, void *sockaddr, unsigned salen, char *host,
serv, servlen, flags);
// FIXME: consider adding READ_RANGE(sockaddr, salen)
// 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.
int res =
REAL(getnameinfo)(sockaddr, salen, host, hostlen, serv, servlen, flags);
if (res == 0) {
@@ -1125,6 +1774,9 @@ INTERCEPTOR(int, getsockname, int sock_fd, void *addr, int *addrlen) {
COMMON_INTERCEPTOR_ENTER(ctx, getsockname, sock_fd, addr, addrlen);
COMMON_INTERCEPTOR_READ_RANGE(ctx, addrlen, sizeof(*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.
int res = REAL(getsockname)(sock_fd, addr, addrlen);
if (res == 0) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, Min(addrlen_in, *addrlen));
@@ -1202,23 +1854,54 @@ INTERCEPTOR(struct __sanitizer_hostent *, gethostbyname2, char *name, int af) {
#endif
#if SANITIZER_INTERCEPT_GETHOSTBYNAME_R
+INTERCEPTOR(int, gethostbyname_r, char *name, struct __sanitizer_hostent *ret,
+ char *buf, SIZE_T buflen, __sanitizer_hostent **result,
+ int *h_errnop) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, gethostbyname_r, name, ret, buf, buflen, 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.
+ int res = REAL(gethostbyname_r)(name, ret, buf, buflen, result, h_errnop);
+ if (result) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
+ if (res == 0 && *result) write_hostent(ctx, *result);
+ }
+ if (h_errnop)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, h_errnop, sizeof(*h_errnop));
+ return res;
+}
+#define INIT_GETHOSTBYNAME_R COMMON_INTERCEPT_FUNCTION(gethostbyname_r);
+#else
+#define INIT_GETHOSTBYNAME_R
+#endif
+
+#if SANITIZER_INTERCEPT_GETHOSTENT_R
INTERCEPTOR(int, gethostent_r, struct __sanitizer_hostent *ret, char *buf,
SIZE_T buflen, __sanitizer_hostent **result, int *h_errnop) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, gethostent_r, ret, buf, buflen, 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.
int res = REAL(gethostent_r)(ret, buf, buflen, result, h_errnop);
- if (res == 0) {
- if (result) {
- COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
- if (*result) write_hostent(ctx, *result);
- }
- if (h_errnop)
- COMMON_INTERCEPTOR_WRITE_RANGE(ctx, h_errnop, sizeof(*h_errnop));
+ if (result) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
+ if (res == 0 && *result) write_hostent(ctx, *result);
}
+ if (h_errnop)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, h_errnop, sizeof(*h_errnop));
return res;
}
+#define INIT_GETHOSTENT_R \
+ COMMON_INTERCEPT_FUNCTION(gethostent_r);
+#else
+#define INIT_GETHOSTENT_R
+#endif
+#if SANITIZER_INTERCEPT_GETHOSTBYADDR_R
INTERCEPTOR(int, gethostbyaddr_r, void *addr, int len, int type,
struct __sanitizer_hostent *ret, char *buf, SIZE_T buflen,
__sanitizer_hostent **result, int *h_errnop) {
@@ -1226,62 +1909,49 @@ INTERCEPTOR(int, gethostbyaddr_r, void *addr, int len, int type,
COMMON_INTERCEPTOR_ENTER(ctx, gethostbyaddr_r, addr, len, type, ret, buf,
buflen, result, h_errnop);
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.
int res = REAL(gethostbyaddr_r)(addr, len, type, ret, buf, buflen, result,
h_errnop);
- if (res == 0) {
- if (result) {
- COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
- if (*result) write_hostent(ctx, *result);
- }
- if (h_errnop)
- COMMON_INTERCEPTOR_WRITE_RANGE(ctx, h_errnop, sizeof(*h_errnop));
- }
- return res;
-}
-
-INTERCEPTOR(int, gethostbyname_r, char *name, struct __sanitizer_hostent *ret,
- char *buf, SIZE_T buflen, __sanitizer_hostent **result,
- int *h_errnop) {
- void *ctx;
- COMMON_INTERCEPTOR_ENTER(ctx, gethostbyname_r, name, ret, buf, buflen, result,
- h_errnop);
- int res = REAL(gethostbyname_r)(name, ret, buf, buflen, result, h_errnop);
- if (res == 0) {
- if (result) {
- COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
- if (*result) write_hostent(ctx, *result);
- }
- if (h_errnop)
- COMMON_INTERCEPTOR_WRITE_RANGE(ctx, h_errnop, sizeof(*h_errnop));
+ if (result) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
+ if (res == 0 && *result) write_hostent(ctx, *result);
}
+ if (h_errnop)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, h_errnop, sizeof(*h_errnop));
return res;
}
+#define INIT_GETHOSTBYADDR_R \
+ COMMON_INTERCEPT_FUNCTION(gethostbyaddr_r);
+#else
+#define INIT_GETHOSTBYADDR_R
+#endif
+#if SANITIZER_INTERCEPT_GETHOSTBYNAME2_R
INTERCEPTOR(int, gethostbyname2_r, char *name, int af,
struct __sanitizer_hostent *ret, char *buf, SIZE_T buflen,
__sanitizer_hostent **result, int *h_errnop) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, gethostbyname2_r, name, af, ret, buf, buflen,
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.
int res =
REAL(gethostbyname2_r)(name, af, ret, buf, buflen, result, h_errnop);
- if (res == 0) {
- if (result) {
- COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
- if (*result) write_hostent(ctx, *result);
- }
- if (h_errnop)
- COMMON_INTERCEPTOR_WRITE_RANGE(ctx, h_errnop, sizeof(*h_errnop));
+ if (result) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
+ if (res == 0 && *result) write_hostent(ctx, *result);
}
+ if (h_errnop)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, h_errnop, sizeof(*h_errnop));
return res;
}
-#define INIT_GETHOSTBYNAME_R \
- COMMON_INTERCEPT_FUNCTION(gethostent_r); \
- COMMON_INTERCEPT_FUNCTION(gethostbyaddr_r); \
- COMMON_INTERCEPT_FUNCTION(gethostbyname_r); \
+#define INIT_GETHOSTBYNAME2_R \
COMMON_INTERCEPT_FUNCTION(gethostbyname2_r);
#else
-#define INIT_GETHOSTBYNAME_R
+#define INIT_GETHOSTBYNAME2_R
#endif
#if SANITIZER_INTERCEPT_GETSOCKOPT
@@ -1291,6 +1961,9 @@ INTERCEPTOR(int, getsockopt, int sockfd, int level, int optname, void *optval,
COMMON_INTERCEPTOR_ENTER(ctx, getsockopt, sockfd, level, optname, optval,
optlen);
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.
int res = REAL(getsockopt)(sockfd, level, optname, optval, optlen);
if (res == 0)
if (optval && optlen) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, optval, *optlen);
@@ -1305,7 +1978,7 @@ INTERCEPTOR(int, getsockopt, int sockfd, int level, int optname, void *optval,
INTERCEPTOR(int, accept, int fd, void *addr, unsigned *addrlen) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, accept, fd, addr, addrlen);
- unsigned addrlen0;
+ unsigned addrlen0 = 0;
if (addrlen) {
COMMON_INTERCEPTOR_READ_RANGE(ctx, addrlen, sizeof(*addrlen));
addrlen0 = *addrlen;
@@ -1327,11 +2000,14 @@ INTERCEPTOR(int, accept, int fd, void *addr, unsigned *addrlen) {
INTERCEPTOR(int, accept4, int fd, void *addr, unsigned *addrlen, int f) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, accept4, fd, addr, addrlen, f);
- unsigned addrlen0;
+ unsigned addrlen0 = 0;
if (addrlen) {
COMMON_INTERCEPTOR_READ_RANGE(ctx, addrlen, sizeof(*addrlen));
addrlen0 = *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.
int fd2 = REAL(accept4)(fd, addr, addrlen, f);
if (fd2 >= 0) {
if (fd >= 0) COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, fd2);
@@ -1349,6 +2025,9 @@ INTERCEPTOR(int, accept4, int fd, void *addr, unsigned *addrlen, int f) {
INTERCEPTOR(double, modf, double x, double *iptr) {
void *ctx;
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.
double res = REAL(modf)(x, iptr);
if (iptr) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, iptr, sizeof(*iptr));
@@ -1358,6 +2037,9 @@ INTERCEPTOR(double, modf, double x, double *iptr) {
INTERCEPTOR(float, modff, float x, float *iptr) {
void *ctx;
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.
float res = REAL(modff)(x, iptr);
if (iptr) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, iptr, sizeof(*iptr));
@@ -1367,6 +2049,9 @@ INTERCEPTOR(float, modff, float x, float *iptr) {
INTERCEPTOR(long double, modfl, long double x, long double *iptr) {
void *ctx;
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.
long double res = REAL(modfl)(x, iptr);
if (iptr) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, iptr, sizeof(*iptr));
@@ -1399,10 +2084,16 @@ INTERCEPTOR(SSIZE_T, recvmsg, int fd, struct __sanitizer_msghdr *msg,
int flags) {
void *ctx;
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.
SSIZE_T res = REAL(recvmsg)(fd, msg, flags);
if (res >= 0) {
if (fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
- if (msg) write_msghdr(ctx, msg, res);
+ if (msg) {
+ write_msghdr(ctx, msg, res);
+ COMMON_INTERCEPTOR_HANDLE_RECVMSG(ctx, msg);
+ }
}
return res;
}
@@ -1417,6 +2108,9 @@ INTERCEPTOR(int, getpeername, int sockfd, void *addr, unsigned *addrlen) {
COMMON_INTERCEPTOR_ENTER(ctx, getpeername, sockfd, addr, addrlen);
unsigned addr_sz;
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.
int res = REAL(getpeername)(sockfd, addr, addrlen);
if (!res && addr && addrlen)
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, Min(addr_sz, *addrlen));
@@ -1430,6 +2124,9 @@ INTERCEPTOR(int, getpeername, int sockfd, void *addr, unsigned *addrlen) {
#if SANITIZER_INTERCEPT_SYSINFO
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.
COMMON_INTERCEPTOR_ENTER(ctx, sysinfo, info);
int res = REAL(sysinfo)(info);
if (!res && info)
@@ -1445,6 +2142,9 @@ INTERCEPTOR(int, sysinfo, void *info) {
INTERCEPTOR(__sanitizer_dirent *, readdir, void *dirp) {
void *ctx;
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.
__sanitizer_dirent *res = REAL(readdir)(dirp);
if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, res->d_reclen);
return res;
@@ -1454,6 +2154,9 @@ INTERCEPTOR(int, readdir_r, void *dirp, __sanitizer_dirent *entry,
__sanitizer_dirent **result) {
void *ctx;
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.
int res = REAL(readdir_r)(dirp, entry, result);
if (!res) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
@@ -1474,6 +2177,9 @@ INTERCEPTOR(int, readdir_r, void *dirp, __sanitizer_dirent *entry,
INTERCEPTOR(__sanitizer_dirent64 *, readdir64, void *dirp) {
void *ctx;
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.
__sanitizer_dirent64 *res = REAL(readdir64)(dirp);
if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, res->d_reclen);
return res;
@@ -1483,6 +2189,9 @@ INTERCEPTOR(int, readdir64_r, void *dirp, __sanitizer_dirent64 *entry,
__sanitizer_dirent64 **result) {
void *ctx;
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.
int res = REAL(readdir64_r)(dirp, entry, result);
if (!res) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
@@ -1518,10 +2227,13 @@ INTERCEPTOR(uptr, ptrace, int request, int pid, void *addr, void *data) {
}
}
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
uptr res = REAL(ptrace)(request, pid, addr, data);
if (!res && data) {
- // Note that PEEK* requests assing different meaning to the return value.
+ // Note that PEEK* requests assign different meaning to the return value.
// This function does not handle them (nor does it need to).
if (request == ptrace_getregs)
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, struct_user_regs_struct_sz);
@@ -1531,6 +2243,8 @@ INTERCEPTOR(uptr, ptrace, int request, int pid, void *addr, void *data) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, struct_user_fpxregs_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);
@@ -1564,6 +2278,9 @@ INTERCEPTOR(char *, setlocale, int category, char *locale) {
INTERCEPTOR(char *, getcwd, char *buf, SIZE_T size) {
void *ctx;
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.
char *res = REAL(getcwd)(buf, size);
if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
return res;
@@ -1577,6 +2294,9 @@ INTERCEPTOR(char *, getcwd, char *buf, SIZE_T size) {
INTERCEPTOR(char *, get_current_dir_name, int fake) {
void *ctx;
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.
char *res = REAL(get_current_dir_name)(fake);
if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
return res;
@@ -1592,6 +2312,9 @@ INTERCEPTOR(char *, get_current_dir_name, int fake) {
INTERCEPTOR(INTMAX_T, strtoimax, const char *nptr, char **endptr, int base) {
void *ctx;
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.
INTMAX_T res = REAL(strtoimax)(nptr, endptr, base);
if (endptr) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, endptr, sizeof(*endptr));
return res;
@@ -1600,6 +2323,9 @@ INTERCEPTOR(INTMAX_T, strtoimax, const char *nptr, char **endptr, int base) {
INTERCEPTOR(INTMAX_T, strtoumax, const char *nptr, char **endptr, int base) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, strtoumax, nptr, endptr, base);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
INTMAX_T res = REAL(strtoumax)(nptr, endptr, base);
if (endptr) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, endptr, sizeof(*endptr));
return res;
@@ -1616,6 +2342,9 @@ INTERCEPTOR(INTMAX_T, strtoumax, const char *nptr, char **endptr, int base) {
INTERCEPTOR(SIZE_T, mbstowcs, wchar_t *dest, const char *src, SIZE_T len) {
void *ctx;
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.
SIZE_T res = REAL(mbstowcs)(dest, src, len);
if (res != (SIZE_T) - 1 && dest) {
SIZE_T write_cnt = res + (res < len);
@@ -1630,6 +2359,9 @@ INTERCEPTOR(SIZE_T, mbsrtowcs, wchar_t *dest, const char **src, SIZE_T len,
COMMON_INTERCEPTOR_ENTER(ctx, mbsrtowcs, dest, src, len, ps);
if (src) COMMON_INTERCEPTOR_READ_RANGE(ctx, src, sizeof(*src));
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.
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
@@ -1657,6 +2389,9 @@ INTERCEPTOR(SIZE_T, mbsnrtowcs, wchar_t *dest, const char **src, SIZE_T nms,
if (nms) COMMON_INTERCEPTOR_READ_RANGE(ctx, *src, 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.
SIZE_T res = REAL(mbsnrtowcs)(dest, src, nms, len, ps);
if (res != (SIZE_T)(-1) && dest && src) {
SIZE_T write_cnt = res + !*src;
@@ -1674,6 +2409,9 @@ INTERCEPTOR(SIZE_T, mbsnrtowcs, wchar_t *dest, const char **src, SIZE_T nms,
INTERCEPTOR(SIZE_T, wcstombs, char *dest, const wchar_t *src, SIZE_T len) {
void *ctx;
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.
SIZE_T res = REAL(wcstombs)(dest, src, len);
if (res != (SIZE_T) - 1 && dest) {
SIZE_T write_cnt = res + (res < len);
@@ -1688,6 +2426,9 @@ INTERCEPTOR(SIZE_T, wcsrtombs, char *dest, const wchar_t **src, SIZE_T len,
COMMON_INTERCEPTOR_ENTER(ctx, wcsrtombs, dest, src, len, ps);
if (src) COMMON_INTERCEPTOR_READ_RANGE(ctx, src, sizeof(*src));
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.
SIZE_T res = REAL(wcsrtombs)(dest, src, len, ps);
if (res != (SIZE_T) - 1 && dest && src) {
SIZE_T write_cnt = res + !*src;
@@ -1713,6 +2454,9 @@ INTERCEPTOR(SIZE_T, wcsnrtombs, char *dest, const wchar_t **src, SIZE_T nms,
if (nms) COMMON_INTERCEPTOR_READ_RANGE(ctx, *src, 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.
SIZE_T res = REAL(wcsnrtombs)(dest, src, nms, len, ps);
if (res != (SIZE_T) - 1 && dest && src) {
SIZE_T write_cnt = res + !*src;
@@ -1730,6 +2474,9 @@ INTERCEPTOR(SIZE_T, wcsnrtombs, char *dest, const wchar_t **src, SIZE_T nms,
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.
int res = REAL(tcgetattr)(fd, termios_p);
if (!res && termios_p)
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, termios_p, struct_termios_sz);
@@ -1784,6 +2531,9 @@ INTERCEPTOR(char *, canonicalize_file_name, const char *path) {
INTERCEPTOR(SIZE_T, confstr, int name, char *buf, SIZE_T len) {
void *ctx;
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.
SIZE_T res = REAL(confstr)(name, buf, len);
if (buf && res)
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, res < len ? res : len);
@@ -1798,6 +2548,9 @@ INTERCEPTOR(SIZE_T, confstr, int name, char *buf, SIZE_T len) {
INTERCEPTOR(int, sched_getaffinity, int pid, SIZE_T cpusetsize, void *mask) {
void *ctx;
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.
int res = REAL(sched_getaffinity)(pid, cpusetsize, mask);
if (mask && !res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, mask, cpusetsize);
return res;
@@ -1812,7 +2565,7 @@ INTERCEPTOR(char *, strerror, int errnum) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, strerror, errnum);
char *res = REAL(strerror)(errnum);
- if (res) COMMON_INTERCEPTOR_INITIALIZE_RANGE(ctx, res, REAL(strlen)(res) + 1);
+ if (res) COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, REAL(strlen)(res) + 1);
return res;
}
#define INIT_STRERROR COMMON_INTERCEPT_FUNCTION(strerror);
@@ -1824,6 +2577,9 @@ INTERCEPTOR(char *, strerror, int errnum) {
INTERCEPTOR(char *, strerror_r, int errnum, char *buf, SIZE_T buflen) {
void *ctx;
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.
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,
@@ -1848,28 +2604,45 @@ INTERCEPTOR(char *, strerror_r, int errnum, char *buf, SIZE_T buflen) {
#define INIT_STRERROR_R
#endif
+#if SANITIZER_INTERCEPT_XPG_STRERROR_R
+INTERCEPTOR(int, __xpg_strerror_r, int errnum, char *buf, SIZE_T buflen) {
+ void *ctx;
+ 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.
+ int res = REAL(__xpg_strerror_r)(errnum, buf, buflen);
+ // This version always returns a null-terminated string.
+ if (buf && buflen)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, REAL(strlen)(buf) + 1);
+ return res;
+}
+#define INIT_XPG_STRERROR_R COMMON_INTERCEPT_FUNCTION(__xpg_strerror_r);
+#else
+#define INIT_XPG_STRERROR_R
+#endif
+
#if SANITIZER_INTERCEPT_SCANDIR
typedef int (*scandir_filter_f)(const struct __sanitizer_dirent *);
typedef int (*scandir_compar_f)(const struct __sanitizer_dirent **,
const struct __sanitizer_dirent **);
-static THREADLOCAL void *scandir_ctx;
static THREADLOCAL scandir_filter_f scandir_filter;
static THREADLOCAL scandir_compar_f scandir_compar;
static int wrapped_scandir_filter(const struct __sanitizer_dirent *dir) {
- COMMON_INTERCEPTOR_UNPOISON_PARAM(scandir_ctx, 1);
- COMMON_INTERCEPTOR_WRITE_RANGE(scandir_ctx, dir, dir->d_reclen);
+ COMMON_INTERCEPTOR_UNPOISON_PARAM(1);
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(dir, dir->d_reclen);
return scandir_filter(dir);
}
static int wrapped_scandir_compar(const struct __sanitizer_dirent **a,
const struct __sanitizer_dirent **b) {
- COMMON_INTERCEPTOR_UNPOISON_PARAM(scandir_ctx, 2);
- COMMON_INTERCEPTOR_WRITE_RANGE(scandir_ctx, a, sizeof(*a));
- COMMON_INTERCEPTOR_WRITE_RANGE(scandir_ctx, *a, (*a)->d_reclen);
- COMMON_INTERCEPTOR_WRITE_RANGE(scandir_ctx, b, sizeof(*b));
- COMMON_INTERCEPTOR_WRITE_RANGE(scandir_ctx, *b, (*b)->d_reclen);
+ COMMON_INTERCEPTOR_UNPOISON_PARAM(2);
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(a, sizeof(*a));
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(*a, (*a)->d_reclen);
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(b, sizeof(*b));
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(*b, (*b)->d_reclen);
return scandir_compar(a, b);
}
@@ -1878,13 +2651,13 @@ INTERCEPTOR(int, scandir, char *dirp, __sanitizer_dirent ***namelist,
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, scandir, dirp, namelist, filter, compar);
if (dirp) COMMON_INTERCEPTOR_READ_RANGE(ctx, dirp, REAL(strlen)(dirp) + 1);
- CHECK_EQ(0, scandir_ctx);
- scandir_ctx = ctx;
scandir_filter = filter;
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_ctx = 0;
scandir_filter = 0;
scandir_compar = 0;
if (namelist && res > 0) {
@@ -1906,23 +2679,22 @@ typedef int (*scandir64_filter_f)(const struct __sanitizer_dirent64 *);
typedef int (*scandir64_compar_f)(const struct __sanitizer_dirent64 **,
const struct __sanitizer_dirent64 **);
-static THREADLOCAL void *scandir64_ctx;
static THREADLOCAL scandir64_filter_f scandir64_filter;
static THREADLOCAL scandir64_compar_f scandir64_compar;
static int wrapped_scandir64_filter(const struct __sanitizer_dirent64 *dir) {
- COMMON_INTERCEPTOR_UNPOISON_PARAM(scandir64_ctx, 1);
- COMMON_INTERCEPTOR_WRITE_RANGE(scandir64_ctx, dir, dir->d_reclen);
+ COMMON_INTERCEPTOR_UNPOISON_PARAM(1);
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(dir, dir->d_reclen);
return scandir64_filter(dir);
}
static int wrapped_scandir64_compar(const struct __sanitizer_dirent64 **a,
const struct __sanitizer_dirent64 **b) {
- COMMON_INTERCEPTOR_UNPOISON_PARAM(scandir64_ctx, 2);
- COMMON_INTERCEPTOR_WRITE_RANGE(scandir64_ctx, a, sizeof(*a));
- COMMON_INTERCEPTOR_WRITE_RANGE(scandir64_ctx, *a, (*a)->d_reclen);
- COMMON_INTERCEPTOR_WRITE_RANGE(scandir64_ctx, b, sizeof(*b));
- COMMON_INTERCEPTOR_WRITE_RANGE(scandir64_ctx, *b, (*b)->d_reclen);
+ COMMON_INTERCEPTOR_UNPOISON_PARAM(2);
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(a, sizeof(*a));
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(*a, (*a)->d_reclen);
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(b, sizeof(*b));
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(*b, (*b)->d_reclen);
return scandir64_compar(a, b);
}
@@ -1931,14 +2703,14 @@ INTERCEPTOR(int, scandir64, char *dirp, __sanitizer_dirent64 ***namelist,
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, scandir64, dirp, namelist, filter, compar);
if (dirp) COMMON_INTERCEPTOR_READ_RANGE(ctx, dirp, REAL(strlen)(dirp) + 1);
- CHECK_EQ(0, scandir64_ctx);
- scandir64_ctx = ctx;
scandir64_filter = filter;
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.
int res =
REAL(scandir64)(dirp, namelist, filter ? wrapped_scandir64_filter : 0,
compar ? wrapped_scandir64_compar : 0);
- scandir64_ctx = 0;
scandir64_filter = 0;
scandir64_compar = 0;
if (namelist && res > 0) {
@@ -1959,6 +2731,9 @@ INTERCEPTOR(int, scandir64, char *dirp, __sanitizer_dirent64 ***namelist,
INTERCEPTOR(int, getgroups, int size, u32 *lst) {
void *ctx;
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.
int res = REAL(getgroups)(size, lst);
if (res && lst) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, lst, res * sizeof(*lst));
return res;
@@ -2022,6 +2797,9 @@ INTERCEPTOR(int, wordexp, char *s, __sanitizer_wordexp_t *p, int flags) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, wordexp, s, p, 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.
int res = REAL(wordexp)(s, p, flags);
if (!res && p) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, sizeof(*p));
@@ -2045,6 +2823,9 @@ INTERCEPTOR(int, sigwait, __sanitizer_sigset_t *set, int *sig) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, sigwait, set, 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.
int res = REAL(sigwait)(set, sig);
if (!res && sig) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sig, sizeof(*sig));
return res;
@@ -2059,6 +2840,9 @@ INTERCEPTOR(int, sigwaitinfo, __sanitizer_sigset_t *set, void *info) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, sigwaitinfo, set, 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.
int res = REAL(sigwaitinfo)(set, info);
if (res > 0 && info) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, info, siginfo_t_sz);
return res;
@@ -2075,6 +2859,9 @@ INTERCEPTOR(int, sigtimedwait, __sanitizer_sigset_t *set, void *info,
COMMON_INTERCEPTOR_ENTER(ctx, sigtimedwait, set, info, timeout);
if (timeout) COMMON_INTERCEPTOR_READ_RANGE(ctx, timeout, struct_timespec_sz);
// 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.
int res = REAL(sigtimedwait)(set, info, timeout);
if (res > 0 && info) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, info, siginfo_t_sz);
return res;
@@ -2088,6 +2875,9 @@ INTERCEPTOR(int, sigtimedwait, __sanitizer_sigset_t *set, void *info,
INTERCEPTOR(int, sigemptyset, __sanitizer_sigset_t *set) {
void *ctx;
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.
int res = REAL(sigemptyset)(set);
if (!res && set) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, set, sizeof(*set));
return res;
@@ -2096,6 +2886,9 @@ INTERCEPTOR(int, sigemptyset, __sanitizer_sigset_t *set) {
INTERCEPTOR(int, sigfillset, __sanitizer_sigset_t *set) {
void *ctx;
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.
int res = REAL(sigfillset)(set);
if (!res && set) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, set, sizeof(*set));
return res;
@@ -2111,6 +2904,9 @@ INTERCEPTOR(int, sigfillset, __sanitizer_sigset_t *set) {
INTERCEPTOR(int, sigpending, __sanitizer_sigset_t *set) {
void *ctx;
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.
int res = REAL(sigpending)(set);
if (!res && set) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, set, sizeof(*set));
return res;
@@ -2126,6 +2922,9 @@ INTERCEPTOR(int, sigprocmask, int how, __sanitizer_sigset_t *set,
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, sigprocmask, how, set, oldset);
// 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.
int res = REAL(sigprocmask)(how, set, oldset);
if (!res && oldset)
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, oldset, sizeof(*oldset));
@@ -2140,6 +2939,9 @@ INTERCEPTOR(int, sigprocmask, int how, __sanitizer_sigset_t *set,
INTERCEPTOR(int, backtrace, void **buffer, int size) {
void *ctx;
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.
int res = REAL(backtrace)(buffer, size);
if (res && buffer)
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buffer, res * sizeof(*buffer));
@@ -2151,6 +2953,9 @@ INTERCEPTOR(char **, backtrace_symbols, void **buffer, int size) {
COMMON_INTERCEPTOR_ENTER(ctx, backtrace_symbols, buffer, size);
if (buffer && 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.
char **res = REAL(backtrace_symbols)(buffer, size);
if (res && size) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, size * sizeof(*res));
@@ -2206,53 +3011,6 @@ INTERCEPTOR(int, pthread_mutex_unlock, void *m) {
#define INIT_PTHREAD_MUTEX_UNLOCK
#endif
-#if SANITIZER_INTERCEPT_PTHREAD_COND
-INTERCEPTOR(int, pthread_cond_wait, void *c, void *m) {
- void *ctx;
- COMMON_INTERCEPTOR_ENTER(ctx, pthread_cond_wait, c, m);
- COMMON_INTERCEPTOR_MUTEX_UNLOCK(ctx, m);
- COMMON_INTERCEPTOR_READ_RANGE(ctx, c, pthread_cond_t_sz);
- int res = REAL(pthread_cond_wait)(c, m);
- COMMON_INTERCEPTOR_MUTEX_LOCK(ctx, m);
- return res;
-}
-
-INTERCEPTOR(int, pthread_cond_init, void *c, void *a) {
- void *ctx;
- COMMON_INTERCEPTOR_ENTER(ctx, pthread_cond_init, c, a);
- COMMON_INTERCEPTOR_WRITE_RANGE(ctx, c, pthread_cond_t_sz);
- return REAL(pthread_cond_init)(c, a);
-}
-
-INTERCEPTOR(int, pthread_cond_signal, void *c) {
- void *ctx;
- COMMON_INTERCEPTOR_ENTER(ctx, pthread_cond_signal, c);
- COMMON_INTERCEPTOR_READ_RANGE(ctx, c, pthread_cond_t_sz);
- return REAL(pthread_cond_signal)(c);
-}
-
-INTERCEPTOR(int, pthread_cond_broadcast, void *c) {
- void *ctx;
- COMMON_INTERCEPTOR_ENTER(ctx, pthread_cond_broadcast, c);
- COMMON_INTERCEPTOR_READ_RANGE(ctx, c, pthread_cond_t_sz);
- return REAL(pthread_cond_broadcast)(c);
-}
-
-#define INIT_PTHREAD_COND_WAIT \
- INTERCEPT_FUNCTION_VER(pthread_cond_wait, "GLIBC_2.3.2")
-#define INIT_PTHREAD_COND_INIT \
- INTERCEPT_FUNCTION_VER(pthread_cond_init, "GLIBC_2.3.2")
-#define INIT_PTHREAD_COND_SIGNAL \
- INTERCEPT_FUNCTION_VER(pthread_cond_signal, "GLIBC_2.3.2")
-#define INIT_PTHREAD_COND_BROADCAST \
- INTERCEPT_FUNCTION_VER(pthread_cond_broadcast, "GLIBC_2.3.2")
-#else
-#define INIT_PTHREAD_COND_WAIT
-#define INIT_PTHREAD_COND_INIT
-#define INIT_PTHREAD_COND_SIGNAL
-#define INIT_PTHREAD_COND_BROADCAST
-#endif
-
#if SANITIZER_INTERCEPT_GETMNTENT || SANITIZER_INTERCEPT_GETMNTENT_R
static void write_mntent(void *ctx, __sanitizer_mntent *mnt) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, mnt, sizeof(*mnt));
@@ -2303,6 +3061,9 @@ INTERCEPTOR(int, statfs, char *path, void *buf) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, statfs, path, 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.
int res = REAL(statfs)(path, buf);
if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statfs_sz);
return res;
@@ -2310,6 +3071,9 @@ INTERCEPTOR(int, statfs, char *path, void *buf) {
INTERCEPTOR(int, fstatfs, int fd, void *buf) {
void *ctx;
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.
int res = REAL(fstatfs)(fd, buf);
if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statfs_sz);
return res;
@@ -2326,6 +3090,9 @@ INTERCEPTOR(int, statfs64, char *path, void *buf) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, statfs64, path, 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.
int res = REAL(statfs64)(path, buf);
if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statfs64_sz);
return res;
@@ -2333,6 +3100,9 @@ INTERCEPTOR(int, statfs64, char *path, void *buf) {
INTERCEPTOR(int, fstatfs64, int fd, void *buf) {
void *ctx;
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.
int res = REAL(fstatfs64)(fd, buf);
if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statfs64_sz);
return res;
@@ -2349,6 +3119,9 @@ INTERCEPTOR(int, statvfs, char *path, void *buf) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, statvfs, path, 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.
int res = REAL(statvfs)(path, buf);
if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs_sz);
return res;
@@ -2356,6 +3129,9 @@ INTERCEPTOR(int, statvfs, char *path, void *buf) {
INTERCEPTOR(int, fstatvfs, int fd, void *buf) {
void *ctx;
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.
int res = REAL(fstatvfs)(fd, buf);
if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs_sz);
return res;
@@ -2372,6 +3148,9 @@ INTERCEPTOR(int, statvfs64, char *path, void *buf) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, statvfs64, path, 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.
int res = REAL(statvfs64)(path, buf);
if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs64_sz);
return res;
@@ -2379,6 +3158,9 @@ INTERCEPTOR(int, statvfs64, char *path, void *buf) {
INTERCEPTOR(int, fstatvfs64, int fd, void *buf) {
void *ctx;
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.
int res = REAL(fstatvfs64)(fd, buf);
if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs64_sz);
return res;
@@ -2403,13 +3185,13 @@ INTERCEPTOR(int, initgroups, char *user, u32 group) {
#define INIT_INITGROUPS
#endif
-#if SANITIZER_INTERCEPT_ETHER
+#if SANITIZER_INTERCEPT_ETHER_NTOA_ATON
INTERCEPTOR(char *, ether_ntoa, __sanitizer_ether_addr *addr) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, ether_ntoa, addr);
if (addr) COMMON_INTERCEPTOR_READ_RANGE(ctx, addr, sizeof(*addr));
char *res = REAL(ether_ntoa)(addr);
- if (res) COMMON_INTERCEPTOR_INITIALIZE_RANGE(ctx, res, REAL(strlen)(res) + 1);
+ if (res) COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, REAL(strlen)(res) + 1);
return res;
}
INTERCEPTOR(__sanitizer_ether_addr *, ether_aton, char *buf) {
@@ -2417,13 +3199,24 @@ INTERCEPTOR(__sanitizer_ether_addr *, ether_aton, char *buf) {
COMMON_INTERCEPTOR_ENTER(ctx, ether_aton, buf);
if (buf) COMMON_INTERCEPTOR_READ_RANGE(ctx, buf, REAL(strlen)(buf) + 1);
__sanitizer_ether_addr *res = REAL(ether_aton)(buf);
- if (res) COMMON_INTERCEPTOR_INITIALIZE_RANGE(ctx, res, sizeof(*res));
+ if (res) COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, sizeof(*res));
return res;
}
+#define INIT_ETHER_NTOA_ATON \
+ COMMON_INTERCEPT_FUNCTION(ether_ntoa); \
+ COMMON_INTERCEPT_FUNCTION(ether_aton);
+#else
+#define INIT_ETHER_NTOA_ATON
+#endif
+
+#if SANITIZER_INTERCEPT_ETHER_HOST
INTERCEPTOR(int, ether_ntohost, char *hostname, __sanitizer_ether_addr *addr) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, ether_ntohost, hostname, 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.
int res = REAL(ether_ntohost)(hostname, addr);
if (!res && hostname)
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, hostname, REAL(strlen)(hostname) + 1);
@@ -2434,6 +3227,9 @@ INTERCEPTOR(int, ether_hostton, char *hostname, __sanitizer_ether_addr *addr) {
COMMON_INTERCEPTOR_ENTER(ctx, ether_hostton, hostname, addr);
if (hostname)
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.
int res = REAL(ether_hostton)(hostname, addr);
if (!res && addr) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, sizeof(*addr));
return res;
@@ -2443,6 +3239,9 @@ INTERCEPTOR(int, ether_line, char *line, __sanitizer_ether_addr *addr,
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, ether_line, line, addr, hostname);
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.
int res = REAL(ether_line)(line, addr, hostname);
if (!res) {
if (addr) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, sizeof(*addr));
@@ -2451,14 +3250,12 @@ INTERCEPTOR(int, ether_line, char *line, __sanitizer_ether_addr *addr,
}
return res;
}
-#define INIT_ETHER \
- COMMON_INTERCEPT_FUNCTION(ether_ntoa); \
- COMMON_INTERCEPT_FUNCTION(ether_aton); \
+#define INIT_ETHER_HOST \
COMMON_INTERCEPT_FUNCTION(ether_ntohost); \
COMMON_INTERCEPT_FUNCTION(ether_hostton); \
COMMON_INTERCEPT_FUNCTION(ether_line);
#else
-#define INIT_ETHER
+#define INIT_ETHER_HOST
#endif
#if SANITIZER_INTERCEPT_ETHER_R
@@ -2466,6 +3263,9 @@ INTERCEPTOR(char *, ether_ntoa_r, __sanitizer_ether_addr *addr, char *buf) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, ether_ntoa_r, addr, 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.
char *res = REAL(ether_ntoa_r)(addr, buf);
if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
return res;
@@ -2475,6 +3275,9 @@ INTERCEPTOR(__sanitizer_ether_addr *, ether_aton_r, char *buf,
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, ether_aton_r, buf, addr);
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.
__sanitizer_ether_addr *res = REAL(ether_aton_r)(buf, addr);
if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, sizeof(*res));
return res;
@@ -2490,6 +3293,9 @@ INTERCEPTOR(__sanitizer_ether_addr *, ether_aton_r, char *buf,
INTERCEPTOR(int, shmctl, int shmid, int cmd, void *buf) {
void *ctx;
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.
int res = REAL(shmctl)(shmid, cmd, buf);
if (res >= 0) {
unsigned sz = 0;
@@ -2512,6 +3318,9 @@ INTERCEPTOR(int, shmctl, int shmid, int cmd, void *buf) {
INTERCEPTOR(int, random_r, void *buf, u32 *result) {
void *ctx;
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.
int res = REAL(random_r)(buf, result);
if (!res && result)
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
@@ -2522,16 +3331,33 @@ INTERCEPTOR(int, random_r, void *buf, u32 *result) {
#define INIT_RANDOM_R
#endif
-#if SANITIZER_INTERCEPT_PTHREAD_ATTR_GET || \
- SANITIZER_INTERCEPT_PTHREAD_ATTR_GETINHERITSSCHED
-#define INTERCEPTOR_PTHREAD_ATTR_GET(what, sz) \
- INTERCEPTOR(int, pthread_attr_get##what, void *attr, void *r) { \
- void *ctx; \
- COMMON_INTERCEPTOR_ENTER(ctx, pthread_attr_get##what, attr, r); \
- int res = REAL(pthread_attr_get##what)(attr, r); \
- if (!res && r) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, r, sz); \
- return res; \
+// 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.
+#if SANITIZER_INTERCEPT_PTHREAD_ATTR_GET || \
+ SANITIZER_INTERCEPT_PTHREAD_ATTR_GETINHERITSSCHED || \
+ SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GET || \
+ SANITIZER_INTERCEPT_PTHREAD_RWLOCKATTR_GET || \
+ SANITIZER_INTERCEPT_PTHREAD_CONDATTR_GET || \
+ SANITIZER_INTERCEPT_PTHREAD_BARRIERATTR_GET
+#define INTERCEPTOR_PTHREAD_OBJECT_ATTR_GET(fn, sz) \
+ INTERCEPTOR(int, fn, void *attr, void *r) { \
+ void *ctx; \
+ COMMON_INTERCEPTOR_ENTER(ctx, fn, attr, r); \
+ int res = REAL(fn)(attr, r); \
+ if (!res && r) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, r, sz); \
+ return res; \
}
+#define INTERCEPTOR_PTHREAD_ATTR_GET(what, sz) \
+ INTERCEPTOR_PTHREAD_OBJECT_ATTR_GET(pthread_attr_get##what, sz)
+#define INTERCEPTOR_PTHREAD_MUTEXATTR_GET(what, sz) \
+ INTERCEPTOR_PTHREAD_OBJECT_ATTR_GET(pthread_mutexattr_get##what, sz)
+#define INTERCEPTOR_PTHREAD_RWLOCKATTR_GET(what, sz) \
+ INTERCEPTOR_PTHREAD_OBJECT_ATTR_GET(pthread_rwlockattr_get##what, sz)
+#define INTERCEPTOR_PTHREAD_CONDATTR_GET(what, sz) \
+ INTERCEPTOR_PTHREAD_OBJECT_ATTR_GET(pthread_condattr_get##what, sz)
+#define INTERCEPTOR_PTHREAD_BARRIERATTR_GET(what, sz) \
+ INTERCEPTOR_PTHREAD_OBJECT_ATTR_GET(pthread_barrierattr_get##what, sz)
#endif
#if SANITIZER_INTERCEPT_PTHREAD_ATTR_GET
@@ -2544,6 +3370,9 @@ INTERCEPTOR_PTHREAD_ATTR_GET(stacksize, sizeof(SIZE_T))
INTERCEPTOR(int, pthread_attr_getstack, void *attr, void **addr, SIZE_T *size) {
void *ctx;
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.
int res = REAL(pthread_attr_getstack)(attr, addr, size);
if (!res) {
if (addr) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, sizeof(*addr));
@@ -2552,6 +3381,17 @@ INTERCEPTOR(int, pthread_attr_getstack, void *attr, void **addr, SIZE_T *size) {
return res;
}
+// We may need to call the real pthread_attr_getstack from the run-time
+// in sanitizer_common, but we don't want to include the interception headers
+// there. So, just define this function here.
+namespace __sanitizer {
+extern "C" {
+int real_pthread_attr_getstack(void *attr, void **addr, SIZE_T *size) {
+ return REAL(pthread_attr_getstack)(attr, addr, size);
+}
+} // extern "C"
+} // namespace __sanitizer
+
#define INIT_PTHREAD_ATTR_GET \
COMMON_INTERCEPT_FUNCTION(pthread_attr_getdetachstate); \
COMMON_INTERCEPT_FUNCTION(pthread_attr_getguardsize); \
@@ -2579,6 +3419,9 @@ INTERCEPTOR(int, pthread_attr_getaffinity_np, void *attr, SIZE_T cpusetsize,
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, pthread_attr_getaffinity_np, attr, 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.
int res = REAL(pthread_attr_getaffinity_np)(attr, cpusetsize, cpuset);
if (!res && cpusetsize && cpuset)
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cpuset, cpusetsize);
@@ -2591,6 +3434,94 @@ INTERCEPTOR(int, pthread_attr_getaffinity_np, void *attr, SIZE_T cpusetsize,
#define INIT_PTHREAD_ATTR_GETAFFINITY_NP
#endif
+#if SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETPSHARED
+INTERCEPTOR_PTHREAD_MUTEXATTR_GET(pshared, sizeof(int))
+#define INIT_PTHREAD_MUTEXATTR_GETPSHARED \
+ COMMON_INTERCEPT_FUNCTION(pthread_mutexattr_getpshared);
+#else
+#define INIT_PTHREAD_MUTEXATTR_GETPSHARED
+#endif
+
+#if SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETTYPE
+INTERCEPTOR_PTHREAD_MUTEXATTR_GET(type, sizeof(int))
+#define INIT_PTHREAD_MUTEXATTR_GETTYPE \
+ COMMON_INTERCEPT_FUNCTION(pthread_mutexattr_gettype);
+#else
+#define INIT_PTHREAD_MUTEXATTR_GETTYPE
+#endif
+
+#if SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETPROTOCOL
+INTERCEPTOR_PTHREAD_MUTEXATTR_GET(protocol, sizeof(int))
+#define INIT_PTHREAD_MUTEXATTR_GETPROTOCOL \
+ COMMON_INTERCEPT_FUNCTION(pthread_mutexattr_getprotocol);
+#else
+#define INIT_PTHREAD_MUTEXATTR_GETPROTOCOL
+#endif
+
+#if SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETPRIOCEILING
+INTERCEPTOR_PTHREAD_MUTEXATTR_GET(prioceiling, sizeof(int))
+#define INIT_PTHREAD_MUTEXATTR_GETPRIOCEILING \
+ COMMON_INTERCEPT_FUNCTION(pthread_mutexattr_getprioceiling);
+#else
+#define INIT_PTHREAD_MUTEXATTR_GETPRIOCEILING
+#endif
+
+#if SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETROBUST
+INTERCEPTOR_PTHREAD_MUTEXATTR_GET(robust, sizeof(int))
+#define INIT_PTHREAD_MUTEXATTR_GETROBUST \
+ COMMON_INTERCEPT_FUNCTION(pthread_mutexattr_getrobust);
+#else
+#define INIT_PTHREAD_MUTEXATTR_GETROBUST
+#endif
+
+#if SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETROBUST_NP
+INTERCEPTOR_PTHREAD_MUTEXATTR_GET(robust_np, sizeof(int))
+#define INIT_PTHREAD_MUTEXATTR_GETROBUST_NP \
+ COMMON_INTERCEPT_FUNCTION(pthread_mutexattr_getrobust_np);
+#else
+#define INIT_PTHREAD_MUTEXATTR_GETROBUST_NP
+#endif
+
+#if SANITIZER_INTERCEPT_PTHREAD_RWLOCKATTR_GETPSHARED
+INTERCEPTOR_PTHREAD_RWLOCKATTR_GET(pshared, sizeof(int))
+#define INIT_PTHREAD_RWLOCKATTR_GETPSHARED \
+ COMMON_INTERCEPT_FUNCTION(pthread_rwlockattr_getpshared);
+#else
+#define INIT_PTHREAD_RWLOCKATTR_GETPSHARED
+#endif
+
+#if SANITIZER_INTERCEPT_PTHREAD_RWLOCKATTR_GETKIND_NP
+INTERCEPTOR_PTHREAD_RWLOCKATTR_GET(kind_np, sizeof(int))
+#define INIT_PTHREAD_RWLOCKATTR_GETKIND_NP \
+ COMMON_INTERCEPT_FUNCTION(pthread_rwlockattr_getkind_np);
+#else
+#define INIT_PTHREAD_RWLOCKATTR_GETKIND_NP
+#endif
+
+#if SANITIZER_INTERCEPT_PTHREAD_CONDATTR_GETPSHARED
+INTERCEPTOR_PTHREAD_CONDATTR_GET(pshared, sizeof(int))
+#define INIT_PTHREAD_CONDATTR_GETPSHARED \
+ COMMON_INTERCEPT_FUNCTION(pthread_condattr_getpshared);
+#else
+#define INIT_PTHREAD_CONDATTR_GETPSHARED
+#endif
+
+#if SANITIZER_INTERCEPT_PTHREAD_CONDATTR_GETCLOCK
+INTERCEPTOR_PTHREAD_CONDATTR_GET(clock, sizeof(int))
+#define INIT_PTHREAD_CONDATTR_GETCLOCK \
+ COMMON_INTERCEPT_FUNCTION(pthread_condattr_getclock);
+#else
+#define INIT_PTHREAD_CONDATTR_GETCLOCK
+#endif
+
+#if SANITIZER_INTERCEPT_PTHREAD_BARRIERATTR_GETPSHARED
+INTERCEPTOR_PTHREAD_BARRIERATTR_GET(pshared, sizeof(int)) // !mac !android
+#define INIT_PTHREAD_BARRIERATTR_GETPSHARED \
+ COMMON_INTERCEPT_FUNCTION(pthread_barrierattr_getpshared);
+#else
+#define INIT_PTHREAD_BARRIERATTR_GETPSHARED
+#endif
+
#if SANITIZER_INTERCEPT_TMPNAM
INTERCEPTOR(char *, tmpnam, char *s) {
void *ctx;
@@ -2598,9 +3529,12 @@ INTERCEPTOR(char *, tmpnam, char *s) {
char *res = REAL(tmpnam)(s);
if (res) {
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.
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, s, REAL(strlen)(s) + 1);
else
- COMMON_INTERCEPTOR_INITIALIZE_RANGE(ctx, res, REAL(strlen)(res) + 1);
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, REAL(strlen)(res) + 1);
}
return res;
}
@@ -2613,6 +3547,9 @@ INTERCEPTOR(char *, tmpnam, char *s) {
INTERCEPTOR(char *, tmpnam_r, char *s) {
void *ctx;
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.
char *res = REAL(tmpnam_r)(s);
if (res && s) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, s, REAL(strlen)(s) + 1);
return res;
@@ -2629,7 +3566,7 @@ INTERCEPTOR(char *, tempnam, char *dir, char *pfx) {
if (dir) COMMON_INTERCEPTOR_READ_RANGE(ctx, dir, REAL(strlen)(dir) + 1);
if (pfx) COMMON_INTERCEPTOR_READ_RANGE(ctx, pfx, REAL(strlen)(pfx) + 1);
char *res = REAL(tempnam)(dir, pfx);
- if (res) COMMON_INTERCEPTOR_INITIALIZE_RANGE(ctx, res, REAL(strlen)(res) + 1);
+ if (res) COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, REAL(strlen)(res) + 1);
return res;
}
#define INIT_TEMPNAM COMMON_INTERCEPT_FUNCTION(tempnam);
@@ -2653,6 +3590,9 @@ INTERCEPTOR(int, pthread_setname_np, uptr thread, const char *name) {
INTERCEPTOR(void, sincos, double x, double *sin, double *cos) {
void *ctx;
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.
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));
@@ -2660,6 +3600,9 @@ INTERCEPTOR(void, sincos, double x, double *sin, double *cos) {
INTERCEPTOR(void, sincosf, float x, float *sin, float *cos) {
void *ctx;
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.
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));
@@ -2667,6 +3610,9 @@ INTERCEPTOR(void, sincosf, float x, float *sin, float *cos) {
INTERCEPTOR(void, sincosl, long double x, long double *sin, long double *cos) {
void *ctx;
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.
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));
@@ -2683,6 +3629,9 @@ INTERCEPTOR(void, sincosl, long double x, long double *sin, long double *cos) {
INTERCEPTOR(double, remquo, double x, double y, int *quo) {
void *ctx;
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.
double res = REAL(remquo)(x, y, quo);
if (quo) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, quo, sizeof(*quo));
return res;
@@ -2690,6 +3639,9 @@ INTERCEPTOR(double, remquo, double x, double y, int *quo) {
INTERCEPTOR(float, remquof, float x, float y, int *quo) {
void *ctx;
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.
float res = REAL(remquof)(x, y, quo);
if (quo) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, quo, sizeof(*quo));
return res;
@@ -2697,6 +3649,9 @@ INTERCEPTOR(float, remquof, float x, float y, int *quo) {
INTERCEPTOR(long double, remquol, long double x, long double y, int *quo) {
void *ctx;
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.
long double res = REAL(remquol)(x, y, quo);
if (quo) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, quo, sizeof(*quo));
return res;
@@ -2744,6 +3699,9 @@ INTERCEPTOR(long double, lgammal, long double x) {
INTERCEPTOR(double, lgamma_r, double x, int *signp) {
void *ctx;
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.
double res = REAL(lgamma_r)(x, signp);
if (signp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, signp, sizeof(*signp));
return res;
@@ -2751,29 +3709,43 @@ INTERCEPTOR(double, lgamma_r, double x, int *signp) {
INTERCEPTOR(float, lgammaf_r, float x, int *signp) {
void *ctx;
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.
float res = REAL(lgammaf_r)(x, signp);
if (signp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, signp, sizeof(*signp));
return res;
}
+#define INIT_LGAMMA_R \
+ COMMON_INTERCEPT_FUNCTION(lgamma_r); \
+ COMMON_INTERCEPT_FUNCTION(lgammaf_r);
+#else
+#define INIT_LGAMMA_R
+#endif
+
+#if SANITIZER_INTERCEPT_LGAMMAL_R
INTERCEPTOR(long double, lgammal_r, long double x, int *signp) {
void *ctx;
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.
long double res = REAL(lgammal_r)(x, signp);
if (signp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, signp, sizeof(*signp));
return res;
}
-#define INIT_LGAMMA_R \
- COMMON_INTERCEPT_FUNCTION(lgamma_r); \
- COMMON_INTERCEPT_FUNCTION(lgammaf_r); \
- COMMON_INTERCEPT_FUNCTION(lgammal_r);
+#define INIT_LGAMMAL_R COMMON_INTERCEPT_FUNCTION(lgammal_r);
#else
-#define INIT_LGAMMA_R
+#define INIT_LGAMMAL_R
#endif
#if SANITIZER_INTERCEPT_DRAND48_R
INTERCEPTOR(int, drand48_r, void *buffer, double *result) {
void *ctx;
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.
int res = REAL(drand48_r)(buffer, result);
if (result) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
return res;
@@ -2781,6 +3753,9 @@ INTERCEPTOR(int, drand48_r, void *buffer, double *result) {
INTERCEPTOR(int, lrand48_r, void *buffer, long *result) {
void *ctx;
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.
int res = REAL(lrand48_r)(buffer, result);
if (result) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
return res;
@@ -2792,10 +3767,25 @@ INTERCEPTOR(int, lrand48_r, void *buffer, long *result) {
#define INIT_DRAND48_R
#endif
+#if SANITIZER_INTERCEPT_RAND_R
+INTERCEPTOR(int, rand_r, unsigned *seedp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, rand_r, seedp);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, seedp, sizeof(*seedp));
+ return REAL(rand_r)(seedp);
+}
+#define INIT_RAND_R COMMON_INTERCEPT_FUNCTION(rand_r);
+#else
+#define INIT_RAND_R
+#endif
+
#if SANITIZER_INTERCEPT_GETLINE
INTERCEPTOR(SSIZE_T, getline, char **lineptr, SIZE_T *n, void *stream) {
void *ctx;
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.
SSIZE_T res = REAL(getline)(lineptr, n, stream);
if (res > 0) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, lineptr, sizeof(*lineptr));
@@ -2804,11 +3794,14 @@ INTERCEPTOR(SSIZE_T, getline, char **lineptr, SIZE_T *n, void *stream) {
}
return res;
}
-INTERCEPTOR(SSIZE_T, getdelim, char **lineptr, SIZE_T *n, int delim,
+INTERCEPTOR(SSIZE_T, __getdelim, char **lineptr, SIZE_T *n, int delim,
void *stream) {
void *ctx;
- COMMON_INTERCEPTOR_ENTER(ctx, getdelim, lineptr, n, delim, stream);
- SSIZE_T res = REAL(getdelim)(lineptr, n, delim, stream);
+ COMMON_INTERCEPTOR_ENTER(ctx, __getdelim, lineptr, n, delim, 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.
+ SSIZE_T res = REAL(__getdelim)(lineptr, n, delim, stream);
if (res > 0) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, lineptr, sizeof(*lineptr));
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, n, sizeof(*n));
@@ -2816,120 +3809,1089 @@ INTERCEPTOR(SSIZE_T, getdelim, char **lineptr, SIZE_T *n, int delim,
}
return res;
}
-#define INIT_GETLINE \
- COMMON_INTERCEPT_FUNCTION(getline); \
+INTERCEPTOR(SSIZE_T, getdelim, char **lineptr, SIZE_T *n, int delim,
+ void *stream) {
+ return __getdelim(lineptr, n, delim, stream);
+}
+#define INIT_GETLINE \
+ COMMON_INTERCEPT_FUNCTION(getline); \
+ COMMON_INTERCEPT_FUNCTION(__getdelim); \
COMMON_INTERCEPT_FUNCTION(getdelim);
#else
#define INIT_GETLINE
#endif
-#define SANITIZER_COMMON_INTERCEPTORS_INIT \
- INIT_STRCMP; \
- INIT_STRNCMP; \
- INIT_STRCASECMP; \
- INIT_STRNCASECMP; \
- INIT_READ; \
- INIT_PREAD; \
- INIT_PREAD64; \
- INIT_READV; \
- INIT_PREADV; \
- INIT_PREADV64; \
- INIT_WRITE; \
- INIT_PWRITE; \
- INIT_PWRITE64; \
- INIT_WRITEV; \
- INIT_PWRITEV; \
- INIT_PWRITEV64; \
- INIT_PRCTL; \
- INIT_LOCALTIME_AND_FRIENDS; \
- INIT_STRPTIME; \
- INIT_SCANF; \
- INIT_ISOC99_SCANF; \
- INIT_FREXP; \
- INIT_FREXPF_FREXPL; \
- INIT_GETPWNAM_AND_FRIENDS; \
- INIT_GETPWNAM_R_AND_FRIENDS; \
- INIT_CLOCK_GETTIME; \
- INIT_GETITIMER; \
- INIT_TIME; \
- INIT_GLOB; \
- INIT_WAIT; \
- INIT_INET; \
- INIT_PTHREAD_GETSCHEDPARAM; \
- INIT_GETADDRINFO; \
- INIT_GETNAMEINFO; \
- INIT_GETSOCKNAME; \
- INIT_GETHOSTBYNAME; \
- INIT_GETHOSTBYNAME_R; \
- INIT_GETSOCKOPT; \
- INIT_ACCEPT; \
- INIT_ACCEPT4; \
- INIT_MODF; \
- INIT_RECVMSG; \
- INIT_GETPEERNAME; \
- INIT_IOCTL; \
- INIT_INET_ATON; \
- INIT_SYSINFO; \
- INIT_READDIR; \
- INIT_READDIR64; \
- INIT_PTRACE; \
- INIT_SETLOCALE; \
- INIT_GETCWD; \
- INIT_GET_CURRENT_DIR_NAME; \
- INIT_STRTOIMAX; \
- INIT_MBSTOWCS; \
- INIT_MBSNRTOWCS; \
- INIT_WCSTOMBS; \
- INIT_WCSNRTOMBS; \
- INIT_TCGETATTR; \
- INIT_REALPATH; \
- INIT_CANONICALIZE_FILE_NAME; \
- INIT_CONFSTR; \
- INIT_SCHED_GETAFFINITY; \
- INIT_STRERROR; \
- INIT_STRERROR_R; \
- INIT_SCANDIR; \
- INIT_SCANDIR64; \
- INIT_GETGROUPS; \
- INIT_POLL; \
- INIT_PPOLL; \
- INIT_WORDEXP; \
- INIT_SIGWAIT; \
- INIT_SIGWAITINFO; \
- INIT_SIGTIMEDWAIT; \
- INIT_SIGSETOPS; \
- INIT_SIGPENDING; \
- INIT_SIGPROCMASK; \
- INIT_BACKTRACE; \
- INIT__EXIT; \
- INIT_PTHREAD_MUTEX_LOCK; \
- INIT_PTHREAD_MUTEX_UNLOCK; \
- INIT_PTHREAD_COND_WAIT; \
- INIT_PTHREAD_COND_INIT; \
- INIT_PTHREAD_COND_SIGNAL; \
- INIT_PTHREAD_COND_BROADCAST; \
- INIT_GETMNTENT; \
- INIT_GETMNTENT_R; \
- INIT_STATFS; \
- INIT_STATFS64; \
- INIT_STATVFS; \
- INIT_STATVFS64; \
- INIT_INITGROUPS; \
- INIT_ETHER; \
- INIT_ETHER_R; \
- INIT_SHMCTL; \
- INIT_RANDOM_R; \
- INIT_PTHREAD_ATTR_GET; \
- INIT_PTHREAD_ATTR_GETINHERITSCHED; \
- INIT_PTHREAD_ATTR_GETAFFINITY_NP; \
- INIT_TMPNAM; \
- INIT_TMPNAM_R; \
- INIT_TEMPNAM; \
- INIT_PTHREAD_SETNAME_NP; \
- INIT_SINCOS; \
- INIT_REMQUO; \
- INIT_LGAMMA; \
- INIT_LGAMMA_R; \
- INIT_DRAND48_R; \
- INIT_GETLINE; \
-/**/
+#if SANITIZER_INTERCEPT_ICONV
+INTERCEPTOR(SIZE_T, iconv, void *cd, char **inbuf, SIZE_T *inbytesleft,
+ char **outbuf, SIZE_T *outbytesleft) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, iconv, cd, inbuf, inbytesleft, outbuf,
+ outbytesleft);
+ if (inbytesleft)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, inbytesleft, sizeof(*inbytesleft));
+ if (inbuf && inbytesleft)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, *inbuf, *inbytesleft);
+ if (outbytesleft)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, outbytesleft, sizeof(*outbytesleft));
+ void *outbuf_orig = outbuf ? *outbuf : 0;
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=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;
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, outbuf_orig, sz);
+ }
+ return res;
+}
+#define INIT_ICONV COMMON_INTERCEPT_FUNCTION(iconv);
+#else
+#define INIT_ICONV
+#endif
+
+#if SANITIZER_INTERCEPT_TIMES
+INTERCEPTOR(__sanitizer_clock_t, times, void *tms) {
+ void *ctx;
+ 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.
+ __sanitizer_clock_t res = REAL(times)(tms);
+ if (res != (__sanitizer_clock_t)-1 && tms)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tms, struct_tms_sz);
+ return res;
+}
+#define INIT_TIMES COMMON_INTERCEPT_FUNCTION(times);
+#else
+#define INIT_TIMES
+#endif
+
+#if SANITIZER_INTERCEPT_TLS_GET_ADDR
+#define INIT_TLS_GET_ADDR COMMON_INTERCEPT_FUNCTION(__tls_get_addr)
+INTERCEPTOR(void *, __tls_get_addr, void *arg) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, __tls_get_addr, arg);
+ void *res = REAL(__tls_get_addr)(arg);
+ DTLS::DTV *dtv = DTLS_on_tls_get_addr(arg, res);
+ if (dtv) {
+ // New DTLS block has been allocated.
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE((void *)dtv->beg, dtv->size);
+ }
+ return res;
+}
+#else
+#define INIT_TLS_GET_ADDR
+#endif
+
+#if SANITIZER_INTERCEPT_LISTXATTR
+INTERCEPTOR(SSIZE_T, listxattr, const char *path, char *list, SIZE_T size) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, listxattr, path, list, 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.
+ 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.
+ if (size && res > 0 && list) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, list, res);
+ return res;
+}
+INTERCEPTOR(SSIZE_T, llistxattr, const char *path, char *list, SIZE_T size) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, llistxattr, path, list, 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.
+ SSIZE_T res = REAL(llistxattr)(path, list, size);
+ if (size && res > 0 && list) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, list, res);
+ return res;
+}
+INTERCEPTOR(SSIZE_T, flistxattr, int fd, char *list, SIZE_T size) {
+ void *ctx;
+ 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.
+ SSIZE_T res = REAL(flistxattr)(fd, list, size);
+ if (size && res > 0 && list) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, list, res);
+ return res;
+}
+#define INIT_LISTXATTR \
+ COMMON_INTERCEPT_FUNCTION(listxattr); \
+ COMMON_INTERCEPT_FUNCTION(llistxattr); \
+ COMMON_INTERCEPT_FUNCTION(flistxattr);
+#else
+#define INIT_LISTXATTR
+#endif
+
+#if SANITIZER_INTERCEPT_GETXATTR
+INTERCEPTOR(SSIZE_T, getxattr, const char *path, const char *name, char *value,
+ SIZE_T size) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getxattr, path, name, value, size);
+ if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
+ 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.
+ SSIZE_T res = REAL(getxattr)(path, name, value, size);
+ if (size && res > 0 && value) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, value, res);
+ return res;
+}
+INTERCEPTOR(SSIZE_T, lgetxattr, const char *path, const char *name, char *value,
+ SIZE_T size) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, lgetxattr, path, name, value, size);
+ if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
+ 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.
+ SSIZE_T res = REAL(lgetxattr)(path, name, value, size);
+ if (size && res > 0 && value) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, value, res);
+ return res;
+}
+INTERCEPTOR(SSIZE_T, fgetxattr, int fd, const char *name, char *value,
+ SIZE_T size) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, fgetxattr, fd, name, value, size);
+ 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.
+ SSIZE_T res = REAL(fgetxattr)(fd, name, value, size);
+ if (size && res > 0 && value) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, value, res);
+ return res;
+}
+#define INIT_GETXATTR \
+ COMMON_INTERCEPT_FUNCTION(getxattr); \
+ COMMON_INTERCEPT_FUNCTION(lgetxattr); \
+ COMMON_INTERCEPT_FUNCTION(fgetxattr);
+#else
+#define INIT_GETXATTR
+#endif
+
+#if SANITIZER_INTERCEPT_GETRESID
+INTERCEPTOR(int, getresuid, void *ruid, void *euid, void *suid) {
+ void *ctx;
+ 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.
+ int res = REAL(getresuid)(ruid, euid, suid);
+ if (res >= 0) {
+ if (ruid) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ruid, uid_t_sz);
+ if (euid) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, euid, uid_t_sz);
+ if (suid) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, suid, uid_t_sz);
+ }
+ return res;
+}
+INTERCEPTOR(int, getresgid, void *rgid, void *egid, void *sgid) {
+ void *ctx;
+ 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.
+ int res = REAL(getresgid)(rgid, egid, sgid);
+ if (res >= 0) {
+ if (rgid) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, rgid, gid_t_sz);
+ if (egid) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, egid, gid_t_sz);
+ if (sgid) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sgid, gid_t_sz);
+ }
+ return res;
+}
+#define INIT_GETRESID \
+ COMMON_INTERCEPT_FUNCTION(getresuid); \
+ COMMON_INTERCEPT_FUNCTION(getresgid);
+#else
+#define INIT_GETRESID
+#endif
+
+#if SANITIZER_INTERCEPT_GETIFADDRS
+// As long as getifaddrs()/freeifaddrs() use calloc()/free(), we don't need to
+// intercept freeifaddrs(). If that ceases to be the case, we might need to
+// intercept it to poison the memory again.
+INTERCEPTOR(int, getifaddrs, __sanitizer_ifaddrs **ifap) {
+ void *ctx;
+ 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.
+ int res = REAL(getifaddrs)(ifap);
+ if (res == 0 && ifap) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ifap, sizeof(void *));
+ __sanitizer_ifaddrs *p = *ifap;
+ while (p) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, sizeof(__sanitizer_ifaddrs));
+ if (p->ifa_name)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->ifa_name,
+ REAL(strlen)(p->ifa_name) + 1);
+ if (p->ifa_addr)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->ifa_addr, struct_sockaddr_sz);
+ if (p->ifa_netmask)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->ifa_netmask, struct_sockaddr_sz);
+ // On Linux this is a union, but the other member also points to a
+ // struct sockaddr, so the following is sufficient.
+ if (p->ifa_dstaddr)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->ifa_dstaddr, struct_sockaddr_sz);
+ // FIXME(smatveev): Unpoison p->ifa_data as well.
+ p = p->ifa_next;
+ }
+ }
+ return res;
+}
+#define INIT_GETIFADDRS \
+ COMMON_INTERCEPT_FUNCTION(getifaddrs);
+#else
+#define INIT_GETIFADDRS
+#endif
+
+#if SANITIZER_INTERCEPT_IF_INDEXTONAME
+INTERCEPTOR(char *, if_indextoname, unsigned int ifindex, char* ifname) {
+ void *ctx;
+ 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.
+ char *res = REAL(if_indextoname)(ifindex, ifname);
+ if (res && ifname)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ifname, REAL(strlen)(ifname) + 1);
+ return res;
+}
+INTERCEPTOR(unsigned int, if_nametoindex, const char* ifname) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, if_nametoindex, ifname);
+ if (ifname)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, ifname, REAL(strlen)(ifname) + 1);
+ return REAL(if_nametoindex)(ifname);
+}
+#define INIT_IF_INDEXTONAME \
+ COMMON_INTERCEPT_FUNCTION(if_indextoname); \
+ COMMON_INTERCEPT_FUNCTION(if_nametoindex);
+#else
+#define INIT_IF_INDEXTONAME
+#endif
+
+#if SANITIZER_INTERCEPT_CAPGET
+INTERCEPTOR(int, capget, void *hdrp, void *datap) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, capget, hdrp, datap);
+ if (hdrp)
+ 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.
+ int res = REAL(capget)(hdrp, datap);
+ if (res == 0 && datap)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, datap, __user_cap_data_struct_sz);
+ // We can also return -1 and write to hdrp->version if the version passed in
+ // hdrp->version is unsupported. But that's not a trivial condition to check,
+ // and anyway COMMON_INTERCEPTOR_READ_RANGE protects us to some extent.
+ return res;
+}
+INTERCEPTOR(int, capset, void *hdrp, const void *datap) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, capset, hdrp, datap);
+ if (hdrp)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, hdrp, __user_cap_header_struct_sz);
+ if (datap)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, datap, __user_cap_data_struct_sz);
+ return REAL(capset)(hdrp, datap);
+}
+#define INIT_CAPGET \
+ COMMON_INTERCEPT_FUNCTION(capget); \
+ COMMON_INTERCEPT_FUNCTION(capset);
+#else
+#define INIT_CAPGET
+#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);
+
+INTERCEPTOR(void *, __aeabi_memmove, void *to, const void *from, uptr size) {
+ return WRAP(memmove)(to, from, size);
+}
+INTERCEPTOR(void *, __aeabi_memmove4, void *to, const void *from, uptr size) {
+ return WRAP(memmove)(to, from, size);
+}
+INTERCEPTOR(void *, __aeabi_memmove8, void *to, const void *from, uptr size) {
+ return WRAP(memmove)(to, from, size);
+}
+INTERCEPTOR(void *, __aeabi_memcpy, void *to, const void *from, uptr size) {
+ return WRAP(memcpy)(to, from, size);
+}
+INTERCEPTOR(void *, __aeabi_memcpy4, void *to, const void *from, uptr size) {
+ return WRAP(memcpy)(to, from, size);
+}
+INTERCEPTOR(void *, __aeabi_memcpy8, void *to, const void *from, uptr size) {
+ return WRAP(memcpy)(to, from, size);
+}
+// Note the argument order.
+INTERCEPTOR(void *, __aeabi_memset, void *block, uptr size, int c) {
+ return WRAP(memset)(block, c, size);
+}
+INTERCEPTOR(void *, __aeabi_memset4, void *block, uptr size, int c) {
+ return WRAP(memset)(block, c, size);
+}
+INTERCEPTOR(void *, __aeabi_memset8, void *block, uptr size, int c) {
+ return WRAP(memset)(block, c, size);
+}
+INTERCEPTOR(void *, __aeabi_memclr, void *block, uptr size) {
+ return WRAP(memset)(block, 0, size);
+}
+INTERCEPTOR(void *, __aeabi_memclr4, void *block, uptr size) {
+ return WRAP(memset)(block, 0, size);
+}
+INTERCEPTOR(void *, __aeabi_memclr8, void *block, uptr size) {
+ return WRAP(memset)(block, 0, size);
+}
+#define INIT_AEABI_MEM \
+ COMMON_INTERCEPT_FUNCTION(__aeabi_memmove); \
+ COMMON_INTERCEPT_FUNCTION(__aeabi_memmove4); \
+ COMMON_INTERCEPT_FUNCTION(__aeabi_memmove8); \
+ COMMON_INTERCEPT_FUNCTION(__aeabi_memcpy); \
+ COMMON_INTERCEPT_FUNCTION(__aeabi_memcpy4); \
+ COMMON_INTERCEPT_FUNCTION(__aeabi_memcpy8); \
+ COMMON_INTERCEPT_FUNCTION(__aeabi_memset); \
+ COMMON_INTERCEPT_FUNCTION(__aeabi_memset4); \
+ COMMON_INTERCEPT_FUNCTION(__aeabi_memset8); \
+ COMMON_INTERCEPT_FUNCTION(__aeabi_memclr); \
+ COMMON_INTERCEPT_FUNCTION(__aeabi_memclr4); \
+ COMMON_INTERCEPT_FUNCTION(__aeabi_memclr8);
+#else
+#define INIT_AEABI_MEM
+#endif // SANITIZER_INTERCEPT_AEABI_MEM
+
+#if SANITIZER_INTERCEPT___BZERO
+DECLARE_REAL_AND_INTERCEPTOR(void *, memset, void *, int, uptr);
+
+INTERCEPTOR(void *, __bzero, void *block, uptr size) {
+ return WRAP(memset)(block, 0, size);
+}
+#define INIT___BZERO COMMON_INTERCEPT_FUNCTION(__bzero);
+#else
+#define INIT___BZERO
+#endif // SANITIZER_INTERCEPT___BZERO
+
+#if SANITIZER_INTERCEPT_FTIME
+INTERCEPTOR(int, ftime, __sanitizer_timeb *tp) {
+ void *ctx;
+ 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.
+ int res = REAL(ftime)(tp);
+ if (tp)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tp, sizeof(*tp));
+ return res;
+}
+#define INIT_FTIME COMMON_INTERCEPT_FUNCTION(ftime);
+#else
+#define INIT_FTIME
+#endif // SANITIZER_INTERCEPT_FTIME
+
+#if SANITIZER_INTERCEPT_XDR
+INTERCEPTOR(void, xdrmem_create, __sanitizer_XDR *xdrs, uptr addr,
+ unsigned size, int op) {
+ void *ctx;
+ 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.
+ REAL(xdrmem_create)(xdrs, addr, size, op);
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, xdrs, sizeof(*xdrs));
+ if (op == __sanitizer_XDR_ENCODE) {
+ // It's not obvious how much data individual xdr_ routines write.
+ // Simply unpoison the entire target buffer in advance.
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, (void *)addr, size);
+ }
+}
+
+INTERCEPTOR(void, xdrstdio_create, __sanitizer_XDR *xdrs, void *file, int op) {
+ void *ctx;
+ 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.
+ 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.
+#define XDR_INTERCEPTOR(F, T) \
+ INTERCEPTOR(int, F, __sanitizer_XDR *xdrs, T *p) { \
+ void *ctx; \
+ COMMON_INTERCEPTOR_ENTER(ctx, F, xdrs, p); \
+ if (p && xdrs->x_op == __sanitizer_XDR_ENCODE) \
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, p, sizeof(*p)); \
+ int res = REAL(F)(xdrs, p); \
+ if (res && p && xdrs->x_op == __sanitizer_XDR_DECODE) \
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, sizeof(*p)); \
+ return res; \
+ }
+
+XDR_INTERCEPTOR(xdr_short, short)
+XDR_INTERCEPTOR(xdr_u_short, unsigned short)
+XDR_INTERCEPTOR(xdr_int, int)
+XDR_INTERCEPTOR(xdr_u_int, unsigned)
+XDR_INTERCEPTOR(xdr_long, long)
+XDR_INTERCEPTOR(xdr_u_long, unsigned long)
+XDR_INTERCEPTOR(xdr_hyper, long long)
+XDR_INTERCEPTOR(xdr_u_hyper, unsigned long long)
+XDR_INTERCEPTOR(xdr_longlong_t, long long)
+XDR_INTERCEPTOR(xdr_u_longlong_t, unsigned long long)
+XDR_INTERCEPTOR(xdr_int8_t, u8)
+XDR_INTERCEPTOR(xdr_uint8_t, u8)
+XDR_INTERCEPTOR(xdr_int16_t, u16)
+XDR_INTERCEPTOR(xdr_uint16_t, u16)
+XDR_INTERCEPTOR(xdr_int32_t, u32)
+XDR_INTERCEPTOR(xdr_uint32_t, u32)
+XDR_INTERCEPTOR(xdr_int64_t, u64)
+XDR_INTERCEPTOR(xdr_uint64_t, u64)
+XDR_INTERCEPTOR(xdr_quad_t, long long)
+XDR_INTERCEPTOR(xdr_u_quad_t, unsigned long long)
+XDR_INTERCEPTOR(xdr_bool, bool)
+XDR_INTERCEPTOR(xdr_enum, int)
+XDR_INTERCEPTOR(xdr_char, char)
+XDR_INTERCEPTOR(xdr_u_char, unsigned char)
+XDR_INTERCEPTOR(xdr_float, float)
+XDR_INTERCEPTOR(xdr_double, double)
+
+// FIXME: intercept xdr_array, opaque, union, vector, reference, pointer,
+// wrapstring, sizeof
+
+INTERCEPTOR(int, xdr_bytes, __sanitizer_XDR *xdrs, char **p, unsigned *sizep,
+ unsigned maxsize) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, xdr_bytes, xdrs, p, sizep, maxsize);
+ if (p && sizep && xdrs->x_op == __sanitizer_XDR_ENCODE) {
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, p, sizeof(*p));
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, sizep, sizeof(*sizep));
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, *p, *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.
+ 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));
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sizep, sizeof(*sizep));
+ if (res && *p && *sizep) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *p, *sizep);
+ }
+ return res;
+}
+
+INTERCEPTOR(int, xdr_string, __sanitizer_XDR *xdrs, char **p,
+ unsigned maxsize) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, xdr_string, xdrs, p, maxsize);
+ if (p && xdrs->x_op == __sanitizer_XDR_ENCODE) {
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, p, sizeof(*p));
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, *p, REAL(strlen)(*p) + 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.
+ int res = REAL(xdr_string)(xdrs, p, maxsize);
+ if (p && xdrs->x_op == __sanitizer_XDR_DECODE) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, sizeof(*p));
+ if (res && *p)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *p, REAL(strlen)(*p) + 1);
+ }
+ return res;
+}
+
+#define INIT_XDR \
+ COMMON_INTERCEPT_FUNCTION(xdrmem_create); \
+ COMMON_INTERCEPT_FUNCTION(xdrstdio_create); \
+ COMMON_INTERCEPT_FUNCTION(xdr_short); \
+ COMMON_INTERCEPT_FUNCTION(xdr_u_short); \
+ COMMON_INTERCEPT_FUNCTION(xdr_int); \
+ COMMON_INTERCEPT_FUNCTION(xdr_u_int); \
+ COMMON_INTERCEPT_FUNCTION(xdr_long); \
+ COMMON_INTERCEPT_FUNCTION(xdr_u_long); \
+ COMMON_INTERCEPT_FUNCTION(xdr_hyper); \
+ COMMON_INTERCEPT_FUNCTION(xdr_u_hyper); \
+ COMMON_INTERCEPT_FUNCTION(xdr_longlong_t); \
+ COMMON_INTERCEPT_FUNCTION(xdr_u_longlong_t); \
+ COMMON_INTERCEPT_FUNCTION(xdr_int8_t); \
+ COMMON_INTERCEPT_FUNCTION(xdr_uint8_t); \
+ COMMON_INTERCEPT_FUNCTION(xdr_int16_t); \
+ COMMON_INTERCEPT_FUNCTION(xdr_uint16_t); \
+ COMMON_INTERCEPT_FUNCTION(xdr_int32_t); \
+ COMMON_INTERCEPT_FUNCTION(xdr_uint32_t); \
+ COMMON_INTERCEPT_FUNCTION(xdr_int64_t); \
+ COMMON_INTERCEPT_FUNCTION(xdr_uint64_t); \
+ COMMON_INTERCEPT_FUNCTION(xdr_quad_t); \
+ COMMON_INTERCEPT_FUNCTION(xdr_u_quad_t); \
+ COMMON_INTERCEPT_FUNCTION(xdr_bool); \
+ COMMON_INTERCEPT_FUNCTION(xdr_enum); \
+ COMMON_INTERCEPT_FUNCTION(xdr_char); \
+ COMMON_INTERCEPT_FUNCTION(xdr_u_char); \
+ COMMON_INTERCEPT_FUNCTION(xdr_float); \
+ COMMON_INTERCEPT_FUNCTION(xdr_double); \
+ COMMON_INTERCEPT_FUNCTION(xdr_bytes); \
+ COMMON_INTERCEPT_FUNCTION(xdr_string);
+#else
+#define INIT_XDR
+#endif // SANITIZER_INTERCEPT_XDR
+
+#if SANITIZER_INTERCEPT_TSEARCH
+INTERCEPTOR(void *, tsearch, void *key, void **rootp,
+ int (*compar)(const void *, const void *)) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, tsearch, key, rootp, compar);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ void *res = REAL(tsearch)(key, rootp, compar);
+ if (res && *(void **)res == key)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, sizeof(void *));
+ return res;
+}
+#define INIT_TSEARCH COMMON_INTERCEPT_FUNCTION(tsearch);
+#else
+#define INIT_TSEARCH
+#endif
+
+#if SANITIZER_INTERCEPT_LIBIO_INTERNALS || SANITIZER_INTERCEPT_FOPEN || \
+ SANITIZER_INTERCEPT_OPEN_MEMSTREAM
+void unpoison_file(__sanitizer_FILE *fp) {
+#if SANITIZER_HAS_STRUCT_FILE
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(fp, sizeof(*fp));
+ if (fp->_IO_read_base && fp->_IO_read_base < fp->_IO_read_end)
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(fp->_IO_read_base,
+ fp->_IO_read_end - fp->_IO_read_base);
+#endif // SANITIZER_HAS_STRUCT_FILE
+}
+#endif
+
+#if SANITIZER_INTERCEPT_LIBIO_INTERNALS
+// These guys are called when a .c source is built with -O2.
+INTERCEPTOR(int, __uflow, __sanitizer_FILE *fp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, __uflow, fp);
+ int res = REAL(__uflow)(fp);
+ unpoison_file(fp);
+ return res;
+}
+INTERCEPTOR(int, __underflow, __sanitizer_FILE *fp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, __underflow, fp);
+ int res = REAL(__underflow)(fp);
+ unpoison_file(fp);
+ return res;
+}
+INTERCEPTOR(int, __overflow, __sanitizer_FILE *fp, int ch) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, __overflow, fp, ch);
+ int res = REAL(__overflow)(fp, ch);
+ unpoison_file(fp);
+ return res;
+}
+INTERCEPTOR(int, __wuflow, __sanitizer_FILE *fp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, __wuflow, fp);
+ int res = REAL(__wuflow)(fp);
+ unpoison_file(fp);
+ return res;
+}
+INTERCEPTOR(int, __wunderflow, __sanitizer_FILE *fp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, __wunderflow, fp);
+ int res = REAL(__wunderflow)(fp);
+ unpoison_file(fp);
+ return res;
+}
+INTERCEPTOR(int, __woverflow, __sanitizer_FILE *fp, int ch) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, __woverflow, fp, ch);
+ int res = REAL(__woverflow)(fp, ch);
+ unpoison_file(fp);
+ return res;
+}
+#define INIT_LIBIO_INTERNALS \
+ COMMON_INTERCEPT_FUNCTION(__uflow); \
+ COMMON_INTERCEPT_FUNCTION(__underflow); \
+ COMMON_INTERCEPT_FUNCTION(__overflow); \
+ COMMON_INTERCEPT_FUNCTION(__wuflow); \
+ COMMON_INTERCEPT_FUNCTION(__wunderflow); \
+ COMMON_INTERCEPT_FUNCTION(__woverflow);
+#else
+#define INIT_LIBIO_INTERNALS
+#endif
+
+#if SANITIZER_INTERCEPT_FOPEN
+INTERCEPTOR(__sanitizer_FILE *, fopen, const char *path, const char *mode) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, fopen, path, mode);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, mode, REAL(strlen)(mode) + 1);
+ __sanitizer_FILE *res = REAL(fopen)(path, mode);
+ COMMON_INTERCEPTOR_FILE_OPEN(ctx, res, path);
+ if (res) unpoison_file(res);
+ return res;
+}
+INTERCEPTOR(__sanitizer_FILE *, fdopen, int fd, const char *mode) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, fdopen, fd, mode);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, mode, REAL(strlen)(mode) + 1);
+ __sanitizer_FILE *res = REAL(fdopen)(fd, mode);
+ if (res) unpoison_file(res);
+ return res;
+}
+INTERCEPTOR(__sanitizer_FILE *, freopen, const char *path, const char *mode,
+ __sanitizer_FILE *fp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, freopen, path, mode, fp);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, mode, REAL(strlen)(mode) + 1);
+ COMMON_INTERCEPTOR_FILE_CLOSE(ctx, fp);
+ __sanitizer_FILE *res = REAL(freopen)(path, mode, fp);
+ COMMON_INTERCEPTOR_FILE_OPEN(ctx, res, path);
+ if (res) unpoison_file(res);
+ return res;
+}
+#define INIT_FOPEN \
+ COMMON_INTERCEPT_FUNCTION(fopen); \
+ COMMON_INTERCEPT_FUNCTION(fdopen); \
+ COMMON_INTERCEPT_FUNCTION(freopen);
+#else
+#define INIT_FOPEN
+#endif
+
+#if SANITIZER_INTERCEPT_FOPEN64
+INTERCEPTOR(__sanitizer_FILE *, fopen64, const char *path, const char *mode) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, fopen64, path, mode);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, mode, REAL(strlen)(mode) + 1);
+ __sanitizer_FILE *res = REAL(fopen64)(path, mode);
+ COMMON_INTERCEPTOR_FILE_OPEN(ctx, res, path);
+ if (res) unpoison_file(res);
+ return res;
+}
+INTERCEPTOR(__sanitizer_FILE *, freopen64, const char *path, const char *mode,
+ __sanitizer_FILE *fp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, freopen64, path, mode, fp);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, mode, REAL(strlen)(mode) + 1);
+ COMMON_INTERCEPTOR_FILE_CLOSE(ctx, fp);
+ __sanitizer_FILE *res = REAL(freopen64)(path, mode, fp);
+ COMMON_INTERCEPTOR_FILE_OPEN(ctx, res, path);
+ if (res) unpoison_file(res);
+ return res;
+}
+#define INIT_FOPEN64 \
+ COMMON_INTERCEPT_FUNCTION(fopen64); \
+ COMMON_INTERCEPT_FUNCTION(freopen64);
+#else
+#define INIT_FOPEN64
+#endif
+
+#if SANITIZER_INTERCEPT_OPEN_MEMSTREAM
+INTERCEPTOR(__sanitizer_FILE *, open_memstream, char **ptr, SIZE_T *sizeloc) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, open_memstream, ptr, sizeloc);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ __sanitizer_FILE *res = REAL(open_memstream)(ptr, sizeloc);
+ if (res) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, sizeof(*ptr));
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sizeloc, sizeof(*sizeloc));
+ unpoison_file(res);
+ FileMetadata file = {ptr, sizeloc};
+ SetInterceptorMetadata(res, file);
+ }
+ return res;
+}
+INTERCEPTOR(__sanitizer_FILE *, open_wmemstream, wchar_t **ptr,
+ SIZE_T *sizeloc) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, open_wmemstream, ptr, sizeloc);
+ __sanitizer_FILE *res = REAL(open_wmemstream)(ptr, sizeloc);
+ if (res) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, sizeof(*ptr));
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sizeloc, sizeof(*sizeloc));
+ unpoison_file(res);
+ FileMetadata file = {(char **)ptr, sizeloc};
+ SetInterceptorMetadata(res, file);
+ }
+ return res;
+}
+INTERCEPTOR(__sanitizer_FILE *, fmemopen, void *buf, SIZE_T size,
+ const char *mode) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, fmemopen, buf, size, mode);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ __sanitizer_FILE *res = REAL(fmemopen)(buf, size, mode);
+ if (res) unpoison_file(res);
+ return res;
+}
+#define INIT_OPEN_MEMSTREAM \
+ COMMON_INTERCEPT_FUNCTION(open_memstream); \
+ COMMON_INTERCEPT_FUNCTION(open_wmemstream); \
+ COMMON_INTERCEPT_FUNCTION(fmemopen);
+#else
+#define INIT_OPEN_MEMSTREAM
+#endif
+
+#if SANITIZER_INTERCEPT_OBSTACK
+static void initialize_obstack(__sanitizer_obstack *obstack) {
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(obstack, sizeof(*obstack));
+ if (obstack->chunk)
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(obstack->chunk,
+ sizeof(*obstack->chunk));
+}
+
+INTERCEPTOR(int, _obstack_begin_1, __sanitizer_obstack *obstack, int sz,
+ int align, void *(*alloc_fn)(uptr arg, uptr sz),
+ void (*free_fn)(uptr arg, void *p)) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, _obstack_begin_1, obstack, sz, align, alloc_fn,
+ free_fn);
+ int res = REAL(_obstack_begin_1)(obstack, sz, align, alloc_fn, free_fn);
+ if (res) initialize_obstack(obstack);
+ return res;
+}
+INTERCEPTOR(int, _obstack_begin, __sanitizer_obstack *obstack, int sz,
+ int align, void *(*alloc_fn)(uptr sz), void (*free_fn)(void *p)) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, _obstack_begin, obstack, sz, align, alloc_fn,
+ free_fn);
+ int res = REAL(_obstack_begin)(obstack, sz, align, alloc_fn, free_fn);
+ if (res) initialize_obstack(obstack);
+ return res;
+}
+INTERCEPTOR(void, _obstack_newchunk, __sanitizer_obstack *obstack, int length) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, _obstack_newchunk, obstack, length);
+ REAL(_obstack_newchunk)(obstack, length);
+ if (obstack->chunk)
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(
+ obstack->chunk, obstack->next_free - (char *)obstack->chunk);
+}
+#define INIT_OBSTACK \
+ COMMON_INTERCEPT_FUNCTION(_obstack_begin_1); \
+ COMMON_INTERCEPT_FUNCTION(_obstack_begin); \
+ COMMON_INTERCEPT_FUNCTION(_obstack_newchunk);
+#else
+#define INIT_OBSTACK
+#endif
+
+#if SANITIZER_INTERCEPT_FFLUSH
+INTERCEPTOR(int, fflush, __sanitizer_FILE *fp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, fflush, fp);
+ int res = REAL(fflush)(fp);
+ // FIXME: handle fp == NULL
+ if (fp) {
+ const FileMetadata *m = GetInterceptorMetadata(fp);
+ if (m) COMMON_INTERCEPTOR_INITIALIZE_RANGE(*m->addr, *m->size);
+ }
+ return res;
+}
+#define INIT_FFLUSH COMMON_INTERCEPT_FUNCTION(fflush);
+#else
+#define INIT_FFLUSH
+#endif
+
+#if SANITIZER_INTERCEPT_FCLOSE
+INTERCEPTOR(int, fclose, __sanitizer_FILE *fp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, fclose, fp);
+ if (fp) {
+ COMMON_INTERCEPTOR_FILE_CLOSE(ctx, fp);
+ const FileMetadata *m = GetInterceptorMetadata(fp);
+ if (m) {
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(*m->addr, *m->size);
+ DeleteInterceptorMetadata(fp);
+ }
+ }
+ return REAL(fclose)(fp);
+}
+#define INIT_FCLOSE COMMON_INTERCEPT_FUNCTION(fclose);
+#else
+#define INIT_FCLOSE
+#endif
+
+#if SANITIZER_INTERCEPT_DLOPEN_DLCLOSE
+INTERCEPTOR(void*, dlopen, const char *filename, int flag) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER_NOIGNORE(ctx, dlopen, filename, flag);
+ void *res = REAL(dlopen)(filename, flag);
+ COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, res);
+ return res;
+}
+
+INTERCEPTOR(int, dlclose, void *handle) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER_NOIGNORE(ctx, dlclose, handle);
+ int res = REAL(dlclose)(handle);
+ COMMON_INTERCEPTOR_LIBRARY_UNLOADED();
+ return res;
+}
+#define INIT_DLOPEN_DLCLOSE \
+ COMMON_INTERCEPT_FUNCTION(dlopen); \
+ COMMON_INTERCEPT_FUNCTION(dlclose);
+#else
+#define INIT_DLOPEN_DLCLOSE
+#endif
+
+#if SANITIZER_INTERCEPT_GETPASS
+INTERCEPTOR(char *, getpass, const char *prompt) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getpass, prompt);
+ if (prompt)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, prompt, REAL(strlen)(prompt)+1);
+ char *res = REAL(getpass)(prompt);
+ if (res) COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, REAL(strlen)(res)+1);
+ return res;
+}
+
+#define INIT_GETPASS COMMON_INTERCEPT_FUNCTION(getpass);
+#else
+#define INIT_GETPASS
+#endif
+
+#if SANITIZER_INTERCEPT_TIMERFD
+INTERCEPTOR(int, timerfd_settime, int fd, int flags, void *new_value,
+ void *old_value) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, timerfd_settime, fd, flags, new_value,
+ old_value);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, new_value, struct_itimerspec_sz);
+ int res = REAL(timerfd_settime)(fd, flags, new_value, old_value);
+ if (res != -1 && old_value)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, old_value, struct_itimerspec_sz);
+ return res;
+}
+
+INTERCEPTOR(int, timerfd_gettime, int fd, void *curr_value) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, timerfd_gettime, fd, curr_value);
+ int res = REAL(timerfd_gettime)(fd, curr_value);
+ if (res != -1 && curr_value)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, curr_value, struct_itimerspec_sz);
+ return res;
+}
+#define INIT_TIMERFD \
+ COMMON_INTERCEPT_FUNCTION(timerfd_settime); \
+ COMMON_INTERCEPT_FUNCTION(timerfd_gettime);
+#else
+#define INIT_TIMERFD
+#endif
+
+#if SANITIZER_INTERCEPT_MLOCKX
+// Linux kernel has a bug that leads to kernel deadlock if a process
+// maps TBs of memory and then calls mlock().
+static void MlockIsUnsupported() {
+ static atomic_uint8_t printed;
+ if (atomic_exchange(&printed, 1, memory_order_relaxed))
+ return;
+ VPrintf(1, "INFO: %s ignores mlock/mlockall/munlock/munlockall\n",
+ SanitizerToolName);
+}
+
+INTERCEPTOR(int, mlock, const void *addr, uptr len) {
+ MlockIsUnsupported();
+ return 0;
+}
+
+INTERCEPTOR(int, munlock, const void *addr, uptr len) {
+ MlockIsUnsupported();
+ return 0;
+}
+
+INTERCEPTOR(int, mlockall, int flags) {
+ MlockIsUnsupported();
+ return 0;
+}
+
+INTERCEPTOR(int, munlockall, void) {
+ MlockIsUnsupported();
+ return 0;
+}
+
+#define INIT_MLOCKX \
+ COMMON_INTERCEPT_FUNCTION(mlock); \
+ COMMON_INTERCEPT_FUNCTION(munlock); \
+ COMMON_INTERCEPT_FUNCTION(mlockall); \
+ COMMON_INTERCEPT_FUNCTION(munlockall);
+
+#else
+#define INIT_MLOCKX
+#endif // SANITIZER_INTERCEPT_MLOCKX
+
+static void InitializeCommonInterceptors() {
+ static u64 metadata_mem[sizeof(MetadataHashMap) / sizeof(u64) + 1];
+ interceptor_metadata_map = new((void *)&metadata_mem) MetadataHashMap();
+
+ INIT_TEXTDOMAIN;
+ INIT_STRCMP;
+ INIT_STRNCMP;
+ INIT_STRCASECMP;
+ INIT_STRNCASECMP;
+ INIT_MEMCHR;
+ INIT_MEMRCHR;
+ INIT_READ;
+ INIT_PREAD;
+ INIT_PREAD64;
+ INIT_READV;
+ INIT_PREADV;
+ INIT_PREADV64;
+ INIT_WRITE;
+ INIT_PWRITE;
+ INIT_PWRITE64;
+ INIT_WRITEV;
+ INIT_PWRITEV;
+ INIT_PWRITEV64;
+ INIT_PRCTL;
+ INIT_LOCALTIME_AND_FRIENDS;
+ INIT_STRPTIME;
+ INIT_SCANF;
+ INIT_ISOC99_SCANF;
+ INIT_PRINTF;
+ INIT_ISOC99_PRINTF;
+ INIT_FREXP;
+ INIT_FREXPF_FREXPL;
+ INIT_GETPWNAM_AND_FRIENDS;
+ INIT_GETPWNAM_R_AND_FRIENDS;
+ INIT_GETPWENT;
+ INIT_FGETPWENT;
+ INIT_GETPWENT_R;
+ INIT_SETPWENT;
+ INIT_CLOCK_GETTIME;
+ INIT_GETITIMER;
+ INIT_TIME;
+ INIT_GLOB;
+ INIT_WAIT;
+ INIT_WAIT4;
+ INIT_INET;
+ INIT_PTHREAD_GETSCHEDPARAM;
+ INIT_GETADDRINFO;
+ INIT_GETNAMEINFO;
+ INIT_GETSOCKNAME;
+ INIT_GETHOSTBYNAME;
+ INIT_GETHOSTBYNAME_R;
+ INIT_GETHOSTBYNAME2_R;
+ INIT_GETHOSTBYADDR_R;
+ INIT_GETHOSTENT_R;
+ INIT_GETSOCKOPT;
+ INIT_ACCEPT;
+ INIT_ACCEPT4;
+ INIT_MODF;
+ INIT_RECVMSG;
+ INIT_GETPEERNAME;
+ INIT_IOCTL;
+ INIT_INET_ATON;
+ INIT_SYSINFO;
+ INIT_READDIR;
+ INIT_READDIR64;
+ INIT_PTRACE;
+ INIT_SETLOCALE;
+ INIT_GETCWD;
+ INIT_GET_CURRENT_DIR_NAME;
+ INIT_STRTOIMAX;
+ INIT_MBSTOWCS;
+ INIT_MBSNRTOWCS;
+ INIT_WCSTOMBS;
+ INIT_WCSNRTOMBS;
+ INIT_TCGETATTR;
+ INIT_REALPATH;
+ INIT_CANONICALIZE_FILE_NAME;
+ INIT_CONFSTR;
+ INIT_SCHED_GETAFFINITY;
+ INIT_STRERROR;
+ INIT_STRERROR_R;
+ INIT_XPG_STRERROR_R;
+ INIT_SCANDIR;
+ INIT_SCANDIR64;
+ INIT_GETGROUPS;
+ INIT_POLL;
+ INIT_PPOLL;
+ INIT_WORDEXP;
+ INIT_SIGWAIT;
+ INIT_SIGWAITINFO;
+ INIT_SIGTIMEDWAIT;
+ INIT_SIGSETOPS;
+ INIT_SIGPENDING;
+ INIT_SIGPROCMASK;
+ INIT_BACKTRACE;
+ INIT__EXIT;
+ INIT_PTHREAD_MUTEX_LOCK;
+ INIT_PTHREAD_MUTEX_UNLOCK;
+ INIT_GETMNTENT;
+ INIT_GETMNTENT_R;
+ INIT_STATFS;
+ INIT_STATFS64;
+ INIT_STATVFS;
+ INIT_STATVFS64;
+ INIT_INITGROUPS;
+ INIT_ETHER_NTOA_ATON;
+ INIT_ETHER_HOST;
+ INIT_ETHER_R;
+ INIT_SHMCTL;
+ INIT_RANDOM_R;
+ INIT_PTHREAD_ATTR_GET;
+ INIT_PTHREAD_ATTR_GETINHERITSCHED;
+ INIT_PTHREAD_ATTR_GETAFFINITY_NP;
+ INIT_PTHREAD_MUTEXATTR_GETPSHARED;
+ INIT_PTHREAD_MUTEXATTR_GETTYPE;
+ INIT_PTHREAD_MUTEXATTR_GETPROTOCOL;
+ INIT_PTHREAD_MUTEXATTR_GETPRIOCEILING;
+ INIT_PTHREAD_MUTEXATTR_GETROBUST;
+ INIT_PTHREAD_MUTEXATTR_GETROBUST_NP;
+ INIT_PTHREAD_RWLOCKATTR_GETPSHARED;
+ INIT_PTHREAD_RWLOCKATTR_GETKIND_NP;
+ INIT_PTHREAD_CONDATTR_GETPSHARED;
+ INIT_PTHREAD_CONDATTR_GETCLOCK;
+ INIT_PTHREAD_BARRIERATTR_GETPSHARED;
+ INIT_TMPNAM;
+ INIT_TMPNAM_R;
+ INIT_TEMPNAM;
+ INIT_PTHREAD_SETNAME_NP;
+ INIT_SINCOS;
+ INIT_REMQUO;
+ INIT_LGAMMA;
+ INIT_LGAMMA_R;
+ INIT_LGAMMAL_R;
+ INIT_DRAND48_R;
+ INIT_RAND_R;
+ INIT_GETLINE;
+ INIT_ICONV;
+ INIT_TIMES;
+ INIT_TLS_GET_ADDR;
+ INIT_LISTXATTR;
+ INIT_GETXATTR;
+ INIT_GETRESID;
+ INIT_GETIFADDRS;
+ INIT_IF_INDEXTONAME;
+ INIT_CAPGET;
+ INIT_AEABI_MEM;
+ INIT___BZERO;
+ INIT_FTIME;
+ INIT_XDR;
+ INIT_TSEARCH;
+ INIT_LIBIO_INTERNALS;
+ INIT_FOPEN;
+ INIT_FOPEN64;
+ INIT_OPEN_MEMSTREAM;
+ INIT_OBSTACK;
+ INIT_FFLUSH;
+ INIT_FCLOSE;
+ INIT_DLOPEN_DLCLOSE;
+ INIT_GETPASS;
+ INIT_TIMERFD;
+ INIT_MLOCKX;
+}
diff --git a/lib/sanitizer_common/sanitizer_common_interceptors_format.inc b/lib/sanitizer_common/sanitizer_common_interceptors_format.inc
new file mode 100644
index 000000000000..8f94802aeae8
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_common_interceptors_format.inc
@@ -0,0 +1,559 @@
+//===-- sanitizer_common_interceptors_format.inc ----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Scanf/printf implementation for use in *Sanitizer interceptors.
+// Follows http://pubs.opengroup.org/onlinepubs/9699919799/functions/fscanf.html
+// and http://pubs.opengroup.org/onlinepubs/9699919799/functions/fprintf.html
+// with a few common GNU extensions.
+//
+//===----------------------------------------------------------------------===//
+#include <stdarg.h>
+
+static const char *parse_number(const char *p, int *out) {
+ *out = internal_atoll(p);
+ while (*p >= '0' && *p <= '9')
+ ++p;
+ return p;
+}
+
+static const char *maybe_parse_param_index(const char *p, int *out) {
+ // n$
+ if (*p >= '0' && *p <= '9') {
+ int number;
+ const char *q = parse_number(p, &number);
+ CHECK(q);
+ if (*q == '$') {
+ *out = number;
+ p = q + 1;
+ }
+ }
+
+ // Otherwise, do not change p. This will be re-parsed later as the field
+ // width.
+ return p;
+}
+
+static bool char_is_one_of(char c, const char *s) {
+ return !!internal_strchr(s, c);
+}
+
+static const char *maybe_parse_length_modifier(const char *p, char ll[2]) {
+ if (char_is_one_of(*p, "jztLq")) {
+ ll[0] = *p;
+ ++p;
+ } else if (*p == 'h') {
+ ll[0] = 'h';
+ ++p;
+ if (*p == 'h') {
+ ll[1] = 'h';
+ ++p;
+ }
+ } else if (*p == 'l') {
+ ll[0] = 'l';
+ ++p;
+ if (*p == 'l') {
+ ll[1] = 'l';
+ ++p;
+ }
+ }
+ return p;
+}
+
+// Returns true if the character is an integer conversion specifier.
+static bool format_is_integer_conv(char c) {
+ return char_is_one_of(c, "diouxXn");
+}
+
+// Returns true if the character is an floating point conversion specifier.
+static bool format_is_float_conv(char c) {
+ return char_is_one_of(c, "aAeEfFgG");
+}
+
+// Returns string output character size for string-like conversions,
+// or 0 if the conversion is invalid.
+static int format_get_char_size(char convSpecifier,
+ const char lengthModifier[2]) {
+ if (char_is_one_of(convSpecifier, "CS")) {
+ return sizeof(wchar_t);
+ }
+
+ if (char_is_one_of(convSpecifier, "cs[")) {
+ if (lengthModifier[0] == 'l' && lengthModifier[1] == '\0')
+ return sizeof(wchar_t);
+ else if (lengthModifier[0] == '\0')
+ return sizeof(char);
+ }
+
+ return 0;
+}
+
+enum FormatStoreSize {
+ // Store size not known in advance; can be calculated as wcslen() of the
+ // destination buffer.
+ FSS_WCSLEN = -2,
+ // Store size not known in advance; can be calculated as strlen() of the
+ // destination buffer.
+ FSS_STRLEN = -1,
+ // Invalid conversion specifier.
+ FSS_INVALID = 0
+};
+
+// Returns the memory size of a format directive (if >0), or a value of
+// FormatStoreSize.
+static int format_get_value_size(char convSpecifier,
+ const char lengthModifier[2],
+ bool promote_float) {
+ if (format_is_integer_conv(convSpecifier)) {
+ switch (lengthModifier[0]) {
+ case 'h':
+ return lengthModifier[1] == 'h' ? sizeof(char) : sizeof(short);
+ case 'l':
+ return lengthModifier[1] == 'l' ? sizeof(long long) : sizeof(long);
+ case 'q':
+ return sizeof(long long);
+ case 'L':
+ return sizeof(long long);
+ case 'j':
+ return sizeof(INTMAX_T);
+ case 'z':
+ return sizeof(SIZE_T);
+ case 't':
+ return sizeof(PTRDIFF_T);
+ case 0:
+ return sizeof(int);
+ default:
+ return FSS_INVALID;
+ }
+ }
+
+ if (format_is_float_conv(convSpecifier)) {
+ switch (lengthModifier[0]) {
+ case 'L':
+ case 'q':
+ return sizeof(long double);
+ case 'l':
+ return lengthModifier[1] == 'l' ? sizeof(long double)
+ : sizeof(double);
+ case 0:
+ // Printf promotes floats to doubles but scanf does not
+ return promote_float ? sizeof(double) : sizeof(float);
+ default:
+ return FSS_INVALID;
+ }
+ }
+
+ if (convSpecifier == 'p') {
+ if (lengthModifier[0] != 0)
+ return FSS_INVALID;
+ return sizeof(void *);
+ }
+
+ return FSS_INVALID;
+}
+
+struct ScanfDirective {
+ int argIdx; // argument index, or -1 if not specified ("%n$")
+ int fieldWidth;
+ const char *begin;
+ const char *end;
+ bool suppressed; // suppress assignment ("*")
+ bool allocate; // allocate space ("m")
+ char lengthModifier[2];
+ char convSpecifier;
+ bool maybeGnuMalloc;
+};
+
+// Parse scanf format string. If a valid directive in encountered, it is
+// returned in dir. This function returns the pointer to the first
+// unprocessed character, or 0 in case of error.
+// In case of the end-of-string, a pointer to the closing \0 is returned.
+static const char *scanf_parse_next(const char *p, bool allowGnuMalloc,
+ ScanfDirective *dir) {
+ internal_memset(dir, 0, sizeof(*dir));
+ dir->argIdx = -1;
+
+ while (*p) {
+ if (*p != '%') {
+ ++p;
+ continue;
+ }
+ dir->begin = p;
+ ++p;
+ // %%
+ if (*p == '%') {
+ ++p;
+ continue;
+ }
+ if (*p == '\0') {
+ return 0;
+ }
+ // %n$
+ p = maybe_parse_param_index(p, &dir->argIdx);
+ CHECK(p);
+ // *
+ if (*p == '*') {
+ dir->suppressed = true;
+ ++p;
+ }
+ // Field width
+ if (*p >= '0' && *p <= '9') {
+ p = parse_number(p, &dir->fieldWidth);
+ CHECK(p);
+ if (dir->fieldWidth <= 0) // Width if at all must be non-zero
+ return 0;
+ }
+ // m
+ if (*p == 'm') {
+ dir->allocate = true;
+ ++p;
+ }
+ // Length modifier.
+ p = maybe_parse_length_modifier(p, dir->lengthModifier);
+ // Conversion specifier.
+ dir->convSpecifier = *p++;
+ // Consume %[...] expression.
+ if (dir->convSpecifier == '[') {
+ if (*p == '^')
+ ++p;
+ if (*p == ']')
+ ++p;
+ while (*p && *p != ']')
+ ++p;
+ if (*p == 0)
+ return 0; // unexpected end of string
+ // Consume the closing ']'.
+ ++p;
+ }
+ // This is unfortunately ambiguous between old GNU extension
+ // of %as, %aS and %a[...] and newer POSIX %a followed by
+ // letters s, S or [.
+ if (allowGnuMalloc && dir->convSpecifier == 'a' &&
+ !dir->lengthModifier[0]) {
+ if (*p == 's' || *p == 'S') {
+ dir->maybeGnuMalloc = true;
+ ++p;
+ } else if (*p == '[') {
+ // Watch for %a[h-j%d], if % appears in the
+ // [...] range, then we need to give up, we don't know
+ // if scanf will parse it as POSIX %a [h-j %d ] or
+ // GNU allocation of string with range dh-j plus %.
+ const char *q = p + 1;
+ if (*q == '^')
+ ++q;
+ if (*q == ']')
+ ++q;
+ while (*q && *q != ']' && *q != '%')
+ ++q;
+ if (*q == 0 || *q == '%')
+ return 0;
+ p = q + 1; // Consume the closing ']'.
+ dir->maybeGnuMalloc = true;
+ }
+ }
+ dir->end = p;
+ break;
+ }
+ return p;
+}
+
+static int scanf_get_value_size(ScanfDirective *dir) {
+ if (dir->allocate) {
+ if (!char_is_one_of(dir->convSpecifier, "cCsS["))
+ return FSS_INVALID;
+ return sizeof(char *);
+ }
+
+ if (dir->maybeGnuMalloc) {
+ if (dir->convSpecifier != 'a' || dir->lengthModifier[0])
+ return FSS_INVALID;
+ // This is ambiguous, so check the smaller size of char * (if it is
+ // a GNU extension of %as, %aS or %a[...]) and float (if it is
+ // POSIX %a followed by s, S or [ letters).
+ return sizeof(char *) < sizeof(float) ? sizeof(char *) : sizeof(float);
+ }
+
+ if (char_is_one_of(dir->convSpecifier, "cCsS[")) {
+ bool needsTerminator = char_is_one_of(dir->convSpecifier, "sS[");
+ unsigned charSize =
+ format_get_char_size(dir->convSpecifier, dir->lengthModifier);
+ if (charSize == 0)
+ return FSS_INVALID;
+ if (dir->fieldWidth == 0) {
+ if (!needsTerminator)
+ return charSize;
+ return (charSize == sizeof(char)) ? FSS_STRLEN : FSS_WCSLEN;
+ }
+ return (dir->fieldWidth + needsTerminator) * charSize;
+ }
+
+ return format_get_value_size(dir->convSpecifier, dir->lengthModifier, false);
+}
+
+// Common part of *scanf interceptors.
+// Process format string and va_list, and report all store ranges.
+// Stops when "consuming" n_inputs input items.
+static void scanf_common(void *ctx, int n_inputs, bool allowGnuMalloc,
+ const char *format, va_list aq) {
+ CHECK_GT(n_inputs, 0);
+ const char *p = format;
+
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, format, internal_strlen(format) + 1);
+
+ while (*p) {
+ ScanfDirective dir;
+ p = scanf_parse_next(p, allowGnuMalloc, &dir);
+ if (!p)
+ break;
+ if (dir.convSpecifier == 0) {
+ // This can only happen at the end of the format string.
+ CHECK_EQ(*p, 0);
+ break;
+ }
+ // Here the directive is valid. Do what it says.
+ if (dir.argIdx != -1) {
+ // Unsupported.
+ break;
+ }
+ if (dir.suppressed)
+ continue;
+ int size = scanf_get_value_size(&dir);
+ if (size == FSS_INVALID) {
+ Report("WARNING: unexpected format specifier in scanf interceptor: "
+ "%.*s\n", dir.end - dir.begin, dir.begin);
+ break;
+ }
+ void *argp = va_arg(aq, void *);
+ if (dir.convSpecifier != 'n')
+ --n_inputs;
+ if (n_inputs < 0)
+ break;
+ if (size == FSS_STRLEN) {
+ size = internal_strlen((const char *)argp) + 1;
+ } else if (size == FSS_WCSLEN) {
+ // FIXME: actually use wcslen() to calculate it.
+ size = 0;
+ }
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, argp, size);
+ }
+}
+
+#if SANITIZER_INTERCEPT_PRINTF
+
+struct PrintfDirective {
+ int fieldWidth;
+ int fieldPrecision;
+ int argIdx; // width argument index, or -1 if not specified ("%*n$")
+ int precisionIdx; // precision argument index, or -1 if not specified (".*n$")
+ const char *begin;
+ const char *end;
+ bool starredWidth;
+ bool starredPrecision;
+ char lengthModifier[2];
+ char convSpecifier;
+};
+
+static const char *maybe_parse_number(const char *p, int *out) {
+ if (*p >= '0' && *p <= '9')
+ p = parse_number(p, out);
+ return p;
+}
+
+static const char *maybe_parse_number_or_star(const char *p, int *out,
+ bool *star) {
+ if (*p == '*') {
+ *star = true;
+ ++p;
+ } else {
+ *star = false;
+ p = maybe_parse_number(p, out);
+ }
+ return p;
+}
+
+// Parse printf format string. Same as scanf_parse_next.
+static const char *printf_parse_next(const char *p, PrintfDirective *dir) {
+ internal_memset(dir, 0, sizeof(*dir));
+ dir->argIdx = -1;
+ dir->precisionIdx = -1;
+
+ while (*p) {
+ if (*p != '%') {
+ ++p;
+ continue;
+ }
+ dir->begin = p;
+ ++p;
+ // %%
+ if (*p == '%') {
+ ++p;
+ continue;
+ }
+ if (*p == '\0') {
+ return 0;
+ }
+ // %n$
+ p = maybe_parse_param_index(p, &dir->precisionIdx);
+ CHECK(p);
+ // Flags
+ while (char_is_one_of(*p, "'-+ #0")) {
+ ++p;
+ }
+ // Field width
+ p = maybe_parse_number_or_star(p, &dir->fieldWidth,
+ &dir->starredWidth);
+ if (!p)
+ return 0;
+ // Precision
+ if (*p == '.') {
+ ++p;
+ // Actual precision is optional (surprise!)
+ p = maybe_parse_number_or_star(p, &dir->fieldPrecision,
+ &dir->starredPrecision);
+ if (!p)
+ return 0;
+ // m$
+ if (dir->starredPrecision) {
+ p = maybe_parse_param_index(p, &dir->precisionIdx);
+ CHECK(p);
+ }
+ }
+ // Length modifier.
+ p = maybe_parse_length_modifier(p, dir->lengthModifier);
+ // Conversion specifier.
+ dir->convSpecifier = *p++;
+ dir->end = p;
+ break;
+ }
+ return p;
+}
+
+static int printf_get_value_size(PrintfDirective *dir) {
+ if (dir->convSpecifier == 'm') {
+ return sizeof(char *);
+ }
+
+ if (char_is_one_of(dir->convSpecifier, "cCsS")) {
+ unsigned charSize =
+ format_get_char_size(dir->convSpecifier, dir->lengthModifier);
+ if (charSize == 0)
+ return FSS_INVALID;
+ if (char_is_one_of(dir->convSpecifier, "sS")) {
+ return (charSize == sizeof(char)) ? FSS_STRLEN : FSS_WCSLEN;
+ }
+ return charSize;
+ }
+
+ return format_get_value_size(dir->convSpecifier, dir->lengthModifier, true);
+}
+
+#define SKIP_SCALAR_ARG(aq, convSpecifier, size) \
+ do { \
+ if (format_is_float_conv(convSpecifier)) { \
+ switch (size) { \
+ case 8: \
+ va_arg(*aq, double); \
+ break; \
+ case 12: \
+ va_arg(*aq, long double); \
+ break; \
+ case 16: \
+ va_arg(*aq, long double); \
+ break; \
+ default: \
+ Report("WARNING: unexpected floating-point arg size" \
+ " in printf interceptor: %d\n", size); \
+ return; \
+ } \
+ } else { \
+ switch (size) { \
+ case 1: \
+ case 2: \
+ case 4: \
+ va_arg(*aq, u32); \
+ break; \
+ case 8: \
+ va_arg(*aq, u64); \
+ break; \
+ default: \
+ Report("WARNING: unexpected arg size" \
+ " in printf interceptor: %d\n", size); \
+ return; \
+ } \
+ } \
+ } while (0)
+
+// Common part of *printf interceptors.
+// Process format string and va_list, and report all load ranges.
+static void printf_common(void *ctx, const char *format, va_list aq) {
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, format, internal_strlen(format) + 1);
+
+ const char *p = format;
+
+ while (*p) {
+ PrintfDirective dir;
+ p = printf_parse_next(p, &dir);
+ if (!p)
+ break;
+ if (dir.convSpecifier == 0) {
+ // This can only happen at the end of the format string.
+ CHECK_EQ(*p, 0);
+ break;
+ }
+ // Here the directive is valid. Do what it says.
+ if (dir.argIdx != -1 || dir.precisionIdx != -1) {
+ // Unsupported.
+ break;
+ }
+ if (dir.starredWidth) {
+ // Dynamic width
+ SKIP_SCALAR_ARG(&aq, 'd', sizeof(int));
+ }
+ if (dir.starredPrecision) {
+ // Dynamic precision
+ SKIP_SCALAR_ARG(&aq, 'd', sizeof(int));
+ }
+ int size = printf_get_value_size(&dir);
+ if (size == FSS_INVALID) {
+ Report("WARNING: unexpected format specifier in printf "
+ "interceptor: %.*s\n", dir.end - dir.begin, dir.begin);
+ break;
+ }
+ if (dir.convSpecifier == 'n') {
+ void *argp = va_arg(aq, void *);
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, argp, size);
+ continue;
+ } else if (size == FSS_STRLEN) {
+ if (void *argp = va_arg(aq, void *)) {
+ if (dir.starredPrecision) {
+ // FIXME: properly support starred precision for strings.
+ size = 0;
+ } else if (dir.fieldPrecision > 0) {
+ // Won't read more than "precision" symbols.
+ size = internal_strnlen((const char *)argp, dir.fieldPrecision);
+ if (size < dir.fieldPrecision) size++;
+ } else {
+ // Whole string will be accessed.
+ size = internal_strlen((const char *)argp) + 1;
+ }
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, argp, size);
+ }
+ } else if (size == FSS_WCSLEN) {
+ if (void *argp = va_arg(aq, void *)) {
+ // FIXME: Properly support wide-character strings (via wcsrtombs).
+ size = 0;
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, argp, size);
+ }
+ } else {
+ // Skip non-pointer args
+ SKIP_SCALAR_ARG(&aq, dir.convSpecifier, size);
+ }
+ }
+}
+
+#endif // SANITIZER_INTERCEPT_PRINTF
diff --git a/lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc b/lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc
index 4b90f8ca8a36..69b7ca9eaa2e 100755
--- a/lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc
+++ b/lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc
@@ -14,14 +14,18 @@
struct ioctl_desc {
unsigned req;
- // FIXME: support read+write arguments. Those are currently marked as WRITE.
+ // FIXME: support read+write arguments. Currently READWRITE and WRITE do the
+ // same thing.
+ // XXX: The declarations below may use WRITE instead of READWRITE, unless
+ // explicitly noted.
enum {
NONE,
READ,
WRITE,
+ READWRITE,
CUSTOM
- } type : 2;
- unsigned size : 30;
+ } type : 3;
+ unsigned size : 29;
const char* name;
};
@@ -489,11 +493,15 @@ static void ioctl_init() {
// Handle the most evil ioctls that encode argument value as part of request id.
static unsigned ioctl_request_fixup(unsigned req) {
#if SANITIZER_LINUX
- if ((req & ~0x3fff001fU) == IOCTL_EVIOCGBIT)
+ // Strip size and event number.
+ const unsigned kEviocgbitMask =
+ (IOC_SIZEMASK << IOC_SIZESHIFT) | EVIOC_EV_MAX;
+ if ((req & ~kEviocgbitMask) == IOCTL_EVIOCGBIT)
return IOCTL_EVIOCGBIT;
- if ((req & ~0x3fU) == IOCTL_EVIOCGABS)
+ // Strip absolute axis number.
+ if ((req & ~EVIOC_ABS_MAX) == IOCTL_EVIOCGABS)
return IOCTL_EVIOCGABS;
- if ((req & ~0x3fU) == IOCTL_EVIOCSABS)
+ if ((req & ~EVIOC_ABS_MAX) == IOCTL_EVIOCSABS)
return IOCTL_EVIOCSABS;
#endif
return req;
@@ -515,24 +523,56 @@ static const ioctl_desc *ioctl_table_lookup(unsigned req) {
return 0;
}
+static bool ioctl_decode(unsigned req, ioctl_desc *desc) {
+ CHECK(desc);
+ desc->req = req;
+ desc->name = "<DECODED_IOCTL>";
+ desc->size = IOC_SIZE(req);
+ // Sanity check.
+ if (desc->size > 0xFFFF) return false;
+ unsigned dir = IOC_DIR(req);
+ switch (dir) {
+ case IOC_NONE:
+ desc->type = ioctl_desc::NONE;
+ break;
+ case IOC_READ | IOC_WRITE:
+ desc->type = ioctl_desc::READWRITE;
+ break;
+ case IOC_READ:
+ desc->type = ioctl_desc::WRITE;
+ break;
+ case IOC_WRITE:
+ desc->type = ioctl_desc::READ;
+ break;
+ default:
+ return false;
+ }
+ // Size can be 0 iff type is NONE.
+ if ((desc->type == IOC_NONE) != (desc->size == 0)) return false;
+ // Sanity check.
+ if (IOC_TYPE(req) == 0) return false;
+ return true;
+}
+
static const ioctl_desc *ioctl_lookup(unsigned req) {
req = ioctl_request_fixup(req);
const ioctl_desc *desc = ioctl_table_lookup(req);
if (desc) return desc;
// Try stripping access size from the request id.
- desc = ioctl_table_lookup(req & ~0x3fff0000U);
+ desc = ioctl_table_lookup(req & ~(IOC_SIZEMASK << IOC_SIZESHIFT));
// Sanity check: requests that encode access size are either read or write and
// have size of 0 in the table.
if (desc && desc->size == 0 &&
- (desc->type == ioctl_desc::WRITE || desc->type == ioctl_desc::READ))
+ (desc->type == ioctl_desc::READWRITE || desc->type == ioctl_desc::WRITE ||
+ desc->type == ioctl_desc::READ))
return desc;
return 0;
}
static void ioctl_common_pre(void *ctx, const ioctl_desc *desc, int d,
unsigned request, void *arg) {
- if (desc->type == ioctl_desc::READ) {
+ if (desc->type == ioctl_desc::READ || desc->type == ioctl_desc::READWRITE) {
unsigned size = desc->size ? desc->size : IOC_SIZE(request);
COMMON_INTERCEPTOR_READ_RANGE(ctx, arg, size);
}
@@ -550,7 +590,7 @@ static void ioctl_common_pre(void *ctx, const ioctl_desc *desc, int d,
static void ioctl_common_post(void *ctx, const ioctl_desc *desc, int res, int d,
unsigned request, void *arg) {
- if (desc->type == ioctl_desc::WRITE) {
+ if (desc->type == ioctl_desc::WRITE || desc->type == ioctl_desc::READWRITE) {
// FIXME: add verbose output
unsigned size = desc->size ? desc->size : IOC_SIZE(request);
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, arg, size);
diff --git a/lib/sanitizer_common/sanitizer_common_interceptors_scanf.inc b/lib/sanitizer_common/sanitizer_common_interceptors_scanf.inc
deleted file mode 100644
index 08752e6a3b88..000000000000
--- a/lib/sanitizer_common/sanitizer_common_interceptors_scanf.inc
+++ /dev/null
@@ -1,311 +0,0 @@
-//===-- sanitizer_common_interceptors_scanf.inc -----------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// Scanf implementation for use in *Sanitizer interceptors.
-// Follows http://pubs.opengroup.org/onlinepubs/9699919799/functions/fscanf.html
-// with a few common GNU extensions.
-//
-//===----------------------------------------------------------------------===//
-#include <stdarg.h>
-
-struct ScanfDirective {
- int argIdx; // argument index, or -1 of not specified ("%n$")
- int fieldWidth;
- bool suppressed; // suppress assignment ("*")
- bool allocate; // allocate space ("m")
- char lengthModifier[2];
- char convSpecifier;
- bool maybeGnuMalloc;
-};
-
-static const char *parse_number(const char *p, int *out) {
- *out = internal_atoll(p);
- while (*p >= '0' && *p <= '9')
- ++p;
- return p;
-}
-
-static bool char_is_one_of(char c, const char *s) {
- return !!internal_strchr(s, c);
-}
-
-// Parse scanf format string. If a valid directive in encountered, it is
-// returned in dir. This function returns the pointer to the first
-// unprocessed character, or 0 in case of error.
-// In case of the end-of-string, a pointer to the closing \0 is returned.
-static const char *scanf_parse_next(const char *p, bool allowGnuMalloc,
- ScanfDirective *dir) {
- internal_memset(dir, 0, sizeof(*dir));
- dir->argIdx = -1;
-
- while (*p) {
- if (*p != '%') {
- ++p;
- continue;
- }
- ++p;
- // %%
- if (*p == '%') {
- ++p;
- continue;
- }
- if (*p == '\0') {
- return 0;
- }
- // %n$
- if (*p >= '0' && *p <= '9') {
- int number;
- const char *q = parse_number(p, &number);
- if (*q == '$') {
- dir->argIdx = number;
- p = q + 1;
- }
- // Otherwise, do not change p. This will be re-parsed later as the field
- // width.
- }
- // *
- if (*p == '*') {
- dir->suppressed = true;
- ++p;
- }
- // Field width.
- if (*p >= '0' && *p <= '9') {
- p = parse_number(p, &dir->fieldWidth);
- if (dir->fieldWidth <= 0)
- return 0;
- }
- // m
- if (*p == 'm') {
- dir->allocate = true;
- ++p;
- }
- // Length modifier.
- if (char_is_one_of(*p, "jztLq")) {
- dir->lengthModifier[0] = *p;
- ++p;
- } else if (*p == 'h') {
- dir->lengthModifier[0] = 'h';
- ++p;
- if (*p == 'h') {
- dir->lengthModifier[1] = 'h';
- ++p;
- }
- } else if (*p == 'l') {
- dir->lengthModifier[0] = 'l';
- ++p;
- if (*p == 'l') {
- dir->lengthModifier[1] = 'l';
- ++p;
- }
- }
- // Conversion specifier.
- dir->convSpecifier = *p++;
- // Consume %[...] expression.
- if (dir->convSpecifier == '[') {
- if (*p == '^')
- ++p;
- if (*p == ']')
- ++p;
- while (*p && *p != ']')
- ++p;
- if (*p == 0)
- return 0; // unexpected end of string
- // Consume the closing ']'.
- ++p;
- }
- // This is unfortunately ambiguous between old GNU extension
- // of %as, %aS and %a[...] and newer POSIX %a followed by
- // letters s, S or [.
- if (allowGnuMalloc && dir->convSpecifier == 'a' &&
- !dir->lengthModifier[0]) {
- if (*p == 's' || *p == 'S') {
- dir->maybeGnuMalloc = true;
- ++p;
- } else if (*p == '[') {
- // Watch for %a[h-j%d], if % appears in the
- // [...] range, then we need to give up, we don't know
- // if scanf will parse it as POSIX %a [h-j %d ] or
- // GNU allocation of string with range dh-j plus %.
- const char *q = p + 1;
- if (*q == '^')
- ++q;
- if (*q == ']')
- ++q;
- while (*q && *q != ']' && *q != '%')
- ++q;
- if (*q == 0 || *q == '%')
- return 0;
- p = q + 1; // Consume the closing ']'.
- dir->maybeGnuMalloc = true;
- }
- }
- break;
- }
- return p;
-}
-
-// Returns true if the character is an integer conversion specifier.
-static bool scanf_is_integer_conv(char c) {
- return char_is_one_of(c, "diouxXn");
-}
-
-// Returns true if the character is an floating point conversion specifier.
-static bool scanf_is_float_conv(char c) {
- return char_is_one_of(c, "aAeEfFgG");
-}
-
-// Returns string output character size for string-like conversions,
-// or 0 if the conversion is invalid.
-static int scanf_get_char_size(ScanfDirective *dir) {
- if (char_is_one_of(dir->convSpecifier, "CS")) {
- // wchar_t
- return 0;
- }
-
- if (char_is_one_of(dir->convSpecifier, "cs[")) {
- if (dir->lengthModifier[0] == 'l')
- // wchar_t
- return 0;
- else if (dir->lengthModifier[0] == 0)
- return sizeof(char);
- else
- return 0;
- }
-
- return 0;
-}
-
-enum ScanfStoreSize {
- // Store size not known in advance; can be calculated as strlen() of the
- // destination buffer.
- SSS_STRLEN = -1,
- // Invalid conversion specifier.
- SSS_INVALID = 0
-};
-
-// Returns the store size of a scanf directive (if >0), or a value of
-// ScanfStoreSize.
-static int scanf_get_store_size(ScanfDirective *dir) {
- if (dir->allocate) {
- if (!char_is_one_of(dir->convSpecifier, "cCsS["))
- return SSS_INVALID;
- return sizeof(char *);
- }
-
- if (dir->maybeGnuMalloc) {
- if (dir->convSpecifier != 'a' || dir->lengthModifier[0])
- return SSS_INVALID;
- // This is ambiguous, so check the smaller size of char * (if it is
- // a GNU extension of %as, %aS or %a[...]) and float (if it is
- // POSIX %a followed by s, S or [ letters).
- return sizeof(char *) < sizeof(float) ? sizeof(char *) : sizeof(float);
- }
-
- if (scanf_is_integer_conv(dir->convSpecifier)) {
- switch (dir->lengthModifier[0]) {
- case 'h':
- return dir->lengthModifier[1] == 'h' ? sizeof(char) : sizeof(short);
- case 'l':
- return dir->lengthModifier[1] == 'l' ? sizeof(long long) : sizeof(long);
- case 'L':
- return sizeof(long long);
- case 'j':
- return sizeof(INTMAX_T);
- case 'z':
- return sizeof(SIZE_T);
- case 't':
- return sizeof(PTRDIFF_T);
- case 0:
- return sizeof(int);
- default:
- return SSS_INVALID;
- }
- }
-
- if (scanf_is_float_conv(dir->convSpecifier)) {
- switch (dir->lengthModifier[0]) {
- case 'L':
- case 'q':
- return sizeof(long double);
- case 'l':
- return dir->lengthModifier[1] == 'l' ? sizeof(long double)
- : sizeof(double);
- case 0:
- return sizeof(float);
- default:
- return SSS_INVALID;
- }
- }
-
- if (char_is_one_of(dir->convSpecifier, "sS[")) {
- unsigned charSize = scanf_get_char_size(dir);
- if (charSize == 0)
- return SSS_INVALID;
- if (dir->fieldWidth == 0)
- return SSS_STRLEN;
- return (dir->fieldWidth + 1) * charSize;
- }
-
- if (char_is_one_of(dir->convSpecifier, "cC")) {
- unsigned charSize = scanf_get_char_size(dir);
- if (charSize == 0)
- return SSS_INVALID;
- if (dir->fieldWidth == 0)
- return charSize;
- return dir->fieldWidth * charSize;
- }
-
- if (dir->convSpecifier == 'p') {
- if (dir->lengthModifier[1] != 0)
- return SSS_INVALID;
- return sizeof(void *);
- }
-
- return SSS_INVALID;
-}
-
-// Common part of *scanf interceptors.
-// Process format string and va_list, and report all store ranges.
-// Stops when "consuming" n_inputs input items.
-static void scanf_common(void *ctx, int n_inputs, bool allowGnuMalloc,
- const char *format, va_list aq) {
- CHECK_GT(n_inputs, 0);
- const char *p = format;
-
- while (*p) {
- ScanfDirective dir;
- p = scanf_parse_next(p, allowGnuMalloc, &dir);
- if (!p)
- break;
- if (dir.convSpecifier == 0) {
- // This can only happen at the end of the format string.
- CHECK_EQ(*p, 0);
- break;
- }
- // Here the directive is valid. Do what it says.
- if (dir.argIdx != -1) {
- // Unsupported.
- break;
- }
- if (dir.suppressed)
- continue;
- int size = scanf_get_store_size(&dir);
- if (size == SSS_INVALID)
- break;
- void *argp = va_arg(aq, void *);
- if (dir.convSpecifier != 'n')
- --n_inputs;
- if (n_inputs < 0)
- break;
- if (size == SSS_STRLEN) {
- size = internal_strlen((const char *)argp) + 1;
- }
- COMMON_INTERCEPTOR_WRITE_RANGE(ctx, argp, size);
- }
-}
diff --git a/lib/sanitizer_common/sanitizer_common_libcdep.cc b/lib/sanitizer_common/sanitizer_common_libcdep.cc
index f3430074eb0f..20c1d5a78987 100644
--- a/lib/sanitizer_common/sanitizer_common_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_common_libcdep.cc
@@ -12,26 +12,58 @@
//===----------------------------------------------------------------------===//
#include "sanitizer_common.h"
+#include "sanitizer_flags.h"
+#include "sanitizer_stacktrace.h"
+#include "sanitizer_symbolizer.h"
namespace __sanitizer {
-bool PrintsToTty() {
- MaybeOpenReportFile();
- return internal_isatty(report_fd) != 0;
+bool ReportFile::PrintsToTty() {
+ SpinMutexLock l(mu);
+ ReopenIfNecessary();
+ return internal_isatty(fd) != 0;
}
-bool PrintsToTtyCached() {
+bool ColorizeReports() {
// FIXME: Add proper Windows support to AnsiColorDecorator and re-enable color
// printing on Windows.
if (SANITIZER_WINDOWS)
- return 0;
+ return false;
- static int cached = 0;
- static bool prints_to_tty;
- if (!cached) { // Not thread-safe.
- prints_to_tty = PrintsToTty();
- cached = 1;
+ const char *flag = common_flags()->color;
+ return internal_strcmp(flag, "always") == 0 ||
+ (internal_strcmp(flag, "auto") == 0 && report_file.PrintsToTty());
+}
+
+static void (*sandboxing_callback)();
+void SetSandboxingCallback(void (*f)()) {
+ sandboxing_callback = f;
+}
+
+void ReportErrorSummary(const char *error_type, StackTrace *stack) {
+ if (!common_flags()->print_summary)
+ return;
+#if !SANITIZER_GO
+ if (stack->size > 0 && Symbolizer::GetOrInit()->CanReturnFileLineInfo()) {
+ // Currently, we include the first stack frame into the report summary.
+ // Maybe sometimes we need to choose another frame (e.g. skip memcpy/etc).
+ uptr pc = StackTrace::GetPreviousInstructionPc(stack->trace[0]);
+ SymbolizedStack *frame = Symbolizer::GetOrInit()->SymbolizePC(pc);
+ const AddressInfo &ai = frame->info;
+ ReportErrorSummary(error_type, ai.file, ai.line, ai.function);
+ frame->ClearAll();
}
- return prints_to_tty;
+#else
+ AddressInfo ai;
+ ReportErrorSummary(error_type, ai.file, ai.line, ai.function);
+#endif
}
+
} // namespace __sanitizer
+
+void NOINLINE
+__sanitizer_sandbox_on_notify(__sanitizer_sandbox_arguments *args) {
+ PrepareForSandboxing(args);
+ if (sandboxing_callback)
+ sandboxing_callback();
+}
diff --git a/lib/sanitizer_common/sanitizer_common_syscalls.inc b/lib/sanitizer_common/sanitizer_common_syscalls.inc
index 958f12f84393..a52338b62f5e 100644
--- a/lib/sanitizer_common/sanitizer_common_syscalls.inc
+++ b/lib/sanitizer_common/sanitizer_common_syscalls.inc
@@ -25,8 +25,16 @@
// COMMON_SYSCALL_POST_WRITE_RANGE
// Called in posthook for regions that were written to by the kernel
// and are now initialized.
+// COMMON_SYSCALL_ACQUIRE(addr)
+// Acquire memory visibility from addr.
+// COMMON_SYSCALL_RELEASE(addr)
+// Release memory visibility to addr.
// COMMON_SYSCALL_FD_CLOSE(fd)
// Called before closing file descriptor fd.
+// COMMON_SYSCALL_FD_ACQUIRE(fd)
+// Acquire memory visibility from fd.
+// COMMON_SYSCALL_FD_RELEASE(fd)
+// Release memory visibility to fd.
// COMMON_SYSCALL_PRE_FORK()
// Called before fork syscall.
// COMMON_SYSCALL_POST_FORK(long res)
@@ -48,16 +56,32 @@
#define POST_READ(p, s) COMMON_SYSCALL_POST_READ_RANGE(p, s)
#define POST_WRITE(p, s) COMMON_SYSCALL_POST_WRITE_RANGE(p, s)
+#ifndef COMMON_SYSCALL_ACQUIRE
+# define COMMON_SYSCALL_ACQUIRE(addr) ((void)(addr))
+#endif
+
+#ifndef COMMON_SYSCALL_RELEASE
+# define COMMON_SYSCALL_RELEASE(addr) ((void)(addr))
+#endif
+
#ifndef COMMON_SYSCALL_FD_CLOSE
-# define COMMON_SYSCALL_FD_CLOSE(fd)
+# define COMMON_SYSCALL_FD_CLOSE(fd) ((void)(fd))
+#endif
+
+#ifndef COMMON_SYSCALL_FD_ACQUIRE
+# define COMMON_SYSCALL_FD_ACQUIRE(fd) ((void)(fd))
+#endif
+
+#ifndef COMMON_SYSCALL_FD_RELEASE
+# define COMMON_SYSCALL_FD_RELEASE(fd) ((void)(fd))
#endif
#ifndef COMMON_SYSCALL_PRE_FORK
-# define COMMON_SYSCALL_PRE_FORK()
+# define COMMON_SYSCALL_PRE_FORK() {}
#endif
#ifndef COMMON_SYSCALL_POST_FORK
-# define COMMON_SYSCALL_POST_FORK(res)
+# define COMMON_SYSCALL_POST_FORK(res) {}
#endif
// FIXME: do some kind of PRE_READ for all syscall arguments (int(s) and such).
@@ -210,6 +234,7 @@ POST_SYSCALL(settimeofday)(long res, void *tv, void *tz) {
}
}
+#if !SANITIZER_ANDROID
PRE_SYSCALL(adjtimex)(void *txc_p) {}
POST_SYSCALL(adjtimex)(long res, void *txc_p) {
@@ -217,6 +242,7 @@ POST_SYSCALL(adjtimex)(long res, void *txc_p) {
if (txc_p) POST_WRITE(txc_p, struct_timex_sz);
}
}
+#endif
PRE_SYSCALL(times)(void *tbuf) {}
@@ -362,24 +388,21 @@ PRE_SYSCALL(acct)(const void *name) {
POST_SYSCALL(acct)(long res, const void *name) {}
-PRE_SYSCALL(capget)(void *header, void *dataptr) {}
+PRE_SYSCALL(capget)(void *header, void *dataptr) {
+ if (header) PRE_READ(header, __user_cap_header_struct_sz);
+}
POST_SYSCALL(capget)(long res, void *header, void *dataptr) {
- if (res >= 0) {
- if (header) POST_WRITE(header, __user_cap_header_struct_sz);
+ if (res >= 0)
if (dataptr) POST_WRITE(dataptr, __user_cap_data_struct_sz);
- }
}
PRE_SYSCALL(capset)(void *header, const void *data) {
+ if (header) PRE_READ(header, __user_cap_header_struct_sz);
if (data) PRE_READ(data, __user_cap_data_struct_sz);
}
-POST_SYSCALL(capset)(long res, void *header, const void *data) {
- if (res >= 0) {
- if (header) POST_WRITE(header, __user_cap_header_struct_sz);
- }
-}
+POST_SYSCALL(capset)(long res, void *header, const void *data) {}
PRE_SYSCALL(personality)(long personality) {}
@@ -472,6 +495,7 @@ POST_SYSCALL(clock_gettime)(long res, long which_clock, void *tp) {
}
}
+#if !SANITIZER_ANDROID
PRE_SYSCALL(clock_adjtime)(long which_clock, void *tx) {}
POST_SYSCALL(clock_adjtime)(long res, long which_clock, void *tx) {
@@ -479,6 +503,7 @@ POST_SYSCALL(clock_adjtime)(long res, long which_clock, void *tx) {
if (tx) POST_WRITE(tx, struct_timex_sz);
}
}
+#endif
PRE_SYSCALL(clock_getres)(long which_clock, void *tp) {}
@@ -806,6 +831,7 @@ POST_SYSCALL(stat)(long res, const void *filename, void *statbuf) {
}
}
+#if !SANITIZER_ANDROID
PRE_SYSCALL(statfs)(const void *path, void *buf) {
if (path)
PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1);
@@ -843,6 +869,7 @@ POST_SYSCALL(fstatfs64)(long res, long fd, long sz, void *buf) {
if (buf) POST_WRITE(buf, struct_statfs64_sz);
}
}
+#endif // !SANITIZER_ANDROID
PRE_SYSCALL(lstat)(const void *filename, void *statbuf) {
if (filename)
@@ -896,6 +923,7 @@ POST_SYSCALL(newfstat)(long res, long fd, void *statbuf) {
}
}
+#if !SANITIZER_ANDROID
PRE_SYSCALL(ustat)(long dev, void *ubuf) {}
POST_SYSCALL(ustat)(long res, long dev, void *ubuf) {
@@ -903,6 +931,7 @@ POST_SYSCALL(ustat)(long res, long dev, void *ubuf) {
if (ubuf) POST_WRITE(ubuf, struct_ustat_sz);
}
}
+#endif // !SANITIZER_ANDROID
PRE_SYSCALL(stat64)(const void *filename, void *statbuf) {
if (filename)
@@ -980,8 +1009,8 @@ PRE_SYSCALL(getxattr)(const void *path, const void *name, void *value,
POST_SYSCALL(getxattr)(long res, const void *path, const void *name,
void *value, long size) {
- if (res >= 0) {
- if (value) POST_WRITE(value, size);
+ if (size && res > 0) {
+ if (value) POST_WRITE(value, res);
}
}
@@ -995,8 +1024,8 @@ PRE_SYSCALL(lgetxattr)(const void *path, const void *name, void *value,
POST_SYSCALL(lgetxattr)(long res, const void *path, const void *name,
void *value, long size) {
- if (res >= 0) {
- if (value) POST_WRITE(value, size);
+ if (size && res > 0) {
+ if (value) POST_WRITE(value, res);
}
}
@@ -1007,8 +1036,8 @@ PRE_SYSCALL(fgetxattr)(long fd, const void *name, void *value, long size) {
POST_SYSCALL(fgetxattr)(long res, long fd, const void *name, void *value,
long size) {
- if (res >= 0) {
- if (value) POST_WRITE(value, size);
+ if (size && res > 0) {
+ if (value) POST_WRITE(value, res);
}
}
@@ -1018,8 +1047,8 @@ PRE_SYSCALL(listxattr)(const void *path, void *list, long size) {
}
POST_SYSCALL(listxattr)(long res, const void *path, void *list, long size) {
- if (res >= 0) {
- if (list) POST_WRITE(list, size);
+ if (size && res > 0) {
+ if (list) POST_WRITE(list, res);
}
}
@@ -1029,16 +1058,16 @@ PRE_SYSCALL(llistxattr)(const void *path, void *list, long size) {
}
POST_SYSCALL(llistxattr)(long res, const void *path, void *list, long size) {
- if (res >= 0) {
- if (list) POST_WRITE(list, size);
+ if (size && res > 0) {
+ if (list) POST_WRITE(list, res);
}
}
PRE_SYSCALL(flistxattr)(long fd, void *list, long size) {}
POST_SYSCALL(flistxattr)(long res, long fd, void *list, long size) {
- if (res >= 0) {
- if (list) POST_WRITE(list, size);
+ if (size && res > 0) {
+ if (list) POST_WRITE(list, res);
}
}
@@ -1245,11 +1274,17 @@ PRE_SYSCALL(flock)(long fd, long cmd) {}
POST_SYSCALL(flock)(long res, long fd, long cmd) {}
-PRE_SYSCALL(io_setup)(long nr_reqs, void *ctx) {}
+PRE_SYSCALL(io_setup)(long nr_reqs, void **ctx) {
+ if (ctx) PRE_WRITE(ctx, sizeof(*ctx));
+}
-POST_SYSCALL(io_setup)(long res, long nr_reqs, void *ctx) {
+POST_SYSCALL(io_setup)(long res, long nr_reqs, void **ctx) {
if (res >= 0) {
- if (ctx) POST_WRITE(ctx, sizeof(long));
+ if (ctx) POST_WRITE(ctx, sizeof(*ctx));
+ // (*ctx) is actually a pointer to a kernel mapped page, and there are
+ // people out there who are crazy enough to peek into that page's 32-byte
+ // header.
+ if (*ctx) POST_WRITE(*ctx, 32);
}
}
@@ -1257,44 +1292,70 @@ PRE_SYSCALL(io_destroy)(long ctx) {}
POST_SYSCALL(io_destroy)(long res, long ctx) {}
-PRE_SYSCALL(io_getevents)(long ctx_id, long min_nr, long nr, void *events,
- void *timeout) {
+PRE_SYSCALL(io_getevents)(long ctx_id, long min_nr, long nr,
+ __sanitizer_io_event *ioevpp, void *timeout) {
if (timeout) PRE_READ(timeout, struct_timespec_sz);
}
POST_SYSCALL(io_getevents)(long res, long ctx_id, long min_nr, long nr,
- void *events, void *timeout) {
+ __sanitizer_io_event *ioevpp, void *timeout) {
if (res >= 0) {
- if (events) POST_WRITE(events, res * struct_io_event_sz);
+ if (ioevpp) POST_WRITE(ioevpp, res * sizeof(*ioevpp));
if (timeout) POST_WRITE(timeout, struct_timespec_sz);
}
+ for (long i = 0; i < res; i++) {
+ // We synchronize io_submit -> io_getevents/io_cancel using the
+ // user-provided data context. Data is not necessary a pointer, it can be
+ // an int, 0 or whatever; acquire/release will correctly handle this.
+ // This scheme can lead to false negatives, e.g. when all operations
+ // synchronize on 0. But there does not seem to be a better solution
+ // (except wrapping all operations in own context, which is unreliable).
+ // We can not reliably extract fildes in io_getevents.
+ COMMON_SYSCALL_ACQUIRE((void*)ioevpp[i].data);
+ }
}
PRE_SYSCALL(io_submit)(long ctx_id, long nr, __sanitizer_iocb **iocbpp) {
for (long i = 0; i < nr; ++i) {
- if (iocbpp[i]->aio_lio_opcode == iocb_cmd_pwrite && iocbpp[i]->aio_buf &&
- iocbpp[i]->aio_nbytes)
- PRE_READ((void *)iocbpp[i]->aio_buf, iocbpp[i]->aio_nbytes);
+ uptr op = iocbpp[i]->aio_lio_opcode;
+ void *data = (void*)iocbpp[i]->aio_data;
+ void *buf = (void*)iocbpp[i]->aio_buf;
+ uptr len = (uptr)iocbpp[i]->aio_nbytes;
+ if (op == iocb_cmd_pwrite && buf && len) {
+ PRE_READ(buf, len);
+ } else if (op == iocb_cmd_pread && buf && len) {
+ POST_WRITE(buf, len);
+ } else if (op == iocb_cmd_pwritev) {
+ __sanitizer_iovec *iovec = (__sanitizer_iovec*)buf;
+ for (uptr v = 0; v < len; v++)
+ PRE_READ(iovec[v].iov_base, iovec[v].iov_len);
+ } else if (op == iocb_cmd_preadv) {
+ __sanitizer_iovec *iovec = (__sanitizer_iovec*)buf;
+ for (uptr v = 0; v < len; v++)
+ POST_WRITE(iovec[v].iov_base, iovec[v].iov_len);
+ }
+ // See comment in io_getevents.
+ COMMON_SYSCALL_RELEASE(data);
}
}
POST_SYSCALL(io_submit)(long res, long ctx_id, long nr,
- __sanitizer_iocb **iocbpp) {
- if (res > 0 && iocbpp) {
- for (long i = 0; i < res; ++i) {
- if (iocbpp[i]->aio_lio_opcode == iocb_cmd_pread && iocbpp[i]->aio_buf &&
- iocbpp[i]->aio_nbytes)
- POST_WRITE((void *)iocbpp[i]->aio_buf, iocbpp[i]->aio_nbytes);
- }
- }
-}
+ __sanitizer_iocb **iocbpp) {}
-PRE_SYSCALL(io_cancel)(long ctx_id, void *iocb, void *result) {}
+PRE_SYSCALL(io_cancel)(long ctx_id, __sanitizer_iocb *iocb,
+ __sanitizer_io_event *result) {
+}
-POST_SYSCALL(io_cancel)(long res, long ctx_id, void *iocb, void *result) {
- if (res >= 0) {
- if (iocb) POST_WRITE(iocb, sizeof(__sanitizer_iocb));
- if (result) POST_WRITE(result, struct_io_event_sz);
+POST_SYSCALL(io_cancel)(long res, long ctx_id, __sanitizer_iocb *iocb,
+ __sanitizer_io_event *result) {
+ if (res == 0) {
+ if (result) {
+ // See comment in io_getevents.
+ COMMON_SYSCALL_ACQUIRE((void*)result->data);
+ POST_WRITE(result, sizeof(*result));
+ }
+ if (iocb)
+ POST_WRITE(iocb, sizeof(*iocb));
}
}
@@ -2026,6 +2087,7 @@ POST_SYSCALL(msgrcv)(long res, long msqid, void *msgp, long msgsz, long msgtyp,
}
}
+#if !SANITIZER_ANDROID
PRE_SYSCALL(msgctl)(long msqid, long cmd, void *buf) {}
POST_SYSCALL(msgctl)(long res, long msqid, long cmd, void *buf) {
@@ -2033,6 +2095,7 @@ POST_SYSCALL(msgctl)(long res, long msqid, long cmd, void *buf) {
if (buf) POST_WRITE(buf, struct_msqid_ds_sz);
}
}
+#endif
PRE_SYSCALL(semget)(long key, long nsems, long semflg) {}
@@ -2234,7 +2297,7 @@ PRE_SYSCALL(ni_syscall)() {}
POST_SYSCALL(ni_syscall)(long res) {}
PRE_SYSCALL(ptrace)(long request, long pid, long addr, long data) {
-#if defined(__i386) || defined (__x86_64)
+#if !SANITIZER_ANDROID && (defined(__i386) || defined (__x86_64))
if (data) {
if (request == ptrace_setregs) {
PRE_READ((void *)data, struct_user_regs_struct_sz);
@@ -2253,7 +2316,7 @@ PRE_SYSCALL(ptrace)(long request, long pid, long addr, long data) {
}
POST_SYSCALL(ptrace)(long res, long request, long pid, long addr, long data) {
-#if defined(__i386) || defined (__x86_64)
+#if !SANITIZER_ANDROID && (defined(__i386) || defined (__x86_64))
if (res >= 0 && data) {
// Note that this is different from the interceptor in
// sanitizer_common_interceptors.inc.
diff --git a/lib/sanitizer_common/sanitizer_coverage.cc b/lib/sanitizer_common/sanitizer_coverage.cc
deleted file mode 100644
index 9e7a0f8b95fb..000000000000
--- a/lib/sanitizer_common/sanitizer_coverage.cc
+++ /dev/null
@@ -1,113 +0,0 @@
-//===-- sanitizer_coverage.cc ---------------------------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// Sanitizer Coverage.
-// This file implements run-time support for a poor man's coverage tool.
-//
-// Compiler instrumentation:
-// For every function F the compiler injects the following code:
-// if (*Guard) {
-// __sanitizer_cov(&F);
-// *Guard = 1;
-// }
-// It's fine to call __sanitizer_cov more than once for a given function.
-//
-// Run-time:
-// - __sanitizer_cov(pc): record that we've executed a given PC.
-// - __sanitizer_cov_dump: dump the coverage data to disk.
-// For every module of the current process that has coverage data
-// this will create a file module_name.PID.sancov. The file format is simple:
-// it's just a sorted sequence of 4-byte offsets in the module.
-//
-// Eventually, this coverage implementation should be obsoleted by a more
-// powerful general purpose Clang/LLVM coverage instrumentation.
-// Consider this implementation as prototype.
-//
-// FIXME: support (or at least test with) dlclose.
-//===----------------------------------------------------------------------===//
-
-#include "sanitizer_allocator_internal.h"
-#include "sanitizer_common.h"
-#include "sanitizer_libc.h"
-#include "sanitizer_mutex.h"
-#include "sanitizer_procmaps.h"
-#include "sanitizer_flags.h"
-
-struct CovData {
- BlockingMutex mu;
- InternalMmapVector<uptr> v;
-};
-
-static uptr cov_data_placeholder[sizeof(CovData) / sizeof(uptr)];
-COMPILER_CHECK(sizeof(cov_data_placeholder) >= sizeof(CovData));
-static CovData *cov_data = reinterpret_cast<CovData*>(cov_data_placeholder);
-
-namespace __sanitizer {
-
-// Simply add the pc into the vector under lock. If the function is called more
-// than once for a given PC it will be inserted multiple times, which is fine.
-static void CovAdd(uptr pc) {
- BlockingMutexLock lock(&cov_data->mu);
- cov_data->v.push_back(pc);
-}
-
-static inline bool CompareLess(const uptr &a, const uptr &b) {
- return a < b;
-}
-
-// Dump the coverage on disk.
-void CovDump() {
-#if !SANITIZER_WINDOWS
- BlockingMutexLock lock(&cov_data->mu);
- InternalMmapVector<uptr> &v = cov_data->v;
- InternalSort(&v, v.size(), CompareLess);
- InternalMmapVector<u32> offsets(v.size());
- const uptr *vb = v.data();
- const uptr *ve = vb + v.size();
- MemoryMappingLayout proc_maps(/*cache_enabled*/false);
- uptr mb, me, off, prot;
- InternalScopedBuffer<char> module(4096);
- InternalScopedBuffer<char> path(4096 * 2);
- for (int i = 0;
- proc_maps.Next(&mb, &me, &off, module.data(), module.size(), &prot);
- i++) {
- if ((prot & MemoryMappingLayout::kProtectionExecute) == 0)
- continue;
- if (vb >= ve) break;
- if (mb <= *vb && *vb < me) {
- offsets.clear();
- const uptr *old_vb = vb;
- CHECK_LE(off, *vb);
- for (; vb < ve && *vb < me; vb++) {
- uptr diff = *vb - (i ? mb : 0) + off;
- CHECK_LE(diff, 0xffffffffU);
- offsets.push_back(static_cast<u32>(diff));
- }
- char *module_name = StripModuleName(module.data());
- internal_snprintf((char *)path.data(), path.size(), "%s.%zd.sancov",
- module_name, internal_getpid());
- InternalFree(module_name);
- uptr fd = OpenFile(path.data(), true);
- internal_write(fd, offsets.data(), offsets.size() * sizeof(u32));
- internal_close(fd);
- if (common_flags()->verbosity)
- Report(" CovDump: %s: %zd PCs written\n", path.data(), vb - old_vb);
- }
- }
-#endif // !SANITIZER_WINDOWS
-}
-
-} // namespace __sanitizer
-
-extern "C" {
-SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov(void *pc) {
- CovAdd(reinterpret_cast<uptr>(pc));
-}
-SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_dump() { CovDump(); }
-} // extern "C"
diff --git a/lib/sanitizer_common/sanitizer_coverage_libcdep.cc b/lib/sanitizer_common/sanitizer_coverage_libcdep.cc
new file mode 100644
index 000000000000..3fa8a18696f8
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_coverage_libcdep.cc
@@ -0,0 +1,581 @@
+//===-- sanitizer_coverage.cc ---------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Sanitizer Coverage.
+// This file implements run-time support for a poor man's coverage tool.
+//
+// Compiler instrumentation:
+// For every interesting basic block the compiler injects the following code:
+// if (Guard) {
+// __sanitizer_cov(&Guard);
+// }
+// It's fine to call __sanitizer_cov more than once for a given block.
+//
+// Run-time:
+// - __sanitizer_cov(): record that we've executed the PC (GET_CALLER_PC).
+// and atomically set Guard to 1.
+// - __sanitizer_cov_dump: dump the coverage data to disk.
+// For every module of the current process that has coverage data
+// this will create a file module_name.PID.sancov. The file format is simple:
+// it's just a sorted sequence of 4-byte offsets in the module.
+//
+// Eventually, this coverage implementation should be obsoleted by a more
+// powerful general purpose Clang/LLVM coverage instrumentation.
+// Consider this implementation as prototype.
+//
+// FIXME: support (or at least test with) dlclose.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_allocator_internal.h"
+#include "sanitizer_common.h"
+#include "sanitizer_libc.h"
+#include "sanitizer_mutex.h"
+#include "sanitizer_procmaps.h"
+#include "sanitizer_stacktrace.h"
+#include "sanitizer_symbolizer.h"
+#include "sanitizer_flags.h"
+
+static atomic_uint32_t dump_once_guard; // Ensure that CovDump runs only once.
+
+static atomic_uintptr_t coverage_counter;
+
+// pc_array is the array containing the covered PCs.
+// To make the pc_array thread- and async-signal-safe it has to be large enough.
+// 128M counters "ought to be enough for anybody" (4M on 32-bit).
+
+// With coverage_direct=1 in ASAN_OPTIONS, pc_array memory is mapped to a file.
+// In this mode, __sanitizer_cov_dump does nothing, and CovUpdateMapping()
+// dump current memory layout to another file.
+
+static bool cov_sandboxed = false;
+static int cov_fd = kInvalidFd;
+static unsigned int cov_max_block_size = 0;
+
+namespace __sanitizer {
+
+class CoverageData {
+ public:
+ void Init();
+ void BeforeFork();
+ void AfterFork(int child_pid);
+ void Extend(uptr npcs);
+ void Add(uptr pc, u8 *guard);
+ void IndirCall(uptr caller, uptr callee, uptr callee_cache[],
+ uptr cache_size);
+ void DumpCallerCalleePairs();
+ void DumpTrace();
+
+ ALWAYS_INLINE
+ void TraceBasicaBlock(uptr *cache);
+
+ uptr *data();
+ uptr size();
+
+ private:
+ // Maximal size pc array may ever grow.
+ // We MmapNoReserve this space to ensure that the array is contiguous.
+ static const uptr kPcArrayMaxSize = FIRST_32_SECOND_64(1 << 22, 1 << 27);
+ // The amount file mapping for the pc array is grown by.
+ static const uptr kPcArrayMmapSize = 64 * 1024;
+
+ // pc_array is allocated with MmapNoReserveOrDie and so it uses only as
+ // much RAM as it really needs.
+ uptr *pc_array;
+ // Index of the first available pc_array slot.
+ atomic_uintptr_t pc_array_index;
+ // Array size.
+ atomic_uintptr_t pc_array_size;
+ // Current file mapped size of the pc array.
+ uptr pc_array_mapped_size;
+ // Descriptor of the file mapped pc array.
+ int pc_fd;
+
+ // Caller-Callee (cc) array, size and current index.
+ static const uptr kCcArrayMaxSize = FIRST_32_SECOND_64(1 << 18, 1 << 24);
+ uptr **cc_array;
+ atomic_uintptr_t cc_array_index;
+ atomic_uintptr_t cc_array_size;
+
+ // Tracing (tr) pc and event arrays, their size and current index.
+ // We record all events (basic block entries) in a global buffer of u32
+ // values. Each such value is an index in the table of TracedPc objects.
+ // So far the tracing is highly experimental:
+ // - not thread-safe;
+ // - does not support long traces;
+ // - not tuned for performance.
+ struct TracedPc {
+ uptr pc;
+ const char *module_name;
+ uptr module_offset;
+ };
+ static const uptr kTrEventArrayMaxSize = FIRST_32_SECOND_64(1 << 22, 1 << 30);
+ u32 *tr_event_array;
+ uptr tr_event_array_size;
+ uptr tr_event_array_index;
+ static const uptr kTrPcArrayMaxSize = FIRST_32_SECOND_64(1 << 22, 1 << 27);
+ TracedPc *tr_pc_array;
+ uptr tr_pc_array_size;
+ uptr tr_pc_array_index;
+
+ StaticSpinMutex mu;
+
+ void DirectOpen();
+ void ReInit();
+};
+
+static CoverageData coverage_data;
+
+void CoverageData::DirectOpen() {
+ InternalScopedString path(kMaxPathLength);
+ internal_snprintf((char *)path.data(), path.size(), "%s/%zd.sancov.raw",
+ common_flags()->coverage_dir, internal_getpid());
+ pc_fd = OpenFile(path.data(), true);
+ if (internal_iserror(pc_fd)) {
+ Report(" Coverage: failed to open %s for writing\n", path.data());
+ Die();
+ }
+
+ pc_array_mapped_size = 0;
+ CovUpdateMapping();
+}
+
+void CoverageData::Init() {
+ pc_array = reinterpret_cast<uptr *>(
+ MmapNoReserveOrDie(sizeof(uptr) * kPcArrayMaxSize, "CovInit"));
+ pc_fd = kInvalidFd;
+ if (common_flags()->coverage_direct) {
+ atomic_store(&pc_array_size, 0, memory_order_relaxed);
+ atomic_store(&pc_array_index, 0, memory_order_relaxed);
+ } else {
+ atomic_store(&pc_array_size, kPcArrayMaxSize, memory_order_relaxed);
+ atomic_store(&pc_array_index, 0, memory_order_relaxed);
+ }
+
+ cc_array = reinterpret_cast<uptr **>(MmapNoReserveOrDie(
+ sizeof(uptr *) * kCcArrayMaxSize, "CovInit::cc_array"));
+ atomic_store(&cc_array_size, kCcArrayMaxSize, memory_order_relaxed);
+ atomic_store(&cc_array_index, 0, memory_order_relaxed);
+
+ tr_event_array = reinterpret_cast<u32 *>(
+ MmapNoReserveOrDie(sizeof(tr_event_array[0]) * kTrEventArrayMaxSize,
+ "CovInit::tr_event_array"));
+ tr_event_array_size = kTrEventArrayMaxSize;
+ tr_event_array_index = 0;
+
+ tr_pc_array = reinterpret_cast<TracedPc *>(MmapNoReserveOrDie(
+ sizeof(tr_pc_array[0]) * kTrEventArrayMaxSize, "CovInit::tr_pc_array"));
+ tr_pc_array_size = kTrEventArrayMaxSize;
+ tr_pc_array_index = 0;
+}
+
+void CoverageData::ReInit() {
+ internal_munmap(pc_array, sizeof(uptr) * kPcArrayMaxSize);
+ if (pc_fd != kInvalidFd) internal_close(pc_fd);
+ if (common_flags()->coverage_direct) {
+ // In memory-mapped mode we must extend the new file to the known array
+ // size.
+ uptr size = atomic_load(&pc_array_size, memory_order_relaxed);
+ Init();
+ if (size) Extend(size);
+ } else {
+ Init();
+ }
+}
+
+void CoverageData::BeforeFork() {
+ mu.Lock();
+}
+
+void CoverageData::AfterFork(int child_pid) {
+ // We are single-threaded so it's OK to release the lock early.
+ mu.Unlock();
+ if (child_pid == 0) ReInit();
+}
+
+// Extend coverage PC array to fit additional npcs elements.
+void CoverageData::Extend(uptr npcs) {
+ if (!common_flags()->coverage_direct) return;
+ SpinMutexLock l(&mu);
+
+ if (pc_fd == kInvalidFd) DirectOpen();
+ CHECK_NE(pc_fd, kInvalidFd);
+
+ uptr size = atomic_load(&pc_array_size, memory_order_relaxed);
+ size += npcs * sizeof(uptr);
+
+ if (size > pc_array_mapped_size) {
+ uptr new_mapped_size = pc_array_mapped_size;
+ while (size > new_mapped_size) new_mapped_size += kPcArrayMmapSize;
+
+ // Extend the file and map the new space at the end of pc_array.
+ uptr res = internal_ftruncate(pc_fd, new_mapped_size);
+ int err;
+ if (internal_iserror(res, &err)) {
+ Printf("failed to extend raw coverage file: %d\n", err);
+ Die();
+ }
+ void *p = MapWritableFileToMemory(pc_array + pc_array_mapped_size,
+ new_mapped_size - pc_array_mapped_size,
+ pc_fd, pc_array_mapped_size);
+ CHECK_EQ(p, pc_array + pc_array_mapped_size);
+ pc_array_mapped_size = new_mapped_size;
+ }
+
+ atomic_store(&pc_array_size, size, memory_order_release);
+}
+
+// Atomically add the pc to the vector. The atomically set the guard to 1.
+// If the function is called more than once for a given PC it will
+// be inserted multiple times, which is fine.
+void CoverageData::Add(uptr pc, u8 *guard) {
+ if (!pc_array) return;
+ uptr idx = atomic_fetch_add(&pc_array_index, 1, memory_order_relaxed);
+ CHECK_LT(idx * sizeof(uptr),
+ atomic_load(&pc_array_size, memory_order_acquire));
+ pc_array[idx] = pc;
+ atomic_fetch_add(&coverage_counter, 1, memory_order_relaxed);
+ // Set the guard.
+ atomic_uint8_t *atomic_guard = reinterpret_cast<atomic_uint8_t*>(guard);
+ atomic_store(atomic_guard, 1, memory_order_relaxed);
+}
+
+// Registers a pair caller=>callee.
+// When a given caller is seen for the first time, the callee_cache is added
+// to the global array cc_array, callee_cache[0] is set to caller and
+// callee_cache[1] is set to cache_size.
+// Then we are trying to add callee to callee_cache [2,cache_size) if it is
+// not there yet.
+// If the cache is full we drop the callee (may want to fix this later).
+void CoverageData::IndirCall(uptr caller, uptr callee, uptr callee_cache[],
+ uptr cache_size) {
+ if (!cc_array) return;
+ atomic_uintptr_t *atomic_callee_cache =
+ reinterpret_cast<atomic_uintptr_t *>(callee_cache);
+ uptr zero = 0;
+ if (atomic_compare_exchange_strong(&atomic_callee_cache[0], &zero, caller,
+ memory_order_seq_cst)) {
+ uptr idx = atomic_fetch_add(&cc_array_index, 1, memory_order_relaxed);
+ CHECK_LT(idx * sizeof(uptr),
+ atomic_load(&cc_array_size, memory_order_acquire));
+ callee_cache[1] = cache_size;
+ cc_array[idx] = callee_cache;
+ }
+ CHECK_EQ(atomic_load(&atomic_callee_cache[0], memory_order_relaxed), caller);
+ for (uptr i = 2; i < cache_size; i++) {
+ uptr was = 0;
+ if (atomic_compare_exchange_strong(&atomic_callee_cache[i], &was, callee,
+ memory_order_seq_cst)) {
+ atomic_fetch_add(&coverage_counter, 1, memory_order_relaxed);
+ return;
+ }
+ if (was == callee) // Already have this callee.
+ return;
+ }
+}
+
+uptr *CoverageData::data() {
+ return pc_array;
+}
+
+uptr CoverageData::size() {
+ return atomic_load(&pc_array_index, memory_order_relaxed);
+}
+
+// Block layout for packed file format: header, followed by module name (no
+// trailing zero), followed by data blob.
+struct CovHeader {
+ int pid;
+ unsigned int module_name_length;
+ unsigned int data_length;
+};
+
+static void CovWritePacked(int pid, const char *module, const void *blob,
+ unsigned int blob_size) {
+ if (cov_fd < 0) return;
+ unsigned module_name_length = internal_strlen(module);
+ CovHeader header = {pid, module_name_length, blob_size};
+
+ if (cov_max_block_size == 0) {
+ // Writing to a file. Just go ahead.
+ internal_write(cov_fd, &header, sizeof(header));
+ internal_write(cov_fd, module, module_name_length);
+ internal_write(cov_fd, blob, blob_size);
+ } else {
+ // Writing to a socket. We want to split the data into appropriately sized
+ // blocks.
+ InternalScopedBuffer<char> block(cov_max_block_size);
+ CHECK_EQ((uptr)block.data(), (uptr)(CovHeader *)block.data());
+ uptr header_size_with_module = sizeof(header) + module_name_length;
+ CHECK_LT(header_size_with_module, cov_max_block_size);
+ unsigned int max_payload_size =
+ cov_max_block_size - header_size_with_module;
+ char *block_pos = block.data();
+ internal_memcpy(block_pos, &header, sizeof(header));
+ block_pos += sizeof(header);
+ internal_memcpy(block_pos, module, module_name_length);
+ block_pos += module_name_length;
+ char *block_data_begin = block_pos;
+ const char *blob_pos = (const char *)blob;
+ while (blob_size > 0) {
+ unsigned int payload_size = Min(blob_size, max_payload_size);
+ blob_size -= payload_size;
+ internal_memcpy(block_data_begin, blob_pos, payload_size);
+ blob_pos += payload_size;
+ ((CovHeader *)block.data())->data_length = payload_size;
+ internal_write(cov_fd, block.data(),
+ header_size_with_module + payload_size);
+ }
+ }
+}
+
+// If packed = false: <name>.<pid>.<sancov> (name = module name).
+// If packed = true and name == 0: <pid>.<sancov>.<packed>.
+// If packed = true and name != 0: <name>.<sancov>.<packed> (name is
+// user-supplied).
+static int CovOpenFile(bool packed, const char* name) {
+ InternalScopedString path(kMaxPathLength);
+ if (!packed) {
+ CHECK(name);
+ path.append("%s/%s.%zd.sancov", common_flags()->coverage_dir, name,
+ internal_getpid());
+ } else {
+ if (!name)
+ path.append("%s/%zd.sancov.packed", common_flags()->coverage_dir,
+ internal_getpid());
+ else
+ path.append("%s/%s.sancov.packed", common_flags()->coverage_dir, name);
+ }
+ uptr fd = OpenFile(path.data(), true);
+ if (internal_iserror(fd)) {
+ Report(" SanitizerCoverage: failed to open %s for writing\n", path.data());
+ return -1;
+ }
+ return fd;
+}
+
+// Dump trace PCs and trace events into two separate files.
+void CoverageData::DumpTrace() {
+ uptr max_idx = tr_event_array_index;
+ if (!max_idx) return;
+ auto sym = Symbolizer::GetOrInit();
+ if (!sym)
+ return;
+ InternalScopedString out(32 << 20);
+ for (uptr i = 0; i < max_idx; i++) {
+ u32 pc_idx = tr_event_array[i];
+ TracedPc *t = &tr_pc_array[pc_idx];
+ if (!t->module_name) {
+ const char *module_name = "<unknown>";
+ uptr module_address = 0;
+ sym->GetModuleNameAndOffsetForPC(t->pc, &module_name, &module_address);
+ t->module_name = internal_strdup(module_name);
+ t->module_offset = module_address;
+ out.append("%s 0x%zx\n", t->module_name, t->module_offset);
+ }
+ }
+ int fd = CovOpenFile(false, "trace-points");
+ if (fd < 0) return;
+ internal_write(fd, out.data(), out.length());
+ internal_close(fd);
+
+ fd = CovOpenFile(false, "trace-events");
+ if (fd < 0) return;
+ internal_write(fd, tr_event_array, max_idx * sizeof(tr_event_array[0]));
+ internal_close(fd);
+ VReport(1, " CovDump: Trace: %zd PCs written\n", tr_pc_array_index);
+ VReport(1, " CovDump: Trace: %zd Events written\n", tr_event_array_index);
+}
+
+// This function dumps the caller=>callee pairs into a file as a sequence of
+// lines like "module_name offset".
+void CoverageData::DumpCallerCalleePairs() {
+ uptr max_idx = atomic_load(&cc_array_index, memory_order_relaxed);
+ if (!max_idx) return;
+ auto sym = Symbolizer::GetOrInit();
+ if (!sym)
+ return;
+ InternalScopedString out(32 << 20);
+ uptr total = 0;
+ for (uptr i = 0; i < max_idx; i++) {
+ uptr *cc_cache = cc_array[i];
+ CHECK(cc_cache);
+ uptr caller = cc_cache[0];
+ uptr n_callees = cc_cache[1];
+ const char *caller_module_name = "<unknown>";
+ uptr caller_module_address = 0;
+ sym->GetModuleNameAndOffsetForPC(caller, &caller_module_name,
+ &caller_module_address);
+ for (uptr j = 2; j < n_callees; j++) {
+ uptr callee = cc_cache[j];
+ if (!callee) break;
+ total++;
+ const char *callee_module_name = "<unknown>";
+ uptr callee_module_address = 0;
+ sym->GetModuleNameAndOffsetForPC(callee, &callee_module_name,
+ &callee_module_address);
+ out.append("%s 0x%zx\n%s 0x%zx\n", caller_module_name,
+ caller_module_address, callee_module_name,
+ callee_module_address);
+ }
+ }
+ int fd = CovOpenFile(false, "caller-callee");
+ if (fd < 0) return;
+ internal_write(fd, out.data(), out.length());
+ internal_close(fd);
+ VReport(1, " CovDump: %zd caller-callee pairs written\n", total);
+}
+
+// Record the current PC into the event buffer.
+// Every event is a u32 value (index in tr_pc_array_index) so we compute
+// it once and then cache in the provided 'cache' storage.
+void CoverageData::TraceBasicaBlock(uptr *cache) {
+ CHECK(common_flags()->coverage);
+ uptr idx = *cache;
+ if (!idx) {
+ CHECK_LT(tr_pc_array_index, kTrPcArrayMaxSize);
+ idx = tr_pc_array_index++;
+ TracedPc *t = &tr_pc_array[idx];
+ t->pc = GET_CALLER_PC();
+ *cache = idx;
+ CHECK_LT(idx, 1U << 31);
+ }
+ CHECK_LT(tr_event_array_index, tr_event_array_size);
+ tr_event_array[tr_event_array_index] = static_cast<u32>(idx);
+ tr_event_array_index++;
+}
+
+// Dump the coverage on disk.
+static void CovDump() {
+ if (!common_flags()->coverage || common_flags()->coverage_direct) return;
+#if !SANITIZER_WINDOWS
+ if (atomic_fetch_add(&dump_once_guard, 1, memory_order_relaxed))
+ return;
+ uptr size = coverage_data.size();
+ InternalMmapVector<u32> offsets(size);
+ uptr *vb = coverage_data.data();
+ uptr *ve = vb + size;
+ SortArray(vb, size);
+ MemoryMappingLayout proc_maps(/*cache_enabled*/true);
+ uptr mb, me, off, prot;
+ InternalScopedString module(kMaxPathLength);
+ InternalScopedString path(kMaxPathLength);
+ for (int i = 0;
+ proc_maps.Next(&mb, &me, &off, module.data(), module.size(), &prot);
+ i++) {
+ if ((prot & MemoryMappingLayout::kProtectionExecute) == 0)
+ continue;
+ while (vb < ve && *vb < mb) vb++;
+ if (vb >= ve) break;
+ if (*vb < me) {
+ offsets.clear();
+ const uptr *old_vb = vb;
+ CHECK_LE(off, *vb);
+ for (; vb < ve && *vb < me; vb++) {
+ uptr diff = *vb - (i ? mb : 0) + off;
+ CHECK_LE(diff, 0xffffffffU);
+ offsets.push_back(static_cast<u32>(diff));
+ }
+ const char *module_name = StripModuleName(module.data());
+ if (cov_sandboxed) {
+ if (cov_fd >= 0) {
+ CovWritePacked(internal_getpid(), module_name, offsets.data(),
+ offsets.size() * sizeof(u32));
+ VReport(1, " CovDump: %zd PCs written to packed file\n", vb - old_vb);
+ }
+ } else {
+ // One file per module per process.
+ path.clear();
+ path.append("%s/%s.%zd.sancov", common_flags()->coverage_dir,
+ module_name, internal_getpid());
+ int fd = CovOpenFile(false /* packed */, module_name);
+ if (fd > 0) {
+ internal_write(fd, offsets.data(), offsets.size() * sizeof(u32));
+ internal_close(fd);
+ VReport(1, " CovDump: %s: %zd PCs written\n", path.data(),
+ vb - old_vb);
+ }
+ }
+ }
+ }
+ if (cov_fd >= 0)
+ internal_close(cov_fd);
+ coverage_data.DumpCallerCalleePairs();
+ coverage_data.DumpTrace();
+#endif // !SANITIZER_WINDOWS
+}
+
+void CovPrepareForSandboxing(__sanitizer_sandbox_arguments *args) {
+ if (!args) return;
+ if (!common_flags()->coverage) return;
+ cov_sandboxed = args->coverage_sandboxed;
+ if (!cov_sandboxed) return;
+ cov_fd = args->coverage_fd;
+ cov_max_block_size = args->coverage_max_block_size;
+ if (cov_fd < 0)
+ // Pre-open the file now. The sandbox won't allow us to do it later.
+ cov_fd = CovOpenFile(true /* packed */, 0);
+}
+
+int MaybeOpenCovFile(const char *name) {
+ CHECK(name);
+ if (!common_flags()->coverage) return -1;
+ return CovOpenFile(true /* packed */, name);
+}
+
+void CovBeforeFork() {
+ coverage_data.BeforeFork();
+}
+
+void CovAfterFork(int child_pid) {
+ coverage_data.AfterFork(child_pid);
+}
+
+} // namespace __sanitizer
+
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov(u8 *guard) {
+ coverage_data.Add(StackTrace::GetPreviousInstructionPc(GET_CALLER_PC()),
+ guard);
+}
+SANITIZER_INTERFACE_ATTRIBUTE void
+__sanitizer_cov_indir_call16(uptr callee, uptr callee_cache16[]) {
+ coverage_data.IndirCall(StackTrace::GetPreviousInstructionPc(GET_CALLER_PC()),
+ callee, callee_cache16, 16);
+}
+SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_dump() { CovDump(); }
+SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_init() {
+ coverage_data.Init();
+}
+SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_module_init(uptr npcs) {
+ if (!common_flags()->coverage || !common_flags()->coverage_direct) return;
+ if (SANITIZER_ANDROID) {
+ // dlopen/dlclose interceptors do not work on Android, so we rely on
+ // Extend() calls to update .sancov.map.
+ CovUpdateMapping(GET_CALLER_PC());
+ }
+ coverage_data.Extend(npcs);
+}
+SANITIZER_INTERFACE_ATTRIBUTE
+sptr __sanitizer_maybe_open_cov_file(const char *name) {
+ return MaybeOpenCovFile(name);
+}
+SANITIZER_INTERFACE_ATTRIBUTE
+uptr __sanitizer_get_total_unique_coverage() {
+ return atomic_load(&coverage_counter, memory_order_relaxed);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_cov_trace_func_enter(uptr *cache) {
+ coverage_data.TraceBasicaBlock(cache);
+}
+SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_cov_trace_basic_block(uptr *cache) {
+ coverage_data.TraceBasicaBlock(cache);
+}
+} // extern "C"
diff --git a/lib/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc b/lib/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc
new file mode 100644
index 000000000000..fe72d06a2fb1
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc
@@ -0,0 +1,125 @@
+//===-- sanitizer_coverage_mapping.cc -------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Mmap-based implementation of sanitizer coverage.
+//
+// This is part of the implementation of code coverage that does not require
+// __sanitizer_cov_dump() call. Data is stored in 2 files per process.
+//
+// $pid.sancov.map describes process memory layout in the following text-based
+// format:
+// <pointer size in bits> // 1 line, 32 or 64
+// <mapping start> <mapping end> <base address> <dso name> // repeated
+// ...
+// Mapping lines are NOT sorted. This file is updated every time memory layout
+// is changed (i.e. in dlopen() and dlclose() interceptors).
+//
+// $pid.sancov.raw is a binary dump of PC values, sizeof(uptr) each. Again, not
+// sorted. This file is extended by 64Kb at a time and mapped into memory. It
+// contains one or more 0 words at the end, up to the next 64Kb aligned offset.
+//
+// To convert these 2 files to the usual .sancov format, run sancov.py rawunpack
+// $pid.sancov.raw.
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_allocator_internal.h"
+#include "sanitizer_libc.h"
+#include "sanitizer_procmaps.h"
+
+namespace __sanitizer {
+
+static const uptr kMaxNumberOfModules = 1 << 14;
+static const uptr kMaxTextSize = 64 * 1024;
+
+struct CachedMapping {
+ public:
+ bool NeedsUpdate(uptr pc) {
+ int new_pid = internal_getpid();
+ if (last_pid == new_pid && pc && pc >= last_range_start &&
+ pc < last_range_end)
+ return false;
+ last_pid = new_pid;
+ return true;
+ }
+
+ void SetModuleRange(uptr start, uptr end) {
+ last_range_start = start;
+ last_range_end = end;
+ }
+
+ private:
+ uptr last_range_start, last_range_end;
+ int last_pid;
+};
+
+static CachedMapping cached_mapping;
+static StaticSpinMutex mapping_mu;
+
+void CovUpdateMapping(uptr caller_pc) {
+ if (!common_flags()->coverage || !common_flags()->coverage_direct) return;
+
+ SpinMutexLock l(&mapping_mu);
+
+ if (!cached_mapping.NeedsUpdate(caller_pc))
+ return;
+
+ InternalScopedString text(kMaxTextSize);
+ InternalScopedBuffer<LoadedModule> modules(kMaxNumberOfModules);
+ CHECK(modules.data());
+ int n_modules = GetListOfModules(modules.data(), kMaxNumberOfModules,
+ /* filter */ 0);
+
+ text.append("%d\n", sizeof(uptr) * 8);
+ for (int i = 0; i < n_modules; ++i) {
+ const char *module_name = StripModuleName(modules[i].full_name());
+ for (unsigned j = 0; j < modules[i].n_ranges(); ++j) {
+ if (modules[i].address_range_executable(j)) {
+ uptr start = modules[i].address_range_start(j);
+ uptr end = modules[i].address_range_end(j);
+ uptr base = modules[i].base_address();
+ text.append("%zx %zx %zx %s\n", start, end, base, module_name);
+ if (caller_pc && caller_pc >= start && caller_pc < end)
+ cached_mapping.SetModuleRange(start, end);
+ }
+ }
+ }
+
+ int err;
+ InternalScopedString tmp_path(64 +
+ internal_strlen(common_flags()->coverage_dir));
+ uptr res = internal_snprintf((char *)tmp_path.data(), tmp_path.size(),
+ "%s/%zd.sancov.map.tmp", common_flags()->coverage_dir,
+ internal_getpid());
+ CHECK_LE(res, tmp_path.size());
+ uptr map_fd = OpenFile(tmp_path.data(), true);
+ if (internal_iserror(map_fd)) {
+ Report(" Coverage: failed to open %s for writing\n", tmp_path.data());
+ Die();
+ }
+
+ res = internal_write(map_fd, text.data(), text.length());
+ if (internal_iserror(res, &err)) {
+ Printf("sancov.map write failed: %d\n", err);
+ Die();
+ }
+ internal_close(map_fd);
+
+ InternalScopedString path(64 + internal_strlen(common_flags()->coverage_dir));
+ res = internal_snprintf((char *)path.data(), path.size(), "%s/%zd.sancov.map",
+ common_flags()->coverage_dir, internal_getpid());
+ CHECK_LE(res, path.size());
+ res = internal_rename(tmp_path.data(), path.data());
+ if (internal_iserror(res, &err)) {
+ Printf("sancov.map rename failed: %d\n", err);
+ Die();
+ }
+}
+
+} // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_deadlock_detector.h b/lib/sanitizer_common/sanitizer_deadlock_detector.h
new file mode 100644
index 000000000000..90e1cc4eb597
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_deadlock_detector.h
@@ -0,0 +1,412 @@
+//===-- sanitizer_deadlock_detector.h ---------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of Sanitizer runtime.
+// The deadlock detector maintains a directed graph of lock acquisitions.
+// When a lock event happens, the detector checks if the locks already held by
+// the current thread are reachable from the newly acquired lock.
+//
+// The detector can handle only a fixed amount of simultaneously live locks
+// (a lock is alive if it has been locked at least once and has not been
+// destroyed). When the maximal number of locks is reached the entire graph
+// is flushed and the new lock epoch is started. The node ids from the old
+// epochs can not be used with any of the detector methods except for
+// nodeBelongsToCurrentEpoch().
+//
+// FIXME: this is work in progress, nothing really works yet.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_DEADLOCK_DETECTOR_H
+#define SANITIZER_DEADLOCK_DETECTOR_H
+
+#include "sanitizer_common.h"
+#include "sanitizer_bvgraph.h"
+
+namespace __sanitizer {
+
+// Thread-local state for DeadlockDetector.
+// It contains the locks currently held by the owning thread.
+template <class BV>
+class DeadlockDetectorTLS {
+ public:
+ // No CTOR.
+ void clear() {
+ bv_.clear();
+ epoch_ = 0;
+ n_recursive_locks = 0;
+ n_all_locks_ = 0;
+ }
+
+ bool empty() const { return bv_.empty(); }
+
+ void ensureCurrentEpoch(uptr current_epoch) {
+ if (epoch_ == current_epoch) return;
+ bv_.clear();
+ epoch_ = current_epoch;
+ }
+
+ uptr getEpoch() const { return epoch_; }
+
+ // Returns true if this is the first (non-recursive) acquisition of this lock.
+ bool addLock(uptr lock_id, uptr current_epoch, u32 stk) {
+ // Printf("addLock: %zx %zx stk %u\n", lock_id, current_epoch, stk);
+ CHECK_EQ(epoch_, current_epoch);
+ if (!bv_.setBit(lock_id)) {
+ // The lock is already held by this thread, it must be recursive.
+ CHECK_LT(n_recursive_locks, ARRAY_SIZE(recursive_locks));
+ recursive_locks[n_recursive_locks++] = lock_id;
+ return false;
+ }
+ CHECK_LT(n_all_locks_, ARRAY_SIZE(all_locks_with_contexts_));
+ // lock_id < BV::kSize, can cast to a smaller int.
+ u32 lock_id_short = static_cast<u32>(lock_id);
+ LockWithContext l = {lock_id_short, stk};
+ all_locks_with_contexts_[n_all_locks_++] = l;
+ return true;
+ }
+
+ void removeLock(uptr lock_id) {
+ if (n_recursive_locks) {
+ for (sptr i = n_recursive_locks - 1; i >= 0; i--) {
+ if (recursive_locks[i] == lock_id) {
+ n_recursive_locks--;
+ Swap(recursive_locks[i], recursive_locks[n_recursive_locks]);
+ return;
+ }
+ }
+ }
+ // Printf("remLock: %zx %zx\n", lock_id, epoch_);
+ CHECK(bv_.clearBit(lock_id));
+ if (n_all_locks_) {
+ for (sptr i = n_all_locks_ - 1; i >= 0; i--) {
+ if (all_locks_with_contexts_[i].lock == static_cast<u32>(lock_id)) {
+ Swap(all_locks_with_contexts_[i],
+ all_locks_with_contexts_[n_all_locks_ - 1]);
+ n_all_locks_--;
+ break;
+ }
+ }
+ }
+ }
+
+ u32 findLockContext(uptr lock_id) {
+ for (uptr i = 0; i < n_all_locks_; i++)
+ if (all_locks_with_contexts_[i].lock == static_cast<u32>(lock_id))
+ return all_locks_with_contexts_[i].stk;
+ return 0;
+ }
+
+ const BV &getLocks(uptr current_epoch) const {
+ CHECK_EQ(epoch_, current_epoch);
+ return bv_;
+ }
+
+ uptr getNumLocks() const { return n_all_locks_; }
+ uptr getLock(uptr idx) const { return all_locks_with_contexts_[idx].lock; }
+
+ private:
+ BV bv_;
+ uptr epoch_;
+ uptr recursive_locks[64];
+ uptr n_recursive_locks;
+ struct LockWithContext {
+ u32 lock;
+ u32 stk;
+ };
+ LockWithContext all_locks_with_contexts_[64];
+ uptr n_all_locks_;
+};
+
+// DeadlockDetector.
+// For deadlock detection to work we need one global DeadlockDetector object
+// and one DeadlockDetectorTLS object per evey thread.
+// This class is not thread safe, all concurrent accesses should be guarded
+// by an external lock.
+// Most of the methods of this class are not thread-safe (i.e. should
+// be protected by an external lock) unless explicitly told otherwise.
+template <class BV>
+class DeadlockDetector {
+ public:
+ typedef BV BitVector;
+
+ uptr size() const { return g_.size(); }
+
+ // No CTOR.
+ void clear() {
+ current_epoch_ = 0;
+ available_nodes_.clear();
+ recycled_nodes_.clear();
+ g_.clear();
+ n_edges_ = 0;
+ }
+
+ // Allocate new deadlock detector node.
+ // If we are out of available nodes first try to recycle some.
+ // If there is nothing to recycle, flush the graph and increment the epoch.
+ // Associate 'data' (opaque user's object) with the new node.
+ uptr newNode(uptr data) {
+ if (!available_nodes_.empty())
+ return getAvailableNode(data);
+ if (!recycled_nodes_.empty()) {
+ // Printf("recycling: n_edges_ %zd\n", n_edges_);
+ for (sptr i = n_edges_ - 1; i >= 0; i--) {
+ if (recycled_nodes_.getBit(edges_[i].from) ||
+ recycled_nodes_.getBit(edges_[i].to)) {
+ Swap(edges_[i], edges_[n_edges_ - 1]);
+ n_edges_--;
+ }
+ }
+ CHECK(available_nodes_.empty());
+ // removeEdgesFrom was called in removeNode.
+ g_.removeEdgesTo(recycled_nodes_);
+ available_nodes_.setUnion(recycled_nodes_);
+ recycled_nodes_.clear();
+ return getAvailableNode(data);
+ }
+ // We are out of vacant nodes. Flush and increment the current_epoch_.
+ current_epoch_ += size();
+ recycled_nodes_.clear();
+ available_nodes_.setAll();
+ g_.clear();
+ return getAvailableNode(data);
+ }
+
+ // Get data associated with the node created by newNode().
+ uptr getData(uptr node) const { return data_[nodeToIndex(node)]; }
+
+ bool nodeBelongsToCurrentEpoch(uptr node) {
+ return node && (node / size() * size()) == current_epoch_;
+ }
+
+ void removeNode(uptr node) {
+ uptr idx = nodeToIndex(node);
+ CHECK(!available_nodes_.getBit(idx));
+ CHECK(recycled_nodes_.setBit(idx));
+ g_.removeEdgesFrom(idx);
+ }
+
+ void ensureCurrentEpoch(DeadlockDetectorTLS<BV> *dtls) {
+ dtls->ensureCurrentEpoch(current_epoch_);
+ }
+
+ // Returns true if there is a cycle in the graph after this lock event.
+ // Ideally should be called before the lock is acquired so that we can
+ // report a deadlock before a real deadlock happens.
+ bool onLockBefore(DeadlockDetectorTLS<BV> *dtls, uptr cur_node) {
+ ensureCurrentEpoch(dtls);
+ uptr cur_idx = nodeToIndex(cur_node);
+ return g_.isReachable(cur_idx, dtls->getLocks(current_epoch_));
+ }
+
+ u32 findLockContext(DeadlockDetectorTLS<BV> *dtls, uptr node) {
+ return dtls->findLockContext(nodeToIndex(node));
+ }
+
+ // Add cur_node to the set of locks held currently by dtls.
+ void onLockAfter(DeadlockDetectorTLS<BV> *dtls, uptr cur_node, u32 stk = 0) {
+ ensureCurrentEpoch(dtls);
+ uptr cur_idx = nodeToIndex(cur_node);
+ dtls->addLock(cur_idx, current_epoch_, stk);
+ }
+
+ // Experimental *racy* fast path function.
+ // Returns true if all edges from the currently held locks to cur_node exist.
+ bool hasAllEdges(DeadlockDetectorTLS<BV> *dtls, uptr cur_node) {
+ uptr local_epoch = dtls->getEpoch();
+ // Read from current_epoch_ is racy.
+ if (cur_node && local_epoch == current_epoch_ &&
+ local_epoch == nodeToEpoch(cur_node)) {
+ uptr cur_idx = nodeToIndexUnchecked(cur_node);
+ for (uptr i = 0, n = dtls->getNumLocks(); i < n; i++) {
+ if (!g_.hasEdge(dtls->getLock(i), cur_idx))
+ return false;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ // Adds edges from currently held locks to cur_node,
+ // returns the number of added edges, and puts the sources of added edges
+ // into added_edges[].
+ // Should be called before onLockAfter.
+ uptr addEdges(DeadlockDetectorTLS<BV> *dtls, uptr cur_node, u32 stk,
+ int unique_tid) {
+ ensureCurrentEpoch(dtls);
+ uptr cur_idx = nodeToIndex(cur_node);
+ uptr added_edges[40];
+ uptr n_added_edges = g_.addEdges(dtls->getLocks(current_epoch_), cur_idx,
+ added_edges, ARRAY_SIZE(added_edges));
+ for (uptr i = 0; i < n_added_edges; i++) {
+ if (n_edges_ < ARRAY_SIZE(edges_)) {
+ Edge e = {(u16)added_edges[i], (u16)cur_idx,
+ dtls->findLockContext(added_edges[i]), stk,
+ unique_tid};
+ edges_[n_edges_++] = e;
+ }
+ // Printf("Edge%zd: %u %zd=>%zd in T%d\n",
+ // n_edges_, stk, added_edges[i], cur_idx, unique_tid);
+ }
+ return n_added_edges;
+ }
+
+ bool findEdge(uptr from_node, uptr to_node, u32 *stk_from, u32 *stk_to,
+ int *unique_tid) {
+ uptr from_idx = nodeToIndex(from_node);
+ uptr to_idx = nodeToIndex(to_node);
+ for (uptr i = 0; i < n_edges_; i++) {
+ if (edges_[i].from == from_idx && edges_[i].to == to_idx) {
+ *stk_from = edges_[i].stk_from;
+ *stk_to = edges_[i].stk_to;
+ *unique_tid = edges_[i].unique_tid;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // Test-only function. Handles the before/after lock events,
+ // returns true if there is a cycle.
+ bool onLock(DeadlockDetectorTLS<BV> *dtls, uptr cur_node, u32 stk = 0) {
+ ensureCurrentEpoch(dtls);
+ bool is_reachable = !isHeld(dtls, cur_node) && onLockBefore(dtls, cur_node);
+ addEdges(dtls, cur_node, stk, 0);
+ onLockAfter(dtls, cur_node, stk);
+ return is_reachable;
+ }
+
+ // Handles the try_lock event, returns false.
+ // When a try_lock event happens (i.e. a try_lock call succeeds) we need
+ // to add this lock to the currently held locks, but we should not try to
+ // change the lock graph or to detect a cycle. We may want to investigate
+ // whether a more aggressive strategy is possible for try_lock.
+ bool onTryLock(DeadlockDetectorTLS<BV> *dtls, uptr cur_node, u32 stk = 0) {
+ ensureCurrentEpoch(dtls);
+ uptr cur_idx = nodeToIndex(cur_node);
+ dtls->addLock(cur_idx, current_epoch_, stk);
+ return false;
+ }
+
+ // Returns true iff dtls is empty (no locks are currently held) and we can
+ // add the node to the currently held locks w/o chanding the global state.
+ // This operation is thread-safe as it only touches the dtls.
+ bool onFirstLock(DeadlockDetectorTLS<BV> *dtls, uptr node, u32 stk = 0) {
+ if (!dtls->empty()) return false;
+ if (dtls->getEpoch() && dtls->getEpoch() == nodeToEpoch(node)) {
+ dtls->addLock(nodeToIndexUnchecked(node), nodeToEpoch(node), stk);
+ return true;
+ }
+ return false;
+ }
+
+ // Finds a path between the lock 'cur_node' (currently not held in dtls)
+ // and some currently held lock, returns the length of the path
+ // or 0 on failure.
+ uptr findPathToLock(DeadlockDetectorTLS<BV> *dtls, uptr cur_node, uptr *path,
+ uptr path_size) {
+ tmp_bv_.copyFrom(dtls->getLocks(current_epoch_));
+ uptr idx = nodeToIndex(cur_node);
+ CHECK(!tmp_bv_.getBit(idx));
+ uptr res = g_.findShortestPath(idx, tmp_bv_, path, path_size);
+ for (uptr i = 0; i < res; i++)
+ path[i] = indexToNode(path[i]);
+ if (res)
+ CHECK_EQ(path[0], cur_node);
+ return res;
+ }
+
+ // Handle the unlock event.
+ // This operation is thread-safe as it only touches the dtls.
+ void onUnlock(DeadlockDetectorTLS<BV> *dtls, uptr node) {
+ if (dtls->getEpoch() == nodeToEpoch(node))
+ dtls->removeLock(nodeToIndexUnchecked(node));
+ }
+
+ // Tries to handle the lock event w/o writing to global state.
+ // Returns true on success.
+ // This operation is thread-safe as it only touches the dtls
+ // (modulo racy nature of hasAllEdges).
+ bool onLockFast(DeadlockDetectorTLS<BV> *dtls, uptr node, u32 stk = 0) {
+ if (hasAllEdges(dtls, node)) {
+ dtls->addLock(nodeToIndexUnchecked(node), nodeToEpoch(node), stk);
+ return true;
+ }
+ return false;
+ }
+
+ bool isHeld(DeadlockDetectorTLS<BV> *dtls, uptr node) const {
+ return dtls->getLocks(current_epoch_).getBit(nodeToIndex(node));
+ }
+
+ uptr testOnlyGetEpoch() const { return current_epoch_; }
+ bool testOnlyHasEdge(uptr l1, uptr l2) {
+ return g_.hasEdge(nodeToIndex(l1), nodeToIndex(l2));
+ }
+ // idx1 and idx2 are raw indices to g_, not lock IDs.
+ bool testOnlyHasEdgeRaw(uptr idx1, uptr idx2) {
+ return g_.hasEdge(idx1, idx2);
+ }
+
+ void Print() {
+ for (uptr from = 0; from < size(); from++)
+ for (uptr to = 0; to < size(); to++)
+ if (g_.hasEdge(from, to))
+ Printf(" %zx => %zx\n", from, to);
+ }
+
+ private:
+ void check_idx(uptr idx) const { CHECK_LT(idx, size()); }
+
+ void check_node(uptr node) const {
+ CHECK_GE(node, size());
+ CHECK_EQ(current_epoch_, nodeToEpoch(node));
+ }
+
+ uptr indexToNode(uptr idx) const {
+ check_idx(idx);
+ return idx + current_epoch_;
+ }
+
+ uptr nodeToIndexUnchecked(uptr node) const { return node % size(); }
+
+ uptr nodeToIndex(uptr node) const {
+ check_node(node);
+ return nodeToIndexUnchecked(node);
+ }
+
+ uptr nodeToEpoch(uptr node) const { return node / size() * size(); }
+
+ uptr getAvailableNode(uptr data) {
+ uptr idx = available_nodes_.getAndClearFirstOne();
+ data_[idx] = data;
+ return indexToNode(idx);
+ }
+
+ struct Edge {
+ u16 from;
+ u16 to;
+ u32 stk_from;
+ u32 stk_to;
+ int unique_tid;
+ };
+
+ uptr current_epoch_;
+ BV available_nodes_;
+ BV recycled_nodes_;
+ BV tmp_bv_;
+ BVGraph<BV> g_;
+ uptr data_[BV::kSize];
+ Edge edges_[BV::kSize * 32];
+ uptr n_edges_;
+};
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_DEADLOCK_DETECTOR_H
diff --git a/lib/sanitizer_common/sanitizer_deadlock_detector1.cc b/lib/sanitizer_common/sanitizer_deadlock_detector1.cc
new file mode 100644
index 000000000000..b931edc7eae5
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_deadlock_detector1.cc
@@ -0,0 +1,189 @@
+//===-- sanitizer_deadlock_detector1.cc -----------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Deadlock detector implementation based on NxN adjacency bit matrix.
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_deadlock_detector_interface.h"
+#include "sanitizer_deadlock_detector.h"
+#include "sanitizer_allocator_internal.h"
+#include "sanitizer_placement_new.h"
+#include "sanitizer_mutex.h"
+
+#if SANITIZER_DEADLOCK_DETECTOR_VERSION == 1
+
+namespace __sanitizer {
+
+typedef TwoLevelBitVector<> DDBV; // DeadlockDetector's bit vector.
+
+struct DDPhysicalThread {
+};
+
+struct DDLogicalThread {
+ u64 ctx;
+ DeadlockDetectorTLS<DDBV> dd;
+ DDReport rep;
+ bool report_pending;
+};
+
+struct DD : public DDetector {
+ SpinMutex mtx;
+ DeadlockDetector<DDBV> dd;
+ DDFlags flags;
+
+ explicit DD(const DDFlags *flags);
+
+ DDPhysicalThread* CreatePhysicalThread();
+ void DestroyPhysicalThread(DDPhysicalThread *pt);
+
+ DDLogicalThread* CreateLogicalThread(u64 ctx);
+ void DestroyLogicalThread(DDLogicalThread *lt);
+
+ void MutexInit(DDCallback *cb, DDMutex *m);
+ void MutexBeforeLock(DDCallback *cb, DDMutex *m, bool wlock);
+ void MutexAfterLock(DDCallback *cb, DDMutex *m, bool wlock, bool trylock);
+ void MutexBeforeUnlock(DDCallback *cb, DDMutex *m, bool wlock);
+ void MutexDestroy(DDCallback *cb, DDMutex *m);
+
+ DDReport *GetReport(DDCallback *cb);
+
+ void MutexEnsureID(DDLogicalThread *lt, DDMutex *m);
+ void ReportDeadlock(DDCallback *cb, DDMutex *m);
+};
+
+DDetector *DDetector::Create(const DDFlags *flags) {
+ (void)flags;
+ void *mem = MmapOrDie(sizeof(DD), "deadlock detector");
+ return new(mem) DD(flags);
+}
+
+DD::DD(const DDFlags *flags)
+ : flags(*flags) {
+ dd.clear();
+}
+
+DDPhysicalThread* DD::CreatePhysicalThread() {
+ return 0;
+}
+
+void DD::DestroyPhysicalThread(DDPhysicalThread *pt) {
+}
+
+DDLogicalThread* DD::CreateLogicalThread(u64 ctx) {
+ DDLogicalThread *lt = (DDLogicalThread*)InternalAlloc(sizeof(*lt));
+ lt->ctx = ctx;
+ lt->dd.clear();
+ lt->report_pending = false;
+ return lt;
+}
+
+void DD::DestroyLogicalThread(DDLogicalThread *lt) {
+ lt->~DDLogicalThread();
+ InternalFree(lt);
+}
+
+void DD::MutexInit(DDCallback *cb, DDMutex *m) {
+ m->id = 0;
+ m->stk = cb->Unwind();
+}
+
+void DD::MutexEnsureID(DDLogicalThread *lt, DDMutex *m) {
+ if (!dd.nodeBelongsToCurrentEpoch(m->id))
+ m->id = dd.newNode(reinterpret_cast<uptr>(m));
+ dd.ensureCurrentEpoch(&lt->dd);
+}
+
+void DD::MutexBeforeLock(DDCallback *cb,
+ DDMutex *m, bool wlock) {
+ DDLogicalThread *lt = cb->lt;
+ if (lt->dd.empty()) return; // This will be the first lock held by lt.
+ if (dd.hasAllEdges(&lt->dd, m->id)) return; // We already have all edges.
+ SpinMutexLock lk(&mtx);
+ MutexEnsureID(lt, m);
+ if (dd.isHeld(&lt->dd, m->id))
+ return; // FIXME: allow this only for recursive locks.
+ if (dd.onLockBefore(&lt->dd, m->id)) {
+ // Actually add this edge now so that we have all the stack traces.
+ dd.addEdges(&lt->dd, m->id, cb->Unwind(), cb->UniqueTid());
+ ReportDeadlock(cb, m);
+ }
+}
+
+void DD::ReportDeadlock(DDCallback *cb, DDMutex *m) {
+ DDLogicalThread *lt = cb->lt;
+ uptr path[10];
+ uptr len = dd.findPathToLock(&lt->dd, m->id, path, ARRAY_SIZE(path));
+ CHECK_GT(len, 0U); // Hm.. cycle of 10 locks? I'd like to see that.
+ CHECK_EQ(m->id, path[0]);
+ lt->report_pending = true;
+ DDReport *rep = &lt->rep;
+ rep->n = len;
+ for (uptr i = 0; i < len; i++) {
+ uptr from = path[i];
+ uptr to = path[(i + 1) % len];
+ DDMutex *m0 = (DDMutex*)dd.getData(from);
+ DDMutex *m1 = (DDMutex*)dd.getData(to);
+
+ u32 stk_from = -1U, stk_to = -1U;
+ int unique_tid = 0;
+ dd.findEdge(from, to, &stk_from, &stk_to, &unique_tid);
+ // Printf("Edge: %zd=>%zd: %u/%u T%d\n", from, to, stk_from, stk_to,
+ // unique_tid);
+ rep->loop[i].thr_ctx = unique_tid;
+ rep->loop[i].mtx_ctx0 = m0->ctx;
+ rep->loop[i].mtx_ctx1 = m1->ctx;
+ rep->loop[i].stk[0] = stk_to;
+ rep->loop[i].stk[1] = stk_from;
+ }
+}
+
+void DD::MutexAfterLock(DDCallback *cb, DDMutex *m, bool wlock, bool trylock) {
+ DDLogicalThread *lt = cb->lt;
+ u32 stk = 0;
+ if (flags.second_deadlock_stack)
+ stk = cb->Unwind();
+ // Printf("T%p MutexLock: %zx stk %u\n", lt, m->id, stk);
+ if (dd.onFirstLock(&lt->dd, m->id, stk))
+ return;
+ if (dd.onLockFast(&lt->dd, m->id, stk))
+ return;
+
+ SpinMutexLock lk(&mtx);
+ MutexEnsureID(lt, m);
+ if (wlock) // Only a recursive rlock may be held.
+ CHECK(!dd.isHeld(&lt->dd, m->id));
+ if (!trylock)
+ dd.addEdges(&lt->dd, m->id, stk ? stk : cb->Unwind(), cb->UniqueTid());
+ dd.onLockAfter(&lt->dd, m->id, stk);
+}
+
+void DD::MutexBeforeUnlock(DDCallback *cb, DDMutex *m, bool wlock) {
+ // Printf("T%p MutexUnLock: %zx\n", cb->lt, m->id);
+ dd.onUnlock(&cb->lt->dd, m->id);
+}
+
+void DD::MutexDestroy(DDCallback *cb,
+ DDMutex *m) {
+ if (!m->id) return;
+ SpinMutexLock lk(&mtx);
+ if (dd.nodeBelongsToCurrentEpoch(m->id))
+ dd.removeNode(m->id);
+ m->id = 0;
+}
+
+DDReport *DD::GetReport(DDCallback *cb) {
+ if (!cb->lt->report_pending)
+ return 0;
+ cb->lt->report_pending = false;
+ return &cb->lt->rep;
+}
+
+} // namespace __sanitizer
+#endif // #if SANITIZER_DEADLOCK_DETECTOR_VERSION == 1
diff --git a/lib/sanitizer_common/sanitizer_deadlock_detector2.cc b/lib/sanitizer_common/sanitizer_deadlock_detector2.cc
new file mode 100644
index 000000000000..87d4a4d9a838
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_deadlock_detector2.cc
@@ -0,0 +1,428 @@
+//===-- sanitizer_deadlock_detector2.cc -----------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Deadlock detector implementation based on adjacency lists.
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_deadlock_detector_interface.h"
+#include "sanitizer_common.h"
+#include "sanitizer_allocator_internal.h"
+#include "sanitizer_placement_new.h"
+#include "sanitizer_mutex.h"
+
+#if SANITIZER_DEADLOCK_DETECTOR_VERSION == 2
+
+namespace __sanitizer {
+
+const int kMaxNesting = 64;
+const u32 kNoId = -1;
+const u32 kEndId = -2;
+const int kMaxLink = 8;
+const int kL1Size = 1024;
+const int kL2Size = 1024;
+const int kMaxMutex = kL1Size * kL2Size;
+
+struct Id {
+ u32 id;
+ u32 seq;
+
+ explicit Id(u32 id = 0, u32 seq = 0)
+ : id(id)
+ , seq(seq) {
+ }
+};
+
+struct Link {
+ u32 id;
+ u32 seq;
+ u32 tid;
+ u32 stk0;
+ u32 stk1;
+
+ explicit Link(u32 id = 0, u32 seq = 0, u32 tid = 0, u32 s0 = 0, u32 s1 = 0)
+ : id(id)
+ , seq(seq)
+ , tid(tid)
+ , stk0(s0)
+ , stk1(s1) {
+ }
+};
+
+struct DDPhysicalThread {
+ DDReport rep;
+ bool report_pending;
+ bool visited[kMaxMutex];
+ Link pending[kMaxMutex];
+ Link path[kMaxMutex];
+};
+
+struct ThreadMutex {
+ u32 id;
+ u32 stk;
+};
+
+struct DDLogicalThread {
+ u64 ctx;
+ ThreadMutex locked[kMaxNesting];
+ int nlocked;
+};
+
+struct Mutex {
+ StaticSpinMutex mtx;
+ u32 seq;
+ int nlink;
+ Link link[kMaxLink];
+};
+
+struct DD : public DDetector {
+ explicit DD(const DDFlags *flags);
+
+ DDPhysicalThread* CreatePhysicalThread();
+ void DestroyPhysicalThread(DDPhysicalThread *pt);
+
+ DDLogicalThread* CreateLogicalThread(u64 ctx);
+ void DestroyLogicalThread(DDLogicalThread *lt);
+
+ void MutexInit(DDCallback *cb, DDMutex *m);
+ void MutexBeforeLock(DDCallback *cb, DDMutex *m, bool wlock);
+ void MutexAfterLock(DDCallback *cb, DDMutex *m, bool wlock,
+ bool trylock);
+ void MutexBeforeUnlock(DDCallback *cb, DDMutex *m, bool wlock);
+ void MutexDestroy(DDCallback *cb, DDMutex *m);
+
+ DDReport *GetReport(DDCallback *cb);
+
+ void CycleCheck(DDPhysicalThread *pt, DDLogicalThread *lt, DDMutex *mtx);
+ void Report(DDPhysicalThread *pt, DDLogicalThread *lt, int npath);
+ u32 allocateId(DDCallback *cb);
+ Mutex *getMutex(u32 id);
+ u32 getMutexId(Mutex *m);
+
+ DDFlags flags;
+
+ Mutex* mutex[kL1Size];
+
+ SpinMutex mtx;
+ InternalMmapVector<u32> free_id;
+ int id_gen;
+};
+
+DDetector *DDetector::Create(const DDFlags *flags) {
+ (void)flags;
+ void *mem = MmapOrDie(sizeof(DD), "deadlock detector");
+ return new(mem) DD(flags);
+}
+
+DD::DD(const DDFlags *flags)
+ : flags(*flags)
+ , free_id(1024) {
+ id_gen = 0;
+}
+
+DDPhysicalThread* DD::CreatePhysicalThread() {
+ DDPhysicalThread *pt = (DDPhysicalThread*)MmapOrDie(sizeof(DDPhysicalThread),
+ "deadlock detector (physical thread)");
+ return pt;
+}
+
+void DD::DestroyPhysicalThread(DDPhysicalThread *pt) {
+ pt->~DDPhysicalThread();
+ UnmapOrDie(pt, sizeof(DDPhysicalThread));
+}
+
+DDLogicalThread* DD::CreateLogicalThread(u64 ctx) {
+ DDLogicalThread *lt = (DDLogicalThread*)InternalAlloc(
+ sizeof(DDLogicalThread));
+ lt->ctx = ctx;
+ lt->nlocked = 0;
+ return lt;
+}
+
+void DD::DestroyLogicalThread(DDLogicalThread *lt) {
+ lt->~DDLogicalThread();
+ InternalFree(lt);
+}
+
+void DD::MutexInit(DDCallback *cb, DDMutex *m) {
+ VPrintf(2, "#%llu: DD::MutexInit(%p)\n", cb->lt->ctx, m);
+ m->id = kNoId;
+ m->recursion = 0;
+ atomic_store(&m->owner, 0, memory_order_relaxed);
+}
+
+Mutex *DD::getMutex(u32 id) {
+ return &mutex[id / kL2Size][id % kL2Size];
+}
+
+u32 DD::getMutexId(Mutex *m) {
+ for (int i = 0; i < kL1Size; i++) {
+ Mutex *tab = mutex[i];
+ if (tab == 0)
+ break;
+ if (m >= tab && m < tab + kL2Size)
+ return i * kL2Size + (m - tab);
+ }
+ return -1;
+}
+
+u32 DD::allocateId(DDCallback *cb) {
+ u32 id = -1;
+ SpinMutexLock l(&mtx);
+ if (free_id.size() > 0) {
+ id = free_id.back();
+ free_id.pop_back();
+ } else {
+ CHECK_LT(id_gen, kMaxMutex);
+ if ((id_gen % kL2Size) == 0) {
+ mutex[id_gen / kL2Size] = (Mutex*)MmapOrDie(kL2Size * sizeof(Mutex),
+ "deadlock detector (mutex table)");
+ }
+ id = id_gen++;
+ }
+ CHECK_LE(id, kMaxMutex);
+ VPrintf(3, "#%llu: DD::allocateId assign id %d\n", cb->lt->ctx, id);
+ return id;
+}
+
+void DD::MutexBeforeLock(DDCallback *cb, DDMutex *m, bool wlock) {
+ VPrintf(2, "#%llu: DD::MutexBeforeLock(%p, wlock=%d) nlocked=%d\n",
+ cb->lt->ctx, m, wlock, cb->lt->nlocked);
+ DDPhysicalThread *pt = cb->pt;
+ DDLogicalThread *lt = cb->lt;
+
+ uptr owner = atomic_load(&m->owner, memory_order_relaxed);
+ if (owner == (uptr)cb->lt) {
+ VPrintf(3, "#%llu: DD::MutexBeforeLock recursive\n",
+ cb->lt->ctx);
+ return;
+ }
+
+ CHECK_LE(lt->nlocked, kMaxNesting);
+
+ // FIXME(dvyukov): don't allocate id if lt->nlocked == 0?
+ if (m->id == kNoId)
+ m->id = allocateId(cb);
+
+ ThreadMutex *tm = &lt->locked[lt->nlocked++];
+ tm->id = m->id;
+ if (flags.second_deadlock_stack)
+ tm->stk = cb->Unwind();
+ if (lt->nlocked == 1) {
+ VPrintf(3, "#%llu: DD::MutexBeforeLock first mutex\n",
+ cb->lt->ctx);
+ return;
+ }
+
+ bool added = false;
+ Mutex *mtx = getMutex(m->id);
+ for (int i = 0; i < lt->nlocked - 1; i++) {
+ u32 id1 = lt->locked[i].id;
+ u32 stk1 = lt->locked[i].stk;
+ Mutex *mtx1 = getMutex(id1);
+ SpinMutexLock l(&mtx1->mtx);
+ if (mtx1->nlink == kMaxLink) {
+ // FIXME(dvyukov): check stale links
+ continue;
+ }
+ int li = 0;
+ for (; li < mtx1->nlink; li++) {
+ Link *link = &mtx1->link[li];
+ if (link->id == m->id) {
+ if (link->seq != mtx->seq) {
+ link->seq = mtx->seq;
+ link->tid = lt->ctx;
+ link->stk0 = stk1;
+ link->stk1 = cb->Unwind();
+ added = true;
+ VPrintf(3, "#%llu: DD::MutexBeforeLock added %d->%d link\n",
+ cb->lt->ctx, getMutexId(mtx1), m->id);
+ }
+ break;
+ }
+ }
+ if (li == mtx1->nlink) {
+ // FIXME(dvyukov): check stale links
+ Link *link = &mtx1->link[mtx1->nlink++];
+ link->id = m->id;
+ link->seq = mtx->seq;
+ link->tid = lt->ctx;
+ link->stk0 = stk1;
+ link->stk1 = cb->Unwind();
+ added = true;
+ VPrintf(3, "#%llu: DD::MutexBeforeLock added %d->%d link\n",
+ cb->lt->ctx, getMutexId(mtx1), m->id);
+ }
+ }
+
+ if (!added || mtx->nlink == 0) {
+ VPrintf(3, "#%llu: DD::MutexBeforeLock don't check\n",
+ cb->lt->ctx);
+ return;
+ }
+
+ CycleCheck(pt, lt, m);
+}
+
+void DD::MutexAfterLock(DDCallback *cb, DDMutex *m, bool wlock,
+ bool trylock) {
+ VPrintf(2, "#%llu: DD::MutexAfterLock(%p, wlock=%d, try=%d) nlocked=%d\n",
+ cb->lt->ctx, m, wlock, trylock, cb->lt->nlocked);
+ DDLogicalThread *lt = cb->lt;
+
+ uptr owner = atomic_load(&m->owner, memory_order_relaxed);
+ if (owner == (uptr)cb->lt) {
+ VPrintf(3, "#%llu: DD::MutexAfterLock recursive\n", cb->lt->ctx);
+ CHECK(wlock);
+ m->recursion++;
+ return;
+ }
+ CHECK_EQ(owner, 0);
+ if (wlock) {
+ VPrintf(3, "#%llu: DD::MutexAfterLock set owner\n", cb->lt->ctx);
+ CHECK_EQ(m->recursion, 0);
+ m->recursion = 1;
+ atomic_store(&m->owner, (uptr)cb->lt, memory_order_relaxed);
+ }
+
+ if (!trylock)
+ return;
+
+ CHECK_LE(lt->nlocked, kMaxNesting);
+ if (m->id == kNoId)
+ m->id = allocateId(cb);
+ ThreadMutex *tm = &lt->locked[lt->nlocked++];
+ tm->id = m->id;
+ if (flags.second_deadlock_stack)
+ tm->stk = cb->Unwind();
+}
+
+void DD::MutexBeforeUnlock(DDCallback *cb, DDMutex *m, bool wlock) {
+ VPrintf(2, "#%llu: DD::MutexBeforeUnlock(%p, wlock=%d) nlocked=%d\n",
+ cb->lt->ctx, m, wlock, cb->lt->nlocked);
+ DDLogicalThread *lt = cb->lt;
+
+ uptr owner = atomic_load(&m->owner, memory_order_relaxed);
+ if (owner == (uptr)cb->lt) {
+ VPrintf(3, "#%llu: DD::MutexBeforeUnlock recursive\n", cb->lt->ctx);
+ if (--m->recursion > 0)
+ return;
+ VPrintf(3, "#%llu: DD::MutexBeforeUnlock reset owner\n", cb->lt->ctx);
+ atomic_store(&m->owner, 0, memory_order_relaxed);
+ }
+ CHECK_NE(m->id, kNoId);
+ int last = lt->nlocked - 1;
+ for (int i = last; i >= 0; i--) {
+ if (cb->lt->locked[i].id == m->id) {
+ lt->locked[i] = lt->locked[last];
+ lt->nlocked--;
+ break;
+ }
+ }
+}
+
+void DD::MutexDestroy(DDCallback *cb, DDMutex *m) {
+ VPrintf(2, "#%llu: DD::MutexDestroy(%p)\n",
+ cb->lt->ctx, m);
+ DDLogicalThread *lt = cb->lt;
+
+ if (m->id == kNoId)
+ return;
+
+ // Remove the mutex from lt->locked if there.
+ int last = lt->nlocked - 1;
+ for (int i = last; i >= 0; i--) {
+ if (lt->locked[i].id == m->id) {
+ lt->locked[i] = lt->locked[last];
+ lt->nlocked--;
+ break;
+ }
+ }
+
+ // Clear and invalidate the mutex descriptor.
+ {
+ Mutex *mtx = getMutex(m->id);
+ SpinMutexLock l(&mtx->mtx);
+ mtx->seq++;
+ mtx->nlink = 0;
+ }
+
+ // Return id to cache.
+ {
+ SpinMutexLock l(&mtx);
+ free_id.push_back(m->id);
+ }
+}
+
+void DD::CycleCheck(DDPhysicalThread *pt, DDLogicalThread *lt,
+ DDMutex *m) {
+ internal_memset(pt->visited, 0, sizeof(pt->visited));
+ int npath = 0;
+ int npending = 0;
+ {
+ Mutex *mtx = getMutex(m->id);
+ SpinMutexLock l(&mtx->mtx);
+ for (int li = 0; li < mtx->nlink; li++)
+ pt->pending[npending++] = mtx->link[li];
+ }
+ while (npending > 0) {
+ Link link = pt->pending[--npending];
+ if (link.id == kEndId) {
+ npath--;
+ continue;
+ }
+ if (pt->visited[link.id])
+ continue;
+ Mutex *mtx1 = getMutex(link.id);
+ SpinMutexLock l(&mtx1->mtx);
+ if (mtx1->seq != link.seq)
+ continue;
+ pt->visited[link.id] = true;
+ if (mtx1->nlink == 0)
+ continue;
+ pt->path[npath++] = link;
+ pt->pending[npending++] = Link(kEndId);
+ if (link.id == m->id)
+ return Report(pt, lt, npath); // Bingo!
+ for (int li = 0; li < mtx1->nlink; li++) {
+ Link *link1 = &mtx1->link[li];
+ // Mutex *mtx2 = getMutex(link->id);
+ // FIXME(dvyukov): fast seq check
+ // FIXME(dvyukov): fast nlink != 0 check
+ // FIXME(dvyukov): fast pending check?
+ // FIXME(dvyukov): npending can be larger than kMaxMutex
+ pt->pending[npending++] = *link1;
+ }
+ }
+}
+
+void DD::Report(DDPhysicalThread *pt, DDLogicalThread *lt, int npath) {
+ DDReport *rep = &pt->rep;
+ rep->n = npath;
+ for (int i = 0; i < npath; i++) {
+ Link *link = &pt->path[i];
+ Link *link0 = &pt->path[i ? i - 1 : npath - 1];
+ rep->loop[i].thr_ctx = link->tid;
+ rep->loop[i].mtx_ctx0 = link0->id;
+ rep->loop[i].mtx_ctx1 = link->id;
+ rep->loop[i].stk[0] = flags.second_deadlock_stack ? link->stk0 : 0;
+ rep->loop[i].stk[1] = link->stk1;
+ }
+ pt->report_pending = true;
+}
+
+DDReport *DD::GetReport(DDCallback *cb) {
+ if (!cb->pt->report_pending)
+ return 0;
+ cb->pt->report_pending = false;
+ return &cb->pt->rep;
+}
+
+} // namespace __sanitizer
+#endif // #if SANITIZER_DEADLOCK_DETECTOR_VERSION == 2
diff --git a/lib/sanitizer_common/sanitizer_deadlock_detector_interface.h b/lib/sanitizer_common/sanitizer_deadlock_detector_interface.h
new file mode 100644
index 000000000000..8cf26e0d5528
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_deadlock_detector_interface.h
@@ -0,0 +1,93 @@
+//===-- sanitizer_deadlock_detector_interface.h -----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of Sanitizer runtime.
+// Abstract deadlock detector interface.
+// FIXME: this is work in progress, nothing really works yet.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_DEADLOCK_DETECTOR_INTERFACE_H
+#define SANITIZER_DEADLOCK_DETECTOR_INTERFACE_H
+
+#ifndef SANITIZER_DEADLOCK_DETECTOR_VERSION
+# define SANITIZER_DEADLOCK_DETECTOR_VERSION 1
+#endif
+
+#include "sanitizer_internal_defs.h"
+#include "sanitizer_atomic.h"
+
+namespace __sanitizer {
+
+// dd - deadlock detector.
+// lt - logical (user) thread.
+// pt - physical (OS) thread.
+
+struct DDPhysicalThread;
+struct DDLogicalThread;
+
+struct DDMutex {
+#if SANITIZER_DEADLOCK_DETECTOR_VERSION == 1
+ uptr id;
+ u32 stk; // creation stack
+#elif SANITIZER_DEADLOCK_DETECTOR_VERSION == 2
+ u32 id;
+ u32 recursion;
+ atomic_uintptr_t owner;
+#else
+# error "BAD SANITIZER_DEADLOCK_DETECTOR_VERSION"
+#endif
+ u64 ctx;
+};
+
+struct DDFlags {
+ bool second_deadlock_stack;
+};
+
+struct DDReport {
+ enum { kMaxLoopSize = 8 };
+ int n; // number of entries in loop
+ struct {
+ u64 thr_ctx; // user thread context
+ u64 mtx_ctx0; // user mutex context, start of the edge
+ u64 mtx_ctx1; // user mutex context, end of the edge
+ u32 stk[2]; // stack ids for the edge
+ } loop[kMaxLoopSize];
+};
+
+struct DDCallback {
+ DDPhysicalThread *pt;
+ DDLogicalThread *lt;
+
+ virtual u32 Unwind() { return 0; }
+ virtual int UniqueTid() { return 0; }
+};
+
+struct DDetector {
+ static DDetector *Create(const DDFlags *flags);
+
+ virtual DDPhysicalThread* CreatePhysicalThread() { return 0; }
+ virtual void DestroyPhysicalThread(DDPhysicalThread *pt) {}
+
+ virtual DDLogicalThread* CreateLogicalThread(u64 ctx) { return 0; }
+ virtual void DestroyLogicalThread(DDLogicalThread *lt) {}
+
+ virtual void MutexInit(DDCallback *cb, DDMutex *m) {}
+ virtual void MutexBeforeLock(DDCallback *cb, DDMutex *m, bool wlock) {}
+ virtual void MutexAfterLock(DDCallback *cb, DDMutex *m, bool wlock,
+ bool trylock) {}
+ virtual void MutexBeforeUnlock(DDCallback *cb, DDMutex *m, bool wlock) {}
+ virtual void MutexDestroy(DDCallback *cb, DDMutex *m) {}
+
+ virtual DDReport *GetReport(DDCallback *cb) { return 0; }
+};
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_DEADLOCK_DETECTOR_INTERFACE_H
diff --git a/lib/sanitizer_common/sanitizer_flags.cc b/lib/sanitizer_common/sanitizer_flags.cc
index 924ed4bc014f..40b6ec067150 100644
--- a/lib/sanitizer_common/sanitizer_flags.cc
+++ b/lib/sanitizer_common/sanitizer_flags.cc
@@ -15,41 +15,157 @@
#include "sanitizer_common.h"
#include "sanitizer_libc.h"
+#include "sanitizer_list.h"
namespace __sanitizer {
-void SetCommonFlagDefaults() {
- CommonFlags *f = common_flags();
+CommonFlags common_flags_dont_use;
+
+struct FlagDescription {
+ const char *name;
+ const char *description;
+ FlagDescription *next;
+};
+
+IntrusiveList<FlagDescription> flag_descriptions;
+
+// If set, the tool will install its own SEGV signal handler by default.
+#ifndef SANITIZER_NEEDS_SEGV
+# define SANITIZER_NEEDS_SEGV 1
+#endif
+
+void SetCommonFlagsDefaults(CommonFlags *f) {
f->symbolize = true;
- f->external_symbolizer_path = "";
+ f->external_symbolizer_path = 0;
+ f->allow_addr2line = false;
f->strip_path_prefix = "";
+ f->fast_unwind_on_check = false;
f->fast_unwind_on_fatal = false;
f->fast_unwind_on_malloc = true;
f->handle_ioctl = false;
f->malloc_context_size = 1;
f->log_path = "stderr";
f->verbosity = 0;
- f->detect_leaks = false;
+ f->detect_leaks = true;
f->leak_check_at_exit = true;
f->allocator_may_return_null = false;
f->print_summary = true;
+ f->check_printf = true;
+ // TODO(glider): tools may want to set different defaults for handle_segv.
+ f->handle_segv = SANITIZER_NEEDS_SEGV;
+ f->allow_user_segv_handler = false;
+ f->use_sigaltstack = true;
+ f->detect_deadlocks = false;
+ f->clear_shadow_mmap_threshold = 64 * 1024;
+ f->color = "auto";
+ f->legacy_pthread_cond = false;
+ f->intercept_tls_get_addr = false;
+ f->coverage = false;
+ f->coverage_direct = SANITIZER_ANDROID;
+ f->coverage_dir = ".";
+ f->full_address_space = false;
+ f->suppressions = "";
+ f->print_suppressions = true;
+ f->disable_coredump = (SANITIZER_WORDSIZE == 64);
+ f->symbolize_inline_frames = true;
+ f->stack_trace_format = "DEFAULT";
}
-void ParseCommonFlagsFromString(const char *str) {
- CommonFlags *f = common_flags();
- ParseFlag(str, &f->symbolize, "symbolize");
- ParseFlag(str, &f->external_symbolizer_path, "external_symbolizer_path");
- ParseFlag(str, &f->strip_path_prefix, "strip_path_prefix");
- ParseFlag(str, &f->fast_unwind_on_fatal, "fast_unwind_on_fatal");
- ParseFlag(str, &f->fast_unwind_on_malloc, "fast_unwind_on_malloc");
- ParseFlag(str, &f->handle_ioctl, "handle_ioctl");
- ParseFlag(str, &f->malloc_context_size, "malloc_context_size");
- ParseFlag(str, &f->log_path, "log_path");
- ParseFlag(str, &f->verbosity, "verbosity");
- ParseFlag(str, &f->detect_leaks, "detect_leaks");
- ParseFlag(str, &f->leak_check_at_exit, "leak_check_at_exit");
- ParseFlag(str, &f->allocator_may_return_null, "allocator_may_return_null");
- ParseFlag(str, &f->print_summary, "print_summary");
+void ParseCommonFlagsFromString(CommonFlags *f, const char *str) {
+ ParseFlag(str, &f->symbolize, "symbolize",
+ "If set, use the online symbolizer from common sanitizer runtime to turn "
+ "virtual addresses to file/line locations.");
+ ParseFlag(str, &f->external_symbolizer_path, "external_symbolizer_path",
+ "Path to external symbolizer. If empty, the tool will search $PATH for "
+ "the symbolizer.");
+ ParseFlag(str, &f->allow_addr2line, "allow_addr2line",
+ "If set, allows online symbolizer to run addr2line binary to symbolize "
+ "stack traces (addr2line will only be used if llvm-symbolizer binary is "
+ "unavailable.");
+ ParseFlag(str, &f->strip_path_prefix, "strip_path_prefix",
+ "Strips this prefix from file paths in error reports.");
+ ParseFlag(str, &f->fast_unwind_on_check, "fast_unwind_on_check",
+ "If available, use the fast frame-pointer-based unwinder on "
+ "internal CHECK failures.");
+ ParseFlag(str, &f->fast_unwind_on_fatal, "fast_unwind_on_fatal",
+ "If available, use the fast frame-pointer-based unwinder on fatal "
+ "errors.");
+ ParseFlag(str, &f->fast_unwind_on_malloc, "fast_unwind_on_malloc",
+ "If available, use the fast frame-pointer-based unwinder on "
+ "malloc/free.");
+ ParseFlag(str, &f->handle_ioctl, "handle_ioctl",
+ "Intercept and handle ioctl requests.");
+ ParseFlag(str, &f->malloc_context_size, "malloc_context_size",
+ "Max number of stack frames kept for each allocation/deallocation.");
+ ParseFlag(str, &f->log_path, "log_path",
+ "Write logs to \"log_path.pid\". The special values are \"stdout\" and "
+ "\"stderr\". The default is \"stderr\".");
+ ParseFlag(str, &f->verbosity, "verbosity",
+ "Verbosity level (0 - silent, 1 - a bit of output, 2+ - more output).");
+ ParseFlag(str, &f->detect_leaks, "detect_leaks",
+ "Enable memory leak detection.");
+ ParseFlag(str, &f->leak_check_at_exit, "leak_check_at_exit",
+ "Invoke leak checking in an atexit handler. Has no effect if "
+ "detect_leaks=false, or if __lsan_do_leak_check() is called before the "
+ "handler has a chance to run.");
+ ParseFlag(str, &f->allocator_may_return_null, "allocator_may_return_null",
+ "If false, the allocator will crash instead of returning 0 on "
+ "out-of-memory.");
+ ParseFlag(str, &f->print_summary, "print_summary",
+ "If false, disable printing error summaries in addition to error "
+ "reports.");
+ ParseFlag(str, &f->check_printf, "check_printf",
+ "Check printf arguments.");
+ ParseFlag(str, &f->handle_segv, "handle_segv",
+ "If set, registers the tool's custom SEGV handler (both SIGBUS and "
+ "SIGSEGV on OSX).");
+ ParseFlag(str, &f->allow_user_segv_handler, "allow_user_segv_handler",
+ "If set, allows user to register a SEGV handler even if the tool "
+ "registers one.");
+ ParseFlag(str, &f->use_sigaltstack, "use_sigaltstack",
+ "If set, uses alternate stack for signal handling.");
+ ParseFlag(str, &f->detect_deadlocks, "detect_deadlocks",
+ "If set, deadlock detection is enabled.");
+ ParseFlag(str, &f->clear_shadow_mmap_threshold,
+ "clear_shadow_mmap_threshold",
+ "Large shadow regions are zero-filled using mmap(NORESERVE) instead of "
+ "memset(). This is the threshold size in bytes.");
+ ParseFlag(str, &f->color, "color",
+ "Colorize reports: (always|never|auto).");
+ ParseFlag(str, &f->legacy_pthread_cond, "legacy_pthread_cond",
+ "Enables support for dynamic libraries linked with libpthread 2.2.5.");
+ ParseFlag(str, &f->intercept_tls_get_addr, "intercept_tls_get_addr",
+ "Intercept __tls_get_addr.");
+ ParseFlag(str, &f->help, "help", "Print the flag descriptions.");
+ ParseFlag(str, &f->mmap_limit_mb, "mmap_limit_mb",
+ "Limit the amount of mmap-ed memory (excluding shadow) in Mb; "
+ "not a user-facing flag, used mosly for testing the tools");
+ ParseFlag(str, &f->coverage, "coverage",
+ "If set, coverage information will be dumped at program shutdown (if the "
+ "coverage instrumentation was enabled at compile time).");
+ ParseFlag(str, &f->coverage_direct, "coverage_direct",
+ "If set, coverage information will be dumped directly to a memory "
+ "mapped file. This way data is not lost even if the process is "
+ "suddenly killed.");
+ ParseFlag(str, &f->coverage_dir, "coverage_dir",
+ "Target directory for coverage dumps. Defaults to the current "
+ "directory.");
+ ParseFlag(str, &f->full_address_space, "full_address_space",
+ "Sanitize complete address space; "
+ "by default kernel area on 32-bit platforms will not be sanitized");
+ ParseFlag(str, &f->suppressions, "suppressions", "Suppressions file name.");
+ ParseFlag(str, &f->print_suppressions, "print_suppressions",
+ "Print matched suppressions at exit.");
+ ParseFlag(str, &f->disable_coredump, "disable_coredump",
+ "Disable core dumping. By default, disable_core=1 on 64-bit to avoid "
+ "dumping a 16T+ core file. Ignored on OSes that don't dump core by"
+ "default and for sanitizers that don't reserve lots of virtual memory.");
+ ParseFlag(str, &f->symbolize_inline_frames, "symbolize_inline_frames",
+ "Print inlined frames in stacktraces. Defaults to true.");
+ ParseFlag(str, &f->stack_trace_format, "stack_trace_format",
+ "Format string used to render stack frames. "
+ "See sanitizer_stacktrace_printer.h for the format description. "
+ "Use DEFAULT to get default format.");
// Do a sanity check for certain flags.
if (f->malloc_context_size < 1)
@@ -65,14 +181,17 @@ static bool GetFlagValue(const char *env, const char *name,
pos = internal_strstr(env, name);
if (pos == 0)
return false;
- if (pos != env && ((pos[-1] >= 'a' && pos[-1] <= 'z') || pos[-1] == '_')) {
+ const char *name_end = pos + internal_strlen(name);
+ if ((pos != env &&
+ ((pos[-1] >= 'a' && pos[-1] <= 'z') || pos[-1] == '_')) ||
+ *name_end != '=') {
// Seems to be middle of another flag name or value.
env = pos + 1;
continue;
}
+ pos = name_end;
break;
}
- pos += internal_strlen(name);
const char *end;
if (pos[0] != '=') {
end = pos;
@@ -104,9 +223,40 @@ static bool StartsWith(const char *flag, int flag_length, const char *value) {
(0 == internal_strncmp(flag, value, value_length));
}
-void ParseFlag(const char *env, bool *flag, const char *name) {
+static LowLevelAllocator allocator_for_flags;
+
+// The linear scan is suboptimal, but the number of flags is relatively small.
+bool FlagInDescriptionList(const char *name) {
+ IntrusiveList<FlagDescription>::Iterator it(&flag_descriptions);
+ while (it.hasNext()) {
+ if (!internal_strcmp(it.next()->name, name)) return true;
+ }
+ return false;
+}
+
+void AddFlagDescription(const char *name, const char *description) {
+ if (FlagInDescriptionList(name)) return;
+ FlagDescription *new_description = new(allocator_for_flags) FlagDescription;
+ new_description->name = name;
+ new_description->description = description;
+ flag_descriptions.push_back(new_description);
+}
+
+// TODO(glider): put the descriptions inside CommonFlags.
+void PrintFlagDescriptions() {
+ IntrusiveList<FlagDescription>::Iterator it(&flag_descriptions);
+ Printf("Available flags for %s:\n", SanitizerToolName);
+ while (it.hasNext()) {
+ FlagDescription *descr = it.next();
+ Printf("\t%s\n\t\t- %s\n", descr->name, descr->description);
+ }
+}
+
+void ParseFlag(const char *env, bool *flag,
+ const char *name, const char *descr) {
const char *value;
int value_length;
+ AddFlagDescription(name, descr);
if (!GetFlagValue(env, name, &value, &value_length))
return;
if (StartsWith(value, value_length, "0") ||
@@ -119,19 +269,31 @@ void ParseFlag(const char *env, bool *flag, const char *name) {
*flag = true;
}
-void ParseFlag(const char *env, int *flag, const char *name) {
+void ParseFlag(const char *env, int *flag,
+ const char *name, const char *descr) {
const char *value;
int value_length;
+ AddFlagDescription(name, descr);
if (!GetFlagValue(env, name, &value, &value_length))
return;
*flag = static_cast<int>(internal_atoll(value));
}
-static LowLevelAllocator allocator_for_flags;
+void ParseFlag(const char *env, uptr *flag,
+ const char *name, const char *descr) {
+ const char *value;
+ int value_length;
+ AddFlagDescription(name, descr);
+ if (!GetFlagValue(env, name, &value, &value_length))
+ return;
+ *flag = static_cast<uptr>(internal_atoll(value));
+}
-void ParseFlag(const char *env, const char **flag, const char *name) {
+void ParseFlag(const char *env, const char **flag,
+ const char *name, const char *descr) {
const char *value;
int value_length;
+ AddFlagDescription(name, descr);
if (!GetFlagValue(env, name, &value, &value_length))
return;
// Copy the flag value. Don't use locks here, as flags are parsed at
diff --git a/lib/sanitizer_common/sanitizer_flags.h b/lib/sanitizer_common/sanitizer_flags.h
index 9461dff80330..4791397a5761 100644
--- a/lib/sanitizer_common/sanitizer_flags.h
+++ b/lib/sanitizer_common/sanitizer_flags.h
@@ -18,50 +18,61 @@
namespace __sanitizer {
-void ParseFlag(const char *env, bool *flag, const char *name);
-void ParseFlag(const char *env, int *flag, const char *name);
-void ParseFlag(const char *env, const char **flag, const char *name);
+void ParseFlag(const char *env, bool *flag,
+ const char *name, const char *descr);
+void ParseFlag(const char *env, int *flag,
+ const char *name, const char *descr);
+void ParseFlag(const char *env, uptr *flag,
+ const char *name, const char *descr);
+void ParseFlag(const char *env, const char **flag,
+ const char *name, const char *descr);
struct CommonFlags {
- // If set, use the online symbolizer from common sanitizer runtime.
bool symbolize;
- // Path to external symbolizer.
const char *external_symbolizer_path;
- // Strips this prefix from file paths in error reports.
+ bool allow_addr2line;
const char *strip_path_prefix;
- // Use fast (frame-pointer-based) unwinder on fatal errors (if available).
+ bool fast_unwind_on_check;
bool fast_unwind_on_fatal;
- // Use fast (frame-pointer-based) unwinder on malloc/free (if available).
bool fast_unwind_on_malloc;
- // Intercept and handle ioctl requests.
bool handle_ioctl;
- // Max number of stack frames kept for each allocation/deallocation.
int malloc_context_size;
- // Write logs to "log_path.pid".
- // The special values are "stdout" and "stderr".
- // The default is "stderr".
const char *log_path;
- // Verbosity level (0 - silent, 1 - a bit of output, 2+ - more output).
int verbosity;
- // Enable memory leak detection.
bool detect_leaks;
- // Invoke leak checking in an atexit handler. Has no effect if
- // detect_leaks=false, or if __lsan_do_leak_check() is called before the
- // handler has a chance to run.
bool leak_check_at_exit;
- // If false, the allocator will crash instead of returning 0 on out-of-memory.
bool allocator_may_return_null;
- // If false, disable printing error summaries in addition to error reports.
bool print_summary;
+ bool check_printf;
+ bool handle_segv;
+ bool allow_user_segv_handler;
+ bool use_sigaltstack;
+ bool detect_deadlocks;
+ uptr clear_shadow_mmap_threshold;
+ const char *color;
+ bool legacy_pthread_cond;
+ bool intercept_tls_get_addr;
+ bool help;
+ uptr mmap_limit_mb;
+ bool coverage;
+ bool coverage_direct;
+ const char *coverage_dir;
+ bool full_address_space;
+ const char *suppressions;
+ bool print_suppressions;
+ bool disable_coredump;
+ bool symbolize_inline_frames;
+ const char *stack_trace_format;
};
inline CommonFlags *common_flags() {
- static CommonFlags f;
- return &f;
+ extern CommonFlags common_flags_dont_use;
+ return &common_flags_dont_use;
}
-void SetCommonFlagDefaults();
-void ParseCommonFlagsFromString(const char *str);
+void SetCommonFlagsDefaults(CommonFlags *f);
+void ParseCommonFlagsFromString(CommonFlags *f, const char *str);
+void PrintFlagDescriptions();
} // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_freebsd.h b/lib/sanitizer_common/sanitizer_freebsd.h
new file mode 100644
index 000000000000..c9bba8064af0
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_freebsd.h
@@ -0,0 +1,137 @@
+//===-- sanitizer_freebsd.h -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of Sanitizer runtime. It contains FreeBSD-specific
+// definitions.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_FREEBSD_H
+#define SANITIZER_FREEBSD_H
+
+#include "sanitizer_internal_defs.h"
+
+// x86-64 FreeBSD 9.2 and older define 'ucontext_t' incorrectly in
+// 32-bit mode.
+#if SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32)
+# include <osreldate.h>
+# if __FreeBSD_version <= 902001 // v9.2
+# include <link.h>
+# include <sys/param.h>
+# include <ucontext.h>
+
+namespace __sanitizer {
+
+typedef unsigned long long __xuint64_t;
+
+typedef __int32_t __xregister_t;
+
+typedef struct __xmcontext {
+ __xregister_t mc_onstack;
+ __xregister_t mc_gs;
+ __xregister_t mc_fs;
+ __xregister_t mc_es;
+ __xregister_t mc_ds;
+ __xregister_t mc_edi;
+ __xregister_t mc_esi;
+ __xregister_t mc_ebp;
+ __xregister_t mc_isp;
+ __xregister_t mc_ebx;
+ __xregister_t mc_edx;
+ __xregister_t mc_ecx;
+ __xregister_t mc_eax;
+ __xregister_t mc_trapno;
+ __xregister_t mc_err;
+ __xregister_t mc_eip;
+ __xregister_t mc_cs;
+ __xregister_t mc_eflags;
+ __xregister_t mc_esp;
+ __xregister_t mc_ss;
+
+ int mc_len;
+ int mc_fpformat;
+ int mc_ownedfp;
+ __xregister_t mc_flags;
+
+ int mc_fpstate[128] __aligned(16);
+ __xregister_t mc_fsbase;
+ __xregister_t mc_gsbase;
+ __xregister_t mc_xfpustate;
+ __xregister_t mc_xfpustate_len;
+
+ int mc_spare2[4];
+} xmcontext_t;
+
+typedef struct __xucontext {
+ sigset_t uc_sigmask;
+ xmcontext_t uc_mcontext;
+
+ struct __ucontext *uc_link;
+ stack_t uc_stack;
+ int uc_flags;
+ int __spare__[4];
+} xucontext_t;
+
+struct xkinfo_vmentry {
+ int kve_structsize;
+ int kve_type;
+ __xuint64_t kve_start;
+ __xuint64_t kve_end;
+ __xuint64_t kve_offset;
+ __xuint64_t kve_vn_fileid;
+ __uint32_t kve_vn_fsid;
+ int kve_flags;
+ int kve_resident;
+ int kve_private_resident;
+ int kve_protection;
+ int kve_ref_count;
+ int kve_shadow_count;
+ int kve_vn_type;
+ __xuint64_t kve_vn_size;
+ __uint32_t kve_vn_rdev;
+ __uint16_t kve_vn_mode;
+ __uint16_t kve_status;
+ int _kve_ispare[12];
+ char kve_path[PATH_MAX];
+};
+
+typedef struct {
+ __uint32_t p_type;
+ __uint32_t p_offset;
+ __uint32_t p_vaddr;
+ __uint32_t p_paddr;
+ __uint32_t p_filesz;
+ __uint32_t p_memsz;
+ __uint32_t p_flags;
+ __uint32_t p_align;
+} XElf32_Phdr;
+
+struct xdl_phdr_info {
+ Elf_Addr dlpi_addr;
+ const char *dlpi_name;
+ const XElf32_Phdr *dlpi_phdr;
+ Elf_Half dlpi_phnum;
+ unsigned long long int dlpi_adds;
+ unsigned long long int dlpi_subs;
+ size_t dlpi_tls_modid;
+ void *dlpi_tls_data;
+};
+
+typedef int (*__xdl_iterate_hdr_callback)(struct xdl_phdr_info*, size_t, void*);
+typedef int xdl_iterate_phdr_t(__xdl_iterate_hdr_callback, void*);
+
+#define xdl_iterate_phdr(callback, param) \
+ (((xdl_iterate_phdr_t*) dl_iterate_phdr)((callback), (param)))
+
+} // namespace __sanitizer
+
+# endif // __FreeBSD_version <= 902001
+#endif // SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32)
+
+#endif // SANITIZER_FREEBSD_H
diff --git a/lib/sanitizer_common/sanitizer_internal_defs.h b/lib/sanitizer_common/sanitizer_internal_defs.h
index daa724be06f1..97eef744bd14 100644
--- a/lib/sanitizer_common/sanitizer_internal_defs.h
+++ b/lib/sanitizer_common/sanitizer_internal_defs.h
@@ -34,10 +34,13 @@
# define SANITIZER_SUPPORTS_WEAK_HOOKS 0
#endif
-#if __LP64__ || defined(_WIN64)
-# define SANITIZER_WORDSIZE 64
+// We can use .preinit_array section on Linux to call sanitizer initialization
+// functions very early in the process startup (unless PIC macro is defined).
+// FIXME: do we have anything like this on Mac?
+#if SANITIZER_LINUX && !SANITIZER_ANDROID && !defined(PIC)
+# define SANITIZER_CAN_USE_PREINIT_ARRAY 1
#else
-# define SANITIZER_WORDSIZE 32
+# define SANITIZER_CAN_USE_PREINIT_ARRAY 0
#endif
// GCC does not understand __has_feature
@@ -59,7 +62,7 @@ typedef unsigned long uptr; // NOLINT
typedef signed long sptr; // NOLINT
#endif // defined(_WIN64)
#if defined(__x86_64__)
-// Since x32 uses ILP32 data model in 64-bit hardware mode, we must use
+// Since x32 uses ILP32 data model in 64-bit hardware mode, we must use
// 64-bit pointer to unwind stack frame.
typedef unsigned long long uhwptr; // NOLINT
#else
@@ -99,11 +102,15 @@ extern "C" {
SANITIZER_INTERFACE_ATTRIBUTE
void __sanitizer_set_report_path(const char *path);
- // Notify the tools that the sandbox is going to be turned on. The reserved
- // parameter will be used in the future to hold a structure with functions
- // that the tools may call to bypass the sandbox.
- SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
- void __sanitizer_sandbox_on_notify(void *reserved);
+ typedef struct {
+ int coverage_sandboxed;
+ __sanitizer::sptr coverage_fd;
+ unsigned int coverage_max_block_size;
+ } __sanitizer_sandbox_arguments;
+
+ // Notify the tools that the sandbox is going to be turned on.
+ SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void
+ __sanitizer_sandbox_on_notify(__sanitizer_sandbox_arguments *args);
// This function is called by the tool when it has just finished reporting
// an error. 'error_summary' is a one-line string that summarizes
@@ -112,10 +119,16 @@ extern "C" {
void __sanitizer_report_error_summary(const char *error_summary);
SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_dump();
- SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov(void *pc);
+ SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_init();
+ SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov(__sanitizer::u8 *guard);
SANITIZER_INTERFACE_ATTRIBUTE
- void __sanitizer_annotate_contiguous_container(void *beg, void *end,
- void *old_mid, void *new_mid);
+ void __sanitizer_annotate_contiguous_container(const void *beg,
+ const void *end,
+ const void *old_mid,
+ const void *new_mid);
+ SANITIZER_INTERFACE_ATTRIBUTE
+ int __sanitizer_verify_contiguous_container(const void *beg, const void *mid,
+ const void *end);
} // extern "C"
@@ -141,8 +154,6 @@ using namespace __sanitizer; // NOLINT
# define NOTHROW
# define LIKELY(x) (x)
# define UNLIKELY(x) (x)
-# define UNUSED
-# define USED
# define PREFETCH(x) /* _mm_prefetch(x, _MM_HINT_NTA) */
#else // _MSC_VER
# define ALWAYS_INLINE inline __attribute__((always_inline))
@@ -157,8 +168,6 @@ using namespace __sanitizer; // NOLINT
# define NOTHROW throw()
# define LIKELY(x) __builtin_expect(!!(x), 1)
# define UNLIKELY(x) __builtin_expect(!!(x), 0)
-# define UNUSED __attribute__((unused))
-# define USED __attribute__((used))
# if defined(__i386__) || defined(__x86_64__)
// __builtin_prefetch(x) generates prefetchnt0 on x86
# define PREFETCH(x) __asm__("prefetchnta (%0)" : : "r" (x))
@@ -167,6 +176,14 @@ using namespace __sanitizer; // NOLINT
# endif
#endif // _MSC_VER
+#if !defined(_MSC_VER) || defined(__clang__)
+# define UNUSED __attribute__((unused))
+# define USED __attribute__((used))
+#else
+# define UNUSED
+# define USED
+#endif
+
// Unaligned versions of basic types.
typedef ALIGNED(1) u16 uu16;
typedef ALIGNED(1) u32 uu32;
@@ -197,7 +214,7 @@ void NORETURN CheckFailed(const char *file, int line, const char *cond,
// Check macro
#define RAW_CHECK_MSG(expr, msg) do { \
- if (!(expr)) { \
+ if (UNLIKELY(!(expr))) { \
RawWrite(msg); \
Die(); \
} \
@@ -209,7 +226,7 @@ void NORETURN CheckFailed(const char *file, int line, const char *cond,
do { \
__sanitizer::u64 v1 = (u64)(c1); \
__sanitizer::u64 v2 = (u64)(c2); \
- if (!(v1 op v2)) \
+ if (UNLIKELY(!(v1 op v2))) \
__sanitizer::CheckFailed(__FILE__, __LINE__, \
"(" #c1 ") " #op " (" #c2 ")", v1, v2); \
} while (false) \
diff --git a/lib/sanitizer_common/sanitizer_libc.cc b/lib/sanitizer_common/sanitizer_libc.cc
index 72ddf0fd3fbe..d8bd1cf7a7e0 100644
--- a/lib/sanitizer_common/sanitizer_libc.cc
+++ b/lib/sanitizer_common/sanitizer_libc.cc
@@ -21,16 +21,16 @@ s64 internal_atoll(const char *nptr) {
}
void *internal_memchr(const void *s, int c, uptr n) {
- const char* t = (char*)s;
+ const char *t = (const char *)s;
for (uptr i = 0; i < n; ++i, ++t)
if (*t == c)
- return (void*)t;
+ return reinterpret_cast<void *>(const_cast<char *>(t));
return 0;
}
int internal_memcmp(const void* s1, const void* s2, uptr n) {
- const char* t1 = (char*)s1;
- const char* t2 = (char*)s2;
+ const char *t1 = (const char *)s1;
+ const char *t2 = (const char *)s2;
for (uptr i = 0; i < n; ++i, ++t1, ++t2)
if (*t1 != *t2)
return *t1 < *t2 ? -1 : 1;
@@ -39,7 +39,7 @@ int internal_memcmp(const void* s1, const void* s2, uptr n) {
void *internal_memcpy(void *dest, const void *src, uptr n) {
char *d = (char*)dest;
- char *s = (char*)src;
+ const char *s = (const char *)src;
for (uptr i = 0; i < n; ++i)
d[i] = s[i];
return dest;
@@ -47,7 +47,7 @@ void *internal_memcpy(void *dest, const void *src, uptr n) {
void *internal_memmove(void *dest, const void *src, uptr n) {
char *d = (char*)dest;
- char *s = (char*)src;
+ const char *s = (const char *)src;
sptr i, signed_n = (sptr)n;
CHECK_GE(signed_n, 0);
if (d < s) {
@@ -62,6 +62,16 @@ void *internal_memmove(void *dest, const void *src, uptr n) {
return dest;
}
+// Semi-fast bzero for 16-aligned data. Still far from peak performance.
+void internal_bzero_aligned16(void *s, uptr n) {
+ struct S16 { u64 a, b; } ALIGNED(16);
+ CHECK_EQ((reinterpret_cast<uptr>(s) | n) & 15, 0);
+ for (S16 *p = reinterpret_cast<S16*>(s), *end = p + n / 16; p < end; p++) {
+ p->a = p->b = 0;
+ SanitizerBreakOptimization(0); // Make sure this does not become memset.
+ }
+}
+
void *internal_memset(void* s, int c, uptr n) {
// The next line prevents Clang from making a call to memset() instead of the
// loop below.
@@ -118,7 +128,7 @@ int internal_strncmp(const char *s1, const char *s2, uptr n) {
char* internal_strchr(const char *s, int c) {
while (true) {
if (*s == (char)c)
- return (char*)s;
+ return const_cast<char *>(s);
if (*s == 0)
return 0;
s++;
@@ -128,7 +138,7 @@ char* internal_strchr(const char *s, int c) {
char *internal_strchrnul(const char *s, int c) {
char *res = internal_strchr(s, c);
if (!res)
- res = (char*)s + internal_strlen(s);
+ res = const_cast<char *>(s) + internal_strlen(s);
return res;
}
@@ -137,7 +147,7 @@ char *internal_strrchr(const char *s, int c) {
for (uptr i = 0; s[i]; i++) {
if (s[i] == c) res = s + i;
}
- return (char*)res;
+ return const_cast<char *>(res);
}
uptr internal_strlen(const char *s) {
@@ -176,7 +186,7 @@ char *internal_strstr(const char *haystack, const char *needle) {
if (len1 < len2) return 0;
for (uptr pos = 0; pos <= len1 - len2; pos++) {
if (internal_memcmp(haystack + pos, needle, len2) == 0)
- return (char*)haystack + pos;
+ return const_cast<char *>(haystack) + pos;
}
return 0;
}
@@ -187,7 +197,7 @@ s64 internal_simple_strtoll(const char *nptr, char **endptr, int base) {
int sgn = 1;
u64 res = 0;
bool have_digits = false;
- char *old_nptr = (char*)nptr;
+ char *old_nptr = const_cast<char *>(nptr);
if (*nptr == '+') {
sgn = 1;
nptr++;
@@ -203,7 +213,7 @@ s64 internal_simple_strtoll(const char *nptr, char **endptr, int base) {
nptr++;
}
if (endptr != 0) {
- *endptr = (have_digits) ? (char*)nptr : old_nptr;
+ *endptr = (have_digits) ? const_cast<char *>(nptr) : old_nptr;
}
if (sgn > 0) {
return (s64)(Min((u64)INT64_MAX, res));
diff --git a/lib/sanitizer_common/sanitizer_libc.h b/lib/sanitizer_common/sanitizer_libc.h
index 187a714a3b2b..6995626821ab 100644
--- a/lib/sanitizer_common/sanitizer_libc.h
+++ b/lib/sanitizer_common/sanitizer_libc.h
@@ -29,6 +29,8 @@ void *internal_memchr(const void *s, int c, uptr n);
int internal_memcmp(const void* s1, const void* s2, uptr n);
void *internal_memcpy(void *dest, const void *src, uptr n);
void *internal_memmove(void *dest, const void *src, uptr n);
+// Set [s, s + n) to 0. Both s and n should be 16-aligned.
+void internal_bzero_aligned16(void *s, uptr n);
// Should not be used in performance-critical places.
void *internal_memset(void *s, int c, uptr n);
char* internal_strchr(const char *s, int c);
@@ -72,6 +74,7 @@ uptr internal_open(const char *filename, int flags, u32 mode);
uptr internal_read(fd_t fd, void *buf, uptr count);
uptr internal_write(fd_t fd, const void *buf, uptr count);
+uptr internal_ftruncate(fd_t fd, uptr size);
// OS
uptr internal_filesize(fd_t fd); // -1 on error.
@@ -81,6 +84,7 @@ uptr internal_fstat(fd_t fd, void *buf);
uptr internal_dup2(int oldfd, int newfd);
uptr internal_readlink(const char *path, char *buf, uptr bufsize);
uptr internal_unlink(const char *path);
+uptr internal_rename(const char *oldpath, const char *newpath);
void NORETURN internal__exit(int exitcode);
uptr internal_lseek(fd_t fd, OFF_T offset, int whence);
@@ -89,12 +93,16 @@ uptr internal_waitpid(int pid, int *status, int options);
uptr internal_getpid();
uptr internal_getppid();
+int internal_fork();
+
// Threading
uptr internal_sched_yield();
// Error handling
bool internal_iserror(uptr retval, int *rverrno = 0);
+int internal_sigaction(int signum, const void *act, void *oldact);
+
} // namespace __sanitizer
#endif // SANITIZER_LIBC_H
diff --git a/lib/sanitizer_common/sanitizer_libignore.cc b/lib/sanitizer_common/sanitizer_libignore.cc
index 0f193a130253..8df0467b1e9b 100644
--- a/lib/sanitizer_common/sanitizer_libignore.cc
+++ b/lib/sanitizer_common/sanitizer_libignore.cc
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
#include "sanitizer_platform.h"
-#if SANITIZER_LINUX
+#if SANITIZER_FREEBSD || SANITIZER_LINUX
#include "sanitizer_libignore.h"
#include "sanitizer_flags.h"
@@ -42,9 +42,9 @@ void LibIgnore::Init(const SuppressionContext &supp) {
void LibIgnore::OnLibraryLoaded(const char *name) {
BlockingMutexLock lock(&mutex_);
// Try to match suppressions with symlink target.
- InternalScopedBuffer<char> buf(4096);
+ InternalScopedString buf(kMaxPathLength);
if (name != 0 && internal_readlink(name, buf.data(), buf.size() - 1) > 0 &&
- buf.data()[0]) {
+ buf[0]) {
for (uptr i = 0; i < count_; i++) {
Lib *lib = &libs_[i];
if (!lib->loaded && lib->real_name == 0 &&
@@ -55,7 +55,7 @@ void LibIgnore::OnLibraryLoaded(const char *name) {
// Scan suppressions list and find newly loaded and unloaded libraries.
MemoryMappingLayout proc_maps(/*cache_enabled*/false);
- InternalScopedBuffer<char> module(4096);
+ InternalScopedString module(kMaxPathLength);
for (uptr i = 0; i < count_; i++) {
Lib *lib = &libs_[i];
bool loaded = false;
@@ -76,9 +76,10 @@ void LibIgnore::OnLibraryLoaded(const char *name) {
loaded = true;
if (lib->loaded)
continue;
- if (common_flags()->verbosity)
- Report("Matched called_from_lib suppression '%s' against library"
- " '%s'\n", lib->templ, module.data());
+ VReport(1,
+ "Matched called_from_lib suppression '%s' against library"
+ " '%s'\n",
+ lib->templ, module.data());
lib->loaded = true;
lib->name = internal_strdup(module.data());
const uptr idx = atomic_load(&loaded_count_, memory_order_relaxed);
@@ -102,4 +103,4 @@ void LibIgnore::OnLibraryUnloaded() {
} // namespace __sanitizer
-#endif // #if SANITIZER_LINUX
+#endif // #if SANITIZER_FREEBSD || SANITIZER_LINUX
diff --git a/lib/sanitizer_common/sanitizer_linux.cc b/lib/sanitizer_common/sanitizer_linux.cc
index b98ad0ab4804..36de1ec70e97 100644
--- a/lib/sanitizer_common/sanitizer_linux.cc
+++ b/lib/sanitizer_common/sanitizer_linux.cc
@@ -13,9 +13,11 @@
//===----------------------------------------------------------------------===//
#include "sanitizer_platform.h"
-#if SANITIZER_LINUX
+#if SANITIZER_FREEBSD || SANITIZER_LINUX
+#include "sanitizer_allocator_internal.h"
#include "sanitizer_common.h"
+#include "sanitizer_flags.h"
#include "sanitizer_internal_defs.h"
#include "sanitizer_libc.h"
#include "sanitizer_linux.h"
@@ -25,7 +27,10 @@
#include "sanitizer_stacktrace.h"
#include "sanitizer_symbolizer.h"
+#if !SANITIZER_FREEBSD
#include <asm/param.h>
+#endif
+
#include <dlfcn.h>
#include <errno.h>
#include <fcntl.h>
@@ -42,12 +47,28 @@
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
-#include <unwind.h>
+
+#if SANITIZER_FREEBSD
+#include <sys/sysctl.h>
+#include <machine/atomic.h>
+extern "C" {
+// <sys/umtx.h> must be included after <errno.h> and <sys/types.h> on
+// FreeBSD 9.2 and 10.0.
+#include <sys/umtx.h>
+}
+extern char **environ; // provided by crt1
+#endif // SANITIZER_FREEBSD
#if !SANITIZER_ANDROID
#include <sys/signal.h>
#endif
+#if SANITIZER_ANDROID
+#include <android/log.h>
+#include <sys/system_properties.h>
+#endif
+
+#if SANITIZER_LINUX
// <linux/time.h>
struct kernel_timeval {
long tv_sec;
@@ -57,11 +78,12 @@ struct kernel_timeval {
// <linux/futex.h> is broken on some linux distributions.
const int FUTEX_WAIT = 0;
const int FUTEX_WAKE = 1;
+#endif // SANITIZER_LINUX
-// Are we using 32-bit or 64-bit syscalls?
+// Are we using 32-bit or 64-bit Linux syscalls?
// x32 (which defines __x86_64__) has SANITIZER_WORDSIZE == 32
// but it still needs to use 64-bit syscalls.
-#if defined(__x86_64__) || SANITIZER_WORDSIZE == 64
+#if SANITIZER_LINUX && (defined(__x86_64__) || SANITIZER_WORDSIZE == 64)
# define SANITIZER_LINUX_USES_64BIT_SYSCALLS 1
#else
# define SANITIZER_LINUX_USES_64BIT_SYSCALLS 0
@@ -69,7 +91,7 @@ const int FUTEX_WAKE = 1;
namespace __sanitizer {
-#ifdef __x86_64__
+#if SANITIZER_LINUX && defined(__x86_64__)
#include "sanitizer_syscall_linux_x86_64.inc"
#else
#include "sanitizer_syscall_generic.inc"
@@ -78,48 +100,66 @@ namespace __sanitizer {
// --------------- sanitizer_libc.h
uptr internal_mmap(void *addr, uptr length, int prot, int flags,
int fd, u64 offset) {
-#if SANITIZER_LINUX_USES_64BIT_SYSCALLS
- return internal_syscall(__NR_mmap, (uptr)addr, length, prot, flags, fd,
+#if SANITIZER_FREEBSD || SANITIZER_LINUX_USES_64BIT_SYSCALLS
+ return internal_syscall(SYSCALL(mmap), (uptr)addr, length, prot, flags, fd,
offset);
#else
- return internal_syscall(__NR_mmap2, addr, length, prot, flags, fd, offset);
+ return internal_syscall(SYSCALL(mmap2), addr, length, prot, flags, fd,
+ offset);
#endif
}
uptr internal_munmap(void *addr, uptr length) {
- return internal_syscall(__NR_munmap, (uptr)addr, length);
+ return internal_syscall(SYSCALL(munmap), (uptr)addr, length);
}
uptr internal_close(fd_t fd) {
- return internal_syscall(__NR_close, fd);
+ return internal_syscall(SYSCALL(close), fd);
}
uptr internal_open(const char *filename, int flags) {
- return internal_syscall(__NR_open, (uptr)filename, flags);
+#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
+ return internal_syscall(SYSCALL(openat), AT_FDCWD, (uptr)filename, flags);
+#else
+ return internal_syscall(SYSCALL(open), (uptr)filename, flags);
+#endif
}
uptr internal_open(const char *filename, int flags, u32 mode) {
- return internal_syscall(__NR_open, (uptr)filename, flags, mode);
+#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
+ return internal_syscall(SYSCALL(openat), AT_FDCWD, (uptr)filename, flags,
+ mode);
+#else
+ return internal_syscall(SYSCALL(open), (uptr)filename, flags, mode);
+#endif
}
uptr OpenFile(const char *filename, bool write) {
return internal_open(filename,
- write ? O_WRONLY | O_CREAT /*| O_CLOEXEC*/ : O_RDONLY, 0660);
+ write ? O_RDWR | O_CREAT /*| O_CLOEXEC*/ : O_RDONLY, 0660);
}
uptr internal_read(fd_t fd, void *buf, uptr count) {
sptr res;
- HANDLE_EINTR(res, (sptr)internal_syscall(__NR_read, fd, (uptr)buf, count));
+ HANDLE_EINTR(res, (sptr)internal_syscall(SYSCALL(read), fd, (uptr)buf,
+ count));
return res;
}
uptr internal_write(fd_t fd, const void *buf, uptr count) {
sptr res;
- HANDLE_EINTR(res, (sptr)internal_syscall(__NR_write, fd, (uptr)buf, count));
+ HANDLE_EINTR(res, (sptr)internal_syscall(SYSCALL(write), fd, (uptr)buf,
+ count));
+ return res;
+}
+
+uptr internal_ftruncate(fd_t fd, uptr size) {
+ sptr res;
+ HANDLE_EINTR(res, (sptr)internal_syscall(SYSCALL(ftruncate), fd, size));
return res;
}
-#if !SANITIZER_LINUX_USES_64BIT_SYSCALLS
+#if !SANITIZER_LINUX_USES_64BIT_SYSCALLS && !SANITIZER_FREEBSD
static void stat64_to_stat(struct stat64 *in, struct stat *out) {
internal_memset(out, 0, sizeof(*out));
out->st_dev = in->st_dev;
@@ -140,33 +180,43 @@ static void stat64_to_stat(struct stat64 *in, struct stat *out) {
#endif
uptr internal_stat(const char *path, void *buf) {
-#if SANITIZER_LINUX_USES_64BIT_SYSCALLS
- return internal_syscall(__NR_stat, (uptr)path, (uptr)buf);
+#if SANITIZER_FREEBSD
+ return internal_syscall(SYSCALL(stat), path, buf);
+#elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
+ return internal_syscall(SYSCALL(newfstatat), AT_FDCWD, (uptr)path,
+ (uptr)buf, 0);
+#elif SANITIZER_LINUX_USES_64BIT_SYSCALLS
+ return internal_syscall(SYSCALL(stat), (uptr)path, (uptr)buf);
#else
struct stat64 buf64;
- int res = internal_syscall(__NR_stat64, path, &buf64);
+ int res = internal_syscall(SYSCALL(stat64), path, &buf64);
stat64_to_stat(&buf64, (struct stat *)buf);
return res;
#endif
}
uptr internal_lstat(const char *path, void *buf) {
-#if SANITIZER_LINUX_USES_64BIT_SYSCALLS
- return internal_syscall(__NR_lstat, (uptr)path, (uptr)buf);
+#if SANITIZER_FREEBSD
+ return internal_syscall(SYSCALL(lstat), path, buf);
+#elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
+ return internal_syscall(SYSCALL(newfstatat), AT_FDCWD, (uptr)path,
+ (uptr)buf, AT_SYMLINK_NOFOLLOW);
+#elif SANITIZER_LINUX_USES_64BIT_SYSCALLS
+ return internal_syscall(SYSCALL(lstat), (uptr)path, (uptr)buf);
#else
struct stat64 buf64;
- int res = internal_syscall(__NR_lstat64, path, &buf64);
+ int res = internal_syscall(SYSCALL(lstat64), path, &buf64);
stat64_to_stat(&buf64, (struct stat *)buf);
return res;
#endif
}
uptr internal_fstat(fd_t fd, void *buf) {
-#if SANITIZER_LINUX_USES_64BIT_SYSCALLS
- return internal_syscall(__NR_fstat, fd, (uptr)buf);
+#if SANITIZER_FREEBSD || SANITIZER_LINUX_USES_64BIT_SYSCALLS
+ return internal_syscall(SYSCALL(fstat), fd, (uptr)buf);
#else
struct stat64 buf64;
- int res = internal_syscall(__NR_fstat64, fd, &buf64);
+ int res = internal_syscall(SYSCALL(fstat64), fd, &buf64);
stat64_to_stat(&buf64, (struct stat *)buf);
return res;
#endif
@@ -180,54 +230,104 @@ uptr internal_filesize(fd_t fd) {
}
uptr internal_dup2(int oldfd, int newfd) {
- return internal_syscall(__NR_dup2, oldfd, newfd);
+#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
+ return internal_syscall(SYSCALL(dup3), oldfd, newfd, 0);
+#else
+ return internal_syscall(SYSCALL(dup2), oldfd, newfd);
+#endif
}
uptr internal_readlink(const char *path, char *buf, uptr bufsize) {
- return internal_syscall(__NR_readlink, (uptr)path, (uptr)buf, bufsize);
+#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
+ return internal_syscall(SYSCALL(readlinkat), AT_FDCWD,
+ (uptr)path, (uptr)buf, bufsize);
+#else
+ return internal_syscall(SYSCALL(readlink), (uptr)path, (uptr)buf, bufsize);
+#endif
}
uptr internal_unlink(const char *path) {
- return internal_syscall(__NR_unlink, (uptr)path);
+#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
+ return internal_syscall(SYSCALL(unlinkat), AT_FDCWD, (uptr)path, 0);
+#else
+ return internal_syscall(SYSCALL(unlink), (uptr)path);
+#endif
+}
+
+uptr internal_rename(const char *oldpath, const char *newpath) {
+#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
+ return internal_syscall(SYSCALL(renameat), AT_FDCWD, (uptr)oldpath, AT_FDCWD,
+ (uptr)newpath);
+#else
+ return internal_syscall(SYSCALL(rename), (uptr)oldpath, (uptr)newpath);
+#endif
}
uptr internal_sched_yield() {
- return internal_syscall(__NR_sched_yield);
+ return internal_syscall(SYSCALL(sched_yield));
}
void internal__exit(int exitcode) {
- internal_syscall(__NR_exit_group, exitcode);
+#if SANITIZER_FREEBSD
+ internal_syscall(SYSCALL(exit), exitcode);
+#else
+ internal_syscall(SYSCALL(exit_group), exitcode);
+#endif
Die(); // Unreachable.
}
uptr internal_execve(const char *filename, char *const argv[],
char *const envp[]) {
- return internal_syscall(__NR_execve, (uptr)filename, (uptr)argv, (uptr)envp);
+ return internal_syscall(SYSCALL(execve), (uptr)filename, (uptr)argv,
+ (uptr)envp);
}
// ----------------- sanitizer_common.h
bool FileExists(const char *filename) {
struct stat st;
+#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
+ if (internal_syscall(SYSCALL(newfstatat), AT_FDCWD, filename, &st, 0))
+#else
if (internal_stat(filename, &st))
+#endif
return false;
// Sanity check: filename is a regular file.
return S_ISREG(st.st_mode);
}
uptr GetTid() {
- return internal_syscall(__NR_gettid);
+#if SANITIZER_FREEBSD
+ return (uptr)pthread_self();
+#else
+ return internal_syscall(SYSCALL(gettid));
+#endif
}
u64 NanoTime() {
+#if SANITIZER_FREEBSD
+ timeval tv;
+#else
kernel_timeval tv;
+#endif
internal_memset(&tv, 0, sizeof(tv));
- internal_syscall(__NR_gettimeofday, (uptr)&tv, 0);
+ internal_syscall(SYSCALL(gettimeofday), (uptr)&tv, 0);
return (u64)tv.tv_sec * 1000*1000*1000 + tv.tv_usec * 1000;
}
-// Like getenv, but reads env directly from /proc and does not use libc.
-// This function should be called first inside __asan_init.
+// Like getenv, but reads env directly from /proc (on Linux) or parses the
+// 'environ' array (on FreeBSD) and does not use libc. This function should be
+// called first inside __asan_init.
const char *GetEnv(const char *name) {
+#if SANITIZER_FREEBSD
+ if (::environ != 0) {
+ uptr NameLen = internal_strlen(name);
+ for (char **Env = ::environ; *Env != 0; Env++) {
+ if (internal_strncmp(*Env, name, NameLen) == 0 && (*Env)[NameLen] == '=')
+ return (*Env) + NameLen + 1;
+ }
+ }
+ return 0; // Not found.
+#elif SANITIZER_LINUX
static char *environ;
static uptr len;
static bool inited;
@@ -251,6 +351,9 @@ const char *GetEnv(const char *name) {
p = endp + 1;
}
return 0; // Not found.
+#else
+#error "Unsupported platform"
+#endif
}
extern "C" {
@@ -278,6 +381,33 @@ static void ReadNullSepFileToArray(const char *path, char ***arr,
}
#endif
+uptr GetRSS() {
+ uptr fd = OpenFile("/proc/self/statm", false);
+ if ((sptr)fd < 0)
+ return 0;
+ char buf[64];
+ uptr len = internal_read(fd, buf, sizeof(buf) - 1);
+ internal_close(fd);
+ if ((sptr)len <= 0)
+ return 0;
+ buf[len] = 0;
+ // The format of the file is:
+ // 1084 89 69 11 0 79 0
+ // We need the second number which is RSS in 4K units.
+ char *pos = buf;
+ // Skip the first number.
+ while (*pos >= '0' && *pos <= '9')
+ pos++;
+ // Skip whitespaces.
+ while (!(*pos >= '0' && *pos <= '9') && *pos != 0)
+ pos++;
+ // Read the number.
+ uptr rss = 0;
+ while (*pos >= '0' && *pos <= '9')
+ rss = rss * 10 + *pos++ - '0';
+ return rss * 4096;
+}
+
static void GetArgsAndEnv(char*** argv, char*** envp) {
#if !SANITIZER_GO
if (&__libc_stack_end) {
@@ -305,225 +435,16 @@ void ReExec() {
Die();
}
-void PrepareForSandboxing() {
- // Some kinds of sandboxes may forbid filesystem access, so we won't be able
- // to read the file mappings from /proc/self/maps. Luckily, neither the
- // process will be able to load additional libraries, so it's fine to use the
- // cached mappings.
- MemoryMappingLayout::CacheMemoryMappings();
- // Same for /proc/self/exe in the symbolizer.
-#if !SANITIZER_GO
- if (Symbolizer *sym = Symbolizer::GetOrNull())
- sym->PrepareForSandboxing();
-#endif
-}
-
-// ----------------- sanitizer_procmaps.h
-// Linker initialized.
-ProcSelfMapsBuff MemoryMappingLayout::cached_proc_self_maps_;
-StaticSpinMutex MemoryMappingLayout::cache_lock_; // Linker initialized.
-
-MemoryMappingLayout::MemoryMappingLayout(bool cache_enabled) {
- proc_self_maps_.len =
- ReadFileToBuffer("/proc/self/maps", &proc_self_maps_.data,
- &proc_self_maps_.mmaped_size, 1 << 26);
- if (cache_enabled) {
- if (proc_self_maps_.mmaped_size == 0) {
- LoadFromCache();
- CHECK_GT(proc_self_maps_.len, 0);
- }
- } else {
- CHECK_GT(proc_self_maps_.mmaped_size, 0);
- }
- Reset();
- // FIXME: in the future we may want to cache the mappings on demand only.
- if (cache_enabled)
- CacheMemoryMappings();
-}
-
-MemoryMappingLayout::~MemoryMappingLayout() {
- // Only unmap the buffer if it is different from the cached one. Otherwise
- // it will be unmapped when the cache is refreshed.
- if (proc_self_maps_.data != cached_proc_self_maps_.data) {
- UnmapOrDie(proc_self_maps_.data, proc_self_maps_.mmaped_size);
- }
-}
-
-void MemoryMappingLayout::Reset() {
- current_ = proc_self_maps_.data;
-}
-
-// static
-void MemoryMappingLayout::CacheMemoryMappings() {
- SpinMutexLock l(&cache_lock_);
- // Don't invalidate the cache if the mappings are unavailable.
- ProcSelfMapsBuff old_proc_self_maps;
- old_proc_self_maps = cached_proc_self_maps_;
- cached_proc_self_maps_.len =
- ReadFileToBuffer("/proc/self/maps", &cached_proc_self_maps_.data,
- &cached_proc_self_maps_.mmaped_size, 1 << 26);
- if (cached_proc_self_maps_.mmaped_size == 0) {
- cached_proc_self_maps_ = old_proc_self_maps;
- } else {
- if (old_proc_self_maps.mmaped_size) {
- UnmapOrDie(old_proc_self_maps.data,
- old_proc_self_maps.mmaped_size);
- }
- }
-}
-
-void MemoryMappingLayout::LoadFromCache() {
- SpinMutexLock l(&cache_lock_);
- if (cached_proc_self_maps_.data) {
- proc_self_maps_ = cached_proc_self_maps_;
- }
-}
-
-// Parse a hex value in str and update str.
-static uptr ParseHex(char **str) {
- uptr x = 0;
- char *s;
- for (s = *str; ; s++) {
- char c = *s;
- uptr v = 0;
- if (c >= '0' && c <= '9')
- v = c - '0';
- else if (c >= 'a' && c <= 'f')
- v = c - 'a' + 10;
- else if (c >= 'A' && c <= 'F')
- v = c - 'A' + 10;
- else
- break;
- x = x * 16 + v;
- }
- *str = s;
- return x;
-}
-
-static bool IsOneOf(char c, char c1, char c2) {
- return c == c1 || c == c2;
-}
-
-static bool IsDecimal(char c) {
- return c >= '0' && c <= '9';
-}
-
-static bool IsHex(char c) {
- return (c >= '0' && c <= '9')
- || (c >= 'a' && c <= 'f');
-}
-
-static uptr ReadHex(const char *p) {
- uptr v = 0;
- for (; IsHex(p[0]); p++) {
- if (p[0] >= '0' && p[0] <= '9')
- v = v * 16 + p[0] - '0';
- else
- v = v * 16 + p[0] - 'a' + 10;
- }
- return v;
-}
-
-static uptr ReadDecimal(const char *p) {
- uptr v = 0;
- for (; IsDecimal(p[0]); p++)
- v = v * 10 + p[0] - '0';
- return v;
-}
-
-
-bool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset,
- char filename[], uptr filename_size,
- uptr *protection) {
- char *last = proc_self_maps_.data + proc_self_maps_.len;
- if (current_ >= last) return false;
- uptr dummy;
- if (!start) start = &dummy;
- if (!end) end = &dummy;
- if (!offset) offset = &dummy;
- char *next_line = (char*)internal_memchr(current_, '\n', last - current_);
- if (next_line == 0)
- next_line = last;
- // Example: 08048000-08056000 r-xp 00000000 03:0c 64593 /foo/bar
- *start = ParseHex(&current_);
- CHECK_EQ(*current_++, '-');
- *end = ParseHex(&current_);
- CHECK_EQ(*current_++, ' ');
- uptr local_protection = 0;
- CHECK(IsOneOf(*current_, '-', 'r'));
- if (*current_++ == 'r')
- local_protection |= kProtectionRead;
- CHECK(IsOneOf(*current_, '-', 'w'));
- if (*current_++ == 'w')
- local_protection |= kProtectionWrite;
- CHECK(IsOneOf(*current_, '-', 'x'));
- if (*current_++ == 'x')
- local_protection |= kProtectionExecute;
- CHECK(IsOneOf(*current_, 's', 'p'));
- if (*current_++ == 's')
- local_protection |= kProtectionShared;
- if (protection) {
- *protection = local_protection;
- }
- CHECK_EQ(*current_++, ' ');
- *offset = ParseHex(&current_);
- CHECK_EQ(*current_++, ' ');
- ParseHex(&current_);
- CHECK_EQ(*current_++, ':');
- ParseHex(&current_);
- CHECK_EQ(*current_++, ' ');
- while (IsDecimal(*current_))
- current_++;
- // Qemu may lack the trailing space.
- // http://code.google.com/p/address-sanitizer/issues/detail?id=160
- // CHECK_EQ(*current_++, ' ');
- // Skip spaces.
- while (current_ < next_line && *current_ == ' ')
- current_++;
- // Fill in the filename.
- uptr i = 0;
- while (current_ < next_line) {
- if (filename && i < filename_size - 1)
- filename[i++] = *current_;
- current_++;
- }
- if (filename && i < filename_size)
- filename[i] = 0;
- current_ = next_line + 1;
- return true;
-}
-
-// Gets the object name and the offset by walking MemoryMappingLayout.
-bool MemoryMappingLayout::GetObjectNameAndOffset(uptr addr, uptr *offset,
- char filename[],
- uptr filename_size,
- uptr *protection) {
- return IterateForObjectNameAndOffset(addr, offset, filename, filename_size,
- protection);
-}
-
-void GetMemoryProfile(fill_profile_f cb, uptr *stats, uptr stats_size) {
- char *smaps = 0;
- uptr smaps_cap = 0;
- uptr smaps_len = ReadFileToBuffer("/proc/self/smaps",
- &smaps, &smaps_cap, 64<<20);
- uptr start = 0;
- bool file = false;
- const char *pos = smaps;
- while (pos < smaps + smaps_len) {
- if (IsHex(pos[0])) {
- start = ReadHex(pos);
- for (; *pos != '/' && *pos > '\n'; pos++) {}
- file = *pos == '/';
- } else if (internal_strncmp(pos, "Rss:", 4) == 0) {
- for (; *pos < '0' || *pos > '9'; pos++) {}
- uptr rss = ReadDecimal(pos) * 1024;
- cb(start, rss, file, stats, stats_size);
- }
- while (*pos++ != '\n') {}
- }
- UnmapOrDie(smaps, smaps_cap);
+// Stub implementation of GetThreadStackAndTls for Go.
+#if SANITIZER_GO
+void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
+ uptr *tls_addr, uptr *tls_size) {
+ *stk_addr = 0;
+ *stk_size = 0;
+ *tls_addr = 0;
+ *tls_size = 0;
}
+#endif // SANITIZER_GO
enum MutexState {
MtxUnlocked = 0,
@@ -543,16 +464,26 @@ void BlockingMutex::Lock() {
atomic_uint32_t *m = reinterpret_cast<atomic_uint32_t *>(&opaque_storage_);
if (atomic_exchange(m, MtxLocked, memory_order_acquire) == MtxUnlocked)
return;
- while (atomic_exchange(m, MtxSleeping, memory_order_acquire) != MtxUnlocked)
- internal_syscall(__NR_futex, (uptr)m, FUTEX_WAIT, MtxSleeping, 0, 0, 0);
+ while (atomic_exchange(m, MtxSleeping, memory_order_acquire) != MtxUnlocked) {
+#if SANITIZER_FREEBSD
+ _umtx_op(m, UMTX_OP_WAIT_UINT, MtxSleeping, 0, 0);
+#else
+ internal_syscall(SYSCALL(futex), (uptr)m, FUTEX_WAIT, MtxSleeping, 0, 0, 0);
+#endif
+ }
}
void BlockingMutex::Unlock() {
atomic_uint32_t *m = reinterpret_cast<atomic_uint32_t *>(&opaque_storage_);
u32 v = atomic_exchange(m, MtxUnlocked, memory_order_relaxed);
CHECK_NE(v, MtxUnlocked);
- if (v == MtxSleeping)
- internal_syscall(__NR_futex, (uptr)m, FUTEX_WAKE, 1, 0, 0, 0);
+ if (v == MtxSleeping) {
+#if SANITIZER_FREEBSD
+ _umtx_op(m, UMTX_OP_WAKE, 1, 0, 0);
+#else
+ internal_syscall(SYSCALL(futex), (uptr)m, FUTEX_WAKE, 1, 0, 0, 0);
+#endif
+ }
}
void BlockingMutex::CheckLocked() {
@@ -565,71 +496,137 @@ void BlockingMutex::CheckLocked() {
// Note that getdents64 uses a different structure format. We only provide the
// 32-bit syscall here.
struct linux_dirent {
+#if SANITIZER_X32
+ u64 d_ino;
+ u64 d_off;
+#else
unsigned long d_ino;
unsigned long d_off;
+#endif
unsigned short d_reclen;
char d_name[256];
};
// Syscall wrappers.
uptr internal_ptrace(int request, int pid, void *addr, void *data) {
- return internal_syscall(__NR_ptrace, request, pid, (uptr)addr, (uptr)data);
+ return internal_syscall(SYSCALL(ptrace), request, pid, (uptr)addr,
+ (uptr)data);
}
uptr internal_waitpid(int pid, int *status, int options) {
- return internal_syscall(__NR_wait4, pid, (uptr)status, options,
+ return internal_syscall(SYSCALL(wait4), pid, (uptr)status, options,
0 /* rusage */);
}
uptr internal_getpid() {
- return internal_syscall(__NR_getpid);
+ return internal_syscall(SYSCALL(getpid));
}
uptr internal_getppid() {
- return internal_syscall(__NR_getppid);
+ return internal_syscall(SYSCALL(getppid));
}
uptr internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned int count) {
- return internal_syscall(__NR_getdents, fd, (uptr)dirp, count);
+#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
+ return internal_syscall(SYSCALL(getdents64), fd, (uptr)dirp, count);
+#else
+ return internal_syscall(SYSCALL(getdents), fd, (uptr)dirp, count);
+#endif
}
uptr internal_lseek(fd_t fd, OFF_T offset, int whence) {
- return internal_syscall(__NR_lseek, fd, offset, whence);
+ return internal_syscall(SYSCALL(lseek), fd, offset, whence);
}
+#if SANITIZER_LINUX
uptr internal_prctl(int option, uptr arg2, uptr arg3, uptr arg4, uptr arg5) {
- return internal_syscall(__NR_prctl, option, arg2, arg3, arg4, arg5);
+ return internal_syscall(SYSCALL(prctl), option, arg2, arg3, arg4, arg5);
}
+#endif
uptr internal_sigaltstack(const struct sigaltstack *ss,
struct sigaltstack *oss) {
- return internal_syscall(__NR_sigaltstack, (uptr)ss, (uptr)oss);
+ return internal_syscall(SYSCALL(sigaltstack), (uptr)ss, (uptr)oss);
}
-uptr internal_sigaction(int signum, const __sanitizer_kernel_sigaction_t *act,
- __sanitizer_kernel_sigaction_t *oldact) {
- return internal_syscall(__NR_rt_sigaction, signum, act, oldact,
- sizeof(__sanitizer_kernel_sigset_t));
+int internal_fork() {
+#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
+ return internal_syscall(SYSCALL(clone), SIGCHLD, 0);
+#else
+ return internal_syscall(SYSCALL(fork));
+#endif
+}
+
+#if SANITIZER_LINUX
+// Doesn't set sa_restorer, use with caution (see below).
+int internal_sigaction_norestorer(int signum, const void *act, void *oldact) {
+ __sanitizer_kernel_sigaction_t k_act, k_oldact;
+ internal_memset(&k_act, 0, sizeof(__sanitizer_kernel_sigaction_t));
+ internal_memset(&k_oldact, 0, sizeof(__sanitizer_kernel_sigaction_t));
+ const __sanitizer_sigaction *u_act = (const __sanitizer_sigaction *)act;
+ __sanitizer_sigaction *u_oldact = (__sanitizer_sigaction *)oldact;
+ if (u_act) {
+ k_act.handler = u_act->handler;
+ k_act.sigaction = u_act->sigaction;
+ internal_memcpy(&k_act.sa_mask, &u_act->sa_mask,
+ sizeof(__sanitizer_kernel_sigset_t));
+ k_act.sa_flags = u_act->sa_flags;
+ // FIXME: most often sa_restorer is unset, however the kernel requires it
+ // to point to a valid signal restorer that calls the rt_sigreturn syscall.
+ // If sa_restorer passed to the kernel is NULL, the program may crash upon
+ // signal delivery or fail to unwind the stack in the signal handler.
+ // libc implementation of sigaction() passes its own restorer to
+ // rt_sigaction, so we need to do the same (we'll need to reimplement the
+ // restorers; for x86_64 the restorer address can be obtained from
+ // oldact->sa_restorer upon a call to sigaction(xxx, NULL, oldact).
+ k_act.sa_restorer = u_act->sa_restorer;
+ }
+
+ uptr result = internal_syscall(SYSCALL(rt_sigaction), (uptr)signum,
+ (uptr)(u_act ? &k_act : NULL),
+ (uptr)(u_oldact ? &k_oldact : NULL),
+ (uptr)sizeof(__sanitizer_kernel_sigset_t));
+
+ if ((result == 0) && u_oldact) {
+ u_oldact->handler = k_oldact.handler;
+ u_oldact->sigaction = k_oldact.sigaction;
+ internal_memcpy(&u_oldact->sa_mask, &k_oldact.sa_mask,
+ sizeof(__sanitizer_kernel_sigset_t));
+ u_oldact->sa_flags = k_oldact.sa_flags;
+ u_oldact->sa_restorer = k_oldact.sa_restorer;
+ }
+ return result;
}
+#endif // SANITIZER_LINUX
-uptr internal_sigprocmask(int how, __sanitizer_kernel_sigset_t *set,
- __sanitizer_kernel_sigset_t *oldset) {
- return internal_syscall(__NR_rt_sigprocmask, (uptr)how, &set->sig[0],
- &oldset->sig[0], sizeof(__sanitizer_kernel_sigset_t));
+uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set,
+ __sanitizer_sigset_t *oldset) {
+#if SANITIZER_FREEBSD
+ return internal_syscall(SYSCALL(sigprocmask), how, set, oldset);
+#else
+ __sanitizer_kernel_sigset_t *k_set = (__sanitizer_kernel_sigset_t *)set;
+ __sanitizer_kernel_sigset_t *k_oldset = (__sanitizer_kernel_sigset_t *)oldset;
+ return internal_syscall(SYSCALL(rt_sigprocmask), (uptr)how,
+ (uptr)&k_set->sig[0], (uptr)&k_oldset->sig[0],
+ sizeof(__sanitizer_kernel_sigset_t));
+#endif
}
-void internal_sigfillset(__sanitizer_kernel_sigset_t *set) {
+void internal_sigfillset(__sanitizer_sigset_t *set) {
internal_memset(set, 0xff, sizeof(*set));
}
-void internal_sigdelset(__sanitizer_kernel_sigset_t *set, int signum) {
+#if SANITIZER_LINUX
+void internal_sigdelset(__sanitizer_sigset_t *set, int signum) {
signum -= 1;
CHECK_GE(signum, 0);
CHECK_LT(signum, sizeof(*set) * 8);
- const uptr idx = signum / (sizeof(set->sig[0]) * 8);
- const uptr bit = signum % (sizeof(set->sig[0]) * 8);
- set->sig[idx] &= ~(1 << bit);
+ __sanitizer_kernel_sigset_t *k_set = (__sanitizer_kernel_sigset_t *)set;
+ const uptr idx = signum / (sizeof(k_set->sig[0]) * 8);
+ const uptr bit = signum % (sizeof(k_set->sig[0]) * 8);
+ k_set->sig[idx] &= ~(1 << bit);
}
+#endif // SANITIZER_LINUX
// ThreadLister implementation.
ThreadLister::ThreadLister(int pid)
@@ -700,7 +697,7 @@ bool ThreadLister::GetDirectoryEntries() {
}
uptr GetPageSize() {
-#if defined(__x86_64__) || defined(__i386__)
+#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__i386__))
return EXEC_PAGESIZE;
#else
return sysconf(_SC_PAGESIZE); // EXEC_PAGESIZE may not be trustworthy.
@@ -711,24 +708,32 @@ static char proc_self_exe_cache_str[kMaxPathLength];
static uptr proc_self_exe_cache_len = 0;
uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) {
+ if (proc_self_exe_cache_len > 0) {
+ // If available, use the cached module name.
+ uptr module_name_len =
+ internal_snprintf(buf, buf_len, "%s", proc_self_exe_cache_str);
+ CHECK_LT(module_name_len, buf_len);
+ return module_name_len;
+ }
+#if SANITIZER_FREEBSD
+ const int Mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
+ size_t Size = buf_len;
+ bool IsErr = (sysctl(Mib, 4, buf, &Size, NULL, 0) != 0);
+ int readlink_error = IsErr ? errno : 0;
+ uptr module_name_len = Size;
+#else
uptr module_name_len = internal_readlink(
"/proc/self/exe", buf, buf_len);
int readlink_error;
- if (internal_iserror(module_name_len, &readlink_error)) {
- if (proc_self_exe_cache_len) {
- // If available, use the cached module name.
- CHECK_LE(proc_self_exe_cache_len, buf_len);
- internal_strncpy(buf, proc_self_exe_cache_str, buf_len);
- module_name_len = internal_strlen(proc_self_exe_cache_str);
- } else {
- // We can't read /proc/self/exe for some reason, assume the name of the
- // binary is unknown.
- Report("WARNING: readlink(\"/proc/self/exe\") failed with errno %d, "
- "some stack frames may not be symbolized\n", readlink_error);
- module_name_len = internal_snprintf(buf, buf_len, "/proc/self/exe");
- }
+ bool IsErr = internal_iserror(module_name_len, &readlink_error);
+#endif
+ if (IsErr) {
+ // We can't read /proc/self/exe for some reason, assume the name of the
+ // binary is unknown.
+ Report("WARNING: readlink(\"/proc/self/exe\") failed with errno %d, "
+ "some stack frames may not be symbolized\n", readlink_error);
+ module_name_len = internal_snprintf(buf, buf_len, "/proc/self/exe");
CHECK_LT(module_name_len, buf_len);
- buf[module_name_len] = '\0';
}
return module_name_len;
}
@@ -755,8 +760,10 @@ bool LibraryNameIs(const char *full_name, const char *base_name) {
#if !SANITIZER_ANDROID
// Call cb for each region mapped by map.
void ForEachMappedRegion(link_map *map, void (*cb)(const void *, uptr)) {
+#if !SANITIZER_FREEBSD
typedef ElfW(Phdr) Elf_Phdr;
typedef ElfW(Ehdr) Elf_Ehdr;
+#endif // !SANITIZER_FREEBSD
char *base = (char *)map->l_addr;
Elf_Ehdr *ehdr = (Elf_Ehdr *)base;
char *phdrs = base + ehdr->e_phoff;
@@ -790,7 +797,7 @@ void ForEachMappedRegion(link_map *map, void (*cb)(const void *, uptr)) {
}
#endif
-#if defined(__x86_64__)
+#if defined(__x86_64__) && SANITIZER_LINUX
// We cannot use glibc's clone wrapper, because it messes with the child
// task's TLS. It writes the PID and TID of the child task to its thread
// descriptor, but in our case the child task shares the thread descriptor with
@@ -809,7 +816,7 @@ uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
register void *r8 __asm__("r8") = newtls;
register int *r10 __asm__("r10") = child_tidptr;
__asm__ __volatile__(
- /* %rax = syscall(%rax = __NR_clone,
+ /* %rax = syscall(%rax = SYSCALL(clone),
* %rdi = flags,
* %rsi = child_stack,
* %rdx = parent_tidptr,
@@ -843,7 +850,7 @@ uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
/* Return to parent. */
"1:\n"
: "=a" (res)
- : "a"(__NR_clone), "i"(__NR_exit),
+ : "a"(SYSCALL(clone)), "i"(SYSCALL(exit)),
"S"(child_stack),
"D"(flags),
"d"(parent_tidptr),
@@ -852,7 +859,46 @@ uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
: "rsp", "memory", "r11", "rcx");
return res;
}
-#endif // defined(__x86_64__)
+#endif // defined(__x86_64__) && SANITIZER_LINUX
+
+#if SANITIZER_ANDROID
+static atomic_uint8_t android_log_initialized;
+
+void AndroidLogInit() {
+ atomic_store(&android_log_initialized, 1, memory_order_release);
+}
+// This thing is not, strictly speaking, async signal safe, but it does not seem
+// to cause any issues. Alternative is writing to log devices directly, but
+// their location and message format might change in the future, so we'd really
+// like to avoid that.
+void AndroidLogWrite(const char *buffer) {
+ if (!atomic_load(&android_log_initialized, memory_order_acquire))
+ return;
+
+ char *copy = internal_strdup(buffer);
+ char *p = copy;
+ char *q;
+ // __android_log_write has an implicit message length limit.
+ // Print one line at a time.
+ do {
+ q = internal_strchr(p, '\n');
+ if (q) *q = '\0';
+ __android_log_write(ANDROID_LOG_INFO, NULL, p);
+ if (q) p = q + 1;
+ } while (q);
+ InternalFree(copy);
+}
+
+void GetExtraActivationFlags(char *buf, uptr size) {
+ CHECK(size > PROP_VALUE_MAX);
+ __system_property_get("asan.options", buf);
+}
+#endif
+
+bool IsDeadlySignal(int signum) {
+ return (signum == SIGSEGV) && common_flags()->handle_segv;
+}
+
} // namespace __sanitizer
-#endif // SANITIZER_LINUX
+#endif // SANITIZER_FREEBSD || SANITIZER_LINUX
diff --git a/lib/sanitizer_common/sanitizer_linux.h b/lib/sanitizer_common/sanitizer_linux.h
index a32e9bf08bad..3013c25f7c38 100644
--- a/lib/sanitizer_common/sanitizer_linux.h
+++ b/lib/sanitizer_common/sanitizer_linux.h
@@ -14,7 +14,7 @@
#define SANITIZER_LINUX_H
#include "sanitizer_platform.h"
-#if SANITIZER_LINUX
+#if SANITIZER_FREEBSD || SANITIZER_LINUX
#include "sanitizer_common.h"
#include "sanitizer_internal_defs.h"
#include "sanitizer_platform_limits_posix.h"
@@ -29,20 +29,25 @@ struct linux_dirent;
// Syscall wrappers.
uptr internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned int count);
-uptr internal_prctl(int option, uptr arg2, uptr arg3, uptr arg4, uptr arg5);
uptr internal_sigaltstack(const struct sigaltstack* ss,
struct sigaltstack* oss);
-uptr internal_sigaction(int signum, const __sanitizer_kernel_sigaction_t *act,
- __sanitizer_kernel_sigaction_t *oldact);
-uptr internal_sigprocmask(int how, __sanitizer_kernel_sigset_t *set,
- __sanitizer_kernel_sigset_t *oldset);
-void internal_sigfillset(__sanitizer_kernel_sigset_t *set);
-void internal_sigdelset(__sanitizer_kernel_sigset_t *set, int signum);
+uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set,
+ __sanitizer_sigset_t *oldset);
+void internal_sigfillset(__sanitizer_sigset_t *set);
-#ifdef __x86_64__
+// Linux-only syscalls.
+#if SANITIZER_LINUX
+uptr internal_prctl(int option, uptr arg2, uptr arg3, uptr arg4, uptr arg5);
+// Used only by sanitizer_stoptheworld. Signal handlers that are actually used
+// (like the process-wide error reporting SEGV handler) must use
+// internal_sigaction instead.
+int internal_sigaction_norestorer(int signum, const void *act, void *oldact);
+void internal_sigdelset(__sanitizer_sigset_t *set, int signum);
+#if defined(__x86_64__)
uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
int *parent_tidptr, void *newtls, int *child_tidptr);
#endif
+#endif // SANITIZER_LINUX
// This class reads thread IDs from /proc/<pid>/task using only syscalls.
class ThreadLister {
@@ -66,8 +71,6 @@ class ThreadLister {
int bytes_read_;
};
-void AdjustStackSizeLinux(void *attr);
-
// Exposed for testing.
uptr ThreadDescriptorSize();
uptr ThreadSelf();
@@ -86,5 +89,5 @@ void CacheBinaryName();
void ForEachMappedRegion(link_map *map, void (*cb)(const void *, uptr));
} // namespace __sanitizer
-#endif // SANITIZER_LINUX
+#endif // SANITIZER_FREEBSD || SANITIZER_LINUX
#endif // SANITIZER_LINUX_H
diff --git a/lib/sanitizer_common/sanitizer_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_linux_libcdep.cc
index 2940686f1275..4e09081e7f54 100644
--- a/lib/sanitizer_common/sanitizer_linux_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_linux_libcdep.cc
@@ -13,31 +13,68 @@
//===----------------------------------------------------------------------===//
#include "sanitizer_platform.h"
-#if SANITIZER_LINUX
+#if SANITIZER_FREEBSD || SANITIZER_LINUX
#include "sanitizer_common.h"
#include "sanitizer_flags.h"
+#include "sanitizer_freebsd.h"
#include "sanitizer_linux.h"
#include "sanitizer_placement_new.h"
#include "sanitizer_procmaps.h"
#include "sanitizer_stacktrace.h"
+#include "sanitizer_atomic.h"
+#include "sanitizer_symbolizer.h"
+
+#if SANITIZER_ANDROID || SANITIZER_FREEBSD
+#include <dlfcn.h> // for dlsym()
+#endif
-#include <dlfcn.h>
#include <pthread.h>
-#include <sys/prctl.h>
+#include <signal.h>
#include <sys/resource.h>
-#include <unwind.h>
+
+#if SANITIZER_FREEBSD
+#include <pthread_np.h>
+#include <osreldate.h>
+#define pthread_getattr_np pthread_attr_get_np
+#endif
+
+#if SANITIZER_LINUX
+#include <sys/prctl.h>
+#endif
#if !SANITIZER_ANDROID
#include <elf.h>
#include <link.h>
+#include <unistd.h>
#endif
namespace __sanitizer {
+// This function is defined elsewhere if we intercepted pthread_attr_getstack.
+extern "C" {
+SANITIZER_WEAK_ATTRIBUTE int
+real_pthread_attr_getstack(void *attr, void **addr, size_t *size);
+} // extern "C"
+
+static int my_pthread_attr_getstack(void *attr, void **addr, size_t *size) {
+ if (real_pthread_attr_getstack)
+ return real_pthread_attr_getstack((pthread_attr_t *)attr, addr, size);
+ return pthread_attr_getstack((pthread_attr_t *)attr, addr, size);
+}
+
+SANITIZER_WEAK_ATTRIBUTE int
+real_sigaction(int signum, const void *act, void *oldact);
+
+int internal_sigaction(int signum, const void *act, void *oldact) {
+ if (real_sigaction)
+ return real_sigaction(signum, act, oldact);
+ return sigaction(signum, (const struct sigaction *)act,
+ (struct sigaction *)oldact);
+}
+
void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
uptr *stack_bottom) {
- static const uptr kMaxThreadStackSize = 1 << 30; // 1Gb
CHECK(stack_top);
CHECK(stack_bottom);
if (at_initialization) {
@@ -71,10 +108,11 @@ void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
return;
}
pthread_attr_t attr;
+ pthread_attr_init(&attr);
CHECK_EQ(pthread_getattr_np(pthread_self(), &attr), 0);
uptr stacksize = 0;
void *stackaddr = 0;
- pthread_attr_getstack(&attr, &stackaddr, (size_t*)&stacksize);
+ my_pthread_attr_getstack(&attr, &stackaddr, (size_t*)&stacksize);
pthread_attr_destroy(&attr);
CHECK_LE(stacksize, kMaxThreadStackSize); // Sanity check.
@@ -82,8 +120,6 @@ void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
*stack_bottom = (uptr)stackaddr;
}
-// Does not compile for Go because dlsym() requires -ldl
-#ifndef SANITIZER_GO
bool SetEnv(const char *name, const char *value) {
void *f = dlsym(RTLD_NEXT, "setenv");
if (f == 0)
@@ -94,7 +130,6 @@ bool SetEnv(const char *name, const char *value) {
internal_memcpy(&setenv_f, &f, sizeof(f));
return setenv_f(name, value, 1) == 0;
}
-#endif
bool SanitizerSetThreadName(const char *name) {
#ifdef PR_SET_NAME
@@ -117,61 +152,9 @@ bool SanitizerGetThreadName(char *name, int max_len) {
#endif
}
-#ifndef SANITIZER_GO
-//------------------------- SlowUnwindStack -----------------------------------
-#ifdef __arm__
-#define UNWIND_STOP _URC_END_OF_STACK
-#define UNWIND_CONTINUE _URC_NO_REASON
-#else
-#define UNWIND_STOP _URC_NORMAL_STOP
-#define UNWIND_CONTINUE _URC_NO_REASON
-#endif
-
-uptr Unwind_GetIP(struct _Unwind_Context *ctx) {
-#ifdef __arm__
- uptr val;
- _Unwind_VRS_Result res = _Unwind_VRS_Get(ctx, _UVRSC_CORE,
- 15 /* r15 = PC */, _UVRSD_UINT32, &val);
- CHECK(res == _UVRSR_OK && "_Unwind_VRS_Get failed");
- // Clear the Thumb bit.
- return val & ~(uptr)1;
-#else
- return _Unwind_GetIP(ctx);
-#endif
-}
-
-struct UnwindTraceArg {
- StackTrace *stack;
- uptr max_depth;
-};
-
-_Unwind_Reason_Code Unwind_Trace(struct _Unwind_Context *ctx, void *param) {
- UnwindTraceArg *arg = (UnwindTraceArg*)param;
- CHECK_LT(arg->stack->size, arg->max_depth);
- uptr pc = Unwind_GetIP(ctx);
- arg->stack->trace[arg->stack->size++] = pc;
- if (arg->stack->size == arg->max_depth) return UNWIND_STOP;
- return UNWIND_CONTINUE;
-}
-
-void StackTrace::SlowUnwindStack(uptr pc, uptr max_depth) {
- size = 0;
- if (max_depth == 0)
- return;
- UnwindTraceArg arg = {this, Min(max_depth + 1, kStackTraceMax)};
- _Unwind_Backtrace(Unwind_Trace, &arg);
- // We need to pop a few frames so that pc is on top.
- uptr to_pop = LocatePcInTrace(pc);
- // trace[0] belongs to the current function so we always pop it.
- if (to_pop == 0)
- to_pop = 1;
- PopStackFrames(to_pop);
- trace[0] = pc;
-}
-
-#endif // !SANITIZER_GO
-
+#if !SANITIZER_FREEBSD
static uptr g_tls_size;
+#endif
#ifdef __i386__
# define DL_INTERNAL_FUNCTION __attribute__((regparm(3), stdcall))
@@ -180,7 +163,7 @@ static uptr g_tls_size;
#endif
void InitTlsSize() {
-#if !defined(SANITIZER_GO) && !SANITIZER_ANDROID
+#if !SANITIZER_FREEBSD && !SANITIZER_ANDROID
typedef void (*get_tls_func)(size_t*, size_t*) DL_INTERNAL_FUNCTION;
get_tls_func get_tls;
void *get_tls_static_info_ptr = dlsym(RTLD_NEXT, "_dl_get_tls_static_info");
@@ -192,25 +175,48 @@ void InitTlsSize() {
size_t tls_align = 0;
get_tls(&tls_size, &tls_align);
g_tls_size = tls_size;
-#endif
+#endif // !SANITIZER_FREEBSD && !SANITIZER_ANDROID
}
-uptr GetTlsSize() {
- return g_tls_size;
-}
-
-#if defined(__x86_64__) || defined(__i386__)
+#if (defined(__x86_64__) || defined(__i386__)) && SANITIZER_LINUX
// sizeof(struct thread) from glibc.
-// There has been a report of this being different on glibc 2.11 and 2.13. We
-// don't know when this change happened, so 2.14 is a conservative estimate.
-#if __GLIBC_PREREQ(2, 14)
-const uptr kThreadDescriptorSize = FIRST_32_SECOND_64(1216, 2304);
-#else
-const uptr kThreadDescriptorSize = FIRST_32_SECOND_64(1168, 2304);
-#endif
+static atomic_uintptr_t kThreadDescriptorSize;
uptr ThreadDescriptorSize() {
- return kThreadDescriptorSize;
+ uptr val = atomic_load(&kThreadDescriptorSize, memory_order_relaxed);
+ if (val)
+ return val;
+#ifdef _CS_GNU_LIBC_VERSION
+ char buf[64];
+ uptr len = confstr(_CS_GNU_LIBC_VERSION, buf, sizeof(buf));
+ if (len < sizeof(buf) && internal_strncmp(buf, "glibc 2.", 8) == 0) {
+ char *end;
+ int minor = internal_simple_strtoll(buf + 8, &end, 10);
+ if (end != buf + 8 && (*end == '\0' || *end == '.')) {
+ /* sizeof(struct thread) values from various glibc versions. */
+ if (SANITIZER_X32)
+ val = 1728; // Assume only one particular version for x32.
+ else if (minor <= 3)
+ val = FIRST_32_SECOND_64(1104, 1696);
+ else if (minor == 4)
+ val = FIRST_32_SECOND_64(1120, 1728);
+ else if (minor == 5)
+ val = FIRST_32_SECOND_64(1136, 1728);
+ else if (minor <= 9)
+ val = FIRST_32_SECOND_64(1136, 1712);
+ else if (minor == 10)
+ val = FIRST_32_SECOND_64(1168, 1776);
+ else if (minor <= 12)
+ val = FIRST_32_SECOND_64(1168, 2288);
+ else
+ val = FIRST_32_SECOND_64(1216, 2304);
+ }
+ if (val)
+ atomic_store(&kThreadDescriptorSize, val, memory_order_relaxed);
+ return val;
+ }
+#endif
+ return 0;
}
// The offset at which pointer to self is located in the thread descriptor.
@@ -222,27 +228,79 @@ uptr ThreadSelfOffset() {
uptr ThreadSelf() {
uptr descr_addr;
-#ifdef __i386__
+# if defined(__i386__)
asm("mov %%gs:%c1,%0" : "=r"(descr_addr) : "i"(kThreadSelfOffset));
-#else
+# elif defined(__x86_64__)
asm("mov %%fs:%c1,%0" : "=r"(descr_addr) : "i"(kThreadSelfOffset));
-#endif
+# else
+# error "unsupported CPU arch"
+# endif
return descr_addr;
}
-#endif // defined(__x86_64__) || defined(__i386__)
+#endif // (defined(__x86_64__) || defined(__i386__)) && SANITIZER_LINUX
+
+#if SANITIZER_FREEBSD
+static void **ThreadSelfSegbase() {
+ void **segbase = 0;
+# if defined(__i386__)
+ // sysarch(I386_GET_GSBASE, segbase);
+ __asm __volatile("mov %%gs:0, %0" : "=r" (segbase));
+# elif defined(__x86_64__)
+ // sysarch(AMD64_GET_FSBASE, segbase);
+ __asm __volatile("movq %%fs:0, %0" : "=r" (segbase));
+# else
+# error "unsupported CPU arch for FreeBSD platform"
+# endif
+ return segbase;
+}
-void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
- uptr *tls_addr, uptr *tls_size) {
-#ifndef SANITIZER_GO
-#if defined(__x86_64__) || defined(__i386__)
- *tls_addr = ThreadSelf();
- *tls_size = GetTlsSize();
- *tls_addr -= *tls_size;
- *tls_addr += kThreadDescriptorSize;
+uptr ThreadSelf() {
+ return (uptr)ThreadSelfSegbase()[2];
+}
+#endif // SANITIZER_FREEBSD
+
+static void GetTls(uptr *addr, uptr *size) {
+#if SANITIZER_LINUX
+# if defined(__x86_64__) || defined(__i386__)
+ *addr = ThreadSelf();
+ *size = GetTlsSize();
+ *addr -= *size;
+ *addr += ThreadDescriptorSize();
+# else
+ *addr = 0;
+ *size = 0;
+# endif
+#elif SANITIZER_FREEBSD
+ void** segbase = ThreadSelfSegbase();
+ *addr = 0;
+ *size = 0;
+ if (segbase != 0) {
+ // tcbalign = 16
+ // tls_size = round(tls_static_space, tcbalign);
+ // dtv = segbase[1];
+ // dtv[2] = segbase - tls_static_space;
+ void **dtv = (void**) segbase[1];
+ *addr = (uptr) dtv[2];
+ *size = (*addr == 0) ? 0 : ((uptr) segbase[0] - (uptr) dtv[2]);
+ }
#else
- *tls_addr = 0;
- *tls_size = 0;
+# error "Unknown OS"
#endif
+}
+
+uptr GetTlsSize() {
+#if SANITIZER_FREEBSD
+ uptr addr, size;
+ GetTls(&addr, &size);
+ return size;
+#else
+ return g_tls_size;
+#endif
+}
+
+void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
+ uptr *tls_addr, uptr *tls_size) {
+ GetTls(tls_addr, tls_size);
uptr stack_top, stack_bottom;
GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom);
@@ -258,19 +316,13 @@ void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
*tls_addr = *stk_addr + *stk_size;
}
}
-#else // SANITIZER_GO
- *stk_addr = 0;
- *stk_size = 0;
- *tls_addr = 0;
- *tls_size = 0;
-#endif // SANITIZER_GO
}
-void AdjustStackSizeLinux(void *attr_) {
+void AdjustStackSize(void *attr_) {
pthread_attr_t *attr = (pthread_attr_t *)attr_;
uptr stackaddr = 0;
size_t stacksize = 0;
- pthread_attr_getstack(attr, (void**)&stackaddr, &stacksize);
+ my_pthread_attr_getstack(attr, (void**)&stackaddr, &stacksize);
// GLibC will return (0 - stacksize) as the stack address in the case when
// stacksize is set, but stackaddr is not.
bool stack_set = (stackaddr != 0) && (stackaddr + stacksize != 0);
@@ -278,10 +330,11 @@ void AdjustStackSizeLinux(void *attr_) {
const uptr minstacksize = GetTlsSize() + 128*1024;
if (stacksize < minstacksize) {
if (!stack_set) {
- if (common_flags()->verbosity && stacksize != 0)
- Printf("Sanitizer: increasing stacksize %zu->%zu\n", stacksize,
- minstacksize);
- pthread_attr_setstacksize(attr, minstacksize);
+ if (stacksize != 0) {
+ VPrintf(1, "Sanitizer: increasing stacksize %zu->%zu\n", stacksize,
+ minstacksize);
+ pthread_attr_setstacksize(attr, minstacksize);
+ }
} else {
Printf("Sanitizer: pre-allocated stack size is insufficient: "
"%zu < %zu\n", stacksize, minstacksize);
@@ -293,10 +346,17 @@ void AdjustStackSizeLinux(void *attr_) {
#if SANITIZER_ANDROID
uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
string_predicate_t filter) {
- return 0;
+ MemoryMappingLayout memory_mapping(false);
+ return memory_mapping.DumpListOfModules(modules, max_modules, filter);
}
#else // SANITIZER_ANDROID
+# if !SANITIZER_FREEBSD
typedef ElfW(Phdr) Elf_Phdr;
+# elif SANITIZER_WORDSIZE == 32 && __FreeBSD_version <= 902001 // v9.2
+# define Elf_Phdr XElf32_Phdr
+# define dl_phdr_info xdl_phdr_info
+# define dl_iterate_phdr(c, b) xdl_iterate_phdr((c), (b))
+# endif
struct DlIteratePhdrData {
LoadedModule *modules;
@@ -310,16 +370,15 @@ static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *arg) {
DlIteratePhdrData *data = (DlIteratePhdrData*)arg;
if (data->current_n == data->max_n)
return 0;
- InternalScopedBuffer<char> module_name(kMaxPathLength);
- module_name.data()[0] = '\0';
+ InternalScopedString module_name(kMaxPathLength);
if (data->first) {
data->first = false;
// First module is the binary itself.
ReadBinaryName(module_name.data(), module_name.size());
} else if (info->dlpi_name) {
- internal_strncpy(module_name.data(), info->dlpi_name, module_name.size());
+ module_name.append("%s", info->dlpi_name);
}
- if (module_name.data()[0] == '\0')
+ if (module_name[0] == '\0')
return 0;
if (data->filter && !data->filter(module_name.data()))
return 0;
@@ -332,7 +391,8 @@ static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *arg) {
if (phdr->p_type == PT_LOAD) {
uptr cur_beg = info->dlpi_addr + phdr->p_vaddr;
uptr cur_end = cur_beg + phdr->p_memsz;
- cur_module->addAddressRange(cur_beg, cur_end);
+ bool executable = phdr->p_flags & PF_X;
+ cur_module->addAddressRange(cur_beg, cur_end, executable);
}
}
return 0;
@@ -347,6 +407,19 @@ uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
}
#endif // SANITIZER_ANDROID
+void PrepareForSandboxing(__sanitizer_sandbox_arguments *args) {
+ // Some kinds of sandboxes may forbid filesystem access, so we won't be able
+ // to read the file mappings from /proc/self/maps. Luckily, neither the
+ // process will be able to load additional libraries, so it's fine to use the
+ // cached mappings.
+ MemoryMappingLayout::CacheMemoryMappings();
+ // Same for /proc/self/exe in the symbolizer.
+#if !SANITIZER_GO
+ Symbolizer::GetOrInit()->PrepareForSandboxing();
+ CovPrepareForSandboxing(args);
+#endif
+}
+
} // namespace __sanitizer
-#endif // SANITIZER_LINUX
+#endif // SANITIZER_FREEBSD || SANITIZER_LINUX
diff --git a/lib/sanitizer_common/sanitizer_list.h b/lib/sanitizer_common/sanitizer_list.h
index f61d28f3d900..a47bc7d45e3e 100644
--- a/lib/sanitizer_common/sanitizer_list.h
+++ b/lib/sanitizer_common/sanitizer_list.h
@@ -26,6 +26,8 @@ namespace __sanitizer {
// non-zero-initialized objects before using.
template<class Item>
struct IntrusiveList {
+ friend class Iterator;
+
void clear() {
first_ = last_ = 0;
size_ = 0;
@@ -113,6 +115,21 @@ struct IntrusiveList {
}
}
+ class Iterator {
+ public:
+ explicit Iterator(IntrusiveList<Item> *list)
+ : list_(list), current_(list->first_) { }
+ Item *next() {
+ Item *ret = current_;
+ if (current_) current_ = current_->next;
+ return ret;
+ }
+ bool hasNext() const { return current_ != 0; }
+ private:
+ IntrusiveList<Item> *list_;
+ Item *current_;
+ };
+
// private, don't use directly.
uptr size_;
Item *first_;
diff --git a/lib/sanitizer_common/sanitizer_mac.cc b/lib/sanitizer_common/sanitizer_mac.cc
index 87ad8b53c6c9..98c5b94112cf 100644
--- a/lib/sanitizer_common/sanitizer_mac.cc
+++ b/lib/sanitizer_common/sanitizer_mac.cc
@@ -7,9 +7,8 @@
//
//===----------------------------------------------------------------------===//
//
-// This file is shared between AddressSanitizer and ThreadSanitizer
-// run-time libraries and implements mac-specific functions from
-// sanitizer_libc.h.
+// This file is shared between various sanitizers' runtime libraries and
+// implements OSX-specific functions.
//===----------------------------------------------------------------------===//
#include "sanitizer_platform.h"
@@ -23,20 +22,22 @@
#include <stdio.h>
#include "sanitizer_common.h"
+#include "sanitizer_flags.h"
#include "sanitizer_internal_defs.h"
#include "sanitizer_libc.h"
+#include "sanitizer_mac.h"
#include "sanitizer_placement_new.h"
#include "sanitizer_procmaps.h"
#include <crt_externs.h> // for _NSGetEnviron
#include <fcntl.h>
-#include <mach-o/dyld.h>
-#include <mach-o/loader.h>
#include <pthread.h>
#include <sched.h>
+#include <signal.h>
#include <sys/mman.h>
#include <sys/resource.h>
#include <sys/stat.h>
+#include <sys/sysctl.h>
#include <sys/types.h>
#include <unistd.h>
#include <libkern/OSAtomic.h>
@@ -120,6 +121,24 @@ uptr internal_getpid() {
return getpid();
}
+int internal_sigaction(int signum, const void *act, void *oldact) {
+ return sigaction(signum,
+ (struct sigaction *)act, (struct sigaction *)oldact);
+}
+
+int internal_fork() {
+ // TODO(glider): this may call user's pthread_atfork() handlers which is bad.
+ return fork();
+}
+
+uptr internal_rename(const char *oldpath, const char *newpath) {
+ return rename(oldpath, newpath);
+}
+
+uptr internal_ftruncate(fd_t fd, uptr size) {
+ return ftruncate(fd, size);
+}
+
// ----------------- sanitizer_common.h
bool FileExists(const char *filename) {
struct stat st;
@@ -138,6 +157,20 @@ void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
CHECK(stack_top);
CHECK(stack_bottom);
uptr stacksize = pthread_get_stacksize_np(pthread_self());
+ // pthread_get_stacksize_np() returns an incorrect stack size for the main
+ // thread on Mavericks. See
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=261
+ if ((GetMacosVersion() >= MACOS_VERSION_MAVERICKS) && at_initialization &&
+ stacksize == (1 << 19)) {
+ struct rlimit rl;
+ CHECK_EQ(getrlimit(RLIMIT_STACK, &rl), 0);
+ // Most often rl.rlim_cur will be the desired 8M.
+ if (rl.rlim_cur < kMaxThreadStackSize) {
+ stacksize = rl.rlim_cur;
+ } else {
+ stacksize = kMaxThreadStackSize;
+ }
+ }
void *stackaddr = pthread_get_stackaddr_np(pthread_self());
*stack_top = (uptr)stackaddr;
*stack_bottom = *stack_top - stacksize;
@@ -171,7 +204,8 @@ void ReExec() {
UNIMPLEMENTED();
}
-void PrepareForSandboxing() {
+void PrepareForSandboxing(__sanitizer_sandbox_arguments *args) {
+ (void)args;
// Nothing here for now.
}
@@ -179,148 +213,6 @@ uptr GetPageSize() {
return sysconf(_SC_PAGESIZE);
}
-// ----------------- sanitizer_procmaps.h
-
-MemoryMappingLayout::MemoryMappingLayout(bool cache_enabled) {
- Reset();
-}
-
-MemoryMappingLayout::~MemoryMappingLayout() {
-}
-
-// More information about Mach-O headers can be found in mach-o/loader.h
-// Each Mach-O image has a header (mach_header or mach_header_64) starting with
-// a magic number, and a list of linker load commands directly following the
-// header.
-// A load command is at least two 32-bit words: the command type and the
-// command size in bytes. We're interested only in segment load commands
-// (LC_SEGMENT and LC_SEGMENT_64), which tell that a part of the file is mapped
-// into the task's address space.
-// The |vmaddr|, |vmsize| and |fileoff| fields of segment_command or
-// segment_command_64 correspond to the memory address, memory size and the
-// file offset of the current memory segment.
-// Because these fields are taken from the images as is, one needs to add
-// _dyld_get_image_vmaddr_slide() to get the actual addresses at runtime.
-
-void MemoryMappingLayout::Reset() {
- // Count down from the top.
- // TODO(glider): as per man 3 dyld, iterating over the headers with
- // _dyld_image_count is thread-unsafe. We need to register callbacks for
- // adding and removing images which will invalidate the MemoryMappingLayout
- // state.
- current_image_ = _dyld_image_count();
- current_load_cmd_count_ = -1;
- current_load_cmd_addr_ = 0;
- current_magic_ = 0;
- current_filetype_ = 0;
-}
-
-// static
-void MemoryMappingLayout::CacheMemoryMappings() {
- // No-op on Mac for now.
-}
-
-void MemoryMappingLayout::LoadFromCache() {
- // No-op on Mac for now.
-}
-
-// Next and NextSegmentLoad were inspired by base/sysinfo.cc in
-// Google Perftools, http://code.google.com/p/google-perftools.
-
-// NextSegmentLoad scans the current image for the next segment load command
-// and returns the start and end addresses and file offset of the corresponding
-// segment.
-// Note that the segment addresses are not necessarily sorted.
-template<u32 kLCSegment, typename SegmentCommand>
-bool MemoryMappingLayout::NextSegmentLoad(
- uptr *start, uptr *end, uptr *offset,
- char filename[], uptr filename_size, uptr *protection) {
- if (protection)
- UNIMPLEMENTED();
- const char* lc = current_load_cmd_addr_;
- current_load_cmd_addr_ += ((const load_command *)lc)->cmdsize;
- if (((const load_command *)lc)->cmd == kLCSegment) {
- const sptr dlloff = _dyld_get_image_vmaddr_slide(current_image_);
- const SegmentCommand* sc = (const SegmentCommand *)lc;
- if (start) *start = sc->vmaddr + dlloff;
- if (end) *end = sc->vmaddr + sc->vmsize + dlloff;
- if (offset) {
- if (current_filetype_ == /*MH_EXECUTE*/ 0x2) {
- *offset = sc->vmaddr;
- } else {
- *offset = sc->fileoff;
- }
- }
- if (filename) {
- internal_strncpy(filename, _dyld_get_image_name(current_image_),
- filename_size);
- }
- return true;
- }
- return false;
-}
-
-bool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset,
- char filename[], uptr filename_size,
- uptr *protection) {
- for (; current_image_ >= 0; current_image_--) {
- const mach_header* hdr = _dyld_get_image_header(current_image_);
- if (!hdr) continue;
- if (current_load_cmd_count_ < 0) {
- // Set up for this image;
- current_load_cmd_count_ = hdr->ncmds;
- current_magic_ = hdr->magic;
- current_filetype_ = hdr->filetype;
- switch (current_magic_) {
-#ifdef MH_MAGIC_64
- case MH_MAGIC_64: {
- current_load_cmd_addr_ = (char*)hdr + sizeof(mach_header_64);
- break;
- }
-#endif
- case MH_MAGIC: {
- current_load_cmd_addr_ = (char*)hdr + sizeof(mach_header);
- break;
- }
- default: {
- continue;
- }
- }
- }
-
- for (; current_load_cmd_count_ >= 0; current_load_cmd_count_--) {
- switch (current_magic_) {
- // current_magic_ may be only one of MH_MAGIC, MH_MAGIC_64.
-#ifdef MH_MAGIC_64
- case MH_MAGIC_64: {
- if (NextSegmentLoad<LC_SEGMENT_64, struct segment_command_64>(
- start, end, offset, filename, filename_size, protection))
- return true;
- break;
- }
-#endif
- case MH_MAGIC: {
- if (NextSegmentLoad<LC_SEGMENT, struct segment_command>(
- start, end, offset, filename, filename_size, protection))
- return true;
- break;
- }
- }
- }
- // If we get here, no more load_cmd's in this image talk about
- // segments. Go on to the next image.
- }
- return false;
-}
-
-bool MemoryMappingLayout::GetObjectNameAndOffset(uptr addr, uptr *offset,
- char filename[],
- uptr filename_size,
- uptr *protection) {
- return IterateForObjectNameAndOffset(addr, offset, filename, filename_size,
- protection);
-}
-
BlockingMutex::BlockingMutex(LinkerInitialized) {
// We assume that OS_SPINLOCK_INIT is zero
}
@@ -379,32 +271,54 @@ void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
string_predicate_t filter) {
MemoryMappingLayout memory_mapping(false);
- memory_mapping.Reset();
- uptr cur_beg, cur_end, cur_offset;
- InternalScopedBuffer<char> module_name(kMaxPathLength);
- uptr n_modules = 0;
- for (uptr i = 0;
- n_modules < max_modules &&
- memory_mapping.Next(&cur_beg, &cur_end, &cur_offset,
- module_name.data(), module_name.size(), 0);
- i++) {
- const char *cur_name = module_name.data();
- if (cur_name[0] == '\0')
- continue;
- if (filter && !filter(cur_name))
- continue;
- LoadedModule *cur_module = 0;
- if (n_modules > 0 &&
- 0 == internal_strcmp(cur_name, modules[n_modules - 1].full_name())) {
- cur_module = &modules[n_modules - 1];
- } else {
- void *mem = &modules[n_modules];
- cur_module = new(mem) LoadedModule(cur_name, cur_beg);
- n_modules++;
+ return memory_mapping.DumpListOfModules(modules, max_modules, filter);
+}
+
+bool IsDeadlySignal(int signum) {
+ return (signum == SIGSEGV || signum == SIGBUS) && common_flags()->handle_segv;
+}
+
+MacosVersion cached_macos_version = MACOS_VERSION_UNINITIALIZED;
+
+MacosVersion GetMacosVersionInternal() {
+ int mib[2] = { CTL_KERN, KERN_OSRELEASE };
+ char version[100];
+ uptr len = 0, maxlen = sizeof(version) / sizeof(version[0]);
+ for (uptr i = 0; i < maxlen; i++) version[i] = '\0';
+ // Get the version length.
+ CHECK_NE(sysctl(mib, 2, 0, &len, 0, 0), -1);
+ CHECK_LT(len, maxlen);
+ CHECK_NE(sysctl(mib, 2, version, &len, 0, 0), -1);
+ switch (version[0]) {
+ case '9': return MACOS_VERSION_LEOPARD;
+ case '1': {
+ switch (version[1]) {
+ case '0': return MACOS_VERSION_SNOW_LEOPARD;
+ case '1': return MACOS_VERSION_LION;
+ case '2': return MACOS_VERSION_MOUNTAIN_LION;
+ case '3': return MACOS_VERSION_MAVERICKS;
+ case '4': return MACOS_VERSION_YOSEMITE;
+ default: return MACOS_VERSION_UNKNOWN;
+ }
}
- cur_module->addAddressRange(cur_beg, cur_end);
+ default: return MACOS_VERSION_UNKNOWN;
+ }
+}
+
+MacosVersion GetMacosVersion() {
+ atomic_uint32_t *cache =
+ reinterpret_cast<atomic_uint32_t*>(&cached_macos_version);
+ MacosVersion result =
+ static_cast<MacosVersion>(atomic_load(cache, memory_order_acquire));
+ if (result == MACOS_VERSION_UNINITIALIZED) {
+ result = GetMacosVersionInternal();
+ atomic_store(cache, result, memory_order_release);
}
- return n_modules;
+ return result;
+}
+
+uptr GetRSS() {
+ return 0;
}
} // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_mac.h b/lib/sanitizer_common/sanitizer_mac.h
new file mode 100644
index 000000000000..3ed0ed3b00c2
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_mac.h
@@ -0,0 +1,37 @@
+//===-- sanitizer_mac.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 shared between various sanitizers' runtime libraries and
+// provides definitions for OSX-specific functions.
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_MAC_H
+#define SANITIZER_MAC_H
+
+#include "sanitizer_platform.h"
+#if SANITIZER_MAC
+
+namespace __sanitizer {
+
+enum MacosVersion {
+ MACOS_VERSION_UNINITIALIZED = 0,
+ MACOS_VERSION_UNKNOWN,
+ MACOS_VERSION_LEOPARD,
+ MACOS_VERSION_SNOW_LEOPARD,
+ MACOS_VERSION_LION,
+ MACOS_VERSION_MOUNTAIN_LION,
+ MACOS_VERSION_MAVERICKS,
+ MACOS_VERSION_YOSEMITE,
+};
+
+MacosVersion GetMacosVersion();
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_MAC
+#endif // SANITIZER_MAC_H
diff --git a/lib/sanitizer_common/sanitizer_mutex.h b/lib/sanitizer_common/sanitizer_mutex.h
index e812fce90598..c7589f76ed3b 100644
--- a/lib/sanitizer_common/sanitizer_mutex.h
+++ b/lib/sanitizer_common/sanitizer_mutex.h
@@ -83,6 +83,88 @@ class BlockingMutex {
uptr owner_; // for debugging
};
+// Reader-writer spin mutex.
+class RWMutex {
+ public:
+ RWMutex() {
+ atomic_store(&state_, kUnlocked, memory_order_relaxed);
+ }
+
+ ~RWMutex() {
+ CHECK_EQ(atomic_load(&state_, memory_order_relaxed), kUnlocked);
+ }
+
+ void Lock() {
+ u32 cmp = kUnlocked;
+ if (atomic_compare_exchange_strong(&state_, &cmp, kWriteLock,
+ memory_order_acquire))
+ return;
+ LockSlow();
+ }
+
+ void Unlock() {
+ u32 prev = atomic_fetch_sub(&state_, kWriteLock, memory_order_release);
+ DCHECK_NE(prev & kWriteLock, 0);
+ (void)prev;
+ }
+
+ void ReadLock() {
+ u32 prev = atomic_fetch_add(&state_, kReadLock, memory_order_acquire);
+ if ((prev & kWriteLock) == 0)
+ return;
+ ReadLockSlow();
+ }
+
+ void ReadUnlock() {
+ u32 prev = atomic_fetch_sub(&state_, kReadLock, memory_order_release);
+ DCHECK_EQ(prev & kWriteLock, 0);
+ DCHECK_GT(prev & ~kWriteLock, 0);
+ (void)prev;
+ }
+
+ void CheckLocked() {
+ CHECK_NE(atomic_load(&state_, memory_order_relaxed), kUnlocked);
+ }
+
+ private:
+ atomic_uint32_t state_;
+
+ enum {
+ kUnlocked = 0,
+ kWriteLock = 1,
+ kReadLock = 2
+ };
+
+ void NOINLINE LockSlow() {
+ for (int i = 0;; i++) {
+ if (i < 10)
+ proc_yield(10);
+ else
+ internal_sched_yield();
+ u32 cmp = atomic_load(&state_, memory_order_relaxed);
+ if (cmp == kUnlocked &&
+ atomic_compare_exchange_weak(&state_, &cmp, kWriteLock,
+ memory_order_acquire))
+ return;
+ }
+ }
+
+ void NOINLINE ReadLockSlow() {
+ for (int i = 0;; i++) {
+ if (i < 10)
+ proc_yield(10);
+ else
+ internal_sched_yield();
+ u32 prev = atomic_load(&state_, memory_order_acquire);
+ if ((prev & kWriteLock) == 0)
+ return;
+ }
+ }
+
+ RWMutex(const RWMutex&);
+ void operator = (const RWMutex&);
+};
+
template<typename MutexType>
class GenericScopedLock {
public:
@@ -123,6 +205,8 @@ class GenericScopedReadLock {
typedef GenericScopedLock<StaticSpinMutex> SpinMutexLock;
typedef GenericScopedLock<BlockingMutex> BlockingMutexLock;
+typedef GenericScopedLock<RWMutex> RWMutexLock;
+typedef GenericScopedReadLock<RWMutex> RWMutexReadLock;
} // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_persistent_allocator.cc b/lib/sanitizer_common/sanitizer_persistent_allocator.cc
new file mode 100644
index 000000000000..5fa533a70861
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_persistent_allocator.cc
@@ -0,0 +1,19 @@
+//===-- sanitizer_persistent_allocator.cc -----------------------*- 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 shared between AddressSanitizer and ThreadSanitizer
+// run-time libraries.
+//===----------------------------------------------------------------------===//
+#include "sanitizer_persistent_allocator.h"
+
+namespace __sanitizer {
+
+PersistentAllocator thePersistentAllocator;
+
+} // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_persistent_allocator.h b/lib/sanitizer_common/sanitizer_persistent_allocator.h
new file mode 100644
index 000000000000..326406b12bfb
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_persistent_allocator.h
@@ -0,0 +1,71 @@
+//===-- sanitizer_persistent_allocator.h ------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// A fast memory allocator that does not support free() nor realloc().
+// All allocations are forever.
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_PERSISTENT_ALLOCATOR_H
+#define SANITIZER_PERSISTENT_ALLOCATOR_H
+
+#include "sanitizer_internal_defs.h"
+#include "sanitizer_mutex.h"
+#include "sanitizer_atomic.h"
+#include "sanitizer_common.h"
+
+namespace __sanitizer {
+
+class PersistentAllocator {
+ public:
+ void *alloc(uptr size);
+
+ private:
+ void *tryAlloc(uptr size);
+ StaticSpinMutex mtx; // Protects alloc of new blocks for region allocator.
+ atomic_uintptr_t region_pos; // Region allocator for Node's.
+ atomic_uintptr_t region_end;
+};
+
+inline void *PersistentAllocator::tryAlloc(uptr size) {
+ // Optimisic lock-free allocation, essentially try to bump the region ptr.
+ for (;;) {
+ uptr cmp = atomic_load(&region_pos, memory_order_acquire);
+ uptr end = atomic_load(&region_end, memory_order_acquire);
+ if (cmp == 0 || cmp + size > end) return 0;
+ if (atomic_compare_exchange_weak(&region_pos, &cmp, cmp + size,
+ memory_order_acquire))
+ return (void *)cmp;
+ }
+}
+
+inline void *PersistentAllocator::alloc(uptr size) {
+ // First, try to allocate optimisitically.
+ void *s = tryAlloc(size);
+ if (s) return s;
+ // If failed, lock, retry and alloc new superblock.
+ SpinMutexLock l(&mtx);
+ for (;;) {
+ s = tryAlloc(size);
+ if (s) return s;
+ atomic_store(&region_pos, 0, memory_order_relaxed);
+ uptr allocsz = 64 * 1024;
+ if (allocsz < size) allocsz = size;
+ uptr mem = (uptr)MmapOrDie(allocsz, "stack depot");
+ atomic_store(&region_end, mem + allocsz, memory_order_release);
+ atomic_store(&region_pos, mem, memory_order_release);
+ }
+}
+
+extern PersistentAllocator thePersistentAllocator;
+inline void *PersistentAlloc(uptr sz) {
+ return thePersistentAllocator.alloc(sz);
+}
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_PERSISTENT_ALLOCATOR_H
diff --git a/lib/sanitizer_common/sanitizer_platform.h b/lib/sanitizer_common/sanitizer_platform.h
index fce721e300fb..6f8cd30bf4d9 100644
--- a/lib/sanitizer_common/sanitizer_platform.h
+++ b/lib/sanitizer_common/sanitizer_platform.h
@@ -13,7 +13,8 @@
#ifndef SANITIZER_PLATFORM_H
#define SANITIZER_PLATFORM_H
-#if !defined(__linux__) && !defined(__APPLE__) && !defined(_WIN32)
+#if !defined(__linux__) && !defined(__FreeBSD__) && \
+ !defined(__APPLE__) && !defined(_WIN32)
# error "This operating system is not supported"
#endif
@@ -23,6 +24,12 @@
# define SANITIZER_LINUX 0
#endif
+#if defined(__FreeBSD__)
+# define SANITIZER_FREEBSD 1
+#else
+# define SANITIZER_FREEBSD 0
+#endif
+
#if defined(__APPLE__)
# define SANITIZER_MAC 1
# include <TargetConditionals.h>
@@ -42,12 +49,72 @@
# define SANITIZER_WINDOWS 0
#endif
-#if defined(__ANDROID__) || defined(ANDROID)
+#if defined(__ANDROID__)
# define SANITIZER_ANDROID 1
#else
# define SANITIZER_ANDROID 0
#endif
-#define SANITIZER_POSIX (SANITIZER_LINUX || SANITIZER_MAC)
+#define SANITIZER_POSIX (SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_MAC)
+
+#if __LP64__ || defined(_WIN64)
+# define SANITIZER_WORDSIZE 64
+#else
+# define SANITIZER_WORDSIZE 32
+#endif
+
+#if SANITIZER_WORDSIZE == 64
+# define FIRST_32_SECOND_64(a, b) (b)
+#else
+# define FIRST_32_SECOND_64(a, b) (a)
+#endif
+
+#if defined(__x86_64__) && !defined(_LP64)
+# define SANITIZER_X32 1
+#else
+# define SANITIZER_X32 0
+#endif
+
+// By default we allow to use SizeClassAllocator64 on 64-bit platform.
+// But in some cases (e.g. AArch64's 39-bit address space) SizeClassAllocator64
+// does not work well and we need to fallback to SizeClassAllocator32.
+// For such platforms build this code with -DSANITIZER_CAN_USE_ALLOCATOR64=0 or
+// change the definition of SANITIZER_CAN_USE_ALLOCATOR64 here.
+#ifndef SANITIZER_CAN_USE_ALLOCATOR64
+# if defined(__aarch64__) || defined(__mips64)
+# define SANITIZER_CAN_USE_ALLOCATOR64 0
+# else
+# define SANITIZER_CAN_USE_ALLOCATOR64 (SANITIZER_WORDSIZE == 64)
+# endif
+#endif
+
+// The range of addresses which can be returned my mmap.
+// FIXME: this value should be different on different platforms,
+// e.g. on AArch64 it is most likely (1ULL << 39). Larger values will still work
+// but will consume more memory for TwoLevelByteMap.
+#if defined(__aarch64__)
+# define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 39)
+#elif defined(__mips__)
+# define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 40)
+#else
+# define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 47)
+#endif
+
+// The AArch64 linux port uses the canonical syscall set as mandated by
+// the upstream linux community for all new ports. Other ports may still
+// use legacy syscalls.
+#ifndef SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
+# if defined(__aarch64__) && SANITIZER_LINUX
+# define SANITIZER_USES_CANONICAL_LINUX_SYSCALLS 1
+# else
+# define SANITIZER_USES_CANONICAL_LINUX_SYSCALLS 0
+# endif
+#endif
+
+#ifdef __mips__
+# define SANITIZER_POINTER_FORMAT_LENGTH FIRST_32_SECOND_64(8, 10)
+#else
+# define SANITIZER_POINTER_FORMAT_LENGTH FIRST_32_SECOND_64(8, 12)
+#endif
#endif // SANITIZER_PLATFORM_H
diff --git a/lib/sanitizer_common/sanitizer_platform_interceptors.h b/lib/sanitizer_common/sanitizer_platform_interceptors.h
index 78d1f5adef7b..7ca88fa972f3 100644
--- a/lib/sanitizer_common/sanitizer_platform_interceptors.h
+++ b/lib/sanitizer_common/sanitizer_platform_interceptors.h
@@ -29,6 +29,12 @@
# define SI_LINUX_NOT_ANDROID 0
#endif
+#if SANITIZER_FREEBSD
+# define SI_FREEBSD 1
+#else
+# define SI_FREEBSD 0
+#endif
+
#if SANITIZER_LINUX
# define SI_LINUX 1
#else
@@ -47,13 +53,16 @@
# define SI_IOS 0
#endif
-# define SANITIZER_INTERCEPT_STRCMP 1
-# define SANITIZER_INTERCEPT_STRCASECMP SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_STRCMP 1
+#define SANITIZER_INTERCEPT_TEXTDOMAIN SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_STRCASECMP SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_MEMCHR 1
+#define SANITIZER_INTERCEPT_MEMRCHR SI_LINUX
-# define SANITIZER_INTERCEPT_READ SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_PREAD SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_WRITE SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_PWRITE SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_READ SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_PREAD SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_WRITE SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_PWRITE SI_NOT_WINDOWS
#define SANITIZER_INTERCEPT_PREAD64 SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_PWRITE64 SI_LINUX_NOT_ANDROID
@@ -66,105 +75,166 @@
#define SANITIZER_INTERCEPT_PREADV64 SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_PWRITEV64 SI_LINUX_NOT_ANDROID
-# define SANITIZER_INTERCEPT_PRCTL SI_LINUX
-
-# define SANITIZER_INTERCEPT_LOCALTIME_AND_FRIENDS SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_STRPTIME SI_NOT_WINDOWS
-
-# define SANITIZER_INTERCEPT_SCANF SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_ISOC99_SCANF SI_LINUX
-
-# define SANITIZER_INTERCEPT_FREXP 1
-# define SANITIZER_INTERCEPT_FREXPF_FREXPL SI_NOT_WINDOWS
-
-# define SANITIZER_INTERCEPT_GETPWNAM_AND_FRIENDS SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_GETPWNAM_R_AND_FRIENDS \
- SI_MAC || SI_LINUX_NOT_ANDROID
-# define SANITIZER_INTERCEPT_CLOCK_GETTIME SI_LINUX
-# define SANITIZER_INTERCEPT_GETITIMER SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_TIME SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_GLOB SI_LINUX_NOT_ANDROID
-# define SANITIZER_INTERCEPT_WAIT SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_INET SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_PTHREAD_GETSCHEDPARAM SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_GETADDRINFO SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_GETNAMEINFO SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_GETSOCKNAME SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_GETHOSTBYNAME SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_GETHOSTBYNAME_R SI_LINUX
-# define SANITIZER_INTERCEPT_GETSOCKOPT SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_ACCEPT SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_ACCEPT4 SI_LINUX
-# define SANITIZER_INTERCEPT_MODF SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_RECVMSG SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_GETPEERNAME SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_IOCTL SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_INET_ATON SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_SYSINFO SI_LINUX
-# define SANITIZER_INTERCEPT_READDIR SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_READDIR64 SI_LINUX_NOT_ANDROID
-# define SANITIZER_INTERCEPT_PTRACE SI_LINUX_NOT_ANDROID && \
- (defined(__i386) || defined (__x86_64)) // NOLINT
-# define SANITIZER_INTERCEPT_SETLOCALE SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_GETCWD SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_GET_CURRENT_DIR_NAME SI_LINUX
-# define SANITIZER_INTERCEPT_STRTOIMAX SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_MBSTOWCS SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_MBSNRTOWCS SI_MAC || SI_LINUX_NOT_ANDROID
-# define SANITIZER_INTERCEPT_WCSTOMBS SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_WCSNRTOMBS SI_MAC || SI_LINUX_NOT_ANDROID
-# define SANITIZER_INTERCEPT_TCGETATTR SI_LINUX
-# define SANITIZER_INTERCEPT_REALPATH SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_CANONICALIZE_FILE_NAME SI_LINUX_NOT_ANDROID
-# define SANITIZER_INTERCEPT_CONFSTR SI_MAC || SI_LINUX_NOT_ANDROID
-# define SANITIZER_INTERCEPT_SCHED_GETAFFINITY SI_LINUX_NOT_ANDROID
-# define SANITIZER_INTERCEPT_STRERROR SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_STRERROR_R SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_SCANDIR SI_LINUX_NOT_ANDROID
-# define SANITIZER_INTERCEPT_SCANDIR64 SI_LINUX_NOT_ANDROID
-# define SANITIZER_INTERCEPT_GETGROUPS SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_POLL SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_PPOLL SI_LINUX_NOT_ANDROID
-# define SANITIZER_INTERCEPT_WORDEXP SI_MAC || SI_LINUX_NOT_ANDROID
-# define SANITIZER_INTERCEPT_SIGWAIT SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_SIGWAITINFO SI_LINUX_NOT_ANDROID
-# define SANITIZER_INTERCEPT_SIGTIMEDWAIT SI_LINUX_NOT_ANDROID
-# define SANITIZER_INTERCEPT_SIGSETOPS SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_SIGPENDING SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_SIGPROCMASK SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_BACKTRACE SI_LINUX_NOT_ANDROID
-# define SANITIZER_INTERCEPT_GETMNTENT SI_LINUX
-# define SANITIZER_INTERCEPT_GETMNTENT_R SI_LINUX_NOT_ANDROID
-# define SANITIZER_INTERCEPT_STATFS SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_STATFS64 \
- (SI_MAC && !SI_IOS) || SI_LINUX_NOT_ANDROID
-# define SANITIZER_INTERCEPT_STATVFS SI_LINUX_NOT_ANDROID
-# define SANITIZER_INTERCEPT_STATVFS64 SI_LINUX_NOT_ANDROID
-# define SANITIZER_INTERCEPT_INITGROUPS SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_ETHER SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_ETHER_R SI_LINUX_NOT_ANDROID
-# define SANITIZER_INTERCEPT_SHMCTL SI_LINUX_NOT_ANDROID
-# define SANITIZER_INTERCEPT_RANDOM_R SI_LINUX_NOT_ANDROID
-# define SANITIZER_INTERCEPT_PTHREAD_ATTR_GET SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_PTHREAD_ATTR_GETINHERITSCHED \
- SI_MAC || SI_LINUX_NOT_ANDROID
-# define SANITIZER_INTERCEPT_PTHREAD_ATTR_GETAFFINITY_NP SI_LINUX_NOT_ANDROID
-# define SANITIZER_INTERCEPT_TMPNAM SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_TMPNAM_R SI_LINUX_NOT_ANDROID
-# define SANITIZER_INTERCEPT_TEMPNAM SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_SINCOS SI_LINUX
-# define SANITIZER_INTERCEPT_REMQUO SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_LGAMMA SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_LGAMMA_R SI_LINUX
-# define SANITIZER_INTERCEPT_DRAND48_R SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_PRCTL SI_LINUX
-// FIXME: getline seems to be available on OSX 10.7
-# define SANITIZER_INTERCEPT_GETLINE SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_LOCALTIME_AND_FRIENDS SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_STRPTIME SI_NOT_WINDOWS
+
+#define SANITIZER_INTERCEPT_SCANF SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_ISOC99_SCANF SI_LINUX_NOT_ANDROID
+
+#ifndef SANITIZER_INTERCEPT_PRINTF
+# define SANITIZER_INTERCEPT_PRINTF SI_NOT_WINDOWS
+# define SANITIZER_INTERCEPT_ISOC99_PRINTF SI_LINUX_NOT_ANDROID
+#endif
-# define SANITIZER_INTERCEPT__EXIT SI_LINUX
+#define SANITIZER_INTERCEPT_FREXP 1
+#define SANITIZER_INTERCEPT_FREXPF_FREXPL SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_PHTREAD_MUTEX SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_PTHREAD_COND SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_PTHREAD_SETNAME_NP SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_GETPWNAM_AND_FRIENDS SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_GETPWNAM_R_AND_FRIENDS \
+ SI_MAC || SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_GETPWENT SI_MAC || SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_FGETPWENT SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_GETPWENT_R SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_SETPWENT SI_MAC || SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_CLOCK_GETTIME SI_LINUX
+#define SANITIZER_INTERCEPT_GETITIMER SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_TIME SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_GLOB SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_WAIT SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_INET SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_PTHREAD_GETSCHEDPARAM SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_GETADDRINFO SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_GETNAMEINFO SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_GETSOCKNAME SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_GETHOSTBYNAME SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_GETHOSTBYNAME_R SI_LINUX
+#define SANITIZER_INTERCEPT_GETHOSTBYNAME2_R SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_GETHOSTBYADDR_R SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_GETHOSTENT_R SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_GETSOCKOPT SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_ACCEPT SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_ACCEPT4 SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_MODF SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_RECVMSG SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_GETPEERNAME SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_IOCTL SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_INET_ATON SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_SYSINFO SI_LINUX
+#define SANITIZER_INTERCEPT_READDIR SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_READDIR64 SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_PTRACE SI_LINUX_NOT_ANDROID && \
+ (defined(__i386) || defined (__x86_64)) // NOLINT
+#define SANITIZER_INTERCEPT_SETLOCALE SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_GETCWD SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_GET_CURRENT_DIR_NAME SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_STRTOIMAX SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_MBSTOWCS SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_MBSNRTOWCS SI_MAC || SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_WCSTOMBS SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_WCSNRTOMBS SI_MAC || SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_TCGETATTR SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_REALPATH SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_CANONICALIZE_FILE_NAME SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_CONFSTR SI_MAC || SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_SCHED_GETAFFINITY SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_STRERROR SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_STRERROR_R SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_XPG_STRERROR_R SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_SCANDIR SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_SCANDIR64 SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_GETGROUPS SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_POLL SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_PPOLL SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_WORDEXP (SI_MAC && !SI_IOS) || SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_SIGWAIT SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_SIGWAITINFO SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_SIGTIMEDWAIT SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_SIGSETOPS \
+ SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_SIGPENDING SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_SIGPROCMASK SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_BACKTRACE SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_GETMNTENT SI_LINUX
+#define SANITIZER_INTERCEPT_GETMNTENT_R SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_STATFS SI_MAC || SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_STATFS64 \
+ (SI_MAC && !SI_IOS) || SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_STATVFS SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_STATVFS64 SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_INITGROUPS SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_ETHER_NTOA_ATON SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_ETHER_HOST SI_MAC || SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_ETHER_R SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_SHMCTL \
+ ((SI_FREEBSD || SI_LINUX_NOT_ANDROID) && SANITIZER_WORDSIZE == 64)
+#define SANITIZER_INTERCEPT_RANDOM_R SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_PTHREAD_ATTR_GET SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_PTHREAD_ATTR_GETINHERITSCHED \
+ SI_MAC || SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_PTHREAD_ATTR_GETAFFINITY_NP SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETPSHARED SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETTYPE SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETPROTOCOL \
+ SI_MAC || SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETPRIOCEILING \
+ SI_MAC || SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETROBUST SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETROBUST_NP SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_PTHREAD_RWLOCKATTR_GETPSHARED SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_PTHREAD_RWLOCKATTR_GETKIND_NP SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_PTHREAD_CONDATTR_GETPSHARED SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_PTHREAD_CONDATTR_GETCLOCK SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_PTHREAD_BARRIERATTR_GETPSHARED SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_TMPNAM SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_TMPNAM_R SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_TEMPNAM SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_SINCOS SI_LINUX
+#define SANITIZER_INTERCEPT_REMQUO SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_LGAMMA SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_LGAMMA_R SI_LINUX
+#define SANITIZER_INTERCEPT_LGAMMAL_R SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_DRAND48_R SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_RAND_R SI_MAC || SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_ICONV SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_TIMES SI_NOT_WINDOWS
+
+// FIXME: getline seems to be available on OSX 10.7
+#define SANITIZER_INTERCEPT_GETLINE SI_LINUX_NOT_ANDROID
+
+#define SANITIZER_INTERCEPT__EXIT SI_LINUX || SI_FREEBSD
+
+#define SANITIZER_INTERCEPT_PHTREAD_MUTEX SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_PTHREAD_SETNAME_NP \
+ SI_FREEBSD || SI_LINUX_NOT_ANDROID
+
+#define SANITIZER_INTERCEPT_TLS_GET_ADDR \
+ SI_FREEBSD || SI_LINUX_NOT_ANDROID
+
+#define SANITIZER_INTERCEPT_LISTXATTR SI_LINUX
+#define SANITIZER_INTERCEPT_GETXATTR SI_LINUX
+#define SANITIZER_INTERCEPT_GETRESID SI_LINUX
+#define SANITIZER_INTERCEPT_GETIFADDRS SI_LINUX_NOT_ANDROID || SI_MAC
+#define SANITIZER_INTERCEPT_IF_INDEXTONAME SI_LINUX_NOT_ANDROID || SI_MAC
+#define SANITIZER_INTERCEPT_CAPGET SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_AEABI_MEM SI_LINUX && defined(__arm__)
+#define SANITIZER_INTERCEPT___BZERO SI_MAC
+#define SANITIZER_INTERCEPT_FTIME SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_XDR SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_TSEARCH SI_LINUX_NOT_ANDROID || SI_MAC
+#define SANITIZER_INTERCEPT_LIBIO_INTERNALS SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_FOPEN SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_FOPEN64 SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_OPEN_MEMSTREAM SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_OBSTACK SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_FFLUSH SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_FCLOSE SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_DLOPEN_DLCLOSE \
+ SI_FREEBSD || SI_LINUX_NOT_ANDROID || SI_MAC
+#define SANITIZER_INTERCEPT_GETPASS SI_LINUX_NOT_ANDROID || SI_MAC
+#define SANITIZER_INTERCEPT_TIMERFD SI_LINUX_NOT_ANDROID
+
+#define SANITIZER_INTERCEPT_MLOCKX SI_NOT_WINDOWS
#endif // #ifndef SANITIZER_PLATFORM_INTERCEPTORS_H
diff --git a/lib/sanitizer_common/sanitizer_platform_limits_linux.cc b/lib/sanitizer_common/sanitizer_platform_limits_linux.cc
index 4c9f12acd3b0..92353e42d984 100644
--- a/lib/sanitizer_common/sanitizer_platform_limits_linux.cc
+++ b/lib/sanitizer_common/sanitizer_platform_limits_linux.cc
@@ -29,6 +29,9 @@
// are not defined anywhere in userspace headers. Fake them. This seems to work
// fine with newer headers, too.
#include <asm/posix_types.h>
+#if defined(__x86_64__) || defined(__mips__)
+#include <sys/stat.h>
+#else
#define ino_t __kernel_ino_t
#define mode_t __kernel_mode_t
#define nlink_t __kernel_nlink_t
@@ -43,24 +46,23 @@
#undef uid_t
#undef gid_t
#undef off_t
+#endif
#include <linux/aio_abi.h>
-#if SANITIZER_ANDROID
-#include <asm/statfs.h>
-#else
-#include <sys/statfs.h>
-#endif
-
#if !SANITIZER_ANDROID
+#include <sys/statfs.h>
#include <linux/perf_event.h>
#endif
namespace __sanitizer {
+#if !SANITIZER_ANDROID
unsigned struct_statfs64_sz = sizeof(struct statfs64);
+#endif
} // namespace __sanitizer
-#if !defined(__powerpc64__)
+#if !defined(__powerpc64__) && !defined(__x86_64__) && !defined(__aarch64__)\
+ && !defined(__mips__)
COMPILER_CHECK(struct___old_kernel_stat_sz == sizeof(struct __old_kernel_stat));
#endif
@@ -70,7 +72,11 @@ COMPILER_CHECK(struct_kernel_stat_sz == sizeof(struct stat));
COMPILER_CHECK(struct_kernel_stat64_sz == sizeof(struct stat64));
#endif
-COMPILER_CHECK(struct_io_event_sz == sizeof(struct io_event));
+CHECK_TYPE_SIZE(io_event);
+CHECK_SIZE_AND_OFFSET(io_event, data);
+CHECK_SIZE_AND_OFFSET(io_event, obj);
+CHECK_SIZE_AND_OFFSET(io_event, res);
+CHECK_SIZE_AND_OFFSET(io_event, res2);
#if !SANITIZER_ANDROID
COMPILER_CHECK(sizeof(struct __sanitizer_perf_event_attr) <=
@@ -81,6 +87,10 @@ CHECK_SIZE_AND_OFFSET(perf_event_attr, size);
COMPILER_CHECK(iocb_cmd_pread == IOCB_CMD_PREAD);
COMPILER_CHECK(iocb_cmd_pwrite == IOCB_CMD_PWRITE);
+#if !SANITIZER_ANDROID
+COMPILER_CHECK(iocb_cmd_preadv == IOCB_CMD_PREADV);
+COMPILER_CHECK(iocb_cmd_pwritev == IOCB_CMD_PWRITEV);
+#endif
CHECK_TYPE_SIZE(iocb);
CHECK_SIZE_AND_OFFSET(iocb, aio_data);
diff --git a/lib/sanitizer_common/sanitizer_platform_limits_posix.cc b/lib/sanitizer_common/sanitizer_platform_limits_posix.cc
index e887751d60f0..6ffc1433cddd 100644
--- a/lib/sanitizer_common/sanitizer_platform_limits_posix.cc
+++ b/lib/sanitizer_common/sanitizer_platform_limits_posix.cc
@@ -14,11 +14,20 @@
#include "sanitizer_platform.h"
-#if SANITIZER_LINUX || SANITIZER_MAC
-
-#include "sanitizer_internal_defs.h"
-#include "sanitizer_platform_limits_posix.h"
-
+#if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_MAC
+// Tests in this file assume that off_t-dependent data structures match the
+// libc ABI. For example, struct dirent here is what readdir() function (as
+// exported from libc) returns, and not the user-facing "dirent", which
+// depends on _FILE_OFFSET_BITS setting.
+// To get this "true" dirent definition, we undefine _FILE_OFFSET_BITS below.
+#ifdef _FILE_OFFSET_BITS
+#undef _FILE_OFFSET_BITS
+#endif
+#if SANITIZER_FREEBSD
+#define _WANT_RTENTRY
+#include <sys/param.h>
+#include <sys/socketvar.h>
+#endif
#include <arpa/inet.h>
#include <dirent.h>
#include <errno.h>
@@ -33,6 +42,7 @@
#include <pwd.h>
#include <signal.h>
#include <stddef.h>
+#include <sys/mman.h>
#include <sys/resource.h>
#include <sys/socket.h>
#include <sys/stat.h>
@@ -44,12 +54,15 @@
#include <time.h>
#include <wchar.h>
+#if !SANITIZER_ANDROID
+#include <sys/mount.h>
+#include <sys/timeb.h>
+#endif
+
#if SANITIZER_LINUX
+#include <malloc.h>
#include <mntent.h>
#include <netinet/ether.h>
-#include <utime.h>
-#include <sys/mount.h>
-#include <sys/ptrace.h>
#include <sys/sysinfo.h>
#include <sys/vt.h>
#include <linux/cdrom.h>
@@ -64,18 +77,63 @@
#include <linux/posix_types.h>
#endif
+#if SANITIZER_FREEBSD
+# include <sys/mount.h>
+# include <sys/sockio.h>
+# include <sys/socket.h>
+# include <sys/filio.h>
+# include <sys/signal.h>
+# include <sys/timespec.h>
+# include <sys/timex.h>
+# include <sys/mqueue.h>
+# include <sys/msg.h>
+# include <sys/ipc.h>
+# include <sys/msg.h>
+# include <sys/statvfs.h>
+# include <sys/soundcard.h>
+# include <sys/mtio.h>
+# include <sys/consio.h>
+# include <sys/kbio.h>
+# include <sys/link_elf.h>
+# include <netinet/ip_mroute.h>
+# include <netinet/in.h>
+# include <netinet/ip_compat.h>
+# include <net/ethernet.h>
+# include <net/ppp_defs.h>
+# include <glob.h>
+# include <term.h>
+
+#define _KERNEL // to declare 'shminfo' structure
+# include <sys/shm.h>
+#undef _KERNEL
+
+#undef INLINE // to avoid clashes with sanitizers' definitions
+#endif
+
+#if SANITIZER_FREEBSD || SANITIZER_IOS
+#undef IOC_DIRMASK
+#endif
+
+#if SANITIZER_LINUX || SANITIZER_FREEBSD
+# include <utime.h>
+# include <sys/ptrace.h>
+#endif
+
#if !SANITIZER_ANDROID
+#include <ifaddrs.h>
#include <sys/ucontext.h>
#include <wordexp.h>
#endif
#if SANITIZER_LINUX && !SANITIZER_ANDROID
#include <glob.h>
+#include <obstack.h>
#include <mqueue.h>
#include <net/if_ppp.h>
#include <netax25/ax25.h>
#include <netipx/ipx.h>
#include <netrom/netrom.h>
+#include <rpc/xdr.h>
#include <scsi/scsi.h>
#include <sys/mtio.h>
#include <sys/kd.h>
@@ -94,7 +152,6 @@
#include <linux/serial.h>
#include <sys/msg.h>
#include <sys/ipc.h>
-#include <sys/shm.h>
#endif // SANITIZER_LINUX && !SANITIZER_ANDROID
#if SANITIZER_ANDROID
@@ -114,16 +171,19 @@
#if SANITIZER_MAC
#include <net/ethernet.h>
#include <sys/filio.h>
-#include <sys/mount.h>
#include <sys/sockio.h>
#endif
+// Include these after system headers to avoid name clashes and ambiguities.
+#include "sanitizer_internal_defs.h"
+#include "sanitizer_platform_limits_posix.h"
+
namespace __sanitizer {
unsigned struct_utsname_sz = sizeof(struct utsname);
unsigned struct_stat_sz = sizeof(struct stat);
-#if !SANITIZER_IOS
+#if !SANITIZER_IOS && !SANITIZER_FREEBSD
unsigned struct_stat64_sz = sizeof(struct stat64);
-#endif // !SANITIZER_IOS
+#endif // !SANITIZER_IOS && !SANITIZER_FREEBSD
unsigned struct_rusage_sz = sizeof(struct rusage);
unsigned struct_tm_sz = sizeof(struct tm);
unsigned struct_passwd_sz = sizeof(struct passwd);
@@ -136,46 +196,55 @@ namespace __sanitizer {
unsigned pid_t_sz = sizeof(pid_t);
unsigned timeval_sz = sizeof(timeval);
unsigned uid_t_sz = sizeof(uid_t);
+ unsigned gid_t_sz = sizeof(gid_t);
unsigned mbstate_t_sz = sizeof(mbstate_t);
unsigned sigset_t_sz = sizeof(sigset_t);
unsigned struct_timezone_sz = sizeof(struct timezone);
unsigned struct_tms_sz = sizeof(struct tms);
unsigned struct_sigevent_sz = sizeof(struct sigevent);
unsigned struct_sched_param_sz = sizeof(struct sched_param);
- unsigned struct_statfs_sz = sizeof(struct statfs);
+
#if SANITIZER_MAC && !SANITIZER_IOS
unsigned struct_statfs64_sz = sizeof(struct statfs64);
#endif // SANITIZER_MAC && !SANITIZER_IOS
#if !SANITIZER_ANDROID
+ unsigned struct_statfs_sz = sizeof(struct statfs);
+ unsigned struct_sockaddr_sz = sizeof(struct sockaddr);
unsigned ucontext_t_sz = sizeof(ucontext_t);
#endif // !SANITIZER_ANDROID
#if SANITIZER_LINUX
- unsigned struct_rlimit_sz = sizeof(struct rlimit);
unsigned struct_epoll_event_sz = sizeof(struct epoll_event);
unsigned struct_sysinfo_sz = sizeof(struct sysinfo);
- unsigned struct_timespec_sz = sizeof(struct timespec);
unsigned __user_cap_header_struct_sz =
sizeof(struct __user_cap_header_struct);
unsigned __user_cap_data_struct_sz = sizeof(struct __user_cap_data_struct);
- unsigned struct_utimbuf_sz = sizeof(struct utimbuf);
unsigned struct_new_utsname_sz = sizeof(struct new_utsname);
unsigned struct_old_utsname_sz = sizeof(struct old_utsname);
unsigned struct_oldold_utsname_sz = sizeof(struct oldold_utsname);
+#endif // SANITIZER_LINUX
+
+#if SANITIZER_LINUX || SANITIZER_FREEBSD
+ unsigned struct_rlimit_sz = sizeof(struct rlimit);
+ unsigned struct_timespec_sz = sizeof(struct timespec);
+ unsigned struct_utimbuf_sz = sizeof(struct utimbuf);
unsigned struct_itimerspec_sz = sizeof(struct itimerspec);
- unsigned struct_ustat_sz = sizeof(struct ustat);
-#endif // SANITIZER_LINUX
+#endif // SANITIZER_LINUX || SANITIZER_FREEBSD
#if SANITIZER_LINUX && !SANITIZER_ANDROID
+ unsigned struct_ustat_sz = sizeof(struct ustat);
unsigned struct_rlimit64_sz = sizeof(struct rlimit64);
+ unsigned struct_statvfs64_sz = sizeof(struct statvfs64);
+#endif // SANITIZER_LINUX && !SANITIZER_ANDROID
+
+#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
unsigned struct_timex_sz = sizeof(struct timex);
unsigned struct_msqid_ds_sz = sizeof(struct msqid_ds);
unsigned struct_mq_attr_sz = sizeof(struct mq_attr);
unsigned struct_statvfs_sz = sizeof(struct statvfs);
- unsigned struct_statvfs64_sz = sizeof(struct statvfs64);
-#endif // SANITIZER_LINUX && !SANITIZER_ANDROID
+#endif // (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
uptr sig_ign = (uptr)SIG_IGN;
uptr sig_dfl = (uptr)SIG_DFL;
@@ -186,15 +255,17 @@ namespace __sanitizer {
#endif
-#if SANITIZER_LINUX && !SANITIZER_ANDROID
+#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
unsigned struct_shminfo_sz = sizeof(struct shminfo);
unsigned struct_shm_info_sz = sizeof(struct shm_info);
int shmctl_ipc_stat = (int)IPC_STAT;
int shmctl_ipc_info = (int)IPC_INFO;
int shmctl_shm_info = (int)SHM_INFO;
- int shmctl_shm_stat = (int)SHM_INFO;
+ int shmctl_shm_stat = (int)SHM_STAT;
#endif
+ int map_fixed = MAP_FIXED;
+
int af_inet = (int)AF_INET;
int af_inet6 = (int)AF_INET6;
@@ -207,13 +278,13 @@ namespace __sanitizer {
return 0;
}
-#if SANITIZER_LINUX && !SANITIZER_ANDROID
+#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
int glob_nomatch = GLOB_NOMATCH;
int glob_altdirfunc = GLOB_ALTDIRFUNC;
#endif
#if SANITIZER_LINUX && !SANITIZER_ANDROID && \
- (defined(__i386) || defined (__x86_64)) // NOLINT
+ (defined(__i386) || defined(__x86_64))
unsigned struct_user_regs_struct_sz = sizeof(struct user_regs_struct);
unsigned struct_user_fpregs_struct_sz = sizeof(struct user_fpregs_struct);
#ifdef __x86_64
@@ -231,15 +302,22 @@ namespace __sanitizer {
int ptrace_setfpregs = PTRACE_SETFPREGS;
int ptrace_getfpxregs = PTRACE_GETFPXREGS;
int ptrace_setfpxregs = PTRACE_SETFPXREGS;
+ int ptrace_geteventmsg = PTRACE_GETEVENTMSG;
+#if (defined(PTRACE_GETSIGINFO) && defined(PTRACE_SETSIGINFO)) || \
+ (defined(PT_GETSIGINFO) && defined(PT_SETSIGINFO))
int ptrace_getsiginfo = PTRACE_GETSIGINFO;
int ptrace_setsiginfo = PTRACE_SETSIGINFO;
+#else
+ int ptrace_getsiginfo = -1;
+ int ptrace_setsiginfo = -1;
+#endif // PTRACE_GETSIGINFO/PTRACE_SETSIGINFO
#if defined(PTRACE_GETREGSET) && defined(PTRACE_SETREGSET)
int ptrace_getregset = PTRACE_GETREGSET;
int ptrace_setregset = PTRACE_SETREGSET;
#else
int ptrace_getregset = -1;
int ptrace_setregset = -1;
-#endif
+#endif // PTRACE_GETREGSET/PTRACE_SETREGSET
#endif
unsigned path_max = PATH_MAX;
@@ -259,15 +337,6 @@ namespace __sanitizer {
unsigned struct_cdrom_tocentry_sz = sizeof(struct cdrom_tocentry);
unsigned struct_cdrom_tochdr_sz = sizeof(struct cdrom_tochdr);
unsigned struct_cdrom_volctrl_sz = sizeof(struct cdrom_volctrl);
-#if SOUND_VERSION >= 0x040000
- unsigned struct_copr_buffer_sz = 0;
- unsigned struct_copr_debug_buf_sz = 0;
- unsigned struct_copr_msg_sz = 0;
-#else
- unsigned struct_copr_buffer_sz = sizeof(struct copr_buffer);
- unsigned struct_copr_debug_buf_sz = sizeof(struct copr_debug_buf);
- unsigned struct_copr_msg_sz = sizeof(struct copr_msg);
-#endif
unsigned struct_ff_effect_sz = sizeof(struct ff_effect);
unsigned struct_floppy_drive_params_sz = sizeof(struct floppy_drive_params);
unsigned struct_floppy_drive_struct_sz = sizeof(struct floppy_drive_struct);
@@ -281,23 +350,34 @@ namespace __sanitizer {
unsigned struct_hd_geometry_sz = sizeof(struct hd_geometry);
unsigned struct_input_absinfo_sz = sizeof(struct input_absinfo);
unsigned struct_input_id_sz = sizeof(struct input_id);
+ unsigned struct_mtpos_sz = sizeof(struct mtpos);
+ unsigned struct_termio_sz = sizeof(struct termio);
+ unsigned struct_vt_consize_sz = sizeof(struct vt_consize);
+ unsigned struct_vt_sizes_sz = sizeof(struct vt_sizes);
+ unsigned struct_vt_stat_sz = sizeof(struct vt_stat);
+#endif // SANITIZER_LINUX
+
+#if SANITIZER_LINUX || SANITIZER_FREEBSD
+#if SOUND_VERSION >= 0x040000
+ unsigned struct_copr_buffer_sz = 0;
+ unsigned struct_copr_debug_buf_sz = 0;
+ unsigned struct_copr_msg_sz = 0;
+#else
+ unsigned struct_copr_buffer_sz = sizeof(struct copr_buffer);
+ unsigned struct_copr_debug_buf_sz = sizeof(struct copr_debug_buf);
+ unsigned struct_copr_msg_sz = sizeof(struct copr_msg);
+#endif
unsigned struct_midi_info_sz = sizeof(struct midi_info);
unsigned struct_mtget_sz = sizeof(struct mtget);
unsigned struct_mtop_sz = sizeof(struct mtop);
- unsigned struct_mtpos_sz = sizeof(struct mtpos);
unsigned struct_rtentry_sz = sizeof(struct rtentry);
unsigned struct_sbi_instrument_sz = sizeof(struct sbi_instrument);
unsigned struct_seq_event_rec_sz = sizeof(struct seq_event_rec);
unsigned struct_synth_info_sz = sizeof(struct synth_info);
- unsigned struct_termio_sz = sizeof(struct termio);
- unsigned struct_vt_consize_sz = sizeof(struct vt_consize);
unsigned struct_vt_mode_sz = sizeof(struct vt_mode);
- unsigned struct_vt_sizes_sz = sizeof(struct vt_sizes);
- unsigned struct_vt_stat_sz = sizeof(struct vt_stat);
-#endif
+#endif // SANITIZER_LINUX || SANITIZER_FREEBSD
#if SANITIZER_LINUX && !SANITIZER_ANDROID
- unsigned struct_audio_buf_info_sz = sizeof(struct audio_buf_info);
unsigned struct_ax25_parms_struct_sz = sizeof(struct ax25_parms_struct);
unsigned struct_cyclades_monitor_sz = sizeof(struct cyclades_monitor);
#if EV_VERSION > (0x010000)
@@ -312,7 +392,6 @@ namespace __sanitizer {
unsigned struct_kbsentry_sz = sizeof(struct kbsentry);
unsigned struct_mtconfiginfo_sz = sizeof(struct mtconfiginfo);
unsigned struct_nr_parms_struct_sz = sizeof(struct nr_parms_struct);
- unsigned struct_ppp_stats_sz = sizeof(struct ppp_stats);
unsigned struct_scc_modem_sz = sizeof(struct scc_modem);
unsigned struct_scc_stat_sz = sizeof(struct scc_stat);
unsigned struct_serial_multiport_struct_sz
@@ -321,14 +400,19 @@ namespace __sanitizer {
unsigned struct_sockaddr_ax25_sz = sizeof(struct sockaddr_ax25);
unsigned struct_unimapdesc_sz = sizeof(struct unimapdesc);
unsigned struct_unimapinit_sz = sizeof(struct unimapinit);
-#endif
+#endif // SANITIZER_LINUX && !SANITIZER_ANDROID
+
+#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
+ unsigned struct_audio_buf_info_sz = sizeof(struct audio_buf_info);
+ unsigned struct_ppp_stats_sz = sizeof(struct ppp_stats);
+#endif // (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
#if !SANITIZER_ANDROID && !SANITIZER_MAC
unsigned struct_sioc_sg_req_sz = sizeof(struct sioc_sg_req);
unsigned struct_sioc_vif_req_sz = sizeof(struct sioc_vif_req);
#endif
- unsigned IOCTL_NOT_PRESENT = 0;
+ const unsigned IOCTL_NOT_PRESENT = 0;
unsigned IOCTL_FIOASYNC = FIOASYNC;
unsigned IOCTL_FIOCLEX = FIOCLEX;
@@ -374,10 +458,11 @@ namespace __sanitizer {
unsigned IOCTL_TIOCSPGRP = TIOCSPGRP;
unsigned IOCTL_TIOCSTI = TIOCSTI;
unsigned IOCTL_TIOCSWINSZ = TIOCSWINSZ;
-#if (SANITIZER_LINUX && !SANITIZER_ANDROID)
+#if ((SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID)
unsigned IOCTL_SIOCGETSGCNT = SIOCGETSGCNT;
unsigned IOCTL_SIOCGETVIFCNT = SIOCGETVIFCNT;
#endif
+
#if SANITIZER_LINUX
unsigned IOCTL_EVIOCGABS = EVIOCGABS(0);
unsigned IOCTL_EVIOCGBIT = EVIOCGBIT(0, 0);
@@ -468,9 +553,7 @@ namespace __sanitizer {
unsigned IOCTL_HDIO_SET_MULTCOUNT = HDIO_SET_MULTCOUNT;
unsigned IOCTL_HDIO_SET_NOWERR = HDIO_SET_NOWERR;
unsigned IOCTL_HDIO_SET_UNMASKINTR = HDIO_SET_UNMASKINTR;
- unsigned IOCTL_MTIOCGET = MTIOCGET;
unsigned IOCTL_MTIOCPOS = MTIOCPOS;
- unsigned IOCTL_MTIOCTOP = MTIOCTOP;
unsigned IOCTL_PPPIOCGASYNCMAP = PPPIOCGASYNCMAP;
unsigned IOCTL_PPPIOCGDEBUG = PPPIOCGDEBUG;
unsigned IOCTL_PPPIOCGFLAGS = PPPIOCGFLAGS;
@@ -503,7 +586,7 @@ namespace __sanitizer {
unsigned IOCTL_SIOCSIFMEM = SIOCSIFMEM;
unsigned IOCTL_SIOCSIFSLAVE = SIOCSIFSLAVE;
unsigned IOCTL_SIOCSRARP = SIOCSRARP;
-#if SOUND_VERSION >= 0x040000
+# if SOUND_VERSION >= 0x040000
unsigned IOCTL_SNDCTL_COPR_HALT = IOCTL_NOT_PRESENT;
unsigned IOCTL_SNDCTL_COPR_LOAD = IOCTL_NOT_PRESENT;
unsigned IOCTL_SNDCTL_COPR_RCODE = IOCTL_NOT_PRESENT;
@@ -520,7 +603,7 @@ namespace __sanitizer {
unsigned IOCTL_SOUND_PCM_READ_RATE = IOCTL_NOT_PRESENT;
unsigned IOCTL_SOUND_PCM_WRITE_CHANNELS = IOCTL_NOT_PRESENT;
unsigned IOCTL_SOUND_PCM_WRITE_FILTER = IOCTL_NOT_PRESENT;
-#else
+# else // SOUND_VERSION
unsigned IOCTL_SNDCTL_COPR_HALT = SNDCTL_COPR_HALT;
unsigned IOCTL_SNDCTL_COPR_LOAD = SNDCTL_COPR_LOAD;
unsigned IOCTL_SNDCTL_COPR_RCODE = SNDCTL_COPR_RCODE;
@@ -537,7 +620,39 @@ namespace __sanitizer {
unsigned IOCTL_SOUND_PCM_READ_RATE = SOUND_PCM_READ_RATE;
unsigned IOCTL_SOUND_PCM_WRITE_CHANNELS = SOUND_PCM_WRITE_CHANNELS;
unsigned IOCTL_SOUND_PCM_WRITE_FILTER = SOUND_PCM_WRITE_FILTER;
-#endif
+#endif // SOUND_VERSION
+ unsigned IOCTL_TCFLSH = TCFLSH;
+ unsigned IOCTL_TCGETA = TCGETA;
+ unsigned IOCTL_TCGETS = TCGETS;
+ unsigned IOCTL_TCSBRK = TCSBRK;
+ unsigned IOCTL_TCSBRKP = TCSBRKP;
+ unsigned IOCTL_TCSETA = TCSETA;
+ unsigned IOCTL_TCSETAF = TCSETAF;
+ unsigned IOCTL_TCSETAW = TCSETAW;
+ unsigned IOCTL_TCSETS = TCSETS;
+ unsigned IOCTL_TCSETSF = TCSETSF;
+ unsigned IOCTL_TCSETSW = TCSETSW;
+ unsigned IOCTL_TCXONC = TCXONC;
+ unsigned IOCTL_TIOCGLCKTRMIOS = TIOCGLCKTRMIOS;
+ unsigned IOCTL_TIOCGSOFTCAR = TIOCGSOFTCAR;
+ unsigned IOCTL_TIOCINQ = TIOCINQ;
+ unsigned IOCTL_TIOCLINUX = TIOCLINUX;
+ unsigned IOCTL_TIOCSERCONFIG = TIOCSERCONFIG;
+ unsigned IOCTL_TIOCSERGETLSR = TIOCSERGETLSR;
+ unsigned IOCTL_TIOCSERGWILD = TIOCSERGWILD;
+ unsigned IOCTL_TIOCSERSWILD = TIOCSERSWILD;
+ unsigned IOCTL_TIOCSLCKTRMIOS = TIOCSLCKTRMIOS;
+ unsigned IOCTL_TIOCSSOFTCAR = TIOCSSOFTCAR;
+ unsigned IOCTL_VT_DISALLOCATE = VT_DISALLOCATE;
+ unsigned IOCTL_VT_GETSTATE = VT_GETSTATE;
+ unsigned IOCTL_VT_RESIZE = VT_RESIZE;
+ unsigned IOCTL_VT_RESIZEX = VT_RESIZEX;
+ unsigned IOCTL_VT_SENDSIG = VT_SENDSIG;
+#endif // SANITIZER_LINUX
+
+#if SANITIZER_LINUX || SANITIZER_FREEBSD
+ unsigned IOCTL_MTIOCGET = MTIOCGET;
+ unsigned IOCTL_MTIOCTOP = MTIOCTOP;
unsigned IOCTL_SNDCTL_DSP_GETBLKSIZE = SNDCTL_DSP_GETBLKSIZE;
unsigned IOCTL_SNDCTL_DSP_GETFMTS = SNDCTL_DSP_GETFMTS;
unsigned IOCTL_SNDCTL_DSP_NONBLOCK = SNDCTL_DSP_NONBLOCK;
@@ -622,40 +737,14 @@ namespace __sanitizer {
unsigned IOCTL_SOUND_MIXER_WRITE_SYNTH = SOUND_MIXER_WRITE_SYNTH;
unsigned IOCTL_SOUND_MIXER_WRITE_TREBLE = SOUND_MIXER_WRITE_TREBLE;
unsigned IOCTL_SOUND_MIXER_WRITE_VOLUME = SOUND_MIXER_WRITE_VOLUME;
- unsigned IOCTL_TCFLSH = TCFLSH;
- unsigned IOCTL_TCGETA = TCGETA;
- unsigned IOCTL_TCGETS = TCGETS;
- unsigned IOCTL_TCSBRK = TCSBRK;
- unsigned IOCTL_TCSBRKP = TCSBRKP;
- unsigned IOCTL_TCSETA = TCSETA;
- unsigned IOCTL_TCSETAF = TCSETAF;
- unsigned IOCTL_TCSETAW = TCSETAW;
- unsigned IOCTL_TCSETS = TCSETS;
- unsigned IOCTL_TCSETSF = TCSETSF;
- unsigned IOCTL_TCSETSW = TCSETSW;
- unsigned IOCTL_TCXONC = TCXONC;
- unsigned IOCTL_TIOCGLCKTRMIOS = TIOCGLCKTRMIOS;
- unsigned IOCTL_TIOCGSOFTCAR = TIOCGSOFTCAR;
- unsigned IOCTL_TIOCINQ = TIOCINQ;
- unsigned IOCTL_TIOCLINUX = TIOCLINUX;
- unsigned IOCTL_TIOCSERCONFIG = TIOCSERCONFIG;
- unsigned IOCTL_TIOCSERGETLSR = TIOCSERGETLSR;
- unsigned IOCTL_TIOCSERGWILD = TIOCSERGWILD;
- unsigned IOCTL_TIOCSERSWILD = TIOCSERSWILD;
- unsigned IOCTL_TIOCSLCKTRMIOS = TIOCSLCKTRMIOS;
- unsigned IOCTL_TIOCSSOFTCAR = TIOCSSOFTCAR;
unsigned IOCTL_VT_ACTIVATE = VT_ACTIVATE;
- unsigned IOCTL_VT_DISALLOCATE = VT_DISALLOCATE;
unsigned IOCTL_VT_GETMODE = VT_GETMODE;
- unsigned IOCTL_VT_GETSTATE = VT_GETSTATE;
unsigned IOCTL_VT_OPENQRY = VT_OPENQRY;
unsigned IOCTL_VT_RELDISP = VT_RELDISP;
- unsigned IOCTL_VT_RESIZE = VT_RESIZE;
- unsigned IOCTL_VT_RESIZEX = VT_RESIZEX;
- unsigned IOCTL_VT_SENDSIG = VT_SENDSIG;
unsigned IOCTL_VT_SETMODE = VT_SETMODE;
unsigned IOCTL_VT_WAITACTIVE = VT_WAITACTIVE;
-#endif
+#endif // SANITIZER_LINUX || SANITIZER_FREEBSD
+
#if SANITIZER_LINUX && !SANITIZER_ANDROID
unsigned IOCTL_CYGETDEFTHRESH = CYGETDEFTHRESH;
unsigned IOCTL_CYGETDEFTIMEOUT = CYGETDEFTIMEOUT;
@@ -687,37 +776,25 @@ namespace __sanitizer {
unsigned IOCTL_FS_IOC_SETVERSION = FS_IOC_SETVERSION;
unsigned IOCTL_GIO_CMAP = GIO_CMAP;
unsigned IOCTL_GIO_FONT = GIO_FONT;
- unsigned IOCTL_GIO_SCRNMAP = GIO_SCRNMAP;
unsigned IOCTL_GIO_UNIMAP = GIO_UNIMAP;
unsigned IOCTL_GIO_UNISCRNMAP = GIO_UNISCRNMAP;
unsigned IOCTL_KDADDIO = KDADDIO;
unsigned IOCTL_KDDELIO = KDDELIO;
- unsigned IOCTL_KDDISABIO = KDDISABIO;
- unsigned IOCTL_KDENABIO = KDENABIO;
unsigned IOCTL_KDGETKEYCODE = KDGETKEYCODE;
- unsigned IOCTL_KDGETLED = KDGETLED;
- unsigned IOCTL_KDGETMODE = KDGETMODE;
unsigned IOCTL_KDGKBDIACR = KDGKBDIACR;
unsigned IOCTL_KDGKBENT = KDGKBENT;
unsigned IOCTL_KDGKBLED = KDGKBLED;
unsigned IOCTL_KDGKBMETA = KDGKBMETA;
- unsigned IOCTL_KDGKBMODE = KDGKBMODE;
unsigned IOCTL_KDGKBSENT = KDGKBSENT;
- unsigned IOCTL_KDGKBTYPE = KDGKBTYPE;
unsigned IOCTL_KDMAPDISP = KDMAPDISP;
- unsigned IOCTL_KDMKTONE = KDMKTONE;
unsigned IOCTL_KDSETKEYCODE = KDSETKEYCODE;
- unsigned IOCTL_KDSETLED = KDSETLED;
- unsigned IOCTL_KDSETMODE = KDSETMODE;
unsigned IOCTL_KDSIGACCEPT = KDSIGACCEPT;
unsigned IOCTL_KDSKBDIACR = KDSKBDIACR;
unsigned IOCTL_KDSKBENT = KDSKBENT;
unsigned IOCTL_KDSKBLED = KDSKBLED;
unsigned IOCTL_KDSKBMETA = KDSKBMETA;
- unsigned IOCTL_KDSKBMODE = KDSKBMODE;
unsigned IOCTL_KDSKBSENT = KDSKBSENT;
unsigned IOCTL_KDUNMAPDISP = KDUNMAPDISP;
- unsigned IOCTL_KIOCSOUND = KIOCSOUND;
unsigned IOCTL_LPABORT = LPABORT;
unsigned IOCTL_LPABORTOPEN = LPABORTOPEN;
unsigned IOCTL_LPCAREFUL = LPCAREFUL;
@@ -732,7 +809,6 @@ namespace __sanitizer {
unsigned IOCTL_MTIOCSETCONFIG = MTIOCSETCONFIG;
unsigned IOCTL_PIO_CMAP = PIO_CMAP;
unsigned IOCTL_PIO_FONT = PIO_FONT;
- unsigned IOCTL_PIO_SCRNMAP = PIO_SCRNMAP;
unsigned IOCTL_PIO_UNIMAP = PIO_UNIMAP;
unsigned IOCTL_PIO_UNIMAPCLR = PIO_UNIMAPCLR;
unsigned IOCTL_PIO_UNISCRNMAP = PIO_UNISCRNMAP;
@@ -754,20 +830,40 @@ namespace __sanitizer {
unsigned IOCTL_SIOCNRGETPARMS = SIOCNRGETPARMS;
unsigned IOCTL_SIOCNRRTCTL = SIOCNRRTCTL;
unsigned IOCTL_SIOCNRSETPARMS = SIOCNRSETPARMS;
- unsigned IOCTL_SNDCTL_DSP_GETISPACE = SNDCTL_DSP_GETISPACE;
- unsigned IOCTL_SNDCTL_DSP_GETOSPACE = SNDCTL_DSP_GETOSPACE;
unsigned IOCTL_TIOCGSERIAL = TIOCGSERIAL;
unsigned IOCTL_TIOCSERGETMULTI = TIOCSERGETMULTI;
unsigned IOCTL_TIOCSERSETMULTI = TIOCSERSETMULTI;
unsigned IOCTL_TIOCSSERIAL = TIOCSSERIAL;
-#endif
+#endif // SANITIZER_LINUX && !SANITIZER_ANDROID
+#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
+ unsigned IOCTL_GIO_SCRNMAP = GIO_SCRNMAP;
+ unsigned IOCTL_KDDISABIO = KDDISABIO;
+ unsigned IOCTL_KDENABIO = KDENABIO;
+ unsigned IOCTL_KDGETLED = KDGETLED;
+ unsigned IOCTL_KDGETMODE = KDGETMODE;
+ unsigned IOCTL_KDGKBMODE = KDGKBMODE;
+ unsigned IOCTL_KDGKBTYPE = KDGKBTYPE;
+ unsigned IOCTL_KDMKTONE = KDMKTONE;
+ unsigned IOCTL_KDSETLED = KDSETLED;
+ unsigned IOCTL_KDSETMODE = KDSETMODE;
+ unsigned IOCTL_KDSKBMODE = KDSKBMODE;
+ unsigned IOCTL_KIOCSOUND = KIOCSOUND;
+ unsigned IOCTL_PIO_SCRNMAP = PIO_SCRNMAP;
+ unsigned IOCTL_SNDCTL_DSP_GETISPACE = SNDCTL_DSP_GETISPACE;
+ unsigned IOCTL_SNDCTL_DSP_GETOSPACE = SNDCTL_DSP_GETOSPACE;
+#endif // (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
+
+ const int errno_EINVAL = EINVAL;
// EOWNERDEAD is not present in some older platforms.
#if defined(EOWNERDEAD)
- extern const int errno_EOWNERDEAD = EOWNERDEAD;
+ const int errno_EOWNERDEAD = EOWNERDEAD;
#else
- extern const int errno_EOWNERDEAD = -1;
+ const int errno_EOWNERDEAD = -1;
#endif
+
+ const int si_SEGV_MAPERR = SEGV_MAPERR;
+ const int si_SEGV_ACCERR = SEGV_ACCERR;
} // namespace __sanitizer
COMPILER_CHECK(sizeof(__sanitizer_pthread_attr_t) >= sizeof(pthread_attr_t));
@@ -776,6 +872,31 @@ COMPILER_CHECK(sizeof(socklen_t) == sizeof(unsigned));
CHECK_TYPE_SIZE(pthread_key_t);
#if SANITIZER_LINUX
+// FIXME: We define those on Linux and Mac, but only check on Linux.
+COMPILER_CHECK(IOC_NRBITS == _IOC_NRBITS);
+COMPILER_CHECK(IOC_TYPEBITS == _IOC_TYPEBITS);
+COMPILER_CHECK(IOC_SIZEBITS == _IOC_SIZEBITS);
+COMPILER_CHECK(IOC_DIRBITS == _IOC_DIRBITS);
+COMPILER_CHECK(IOC_NRMASK == _IOC_NRMASK);
+COMPILER_CHECK(IOC_TYPEMASK == _IOC_TYPEMASK);
+COMPILER_CHECK(IOC_SIZEMASK == _IOC_SIZEMASK);
+COMPILER_CHECK(IOC_DIRMASK == _IOC_DIRMASK);
+COMPILER_CHECK(IOC_NRSHIFT == _IOC_NRSHIFT);
+COMPILER_CHECK(IOC_TYPESHIFT == _IOC_TYPESHIFT);
+COMPILER_CHECK(IOC_SIZESHIFT == _IOC_SIZESHIFT);
+COMPILER_CHECK(IOC_DIRSHIFT == _IOC_DIRSHIFT);
+COMPILER_CHECK(IOC_NONE == _IOC_NONE);
+COMPILER_CHECK(IOC_WRITE == _IOC_WRITE);
+COMPILER_CHECK(IOC_READ == _IOC_READ);
+COMPILER_CHECK(EVIOC_ABS_MAX == ABS_MAX);
+COMPILER_CHECK(EVIOC_EV_MAX == EV_MAX);
+COMPILER_CHECK(IOC_SIZE(0x12345678) == _IOC_SIZE(0x12345678));
+COMPILER_CHECK(IOC_DIR(0x12345678) == _IOC_DIR(0x12345678));
+COMPILER_CHECK(IOC_NR(0x12345678) == _IOC_NR(0x12345678));
+COMPILER_CHECK(IOC_TYPE(0x12345678) == _IOC_TYPE(0x12345678));
+#endif // SANITIZER_LINUX
+
+#if SANITIZER_LINUX || SANITIZER_FREEBSD
// There are more undocumented fields in dl_phdr_info that we are not interested
// in.
COMPILER_CHECK(sizeof(__sanitizer_dl_phdr_info) <= sizeof(dl_phdr_info));
@@ -783,11 +904,9 @@ CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_addr);
CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_name);
CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phdr);
CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phnum);
+#endif // SANITIZER_LINUX || SANITIZER_FREEBSD
-COMPILER_CHECK(IOC_SIZE(0x12345678) == _IOC_SIZE(0x12345678));
-#endif
-
-#if SANITIZER_LINUX && !SANITIZER_ANDROID
+#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
CHECK_TYPE_SIZE(glob_t);
CHECK_SIZE_AND_OFFSET(glob_t, gl_pathc);
CHECK_SIZE_AND_OFFSET(glob_t, gl_pathv);
@@ -839,6 +958,8 @@ COMPILER_CHECK(sizeof(__sanitizer_dirent) <= sizeof(dirent));
CHECK_SIZE_AND_OFFSET(dirent, d_ino);
#if SANITIZER_MAC
CHECK_SIZE_AND_OFFSET(dirent, d_seekoff);
+#elif SANITIZER_FREEBSD
+// There is no 'd_off' field on FreeBSD.
#else
CHECK_SIZE_AND_OFFSET(dirent, d_off);
#endif
@@ -884,8 +1005,12 @@ CHECK_SIZE_AND_OFFSET(__sysctl_args, newlen);
CHECK_TYPE_SIZE(__kernel_uid_t);
CHECK_TYPE_SIZE(__kernel_gid_t);
+
+#if !defined(__aarch64__)
CHECK_TYPE_SIZE(__kernel_old_uid_t);
CHECK_TYPE_SIZE(__kernel_old_gid_t);
+#endif
+
CHECK_TYPE_SIZE(__kernel_off_t);
CHECK_TYPE_SIZE(__kernel_loff_t);
CHECK_TYPE_SIZE(__kernel_fd_set);
@@ -923,15 +1048,20 @@ CHECK_SIZE_AND_OFFSET(mntent, mnt_passno);
CHECK_TYPE_SIZE(ether_addr);
-#if SANITIZER_LINUX && !SANITIZER_ANDROID
+#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
CHECK_TYPE_SIZE(ipc_perm);
+# if SANITIZER_FREEBSD
+CHECK_SIZE_AND_OFFSET(ipc_perm, key);
+CHECK_SIZE_AND_OFFSET(ipc_perm, seq);
+# else
CHECK_SIZE_AND_OFFSET(ipc_perm, __key);
+CHECK_SIZE_AND_OFFSET(ipc_perm, __seq);
+# endif
CHECK_SIZE_AND_OFFSET(ipc_perm, uid);
CHECK_SIZE_AND_OFFSET(ipc_perm, gid);
CHECK_SIZE_AND_OFFSET(ipc_perm, cuid);
CHECK_SIZE_AND_OFFSET(ipc_perm, cgid);
CHECK_SIZE_AND_OFFSET(ipc_perm, mode);
-CHECK_SIZE_AND_OFFSET(ipc_perm, __seq);
CHECK_TYPE_SIZE(shmid_ds);
CHECK_SIZE_AND_OFFSET(shmid_ds, shm_perm);
@@ -944,4 +1074,116 @@ CHECK_SIZE_AND_OFFSET(shmid_ds, shm_lpid);
CHECK_SIZE_AND_OFFSET(shmid_ds, shm_nattch);
#endif
-#endif // SANITIZER_LINUX || SANITIZER_MAC
+CHECK_TYPE_SIZE(clock_t);
+
+#if SANITIZER_LINUX
+CHECK_TYPE_SIZE(clockid_t);
+#endif
+
+#if !SANITIZER_ANDROID
+CHECK_TYPE_SIZE(ifaddrs);
+CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_next);
+CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_name);
+CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_addr);
+CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_netmask);
+#if SANITIZER_LINUX || SANITIZER_FREEBSD
+// Compare against the union, because we can't reach into the union in a
+// compliant way.
+#ifdef ifa_dstaddr
+#undef ifa_dstaddr
+#endif
+# if SANITIZER_FREEBSD
+CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_dstaddr);
+# else
+COMPILER_CHECK(sizeof(((__sanitizer_ifaddrs *)NULL)->ifa_dstaddr) ==
+ sizeof(((ifaddrs *)NULL)->ifa_ifu));
+COMPILER_CHECK(offsetof(__sanitizer_ifaddrs, ifa_dstaddr) ==
+ offsetof(ifaddrs, ifa_ifu));
+# endif // SANITIZER_FREEBSD
+#else
+CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_dstaddr);
+#endif // SANITIZER_LINUX
+CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_data);
+#endif
+
+#if SANITIZER_LINUX
+COMPILER_CHECK(sizeof(__sanitizer_mallinfo) == sizeof(struct mallinfo));
+#endif
+
+#if !SANITIZER_ANDROID
+CHECK_TYPE_SIZE(timeb);
+CHECK_SIZE_AND_OFFSET(timeb, time);
+CHECK_SIZE_AND_OFFSET(timeb, millitm);
+CHECK_SIZE_AND_OFFSET(timeb, timezone);
+CHECK_SIZE_AND_OFFSET(timeb, dstflag);
+#endif
+
+CHECK_TYPE_SIZE(passwd);
+CHECK_SIZE_AND_OFFSET(passwd, pw_name);
+CHECK_SIZE_AND_OFFSET(passwd, pw_passwd);
+CHECK_SIZE_AND_OFFSET(passwd, pw_uid);
+CHECK_SIZE_AND_OFFSET(passwd, pw_gid);
+CHECK_SIZE_AND_OFFSET(passwd, pw_dir);
+CHECK_SIZE_AND_OFFSET(passwd, pw_shell);
+
+#if !SANITIZER_ANDROID
+CHECK_SIZE_AND_OFFSET(passwd, pw_gecos);
+#endif
+
+#if SANITIZER_MAC
+CHECK_SIZE_AND_OFFSET(passwd, pw_change);
+CHECK_SIZE_AND_OFFSET(passwd, pw_expire);
+CHECK_SIZE_AND_OFFSET(passwd, pw_class);
+#endif
+
+
+CHECK_TYPE_SIZE(group);
+CHECK_SIZE_AND_OFFSET(group, gr_name);
+CHECK_SIZE_AND_OFFSET(group, gr_passwd);
+CHECK_SIZE_AND_OFFSET(group, gr_gid);
+CHECK_SIZE_AND_OFFSET(group, gr_mem);
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+CHECK_TYPE_SIZE(XDR);
+CHECK_SIZE_AND_OFFSET(XDR, x_op);
+CHECK_SIZE_AND_OFFSET(XDR, x_ops);
+CHECK_SIZE_AND_OFFSET(XDR, x_public);
+CHECK_SIZE_AND_OFFSET(XDR, x_private);
+CHECK_SIZE_AND_OFFSET(XDR, x_base);
+CHECK_SIZE_AND_OFFSET(XDR, x_handy);
+COMPILER_CHECK(__sanitizer_XDR_ENCODE == XDR_ENCODE);
+COMPILER_CHECK(__sanitizer_XDR_DECODE == XDR_DECODE);
+COMPILER_CHECK(__sanitizer_XDR_FREE == XDR_FREE);
+#endif
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+COMPILER_CHECK(sizeof(__sanitizer_FILE) <= sizeof(FILE));
+CHECK_SIZE_AND_OFFSET(FILE, _flags);
+CHECK_SIZE_AND_OFFSET(FILE, _IO_read_ptr);
+CHECK_SIZE_AND_OFFSET(FILE, _IO_read_end);
+CHECK_SIZE_AND_OFFSET(FILE, _IO_read_base);
+CHECK_SIZE_AND_OFFSET(FILE, _IO_write_ptr);
+CHECK_SIZE_AND_OFFSET(FILE, _IO_write_end);
+CHECK_SIZE_AND_OFFSET(FILE, _IO_write_base);
+CHECK_SIZE_AND_OFFSET(FILE, _IO_buf_base);
+CHECK_SIZE_AND_OFFSET(FILE, _IO_buf_end);
+CHECK_SIZE_AND_OFFSET(FILE, _IO_save_base);
+CHECK_SIZE_AND_OFFSET(FILE, _IO_backup_base);
+CHECK_SIZE_AND_OFFSET(FILE, _IO_save_end);
+CHECK_SIZE_AND_OFFSET(FILE, _markers);
+CHECK_SIZE_AND_OFFSET(FILE, _chain);
+CHECK_SIZE_AND_OFFSET(FILE, _fileno);
+#endif
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+COMPILER_CHECK(sizeof(__sanitizer__obstack_chunk) <= sizeof(_obstack_chunk));
+CHECK_SIZE_AND_OFFSET(_obstack_chunk, limit);
+CHECK_SIZE_AND_OFFSET(_obstack_chunk, prev);
+CHECK_TYPE_SIZE(obstack);
+CHECK_SIZE_AND_OFFSET(obstack, chunk_size);
+CHECK_SIZE_AND_OFFSET(obstack, chunk);
+CHECK_SIZE_AND_OFFSET(obstack, object_base);
+CHECK_SIZE_AND_OFFSET(obstack, next_free);
+#endif
+
+#endif // SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_MAC
diff --git a/lib/sanitizer_common/sanitizer_platform_limits_posix.h b/lib/sanitizer_common/sanitizer_platform_limits_posix.h
index b9a0fc98c017..80a3ddb36670 100644
--- a/lib/sanitizer_common/sanitizer_platform_limits_posix.h
+++ b/lib/sanitizer_common/sanitizer_platform_limits_posix.h
@@ -21,12 +21,10 @@
namespace __sanitizer {
extern unsigned struct_utsname_sz;
extern unsigned struct_stat_sz;
-#if !SANITIZER_IOS
+#if !SANITIZER_FREEBSD && !SANITIZER_IOS
extern unsigned struct_stat64_sz;
#endif
extern unsigned struct_rusage_sz;
- extern unsigned struct_passwd_sz;
- extern unsigned struct_group_sz;
extern unsigned siginfo_t_sz;
extern unsigned struct_itimerval_sz;
extern unsigned pthread_t_sz;
@@ -34,66 +32,77 @@ namespace __sanitizer {
extern unsigned pid_t_sz;
extern unsigned timeval_sz;
extern unsigned uid_t_sz;
+ extern unsigned gid_t_sz;
extern unsigned mbstate_t_sz;
extern unsigned struct_timezone_sz;
extern unsigned struct_tms_sz;
extern unsigned struct_itimerspec_sz;
extern unsigned struct_sigevent_sz;
extern unsigned struct_sched_param_sz;
- extern unsigned struct_statfs_sz;
extern unsigned struct_statfs64_sz;
#if !SANITIZER_ANDROID
+ extern unsigned struct_statfs_sz;
+ extern unsigned struct_sockaddr_sz;
extern unsigned ucontext_t_sz;
#endif // !SANITIZER_ANDROID
#if SANITIZER_LINUX
#if defined(__x86_64__)
- const unsigned struct___old_kernel_stat_sz = 32;
const unsigned struct_kernel_stat_sz = 144;
const unsigned struct_kernel_stat64_sz = 0;
#elif defined(__i386__)
- const unsigned struct___old_kernel_stat_sz = 32;
const unsigned struct_kernel_stat_sz = 64;
const unsigned struct_kernel_stat64_sz = 96;
#elif defined(__arm__)
- const unsigned struct___old_kernel_stat_sz = 32;
const unsigned struct_kernel_stat_sz = 64;
const unsigned struct_kernel_stat64_sz = 104;
+#elif defined(__aarch64__)
+ const unsigned struct_kernel_stat_sz = 128;
+ const unsigned struct_kernel_stat64_sz = 104;
#elif defined(__powerpc__) && !defined(__powerpc64__)
- const unsigned struct___old_kernel_stat_sz = 32;
const unsigned struct_kernel_stat_sz = 72;
const unsigned struct_kernel_stat64_sz = 104;
#elif defined(__powerpc64__)
- const unsigned struct___old_kernel_stat_sz = 0;
const unsigned struct_kernel_stat_sz = 144;
const unsigned struct_kernel_stat64_sz = 104;
+#elif defined(__mips__)
+ #if SANITIZER_WORDSIZE == 64
+ const unsigned struct_kernel_stat_sz = 216;
+ #else
+ const unsigned struct_kernel_stat_sz = 144;
+ #endif
+ const unsigned struct_kernel_stat64_sz = 104;
#endif
- const unsigned struct_io_event_sz = 32;
struct __sanitizer_perf_event_attr {
unsigned type;
unsigned size;
// More fields that vary with the kernel version.
};
- extern unsigned struct_utimbuf_sz;
+ extern unsigned struct_epoll_event_sz;
+ extern unsigned struct_sysinfo_sz;
+ extern unsigned __user_cap_header_struct_sz;
+ extern unsigned __user_cap_data_struct_sz;
extern unsigned struct_new_utsname_sz;
extern unsigned struct_old_utsname_sz;
extern unsigned struct_oldold_utsname_sz;
- extern unsigned struct_msqid_ds_sz;
- extern unsigned struct_mq_attr_sz;
- extern unsigned struct_timex_sz;
- extern unsigned struct_ustat_sz;
+
+ const unsigned struct_kexec_segment_sz = 4 * sizeof(unsigned long);
+#endif // SANITIZER_LINUX
+
+#if SANITIZER_LINUX || SANITIZER_FREEBSD
+
+#if defined(__powerpc64__)
+ const unsigned struct___old_kernel_stat_sz = 0;
+#else
+ const unsigned struct___old_kernel_stat_sz = 32;
+#endif
extern unsigned struct_rlimit_sz;
- extern unsigned struct_epoll_event_sz;
- extern unsigned struct_sysinfo_sz;
+ extern unsigned struct_utimbuf_sz;
extern unsigned struct_timespec_sz;
- extern unsigned __user_cap_header_struct_sz;
- extern unsigned __user_cap_data_struct_sz;
- const unsigned old_sigset_t_sz = sizeof(unsigned long);
- const unsigned struct_kexec_segment_sz = 4 * sizeof(unsigned long);
struct __sanitizer_iocb {
u64 aio_data;
@@ -109,8 +118,17 @@ namespace __sanitizer {
u64 aio_reserved3;
};
+ struct __sanitizer_io_event {
+ u64 data;
+ u64 obj;
+ u64 res;
+ u64 res2;
+ };
+
const unsigned iocb_cmd_pread = 0;
const unsigned iocb_cmd_pwrite = 1;
+ const unsigned iocb_cmd_preadv = 7;
+ const unsigned iocb_cmd_pwritev = 8;
struct __sanitizer___sysctl_args {
int *name;
@@ -121,11 +139,23 @@ namespace __sanitizer {
uptr newlen;
unsigned long ___unused[4];
};
-#endif // SANITIZER_LINUX
+
+ const unsigned old_sigset_t_sz = sizeof(unsigned long);
+#endif // SANITIZER_LINUX || SANITIZER_FREEBSD
+
+#if SANITIZER_ANDROID
+ struct __sanitizer_mallinfo {
+ uptr v[10];
+ };
+#endif
#if SANITIZER_LINUX && !SANITIZER_ANDROID
+ struct __sanitizer_mallinfo {
+ int v[10];
+ };
+
+ extern unsigned struct_ustat_sz;
extern unsigned struct_rlimit64_sz;
- extern unsigned struct_statvfs_sz;
extern unsigned struct_statvfs64_sz;
struct __sanitizer_ipc_perm {
@@ -139,6 +169,12 @@ namespace __sanitizer {
unsigned __seq;
u64 __unused1;
u64 __unused2;
+#elif defined(__mips__)
+ unsigned int mode;
+ unsigned short __seq;
+ unsigned short __pad1;
+ unsigned long __unused1;
+ unsigned long __unused2;
#else
unsigned short mode;
unsigned short __pad1;
@@ -161,40 +197,154 @@ namespace __sanitizer {
#elif !defined(__powerpc64__)
uptr __unused0;
#endif
+ #if defined(__x86_64__) && !defined(_LP64)
+ u64 shm_atime;
+ u64 shm_dtime;
+ u64 shm_ctime;
+ #else
uptr shm_atime;
- #ifndef _LP64
+ #if !defined(_LP64) && !defined(__mips__)
uptr __unused1;
#endif
uptr shm_dtime;
- #ifndef _LP64
+ #if !defined(_LP64) && !defined(__mips__)
uptr __unused2;
#endif
uptr shm_ctime;
- #ifndef _LP64
+ #if !defined(_LP64) && !defined(__mips__)
uptr __unused3;
#endif
+ #endif
#ifdef __powerpc__
uptr shm_segsz;
#endif
int shm_cpid;
int shm_lpid;
+ #if defined(__x86_64__) && !defined(_LP64)
+ u64 shm_nattch;
+ u64 __unused4;
+ u64 __unused5;
+ #else
uptr shm_nattch;
uptr __unused4;
uptr __unused5;
+ #endif
+ };
+#elif SANITIZER_FREEBSD
+ struct __sanitizer_ipc_perm {
+ unsigned int cuid;
+ unsigned int cgid;
+ unsigned int uid;
+ unsigned int gid;
+ unsigned short mode;
+ unsigned short seq;
+ long key;
};
- #endif // SANITIZER_LINUX && !SANITIZER_ANDROID
+
+ struct __sanitizer_shmid_ds {
+ __sanitizer_ipc_perm shm_perm;
+ unsigned long shm_segsz;
+ unsigned int shm_lpid;
+ unsigned int shm_cpid;
+ int shm_nattch;
+ unsigned long shm_atime;
+ unsigned long shm_dtime;
+ unsigned long shm_ctime;
+ };
+#endif
+
+#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
+ extern unsigned struct_msqid_ds_sz;
+ extern unsigned struct_mq_attr_sz;
+ extern unsigned struct_timex_sz;
+ extern unsigned struct_statvfs_sz;
+#endif // (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
struct __sanitizer_iovec {
- void *iov_base;
+ void *iov_base;
uptr iov_len;
};
+#if !SANITIZER_ANDROID
+ struct __sanitizer_ifaddrs {
+ struct __sanitizer_ifaddrs *ifa_next;
+ char *ifa_name;
+ unsigned int ifa_flags;
+ void *ifa_addr; // (struct sockaddr *)
+ void *ifa_netmask; // (struct sockaddr *)
+ // This is a union on Linux.
+# ifdef ifa_dstaddr
+# undef ifa_dstaddr
+# endif
+ void *ifa_dstaddr; // (struct sockaddr *)
+ void *ifa_data;
+ };
+#endif // !SANITIZER_ANDROID
+
#if SANITIZER_MAC
typedef unsigned long __sanitizer_pthread_key_t;
#else
typedef unsigned __sanitizer_pthread_key_t;
#endif
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+
+ struct __sanitizer_XDR {
+ int x_op;
+ void *x_ops;
+ uptr x_public;
+ uptr x_private;
+ uptr x_base;
+ unsigned x_handy;
+ };
+
+ const int __sanitizer_XDR_ENCODE = 0;
+ const int __sanitizer_XDR_DECODE = 1;
+ const int __sanitizer_XDR_FREE = 2;
+#endif
+
+ struct __sanitizer_passwd {
+ char *pw_name;
+ char *pw_passwd;
+ int pw_uid;
+ int pw_gid;
+#if SANITIZER_MAC || SANITIZER_FREEBSD
+ long pw_change;
+ char *pw_class;
+#endif
+#if !SANITIZER_ANDROID
+ char *pw_gecos;
+#endif
+ char *pw_dir;
+ char *pw_shell;
+#if SANITIZER_MAC || SANITIZER_FREEBSD
+ long pw_expire;
+#endif
+#if SANITIZER_FREEBSD
+ int pw_fields;
+#endif
+ };
+
+ struct __sanitizer_group {
+ char *gr_name;
+ char *gr_passwd;
+ int gr_gid;
+ char **gr_mem;
+ };
+
+#if defined(__x86_64__) && !defined(_LP64)
+ typedef long long __sanitizer_time_t;
+#else
+ typedef long __sanitizer_time_t;
+#endif
+
+ struct __sanitizer_timeb {
+ __sanitizer_time_t time;
+ unsigned short millitm;
+ short timezone;
+ short dstflag;
+ };
+
struct __sanitizer_ether_addr {
u8 octet[6];
};
@@ -224,7 +374,7 @@ namespace __sanitizer {
};
#endif
-#if SANITIZER_ANDROID || SANITIZER_MAC
+#if SANITIZER_ANDROID || SANITIZER_MAC || SANITIZER_FREEBSD
struct __sanitizer_msghdr {
void *msg_name;
unsigned msg_namelen;
@@ -263,6 +413,12 @@ namespace __sanitizer {
unsigned short d_reclen;
// more fields that we don't care about
};
+#elif SANITIZER_FREEBSD
+ struct __sanitizer_dirent {
+ unsigned int d_fileno;
+ unsigned short d_reclen;
+ // more fields that we don't care about
+ };
#elif SANITIZER_ANDROID || defined(__x86_64__)
struct __sanitizer_dirent {
unsigned long long d_ino;
@@ -288,8 +444,22 @@ namespace __sanitizer {
};
#endif
+// 'clock_t' is 32 bits wide on x64 FreeBSD
+#if SANITIZER_FREEBSD
+ typedef int __sanitizer_clock_t;
+#elif defined(__x86_64__) && !defined(_LP64)
+ typedef long long __sanitizer_clock_t;
+#else
+ typedef long __sanitizer_clock_t;
+#endif
+
#if SANITIZER_LINUX
-#if defined(_LP64) || defined(__x86_64__) || defined(__powerpc__)
+ typedef int __sanitizer_clockid_t;
+#endif
+
+#if SANITIZER_LINUX || SANITIZER_FREEBSD
+#if defined(_LP64) || defined(__x86_64__) || defined(__powerpc__)\
+ || defined(__mips__)
typedef unsigned __sanitizer___kernel_uid_t;
typedef unsigned __sanitizer___kernel_gid_t;
#else
@@ -302,7 +472,7 @@ namespace __sanitizer {
typedef long __sanitizer___kernel_off_t;
#endif
-#if defined(__powerpc__)
+#if defined(__powerpc__) || defined(__mips__)
typedef unsigned int __sanitizer___kernel_old_uid_t;
typedef unsigned int __sanitizer___kernel_old_gid_t;
#else
@@ -333,28 +503,52 @@ namespace __sanitizer {
// The size is determined by looking at sizeof of real sigset_t on linux.
uptr val[128 / sizeof(uptr)];
};
+#elif SANITIZER_FREEBSD
+ struct __sanitizer_sigset_t {
+ // uint32_t * 4
+ unsigned int __bits[4];
+ };
#endif
+ // Linux system headers define the 'sa_handler' and 'sa_sigaction' macros.
struct __sanitizer_sigaction {
+#if defined(__mips__) && !SANITIZER_FREEBSD
+ unsigned int sa_flags;
+#endif
union {
- void (*sa_handler)(int sig);
- void (*sa_sigaction)(int sig, void *siginfo, void *uctx);
+ void (*sigaction)(int sig, void *siginfo, void *uctx);
+ void (*handler)(int sig);
};
+#if SANITIZER_FREEBSD
+ int sa_flags;
+ __sanitizer_sigset_t sa_mask;
+#else
__sanitizer_sigset_t sa_mask;
+#ifndef __mips__
int sa_flags;
+#endif
+#endif
#if SANITIZER_LINUX
void (*sa_restorer)();
#endif
+#if defined(__mips__) && (SANITIZER_WORDSIZE == 32)
+ int sa_resv[1];
+#endif
};
+#if SANITIZER_FREEBSD
+ typedef __sanitizer_sigset_t __sanitizer_kernel_sigset_t;
+#else
struct __sanitizer_kernel_sigset_t {
u8 sig[8];
};
+#endif
+ // Linux system headers define the 'sa_handler' and 'sa_sigaction' macros.
struct __sanitizer_kernel_sigaction_t {
union {
- void (*sigaction)(int signo, void *info, void *ctx);
void (*handler)(int signo);
+ void (*sigaction)(int signo, void *info, void *ctx);
};
unsigned long sa_flags;
void (*sa_restorer)(void);
@@ -373,7 +567,7 @@ namespace __sanitizer {
extern int af_inet6;
uptr __sanitizer_in_addr_sz(int af);
-#if SANITIZER_LINUX
+#if SANITIZER_LINUX || SANITIZER_FREEBSD
struct __sanitizer_dl_phdr_info {
uptr dlpi_addr;
const char *dlpi_name;
@@ -387,7 +581,7 @@ namespace __sanitizer {
int ai_family;
int ai_socktype;
int ai_protocol;
-#if SANITIZER_ANDROID || SANITIZER_MAC
+#if SANITIZER_ANDROID || SANITIZER_MAC || SANITIZER_FREEBSD
unsigned ai_addrlen;
char *ai_canonname;
void *ai_addr;
@@ -413,13 +607,14 @@ namespace __sanitizer {
short revents;
};
-#if SANITIZER_ANDROID || SANITIZER_MAC
+#if SANITIZER_ANDROID || SANITIZER_MAC || SANITIZER_FREEBSD
typedef unsigned __sanitizer_nfds_t;
#else
typedef unsigned long __sanitizer_nfds_t;
#endif
-#if SANITIZER_LINUX && !SANITIZER_ANDROID
+#if !SANITIZER_ANDROID
+# if SANITIZER_LINUX
struct __sanitizer_glob_t {
uptr gl_pathc;
char **gl_pathv;
@@ -432,10 +627,27 @@ namespace __sanitizer {
int (*gl_lstat)(const char *, void *);
int (*gl_stat)(const char *, void *);
};
+# elif SANITIZER_FREEBSD
+ struct __sanitizer_glob_t {
+ uptr gl_pathc;
+ uptr gl_matchc;
+ uptr gl_offs;
+ int gl_flags;
+ char **gl_pathv;
+ int (*gl_errfunc)(const char*, int);
+ void (*gl_closedir)(void *dirp);
+ struct dirent *(*gl_readdir)(void *dirp);
+ void *(*gl_opendir)(const char*);
+ int (*gl_lstat)(const char*, void* /* struct stat* */);
+ int (*gl_stat)(const char*, void* /* struct stat* */);
+ };
+# endif // SANITIZER_FREEBSD
+# if SANITIZER_LINUX || SANITIZER_FREEBSD
extern int glob_nomatch;
extern int glob_altdirfunc;
-#endif
+# endif
+#endif // !SANITIZER_ANDROID
extern unsigned path_max;
@@ -443,10 +655,38 @@ namespace __sanitizer {
uptr we_wordc;
char **we_wordv;
uptr we_offs;
+#if SANITIZER_FREEBSD
+ char *we_strings;
+ uptr we_nbytes;
+#endif
};
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+ struct __sanitizer_FILE {
+ int _flags;
+ char *_IO_read_ptr;
+ char *_IO_read_end;
+ char *_IO_read_base;
+ char *_IO_write_base;
+ char *_IO_write_ptr;
+ char *_IO_write_end;
+ char *_IO_buf_base;
+ char *_IO_buf_end;
+ char *_IO_save_base;
+ char *_IO_backup_base;
+ char *_IO_save_end;
+ void *_markers;
+ __sanitizer_FILE *_chain;
+ int _fileno;
+ };
+# define SANITIZER_HAS_STRUCT_FILE 1
+#else
+ typedef void __sanitizer_FILE;
+# define SANITIZER_HAS_STRUCT_FILE 0
+#endif
+
#if SANITIZER_LINUX && !SANITIZER_ANDROID && \
- (defined(__i386) || defined (__x86_64)) // NOLINT
+ (defined(__i386) || defined(__x86_64))
extern unsigned struct_user_regs_struct_sz;
extern unsigned struct_user_fpregs_struct_sz;
extern unsigned struct_user_fpxregs_struct_sz;
@@ -464,9 +704,10 @@ namespace __sanitizer {
extern int ptrace_setsiginfo;
extern int ptrace_getregset;
extern int ptrace_setregset;
+ extern int ptrace_geteventmsg;
#endif
-#if SANITIZER_LINUX && !SANITIZER_ANDROID
+#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
extern unsigned struct_shminfo_sz;
extern unsigned struct_shm_info_sz;
extern int shmctl_ipc_stat;
@@ -475,6 +716,8 @@ namespace __sanitizer {
extern int shmctl_shm_stat;
#endif
+ extern int map_fixed;
+
// ioctl arguments
struct __sanitizer_ifconf {
int ifc_len;
@@ -487,7 +730,54 @@ namespace __sanitizer {
};
#endif
-#define IOC_SIZE(nr) (((nr) >> 16) & 0x3fff)
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+struct __sanitizer__obstack_chunk {
+ char *limit;
+ struct __sanitizer__obstack_chunk *prev;
+};
+
+struct __sanitizer_obstack {
+ long chunk_size;
+ struct __sanitizer__obstack_chunk *chunk;
+ char *object_base;
+ char *next_free;
+ uptr more_fields[7];
+};
+#endif
+
+#define IOC_NRBITS 8
+#define IOC_TYPEBITS 8
+#if defined(__powerpc__) || defined(__powerpc64__) || defined(__mips__)
+#define IOC_SIZEBITS 13
+#define IOC_DIRBITS 3
+#define IOC_NONE 1U
+#define IOC_WRITE 4U
+#define IOC_READ 2U
+#else
+#define IOC_SIZEBITS 14
+#define IOC_DIRBITS 2
+#define IOC_NONE 0U
+#define IOC_WRITE 1U
+#define IOC_READ 2U
+#endif
+#define IOC_NRMASK ((1 << IOC_NRBITS) - 1)
+#define IOC_TYPEMASK ((1 << IOC_TYPEBITS) - 1)
+#define IOC_SIZEMASK ((1 << IOC_SIZEBITS) - 1)
+#if defined(IOC_DIRMASK)
+#undef IOC_DIRMASK
+#endif
+#define IOC_DIRMASK ((1 << IOC_DIRBITS) - 1)
+#define IOC_NRSHIFT 0
+#define IOC_TYPESHIFT (IOC_NRSHIFT + IOC_NRBITS)
+#define IOC_SIZESHIFT (IOC_TYPESHIFT + IOC_TYPEBITS)
+#define IOC_DIRSHIFT (IOC_SIZESHIFT + IOC_SIZEBITS)
+#define EVIOC_EV_MAX 0x1f
+#define EVIOC_ABS_MAX 0x3f
+
+#define IOC_DIR(nr) (((nr) >> IOC_DIRSHIFT) & IOC_DIRMASK)
+#define IOC_TYPE(nr) (((nr) >> IOC_TYPESHIFT) & IOC_TYPEMASK)
+#define IOC_NR(nr) (((nr) >> IOC_NRSHIFT) & IOC_NRMASK)
+#define IOC_SIZE(nr) (((nr) >> IOC_SIZESHIFT) & IOC_SIZEMASK)
extern unsigned struct_arpreq_sz;
extern unsigned struct_ifreq_sz;
@@ -503,9 +793,6 @@ namespace __sanitizer {
extern unsigned struct_cdrom_tocentry_sz;
extern unsigned struct_cdrom_tochdr_sz;
extern unsigned struct_cdrom_volctrl_sz;
- extern unsigned struct_copr_buffer_sz;
- extern unsigned struct_copr_debug_buf_sz;
- extern unsigned struct_copr_msg_sz;
extern unsigned struct_ff_effect_sz;
extern unsigned struct_floppy_drive_params_sz;
extern unsigned struct_floppy_drive_struct_sz;
@@ -519,23 +806,28 @@ namespace __sanitizer {
extern unsigned struct_hd_geometry_sz;
extern unsigned struct_input_absinfo_sz;
extern unsigned struct_input_id_sz;
+ extern unsigned struct_mtpos_sz;
+ extern unsigned struct_termio_sz;
+ extern unsigned struct_vt_consize_sz;
+ extern unsigned struct_vt_sizes_sz;
+ extern unsigned struct_vt_stat_sz;
+#endif // SANITIZER_LINUX
+
+#if SANITIZER_LINUX || SANITIZER_FREEBSD
+ extern unsigned struct_copr_buffer_sz;
+ extern unsigned struct_copr_debug_buf_sz;
+ extern unsigned struct_copr_msg_sz;
extern unsigned struct_midi_info_sz;
extern unsigned struct_mtget_sz;
extern unsigned struct_mtop_sz;
- extern unsigned struct_mtpos_sz;
extern unsigned struct_rtentry_sz;
extern unsigned struct_sbi_instrument_sz;
extern unsigned struct_seq_event_rec_sz;
extern unsigned struct_synth_info_sz;
- extern unsigned struct_termio_sz;
- extern unsigned struct_vt_consize_sz;
extern unsigned struct_vt_mode_sz;
- extern unsigned struct_vt_sizes_sz;
- extern unsigned struct_vt_stat_sz;
-#endif
+#endif // SANITIZER_LINUX || SANITIZER_FREEBSD
#if SANITIZER_LINUX && !SANITIZER_ANDROID
- extern unsigned struct_audio_buf_info_sz;
extern unsigned struct_ax25_parms_struct_sz;
extern unsigned struct_cyclades_monitor_sz;
extern unsigned struct_input_keymap_entry_sz;
@@ -546,7 +838,6 @@ namespace __sanitizer {
extern unsigned struct_kbsentry_sz;
extern unsigned struct_mtconfiginfo_sz;
extern unsigned struct_nr_parms_struct_sz;
- extern unsigned struct_ppp_stats_sz;
extern unsigned struct_scc_modem_sz;
extern unsigned struct_scc_stat_sz;
extern unsigned struct_serial_multiport_struct_sz;
@@ -554,7 +845,12 @@ namespace __sanitizer {
extern unsigned struct_sockaddr_ax25_sz;
extern unsigned struct_unimapdesc_sz;
extern unsigned struct_unimapinit_sz;
-#endif
+#endif // SANITIZER_LINUX && !SANITIZER_ANDROID
+
+#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
+ extern unsigned struct_audio_buf_info_sz;
+ extern unsigned struct_ppp_stats_sz;
+#endif // (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
#if !SANITIZER_ANDROID && !SANITIZER_MAC
extern unsigned struct_sioc_sg_req_sz;
@@ -565,7 +861,7 @@ namespace __sanitizer {
// A special value to mark ioctls that are not present on the target platform,
// when it can not be determined without including any system headers.
- extern unsigned IOCTL_NOT_PRESENT;
+ extern const unsigned IOCTL_NOT_PRESENT;
extern unsigned IOCTL_FIOASYNC;
extern unsigned IOCTL_FIOCLEX;
@@ -611,7 +907,7 @@ namespace __sanitizer {
extern unsigned IOCTL_TIOCSPGRP;
extern unsigned IOCTL_TIOCSTI;
extern unsigned IOCTL_TIOCSWINSZ;
-#if (SANITIZER_LINUX && !SANITIZER_ANDROID)
+#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
extern unsigned IOCTL_SIOCGETSGCNT;
extern unsigned IOCTL_SIOCGETVIFCNT;
#endif
@@ -705,9 +1001,7 @@ namespace __sanitizer {
extern unsigned IOCTL_HDIO_SET_MULTCOUNT;
extern unsigned IOCTL_HDIO_SET_NOWERR;
extern unsigned IOCTL_HDIO_SET_UNMASKINTR;
- extern unsigned IOCTL_MTIOCGET;
extern unsigned IOCTL_MTIOCPOS;
- extern unsigned IOCTL_MTIOCTOP;
extern unsigned IOCTL_PPPIOCGASYNCMAP;
extern unsigned IOCTL_PPPIOCGDEBUG;
extern unsigned IOCTL_PPPIOCGFLAGS;
@@ -719,9 +1013,7 @@ namespace __sanitizer {
extern unsigned IOCTL_PPPIOCSMAXCID;
extern unsigned IOCTL_PPPIOCSMRU;
extern unsigned IOCTL_PPPIOCSXASYNCMAP;
- extern unsigned IOCTL_SIOCADDRT;
extern unsigned IOCTL_SIOCDARP;
- extern unsigned IOCTL_SIOCDELRT;
extern unsigned IOCTL_SIOCDRARP;
extern unsigned IOCTL_SIOCGARP;
extern unsigned IOCTL_SIOCGIFENCAP;
@@ -750,6 +1042,39 @@ namespace __sanitizer {
extern unsigned IOCTL_SNDCTL_COPR_SENDMSG;
extern unsigned IOCTL_SNDCTL_COPR_WCODE;
extern unsigned IOCTL_SNDCTL_COPR_WDATA;
+ extern unsigned IOCTL_TCFLSH;
+ extern unsigned IOCTL_TCGETA;
+ extern unsigned IOCTL_TCGETS;
+ extern unsigned IOCTL_TCSBRK;
+ extern unsigned IOCTL_TCSBRKP;
+ extern unsigned IOCTL_TCSETA;
+ extern unsigned IOCTL_TCSETAF;
+ extern unsigned IOCTL_TCSETAW;
+ extern unsigned IOCTL_TCSETS;
+ extern unsigned IOCTL_TCSETSF;
+ extern unsigned IOCTL_TCSETSW;
+ extern unsigned IOCTL_TCXONC;
+ extern unsigned IOCTL_TIOCGLCKTRMIOS;
+ extern unsigned IOCTL_TIOCGSOFTCAR;
+ extern unsigned IOCTL_TIOCINQ;
+ extern unsigned IOCTL_TIOCLINUX;
+ extern unsigned IOCTL_TIOCSERCONFIG;
+ extern unsigned IOCTL_TIOCSERGETLSR;
+ extern unsigned IOCTL_TIOCSERGWILD;
+ extern unsigned IOCTL_TIOCSERSWILD;
+ extern unsigned IOCTL_TIOCSLCKTRMIOS;
+ extern unsigned IOCTL_TIOCSSOFTCAR;
+ extern unsigned IOCTL_VT_DISALLOCATE;
+ extern unsigned IOCTL_VT_GETSTATE;
+ extern unsigned IOCTL_VT_RESIZE;
+ extern unsigned IOCTL_VT_RESIZEX;
+ extern unsigned IOCTL_VT_SENDSIG;
+#endif // SANITIZER_LINUX
+#if SANITIZER_LINUX || SANITIZER_FREEBSD
+ extern unsigned IOCTL_MTIOCGET;
+ extern unsigned IOCTL_MTIOCTOP;
+ extern unsigned IOCTL_SIOCADDRT;
+ extern unsigned IOCTL_SIOCDELRT;
extern unsigned IOCTL_SNDCTL_DSP_GETBLKSIZE;
extern unsigned IOCTL_SNDCTL_DSP_GETFMTS;
extern unsigned IOCTL_SNDCTL_DSP_NONBLOCK;
@@ -840,40 +1165,14 @@ namespace __sanitizer {
extern unsigned IOCTL_SOUND_PCM_READ_RATE;
extern unsigned IOCTL_SOUND_PCM_WRITE_CHANNELS;
extern unsigned IOCTL_SOUND_PCM_WRITE_FILTER;
- extern unsigned IOCTL_TCFLSH;
- extern unsigned IOCTL_TCGETA;
- extern unsigned IOCTL_TCGETS;
- extern unsigned IOCTL_TCSBRK;
- extern unsigned IOCTL_TCSBRKP;
- extern unsigned IOCTL_TCSETA;
- extern unsigned IOCTL_TCSETAF;
- extern unsigned IOCTL_TCSETAW;
- extern unsigned IOCTL_TCSETS;
- extern unsigned IOCTL_TCSETSF;
- extern unsigned IOCTL_TCSETSW;
- extern unsigned IOCTL_TCXONC;
- extern unsigned IOCTL_TIOCGLCKTRMIOS;
- extern unsigned IOCTL_TIOCGSOFTCAR;
- extern unsigned IOCTL_TIOCINQ;
- extern unsigned IOCTL_TIOCLINUX;
- extern unsigned IOCTL_TIOCSERCONFIG;
- extern unsigned IOCTL_TIOCSERGETLSR;
- extern unsigned IOCTL_TIOCSERGWILD;
- extern unsigned IOCTL_TIOCSERSWILD;
- extern unsigned IOCTL_TIOCSLCKTRMIOS;
- extern unsigned IOCTL_TIOCSSOFTCAR;
extern unsigned IOCTL_VT_ACTIVATE;
- extern unsigned IOCTL_VT_DISALLOCATE;
extern unsigned IOCTL_VT_GETMODE;
- extern unsigned IOCTL_VT_GETSTATE;
extern unsigned IOCTL_VT_OPENQRY;
extern unsigned IOCTL_VT_RELDISP;
- extern unsigned IOCTL_VT_RESIZE;
- extern unsigned IOCTL_VT_RESIZEX;
- extern unsigned IOCTL_VT_SENDSIG;
extern unsigned IOCTL_VT_SETMODE;
extern unsigned IOCTL_VT_WAITACTIVE;
-#endif
+#endif // SANITIZER_LINUX || SANITIZER_FREEBSD
+
#if SANITIZER_LINUX && !SANITIZER_ANDROID
extern unsigned IOCTL_CYGETDEFTHRESH;
extern unsigned IOCTL_CYGETDEFTIMEOUT;
@@ -899,37 +1198,25 @@ namespace __sanitizer {
extern unsigned IOCTL_FS_IOC_SETVERSION;
extern unsigned IOCTL_GIO_CMAP;
extern unsigned IOCTL_GIO_FONT;
- extern unsigned IOCTL_GIO_SCRNMAP;
extern unsigned IOCTL_GIO_UNIMAP;
extern unsigned IOCTL_GIO_UNISCRNMAP;
extern unsigned IOCTL_KDADDIO;
extern unsigned IOCTL_KDDELIO;
- extern unsigned IOCTL_KDDISABIO;
- extern unsigned IOCTL_KDENABIO;
extern unsigned IOCTL_KDGETKEYCODE;
- extern unsigned IOCTL_KDGETLED;
- extern unsigned IOCTL_KDGETMODE;
extern unsigned IOCTL_KDGKBDIACR;
extern unsigned IOCTL_KDGKBENT;
extern unsigned IOCTL_KDGKBLED;
extern unsigned IOCTL_KDGKBMETA;
- extern unsigned IOCTL_KDGKBMODE;
extern unsigned IOCTL_KDGKBSENT;
- extern unsigned IOCTL_KDGKBTYPE;
extern unsigned IOCTL_KDMAPDISP;
- extern unsigned IOCTL_KDMKTONE;
extern unsigned IOCTL_KDSETKEYCODE;
- extern unsigned IOCTL_KDSETLED;
- extern unsigned IOCTL_KDSETMODE;
extern unsigned IOCTL_KDSIGACCEPT;
extern unsigned IOCTL_KDSKBDIACR;
extern unsigned IOCTL_KDSKBENT;
extern unsigned IOCTL_KDSKBLED;
extern unsigned IOCTL_KDSKBMETA;
- extern unsigned IOCTL_KDSKBMODE;
extern unsigned IOCTL_KDSKBSENT;
extern unsigned IOCTL_KDUNMAPDISP;
- extern unsigned IOCTL_KIOCSOUND;
extern unsigned IOCTL_LPABORT;
extern unsigned IOCTL_LPABORTOPEN;
extern unsigned IOCTL_LPCAREFUL;
@@ -944,7 +1231,6 @@ namespace __sanitizer {
extern unsigned IOCTL_MTIOCSETCONFIG;
extern unsigned IOCTL_PIO_CMAP;
extern unsigned IOCTL_PIO_FONT;
- extern unsigned IOCTL_PIO_SCRNMAP;
extern unsigned IOCTL_PIO_UNIMAP;
extern unsigned IOCTL_PIO_UNIMAPCLR;
extern unsigned IOCTL_PIO_UNISCRNMAP;
@@ -972,9 +1258,29 @@ namespace __sanitizer {
extern unsigned IOCTL_TIOCSERGETMULTI;
extern unsigned IOCTL_TIOCSERSETMULTI;
extern unsigned IOCTL_TIOCSSERIAL;
+#endif // SANITIZER_LINUX && !SANITIZER_ANDROID
+
+#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
+ extern unsigned IOCTL_GIO_SCRNMAP;
+ extern unsigned IOCTL_KDDISABIO;
+ extern unsigned IOCTL_KDENABIO;
+ extern unsigned IOCTL_KDGETLED;
+ extern unsigned IOCTL_KDGETMODE;
+ extern unsigned IOCTL_KDGKBMODE;
+ extern unsigned IOCTL_KDGKBTYPE;
+ extern unsigned IOCTL_KDMKTONE;
+ extern unsigned IOCTL_KDSETLED;
+ extern unsigned IOCTL_KDSETMODE;
+ extern unsigned IOCTL_KDSKBMODE;
+ extern unsigned IOCTL_KIOCSOUND;
+ extern unsigned IOCTL_PIO_SCRNMAP;
#endif
+ extern const int errno_EINVAL;
extern const int errno_EOWNERDEAD;
+
+ extern const int si_SEGV_MAPERR;
+ extern const int si_SEGV_ACCERR;
} // namespace __sanitizer
#define CHECK_TYPE_SIZE(TYPE) \
diff --git a/lib/sanitizer_common/sanitizer_posix.cc b/lib/sanitizer_common/sanitizer_posix.cc
index ffe91df1a59e..4205c2b116ba 100644
--- a/lib/sanitizer_common/sanitizer_posix.cc
+++ b/lib/sanitizer_common/sanitizer_posix.cc
@@ -13,7 +13,7 @@
//===----------------------------------------------------------------------===//
#include "sanitizer_platform.h"
-#if SANITIZER_LINUX || SANITIZER_MAC
+#if SANITIZER_POSIX
#include "sanitizer_common.h"
#include "sanitizer_libc.h"
@@ -22,6 +22,14 @@
#include <sys/mman.h>
+#if SANITIZER_LINUX
+#include <sys/utsname.h>
+#endif
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+#include <sys/personality.h>
+#endif
+
namespace __sanitizer {
// ------------- sanitizer_common.h
@@ -29,21 +37,68 @@ uptr GetMmapGranularity() {
return GetPageSize();
}
+#if SANITIZER_WORDSIZE == 32
+// Take care of unusable kernel area in top gigabyte.
+static uptr GetKernelAreaSize() {
+#if SANITIZER_LINUX
+ const uptr gbyte = 1UL << 30;
+
+ // Firstly check if there are writable segments
+ // mapped to top gigabyte (e.g. stack).
+ MemoryMappingLayout proc_maps(/*cache_enabled*/true);
+ uptr end, prot;
+ while (proc_maps.Next(/*start*/0, &end,
+ /*offset*/0, /*filename*/0,
+ /*filename_size*/0, &prot)) {
+ if ((end >= 3 * gbyte)
+ && (prot & MemoryMappingLayout::kProtectionWrite) != 0)
+ return 0;
+ }
+
+#if !SANITIZER_ANDROID
+ // Even if nothing is mapped, top Gb may still be accessible
+ // if we are running on 64-bit kernel.
+ // Uname may report misleading results if personality type
+ // is modified (e.g. under schroot) so check this as well.
+ struct utsname uname_info;
+ int pers = personality(0xffffffffUL);
+ if (!(pers & PER_MASK)
+ && uname(&uname_info) == 0
+ && internal_strstr(uname_info.machine, "64"))
+ return 0;
+#endif // SANITIZER_ANDROID
+
+ // Top gigabyte is reserved for kernel.
+ return gbyte;
+#else
+ return 0;
+#endif // SANITIZER_LINUX
+}
+#endif // SANITIZER_WORDSIZE == 32
+
uptr GetMaxVirtualAddress() {
#if SANITIZER_WORDSIZE == 64
# if defined(__powerpc64__)
// On PowerPC64 we have two different address space layouts: 44- and 46-bit.
- // We somehow need to figure our which one we are using now and choose
+ // We somehow need to figure out which one we are using now and choose
// one of 0x00000fffffffffffUL and 0x00003fffffffffffUL.
// Note that with 'ulimit -s unlimited' the stack is moved away from the top
// of the address space, so simply checking the stack address is not enough.
- return (1ULL << 44) - 1; // 0x00000fffffffffffUL
+ // This should (does) work for both PowerPC64 Endian modes.
+ return (1ULL << (MostSignificantSetBitIndex(GET_CURRENT_FRAME()) + 1)) - 1;
+# elif defined(__aarch64__)
+ return (1ULL << 39) - 1;
+# elif defined(__mips64)
+ return (1ULL << 40) - 1; // 0x000000ffffffffffUL;
# else
return (1ULL << 47) - 1; // 0x00007fffffffffffUL;
# endif
#else // SANITIZER_WORDSIZE == 32
- // FIXME: We can probably lower this on Android?
- return (1ULL << 32) - 1; // 0xffffffff;
+ uptr res = (1ULL << 32) - 1; // 0xffffffff;
+ if (!common_flags()->full_address_space)
+ res -= GetKernelAreaSize();
+ CHECK_LT(reinterpret_cast<uptr>(&res), res);
+ return res;
#endif // SANITIZER_WORDSIZE
}
@@ -62,11 +117,13 @@ void *MmapOrDie(uptr size, const char *mem_type) {
Die();
}
recursion_count++;
- Report("ERROR: %s failed to allocate 0x%zx (%zd) bytes of %s: %d\n",
+ Report("ERROR: %s failed to "
+ "allocate 0x%zx (%zd) bytes of %s (errno: %d)\n",
SanitizerToolName, size, size, mem_type, reserrno);
DumpProcessMap();
CHECK("unable to mmap" && 0);
}
+ IncreaseTotalMmap(size);
return (void *)res;
}
@@ -78,6 +135,25 @@ void UnmapOrDie(void *addr, uptr size) {
SanitizerToolName, size, size, addr);
CHECK("unable to unmap" && 0);
}
+ DecreaseTotalMmap(size);
+}
+
+void *MmapNoReserveOrDie(uptr size, const char *mem_type) {
+ uptr PageSize = GetPageSizeCached();
+ uptr p = internal_mmap(0,
+ RoundUpTo(size, PageSize),
+ PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
+ -1, 0);
+ int reserrno;
+ if (internal_iserror(p, &reserrno)) {
+ Report("ERROR: %s failed to "
+ "allocate noreserve 0x%zx (%zd) bytes for '%s' (errno: %d)\n",
+ SanitizerToolName, size, size, mem_type, reserrno);
+ CHECK("unable to mmap" && 0);
+ }
+ IncreaseTotalMmap(size);
+ return (void *)p;
}
void *MmapFixedNoReserve(uptr fixed_addr, uptr size) {
@@ -89,9 +165,10 @@ void *MmapFixedNoReserve(uptr fixed_addr, uptr size) {
-1, 0);
int reserrno;
if (internal_iserror(p, &reserrno))
- Report("ERROR: "
- "%s failed to allocate 0x%zx (%zd) bytes at address %p (%d)\n",
+ Report("ERROR: %s failed to "
+ "allocate 0x%zx (%zd) bytes at address %zx (errno: %d)\n",
SanitizerToolName, size, size, fixed_addr, reserrno);
+ IncreaseTotalMmap(size);
return (void *)p;
}
@@ -104,11 +181,12 @@ void *MmapFixedOrDie(uptr fixed_addr, uptr size) {
-1, 0);
int reserrno;
if (internal_iserror(p, &reserrno)) {
- Report("ERROR:"
- " %s failed to allocate 0x%zx (%zd) bytes at address %p (%d)\n",
+ Report("ERROR: %s failed to "
+ "allocate 0x%zx (%zd) bytes at address %zx (errno: %d)\n",
SanitizerToolName, size, size, fixed_addr, reserrno);
CHECK("unable to mmap" && 0);
}
+ IncreaseTotalMmap(size);
return (void *)p;
}
@@ -131,6 +209,17 @@ void *MapFileToMemory(const char *file_name, uptr *buff_size) {
return internal_iserror(map) ? 0 : (void *)map;
}
+void *MapWritableFileToMemory(void *addr, uptr size, uptr fd, uptr offset) {
+ uptr flags = MAP_SHARED;
+ if (addr) flags |= MAP_FIXED;
+ uptr p = internal_mmap(addr, size, PROT_READ | PROT_WRITE, flags, fd, offset);
+ if (internal_iserror(p)) {
+ Printf("could not map writable file (%zd, %zu, %zu): %zd\n", fd, offset,
+ size, p);
+ return 0;
+ }
+ return (void *)p;
+}
static inline bool IntervalsAreSeparate(uptr start1, uptr end1,
uptr start2, uptr end2) {
@@ -159,7 +248,7 @@ void DumpProcessMap() {
MemoryMappingLayout proc_maps(/*cache_enabled*/true);
uptr start, end;
const sptr kBufSize = 4095;
- char *filename = (char*)MmapOrDie(kBufSize, __FUNCTION__);
+ char *filename = (char*)MmapOrDie(kBufSize, __func__);
Report("Process memory map follows:\n");
while (proc_maps.Next(&start, &end, /* file_offset */0,
filename, kBufSize, /* protection */0)) {
@@ -197,45 +286,24 @@ char *FindPathToBinary(const char *name) {
return 0;
}
-void MaybeOpenReportFile() {
- if (!log_to_file || (report_fd_pid == internal_getpid())) return;
- InternalScopedBuffer<char> report_path_full(4096);
- internal_snprintf(report_path_full.data(), report_path_full.size(),
- "%s.%d", report_path_prefix, internal_getpid());
- uptr openrv = OpenFile(report_path_full.data(), true);
- if (internal_iserror(openrv)) {
- report_fd = kStderrFd;
- log_to_file = false;
- Report("ERROR: Can't open file: %s\n", report_path_full.data());
- Die();
- }
- if (report_fd != kInvalidFd) {
- // We're in the child. Close the parent's log.
- internal_close(report_fd);
- }
- report_fd = openrv;
- report_fd_pid = internal_getpid();
-}
-
-void RawWrite(const char *buffer) {
- static const char *kRawWriteError =
- "RawWrite can't output requested buffer!\n";
- uptr length = (uptr)internal_strlen(buffer);
- MaybeOpenReportFile();
- if (length != internal_write(report_fd, buffer, length)) {
- internal_write(report_fd, kRawWriteError, internal_strlen(kRawWriteError));
+void ReportFile::Write(const char *buffer, uptr length) {
+ SpinMutexLock l(mu);
+ static const char *kWriteError =
+ "ReportFile::Write() can't output requested buffer!\n";
+ ReopenIfNecessary();
+ if (length != internal_write(fd, buffer, length)) {
+ internal_write(fd, kWriteError, internal_strlen(kWriteError));
Die();
}
}
bool GetCodeRangeForFile(const char *module, uptr *start, uptr *end) {
uptr s, e, off, prot;
- InternalMmapVector<char> fn(4096);
- fn.push_back(0);
+ InternalScopedString buff(kMaxPathLength);
MemoryMappingLayout proc_maps(/*cache_enabled*/false);
- while (proc_maps.Next(&s, &e, &off, &fn[0], fn.capacity(), &prot)) {
+ while (proc_maps.Next(&s, &e, &off, buff.data(), buff.size(), &prot)) {
if ((prot & MemoryMappingLayout::kProtectionExecute) != 0
- && internal_strcmp(module, &fn[0]) == 0) {
+ && internal_strcmp(module, buff.data()) == 0) {
*start = s;
*end = e;
return true;
@@ -246,4 +314,4 @@ bool GetCodeRangeForFile(const char *module, uptr *start, uptr *end) {
} // namespace __sanitizer
-#endif // SANITIZER_LINUX || SANITIZER_MAC
+#endif // SANITIZER_POSIX
diff --git a/lib/sanitizer_common/sanitizer_posix_libcdep.cc b/lib/sanitizer_common/sanitizer_posix_libcdep.cc
index 6032f520dee0..ed1e3729a00e 100644
--- a/lib/sanitizer_common/sanitizer_posix_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_posix_libcdep.cc
@@ -14,12 +14,15 @@
#include "sanitizer_platform.h"
-#if SANITIZER_LINUX || SANITIZER_MAC
+#if SANITIZER_POSIX
#include "sanitizer_common.h"
+#include "sanitizer_flags.h"
+#include "sanitizer_platform_limits_posix.h"
#include "sanitizer_stacktrace.h"
#include <errno.h>
#include <pthread.h>
+#include <signal.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/resource.h>
@@ -41,30 +44,49 @@ void FlushUnneededShadowMemory(uptr addr, uptr size) {
madvise((void*)addr, size, MADV_DONTNEED);
}
-void DisableCoreDumper() {
- struct rlimit nocore;
- nocore.rlim_cur = 0;
- nocore.rlim_max = 0;
- setrlimit(RLIMIT_CORE, &nocore);
+static rlim_t getlim(int res) {
+ rlimit rlim;
+ CHECK_EQ(0, getrlimit(res, &rlim));
+ return rlim.rlim_cur;
+}
+
+static void setlim(int res, rlim_t lim) {
+ // The following magic is to prevent clang from replacing it with memset.
+ volatile struct rlimit rlim;
+ rlim.rlim_cur = lim;
+ rlim.rlim_max = lim;
+ if (setrlimit(res, const_cast<struct rlimit *>(&rlim))) {
+ Report("ERROR: %s setrlimit() failed %d\n", SanitizerToolName, errno);
+ Die();
+ }
+}
+
+void DisableCoreDumperIfNecessary() {
+ if (common_flags()->disable_coredump) {
+ setlim(RLIMIT_CORE, 0);
+ }
}
bool StackSizeIsUnlimited() {
- struct rlimit rlim;
- CHECK_EQ(0, getrlimit(RLIMIT_STACK, &rlim));
- return (rlim.rlim_cur == (uptr)-1);
+ rlim_t stack_size = getlim(RLIMIT_STACK);
+ return (stack_size == RLIM_INFINITY);
}
void SetStackSizeLimitInBytes(uptr limit) {
- struct rlimit rlim;
- rlim.rlim_cur = limit;
- rlim.rlim_max = limit;
- if (setrlimit(RLIMIT_STACK, &rlim)) {
- Report("ERROR: %s setrlimit() failed %d\n", SanitizerToolName, errno);
- Die();
- }
+ setlim(RLIMIT_STACK, (rlim_t)limit);
CHECK(!StackSizeIsUnlimited());
}
+bool AddressSpaceIsUnlimited() {
+ rlim_t as_size = getlim(RLIMIT_AS);
+ return (as_size == RLIM_INFINITY);
+}
+
+void SetAddressSpaceUnlimited() {
+ setlim(RLIMIT_AS, RLIM_INFINITY);
+ CHECK(AddressSpaceIsUnlimited());
+}
+
void SleepForSeconds(int seconds) {
sleep(seconds);
}
@@ -89,6 +111,83 @@ int internal_isatty(fd_t fd) {
return isatty(fd);
}
+#ifndef SANITIZER_GO
+// TODO(glider): different tools may require different altstack size.
+static const uptr kAltStackSize = SIGSTKSZ * 4; // SIGSTKSZ is not enough.
+
+void SetAlternateSignalStack() {
+ stack_t altstack, oldstack;
+ CHECK_EQ(0, sigaltstack(0, &oldstack));
+ // If the alternate stack is already in place, do nothing.
+ // Android always sets an alternate stack, but it's too small for us.
+ if (!SANITIZER_ANDROID && !(oldstack.ss_flags & SS_DISABLE)) return;
+ // TODO(glider): the mapped stack should have the MAP_STACK flag in the
+ // future. It is not required by man 2 sigaltstack now (they're using
+ // malloc()).
+ void* base = MmapOrDie(kAltStackSize, __func__);
+ altstack.ss_sp = (char*) base;
+ altstack.ss_flags = 0;
+ altstack.ss_size = kAltStackSize;
+ CHECK_EQ(0, sigaltstack(&altstack, 0));
+}
+
+void UnsetAlternateSignalStack() {
+ stack_t altstack, oldstack;
+ altstack.ss_sp = 0;
+ altstack.ss_flags = SS_DISABLE;
+ altstack.ss_size = kAltStackSize; // Some sane value required on Darwin.
+ CHECK_EQ(0, sigaltstack(&altstack, &oldstack));
+ UnmapOrDie(oldstack.ss_sp, oldstack.ss_size);
+}
+
+typedef void (*sa_sigaction_t)(int, siginfo_t *, void *);
+static void MaybeInstallSigaction(int signum,
+ SignalHandlerType handler) {
+ if (!IsDeadlySignal(signum))
+ return;
+ struct sigaction sigact;
+ internal_memset(&sigact, 0, sizeof(sigact));
+ sigact.sa_sigaction = (sa_sigaction_t)handler;
+ // Do not block the signal from being received in that signal's handler.
+ // Clients are responsible for handling this correctly.
+ sigact.sa_flags = SA_SIGINFO | SA_NODEFER;
+ if (common_flags()->use_sigaltstack) sigact.sa_flags |= SA_ONSTACK;
+ CHECK_EQ(0, internal_sigaction(signum, &sigact, 0));
+ VReport(1, "Installed the sigaction for signal %d\n", signum);
+}
+
+void InstallDeadlySignalHandlers(SignalHandlerType handler) {
+ // Set the alternate signal stack for the main thread.
+ // This will cause SetAlternateSignalStack to be called twice, but the stack
+ // will be actually set only once.
+ if (common_flags()->use_sigaltstack) SetAlternateSignalStack();
+ MaybeInstallSigaction(SIGSEGV, handler);
+ MaybeInstallSigaction(SIGBUS, handler);
+}
+#endif // SANITIZER_GO
+
+bool IsAccessibleMemoryRange(uptr beg, uptr size) {
+ uptr page_size = GetPageSizeCached();
+ // Checking too large memory ranges is slow.
+ CHECK_LT(size, page_size * 10);
+ int sock_pair[2];
+ if (pipe(sock_pair))
+ return false;
+ uptr bytes_written =
+ internal_write(sock_pair[1], reinterpret_cast<void *>(beg), size);
+ int write_errno;
+ bool result;
+ if (internal_iserror(bytes_written, &write_errno)) {
+ CHECK_EQ(EFAULT, write_errno);
+ result = false;
+ } else {
+ result = (bytes_written == size);
+ }
+ internal_close(sock_pair[0]);
+ internal_close(sock_pair[1]);
+ return result;
+}
+
} // namespace __sanitizer
-#endif
+#endif // SANITIZER_POSIX
diff --git a/lib/sanitizer_common/sanitizer_printf.cc b/lib/sanitizer_common/sanitizer_printf.cc
index bbdb24b685de..3be6723cd660 100644
--- a/lib/sanitizer_common/sanitizer_printf.cc
+++ b/lib/sanitizer_common/sanitizer_printf.cc
@@ -16,12 +16,14 @@
#include "sanitizer_common.h"
+#include "sanitizer_flags.h"
#include "sanitizer_libc.h"
#include <stdio.h>
#include <stdarg.h>
-#if SANITIZER_WINDOWS && !defined(va_copy)
+#if SANITIZER_WINDOWS && defined(_MSC_VER) && _MSC_VER < 1800 && \
+ !defined(va_copy)
# define va_copy(dst, src) ((dst) = (src))
#endif
@@ -94,11 +96,14 @@ static int AppendSignedDecimal(char **buff, const char *buff_end, s64 num,
minimal_num_length, pad_with_zero, negative);
}
-static int AppendString(char **buff, const char *buff_end, const char *s) {
+static int AppendString(char **buff, const char *buff_end, int precision,
+ const char *s) {
if (s == 0)
s = "<null>";
int result = 0;
for (; *s; s++) {
+ if (precision >= 0 && result >= precision)
+ break;
result += AppendChar(buff, buff_end, *s);
}
return result;
@@ -106,16 +111,16 @@ static int AppendString(char **buff, const char *buff_end, const char *s) {
static int AppendPointer(char **buff, const char *buff_end, u64 ptr_value) {
int result = 0;
- result += AppendString(buff, buff_end, "0x");
+ result += AppendString(buff, buff_end, -1, "0x");
result += AppendUnsigned(buff, buff_end, ptr_value, 16,
- (SANITIZER_WORDSIZE == 64) ? 12 : 8, true);
+ SANITIZER_POINTER_FORMAT_LENGTH, true);
return result;
}
int VSNPrintf(char *buff, int buff_length,
const char *format, va_list args) {
static const char *kPrintfFormatsHelp =
- "Supported Printf formats: %([0-9]*)?(z|ll)?{d,u,x}; %p; %s; %c\n";
+ "Supported Printf formats: %([0-9]*)?(z|ll)?{d,u,x}; %p; %(\\.\\*)?s; %c\n";
RAW_CHECK(format);
RAW_CHECK(buff_length > 0);
const char *buff_end = &buff[buff_length - 1];
@@ -135,6 +140,12 @@ int VSNPrintf(char *buff, int buff_length,
width = width * 10 + *cur++ - '0';
}
}
+ bool have_precision = (cur[0] == '.' && cur[1] == '*');
+ int precision = -1;
+ if (have_precision) {
+ cur += 2;
+ precision = va_arg(args, int);
+ }
bool have_z = (*cur == 'z');
cur += have_z;
bool have_ll = !have_z && (cur[0] == 'l' && cur[1] == 'l');
@@ -142,6 +153,8 @@ int VSNPrintf(char *buff, int buff_length,
s64 dval;
u64 uval;
bool have_flags = have_width | have_z | have_ll;
+ // Only %s supports precision for now
+ CHECK(!(precision >= 0 && *cur != 's'));
switch (*cur) {
case 'd': {
dval = have_ll ? va_arg(args, s64)
@@ -167,7 +180,7 @@ int VSNPrintf(char *buff, int buff_length,
}
case 's': {
RAW_CHECK_MSG(!have_flags, kPrintfFormatsHelp);
- result += AppendString(&buff, buff_end, va_arg(args, char*));
+ result += AppendString(&buff, buff_end, precision, va_arg(args, char*));
break;
}
case 'c': {
@@ -260,6 +273,7 @@ static void SharedPrintfCode(bool append_pid, const char *format,
break;
}
RawWrite(buffer);
+ AndroidLogWrite(buffer);
CallPrintfAndReportCallback(buffer);
// If we had mapped any memory, clean up.
if (buffer != local_buffer)
@@ -267,6 +281,7 @@ static void SharedPrintfCode(bool append_pid, const char *format,
va_end(args2);
}
+FORMAT(1, 2)
void Printf(const char *format, ...) {
va_list args;
va_start(args, format);
@@ -275,6 +290,7 @@ void Printf(const char *format, ...) {
}
// Like Printf, but prints the current PID before the output string.
+FORMAT(1, 2)
void Report(const char *format, ...) {
va_list args;
va_start(args, format);
@@ -286,6 +302,7 @@ void Report(const char *format, ...) {
// Returns the number of symbols that should have been written to buffer
// (not including trailing '\0'). Thus, the string is truncated
// iff return value is not less than "length".
+FORMAT(3, 4)
int internal_snprintf(char *buffer, uptr length, const char *format, ...) {
va_list args;
va_start(args, format);
@@ -294,6 +311,7 @@ int internal_snprintf(char *buffer, uptr length, const char *format, ...) {
return needed_length;
}
+FORMAT(2, 3)
void InternalScopedString::append(const char *format, ...) {
CHECK_LT(length_, size());
va_list args;
@@ -301,6 +319,7 @@ void InternalScopedString::append(const char *format, ...) {
VSNPrintf(data() + length_, size() - length_, format, args);
va_end(args);
length_ += internal_strlen(data() + length_);
+ CHECK_LT(length_, size());
}
} // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_procmaps.h b/lib/sanitizer_common/sanitizer_procmaps.h
index 65bcac6338d5..94e3871af9a2 100644
--- a/lib/sanitizer_common/sanitizer_procmaps.h
+++ b/lib/sanitizer_common/sanitizer_procmaps.h
@@ -14,49 +14,38 @@
#ifndef SANITIZER_PROCMAPS_H
#define SANITIZER_PROCMAPS_H
+#include "sanitizer_common.h"
#include "sanitizer_internal_defs.h"
#include "sanitizer_mutex.h"
namespace __sanitizer {
-#if SANITIZER_WINDOWS
-class MemoryMappingLayout {
- public:
- explicit MemoryMappingLayout(bool cache_enabled) {
- (void)cache_enabled;
- }
- bool GetObjectNameAndOffset(uptr addr, uptr *offset,
- char filename[], uptr filename_size,
- uptr *protection) {
- UNIMPLEMENTED();
- }
-};
-
-#else // SANITIZER_WINDOWS
-#if SANITIZER_LINUX
+#if SANITIZER_FREEBSD || SANITIZER_LINUX
struct ProcSelfMapsBuff {
char *data;
uptr mmaped_size;
uptr len;
};
-#endif // SANITIZER_LINUX
+
+// Reads process memory map in an OS-specific way.
+void ReadProcMaps(ProcSelfMapsBuff *proc_maps);
+#endif // SANITIZER_FREEBSD || SANITIZER_LINUX
class MemoryMappingLayout {
public:
explicit MemoryMappingLayout(bool cache_enabled);
+ ~MemoryMappingLayout();
bool Next(uptr *start, uptr *end, uptr *offset,
char filename[], uptr filename_size, uptr *protection);
void Reset();
- // Gets the object file name and the offset in that object for a given
- // address 'addr'. Returns true on success.
- bool GetObjectNameAndOffset(uptr addr, uptr *offset,
- char filename[], uptr filename_size,
- uptr *protection);
// In some cases, e.g. when running under a sandbox on Linux, ASan is unable
// to obtain the memory mappings. It should fall back to pre-cached data
// instead of aborting.
static void CacheMemoryMappings();
- ~MemoryMappingLayout();
+
+ // Stores the list of mapped objects into an array.
+ uptr DumpListOfModules(LoadedModule *modules, uptr max_modules,
+ string_predicate_t filter);
// Memory protection masks.
static const uptr kProtectionRead = 1;
@@ -66,41 +55,12 @@ class MemoryMappingLayout {
private:
void LoadFromCache();
- // Default implementation of GetObjectNameAndOffset.
- // Quite slow, because it iterates through the whole process map for each
- // lookup.
- bool IterateForObjectNameAndOffset(uptr addr, uptr *offset,
- char filename[], uptr filename_size,
- uptr *protection) {
- Reset();
- uptr start, end, file_offset;
- for (int i = 0; Next(&start, &end, &file_offset, filename, filename_size,
- protection);
- i++) {
- if (addr >= start && addr < end) {
- // Don't subtract 'start' for the first entry:
- // * If a binary is compiled w/o -pie, then the first entry in
- // process maps is likely the binary itself (all dynamic libs
- // are mapped higher in address space). For such a binary,
- // instruction offset in binary coincides with the actual
- // instruction address in virtual memory (as code section
- // is mapped to a fixed memory range).
- // * If a binary is compiled with -pie, all the modules are
- // mapped high at address space (in particular, higher than
- // shadow memory of the tool), so the module can't be the
- // first entry.
- *offset = (addr - (i ? start : 0)) + file_offset;
- return true;
- }
- }
- if (filename_size)
- filename[0] = '\0';
- return false;
- }
-
-# if SANITIZER_LINUX
+
+ // FIXME: Hide implementation details for different platforms in
+ // platform-specific files.
+# if SANITIZER_FREEBSD || SANITIZER_LINUX
ProcSelfMapsBuff proc_self_maps_;
- char *current_;
+ const char *current_;
// Static mappings cache.
static ProcSelfMapsBuff cached_proc_self_maps_;
@@ -129,7 +89,10 @@ void GetMemoryProfile(fill_profile_f cb, uptr *stats, uptr stats_size);
// Returns code range for the specified module.
bool GetCodeRangeForFile(const char *module, uptr *start, uptr *end);
-#endif // SANITIZER_WINDOWS
+bool IsDecimal(char c);
+uptr ParseDecimal(const char **p);
+bool IsHex(char c);
+uptr ParseHex(const char **p);
} // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_procmaps_common.cc b/lib/sanitizer_common/sanitizer_procmaps_common.cc
new file mode 100644
index 000000000000..2ec08d7f127b
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_procmaps_common.cc
@@ -0,0 +1,178 @@
+//===-- sanitizer_procmaps_common.cc --------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Information about the process mappings (common parts).
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_platform.h"
+#if SANITIZER_FREEBSD || SANITIZER_LINUX
+#include "sanitizer_common.h"
+#include "sanitizer_placement_new.h"
+#include "sanitizer_procmaps.h"
+
+namespace __sanitizer {
+
+// Linker initialized.
+ProcSelfMapsBuff MemoryMappingLayout::cached_proc_self_maps_;
+StaticSpinMutex MemoryMappingLayout::cache_lock_; // Linker initialized.
+
+static int TranslateDigit(char c) {
+ if (c >= '0' && c <= '9')
+ return c - '0';
+ if (c >= 'a' && c <= 'f')
+ return c - 'a' + 10;
+ if (c >= 'A' && c <= 'F')
+ return c - 'A' + 10;
+ return -1;
+}
+
+// Parse a number and promote 'p' up to the first non-digit character.
+static uptr ParseNumber(const char **p, int base) {
+ uptr n = 0;
+ int d;
+ CHECK(base >= 2 && base <= 16);
+ while ((d = TranslateDigit(**p)) >= 0 && d < base) {
+ n = n * base + d;
+ (*p)++;
+ }
+ return n;
+}
+
+bool IsDecimal(char c) {
+ int d = TranslateDigit(c);
+ return d >= 0 && d < 10;
+}
+
+uptr ParseDecimal(const char **p) {
+ return ParseNumber(p, 10);
+}
+
+bool IsHex(char c) {
+ int d = TranslateDigit(c);
+ return d >= 0 && d < 16;
+}
+
+uptr ParseHex(const char **p) {
+ return ParseNumber(p, 16);
+}
+
+MemoryMappingLayout::MemoryMappingLayout(bool cache_enabled) {
+ ReadProcMaps(&proc_self_maps_);
+ if (cache_enabled) {
+ if (proc_self_maps_.mmaped_size == 0) {
+ LoadFromCache();
+ CHECK_GT(proc_self_maps_.len, 0);
+ }
+ } else {
+ CHECK_GT(proc_self_maps_.mmaped_size, 0);
+ }
+ Reset();
+ // FIXME: in the future we may want to cache the mappings on demand only.
+ if (cache_enabled)
+ CacheMemoryMappings();
+}
+
+MemoryMappingLayout::~MemoryMappingLayout() {
+ // Only unmap the buffer if it is different from the cached one. Otherwise
+ // it will be unmapped when the cache is refreshed.
+ if (proc_self_maps_.data != cached_proc_self_maps_.data) {
+ UnmapOrDie(proc_self_maps_.data, proc_self_maps_.mmaped_size);
+ }
+}
+
+void MemoryMappingLayout::Reset() {
+ current_ = proc_self_maps_.data;
+}
+
+// static
+void MemoryMappingLayout::CacheMemoryMappings() {
+ SpinMutexLock l(&cache_lock_);
+ // Don't invalidate the cache if the mappings are unavailable.
+ ProcSelfMapsBuff old_proc_self_maps;
+ old_proc_self_maps = cached_proc_self_maps_;
+ ReadProcMaps(&cached_proc_self_maps_);
+ if (cached_proc_self_maps_.mmaped_size == 0) {
+ cached_proc_self_maps_ = old_proc_self_maps;
+ } else {
+ if (old_proc_self_maps.mmaped_size) {
+ UnmapOrDie(old_proc_self_maps.data,
+ old_proc_self_maps.mmaped_size);
+ }
+ }
+}
+
+void MemoryMappingLayout::LoadFromCache() {
+ SpinMutexLock l(&cache_lock_);
+ if (cached_proc_self_maps_.data) {
+ proc_self_maps_ = cached_proc_self_maps_;
+ }
+}
+
+uptr MemoryMappingLayout::DumpListOfModules(LoadedModule *modules,
+ uptr max_modules,
+ string_predicate_t filter) {
+ Reset();
+ uptr cur_beg, cur_end, cur_offset, prot;
+ InternalScopedString module_name(kMaxPathLength);
+ uptr n_modules = 0;
+ for (uptr i = 0; n_modules < max_modules &&
+ Next(&cur_beg, &cur_end, &cur_offset, module_name.data(),
+ module_name.size(), &prot);
+ i++) {
+ const char *cur_name = module_name.data();
+ if (cur_name[0] == '\0')
+ continue;
+ if (filter && !filter(cur_name))
+ continue;
+ void *mem = &modules[n_modules];
+ // Don't subtract 'cur_beg' from the first entry:
+ // * If a binary is compiled w/o -pie, then the first entry in
+ // process maps is likely the binary itself (all dynamic libs
+ // are mapped higher in address space). For such a binary,
+ // instruction offset in binary coincides with the actual
+ // instruction address in virtual memory (as code section
+ // is mapped to a fixed memory range).
+ // * If a binary is compiled with -pie, all the modules are
+ // mapped high at address space (in particular, higher than
+ // shadow memory of the tool), so the module can't be the
+ // first entry.
+ uptr base_address = (i ? cur_beg : 0) - cur_offset;
+ LoadedModule *cur_module = new(mem) LoadedModule(cur_name, base_address);
+ cur_module->addAddressRange(cur_beg, cur_end, prot & kProtectionExecute);
+ n_modules++;
+ }
+ return n_modules;
+}
+
+void GetMemoryProfile(fill_profile_f cb, uptr *stats, uptr stats_size) {
+ char *smaps = 0;
+ uptr smaps_cap = 0;
+ uptr smaps_len = ReadFileToBuffer("/proc/self/smaps",
+ &smaps, &smaps_cap, 64<<20);
+ uptr start = 0;
+ bool file = false;
+ const char *pos = smaps;
+ while (pos < smaps + smaps_len) {
+ if (IsHex(pos[0])) {
+ start = ParseHex(&pos);
+ for (; *pos != '/' && *pos > '\n'; pos++) {}
+ file = *pos == '/';
+ } else if (internal_strncmp(pos, "Rss:", 4) == 0) {
+ while (!IsDecimal(*pos)) pos++;
+ uptr rss = ParseDecimal(&pos) * 1024;
+ cb(start, rss, file, stats, stats_size);
+ }
+ while (*pos++ != '\n') {}
+ }
+ UnmapOrDie(smaps, smaps_cap);
+}
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_FREEBSD || SANITIZER_LINUX
diff --git a/lib/sanitizer_common/sanitizer_procmaps_freebsd.cc b/lib/sanitizer_common/sanitizer_procmaps_freebsd.cc
new file mode 100644
index 000000000000..5011b1ff14b2
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_procmaps_freebsd.cc
@@ -0,0 +1,88 @@
+//===-- sanitizer_procmaps_freebsd.cc -------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Information about the process mappings (FreeBSD-specific parts).
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_platform.h"
+#if SANITIZER_FREEBSD
+#include "sanitizer_common.h"
+#include "sanitizer_freebsd.h"
+#include "sanitizer_procmaps.h"
+
+#include <unistd.h>
+#include <sys/sysctl.h>
+#include <sys/user.h>
+
+// Fix 'kinfo_vmentry' definition on FreeBSD prior v9.2 in 32-bit mode.
+#if SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32)
+# include <osreldate.h>
+# if __FreeBSD_version <= 902001 // v9.2
+# define kinfo_vmentry xkinfo_vmentry
+# endif
+#endif
+
+namespace __sanitizer {
+
+void ReadProcMaps(ProcSelfMapsBuff *proc_maps) {
+ const int Mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_VMMAP, getpid() };
+ size_t Size = 0;
+ int Err = sysctl(Mib, 4, NULL, &Size, NULL, 0);
+ CHECK_EQ(Err, 0);
+ CHECK_GT(Size, 0);
+
+ size_t MmapedSize = Size * 4 / 3;
+ void *VmMap = MmapOrDie(MmapedSize, "ReadProcMaps()");
+ Size = MmapedSize;
+ Err = sysctl(Mib, 4, VmMap, &Size, NULL, 0);
+ CHECK_EQ(Err, 0);
+
+ proc_maps->data = (char*)VmMap;
+ proc_maps->mmaped_size = MmapedSize;
+ proc_maps->len = Size;
+}
+
+bool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset,
+ char filename[], uptr filename_size,
+ uptr *protection) {
+ char *last = proc_self_maps_.data + proc_self_maps_.len;
+ if (current_ >= last) return false;
+ uptr dummy;
+ if (!start) start = &dummy;
+ if (!end) end = &dummy;
+ if (!offset) offset = &dummy;
+ if (!protection) protection = &dummy;
+ struct kinfo_vmentry *VmEntry = (struct kinfo_vmentry*)current_;
+
+ *start = (uptr)VmEntry->kve_start;
+ *end = (uptr)VmEntry->kve_end;
+ *offset = (uptr)VmEntry->kve_offset;
+
+ *protection = 0;
+ if ((VmEntry->kve_protection & KVME_PROT_READ) != 0)
+ *protection |= kProtectionRead;
+ if ((VmEntry->kve_protection & KVME_PROT_WRITE) != 0)
+ *protection |= kProtectionWrite;
+ if ((VmEntry->kve_protection & KVME_PROT_EXEC) != 0)
+ *protection |= kProtectionExecute;
+
+ if (filename != NULL && filename_size > 0) {
+ internal_snprintf(filename,
+ Min(filename_size, (uptr)PATH_MAX),
+ "%s", VmEntry->kve_path);
+ }
+
+ current_ += VmEntry->kve_structsize;
+
+ return true;
+}
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_FREEBSD
diff --git a/lib/sanitizer_common/sanitizer_procmaps_linux.cc b/lib/sanitizer_common/sanitizer_procmaps_linux.cc
new file mode 100644
index 000000000000..79ca4dfd8fca
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_procmaps_linux.cc
@@ -0,0 +1,90 @@
+//===-- sanitizer_procmaps_linux.cc ---------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Information about the process mappings (Linux-specific parts).
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_platform.h"
+#if SANITIZER_LINUX
+#include "sanitizer_common.h"
+#include "sanitizer_procmaps.h"
+
+namespace __sanitizer {
+
+void ReadProcMaps(ProcSelfMapsBuff *proc_maps) {
+ proc_maps->len = ReadFileToBuffer("/proc/self/maps", &proc_maps->data,
+ &proc_maps->mmaped_size, 1 << 26);
+}
+
+static bool IsOneOf(char c, char c1, char c2) {
+ return c == c1 || c == c2;
+}
+
+bool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset,
+ char filename[], uptr filename_size,
+ uptr *protection) {
+ char *last = proc_self_maps_.data + proc_self_maps_.len;
+ if (current_ >= last) return false;
+ uptr dummy;
+ if (!start) start = &dummy;
+ if (!end) end = &dummy;
+ if (!offset) offset = &dummy;
+ if (!protection) protection = &dummy;
+ char *next_line = (char*)internal_memchr(current_, '\n', last - current_);
+ if (next_line == 0)
+ next_line = last;
+ // Example: 08048000-08056000 r-xp 00000000 03:0c 64593 /foo/bar
+ *start = ParseHex(&current_);
+ CHECK_EQ(*current_++, '-');
+ *end = ParseHex(&current_);
+ CHECK_EQ(*current_++, ' ');
+ CHECK(IsOneOf(*current_, '-', 'r'));
+ *protection = 0;
+ if (*current_++ == 'r')
+ *protection |= kProtectionRead;
+ CHECK(IsOneOf(*current_, '-', 'w'));
+ if (*current_++ == 'w')
+ *protection |= kProtectionWrite;
+ CHECK(IsOneOf(*current_, '-', 'x'));
+ if (*current_++ == 'x')
+ *protection |= kProtectionExecute;
+ CHECK(IsOneOf(*current_, 's', 'p'));
+ if (*current_++ == 's')
+ *protection |= kProtectionShared;
+ CHECK_EQ(*current_++, ' ');
+ *offset = ParseHex(&current_);
+ CHECK_EQ(*current_++, ' ');
+ ParseHex(&current_);
+ CHECK_EQ(*current_++, ':');
+ ParseHex(&current_);
+ CHECK_EQ(*current_++, ' ');
+ while (IsDecimal(*current_))
+ current_++;
+ // Qemu may lack the trailing space.
+ // http://code.google.com/p/address-sanitizer/issues/detail?id=160
+ // CHECK_EQ(*current_++, ' ');
+ // Skip spaces.
+ while (current_ < next_line && *current_ == ' ')
+ current_++;
+ // Fill in the filename.
+ uptr i = 0;
+ while (current_ < next_line) {
+ if (filename && i < filename_size - 1)
+ filename[i++] = *current_;
+ current_++;
+ }
+ if (filename && i < filename_size)
+ filename[i] = 0;
+ current_ = next_line + 1;
+ return true;
+}
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_LINUX
diff --git a/lib/sanitizer_common/sanitizer_procmaps_mac.cc b/lib/sanitizer_common/sanitizer_procmaps_mac.cc
new file mode 100644
index 000000000000..c0a86149788c
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_procmaps_mac.cc
@@ -0,0 +1,190 @@
+//===-- sanitizer_procmaps_mac.cc -----------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Information about the process mappings (Mac-specific parts).
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_platform.h"
+#if SANITIZER_MAC
+#include "sanitizer_common.h"
+#include "sanitizer_placement_new.h"
+#include "sanitizer_procmaps.h"
+
+#include <mach-o/dyld.h>
+#include <mach-o/loader.h>
+
+namespace __sanitizer {
+
+MemoryMappingLayout::MemoryMappingLayout(bool cache_enabled) {
+ Reset();
+}
+
+MemoryMappingLayout::~MemoryMappingLayout() {
+}
+
+// More information about Mach-O headers can be found in mach-o/loader.h
+// Each Mach-O image has a header (mach_header or mach_header_64) starting with
+// a magic number, and a list of linker load commands directly following the
+// header.
+// A load command is at least two 32-bit words: the command type and the
+// command size in bytes. We're interested only in segment load commands
+// (LC_SEGMENT and LC_SEGMENT_64), which tell that a part of the file is mapped
+// into the task's address space.
+// The |vmaddr|, |vmsize| and |fileoff| fields of segment_command or
+// segment_command_64 correspond to the memory address, memory size and the
+// file offset of the current memory segment.
+// Because these fields are taken from the images as is, one needs to add
+// _dyld_get_image_vmaddr_slide() to get the actual addresses at runtime.
+
+void MemoryMappingLayout::Reset() {
+ // Count down from the top.
+ // TODO(glider): as per man 3 dyld, iterating over the headers with
+ // _dyld_image_count is thread-unsafe. We need to register callbacks for
+ // adding and removing images which will invalidate the MemoryMappingLayout
+ // state.
+ current_image_ = _dyld_image_count();
+ current_load_cmd_count_ = -1;
+ current_load_cmd_addr_ = 0;
+ current_magic_ = 0;
+ current_filetype_ = 0;
+}
+
+// static
+void MemoryMappingLayout::CacheMemoryMappings() {
+ // No-op on Mac for now.
+}
+
+void MemoryMappingLayout::LoadFromCache() {
+ // No-op on Mac for now.
+}
+
+// Next and NextSegmentLoad were inspired by base/sysinfo.cc in
+// Google Perftools, http://code.google.com/p/google-perftools.
+
+// NextSegmentLoad scans the current image for the next segment load command
+// and returns the start and end addresses and file offset of the corresponding
+// segment.
+// Note that the segment addresses are not necessarily sorted.
+template<u32 kLCSegment, typename SegmentCommand>
+bool MemoryMappingLayout::NextSegmentLoad(
+ uptr *start, uptr *end, uptr *offset,
+ char filename[], uptr filename_size, uptr *protection) {
+ const char* lc = current_load_cmd_addr_;
+ current_load_cmd_addr_ += ((const load_command *)lc)->cmdsize;
+ if (((const load_command *)lc)->cmd == kLCSegment) {
+ const sptr dlloff = _dyld_get_image_vmaddr_slide(current_image_);
+ const SegmentCommand* sc = (const SegmentCommand *)lc;
+ if (start) *start = sc->vmaddr + dlloff;
+ if (protection) {
+ // Return the initial protection.
+ *protection = sc->initprot;
+ }
+ if (end) *end = sc->vmaddr + sc->vmsize + dlloff;
+ if (offset) {
+ if (current_filetype_ == /*MH_EXECUTE*/ 0x2) {
+ *offset = sc->vmaddr;
+ } else {
+ *offset = sc->fileoff;
+ }
+ }
+ if (filename) {
+ internal_strncpy(filename, _dyld_get_image_name(current_image_),
+ filename_size);
+ }
+ return true;
+ }
+ return false;
+}
+
+bool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset,
+ char filename[], uptr filename_size,
+ uptr *protection) {
+ for (; current_image_ >= 0; current_image_--) {
+ const mach_header* hdr = _dyld_get_image_header(current_image_);
+ if (!hdr) continue;
+ if (current_load_cmd_count_ < 0) {
+ // Set up for this image;
+ current_load_cmd_count_ = hdr->ncmds;
+ current_magic_ = hdr->magic;
+ current_filetype_ = hdr->filetype;
+ switch (current_magic_) {
+#ifdef MH_MAGIC_64
+ case MH_MAGIC_64: {
+ current_load_cmd_addr_ = (char*)hdr + sizeof(mach_header_64);
+ break;
+ }
+#endif
+ case MH_MAGIC: {
+ current_load_cmd_addr_ = (char*)hdr + sizeof(mach_header);
+ break;
+ }
+ default: {
+ continue;
+ }
+ }
+ }
+
+ for (; current_load_cmd_count_ >= 0; current_load_cmd_count_--) {
+ switch (current_magic_) {
+ // current_magic_ may be only one of MH_MAGIC, MH_MAGIC_64.
+#ifdef MH_MAGIC_64
+ case MH_MAGIC_64: {
+ if (NextSegmentLoad<LC_SEGMENT_64, struct segment_command_64>(
+ start, end, offset, filename, filename_size, protection))
+ return true;
+ break;
+ }
+#endif
+ case MH_MAGIC: {
+ if (NextSegmentLoad<LC_SEGMENT, struct segment_command>(
+ start, end, offset, filename, filename_size, protection))
+ return true;
+ break;
+ }
+ }
+ }
+ // If we get here, no more load_cmd's in this image talk about
+ // segments. Go on to the next image.
+ }
+ return false;
+}
+
+uptr MemoryMappingLayout::DumpListOfModules(LoadedModule *modules,
+ uptr max_modules,
+ string_predicate_t filter) {
+ Reset();
+ uptr cur_beg, cur_end, prot;
+ InternalScopedString module_name(kMaxPathLength);
+ uptr n_modules = 0;
+ for (uptr i = 0; n_modules < max_modules &&
+ Next(&cur_beg, &cur_end, 0, module_name.data(),
+ module_name.size(), &prot);
+ i++) {
+ const char *cur_name = module_name.data();
+ if (cur_name[0] == '\0')
+ continue;
+ if (filter && !filter(cur_name))
+ continue;
+ LoadedModule *cur_module = 0;
+ if (n_modules > 0 &&
+ 0 == internal_strcmp(cur_name, modules[n_modules - 1].full_name())) {
+ cur_module = &modules[n_modules - 1];
+ } else {
+ void *mem = &modules[n_modules];
+ cur_module = new(mem) LoadedModule(cur_name, cur_beg);
+ n_modules++;
+ }
+ cur_module->addAddressRange(cur_beg, cur_end, prot & kProtectionExecute);
+ }
+ return n_modules;
+}
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_MAC
diff --git a/lib/sanitizer_common/sanitizer_report_decorator.h b/lib/sanitizer_common/sanitizer_report_decorator.h
index eef2b15ccd34..86536aa19658 100644
--- a/lib/sanitizer_common/sanitizer_report_decorator.h
+++ b/lib/sanitizer_common/sanitizer_report_decorator.h
@@ -17,13 +17,19 @@
#ifndef SANITIZER_REPORT_DECORATOR_H
#define SANITIZER_REPORT_DECORATOR_H
+#include "sanitizer_common.h"
+
namespace __sanitizer {
-class AnsiColorDecorator {
+class SanitizerCommonDecorator {
// FIXME: This is not portable. It assumes the special strings are printed to
// stdout, which is not the case on Windows (see SetConsoleTextAttribute()).
public:
- explicit AnsiColorDecorator(bool use_ansi_colors) : ansi_(use_ansi_colors) { }
+ SanitizerCommonDecorator() : ansi_(ColorizeReports()) {}
const char *Bold() const { return ansi_ ? "\033[1m" : ""; }
+ const char *Default() const { return ansi_ ? "\033[1m\033[0m" : ""; }
+ const char *Warning() { return Red(); }
+ const char *EndWarning() { return Default(); }
+ protected:
const char *Black() const { return ansi_ ? "\033[1m\033[30m" : ""; }
const char *Red() const { return ansi_ ? "\033[1m\033[31m" : ""; }
const char *Green() const { return ansi_ ? "\033[1m\033[32m" : ""; }
@@ -32,10 +38,10 @@ class AnsiColorDecorator {
const char *Magenta() const { return ansi_ ? "\033[1m\033[35m" : ""; }
const char *Cyan() const { return ansi_ ? "\033[1m\033[36m" : ""; }
const char *White() const { return ansi_ ? "\033[1m\033[37m" : ""; }
- const char *Default() const { return ansi_ ? "\033[1m\033[0m" : ""; }
private:
bool ansi_;
};
+
} // namespace __sanitizer
#endif // SANITIZER_REPORT_DECORATOR_H
diff --git a/lib/sanitizer_common/sanitizer_stackdepot.cc b/lib/sanitizer_common/sanitizer_stackdepot.cc
index 2793bd0714a1..f10f1f973fd0 100644
--- a/lib/sanitizer_common/sanitizer_stackdepot.cc
+++ b/lib/sanitizer_common/sanitizer_stackdepot.cc
@@ -12,193 +12,118 @@
//===----------------------------------------------------------------------===//
#include "sanitizer_stackdepot.h"
+
#include "sanitizer_common.h"
-#include "sanitizer_internal_defs.h"
-#include "sanitizer_mutex.h"
-#include "sanitizer_atomic.h"
+#include "sanitizer_stackdepotbase.h"
namespace __sanitizer {
-const int kTabSize = 1024 * 1024; // Hash table size.
-const int kPartBits = 8;
-const int kPartShift = sizeof(u32) * 8 - kPartBits - 1;
-const int kPartCount = 1 << kPartBits; // Number of subparts in the table.
-const int kPartSize = kTabSize / kPartCount;
-const int kMaxId = 1 << kPartShift;
-
-struct StackDesc {
- StackDesc *link;
+struct StackDepotNode {
+ StackDepotNode *link;
u32 id;
- u32 hash;
+ atomic_uint32_t hash_and_use_count; // hash_bits : 12; use_count : 20;
uptr size;
uptr stack[1]; // [size]
-};
-static struct {
- StaticSpinMutex mtx; // Protects alloc of new blocks for region allocator.
- atomic_uintptr_t region_pos; // Region allocator for StackDesc's.
- atomic_uintptr_t region_end;
- atomic_uintptr_t tab[kTabSize]; // Hash table of StackDesc's.
- atomic_uint32_t seq[kPartCount]; // Unique id generators.
-} depot;
+ static const u32 kTabSizeLog = 20;
+ // Lower kTabSizeLog bits are equal for all items in one bucket.
+ // We use these bits to store the per-stack use counter.
+ static const u32 kUseCountBits = kTabSizeLog;
+ static const u32 kMaxUseCount = 1 << kUseCountBits;
+ static const u32 kUseCountMask = (1 << kUseCountBits) - 1;
+ static const u32 kHashMask = ~kUseCountMask;
+
+ typedef StackTrace args_type;
+ bool eq(u32 hash, const args_type &args) const {
+ u32 hash_bits =
+ atomic_load(&hash_and_use_count, memory_order_relaxed) & kHashMask;
+ if ((hash & kHashMask) != hash_bits || args.size != size) return false;
+ uptr i = 0;
+ for (; i < size; i++) {
+ if (stack[i] != args.trace[i]) return false;
+ }
+ return true;
+ }
+ static uptr storage_size(const args_type &args) {
+ return sizeof(StackDepotNode) + (args.size - 1) * sizeof(uptr);
+ }
+ static u32 hash(const args_type &args) {
+ // murmur2
+ const u32 m = 0x5bd1e995;
+ const u32 seed = 0x9747b28c;
+ const u32 r = 24;
+ u32 h = seed ^ (args.size * sizeof(uptr));
+ for (uptr i = 0; i < args.size; i++) {
+ u32 k = args.trace[i];
+ k *= m;
+ k ^= k >> r;
+ k *= m;
+ h *= m;
+ h ^= k;
+ }
+ h ^= h >> 13;
+ h *= m;
+ h ^= h >> 15;
+ return h;
+ }
+ static bool is_valid(const args_type &args) {
+ return args.size > 0 && args.trace;
+ }
+ void store(const args_type &args, u32 hash) {
+ atomic_store(&hash_and_use_count, hash & kHashMask, memory_order_relaxed);
+ size = args.size;
+ internal_memcpy(stack, args.trace, size * sizeof(uptr));
+ }
+ args_type load() const {
+ return args_type(&stack[0], size);
+ }
+ StackDepotHandle get_handle() { return StackDepotHandle(this); }
-static StackDepotStats stats;
+ typedef StackDepotHandle handle_type;
+};
-StackDepotStats *StackDepotGetStats() {
- return &stats;
-}
+COMPILER_CHECK(StackDepotNode::kMaxUseCount == (u32)kStackDepotMaxUseCount);
-static u32 hash(const uptr *stack, uptr size) {
- // murmur2
- const u32 m = 0x5bd1e995;
- const u32 seed = 0x9747b28c;
- const u32 r = 24;
- u32 h = seed ^ (size * sizeof(uptr));
- for (uptr i = 0; i < size; i++) {
- u32 k = stack[i];
- k *= m;
- k ^= k >> r;
- k *= m;
- h *= m;
- h ^= k;
- }
- h ^= h >> 13;
- h *= m;
- h ^= h >> 15;
- return h;
+u32 StackDepotHandle::id() { return node_->id; }
+int StackDepotHandle::use_count() {
+ return atomic_load(&node_->hash_and_use_count, memory_order_relaxed) &
+ StackDepotNode::kUseCountMask;
}
-
-static StackDesc *tryallocDesc(uptr memsz) {
- // Optimisic lock-free allocation, essentially try to bump the region ptr.
- for (;;) {
- uptr cmp = atomic_load(&depot.region_pos, memory_order_acquire);
- uptr end = atomic_load(&depot.region_end, memory_order_acquire);
- if (cmp == 0 || cmp + memsz > end)
- return 0;
- if (atomic_compare_exchange_weak(
- &depot.region_pos, &cmp, cmp + memsz,
- memory_order_acquire))
- return (StackDesc*)cmp;
- }
+void StackDepotHandle::inc_use_count_unsafe() {
+ u32 prev =
+ atomic_fetch_add(&node_->hash_and_use_count, 1, memory_order_relaxed) &
+ StackDepotNode::kUseCountMask;
+ CHECK_LT(prev + 1, StackDepotNode::kMaxUseCount);
}
-static StackDesc *allocDesc(uptr size) {
- // First, try to allocate optimisitically.
- uptr memsz = sizeof(StackDesc) + (size - 1) * sizeof(uptr);
- StackDesc *s = tryallocDesc(memsz);
- if (s)
- return s;
- // If failed, lock, retry and alloc new superblock.
- SpinMutexLock l(&depot.mtx);
- for (;;) {
- s = tryallocDesc(memsz);
- if (s)
- return s;
- atomic_store(&depot.region_pos, 0, memory_order_relaxed);
- uptr allocsz = 64 * 1024;
- if (allocsz < memsz)
- allocsz = memsz;
- uptr mem = (uptr)MmapOrDie(allocsz, "stack depot");
- stats.mapped += allocsz;
- atomic_store(&depot.region_end, mem + allocsz, memory_order_release);
- atomic_store(&depot.region_pos, mem, memory_order_release);
- }
+// FIXME(dvyukov): this single reserved bit is used in TSan.
+typedef StackDepotBase<StackDepotNode, 1, StackDepotNode::kTabSizeLog>
+ StackDepot;
+static StackDepot theDepot;
+
+StackDepotStats *StackDepotGetStats() {
+ return theDepot.GetStats();
}
-static u32 find(StackDesc *s, const uptr *stack, uptr size, u32 hash) {
- // Searches linked list s for the stack, returns its id.
- for (; s; s = s->link) {
- if (s->hash == hash && s->size == size) {
- uptr i = 0;
- for (; i < size; i++) {
- if (stack[i] != s->stack[i])
- break;
- }
- if (i == size)
- return s->id;
- }
- }
- return 0;
+u32 StackDepotPut(StackTrace stack) {
+ StackDepotHandle h = theDepot.Put(stack);
+ return h.valid() ? h.id() : 0;
}
-static StackDesc *lock(atomic_uintptr_t *p) {
- // Uses the pointer lsb as mutex.
- for (int i = 0;; i++) {
- uptr cmp = atomic_load(p, memory_order_relaxed);
- if ((cmp & 1) == 0
- && atomic_compare_exchange_weak(p, &cmp, cmp | 1,
- memory_order_acquire))
- return (StackDesc*)cmp;
- if (i < 10)
- proc_yield(10);
- else
- internal_sched_yield();
- }
+StackDepotHandle StackDepotPut_WithHandle(StackTrace stack) {
+ return theDepot.Put(stack);
}
-static void unlock(atomic_uintptr_t *p, StackDesc *s) {
- DCHECK_EQ((uptr)s & 1, 0);
- atomic_store(p, (uptr)s, memory_order_release);
+StackTrace StackDepotGet(u32 id) {
+ return theDepot.Get(id);
}
-u32 StackDepotPut(const uptr *stack, uptr size) {
- if (stack == 0 || size == 0)
- return 0;
- uptr h = hash(stack, size);
- atomic_uintptr_t *p = &depot.tab[h % kTabSize];
- uptr v = atomic_load(p, memory_order_consume);
- StackDesc *s = (StackDesc*)(v & ~1);
- // First, try to find the existing stack.
- u32 id = find(s, stack, size, h);
- if (id)
- return id;
- // If failed, lock, retry and insert new.
- StackDesc *s2 = lock(p);
- if (s2 != s) {
- id = find(s2, stack, size, h);
- if (id) {
- unlock(p, s2);
- return id;
- }
- }
- uptr part = (h % kTabSize) / kPartSize;
- id = atomic_fetch_add(&depot.seq[part], 1, memory_order_relaxed) + 1;
- stats.n_uniq_ids++;
- CHECK_LT(id, kMaxId);
- id |= part << kPartShift;
- CHECK_NE(id, 0);
- CHECK_EQ(id & (1u << 31), 0);
- s = allocDesc(size);
- s->id = id;
- s->hash = h;
- s->size = size;
- internal_memcpy(s->stack, stack, size * sizeof(uptr));
- s->link = s2;
- unlock(p, s);
- return id;
+void StackDepotLockAll() {
+ theDepot.LockAll();
}
-const uptr *StackDepotGet(u32 id, uptr *size) {
- if (id == 0)
- return 0;
- CHECK_EQ(id & (1u << 31), 0);
- // High kPartBits contain part id, so we need to scan at most kPartSize lists.
- uptr part = id >> kPartShift;
- for (int i = 0; i != kPartSize; i++) {
- uptr idx = part * kPartSize + i;
- CHECK_LT(idx, kTabSize);
- atomic_uintptr_t *p = &depot.tab[idx];
- uptr v = atomic_load(p, memory_order_consume);
- StackDesc *s = (StackDesc*)(v & ~1);
- for (; s; s = s->link) {
- if (s->id == id) {
- *size = s->size;
- return s->stack;
- }
- }
- }
- *size = 0;
- return 0;
+void StackDepotUnlockAll() {
+ theDepot.UnlockAll();
}
bool StackDepotReverseMap::IdDescPair::IdComparator(
@@ -209,10 +134,10 @@ bool StackDepotReverseMap::IdDescPair::IdComparator(
StackDepotReverseMap::StackDepotReverseMap()
: map_(StackDepotGetStats()->n_uniq_ids + 100) {
- for (int idx = 0; idx < kTabSize; idx++) {
- atomic_uintptr_t *p = &depot.tab[idx];
+ for (int idx = 0; idx < StackDepot::kTabSize; idx++) {
+ atomic_uintptr_t *p = &theDepot.tab[idx];
uptr v = atomic_load(p, memory_order_consume);
- StackDesc *s = (StackDesc*)(v & ~1);
+ StackDepotNode *s = (StackDepotNode*)(v & ~1);
for (; s; s = s->link) {
IdDescPair pair = {s->id, s};
map_.push_back(pair);
@@ -221,18 +146,15 @@ StackDepotReverseMap::StackDepotReverseMap()
InternalSort(&map_, map_.size(), IdDescPair::IdComparator);
}
-const uptr *StackDepotReverseMap::Get(u32 id, uptr *size) {
- if (!map_.size()) return 0;
+StackTrace StackDepotReverseMap::Get(u32 id) {
+ if (!map_.size())
+ return StackTrace();
IdDescPair pair = {id, 0};
uptr idx = InternalBinarySearch(map_, 0, map_.size(), pair,
IdDescPair::IdComparator);
- if (idx > map_.size()) {
- *size = 0;
- return 0;
- }
- StackDesc *desc = map_[idx].desc;
- *size = desc->size;
- return desc->stack;
+ if (idx > map_.size())
+ return StackTrace();
+ return map_[idx].desc->load();
}
} // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_stackdepot.h b/lib/sanitizer_common/sanitizer_stackdepot.h
index 4f77ff28eab1..5e3a8b783ac7 100644
--- a/lib/sanitizer_common/sanitizer_stackdepot.h
+++ b/lib/sanitizer_common/sanitizer_stackdepot.h
@@ -15,24 +15,32 @@
#include "sanitizer_common.h"
#include "sanitizer_internal_defs.h"
+#include "sanitizer_stacktrace.h"
namespace __sanitizer {
// StackDepot efficiently stores huge amounts of stack traces.
-
-// Maps stack trace to an unique id.
-u32 StackDepotPut(const uptr *stack, uptr size);
-// Retrieves a stored stack trace by the id.
-const uptr *StackDepotGet(u32 id, uptr *size);
-
-struct StackDepotStats {
- uptr n_uniq_ids;
- uptr mapped;
+struct StackDepotNode;
+struct StackDepotHandle {
+ StackDepotNode *node_;
+ StackDepotHandle() : node_(0) {}
+ explicit StackDepotHandle(StackDepotNode *node) : node_(node) {}
+ bool valid() { return node_; }
+ u32 id();
+ int use_count();
+ void inc_use_count_unsafe();
};
+const int kStackDepotMaxUseCount = 1U << 20;
+
StackDepotStats *StackDepotGetStats();
+u32 StackDepotPut(StackTrace stack);
+StackDepotHandle StackDepotPut_WithHandle(StackTrace stack);
+// Retrieves a stored stack trace by the id.
+StackTrace StackDepotGet(u32 id);
-struct StackDesc;
+void StackDepotLockAll();
+void StackDepotUnlockAll();
// Instantiating this class creates a snapshot of StackDepot which can be
// efficiently queried with StackDepotGet(). You can use it concurrently with
@@ -41,12 +49,12 @@ struct StackDesc;
class StackDepotReverseMap {
public:
StackDepotReverseMap();
- const uptr *Get(u32 id, uptr *size);
+ StackTrace Get(u32 id);
private:
struct IdDescPair {
u32 id;
- StackDesc *desc;
+ StackDepotNode *desc;
static bool IdComparator(const IdDescPair &a, const IdDescPair &b);
};
@@ -57,6 +65,7 @@ class StackDepotReverseMap {
StackDepotReverseMap(const StackDepotReverseMap&);
void operator=(const StackDepotReverseMap&);
};
+
} // namespace __sanitizer
#endif // SANITIZER_STACKDEPOT_H
diff --git a/lib/sanitizer_common/sanitizer_stackdepotbase.h b/lib/sanitizer_common/sanitizer_stackdepotbase.h
new file mode 100644
index 000000000000..5de2e711fe45
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_stackdepotbase.h
@@ -0,0 +1,176 @@
+//===-- sanitizer_stackdepotbase.h ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Implementation of a mapping from arbitrary values to unique 32-bit
+// identifiers.
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_STACKDEPOTBASE_H
+#define SANITIZER_STACKDEPOTBASE_H
+
+#include "sanitizer_internal_defs.h"
+#include "sanitizer_mutex.h"
+#include "sanitizer_atomic.h"
+#include "sanitizer_persistent_allocator.h"
+
+namespace __sanitizer {
+
+template <class Node, int kReservedBits, int kTabSizeLog>
+class StackDepotBase {
+ public:
+ typedef typename Node::args_type args_type;
+ typedef typename Node::handle_type handle_type;
+ // Maps stack trace to an unique id.
+ handle_type Put(args_type args, bool *inserted = 0);
+ // Retrieves a stored stack trace by the id.
+ args_type Get(u32 id);
+
+ StackDepotStats *GetStats() { return &stats; }
+
+ void LockAll();
+ void UnlockAll();
+
+ private:
+ static Node *find(Node *s, args_type args, u32 hash);
+ static Node *lock(atomic_uintptr_t *p);
+ static void unlock(atomic_uintptr_t *p, Node *s);
+
+ static const int kTabSize = 1 << kTabSizeLog; // Hash table size.
+ static const int kPartBits = 8;
+ static const int kPartShift = sizeof(u32) * 8 - kPartBits - kReservedBits;
+ static const int kPartCount =
+ 1 << kPartBits; // Number of subparts in the table.
+ static const int kPartSize = kTabSize / kPartCount;
+ static const int kMaxId = 1 << kPartShift;
+
+ atomic_uintptr_t tab[kTabSize]; // Hash table of Node's.
+ atomic_uint32_t seq[kPartCount]; // Unique id generators.
+
+ StackDepotStats stats;
+
+ friend class StackDepotReverseMap;
+};
+
+template <class Node, int kReservedBits, int kTabSizeLog>
+Node *StackDepotBase<Node, kReservedBits, kTabSizeLog>::find(Node *s,
+ args_type args,
+ u32 hash) {
+ // Searches linked list s for the stack, returns its id.
+ for (; s; s = s->link) {
+ if (s->eq(hash, args)) {
+ return s;
+ }
+ }
+ return 0;
+}
+
+template <class Node, int kReservedBits, int kTabSizeLog>
+Node *StackDepotBase<Node, kReservedBits, kTabSizeLog>::lock(
+ atomic_uintptr_t *p) {
+ // Uses the pointer lsb as mutex.
+ for (int i = 0;; i++) {
+ uptr cmp = atomic_load(p, memory_order_relaxed);
+ if ((cmp & 1) == 0 &&
+ atomic_compare_exchange_weak(p, &cmp, cmp | 1, memory_order_acquire))
+ return (Node *)cmp;
+ if (i < 10)
+ proc_yield(10);
+ else
+ internal_sched_yield();
+ }
+}
+
+template <class Node, int kReservedBits, int kTabSizeLog>
+void StackDepotBase<Node, kReservedBits, kTabSizeLog>::unlock(
+ atomic_uintptr_t *p, Node *s) {
+ DCHECK_EQ((uptr)s & 1, 0);
+ atomic_store(p, (uptr)s, memory_order_release);
+}
+
+template <class Node, int kReservedBits, int kTabSizeLog>
+typename StackDepotBase<Node, kReservedBits, kTabSizeLog>::handle_type
+StackDepotBase<Node, kReservedBits, kTabSizeLog>::Put(args_type args,
+ bool *inserted) {
+ if (inserted) *inserted = false;
+ if (!Node::is_valid(args)) return handle_type();
+ uptr h = Node::hash(args);
+ atomic_uintptr_t *p = &tab[h % kTabSize];
+ uptr v = atomic_load(p, memory_order_consume);
+ Node *s = (Node *)(v & ~1);
+ // First, try to find the existing stack.
+ Node *node = find(s, args, h);
+ if (node) return node->get_handle();
+ // If failed, lock, retry and insert new.
+ Node *s2 = lock(p);
+ if (s2 != s) {
+ node = find(s2, args, h);
+ if (node) {
+ unlock(p, s2);
+ return node->get_handle();
+ }
+ }
+ uptr part = (h % kTabSize) / kPartSize;
+ u32 id = atomic_fetch_add(&seq[part], 1, memory_order_relaxed) + 1;
+ stats.n_uniq_ids++;
+ CHECK_LT(id, kMaxId);
+ id |= part << kPartShift;
+ CHECK_NE(id, 0);
+ CHECK_EQ(id & (((u32)-1) >> kReservedBits), id);
+ uptr memsz = Node::storage_size(args);
+ s = (Node *)PersistentAlloc(memsz);
+ stats.allocated += memsz;
+ s->id = id;
+ s->store(args, h);
+ s->link = s2;
+ unlock(p, s);
+ if (inserted) *inserted = true;
+ return s->get_handle();
+}
+
+template <class Node, int kReservedBits, int kTabSizeLog>
+typename StackDepotBase<Node, kReservedBits, kTabSizeLog>::args_type
+StackDepotBase<Node, kReservedBits, kTabSizeLog>::Get(u32 id) {
+ if (id == 0) {
+ return args_type();
+ }
+ CHECK_EQ(id & (((u32)-1) >> kReservedBits), id);
+ // High kPartBits contain part id, so we need to scan at most kPartSize lists.
+ uptr part = id >> kPartShift;
+ for (int i = 0; i != kPartSize; i++) {
+ uptr idx = part * kPartSize + i;
+ CHECK_LT(idx, kTabSize);
+ atomic_uintptr_t *p = &tab[idx];
+ uptr v = atomic_load(p, memory_order_consume);
+ Node *s = (Node *)(v & ~1);
+ for (; s; s = s->link) {
+ if (s->id == id) {
+ return s->load();
+ }
+ }
+ }
+ return args_type();
+}
+
+template <class Node, int kReservedBits, int kTabSizeLog>
+void StackDepotBase<Node, kReservedBits, kTabSizeLog>::LockAll() {
+ for (int i = 0; i < kTabSize; ++i) {
+ lock(&tab[i]);
+ }
+}
+
+template <class Node, int kReservedBits, int kTabSizeLog>
+void StackDepotBase<Node, kReservedBits, kTabSizeLog>::UnlockAll() {
+ for (int i = 0; i < kTabSize; ++i) {
+ atomic_uintptr_t *p = &tab[i];
+ uptr s = atomic_load(p, memory_order_relaxed);
+ unlock(p, (Node *)(s & ~1UL));
+ }
+}
+
+} // namespace __sanitizer
+#endif // SANITIZER_STACKDEPOTBASE_H
diff --git a/lib/sanitizer_common/sanitizer_stacktrace.cc b/lib/sanitizer_common/sanitizer_stacktrace.cc
index 70ce26bde0d2..cf061fb8c73f 100644
--- a/lib/sanitizer_common/sanitizer_stacktrace.cc
+++ b/lib/sanitizer_common/sanitizer_stacktrace.cc
@@ -13,144 +13,95 @@
#include "sanitizer_common.h"
#include "sanitizer_flags.h"
-#include "sanitizer_procmaps.h"
#include "sanitizer_stacktrace.h"
-#include "sanitizer_symbolizer.h"
namespace __sanitizer {
uptr StackTrace::GetPreviousInstructionPc(uptr pc) {
-#ifdef __arm__
+#if defined(__arm__)
// Cancel Thumb bit.
pc = pc & (~1);
#endif
#if defined(__powerpc__) || defined(__powerpc64__)
// PCs are always 4 byte aligned.
return pc - 4;
-#elif defined(__sparc__)
+#elif defined(__sparc__) || defined(__mips__)
return pc - 8;
#else
return pc - 1;
#endif
}
-static void PrintStackFramePrefix(InternalScopedString *buffer, uptr frame_num,
- uptr pc) {
- buffer->append(" #%zu 0x%zx", frame_num, pc);
-}
-
-void StackTrace::PrintStack(const uptr *addr, uptr size,
- SymbolizeCallback symbolize_callback) {
- if (addr == 0) {
- Printf("<empty stack>\n\n");
- return;
- }
- MemoryMappingLayout proc_maps(/*cache_enabled*/true);
- InternalScopedBuffer<char> buff(GetPageSizeCached() * 2);
- InternalScopedBuffer<AddressInfo> addr_frames(64);
- InternalScopedString frame_desc(GetPageSizeCached() * 2);
- uptr frame_num = 0;
- for (uptr i = 0; i < size && addr[i]; i++) {
- // PCs in stack traces are actually the return addresses, that is,
- // addresses of the next instructions after the call.
- uptr pc = GetPreviousInstructionPc(addr[i]);
- uptr addr_frames_num = 0; // The number of stack frames for current
- // instruction address.
- if (symbolize_callback) {
- if (symbolize_callback((void*)pc, buff.data(), buff.size())) {
- addr_frames_num = 1;
- frame_desc.clear();
- PrintStackFramePrefix(&frame_desc, frame_num, pc);
- // We can't know anything about the string returned by external
- // symbolizer, but if it starts with filename, try to strip path prefix
- // from it.
- frame_desc.append(
- " %s",
- StripPathPrefix(buff.data(), common_flags()->strip_path_prefix));
- Printf("%s\n", frame_desc.data());
- frame_num++;
- }
- }
- if (common_flags()->symbolize && addr_frames_num == 0) {
- // Use our own (online) symbolizer, if necessary.
- if (Symbolizer *sym = Symbolizer::GetOrNull())
- addr_frames_num =
- sym->SymbolizeCode(pc, addr_frames.data(), addr_frames.size());
- for (uptr j = 0; j < addr_frames_num; j++) {
- AddressInfo &info = addr_frames[j];
- frame_desc.clear();
- PrintStackFramePrefix(&frame_desc, frame_num, pc);
- if (info.function) {
- frame_desc.append(" in %s", info.function);
- }
- if (info.file) {
- frame_desc.append(" ");
- PrintSourceLocation(&frame_desc, info.file, info.line, info.column);
- } else if (info.module) {
- frame_desc.append(" ");
- PrintModuleAndOffset(&frame_desc, info.module, info.module_offset);
- }
- Printf("%s\n", frame_desc.data());
- frame_num++;
- info.Clear();
- }
- }
- if (addr_frames_num == 0) {
- // If online symbolization failed, try to output at least module and
- // offset for instruction.
- frame_desc.clear();
- PrintStackFramePrefix(&frame_desc, frame_num, pc);
- uptr offset;
- if (proc_maps.GetObjectNameAndOffset(pc, &offset,
- buff.data(), buff.size(),
- /* protection */0)) {
- frame_desc.append(" ");
- PrintModuleAndOffset(&frame_desc, buff.data(), offset);
- }
- Printf("%s\n", frame_desc.data());
- frame_num++;
- }
- }
- // Always print a trailing empty line after stack trace.
- Printf("\n");
+uptr StackTrace::GetNextInstructionPc(uptr pc) {
+#if defined(__mips__)
+ return pc + 8;
+#else
+ return pc + 1;
+#endif
}
uptr StackTrace::GetCurrentPc() {
return GET_CALLER_PC();
}
-void StackTrace::FastUnwindStack(uptr pc, uptr bp,
- uptr stack_top, uptr stack_bottom,
- uptr max_depth) {
- if (max_depth == 0) {
- size = 0;
- return;
- }
- trace[0] = pc;
+void BufferedStackTrace::Init(const uptr *pcs, uptr cnt, uptr extra_top_pc) {
+ size = cnt + !!extra_top_pc;
+ CHECK_LE(size, kStackTraceMax);
+ internal_memcpy(trace_buffer, pcs, cnt * sizeof(trace_buffer[0]));
+ if (extra_top_pc)
+ trace_buffer[cnt] = extra_top_pc;
+ top_frame_bp = 0;
+}
+
+// Check if given pointer points into allocated stack area.
+static inline bool IsValidFrame(uptr frame, uptr stack_top, uptr stack_bottom) {
+ return frame > stack_bottom && frame < stack_top - 2 * sizeof (uhwptr);
+}
+
+// In GCC on ARM bp points to saved lr, not fp, so we should check the next
+// cell in stack to be a saved frame pointer. GetCanonicFrame returns the
+// pointer to saved frame pointer in any case.
+static inline uhwptr *GetCanonicFrame(uptr bp,
+ uptr stack_top,
+ uptr stack_bottom) {
+#ifdef __arm__
+ if (!IsValidFrame(bp, stack_top, stack_bottom)) return 0;
+ uhwptr *bp_prev = (uhwptr *)bp;
+ if (IsValidFrame((uptr)bp_prev[0], stack_top, stack_bottom)) return bp_prev;
+ // The next frame pointer does not look right. This could be a GCC frame, step
+ // back by 1 word and try again.
+ if (IsValidFrame((uptr)bp_prev[-1], stack_top, stack_bottom))
+ return bp_prev - 1;
+ // Nope, this does not look right either. This means the frame after next does
+ // not have a valid frame pointer, but we can still extract the caller PC.
+ // Unfortunately, there is no way to decide between GCC and LLVM frame
+ // layouts. Assume LLVM.
+ return bp_prev;
+#else
+ return (uhwptr*)bp;
+#endif
+}
+
+void BufferedStackTrace::FastUnwindStack(uptr pc, uptr bp, uptr stack_top,
+ uptr stack_bottom, uptr max_depth) {
+ CHECK_GE(max_depth, 2);
+ trace_buffer[0] = pc;
size = 1;
- uhwptr *frame = (uhwptr *)bp;
- uhwptr *prev_frame = frame - 1;
if (stack_top < 4096) return; // Sanity check for stack top.
+ uhwptr *frame = GetCanonicFrame(bp, stack_top, stack_bottom);
+ // Lowest possible address that makes sense as the next frame pointer.
+ // Goes up as we walk the stack.
+ uptr bottom = stack_bottom;
// Avoid infinite loop when frame == frame[0] by using frame > prev_frame.
- while (frame > prev_frame &&
- frame < (uhwptr *)stack_top - 2 &&
- frame > (uhwptr *)stack_bottom &&
+ while (IsValidFrame((uptr)frame, stack_top, bottom) &&
IsAligned((uptr)frame, sizeof(*frame)) &&
size < max_depth) {
uhwptr pc1 = frame[1];
if (pc1 != pc) {
- trace[size++] = (uptr) pc1;
+ trace_buffer[size++] = (uptr) pc1;
}
- prev_frame = frame;
- frame = (uhwptr *)frame[0];
- }
-}
-
-void StackTrace::PopStackFrames(uptr count) {
- CHECK(size >= count);
- size -= count;
- for (uptr i = 0; i < size; i++) {
- trace[i] = trace[i + count];
+ bottom = (uptr)frame;
+ frame = GetCanonicFrame((uptr)frame[0], stack_top, bottom);
}
}
@@ -158,10 +109,18 @@ static bool MatchPc(uptr cur_pc, uptr trace_pc, uptr threshold) {
return cur_pc - trace_pc <= threshold || trace_pc - cur_pc <= threshold;
}
-uptr StackTrace::LocatePcInTrace(uptr pc) {
+void BufferedStackTrace::PopStackFrames(uptr count) {
+ CHECK_LT(count, size);
+ size -= count;
+ for (uptr i = 0; i < size; ++i) {
+ trace_buffer[i] = trace_buffer[i + count];
+ }
+}
+
+uptr BufferedStackTrace::LocatePcInTrace(uptr pc) {
// Use threshold to find PC in stack trace, as PC we want to unwind from may
// slightly differ from return address in the actual unwinded stack trace.
- const int kPcThreshold = 96;
+ const int kPcThreshold = 288;
for (uptr i = 0; i < size; ++i) {
if (MatchPc(pc, trace[i], kPcThreshold))
return i;
diff --git a/lib/sanitizer_common/sanitizer_stacktrace.h b/lib/sanitizer_common/sanitizer_stacktrace.h
index 5042f230188a..e755c052cb77 100644
--- a/lib/sanitizer_common/sanitizer_stacktrace.h
+++ b/lib/sanitizer_common/sanitizer_stacktrace.h
@@ -19,10 +19,9 @@ namespace __sanitizer {
static const uptr kStackTraceMax = 256;
-#if SANITIZER_LINUX && (defined(__arm__) || \
- defined(__powerpc__) || defined(__powerpc64__) || \
- defined(__sparc__) || \
- defined(__mips__))
+#if SANITIZER_LINUX && (defined(__aarch64__) || defined(__powerpc__) || \
+ defined(__powerpc64__) || defined(__sparc__) || \
+ defined(__mips__))
# define SANITIZER_CAN_FAST_UNWIND 0
#elif SANITIZER_WINDOWS
# define SANITIZER_CAN_FAST_UNWIND 0
@@ -30,46 +29,62 @@ static const uptr kStackTraceMax = 256;
# define SANITIZER_CAN_FAST_UNWIND 1
#endif
+// Fast unwind is the only option on Mac for now; we will need to
+// revisit this macro when slow unwind works on Mac, see
+// https://code.google.com/p/address-sanitizer/issues/detail?id=137
+#if SANITIZER_MAC
+# define SANITIZER_CAN_SLOW_UNWIND 0
+#else
+# define SANITIZER_CAN_SLOW_UNWIND 1
+#endif
+
struct StackTrace {
- typedef bool (*SymbolizeCallback)(const void *pc, char *out_buffer,
- int out_size);
- uptr top_frame_bp;
+ const uptr *trace;
uptr size;
- uptr trace[kStackTraceMax];
+
+ StackTrace() : trace(nullptr), size(0) {}
+ StackTrace(const uptr *trace, uptr size) : trace(trace), size(size) {}
// Prints a symbolized stacktrace, followed by an empty line.
- static void PrintStack(const uptr *addr, uptr size,
- SymbolizeCallback symbolize_callback = 0);
-
- void CopyFrom(const uptr *src, uptr src_size) {
- top_frame_bp = 0;
- size = src_size;
- if (size > kStackTraceMax) size = kStackTraceMax;
- for (uptr i = 0; i < size; i++)
- trace[i] = src[i];
- }
+ void Print() const;
static bool WillUseFastUnwind(bool request_fast_unwind) {
- // Check if fast unwind is available. Fast unwind is the only option on Mac.
if (!SANITIZER_CAN_FAST_UNWIND)
return false;
- else if (SANITIZER_MAC)
+ else if (!SANITIZER_CAN_SLOW_UNWIND)
return true;
return request_fast_unwind;
}
- void Unwind(uptr max_depth, uptr pc, uptr bp, uptr stack_top,
- uptr stack_bottom, bool request_fast_unwind);
-
static uptr GetCurrentPc();
static uptr GetPreviousInstructionPc(uptr pc);
+ static uptr GetNextInstructionPc(uptr pc);
+ typedef bool (*SymbolizeCallback)(const void *pc, char *out_buffer,
+ int out_size);
+};
+
+// StackTrace that owns the buffer used to store the addresses.
+struct BufferedStackTrace : public StackTrace {
+ uptr trace_buffer[kStackTraceMax];
+ uptr top_frame_bp; // Optional bp of a top frame.
+
+ BufferedStackTrace() : StackTrace(trace_buffer, 0), top_frame_bp(0) {}
+
+ void Init(const uptr *pcs, uptr cnt, uptr extra_top_pc = 0);
+ void Unwind(uptr max_depth, uptr pc, uptr bp, void *context, uptr stack_top,
+ uptr stack_bottom, bool request_fast_unwind);
private:
void FastUnwindStack(uptr pc, uptr bp, uptr stack_top, uptr stack_bottom,
uptr max_depth);
void SlowUnwindStack(uptr pc, uptr max_depth);
+ void SlowUnwindStackWithContext(uptr pc, void *context,
+ uptr max_depth);
void PopStackFrames(uptr count);
uptr LocatePcInTrace(uptr pc);
+
+ BufferedStackTrace(const BufferedStackTrace &);
+ void operator=(const BufferedStackTrace &);
};
} // namespace __sanitizer
@@ -82,6 +97,10 @@ struct StackTrace {
uptr local_stack; \
uptr sp = (uptr)&local_stack
+#define GET_CALLER_PC_BP \
+ uptr bp = GET_CURRENT_FRAME(); \
+ uptr pc = GET_CALLER_PC();
+
// Use this macro if you want to print stack trace with the current
// function in the top frame.
#define GET_CURRENT_PC_BP_SP \
diff --git a/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc b/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc
index 58fa18251ecf..0d90980e6a68 100644
--- a/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc
@@ -11,18 +11,61 @@
// run-time libraries.
//===----------------------------------------------------------------------===//
+#include "sanitizer_common.h"
+#include "sanitizer_placement_new.h"
#include "sanitizer_stacktrace.h"
+#include "sanitizer_stacktrace_printer.h"
+#include "sanitizer_symbolizer.h"
namespace __sanitizer {
-void StackTrace::Unwind(uptr max_depth, uptr pc, uptr bp, uptr stack_top,
- uptr stack_bottom, bool request_fast_unwind) {
- if (!WillUseFastUnwind(request_fast_unwind))
- SlowUnwindStack(pc, max_depth);
- else
- FastUnwindStack(pc, bp, stack_top, stack_bottom, max_depth);
+void StackTrace::Print() const {
+ if (trace == nullptr || size == 0) {
+ Printf(" <empty stack>\n\n");
+ return;
+ }
+ InternalScopedString frame_desc(GetPageSizeCached() * 2);
+ uptr frame_num = 0;
+ for (uptr i = 0; i < size && trace[i]; i++) {
+ // PCs in stack traces are actually the return addresses, that is,
+ // addresses of the next instructions after the call.
+ uptr pc = GetPreviousInstructionPc(trace[i]);
+ SymbolizedStack *frames = Symbolizer::GetOrInit()->SymbolizePC(pc);
+ CHECK(frames);
+ for (SymbolizedStack *cur = frames; cur; cur = cur->next) {
+ frame_desc.clear();
+ RenderFrame(&frame_desc, common_flags()->stack_trace_format, frame_num++,
+ cur->info, common_flags()->strip_path_prefix);
+ Printf("%s\n", frame_desc.data());
+ }
+ frames->ClearAll();
+ }
+ // Always print a trailing empty line after stack trace.
+ Printf("\n");
+}
- top_frame_bp = size ? bp : 0;
+void BufferedStackTrace::Unwind(uptr max_depth, uptr pc, uptr bp, void *context,
+ uptr stack_top, uptr stack_bottom,
+ bool request_fast_unwind) {
+ top_frame_bp = (max_depth > 0) ? bp : 0;
+ // Avoid doing any work for small max_depth.
+ if (max_depth == 0) {
+ size = 0;
+ return;
+ }
+ if (max_depth == 1) {
+ size = 1;
+ trace_buffer[0] = pc;
+ return;
+ }
+ if (!WillUseFastUnwind(request_fast_unwind)) {
+ if (context)
+ SlowUnwindStackWithContext(pc, context, max_depth);
+ else
+ SlowUnwindStack(pc, max_depth);
+ } else {
+ FastUnwindStack(pc, bp, stack_top, stack_bottom, max_depth);
+ }
}
} // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_stacktrace_printer.cc b/lib/sanitizer_common/sanitizer_stacktrace_printer.cc
new file mode 100644
index 000000000000..7b37dbcf3860
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_stacktrace_printer.cc
@@ -0,0 +1,132 @@
+//===-- sanitizer_common.cc -----------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is shared between sanitizers' run-time libraries.
+//
+//===----------------------------------------------------------------------===//
+#include "sanitizer_stacktrace_printer.h"
+
+namespace __sanitizer {
+
+static const char *StripFunctionName(const char *function, const char *prefix) {
+ if (function == 0) return 0;
+ if (prefix == 0) return function;
+ uptr prefix_len = internal_strlen(prefix);
+ if (0 == internal_strncmp(function, prefix, prefix_len))
+ return function + prefix_len;
+ return function;
+}
+
+static const char kDefaultFormat[] = " #%n %p %F %L";
+
+void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no,
+ const AddressInfo &info, const char *strip_path_prefix,
+ const char *strip_func_prefix) {
+ if (0 == internal_strcmp(format, "DEFAULT"))
+ format = kDefaultFormat;
+ for (const char *p = format; *p != '\0'; p++) {
+ if (*p != '%') {
+ buffer->append("%c", *p);
+ continue;
+ }
+ p++;
+ switch (*p) {
+ case '%':
+ buffer->append("%%");
+ break;
+ // Frame number and all fields of AddressInfo structure.
+ case 'n':
+ buffer->append("%zu", frame_no);
+ break;
+ case 'p':
+ buffer->append("0x%zx", info.address);
+ break;
+ case 'm':
+ buffer->append("%s", StripPathPrefix(info.module, strip_path_prefix));
+ break;
+ case 'o':
+ buffer->append("0x%zx", info.module_offset);
+ break;
+ case 'f':
+ buffer->append("%s", StripFunctionName(info.function, strip_func_prefix));
+ break;
+ case 'q':
+ buffer->append("0x%zx", info.function_offset != AddressInfo::kUnknown
+ ? info.function_offset
+ : 0x0);
+ break;
+ case 's':
+ buffer->append("%s", StripPathPrefix(info.file, strip_path_prefix));
+ break;
+ case 'l':
+ buffer->append("%d", info.line);
+ break;
+ case 'c':
+ buffer->append("%d", info.column);
+ break;
+ // Smarter special cases.
+ case 'F':
+ // Function name and offset, if file is unknown.
+ if (info.function) {
+ buffer->append("in %s",
+ StripFunctionName(info.function, strip_func_prefix));
+ if (!info.file && info.function_offset != AddressInfo::kUnknown)
+ buffer->append("+0x%zx", info.function_offset);
+ }
+ break;
+ case 'S':
+ // File/line information.
+ RenderSourceLocation(buffer, info.file, info.line, info.column,
+ strip_path_prefix);
+ break;
+ case 'L':
+ // Source location, or module location.
+ if (info.file) {
+ RenderSourceLocation(buffer, info.file, info.line, info.column,
+ strip_path_prefix);
+ } else if (info.module) {
+ RenderModuleLocation(buffer, info.module, info.module_offset,
+ strip_path_prefix);
+ } else {
+ buffer->append("(<unknown module>)");
+ }
+ break;
+ case 'M':
+ // Module basename and offset, or PC.
+ if (info.module)
+ buffer->append("(%s+%p)", StripModuleName(info.module),
+ (void *)info.module_offset);
+ else
+ buffer->append("(%p)", (void *)info.address);
+ break;
+ default:
+ Report("Unsupported specifier in stack frame format: %c (0x%zx)!\n",
+ *p, *p);
+ Die();
+ }
+ }
+}
+
+void RenderSourceLocation(InternalScopedString *buffer, const char *file,
+ int line, int column, const char *strip_path_prefix) {
+ buffer->append("%s", StripPathPrefix(file, strip_path_prefix));
+ if (line > 0) {
+ buffer->append(":%d", line);
+ if (column > 0)
+ buffer->append(":%d", column);
+ }
+}
+
+void RenderModuleLocation(InternalScopedString *buffer, const char *module,
+ uptr offset, const char *strip_path_prefix) {
+ buffer->append("(%s+0x%zx)", StripPathPrefix(module, strip_path_prefix),
+ offset);
+}
+
+} // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_stacktrace_printer.h b/lib/sanitizer_common/sanitizer_stacktrace_printer.h
new file mode 100644
index 000000000000..93569882ba9d
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_stacktrace_printer.h
@@ -0,0 +1,62 @@
+//===-- sanitizer_stacktrace_printer.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 shared between sanitizers' run-time libraries.
+//
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_STACKTRACE_PRINTER_H
+#define SANITIZER_STACKTRACE_PRINTER_H
+
+#include "sanitizer_common.h"
+#include "sanitizer_symbolizer.h"
+
+namespace __sanitizer {
+
+// Render the contents of "info" structure, which represents the contents of
+// stack frame "frame_no" and appends it to the "buffer". "format" is a
+// string with placeholders, which is copied to the output with
+// placeholders substituted with the contents of "info". For example,
+// format string
+// " frame %n: function %F at %S"
+// will be turned into
+// " frame 10: function foo::bar() at my/file.cc:10"
+// You may additionally pass "strip_path_prefix" to strip prefixes of paths to
+// source files and modules, and "strip_func_prefix" to strip prefixes of
+// function names.
+// Here's the full list of available placeholders:
+// %% - represents a '%' character;
+// %n - frame number (copy of frame_no);
+// %p - PC in hex format;
+// %m - path to module (binary or shared object);
+// %o - offset in the module in hex format;
+// %f - function name;
+// %q - offset in the function in hex format (*if available*);
+// %s - path to source file;
+// %l - line in the source file;
+// %c - column in the source file;
+// %F - if function is known to be <foo>, prints "in <foo>", possibly
+// followed by the offset in this function, but only if source file
+// is unknown;
+// %S - prints file/line/column information;
+// %L - prints location information: file/line/column, if it is known, or
+// module+offset if it is known, or (<unknown module>) string.
+// %M - prints module basename and offset, if it is known, or PC.
+void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no,
+ const AddressInfo &info, const char *strip_path_prefix = "",
+ const char *strip_func_prefix = "");
+
+void RenderSourceLocation(InternalScopedString *buffer, const char *file,
+ int line, int column, const char *strip_path_prefix);
+
+void RenderModuleLocation(InternalScopedString *buffer, const char *module,
+ uptr offset, const char *strip_path_prefix);
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_STACKTRACE_PRINTER_H
diff --git a/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
index a34ddd872209..d20b52483a91 100644
--- a/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
@@ -100,12 +100,11 @@ bool ThreadSuspender::SuspendThread(SuspendedThreadID thread_id) {
&pterrno)) {
// Either the thread is dead, or something prevented us from attaching.
// Log this event and move on.
- if (common_flags()->verbosity)
- Report("Could not attach to thread %d (errno %d).\n", thread_id, pterrno);
+ VReport(1, "Could not attach to thread %d (errno %d).\n", thread_id,
+ pterrno);
return false;
} else {
- if (common_flags()->verbosity)
- Report("Attached to thread %d.\n", thread_id);
+ VReport(1, "Attached to thread %d.\n", thread_id);
// The thread is not guaranteed to stop before ptrace returns, so we must
// wait on it.
uptr waitpid_status;
@@ -114,9 +113,8 @@ bool ThreadSuspender::SuspendThread(SuspendedThreadID thread_id) {
if (internal_iserror(waitpid_status, &wperrno)) {
// Got a ECHILD error. I don't think this situation is possible, but it
// doesn't hurt to report it.
- if (common_flags()->verbosity)
- Report("Waiting on thread %d failed, detaching (errno %d).\n",
- thread_id, wperrno);
+ VReport(1, "Waiting on thread %d failed, detaching (errno %d).\n",
+ thread_id, wperrno);
internal_ptrace(PTRACE_DETACH, thread_id, NULL, NULL);
return false;
}
@@ -131,14 +129,12 @@ void ThreadSuspender::ResumeAllThreads() {
int pterrno;
if (!internal_iserror(internal_ptrace(PTRACE_DETACH, tid, NULL, NULL),
&pterrno)) {
- if (common_flags()->verbosity)
- Report("Detached from thread %d.\n", tid);
+ VReport(1, "Detached from thread %d.\n", tid);
} else {
// Either the thread is dead, or we are already detached.
// The latter case is possible, for instance, if this function was called
// from a signal handler.
- if (common_flags()->verbosity)
- Report("Could not detach from thread %d (errno %d).\n", tid, pterrno);
+ VReport(1, "Could not detach from thread %d (errno %d).\n", tid, pterrno);
}
}
}
@@ -250,18 +246,18 @@ static int TracerThread(void* argument) {
// the mask we inherited from the caller thread.
for (uptr signal_index = 0; signal_index < ARRAY_SIZE(kUnblockedSignals);
signal_index++) {
- __sanitizer_kernel_sigaction_t new_sigaction;
+ __sanitizer_sigaction new_sigaction;
internal_memset(&new_sigaction, 0, sizeof(new_sigaction));
new_sigaction.sigaction = TracerThreadSignalHandler;
new_sigaction.sa_flags = SA_ONSTACK | SA_SIGINFO;
internal_sigfillset(&new_sigaction.sa_mask);
- internal_sigaction(kUnblockedSignals[signal_index], &new_sigaction, NULL);
+ internal_sigaction_norestorer(kUnblockedSignals[signal_index],
+ &new_sigaction, NULL);
}
int exit_code = 0;
if (!thread_suspender.SuspendAllThreads()) {
- if (common_flags()->verbosity)
- Report("Failed suspending threads.\n");
+ VReport(1, "Failed suspending threads.\n");
exit_code = 3;
} else {
tracer_thread_argument->callback(thread_suspender.suspended_threads_list(),
@@ -301,9 +297,9 @@ class ScopedStackSpaceWithGuard {
// We have a limitation on the stack frame size, so some stuff had to be moved
// into globals.
-static __sanitizer_kernel_sigset_t blocked_sigset;
-static __sanitizer_kernel_sigset_t old_sigset;
-static __sanitizer_kernel_sigaction_t old_sigactions
+static __sanitizer_sigset_t blocked_sigset;
+static __sanitizer_sigset_t old_sigset;
+static __sanitizer_sigaction old_sigactions
[ARRAY_SIZE(kUnblockedSignals)];
class StopTheWorldScope {
@@ -320,12 +316,12 @@ class StopTheWorldScope {
// Remove the signal from the set of blocked signals.
internal_sigdelset(&blocked_sigset, kUnblockedSignals[signal_index]);
// Install the default handler.
- __sanitizer_kernel_sigaction_t new_sigaction;
+ __sanitizer_sigaction new_sigaction;
internal_memset(&new_sigaction, 0, sizeof(new_sigaction));
new_sigaction.handler = SIG_DFL;
internal_sigfillset(&new_sigaction.sa_mask);
- internal_sigaction(kUnblockedSignals[signal_index], &new_sigaction,
- &old_sigactions[signal_index]);
+ internal_sigaction_norestorer(kUnblockedSignals[signal_index],
+ &new_sigaction, &old_sigactions[signal_index]);
}
int sigprocmask_status =
internal_sigprocmask(SIG_BLOCK, &blocked_sigset, &old_sigset);
@@ -346,8 +342,8 @@ class StopTheWorldScope {
// Restore the signal handlers.
for (uptr signal_index = 0; signal_index < ARRAY_SIZE(kUnblockedSignals);
signal_index++) {
- internal_sigaction(kUnblockedSignals[signal_index],
- &old_sigactions[signal_index], NULL);
+ internal_sigaction_norestorer(kUnblockedSignals[signal_index],
+ &old_sigactions[signal_index], NULL);
}
internal_sigprocmask(SIG_SETMASK, &old_sigset, &old_sigset);
}
@@ -356,6 +352,20 @@ class StopTheWorldScope {
int process_was_dumpable_;
};
+// When sanitizer output is being redirected to file (i.e. by using log_path),
+// the tracer should write to the parent's log instead of trying to open a new
+// file. Alert the logging code to the fact that we have a tracer.
+struct ScopedSetTracerPID {
+ explicit ScopedSetTracerPID(uptr tracer_pid) {
+ stoptheworld_tracer_pid = tracer_pid;
+ stoptheworld_tracer_ppid = internal_getpid();
+ }
+ ~ScopedSetTracerPID() {
+ stoptheworld_tracer_pid = 0;
+ stoptheworld_tracer_ppid = 0;
+ }
+};
+
void StopTheWorld(StopTheWorldCallback callback, void *argument) {
StopTheWorldScope in_stoptheworld;
// Prepare the arguments for TracerThread.
@@ -375,10 +385,10 @@ void StopTheWorld(StopTheWorldCallback callback, void *argument) {
/* child_tidptr */);
int local_errno = 0;
if (internal_iserror(tracer_pid, &local_errno)) {
- if (common_flags()->verbosity)
- Report("Failed spawning a tracer thread (errno %d).\n", local_errno);
+ VReport(1, "Failed spawning a tracer thread (errno %d).\n", local_errno);
tracer_thread_argument.mutex.Unlock();
} else {
+ ScopedSetTracerPID scoped_set_tracer_pid(tracer_pid);
// On some systems we have to explicitly declare that we want to be traced
// by the tracer thread.
#ifdef PR_SET_PTRACER
@@ -391,11 +401,9 @@ void StopTheWorld(StopTheWorldCallback callback, void *argument) {
// At this point, any signal will either be blocked or kill us, so waitpid
// should never return (and set errno) while the tracer thread is alive.
uptr waitpid_status = internal_waitpid(tracer_pid, NULL, __WALL);
- if (internal_iserror(waitpid_status, &local_errno)) {
- if (common_flags()->verbosity)
- Report("Waiting on the tracer thread failed (errno %d).\n",
- local_errno);
- }
+ if (internal_iserror(waitpid_status, &local_errno))
+ VReport(1, "Waiting on the tracer thread failed (errno %d).\n",
+ local_errno);
}
}
@@ -436,9 +444,8 @@ int SuspendedThreadsList::GetRegistersAndSP(uptr index,
int pterrno;
if (internal_iserror(internal_ptrace(PTRACE_GETREGS, tid, NULL, &regs),
&pterrno)) {
- if (common_flags()->verbosity)
- Report("Could not get registers from thread %d (errno %d).\n",
- tid, pterrno);
+ VReport(1, "Could not get registers from thread %d (errno %d).\n", tid,
+ pterrno);
return -1;
}
diff --git a/lib/sanitizer_common/sanitizer_suppressions.cc b/lib/sanitizer_common/sanitizer_suppressions.cc
index 5f3d2cee8cef..6b75036c7e50 100644
--- a/lib/sanitizer_common/sanitizer_suppressions.cc
+++ b/lib/sanitizer_common/sanitizer_suppressions.cc
@@ -15,13 +15,16 @@
#include "sanitizer_allocator_internal.h"
#include "sanitizer_common.h"
+#include "sanitizer_flags.h"
#include "sanitizer_libc.h"
+#include "sanitizer_placement_new.h"
namespace __sanitizer {
static const char *const kTypeStrings[SuppressionTypeCount] = {
- "none", "race", "mutex", "thread", "signal", "leak", "called_from_lib"
-};
+ "none", "race", "mutex", "thread", "signal", "leak", "called_from_lib",
+ "deadlock", "vptr_check", "interceptor_name", "interceptor_via_fun",
+ "interceptor_via_lib"};
bool TemplateMatch(char *templ, const char *str) {
if (str == 0 || str[0] == 0)
@@ -65,8 +68,41 @@ bool TemplateMatch(char *templ, const char *str) {
return true;
}
+ALIGNED(64) static char placeholder[sizeof(SuppressionContext)];
+static SuppressionContext *suppression_ctx = 0;
+
+SuppressionContext::SuppressionContext() : suppressions_(1), can_parse_(true) {
+ internal_memset(has_suppresson_type_, 0, sizeof(has_suppresson_type_));
+}
+
+SuppressionContext *SuppressionContext::Get() {
+ CHECK(suppression_ctx);
+ return suppression_ctx;
+}
+
+void SuppressionContext::InitIfNecessary() {
+ if (suppression_ctx)
+ return;
+ suppression_ctx = new(placeholder) SuppressionContext;
+ if (common_flags()->suppressions[0] == '\0')
+ return;
+ char *suppressions_from_file;
+ uptr buffer_size;
+ uptr contents_size =
+ ReadFileToBuffer(common_flags()->suppressions, &suppressions_from_file,
+ &buffer_size, 1 << 26 /* max_len */);
+ if (contents_size == 0) {
+ Printf("%s: failed to read suppressions file '%s'\n", SanitizerToolName,
+ common_flags()->suppressions);
+ Die();
+ }
+ suppression_ctx->Parse(suppressions_from_file);
+}
+
bool SuppressionContext::Match(const char *str, SuppressionType type,
Suppression **s) {
+ if (!has_suppresson_type_[type])
+ return false;
can_parse_ = false;
uptr i;
for (i = 0; i < suppressions_.size(); i++)
@@ -122,6 +158,7 @@ void SuppressionContext::Parse(const char *str) {
s.hit_count = 0;
s.weight = 0;
suppressions_.push_back(s);
+ has_suppresson_type_[s.type] = true;
}
if (end[0] == 0)
break;
@@ -133,6 +170,10 @@ uptr SuppressionContext::SuppressionCount() const {
return suppressions_.size();
}
+bool SuppressionContext::HasSuppressionType(SuppressionType type) const {
+ return has_suppresson_type_[type];
+}
+
const Suppression *SuppressionContext::SuppressionAt(uptr i) const {
CHECK_LT(i, suppressions_.size());
return &suppressions_[i];
diff --git a/lib/sanitizer_common/sanitizer_suppressions.h b/lib/sanitizer_common/sanitizer_suppressions.h
index 92cb09365b5e..453731456169 100644
--- a/lib/sanitizer_common/sanitizer_suppressions.h
+++ b/lib/sanitizer_common/sanitizer_suppressions.h
@@ -26,6 +26,11 @@ enum SuppressionType {
SuppressionSignal,
SuppressionLeak,
SuppressionLib,
+ SuppressionDeadlock,
+ SuppressionVptrCheck,
+ SuppressionInterceptorName,
+ SuppressionInterceptorViaFunction,
+ SuppressionInterceptorViaLibrary,
SuppressionTypeCount
};
@@ -38,15 +43,24 @@ struct Suppression {
class SuppressionContext {
public:
- SuppressionContext() : suppressions_(1), can_parse_(true) {}
void Parse(const char *str);
bool Match(const char* str, SuppressionType type, Suppression **s);
uptr SuppressionCount() const;
+ bool HasSuppressionType(SuppressionType type) const;
const Suppression *SuppressionAt(uptr i) const;
void GetMatched(InternalMmapVector<Suppression *> *matched);
+ // Create a SuppressionContext singleton if it hasn't been created earlier.
+ // Not thread safe. Must be called early during initialization (but after
+ // runtime flags are parsed).
+ static void InitIfNecessary();
+ // Returns a SuppressionContext singleton.
+ static SuppressionContext *Get();
+
private:
+ SuppressionContext();
InternalMmapVector<Suppression> suppressions_;
+ bool has_suppresson_type_[SuppressionTypeCount];
bool can_parse_;
friend class SuppressionContextTest;
diff --git a/lib/sanitizer_common/sanitizer_symbolizer.cc b/lib/sanitizer_common/sanitizer_symbolizer.cc
index 2290767b0930..135720ed5eb1 100644
--- a/lib/sanitizer_common/sanitizer_symbolizer.cc
+++ b/lib/sanitizer_common/sanitizer_symbolizer.cc
@@ -11,28 +11,65 @@
// run-time libraries.
//===----------------------------------------------------------------------===//
+#include "sanitizer_allocator_internal.h"
#include "sanitizer_platform.h"
#include "sanitizer_internal_defs.h"
+#include "sanitizer_libc.h"
#include "sanitizer_placement_new.h"
#include "sanitizer_symbolizer.h"
namespace __sanitizer {
-Symbolizer *Symbolizer::symbolizer_;
-StaticSpinMutex Symbolizer::init_mu_;
-LowLevelAllocator Symbolizer::symbolizer_allocator_;
+AddressInfo::AddressInfo() {
+ internal_memset(this, 0, sizeof(AddressInfo));
+ function_offset = kUnknown;
+}
-Symbolizer *Symbolizer::GetOrNull() {
- SpinMutexLock l(&init_mu_);
- return symbolizer_;
+void AddressInfo::Clear() {
+ InternalFree(module);
+ InternalFree(function);
+ InternalFree(file);
+ internal_memset(this, 0, sizeof(AddressInfo));
+ function_offset = kUnknown;
}
-Symbolizer *Symbolizer::Get() {
- SpinMutexLock l(&init_mu_);
- RAW_CHECK_MSG(symbolizer_ != 0, "Using uninitialized symbolizer!");
- return symbolizer_;
+void AddressInfo::FillAddressAndModuleInfo(uptr addr, const char *mod_name,
+ uptr mod_offset) {
+ address = addr;
+ module = internal_strdup(mod_name);
+ module_offset = mod_offset;
}
+SymbolizedStack::SymbolizedStack() : next(nullptr), info() {}
+
+SymbolizedStack *SymbolizedStack::New(uptr addr) {
+ void *mem = InternalAlloc(sizeof(SymbolizedStack));
+ SymbolizedStack *res = new(mem) SymbolizedStack();
+ res->info.address = addr;
+ return res;
+}
+
+void SymbolizedStack::ClearAll() {
+ info.Clear();
+ if (next)
+ next->ClearAll();
+ InternalFree(this);
+}
+
+DataInfo::DataInfo() {
+ internal_memset(this, 0, sizeof(DataInfo));
+}
+
+void DataInfo::Clear() {
+ InternalFree(module);
+ InternalFree(name);
+ internal_memset(this, 0, sizeof(DataInfo));
+}
+
+Symbolizer *Symbolizer::symbolizer_;
+StaticSpinMutex Symbolizer::init_mu_;
+LowLevelAllocator Symbolizer::symbolizer_allocator_;
+
Symbolizer *Symbolizer::Disable() {
CHECK_EQ(0, symbolizer_);
// Initialize a dummy symbolizer.
diff --git a/lib/sanitizer_common/sanitizer_symbolizer.h b/lib/sanitizer_common/sanitizer_symbolizer.h
index 886fed20db03..3ccfce9995be 100644
--- a/lib/sanitizer_common/sanitizer_symbolizer.h
+++ b/lib/sanitizer_common/sanitizer_symbolizer.h
@@ -19,82 +19,79 @@
#ifndef SANITIZER_SYMBOLIZER_H
#define SANITIZER_SYMBOLIZER_H
-#include "sanitizer_allocator_internal.h"
-#include "sanitizer_internal_defs.h"
-#include "sanitizer_libc.h"
+#include "sanitizer_common.h"
+#include "sanitizer_mutex.h"
namespace __sanitizer {
struct AddressInfo {
+ // Owns all the string members. Storage for them is
+ // (de)allocated using sanitizer internal allocator.
uptr address;
+
char *module;
uptr module_offset;
+
+ static const uptr kUnknown = ~(uptr)0;
char *function;
+ uptr function_offset;
+
char *file;
int line;
int column;
- AddressInfo() {
- internal_memset(this, 0, sizeof(AddressInfo));
- }
+ AddressInfo();
+ // Deletes all strings and resets all fields.
+ void Clear();
+ void FillAddressAndModuleInfo(uptr addr, const char *mod_name,
+ uptr mod_offset);
+};
- // Deletes all strings and sets all fields to zero.
- void Clear() {
- InternalFree(module);
- InternalFree(function);
- InternalFree(file);
- internal_memset(this, 0, sizeof(AddressInfo));
- }
+// Linked list of symbolized frames (each frame is described by AddressInfo).
+struct SymbolizedStack {
+ SymbolizedStack *next;
+ AddressInfo info;
+ static SymbolizedStack *New(uptr addr);
+ // Deletes current, and all subsequent frames in the linked list.
+ // The object cannot be accessed after the call to this function.
+ void ClearAll();
- void FillAddressAndModuleInfo(uptr addr, const char *mod_name,
- uptr mod_offset) {
- address = addr;
- module = internal_strdup(mod_name);
- module_offset = mod_offset;
- }
+ private:
+ SymbolizedStack();
};
+// For now, DataInfo is used to describe global variable.
struct DataInfo {
- uptr address;
+ // Owns all the string members. Storage for them is
+ // (de)allocated using sanitizer internal allocator.
char *module;
uptr module_offset;
char *name;
uptr start;
uptr size;
+
+ DataInfo();
+ void Clear();
};
class Symbolizer {
public:
- /// Returns platform-specific implementation of Symbolizer. The symbolizer
- /// must be initialized (with init or disable) before calling this function.
- static Symbolizer *Get();
- /// Returns platform-specific implementation of Symbolizer, or null if not
- /// initialized.
- static Symbolizer *GetOrNull();
- /// Returns platform-specific implementation of Symbolizer. Will
- /// automatically initialize symbolizer as if by calling Init(0) if needed.
+ /// Initialize and return platform-specific implementation of symbolizer
+ /// (if it wasn't already initialized).
static Symbolizer *GetOrInit();
- /// Initialize and return the symbolizer, given an optional path to an
- /// external symbolizer. The path argument is only required for legacy
- /// reasons as this function will check $PATH for an external symbolizer. Not
- /// thread safe.
- static Symbolizer *Init(const char* path_to_external = 0);
- /// Initialize the symbolizer in a disabled state. Not thread safe.
- static Symbolizer *Disable();
- // Fills at most "max_frames" elements of "frames" with descriptions
- // for a given address (in all inlined functions). Returns the number
- // of descriptions actually filled.
- virtual uptr SymbolizeCode(uptr address, AddressInfo *frames,
- uptr max_frames) {
- return 0;
+ // Returns a list of symbolized frames for a given address (containing
+ // all inlined functions, if necessary).
+ virtual SymbolizedStack *SymbolizePC(uptr address) {
+ return SymbolizedStack::New(address);
}
virtual bool SymbolizeData(uptr address, DataInfo *info) {
return false;
}
- virtual bool IsAvailable() {
+ virtual bool GetModuleNameAndOffsetForPC(uptr pc, const char **module_name,
+ uptr *module_address) {
return false;
}
- virtual bool IsExternalAvailable() {
+ virtual bool CanReturnFileLineInfo() {
return false;
}
// Release internal caches (if any).
@@ -117,10 +114,9 @@ class Symbolizer {
private:
/// Platform-specific function for creating a Symbolizer object.
- static Symbolizer *PlatformInit(const char *path_to_external);
- /// Create a symbolizer and store it to symbolizer_ without checking if one
- /// already exists. Not thread safe.
- static Symbolizer *CreateAndStore(const char *path_to_external);
+ static Symbolizer *PlatformInit();
+ /// Initialize the symbolizer in a disabled state. Not thread safe.
+ static Symbolizer *Disable();
static Symbolizer *symbolizer_;
static StaticSpinMutex init_mu_;
diff --git a/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.cc b/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.cc
new file mode 100644
index 000000000000..bb8ba6b81674
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.cc
@@ -0,0 +1,211 @@
+//===-- sanitizer_symbolizer_libbacktrace.cc ------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is shared between AddressSanitizer and ThreadSanitizer
+// run-time libraries.
+// Libbacktrace implementation of symbolizer parts.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_platform.h"
+
+#include "sanitizer_internal_defs.h"
+#include "sanitizer_symbolizer.h"
+#include "sanitizer_symbolizer_libbacktrace.h"
+
+#if SANITIZER_LIBBACKTRACE
+# include "backtrace-supported.h"
+# if SANITIZER_POSIX && BACKTRACE_SUPPORTED && !BACKTRACE_USES_MALLOC
+# include "backtrace.h"
+# if SANITIZER_CP_DEMANGLE
+# undef ARRAY_SIZE
+# include "demangle.h"
+# endif
+# else
+# define SANITIZER_LIBBACKTRACE 0
+# endif
+#endif
+
+namespace __sanitizer {
+
+#if SANITIZER_LIBBACKTRACE
+
+namespace {
+
+# if SANITIZER_CP_DEMANGLE
+struct CplusV3DemangleData {
+ char *buf;
+ uptr size, allocated;
+};
+
+extern "C" {
+static void CplusV3DemangleCallback(const char *s, size_t l, void *vdata) {
+ CplusV3DemangleData *data = (CplusV3DemangleData *)vdata;
+ uptr needed = data->size + l + 1;
+ if (needed > data->allocated) {
+ data->allocated *= 2;
+ if (needed > data->allocated)
+ data->allocated = needed;
+ char *buf = (char *)InternalAlloc(data->allocated);
+ if (data->buf) {
+ internal_memcpy(buf, data->buf, data->size);
+ InternalFree(data->buf);
+ }
+ data->buf = buf;
+ }
+ internal_memcpy(data->buf + data->size, s, l);
+ data->buf[data->size + l] = '\0';
+ data->size += l;
+}
+} // extern "C"
+
+char *CplusV3Demangle(const char *name) {
+ CplusV3DemangleData data;
+ data.buf = 0;
+ data.size = 0;
+ data.allocated = 0;
+ if (cplus_demangle_v3_callback(name, DMGL_PARAMS | DMGL_ANSI,
+ CplusV3DemangleCallback, &data)) {
+ if (data.size + 64 > data.allocated)
+ return data.buf;
+ char *buf = internal_strdup(data.buf);
+ InternalFree(data.buf);
+ return buf;
+ }
+ if (data.buf)
+ InternalFree(data.buf);
+ return 0;
+}
+# endif // SANITIZER_CP_DEMANGLE
+
+struct SymbolizeCodeCallbackArg {
+ SymbolizedStack *first;
+ SymbolizedStack *last;
+ const char *module_name;
+ uptr module_offset;
+
+ void append(SymbolizedStack *f) {
+ if (last != nullptr) {
+ last->next = f;
+ last = f;
+ } else {
+ first = f;
+ last = f;
+ }
+ }
+};
+
+extern "C" {
+static int SymbolizeCodePCInfoCallback(void *vdata, uintptr_t addr,
+ const char *filename, int lineno,
+ const char *function) {
+ SymbolizeCodeCallbackArg *cdata = (SymbolizeCodeCallbackArg *)vdata;
+ if (function) {
+ SymbolizedStack *cur = SymbolizedStack::New(addr);
+ cdata->append(cur);
+ AddressInfo *info = &cur->info;
+ info->FillAddressAndModuleInfo(addr, cdata->module_name,
+ cdata->module_offset);
+ info->function = LibbacktraceSymbolizer::Demangle(function, true);
+ if (filename)
+ info->file = internal_strdup(filename);
+ info->line = lineno;
+ }
+ return 0;
+}
+
+static void SymbolizeCodeCallback(void *vdata, uintptr_t addr,
+ const char *symname, uintptr_t, uintptr_t) {
+ SymbolizeCodeCallbackArg *cdata = (SymbolizeCodeCallbackArg *)vdata;
+ if (symname) {
+ SymbolizedStack *cur = SymbolizedStack::New(addr);
+ cdata->append(cur);
+ AddressInfo *info = &cur->info;
+ info->FillAddressAndModuleInfo(addr, cdata->module_name,
+ cdata->module_offset);
+ info->function = LibbacktraceSymbolizer::Demangle(symname, true);
+ }
+}
+
+static void SymbolizeDataCallback(void *vdata, uintptr_t, const char *symname,
+ uintptr_t symval, uintptr_t symsize) {
+ DataInfo *info = (DataInfo *)vdata;
+ if (symname && symval) {
+ info->name = LibbacktraceSymbolizer::Demangle(symname, true);
+ info->start = symval;
+ info->size = symsize;
+ }
+}
+
+static void ErrorCallback(void *, const char *, int) {}
+} // extern "C"
+
+} // namespace
+
+LibbacktraceSymbolizer *LibbacktraceSymbolizer::get(LowLevelAllocator *alloc) {
+ // State created in backtrace_create_state is leaked.
+ void *state = (void *)(backtrace_create_state("/proc/self/exe", 0,
+ ErrorCallback, NULL));
+ if (!state)
+ return 0;
+ return new(*alloc) LibbacktraceSymbolizer(state);
+}
+
+SymbolizedStack *LibbacktraceSymbolizer::SymbolizeCode(uptr addr,
+ const char *module_name,
+ uptr module_offset) {
+ SymbolizeCodeCallbackArg data;
+ data.first = nullptr;
+ data.last = nullptr;
+ data.module_name = module_name;
+ data.module_offset = module_offset;
+ backtrace_pcinfo((backtrace_state *)state_, addr, SymbolizeCodePCInfoCallback,
+ ErrorCallback, &data);
+ if (data.first)
+ return data.first;
+ backtrace_syminfo((backtrace_state *)state_, addr, SymbolizeCodeCallback,
+ ErrorCallback, &data);
+ return data.first;
+}
+
+bool LibbacktraceSymbolizer::SymbolizeData(DataInfo *info) {
+ backtrace_syminfo((backtrace_state *)state_, info->address,
+ SymbolizeDataCallback, ErrorCallback, info);
+ return true;
+}
+
+#else // SANITIZER_LIBBACKTRACE
+
+LibbacktraceSymbolizer *LibbacktraceSymbolizer::get(LowLevelAllocator *alloc) {
+ return 0;
+}
+
+SymbolizedStack *LibbacktraceSymbolizer::SymbolizeCode(uptr addr,
+ const char *module_name,
+ uptr module_offset) {
+ (void)state_;
+ return nullptr;
+}
+
+bool LibbacktraceSymbolizer::SymbolizeData(DataInfo *info) {
+ return false;
+}
+
+#endif // SANITIZER_LIBBACKTRACE
+
+char *LibbacktraceSymbolizer::Demangle(const char *name, bool always_alloc) {
+#if SANITIZER_LIBBACKTRACE && SANITIZER_CP_DEMANGLE
+ if (char *demangled = CplusV3Demangle(name))
+ return demangled;
+#endif
+ if (always_alloc)
+ return internal_strdup(name);
+ return 0;
+}
+
+} // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.h b/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.h
new file mode 100644
index 000000000000..a335cb23788c
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.h
@@ -0,0 +1,50 @@
+//===-- sanitizer_symbolizer_libbacktrace.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 shared between AddressSanitizer and ThreadSanitizer
+// run-time libraries.
+// Header for libbacktrace symbolizer.
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_SYMBOLIZER_LIBBACKTRACE_H
+#define SANITIZER_SYMBOLIZER_LIBBACKTRACE_H
+
+#include "sanitizer_platform.h"
+#include "sanitizer_common.h"
+#include "sanitizer_symbolizer.h"
+
+#ifndef SANITIZER_LIBBACKTRACE
+# define SANITIZER_LIBBACKTRACE 0
+#endif
+
+#ifndef SANITIZER_CP_DEMANGLE
+# define SANITIZER_CP_DEMANGLE 0
+#endif
+
+namespace __sanitizer {
+
+class LibbacktraceSymbolizer {
+ public:
+ static LibbacktraceSymbolizer *get(LowLevelAllocator *alloc);
+
+ SymbolizedStack *SymbolizeCode(uptr addr, const char *module_name,
+ uptr module_offset);
+
+ bool SymbolizeData(DataInfo *info);
+
+ // May return NULL if demangling failed.
+ static char *Demangle(const char *name, bool always_alloc = false);
+
+ private:
+ explicit LibbacktraceSymbolizer(void *state) : state_(state) {}
+
+ void *state_; // Leaked.
+};
+
+} // namespace __sanitizer
+#endif // SANITIZER_SYMBOLIZER_LIBBACKTRACE_H
diff --git a/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc b/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc
index b431e51e24d6..63c9356a521f 100644
--- a/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc
@@ -16,24 +16,13 @@
namespace __sanitizer {
-Symbolizer *Symbolizer::CreateAndStore(const char *path_to_external) {
- Symbolizer *platform_symbolizer = PlatformInit(path_to_external);
- if (!platform_symbolizer)
- return Disable();
- symbolizer_ = platform_symbolizer;
- return platform_symbolizer;
-}
-
-Symbolizer *Symbolizer::Init(const char *path_to_external) {
- CHECK_EQ(0, symbolizer_);
- return CreateAndStore(path_to_external);
-}
-
Symbolizer *Symbolizer::GetOrInit() {
SpinMutexLock l(&init_mu_);
- if (symbolizer_ == 0)
- return CreateAndStore(0);
- return symbolizer_;
+ if (symbolizer_)
+ return symbolizer_;
+ if ((symbolizer_ = PlatformInit()))
+ return symbolizer_;
+ return Disable();
}
} // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc b/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc
index de11832870e3..d46c249e6cab 100644
--- a/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc
@@ -16,11 +16,13 @@
#if SANITIZER_POSIX
#include "sanitizer_allocator_internal.h"
#include "sanitizer_common.h"
+#include "sanitizer_flags.h"
#include "sanitizer_internal_defs.h"
#include "sanitizer_linux.h"
#include "sanitizer_placement_new.h"
#include "sanitizer_procmaps.h"
#include "sanitizer_symbolizer.h"
+#include "sanitizer_symbolizer_libbacktrace.h"
#include <errno.h>
#include <stdlib.h>
@@ -53,107 +55,6 @@ static const char *DemangleCXXABI(const char *name) {
return name;
}
-#if defined(__x86_64__)
-static const char* const kSymbolizerArch = "--default-arch=x86_64";
-#elif defined(__i386__)
-static const char* const kSymbolizerArch = "--default-arch=i386";
-#elif defined(__powerpc64__)
-static const char* const kSymbolizerArch = "--default-arch=powerpc64";
-#else
-static const char* const kSymbolizerArch = "--default-arch=unknown";
-#endif
-
-static const int kSymbolizerStartupTimeMillis = 10;
-
-// Creates external symbolizer connected via pipe, user should write
-// to output_fd and read from input_fd.
-static bool StartSymbolizerSubprocess(const char *path_to_symbolizer,
- int *input_fd, int *output_fd) {
- if (!FileExists(path_to_symbolizer)) {
- Report("WARNING: invalid path to external symbolizer!\n");
- return false;
- }
-
- int *infd = NULL;
- int *outfd = NULL;
- // The client program may close its stdin and/or stdout and/or stderr
- // thus allowing socketpair to reuse file descriptors 0, 1 or 2.
- // In this case the communication between the forked processes may be
- // broken if either the parent or the child tries to close or duplicate
- // these descriptors. The loop below produces two pairs of file
- // descriptors, each greater than 2 (stderr).
- int sock_pair[5][2];
- for (int i = 0; i < 5; i++) {
- if (pipe(sock_pair[i]) == -1) {
- for (int j = 0; j < i; j++) {
- internal_close(sock_pair[j][0]);
- internal_close(sock_pair[j][1]);
- }
- Report("WARNING: Can't create a socket pair to start "
- "external symbolizer (errno: %d)\n", errno);
- return false;
- } else if (sock_pair[i][0] > 2 && sock_pair[i][1] > 2) {
- if (infd == NULL) {
- infd = sock_pair[i];
- } else {
- outfd = sock_pair[i];
- for (int j = 0; j < i; j++) {
- if (sock_pair[j] == infd) continue;
- internal_close(sock_pair[j][0]);
- internal_close(sock_pair[j][1]);
- }
- break;
- }
- }
- }
- CHECK(infd);
- CHECK(outfd);
-
- int pid = fork();
- if (pid == -1) {
- // Fork() failed.
- internal_close(infd[0]);
- internal_close(infd[1]);
- internal_close(outfd[0]);
- internal_close(outfd[1]);
- Report("WARNING: failed to fork external symbolizer "
- " (errno: %d)\n", errno);
- return false;
- } else if (pid == 0) {
- // Child subprocess.
- internal_close(STDOUT_FILENO);
- internal_close(STDIN_FILENO);
- internal_dup2(outfd[0], STDIN_FILENO);
- internal_dup2(infd[1], STDOUT_FILENO);
- internal_close(outfd[0]);
- internal_close(outfd[1]);
- internal_close(infd[0]);
- internal_close(infd[1]);
- for (int fd = getdtablesize(); fd > 2; fd--)
- internal_close(fd);
- execl(path_to_symbolizer, path_to_symbolizer, kSymbolizerArch, (char*)0);
- internal__exit(1);
- }
-
- // Continue execution in parent process.
- internal_close(outfd[0]);
- internal_close(infd[1]);
- *input_fd = infd[0];
- *output_fd = outfd[1];
-
- // Check that symbolizer subprocess started successfully.
- int pid_status;
- SleepForMillis(kSymbolizerStartupTimeMillis);
- int exited_pid = waitpid(pid, &pid_status, WNOHANG);
- if (exited_pid != 0) {
- // Either waitpid failed, or child has already exited.
- Report("WARNING: external symbolizer didn't start up correctly!\n");
- return false;
- }
-
- return true;
-}
-
// Extracts the prefix of "str" that consists of any characters not
// present in "delims" string, and copies this prefix to "result", allocating
// space for it.
@@ -193,34 +94,63 @@ static const char *ExtractUptr(const char *str, const char *delims,
return ret;
}
-// ExternalSymbolizer encapsulates communication between the tool and
-// external symbolizer program, running in a different subprocess,
-// For now we assume the following protocol:
-// For each request of the form
-// <module_name> <module_offset>
-// passed to STDIN, external symbolizer prints to STDOUT response:
-// <function_name>
-// <file_name>:<line_number>:<column_number>
-// <function_name>
-// <file_name>:<line_number>:<column_number>
-// ...
-// <empty line>
-class ExternalSymbolizer {
+class ExternalSymbolizerInterface {
public:
- ExternalSymbolizer(const char *path, int input_fd, int output_fd)
+ // Can't declare pure virtual functions in sanitizer runtimes:
+ // __cxa_pure_virtual might be unavailable.
+ virtual char *SendCommand(bool is_data, const char *module_name,
+ uptr module_offset) {
+ UNIMPLEMENTED();
+ }
+};
+
+// SymbolizerProcess encapsulates communication between the tool and
+// external symbolizer program, running in a different subprocess.
+// SymbolizerProcess may not be used from two threads simultaneously.
+class SymbolizerProcess : public ExternalSymbolizerInterface {
+ public:
+ explicit SymbolizerProcess(const char *path)
: path_(path),
- input_fd_(input_fd),
- output_fd_(output_fd),
- times_restarted_(0) {
+ input_fd_(kInvalidFd),
+ output_fd_(kInvalidFd),
+ times_restarted_(0),
+ failed_to_start_(false),
+ reported_invalid_path_(false) {
CHECK(path_);
- CHECK_NE(input_fd_, kInvalidFd);
- CHECK_NE(output_fd_, kInvalidFd);
+ CHECK_NE(path_[0], '\0');
}
char *SendCommand(bool is_data, const char *module_name, uptr module_offset) {
+ for (; times_restarted_ < kMaxTimesRestarted; times_restarted_++) {
+ // Start or restart symbolizer if we failed to send command to it.
+ if (char *res = SendCommandImpl(is_data, module_name, module_offset))
+ return res;
+ Restart();
+ }
+ if (!failed_to_start_) {
+ Report("WARNING: Failed to use and restart external symbolizer!\n");
+ failed_to_start_ = true;
+ }
+ return 0;
+ }
+
+ private:
+ bool Restart() {
+ if (input_fd_ != kInvalidFd)
+ internal_close(input_fd_);
+ if (output_fd_ != kInvalidFd)
+ internal_close(output_fd_);
+ return StartSymbolizerSubprocess();
+ }
+
+ char *SendCommandImpl(bool is_data, const char *module_name,
+ uptr module_offset) {
+ if (input_fd_ == kInvalidFd || output_fd_ == kInvalidFd)
+ return 0;
CHECK(module_name);
- internal_snprintf(buffer_, kBufferSize, "%s\"%s\" 0x%zx\n",
- is_data ? "DATA " : "", module_name, module_offset);
+ if (!RenderInputCommand(buffer_, kBufferSize, is_data, module_name,
+ module_offset))
+ return 0;
if (!writeToSymbolizer(buffer_, internal_strlen(buffer_)))
return 0;
if (!readFromSymbolizer(buffer_, kBufferSize))
@@ -228,25 +158,13 @@ class ExternalSymbolizer {
return buffer_;
}
- bool Restart() {
- if (times_restarted_ >= kMaxTimesRestarted) return false;
- times_restarted_++;
- internal_close(input_fd_);
- internal_close(output_fd_);
- return StartSymbolizerSubprocess(path_, &input_fd_, &output_fd_);
- }
-
- void Flush() {
- }
-
- private:
bool readFromSymbolizer(char *buffer, uptr max_length) {
if (max_length == 0)
return true;
uptr read_len = 0;
while (true) {
uptr just_read = internal_read(input_fd_, buffer + read_len,
- max_length - read_len);
+ max_length - read_len - 1);
// We can't read 0 bytes, as we don't expect external symbolizer to close
// its stdout.
if (just_read == 0 || just_read == (uptr)-1) {
@@ -254,12 +172,10 @@ class ExternalSymbolizer {
return false;
}
read_len += just_read;
- // Empty line marks the end of symbolizer output.
- if (read_len >= 2 && buffer[read_len - 1] == '\n' &&
- buffer[read_len - 2] == '\n') {
+ if (ReachedEndOfOutput(buffer, read_len))
break;
- }
}
+ buffer[read_len] = '\0';
return true;
}
@@ -274,6 +190,110 @@ class ExternalSymbolizer {
return true;
}
+ bool StartSymbolizerSubprocess() {
+ if (!FileExists(path_)) {
+ if (!reported_invalid_path_) {
+ Report("WARNING: invalid path to external symbolizer!\n");
+ reported_invalid_path_ = true;
+ }
+ return false;
+ }
+
+ int *infd = NULL;
+ int *outfd = NULL;
+ // The client program may close its stdin and/or stdout and/or stderr
+ // thus allowing socketpair to reuse file descriptors 0, 1 or 2.
+ // In this case the communication between the forked processes may be
+ // broken if either the parent or the child tries to close or duplicate
+ // these descriptors. The loop below produces two pairs of file
+ // descriptors, each greater than 2 (stderr).
+ int sock_pair[5][2];
+ for (int i = 0; i < 5; i++) {
+ if (pipe(sock_pair[i]) == -1) {
+ for (int j = 0; j < i; j++) {
+ internal_close(sock_pair[j][0]);
+ internal_close(sock_pair[j][1]);
+ }
+ Report("WARNING: Can't create a socket pair to start "
+ "external symbolizer (errno: %d)\n", errno);
+ return false;
+ } else if (sock_pair[i][0] > 2 && sock_pair[i][1] > 2) {
+ if (infd == NULL) {
+ infd = sock_pair[i];
+ } else {
+ outfd = sock_pair[i];
+ for (int j = 0; j < i; j++) {
+ if (sock_pair[j] == infd) continue;
+ internal_close(sock_pair[j][0]);
+ internal_close(sock_pair[j][1]);
+ }
+ break;
+ }
+ }
+ }
+ CHECK(infd);
+ CHECK(outfd);
+
+ // Real fork() may call user callbacks registered with pthread_atfork().
+ int pid = internal_fork();
+ if (pid == -1) {
+ // Fork() failed.
+ internal_close(infd[0]);
+ internal_close(infd[1]);
+ internal_close(outfd[0]);
+ internal_close(outfd[1]);
+ Report("WARNING: failed to fork external symbolizer "
+ " (errno: %d)\n", errno);
+ return false;
+ } else if (pid == 0) {
+ // Child subprocess.
+ internal_close(STDOUT_FILENO);
+ internal_close(STDIN_FILENO);
+ internal_dup2(outfd[0], STDIN_FILENO);
+ internal_dup2(infd[1], STDOUT_FILENO);
+ internal_close(outfd[0]);
+ internal_close(outfd[1]);
+ internal_close(infd[0]);
+ internal_close(infd[1]);
+ for (int fd = sysconf(_SC_OPEN_MAX); fd > 2; fd--)
+ internal_close(fd);
+ ExecuteWithDefaultArgs(path_);
+ internal__exit(1);
+ }
+
+ // Continue execution in parent process.
+ internal_close(outfd[0]);
+ internal_close(infd[1]);
+ input_fd_ = infd[0];
+ output_fd_ = outfd[1];
+
+ // Check that symbolizer subprocess started successfully.
+ int pid_status;
+ SleepForMillis(kSymbolizerStartupTimeMillis);
+ int exited_pid = waitpid(pid, &pid_status, WNOHANG);
+ if (exited_pid != 0) {
+ // Either waitpid failed, or child has already exited.
+ Report("WARNING: external symbolizer didn't start up correctly!\n");
+ return false;
+ }
+
+ return true;
+ }
+
+ virtual bool RenderInputCommand(char *buffer, uptr max_length, bool is_data,
+ const char *module_name,
+ uptr module_offset) const {
+ UNIMPLEMENTED();
+ }
+
+ virtual bool ReachedEndOfOutput(const char *buffer, uptr length) const {
+ UNIMPLEMENTED();
+ }
+
+ virtual void ExecuteWithDefaultArgs(const char *path_to_binary) const {
+ UNIMPLEMENTED();
+ }
+
const char *path_;
int input_fd_;
int output_fd_;
@@ -282,7 +302,127 @@ class ExternalSymbolizer {
char buffer_[kBufferSize];
static const uptr kMaxTimesRestarted = 5;
+ static const int kSymbolizerStartupTimeMillis = 10;
uptr times_restarted_;
+ bool failed_to_start_;
+ bool reported_invalid_path_;
+};
+
+// For now we assume the following protocol:
+// For each request of the form
+// <module_name> <module_offset>
+// passed to STDIN, external symbolizer prints to STDOUT response:
+// <function_name>
+// <file_name>:<line_number>:<column_number>
+// <function_name>
+// <file_name>:<line_number>:<column_number>
+// ...
+// <empty line>
+class LLVMSymbolizerProcess : public SymbolizerProcess {
+ public:
+ explicit LLVMSymbolizerProcess(const char *path) : SymbolizerProcess(path) {}
+
+ private:
+ bool RenderInputCommand(char *buffer, uptr max_length, bool is_data,
+ const char *module_name, uptr module_offset) const {
+ internal_snprintf(buffer, max_length, "%s\"%s\" 0x%zx\n",
+ is_data ? "DATA " : "", module_name, module_offset);
+ return true;
+ }
+
+ bool ReachedEndOfOutput(const char *buffer, uptr length) const {
+ // Empty line marks the end of llvm-symbolizer output.
+ return length >= 2 && buffer[length - 1] == '\n' &&
+ buffer[length - 2] == '\n';
+ }
+
+ void ExecuteWithDefaultArgs(const char *path_to_binary) const {
+#if defined(__x86_64__)
+ const char* const kSymbolizerArch = "--default-arch=x86_64";
+#elif defined(__i386__)
+ const char* const kSymbolizerArch = "--default-arch=i386";
+#elif defined(__powerpc64__) && defined(__BIG_ENDIAN__)
+ const char* const kSymbolizerArch = "--default-arch=powerpc64";
+#elif defined(__powerpc64__) && defined(__LITTLE_ENDIAN__)
+ const char* const kSymbolizerArch = "--default-arch=powerpc64le";
+#else
+ const char* const kSymbolizerArch = "--default-arch=unknown";
+#endif
+
+ const char *const inline_flag = common_flags()->symbolize_inline_frames
+ ? "--inlining=true"
+ : "--inlining=false";
+ execl(path_to_binary, path_to_binary, inline_flag, kSymbolizerArch,
+ (char *)0);
+ }
+};
+
+class Addr2LineProcess : public SymbolizerProcess {
+ public:
+ Addr2LineProcess(const char *path, const char *module_name)
+ : SymbolizerProcess(path), module_name_(internal_strdup(module_name)) {}
+
+ const char *module_name() const { return module_name_; }
+
+ private:
+ bool RenderInputCommand(char *buffer, uptr max_length, bool is_data,
+ const char *module_name, uptr module_offset) const {
+ if (is_data)
+ return false;
+ CHECK_EQ(0, internal_strcmp(module_name, module_name_));
+ internal_snprintf(buffer, max_length, "0x%zx\n", module_offset);
+ return true;
+ }
+
+ bool ReachedEndOfOutput(const char *buffer, uptr length) const {
+ // Output should consist of two lines.
+ int num_lines = 0;
+ for (uptr i = 0; i < length; ++i) {
+ if (buffer[i] == '\n')
+ num_lines++;
+ if (num_lines >= 2)
+ return true;
+ }
+ return false;
+ }
+
+ void ExecuteWithDefaultArgs(const char *path_to_binary) const {
+ execl(path_to_binary, path_to_binary, "-Cfe", module_name_, (char *)0);
+ }
+
+ const char *module_name_; // Owned, leaked.
+};
+
+class Addr2LinePool : public ExternalSymbolizerInterface {
+ public:
+ explicit Addr2LinePool(const char *addr2line_path,
+ LowLevelAllocator *allocator)
+ : addr2line_path_(addr2line_path), allocator_(allocator),
+ addr2line_pool_(16) {}
+
+ char *SendCommand(bool is_data, const char *module_name, uptr module_offset) {
+ if (is_data)
+ return 0;
+ Addr2LineProcess *addr2line = 0;
+ for (uptr i = 0; i < addr2line_pool_.size(); ++i) {
+ if (0 ==
+ internal_strcmp(module_name, addr2line_pool_[i]->module_name())) {
+ addr2line = addr2line_pool_[i];
+ break;
+ }
+ }
+ if (!addr2line) {
+ addr2line =
+ new(*allocator_) Addr2LineProcess(addr2line_path_, module_name);
+ addr2line_pool_.push_back(addr2line);
+ }
+ return addr2line->SendCommand(is_data, module_name, module_offset);
+ }
+
+ private:
+ const char *addr2line_path_;
+ LowLevelAllocator *allocator_;
+ InternalMmapVector<Addr2LineProcess*> addr2line_pool_;
};
#if SANITIZER_SUPPORTS_WEAK_HOOKS
@@ -366,33 +506,40 @@ class InternalSymbolizer {
class POSIXSymbolizer : public Symbolizer {
public:
- POSIXSymbolizer(ExternalSymbolizer *external_symbolizer,
- InternalSymbolizer *internal_symbolizer)
+ POSIXSymbolizer(ExternalSymbolizerInterface *external_symbolizer,
+ InternalSymbolizer *internal_symbolizer,
+ LibbacktraceSymbolizer *libbacktrace_symbolizer)
: Symbolizer(),
external_symbolizer_(external_symbolizer),
- internal_symbolizer_(internal_symbolizer) {}
+ internal_symbolizer_(internal_symbolizer),
+ libbacktrace_symbolizer_(libbacktrace_symbolizer) {}
- uptr SymbolizeCode(uptr addr, AddressInfo *frames, uptr max_frames) {
+ SymbolizedStack *SymbolizePC(uptr addr) override {
BlockingMutexLock l(&mu_);
- if (max_frames == 0)
- return 0;
- LoadedModule *module = FindModuleForAddress(addr);
- if (module == 0)
- return 0;
- const char *module_name = module->full_name();
- uptr module_offset = addr - module->base_address();
+ const char *module_name;
+ uptr module_offset;
+ if (!FindModuleNameAndOffsetForAddress(addr, &module_name, &module_offset))
+ return SymbolizedStack::New(addr);
+ // First, try to use libbacktrace symbolizer (if it's available).
+ if (libbacktrace_symbolizer_ != 0) {
+ mu_.CheckLocked();
+ if (SymbolizedStack *res = libbacktrace_symbolizer_->SymbolizeCode(
+ addr, module_name, module_offset))
+ return res;
+ }
+ // Always fill data about module name and offset.
+ SymbolizedStack *res = SymbolizedStack::New(addr);
+ res->info.FillAddressAndModuleInfo(addr, module_name, module_offset);
+
const char *str = SendCommand(false, module_name, module_offset);
if (str == 0) {
- // External symbolizer was not initialized or failed. Fill only data
- // about module name and offset.
- AddressInfo *info = &frames[0];
- info->Clear();
- info->FillAddressAndModuleInfo(addr, module_name, module_offset);
- return 1;
+ // Symbolizer was not initialized or failed.
+ return res;
}
- uptr frame_id = 0;
- for (frame_id = 0; frame_id < max_frames; frame_id++) {
- AddressInfo *info = &frames[frame_id];
+
+ bool top_frame = true;
+ SymbolizedStack *last = res;
+ while (true) {
char *function_name = 0;
str = ExtractToken(str, "\n", &function_name);
CHECK(function_name);
@@ -400,8 +547,18 @@ class POSIXSymbolizer : public Symbolizer {
// There are no more frames.
break;
}
- info->Clear();
- info->FillAddressAndModuleInfo(addr, module_name, module_offset);
+ SymbolizedStack *cur;
+ if (top_frame) {
+ cur = res;
+ top_frame = false;
+ } else {
+ cur = SymbolizedStack::New(addr);
+ cur->info.FillAddressAndModuleInfo(addr, module_name, module_offset);
+ last->next = cur;
+ last = cur;
+ }
+
+ AddressInfo *info = &cur->info;
info->function = function_name;
// Parse <file>:<line>:<column> buffer.
char *file_line_info = 0;
@@ -423,27 +580,25 @@ class POSIXSymbolizer : public Symbolizer {
info->file = 0;
}
}
- if (frame_id == 0) {
- // Make sure we return at least one frame.
- AddressInfo *info = &frames[0];
- info->Clear();
- info->FillAddressAndModuleInfo(addr, module_name, module_offset);
- frame_id = 1;
- }
- return frame_id;
+ return res;
}
- bool SymbolizeData(uptr addr, DataInfo *info) {
+ bool SymbolizeData(uptr addr, DataInfo *info) override {
BlockingMutexLock l(&mu_);
LoadedModule *module = FindModuleForAddress(addr);
if (module == 0)
return false;
const char *module_name = module->full_name();
uptr module_offset = addr - module->base_address();
- internal_memset(info, 0, sizeof(*info));
- info->address = addr;
+ info->Clear();
info->module = internal_strdup(module_name);
info->module_offset = module_offset;
+ // First, try to use libbacktrace symbolizer (if it's available).
+ if (libbacktrace_symbolizer_ != 0) {
+ mu_.CheckLocked();
+ if (libbacktrace_symbolizer_->SymbolizeData(info))
+ return true;
+ }
const char *str = SendCommand(true, module_name, module_offset);
if (str == 0)
return true;
@@ -454,35 +609,41 @@ class POSIXSymbolizer : public Symbolizer {
return true;
}
- bool IsAvailable() {
- return internal_symbolizer_ != 0 || external_symbolizer_ != 0;
+ bool GetModuleNameAndOffsetForPC(uptr pc, const char **module_name,
+ uptr *module_address) override {
+ BlockingMutexLock l(&mu_);
+ return FindModuleNameAndOffsetForAddress(pc, module_name, module_address);
}
- bool IsExternalAvailable() {
- return external_symbolizer_ != 0;
+ bool CanReturnFileLineInfo() override {
+ return internal_symbolizer_ != 0 || external_symbolizer_ != 0 ||
+ libbacktrace_symbolizer_ != 0;
}
- void Flush() {
+ void Flush() override {
BlockingMutexLock l(&mu_);
if (internal_symbolizer_ != 0) {
SymbolizerScope sym_scope(this);
internal_symbolizer_->Flush();
}
- if (external_symbolizer_ != 0)
- external_symbolizer_->Flush();
}
- const char *Demangle(const char *name) {
+ const char *Demangle(const char *name) override {
BlockingMutexLock l(&mu_);
// Run hooks even if we don't use internal symbolizer, as cxxabi
// demangle may call system functions.
SymbolizerScope sym_scope(this);
+ // Try to use libbacktrace demangler (if available).
+ if (libbacktrace_symbolizer_ != 0) {
+ if (const char *demangled = libbacktrace_symbolizer_->Demangle(name))
+ return demangled;
+ }
if (internal_symbolizer_ != 0)
return internal_symbolizer_->Demangle(name);
return DemangleCXXABI(name);
}
- void PrepareForSandboxing() {
+ void PrepareForSandboxing() override {
#if SANITIZER_LINUX && !SANITIZER_ANDROID
BlockingMutexLock l(&mu_);
// Cache /proc/self/exe on Linux.
@@ -500,26 +661,12 @@ class POSIXSymbolizer : public Symbolizer {
module_offset);
}
// Otherwise, fall back to external symbolizer.
- if (external_symbolizer_ == 0) {
- ReportExternalSymbolizerError(
- "WARNING: Trying to symbolize code, but external "
- "symbolizer is not initialized!\n");
- return 0;
- }
- for (;;) {
- char *reply = external_symbolizer_->SendCommand(is_data, module_name,
- module_offset);
- if (reply)
- return reply;
- // Try to restart symbolizer subprocess. If we don't succeed, forget
- // about it and don't try to use it later.
- if (!external_symbolizer_->Restart()) {
- ReportExternalSymbolizerError(
- "WARNING: Failed to use and restart external symbolizer!\n");
- external_symbolizer_ = 0;
- return 0;
- }
+ if (external_symbolizer_) {
+ SymbolizerScope sym_scope(this);
+ return external_symbolizer_->SendCommand(is_data, module_name,
+ module_offset);
}
+ return 0;
}
LoadedModule *FindModuleForAddress(uptr address) {
@@ -531,8 +678,7 @@ class POSIXSymbolizer : public Symbolizer {
CHECK(modules_);
n_modules_ = GetListOfModules(modules_, kMaxNumberOfModuleContexts,
/* filter */ 0);
- // FIXME: Return this check when GetListOfModules is implemented on Mac.
- // CHECK_GT(n_modules_, 0);
+ CHECK_GT(n_modules_, 0);
CHECK_LT(n_modules_, kMaxNumberOfModuleContexts);
modules_fresh_ = true;
modules_were_reloaded = true;
@@ -553,14 +699,15 @@ class POSIXSymbolizer : public Symbolizer {
return 0;
}
- void ReportExternalSymbolizerError(const char *msg) {
- // Don't use atomics here for now, as SymbolizeCode can't be called
- // from multiple threads anyway.
- static bool reported;
- if (!reported) {
- Report(msg);
- reported = true;
- }
+ bool FindModuleNameAndOffsetForAddress(uptr address, const char **module_name,
+ uptr *module_offset) {
+ mu_.CheckLocked();
+ LoadedModule *module = FindModuleForAddress(address);
+ if (module == 0)
+ return false;
+ *module_name = module->full_name();
+ *module_offset = address - module->base_address();
+ return true;
}
// 16K loaded modules should be enough for everyone.
@@ -571,29 +718,47 @@ class POSIXSymbolizer : public Symbolizer {
bool modules_fresh_;
BlockingMutex mu_;
- ExternalSymbolizer *external_symbolizer_; // Leaked.
- InternalSymbolizer *const internal_symbolizer_; // Leaked.
+ ExternalSymbolizerInterface *external_symbolizer_; // Leaked.
+ InternalSymbolizer *const internal_symbolizer_; // Leaked.
+ LibbacktraceSymbolizer *libbacktrace_symbolizer_; // Leaked.
};
-Symbolizer *Symbolizer::PlatformInit(const char *path_to_external) {
+Symbolizer *Symbolizer::PlatformInit() {
+ if (!common_flags()->symbolize) {
+ return new(symbolizer_allocator_) POSIXSymbolizer(0, 0, 0);
+ }
InternalSymbolizer* internal_symbolizer =
InternalSymbolizer::get(&symbolizer_allocator_);
- ExternalSymbolizer *external_symbolizer = 0;
+ ExternalSymbolizerInterface *external_symbolizer = 0;
+ LibbacktraceSymbolizer *libbacktrace_symbolizer = 0;
if (!internal_symbolizer) {
- if (!path_to_external || path_to_external[0] == '\0')
- path_to_external = FindPathToBinary("llvm-symbolizer");
-
- int input_fd, output_fd;
- if (path_to_external &&
- StartSymbolizerSubprocess(path_to_external, &input_fd, &output_fd)) {
- external_symbolizer = new(symbolizer_allocator_)
- ExternalSymbolizer(path_to_external, input_fd, output_fd);
+ libbacktrace_symbolizer =
+ LibbacktraceSymbolizer::get(&symbolizer_allocator_);
+ if (!libbacktrace_symbolizer) {
+ const char *path_to_external = common_flags()->external_symbolizer_path;
+ if (path_to_external && path_to_external[0] == '\0') {
+ // External symbolizer is explicitly disabled. Do nothing.
+ } else {
+ // Find path to llvm-symbolizer if it's not provided.
+ if (!path_to_external)
+ path_to_external = FindPathToBinary("llvm-symbolizer");
+ if (path_to_external) {
+ external_symbolizer = new(symbolizer_allocator_)
+ LLVMSymbolizerProcess(path_to_external);
+ } else if (common_flags()->allow_addr2line) {
+ // If llvm-symbolizer is not found, try to use addr2line.
+ if (const char *addr2line_path = FindPathToBinary("addr2line")) {
+ external_symbolizer = new(symbolizer_allocator_)
+ Addr2LinePool(addr2line_path, &symbolizer_allocator_);
+ }
+ }
+ }
}
}
- return new(symbolizer_allocator_)
- POSIXSymbolizer(external_symbolizer, internal_symbolizer);
+ return new(symbolizer_allocator_) POSIXSymbolizer(
+ external_symbolizer, internal_symbolizer, libbacktrace_symbolizer);
}
} // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_symbolizer_win.cc b/lib/sanitizer_common/sanitizer_symbolizer_win.cc
index 5d451eff62bd..6bb7d3805604 100644
--- a/lib/sanitizer_common/sanitizer_symbolizer_win.cc
+++ b/lib/sanitizer_common/sanitizer_symbolizer_win.cc
@@ -14,11 +14,110 @@
#include "sanitizer_platform.h"
#if SANITIZER_WINDOWS
+#include <windows.h>
+#include <dbghelp.h>
+#pragma comment(lib, "dbghelp.lib")
+
#include "sanitizer_symbolizer.h"
namespace __sanitizer {
-Symbolizer *Symbolizer::PlatformInit(const char *path_to_external) { return 0; }
+class WinSymbolizer : public Symbolizer {
+ public:
+ WinSymbolizer() : initialized_(false) {}
+
+ SymbolizedStack *SymbolizePC(uptr addr) override {
+ SymbolizedStack *frame = SymbolizedStack::New(addr);
+
+ BlockingMutexLock l(&dbghelp_mu_);
+ if (!initialized_) {
+ if (!TrySymInitialize()) {
+ // OK, maybe the client app has called SymInitialize already.
+ // That's a bit unfortunate for us as all the DbgHelp functions are
+ // single-threaded and we can't coordinate with the app.
+ // FIXME: Can we stop the other threads at this point?
+ // Anyways, we have to reconfigure stuff to make sure that SymInitialize
+ // has all the appropriate options set.
+ // Cross our fingers and reinitialize DbgHelp.
+ Report("*** WARNING: Failed to initialize DbgHelp! ***\n");
+ Report("*** Most likely this means that the app is already ***\n");
+ Report("*** using DbgHelp, possibly with incompatible flags. ***\n");
+ Report("*** Due to technical reasons, symbolization might crash ***\n");
+ Report("*** or produce wrong results. ***\n");
+ SymCleanup(GetCurrentProcess());
+ TrySymInitialize();
+ }
+ initialized_ = true;
+ }
+
+ // See http://msdn.microsoft.com/en-us/library/ms680578(VS.85).aspx
+ char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(CHAR)];
+ PSYMBOL_INFO symbol = (PSYMBOL_INFO)buffer;
+ symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
+ symbol->MaxNameLen = MAX_SYM_NAME;
+ DWORD64 offset = 0;
+ BOOL got_objname = SymFromAddr(GetCurrentProcess(),
+ (DWORD64)addr, &offset, symbol);
+ if (!got_objname)
+ return frame;
+
+ DWORD unused;
+ IMAGEHLP_LINE64 line_info;
+ line_info.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
+ BOOL got_fileline = SymGetLineFromAddr64(GetCurrentProcess(), (DWORD64)addr,
+ &unused, &line_info);
+ frame->info.function = internal_strdup(symbol->Name);
+ frame->info.function_offset = (uptr)offset;
+ if (got_fileline) {
+ frame->info.file = internal_strdup(line_info.FileName);
+ frame->info.line = line_info.LineNumber;
+ }
+
+ IMAGEHLP_MODULE64 mod_info;
+ internal_memset(&mod_info, 0, sizeof(mod_info));
+ mod_info.SizeOfStruct = sizeof(mod_info);
+ if (SymGetModuleInfo64(GetCurrentProcess(), addr, &mod_info))
+ frame->info.FillAddressAndModuleInfo(addr, mod_info.ImageName,
+ addr - (uptr)mod_info.BaseOfImage);
+ return frame;
+ }
+
+ bool CanReturnFileLineInfo() override {
+ return true;
+ }
+
+ const char *Demangle(const char *name) override {
+ CHECK(initialized_);
+ static char demangle_buffer[1000];
+ if (name[0] == '\01' &&
+ UnDecorateSymbolName(name + 1, demangle_buffer, sizeof(demangle_buffer),
+ UNDNAME_NAME_ONLY))
+ return demangle_buffer;
+ else
+ return name;
+ }
+
+ // FIXME: Implement GetModuleNameAndOffsetForPC().
+
+ private:
+ bool TrySymInitialize() {
+ SymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_UNDNAME | SYMOPT_LOAD_LINES);
+ return SymInitialize(GetCurrentProcess(), 0, TRUE);
+ // FIXME: We don't call SymCleanup() on exit yet - should we?
+ }
+
+ // All DbgHelp functions are single threaded, so we should use a mutex to
+ // serialize accesses.
+ BlockingMutex dbghelp_mu_;
+ bool initialized_;
+};
+
+Symbolizer *Symbolizer::PlatformInit() {
+ static bool called_once = false;
+ CHECK(!called_once && "Shouldn't create more than one symbolizer");
+ called_once = true;
+ return new(symbolizer_allocator_) WinSymbolizer();
+}
} // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_syscall_generic.inc b/lib/sanitizer_common/sanitizer_syscall_generic.inc
index aac20a5f2d69..88d237f4e3ce 100644
--- a/lib/sanitizer_common/sanitizer_syscall_generic.inc
+++ b/lib/sanitizer_common/sanitizer_syscall_generic.inc
@@ -11,7 +11,17 @@
//
//===----------------------------------------------------------------------===//
-#define internal_syscall syscall
+#if SANITIZER_FREEBSD
+# define SYSCALL(name) SYS_ ## name
+#else
+# define SYSCALL(name) __NR_ ## name
+#endif
+
+#if SANITIZER_FREEBSD && defined(__x86_64__)
+# define internal_syscall __syscall
+# else
+# define internal_syscall syscall
+#endif
bool internal_iserror(uptr retval, int *rverrno) {
if (retval == (uptr)-1) {
diff --git a/lib/sanitizer_common/sanitizer_syscall_linux_x86_64.inc b/lib/sanitizer_common/sanitizer_syscall_linux_x86_64.inc
index 5ccb83a236bd..9853a6a675d3 100644
--- a/lib/sanitizer_common/sanitizer_syscall_linux_x86_64.inc
+++ b/lib/sanitizer_common/sanitizer_syscall_linux_x86_64.inc
@@ -11,6 +11,8 @@
//
//===----------------------------------------------------------------------===//
+#define SYSCALL(name) __NR_ ## name
+
static uptr internal_syscall(u64 nr) {
u64 retval;
asm volatile("syscall" : "=a"(retval) : "a"(nr) : "rcx", "r11",
diff --git a/lib/sanitizer_common/sanitizer_thread_registry.cc b/lib/sanitizer_common/sanitizer_thread_registry.cc
index bfa29a19cd2d..2ec92ffd385f 100644
--- a/lib/sanitizer_common/sanitizer_thread_registry.cc
+++ b/lib/sanitizer_common/sanitizer_thread_registry.cc
@@ -17,8 +17,9 @@
namespace __sanitizer {
ThreadContextBase::ThreadContextBase(u32 tid)
- : tid(tid), unique_id(0), os_id(0), user_id(0), status(ThreadStatusInvalid),
- detached(false), reuse_count(0), parent_tid(0), next(0) {
+ : tid(tid), unique_id(0), reuse_count(), os_id(0), user_id(0),
+ status(ThreadStatusInvalid),
+ detached(false), parent_tid(0), next(0) {
name[0] = '\0';
}
@@ -78,7 +79,6 @@ void ThreadContextBase::SetCreated(uptr _user_id, u64 _unique_id,
void ThreadContextBase::Reset() {
status = ThreadStatusInvalid;
- reuse_count++;
SetName(0);
OnReset();
}
@@ -88,10 +88,11 @@ void ThreadContextBase::Reset() {
const u32 ThreadRegistry::kUnknownTid = ~0U;
ThreadRegistry::ThreadRegistry(ThreadContextFactory factory, u32 max_threads,
- u32 thread_quarantine_size)
+ u32 thread_quarantine_size, u32 max_reuse)
: context_factory_(factory),
max_threads_(max_threads),
thread_quarantine_size_(thread_quarantine_size),
+ max_reuse_(max_reuse),
mtx_(),
n_contexts_(0),
total_threads_(0),
@@ -130,8 +131,13 @@ u32 ThreadRegistry::CreateThread(uptr user_id, bool detached, u32 parent_tid,
tctx = context_factory_(tid);
threads_[tid] = tctx;
} else {
+#ifndef SANITIZER_GO
Report("%s: Thread limit (%u threads) exceeded. Dying.\n",
SanitizerToolName, max_threads_);
+#else
+ Printf("race: limit on %u simultaneously alive goroutines is exceeded,"
+ " dying\n", max_threads_);
+#endif
Die();
}
CHECK_NE(tctx, 0);
@@ -212,7 +218,7 @@ void ThreadRegistry::SetThreadNameByUserId(uptr user_id, const char *name) {
}
}
-void ThreadRegistry::DetachThread(u32 tid) {
+void ThreadRegistry::DetachThread(u32 tid, void *arg) {
BlockingMutexLock l(&mtx_);
CHECK_LT(tid, n_contexts_);
ThreadContextBase *tctx = threads_[tid];
@@ -221,6 +227,7 @@ void ThreadRegistry::DetachThread(u32 tid) {
Report("%s: Detach of non-existent thread\n", SanitizerToolName);
return;
}
+ tctx->OnDetached(arg);
if (tctx->status == ThreadStatusFinished) {
tctx->SetDead();
QuarantinePush(tctx);
@@ -277,6 +284,9 @@ void ThreadRegistry::QuarantinePush(ThreadContextBase *tctx) {
dead_threads_.pop_front();
CHECK_EQ(tctx->status, ThreadStatusDead);
tctx->Reset();
+ tctx->reuse_count++;
+ if (max_reuse_ > 0 && tctx->reuse_count >= max_reuse_)
+ return;
invalid_threads_.push_back(tctx);
}
diff --git a/lib/sanitizer_common/sanitizer_thread_registry.h b/lib/sanitizer_common/sanitizer_thread_registry.h
index a59bba570e88..5d9c3b9694e8 100644
--- a/lib/sanitizer_common/sanitizer_thread_registry.h
+++ b/lib/sanitizer_common/sanitizer_thread_registry.h
@@ -38,13 +38,13 @@ class ThreadContextBase {
const u32 tid; // Thread ID. Main thread should have tid = 0.
u64 unique_id; // Unique thread ID.
+ u32 reuse_count; // Number of times this tid was reused.
uptr os_id; // PID (used for reporting).
uptr user_id; // Some opaque user thread id (e.g. pthread_t).
char name[64]; // As annotated by user.
ThreadStatus status;
bool detached;
- int reuse_count;
u32 parent_tid;
ThreadContextBase *next; // For storing thread contexts in a list.
@@ -68,6 +68,7 @@ class ThreadContextBase {
virtual void OnStarted(void *arg) {}
virtual void OnCreated(void *arg) {}
virtual void OnReset() {}
+ virtual void OnDetached(void *arg) {}
};
typedef ThreadContextBase* (*ThreadContextFactory)(u32 tid);
@@ -77,7 +78,7 @@ class ThreadRegistry {
static const u32 kUnknownTid;
ThreadRegistry(ThreadContextFactory factory, u32 max_threads,
- u32 thread_quarantine_size);
+ u32 thread_quarantine_size, u32 max_reuse = 0);
void GetNumberOfThreads(uptr *total = 0, uptr *running = 0, uptr *alive = 0);
uptr GetMaxAliveThreads();
@@ -110,7 +111,7 @@ class ThreadRegistry {
void SetThreadName(u32 tid, const char *name);
void SetThreadNameByUserId(uptr user_id, const char *name);
- void DetachThread(u32 tid);
+ void DetachThread(u32 tid, void *arg);
void JoinThread(u32 tid, void *arg);
void FinishThread(u32 tid);
void StartThread(u32 tid, uptr os_id, void *arg);
@@ -119,6 +120,7 @@ class ThreadRegistry {
const ThreadContextFactory context_factory_;
const u32 max_threads_;
const u32 thread_quarantine_size_;
+ const u32 max_reuse_;
BlockingMutex mtx_;
diff --git a/lib/sanitizer_common/sanitizer_tls_get_addr.cc b/lib/sanitizer_common/sanitizer_tls_get_addr.cc
new file mode 100644
index 000000000000..6142ce517db5
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_tls_get_addr.cc
@@ -0,0 +1,131 @@
+//===-- sanitizer_tls_get_addr.cc -----------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Handle the __tls_get_addr call.
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_tls_get_addr.h"
+
+#include "sanitizer_flags.h"
+#include "sanitizer_platform_interceptors.h"
+
+namespace __sanitizer {
+#if SANITIZER_INTERCEPT_TLS_GET_ADDR
+
+// The actual parameter that comes to __tls_get_addr
+// is a pointer to a struct with two words in it:
+struct TlsGetAddrParam {
+ uptr dso_id;
+ uptr offset;
+};
+
+// Glibc starting from 2.19 allocates tls using __signal_safe_memalign,
+// which has such header.
+struct Glibc_2_19_tls_header {
+ uptr size;
+ uptr start;
+};
+
+// This must be static TLS
+__attribute__((tls_model("initial-exec")))
+static __thread DTLS dtls;
+
+// Make sure we properly destroy the DTLS objects:
+// this counter should never get too large.
+static atomic_uintptr_t number_of_live_dtls;
+
+static const uptr kDestroyedThread = -1;
+
+static inline void DTLS_Deallocate(DTLS::DTV *dtv, uptr size) {
+ if (!size) return;
+ VPrintf(2, "__tls_get_addr: DTLS_Deallocate %p %zd\n", dtv, size);
+ UnmapOrDie(dtv, size * sizeof(DTLS::DTV));
+ atomic_fetch_sub(&number_of_live_dtls, 1, memory_order_relaxed);
+}
+
+static inline void DTLS_Resize(uptr new_size) {
+ if (dtls.dtv_size >= new_size) return;
+ new_size = RoundUpToPowerOfTwo(new_size);
+ new_size = Max(new_size, 4096UL / sizeof(DTLS::DTV));
+ DTLS::DTV *new_dtv =
+ (DTLS::DTV *)MmapOrDie(new_size * sizeof(DTLS::DTV), "DTLS_Resize");
+ uptr num_live_dtls =
+ atomic_fetch_add(&number_of_live_dtls, 1, memory_order_relaxed);
+ VPrintf(2, "__tls_get_addr: DTLS_Resize %p %zd\n", &dtls, num_live_dtls);
+ CHECK_LT(num_live_dtls, 1 << 20);
+ uptr old_dtv_size = dtls.dtv_size;
+ DTLS::DTV *old_dtv = dtls.dtv;
+ if (old_dtv_size)
+ internal_memcpy(new_dtv, dtls.dtv, dtls.dtv_size * sizeof(DTLS::DTV));
+ dtls.dtv = new_dtv;
+ dtls.dtv_size = new_size;
+ if (old_dtv_size)
+ DTLS_Deallocate(old_dtv, old_dtv_size);
+}
+
+void DTLS_Destroy() {
+ if (!common_flags()->intercept_tls_get_addr) return;
+ VPrintf(2, "__tls_get_addr: DTLS_Destroy %p %zd\n", &dtls, dtls.dtv_size);
+ uptr s = dtls.dtv_size;
+ dtls.dtv_size = kDestroyedThread; // Do this before unmap for AS-safety.
+ DTLS_Deallocate(dtls.dtv, s);
+}
+
+DTLS::DTV *DTLS_on_tls_get_addr(void *arg_void, void *res) {
+ if (!common_flags()->intercept_tls_get_addr) return 0;
+ TlsGetAddrParam *arg = reinterpret_cast<TlsGetAddrParam *>(arg_void);
+ uptr dso_id = arg->dso_id;
+ if (dtls.dtv_size == kDestroyedThread) return 0;
+ DTLS_Resize(dso_id + 1);
+ if (dtls.dtv[dso_id].beg) return 0;
+ uptr tls_size = 0;
+ uptr tls_beg = reinterpret_cast<uptr>(res) - arg->offset;
+ VPrintf(2, "__tls_get_addr: %p {%p,%p} => %p; tls_beg: %p; sp: %p "
+ "num_live_dtls %zd\n",
+ arg, arg->dso_id, arg->offset, res, tls_beg, &tls_beg,
+ atomic_load(&number_of_live_dtls, memory_order_relaxed));
+ if (dtls.last_memalign_ptr == tls_beg) {
+ tls_size = dtls.last_memalign_size;
+ VPrintf(2, "__tls_get_addr: glibc <=2.18 suspected; tls={%p,%p}\n",
+ tls_beg, tls_size);
+ } else if ((tls_beg % 4096) == sizeof(Glibc_2_19_tls_header)) {
+ // We may want to check gnu_get_libc_version().
+ Glibc_2_19_tls_header *header = (Glibc_2_19_tls_header *)tls_beg - 1;
+ tls_size = header->size;
+ tls_beg = header->start;
+ VPrintf(2, "__tls_get_addr: glibc >=2.19 suspected; tls={%p %p}\n",
+ tls_beg, tls_size);
+ } else {
+ VPrintf(2, "__tls_get_addr: Can't guess glibc version\n");
+ // This may happen inside the DTOR of main thread, so just ignore it.
+ tls_size = 0;
+ }
+ dtls.dtv[dso_id].beg = tls_beg;
+ dtls.dtv[dso_id].size = tls_size;
+ return dtls.dtv + dso_id;
+}
+
+void DTLS_on_libc_memalign(void *ptr, uptr size) {
+ if (!common_flags()->intercept_tls_get_addr) return;
+ VPrintf(2, "DTLS_on_libc_memalign: %p %p\n", ptr, size);
+ dtls.last_memalign_ptr = reinterpret_cast<uptr>(ptr);
+ dtls.last_memalign_size = size;
+}
+
+DTLS *DTLS_Get() { return &dtls; }
+
+#else
+void DTLS_on_libc_memalign(void *ptr, uptr size) {}
+DTLS::DTV *DTLS_on_tls_get_addr(void *arg, void *res) { return 0; }
+DTLS *DTLS_Get() { return 0; }
+void DTLS_Destroy() {}
+#endif // SANITIZER_INTERCEPT_TLS_GET_ADDR
+
+} // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_tls_get_addr.h b/lib/sanitizer_common/sanitizer_tls_get_addr.h
new file mode 100644
index 000000000000..0fc9a2257c68
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_tls_get_addr.h
@@ -0,0 +1,60 @@
+//===-- sanitizer_tls_get_addr.h --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Handle the __tls_get_addr call.
+//
+// All this magic is specific to glibc and is required to workaround
+// the lack of interface that would tell us about the Dynamic TLS (DTLS).
+// https://sourceware.org/bugzilla/show_bug.cgi?id=16291
+//
+// The matters get worse because the glibc implementation changed between
+// 2.18 and 2.19:
+// https://groups.google.com/forum/#!topic/address-sanitizer/BfwYD8HMxTM
+//
+// Before 2.19, every DTLS chunk is allocated with __libc_memalign,
+// which we intercept and thus know where is the DTLS.
+// Since 2.19, DTLS chunks are allocated with __signal_safe_memalign,
+// which is an internal function that wraps a mmap call, neither of which
+// we can intercept. Luckily, __signal_safe_memalign has a simple parseable
+// header which we can use.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_TLS_GET_ADDR_H
+#define SANITIZER_TLS_GET_ADDR_H
+
+#include "sanitizer_common.h"
+
+namespace __sanitizer {
+
+struct DTLS {
+ // Array of DTLS chunks for the current Thread.
+ // If beg == 0, the chunk is unused.
+ struct DTV {
+ uptr beg, size;
+ };
+
+ uptr dtv_size;
+ DTV *dtv; // dtv_size elements, allocated by MmapOrDie.
+
+ // Auxiliary fields, don't access them outside sanitizer_tls_get_addr.cc
+ uptr last_memalign_size;
+ uptr last_memalign_ptr;
+};
+
+// Returns pointer and size of a linker-allocated TLS block.
+// Each block is returned exactly once.
+DTLS::DTV *DTLS_on_tls_get_addr(void *arg, void *res);
+void DTLS_on_libc_memalign(void *ptr, uptr size);
+DTLS *DTLS_Get();
+void DTLS_Destroy(); // Make sure to call this before the thread is destroyed.
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_TLS_GET_ADDR_H
diff --git a/lib/sanitizer_common/sanitizer_unwind_posix_libcdep.cc b/lib/sanitizer_common/sanitizer_unwind_posix_libcdep.cc
new file mode 100644
index 000000000000..a98e61771c02
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_unwind_posix_libcdep.cc
@@ -0,0 +1,158 @@
+//===-- sanitizer_unwind_posix.cc ----------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the unwind.h-based (aka "slow") stack unwinding routines
+// available to the tools on Linux, Android, FreeBSD and OS X.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_platform.h"
+#if SANITIZER_POSIX
+#include "sanitizer_common.h"
+#include "sanitizer_stacktrace.h"
+
+#if SANITIZER_ANDROID
+#include <dlfcn.h> // for dlopen()
+#endif
+
+#if SANITIZER_FREEBSD
+#define _GNU_SOURCE // to declare _Unwind_Backtrace() from <unwind.h>
+#endif
+#include <unwind.h>
+
+namespace __sanitizer {
+
+//------------------------- SlowUnwindStack -----------------------------------
+
+typedef struct {
+ uptr absolute_pc;
+ uptr stack_top;
+ uptr stack_size;
+} backtrace_frame_t;
+
+extern "C" {
+typedef void *(*acquire_my_map_info_list_func)();
+typedef void (*release_my_map_info_list_func)(void *map);
+typedef sptr (*unwind_backtrace_signal_arch_func)(
+ void *siginfo, void *sigcontext, void *map_info_list,
+ backtrace_frame_t *backtrace, uptr ignore_depth, uptr max_depth);
+acquire_my_map_info_list_func acquire_my_map_info_list;
+release_my_map_info_list_func release_my_map_info_list;
+unwind_backtrace_signal_arch_func unwind_backtrace_signal_arch;
+} // extern "C"
+
+#if SANITIZER_ANDROID
+void SanitizerInitializeUnwinder() {
+ void *p = dlopen("libcorkscrew.so", RTLD_LAZY);
+ if (!p) {
+ VReport(1,
+ "Failed to open libcorkscrew.so. You may see broken stack traces "
+ "in SEGV reports.");
+ return;
+ }
+ acquire_my_map_info_list =
+ (acquire_my_map_info_list_func)(uptr)dlsym(p, "acquire_my_map_info_list");
+ release_my_map_info_list =
+ (release_my_map_info_list_func)(uptr)dlsym(p, "release_my_map_info_list");
+ unwind_backtrace_signal_arch = (unwind_backtrace_signal_arch_func)(uptr)dlsym(
+ p, "unwind_backtrace_signal_arch");
+ if (!acquire_my_map_info_list || !release_my_map_info_list ||
+ !unwind_backtrace_signal_arch) {
+ VReport(1,
+ "Failed to find one of the required symbols in libcorkscrew.so. "
+ "You may see broken stack traces in SEGV reports.");
+ acquire_my_map_info_list = 0;
+ unwind_backtrace_signal_arch = 0;
+ release_my_map_info_list = 0;
+ }
+}
+#endif
+
+#ifdef __arm__
+#define UNWIND_STOP _URC_END_OF_STACK
+#define UNWIND_CONTINUE _URC_NO_REASON
+#else
+#define UNWIND_STOP _URC_NORMAL_STOP
+#define UNWIND_CONTINUE _URC_NO_REASON
+#endif
+
+uptr Unwind_GetIP(struct _Unwind_Context *ctx) {
+#ifdef __arm__
+ uptr val;
+ _Unwind_VRS_Result res = _Unwind_VRS_Get(ctx, _UVRSC_CORE,
+ 15 /* r15 = PC */, _UVRSD_UINT32, &val);
+ CHECK(res == _UVRSR_OK && "_Unwind_VRS_Get failed");
+ // Clear the Thumb bit.
+ return val & ~(uptr)1;
+#else
+ return _Unwind_GetIP(ctx);
+#endif
+}
+
+struct UnwindTraceArg {
+ BufferedStackTrace *stack;
+ uptr max_depth;
+};
+
+_Unwind_Reason_Code Unwind_Trace(struct _Unwind_Context *ctx, void *param) {
+ UnwindTraceArg *arg = (UnwindTraceArg*)param;
+ CHECK_LT(arg->stack->size, arg->max_depth);
+ uptr pc = Unwind_GetIP(ctx);
+ arg->stack->trace_buffer[arg->stack->size++] = pc;
+ if (arg->stack->size == arg->max_depth) return UNWIND_STOP;
+ return UNWIND_CONTINUE;
+}
+
+void BufferedStackTrace::SlowUnwindStack(uptr pc, uptr max_depth) {
+ CHECK_GE(max_depth, 2);
+ size = 0;
+ UnwindTraceArg arg = {this, Min(max_depth + 1, kStackTraceMax)};
+ _Unwind_Backtrace(Unwind_Trace, &arg);
+ // We need to pop a few frames so that pc is on top.
+ uptr to_pop = LocatePcInTrace(pc);
+ // trace_buffer[0] belongs to the current function so we always pop it,
+ // unless there is only 1 frame in the stack trace (1 frame is always better
+ // than 0!).
+ // 1-frame stacks don't normally happen, but this depends on the actual
+ // unwinder implementation (libgcc, libunwind, etc) which is outside of our
+ // control.
+ if (to_pop == 0 && size > 1)
+ to_pop = 1;
+ PopStackFrames(to_pop);
+ trace_buffer[0] = pc;
+}
+
+void BufferedStackTrace::SlowUnwindStackWithContext(uptr pc, void *context,
+ uptr max_depth) {
+ CHECK_GE(max_depth, 2);
+ if (!unwind_backtrace_signal_arch) {
+ SlowUnwindStack(pc, max_depth);
+ return;
+ }
+
+ void *map = acquire_my_map_info_list();
+ CHECK(map);
+ InternalScopedBuffer<backtrace_frame_t> frames(kStackTraceMax);
+ // siginfo argument appears to be unused.
+ sptr res = unwind_backtrace_signal_arch(/* siginfo */ 0, context, map,
+ frames.data(),
+ /* ignore_depth */ 0, max_depth);
+ release_my_map_info_list(map);
+ if (res < 0) return;
+ CHECK_LE((uptr)res, kStackTraceMax);
+
+ size = 0;
+ // +2 compensate for libcorkscrew unwinder returning addresses of call
+ // instructions instead of raw return addresses.
+ for (sptr i = 0; i < res; ++i)
+ trace_buffer[size++] = frames[i].absolute_pc + 2;
+}
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_POSIX
diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc
index 362c8c99a74c..3e9014199651 100644
--- a/lib/sanitizer_common/sanitizer_win.cc
+++ b/lib/sanitizer_common/sanitizer_win.cc
@@ -17,9 +17,10 @@
#define WIN32_LEAN_AND_MEAN
#define NOGDI
-#include <stdlib.h>
-#include <io.h>
#include <windows.h>
+#include <dbghelp.h>
+#include <io.h>
+#include <stdlib.h>
#include "sanitizer_common.h"
#include "sanitizer_libc.h"
@@ -64,6 +65,7 @@ uptr GetThreadSelf() {
return GetTid();
}
+#if !SANITIZER_GO
void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
uptr *stack_bottom) {
CHECK(stack_top);
@@ -76,12 +78,14 @@ void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
*stack_top = (uptr)mbi.BaseAddress + mbi.RegionSize;
*stack_bottom = (uptr)mbi.AllocationBase;
}
+#endif // #if !SANITIZER_GO
void *MmapOrDie(uptr size, const char *mem_type) {
void *rv = VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
if (rv == 0) {
- Report("ERROR: Failed to allocate 0x%zx (%zd) bytes of %s\n",
- size, size, mem_type);
+ Report("ERROR: %s failed to "
+ "allocate 0x%zx (%zd) bytes of %s (error code: %d)\n",
+ SanitizerToolName, size, size, mem_type, GetLastError());
CHECK("unable to mmap" && 0);
}
return rv;
@@ -89,8 +93,9 @@ void *MmapOrDie(uptr size, const char *mem_type) {
void UnmapOrDie(void *addr, uptr size) {
if (VirtualFree(addr, size, MEM_DECOMMIT) == 0) {
- Report("ERROR: Failed to deallocate 0x%zx (%zd) bytes at address %p\n",
- size, size, addr);
+ Report("ERROR: %s failed to "
+ "deallocate 0x%zx (%zd) bytes at address %p (error code: %d)\n",
+ SanitizerToolName, size, size, addr, GetLastError());
CHECK("unable to unmap" && 0);
}
}
@@ -101,8 +106,9 @@ void *MmapFixedNoReserve(uptr fixed_addr, uptr size) {
void *p = VirtualAlloc((LPVOID)fixed_addr, size,
MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
if (p == 0)
- Report("ERROR: Failed to allocate 0x%zx (%zd) bytes at %p (%d)\n",
- size, size, fixed_addr, GetLastError());
+ Report("ERROR: %s failed to "
+ "allocate %p (%zd) bytes at %p (error code: %d)\n",
+ SanitizerToolName, size, size, fixed_addr, GetLastError());
return p;
}
@@ -110,6 +116,11 @@ void *MmapFixedOrDie(uptr fixed_addr, uptr size) {
return MmapFixedNoReserve(fixed_addr, size);
}
+void *MmapNoReserveOrDie(uptr size, const char *mem_type) {
+ // FIXME: make this really NoReserve?
+ return MmapOrDie(size, mem_type);
+}
+
void *Mprotect(uptr fixed_addr, uptr size) {
return VirtualAlloc((LPVOID)fixed_addr, size,
MEM_RESERVE | MEM_COMMIT, PAGE_NOACCESS);
@@ -129,6 +140,10 @@ void *MapFileToMemory(const char *file_name, uptr *buff_size) {
UNIMPLEMENTED();
}
+void *MapWritableFileToMemory(void *addr, uptr size, uptr fd, uptr offset) {
+ UNIMPLEMENTED();
+}
+
static const int kMaxEnvNameLength = 128;
static const DWORD kMaxEnvValueLength = 32767;
@@ -176,15 +191,16 @@ void DumpProcessMap() {
UNIMPLEMENTED();
}
-void DisableCoreDumper() {
- UNIMPLEMENTED();
+void DisableCoreDumperIfNecessary() {
+ // Do nothing.
}
void ReExec() {
UNIMPLEMENTED();
}
-void PrepareForSandboxing() {
+void PrepareForSandboxing(__sanitizer_sandbox_arguments *args) {
+ (void)args;
// Nothing here for now.
}
@@ -196,6 +212,14 @@ void SetStackSizeLimitInBytes(uptr limit) {
UNIMPLEMENTED();
}
+bool AddressSpaceIsUnlimited() {
+ UNIMPLEMENTED();
+}
+
+void SetAddressSpaceUnlimited() {
+ UNIMPLEMENTED();
+}
+
char *FindPathToBinary(const char *name) {
// Nothing here for now.
return 0;
@@ -215,7 +239,7 @@ u64 NanoTime() {
void Abort() {
abort();
- _exit(-1); // abort is not NORETURN on Windows.
+ internal__exit(-1); // abort is not NORETURN on Windows.
}
uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
@@ -266,13 +290,48 @@ uptr internal_read(fd_t fd, void *buf, uptr count) {
uptr internal_write(fd_t fd, const void *buf, uptr count) {
if (fd != kStderrFd)
UNIMPLEMENTED();
- HANDLE err = GetStdHandle(STD_ERROR_HANDLE);
- if (err == 0)
- return 0; // FIXME: this might not work on some apps.
- DWORD ret;
- if (!WriteFile(err, buf, count, &ret, 0))
+
+ static HANDLE output_stream = 0;
+ // Abort immediately if we know printing is not possible.
+ if (output_stream == INVALID_HANDLE_VALUE)
return 0;
- return ret;
+
+ // If called for the first time, try to use stderr to output stuff,
+ // falling back to stdout if anything goes wrong.
+ bool fallback_to_stdout = false;
+ if (output_stream == 0) {
+ output_stream = GetStdHandle(STD_ERROR_HANDLE);
+ // We don't distinguish "no such handle" from error.
+ if (output_stream == 0)
+ output_stream = INVALID_HANDLE_VALUE;
+
+ if (output_stream == INVALID_HANDLE_VALUE) {
+ // Retry with stdout?
+ output_stream = GetStdHandle(STD_OUTPUT_HANDLE);
+ if (output_stream == 0)
+ output_stream = INVALID_HANDLE_VALUE;
+ if (output_stream == INVALID_HANDLE_VALUE)
+ return 0;
+ } else {
+ // Successfully got an stderr handle. However, if WriteFile() fails,
+ // we can still try to fallback to stdout.
+ fallback_to_stdout = true;
+ }
+ }
+
+ DWORD ret;
+ if (WriteFile(output_stream, buf, count, &ret, 0))
+ return ret;
+
+ // Re-try with stdout if using a valid stderr handle fails.
+ if (fallback_to_stdout) {
+ output_stream = GetStdHandle(STD_OUTPUT_HANDLE);
+ if (output_stream == 0)
+ output_stream = INVALID_HANDLE_VALUE;
+ if (output_stream != INVALID_HANDLE_VALUE)
+ return internal_write(fd, buf, count);
+ }
+ return 0;
}
uptr internal_stat(const char *path, void *buf) {
@@ -305,7 +364,19 @@ uptr internal_sched_yield() {
}
void internal__exit(int exitcode) {
- _exit(exitcode);
+ ExitProcess(exitcode);
+}
+
+uptr internal_ftruncate(fd_t fd, uptr size) {
+ UNIMPLEMENTED();
+}
+
+uptr internal_rename(const char *oldpath, const char *newpath) {
+ UNIMPLEMENTED();
+}
+
+uptr GetRSS() {
+ return 0;
}
// ---------------------- BlockingMutex ---------------- {{{1
@@ -376,28 +447,55 @@ void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
#endif
}
-void StackTrace::SlowUnwindStack(uptr pc, uptr max_depth) {
+#if !SANITIZER_GO
+void BufferedStackTrace::SlowUnwindStack(uptr pc, uptr max_depth) {
+ CHECK_GE(max_depth, 2);
// FIXME: CaptureStackBackTrace might be too slow for us.
// FIXME: Compare with StackWalk64.
// FIXME: Look at LLVMUnhandledExceptionFilter in Signals.inc
size = CaptureStackBackTrace(2, Min(max_depth, kStackTraceMax),
(void**)trace, 0);
+ if (size == 0)
+ return;
+
// Skip the RTL frames by searching for the PC in the stacktrace.
uptr pc_location = LocatePcInTrace(pc);
PopStackFrames(pc_location);
}
-void MaybeOpenReportFile() {
- // Windows doesn't have native fork, and we don't support Cygwin or other
- // environments that try to fake it, so the initial report_fd will always be
- // correct.
+void BufferedStackTrace::SlowUnwindStackWithContext(uptr pc, void *context,
+ uptr max_depth) {
+ CONTEXT ctx = *(CONTEXT *)context;
+ STACKFRAME64 stack_frame;
+ memset(&stack_frame, 0, sizeof(stack_frame));
+ size = 0;
+#if defined(_WIN64)
+ int machine_type = IMAGE_FILE_MACHINE_AMD64;
+ stack_frame.AddrPC.Offset = ctx.Rip;
+ stack_frame.AddrFrame.Offset = ctx.Rbp;
+ stack_frame.AddrStack.Offset = ctx.Rsp;
+#else
+ int machine_type = IMAGE_FILE_MACHINE_I386;
+ stack_frame.AddrPC.Offset = ctx.Eip;
+ stack_frame.AddrFrame.Offset = ctx.Ebp;
+ stack_frame.AddrStack.Offset = ctx.Esp;
+#endif
+ stack_frame.AddrPC.Mode = AddrModeFlat;
+ stack_frame.AddrFrame.Mode = AddrModeFlat;
+ stack_frame.AddrStack.Mode = AddrModeFlat;
+ while (StackWalk64(machine_type, GetCurrentProcess(), GetCurrentThread(),
+ &stack_frame, &ctx, NULL, &SymFunctionTableAccess64,
+ &SymGetModuleBase64, NULL) &&
+ size < Min(max_depth, kStackTraceMax)) {
+ trace_buffer[size++] = (uptr)stack_frame.AddrPC.Offset;
+ }
}
+#endif // #if !SANITIZER_GO
-void RawWrite(const char *buffer) {
- static const char *kRawWriteError =
- "RawWrite can't output requested buffer!\n";
- uptr length = (uptr)internal_strlen(buffer);
- if (length != internal_write(report_fd, buffer, length)) {
+void ReportFile::Write(const char *buffer, uptr length) {
+ SpinMutexLock l(mu);
+ ReopenIfNecessary();
+ if (length != internal_write(fd, buffer, length)) {
// stderr may be closed, but we may be able to print to the debugger
// instead. This is the case when launching a program from Visual Studio,
// and the following routine should write to its console.
@@ -405,6 +503,29 @@ void RawWrite(const char *buffer) {
}
}
+void SetAlternateSignalStack() {
+ // FIXME: Decide what to do on Windows.
+}
+
+void UnsetAlternateSignalStack() {
+ // FIXME: Decide what to do on Windows.
+}
+
+void InstallDeadlySignalHandlers(SignalHandlerType handler) {
+ (void)handler;
+ // FIXME: Decide what to do on Windows.
+}
+
+bool IsDeadlySignal(int signum) {
+ // FIXME: Decide what to do on Windows.
+ return false;
+}
+
+bool IsAccessibleMemoryRange(uptr beg, uptr size) {
+ // FIXME: Actually implement this function.
+ return true;
+}
+
} // namespace __sanitizer
#endif // _WIN32
diff --git a/lib/sanitizer_common/scripts/check_lint.sh b/lib/sanitizer_common/scripts/check_lint.sh
index 5f1bd4ba4316..267273d97794 100755
--- a/lib/sanitizer_common/scripts/check_lint.sh
+++ b/lib/sanitizer_common/scripts/check_lint.sh
@@ -1,16 +1,18 @@
-#!/bin/bash
+#!/bin/sh
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
# Guess path to LLVM_CHECKOUT if not provided
-if [ "${LLVM_CHECKOUT}" == "" ]; then
+if [ "${LLVM_CHECKOUT}" = "" ]; then
LLVM_CHECKOUT="${SCRIPT_DIR}/../../../../../"
fi
-# Cpplint setup
+# python tools setup
CPPLINT=${SCRIPT_DIR}/cpplint.py
+LITLINT=${SCRIPT_DIR}/litlint.py
if [ "${PYTHON_EXECUTABLE}" != "" ]; then
CPPLINT="${PYTHON_EXECUTABLE} ${CPPLINT}"
+ LITLINT="${PYTHON_EXECUTABLE} ${LITLINT}"
fi
# Filters
@@ -19,7 +21,7 @@ LLVM_LINT_FILTER=-,+whitespace
COMMON_LINT_FILTER=-build/include,-build/header_guard,-legal/copyright,-whitespace/comments,-readability/casting,\
-build/namespaces
ASAN_RTL_LINT_FILTER=${COMMON_LINT_FILTER},-runtime/int
-ASAN_TEST_LINT_FILTER=${COMMON_LINT_FILTER},-runtime/sizeof,-runtime/int,-runtime/printf
+ASAN_TEST_LINT_FILTER=${COMMON_LINT_FILTER},-runtime/sizeof,-runtime/int,-runtime/printf,-runtime/threadsafe_fn
ASAN_LIT_TEST_LINT_FILTER=${ASAN_TEST_LINT_FILTER},-whitespace/line_length
TSAN_RTL_LINT_FILTER=${COMMON_LINT_FILTER}
TSAN_TEST_LINT_FILTER=${TSAN_RTL_LINT_FILTER},-runtime/threadsafe_fn,-runtime/int
@@ -27,7 +29,8 @@ TSAN_LIT_TEST_LINT_FILTER=${TSAN_TEST_LINT_FILTER},-whitespace/line_length
MSAN_RTL_LINT_FILTER=${COMMON_LINT_FILTER}
LSAN_RTL_LINT_FILTER=${COMMON_LINT_FILTER}
LSAN_LIT_TEST_LINT_FILTER=${LSAN_RTL_LINT_FILTER},-whitespace/line_length
-COMMON_RTL_INC_LINT_FILTER=${COMMON_LINT_FILTER},-runtime/int,-runtime/sizeof,-runtime/printf
+DFSAN_RTL_LINT_FILTER=${COMMON_LINT_FILTER},-runtime/int,-runtime/printf,-runtime/references,-readability/function
+COMMON_RTL_INC_LINT_FILTER=${COMMON_LINT_FILTER},-runtime/int,-runtime/sizeof,-runtime/printf,-readability/fn_size
SANITIZER_INCLUDES_LINT_FILTER=${COMMON_LINT_FILTER},-runtime/int
MKTEMP="mktemp -q /tmp/tmp.XXXXXXXXXX"
cd ${LLVM_CHECKOUT}
@@ -44,51 +47,67 @@ run_lint() {
cat $TASK_LOG | grep -v "Done processing" | grep -v "Total errors found" \
| grep -v "Skipping input" >> $ERROR_LOG
fi
- if [[ "${SILENT}" != "1" ]]; then
+ if [ "${SILENT}" != "1" ]; then
cat $TASK_LOG
fi
+ ${LITLINT} "$@" 2>>$ERROR_LOG
}
run_lint ${LLVM_LINT_FILTER} --filter=${LLVM_LINT_FILTER} \
- lib/Transforms/Instrumentation/*Sanitizer.cpp \
- lib/Transforms/Utils/SpecialCaseList.cpp &
+ lib/Transforms/Instrumentation/*Sanitizer.cpp &
-COMPILER_RT=projects/compiler-rt
+if [ "${COMPILER_RT}" = "" ]; then
+ COMPILER_RT=projects/compiler-rt
+fi
+LIT_TESTS=${COMPILER_RT}/test
# Headers
SANITIZER_INCLUDES=${COMPILER_RT}/include/sanitizer
run_lint ${SANITIZER_INCLUDES_LINT_FILTER} ${SANITIZER_INCLUDES}/*.h &
# Sanitizer_common
COMMON_RTL=${COMPILER_RT}/lib/sanitizer_common
-run_lint ${COMMON_RTL_INC_LINT_FILTER} ${COMMON_RTL}/*.{cc,h} \
+run_lint ${COMMON_RTL_INC_LINT_FILTER} ${COMMON_RTL}/*.cc \
+ ${COMMON_RTL}/*.h \
${COMMON_RTL}/tests/*.cc &
# Interception
INTERCEPTION=${COMPILER_RT}/lib/interception
-run_lint ${ASAN_RTL_LINT_FILTER} ${INTERCEPTION}/*.{cc,h} &
+run_lint ${ASAN_RTL_LINT_FILTER} ${INTERCEPTION}/*.cc \
+ ${INTERCEPTION}/*.h &
# ASan
ASAN_RTL=${COMPILER_RT}/lib/asan
-run_lint ${ASAN_RTL_LINT_FILTER} ${ASAN_RTL}/*.{cc,h} &
-run_lint ${ASAN_TEST_LINT_FILTER} ${ASAN_RTL}/tests/*.{cc,h} &
-run_lint ${ASAN_LIT_TEST_LINT_FILTER} ${ASAN_RTL}/lit_tests/*/*.cc &
+run_lint ${ASAN_RTL_LINT_FILTER} ${ASAN_RTL}/*.cc \
+ ${ASAN_RTL}/*.h &
+run_lint ${ASAN_TEST_LINT_FILTER} ${ASAN_RTL}/tests/*.cc \
+ ${ASAN_RTL}/tests/*.h &
+run_lint ${ASAN_LIT_TEST_LINT_FILTER} ${LIT_TESTS}/asan/*/*.cc &
# TSan
TSAN_RTL=${COMPILER_RT}/lib/tsan
-run_lint ${TSAN_RTL_LINT_FILTER} ${TSAN_RTL}/rtl/*.{cc,h} &
-run_lint ${TSAN_TEST_LINT_FILTER} ${TSAN_RTL}/tests/rtl/*.{cc,h} \
+run_lint ${TSAN_RTL_LINT_FILTER} ${TSAN_RTL}/rtl/*.cc \
+ ${TSAN_RTL}/rtl/*.h &
+run_lint ${TSAN_TEST_LINT_FILTER} ${TSAN_RTL}/tests/rtl/*.cc \
+ ${TSAN_RTL}/tests/rtl/*.h \
${TSAN_RTL}/tests/unit/*.cc &
-run_lint ${TSAN_LIT_TEST_LINT_FILTER} ${TSAN_RTL}/lit_tests/*.cc &
+run_lint ${TSAN_LIT_TEST_LINT_FILTER} ${LIT_TESTS}/tsan/*.cc &
# MSan
MSAN_RTL=${COMPILER_RT}/lib/msan
-run_lint ${MSAN_RTL_LINT_FILTER} ${MSAN_RTL}/*.{cc,h} &
+run_lint ${MSAN_RTL_LINT_FILTER} ${MSAN_RTL}/*.cc \
+ ${MSAN_RTL}/*.h &
# LSan
LSAN_RTL=${COMPILER_RT}/lib/lsan
-run_lint ${LSAN_RTL_LINT_FILTER} ${LSAN_RTL}/*.{cc,h} \
- ${LSAN_RTL}/tests/*.{cc,h} &
-run_lint ${LSAN_LIT_TEST_LINT_FILTER} ${LSAN_RTL}/lit_tests/*/*.cc &
+run_lint ${LSAN_RTL_LINT_FILTER} ${LSAN_RTL}/*.cc \
+ ${LSAN_RTL}/*.h &
+run_lint ${LSAN_LIT_TEST_LINT_FILTER} ${LIT_TESTS}/lsan/*/*.cc &
+
+# DFSan
+DFSAN_RTL=${COMPILER_RT}/lib/dfsan
+run_lint ${DFSAN_RTL_LINT_FILTER} ${DFSAN_RTL}/*.cc \
+ ${DFSAN_RTL}/*.h &
+${DFSAN_RTL}/scripts/check_custom_wrappers.sh >> $ERROR_LOG
# Misc files
FILES=${COMMON_RTL}/*.inc
@@ -106,7 +125,7 @@ for temp in $TMPFILES; do
rm -f $temp
done
-if [[ -s $ERROR_LOG ]]; then
+if [ -s $ERROR_LOG ]; then
cat $ERROR_LOG
exit 1
fi
diff --git a/lib/sanitizer_common/scripts/cpplint.py b/lib/sanitizer_common/scripts/cpplint.py
index a8c9f6784f2d..742459af172f 100755
--- a/lib/sanitizer_common/scripts/cpplint.py
+++ b/lib/sanitizer_common/scripts/cpplint.py
@@ -3634,7 +3634,7 @@ def UpdateIncludeState(filename, include_state, io=codecs):
io: The io factory to use to read the file. Provided for testability.
Returns:
- True if a header was succesfully added. False otherwise.
+ True if a header was successfully added. False otherwise.
"""
headerfile = None
try:
@@ -3706,7 +3706,7 @@ def CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error,
# Let's copy the include_state so it is only messed up within this function.
include_state = include_state.copy()
- # Did we find the header for this file (if any) and succesfully load it?
+ # Did we find the header for this file (if any) and successfully load it?
header_found = False
# Use the absolute path so that matching works properly.
diff --git a/lib/sanitizer_common/scripts/gen_dynamic_list.py b/lib/sanitizer_common/scripts/gen_dynamic_list.py
index 32ba9226911e..7bab230650cb 100755
--- a/lib/sanitizer_common/scripts/gen_dynamic_list.py
+++ b/lib/sanitizer_common/scripts/gen_dynamic_list.py
@@ -35,12 +35,16 @@ def get_global_functions(library):
functions = []
nm_proc = subprocess.Popen(['nm', library], stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
- nm_out = nm_proc.communicate()[0].split('\n')
+ nm_out = nm_proc.communicate()[0].decode().split('\n')
if nm_proc.returncode != 0:
raise subprocess.CalledProcessError(nm_proc.returncode, 'nm')
+ func_symbols = ['T', 'W']
+ # On PowerPC, nm prints function descriptors from .data section.
+ if os.uname()[4] in ["powerpc", "ppc64"]:
+ func_symbols += ['D']
for line in nm_out:
cols = line.split(' ')
- if (len(cols) == 3 and cols[1] in ('T', 'W')) :
+ if len(cols) == 3 and cols[1] in func_symbols :
functions.append(cols[2])
return functions
@@ -75,11 +79,11 @@ def main(argv):
for line in f:
result.append(line.rstrip())
# Print the resulting list in the format recognized by ld.
- print '{'
+ print('{')
result.sort()
for f in result:
- print ' ' + f + ';'
- print '};'
+ print(' ' + f + ';')
+ print('};')
if __name__ == '__main__':
main(sys.argv)
diff --git a/lib/sanitizer_common/scripts/litlint.py b/lib/sanitizer_common/scripts/litlint.py
new file mode 100755
index 000000000000..1e78448b63d4
--- /dev/null
+++ b/lib/sanitizer_common/scripts/litlint.py
@@ -0,0 +1,72 @@
+#!/usr/bin/python
+#
+# litlint
+#
+# Ensure RUN commands in lit tests are free of common errors.
+#
+# If any errors are detected, litlint returns a nonzero exit code.
+#
+
+import optparse
+import re
+import sys
+
+# Compile regex once for all files
+runRegex = re.compile(r'(?<!-o)(?<!%run) %t\s')
+
+def LintLine(s):
+ """ Validate a line
+
+ Args:
+ s: str, the line to validate
+
+ Returns:
+ Returns an error message and a 1-based column number if an error was
+ detected, otherwise (None, None).
+ """
+
+ # Check that RUN command can be executed with an emulator
+ m = runRegex.search(s)
+ if m:
+ start, end = m.span()
+ return ('missing %run before %t', start + 2)
+
+ # No errors
+ return (None, None)
+
+
+def LintFile(p):
+ """ Check that each RUN command can be executed with an emulator
+
+ Args:
+ p: str, valid path to a file
+
+ Returns:
+ The number of errors detected.
+ """
+ errs = 0
+ with open(p, 'r') as f:
+ for i, s in enumerate(f.readlines(), start=1):
+ msg, col = LintLine(s)
+ if msg != None:
+ errs += 1
+ errorMsg = 'litlint: {}:{}:{}: error: {}.\n{}{}\n'
+ arrow = (col-1) * ' ' + '^'
+ sys.stderr.write(errorMsg.format(p, i, col, msg, s, arrow))
+ return errs
+
+
+if __name__ == "__main__":
+ # Parse args
+ parser = optparse.OptionParser()
+ parser.add_option('--filter') # ignored
+ (options, filenames) = parser.parse_args()
+
+ # Lint each file
+ errs = 0
+ for p in filenames:
+ errs += LintFile(p)
+
+ # If errors, return nonzero
+ if errs > 0:
+ sys.exit(1)
diff --git a/lib/sanitizer_common/scripts/litlint_test.py b/lib/sanitizer_common/scripts/litlint_test.py
new file mode 100755
index 000000000000..3ce482d70444
--- /dev/null
+++ b/lib/sanitizer_common/scripts/litlint_test.py
@@ -0,0 +1,23 @@
+#!/usr/bin/python
+
+# Tests for litlint.py
+#
+# Usage: python litlint_test.py
+#
+# Returns nonzero if any test fails
+
+import litlint
+import unittest
+
+class TestLintLine(unittest.TestCase):
+ def test_missing_run(self):
+ f = litlint.LintLine
+ self.assertEqual(f(' %t '), ('missing %run before %t', 2))
+ self.assertEqual(f(' %t\n'), ('missing %run before %t', 2))
+ self.assertEqual(f(' %t.so '), (None, None))
+ self.assertEqual(f(' %t.o '), (None, None))
+ self.assertEqual(f('%run %t '), (None, None))
+ self.assertEqual(f('-o %t '), (None, None))
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/lib/sanitizer_common/scripts/sancov.py b/lib/sanitizer_common/scripts/sancov.py
index aa791bc4eb01..476953015280 100755
--- a/lib/sanitizer_common/scripts/sancov.py
+++ b/lib/sanitizer_common/scripts/sancov.py
@@ -4,23 +4,27 @@
# We need to merge these integers into a set and then
# either print them (as hex) or dump them into another file.
import array
+import struct
import sys
+import bisect
+import os.path
prog_name = "";
def Usage():
print >> sys.stderr, "Usage: \n" + \
" " + prog_name + " merge file1 [file2 ...] > output\n" \
- " " + prog_name + " print file1 [file2 ...]\n"
+ " " + prog_name + " print file1 [file2 ...]\n" \
+ " " + prog_name + " unpack file1 [file2 ...]\n" \
+ " " + prog_name + " rawunpack file1 [file2 ...]\n"
exit(1)
def ReadOneFile(path):
- f = open(path, mode="rb")
- f.seek(0, 2)
- size = f.tell()
- f.seek(0, 0)
- s = set(array.array('I', f.read(size)))
- f.close()
+ with open(path, mode="rb") as f:
+ f.seek(0, 2)
+ size = f.tell()
+ f.seek(0, 0)
+ s = set(array.array('I', f.read(size)))
print >>sys.stderr, "%s: read %d PCs from %s" % (prog_name, size / 4, path)
return s
@@ -44,6 +48,89 @@ def MergeAndPrint(files):
a = array.array('I', s)
a.tofile(sys.stdout)
+
+def UnpackOneFile(path):
+ with open(path, mode="rb") as f:
+ print >> sys.stderr, "%s: unpacking %s" % (prog_name, path)
+ while True:
+ header = f.read(12)
+ if not header: return
+ if len(header) < 12:
+ break
+ pid, module_length, blob_size = struct.unpack('iII', header)
+ module = f.read(module_length)
+ blob = f.read(blob_size)
+ assert(len(module) == module_length)
+ assert(len(blob) == blob_size)
+ extracted_file = "%s.%d.sancov" % (module, pid)
+ print >> sys.stderr, "%s: extracting %s" % \
+ (prog_name, extracted_file)
+ # The packed file may contain multiple blobs for the same pid/module
+ # pair. Append to the end of the file instead of overwriting.
+ with open(extracted_file, 'ab') as f2:
+ f2.write(blob)
+ # fail
+ raise Exception('Error reading file %s' % path)
+
+
+def Unpack(files):
+ for f in files:
+ UnpackOneFile(f)
+
+def UnpackOneRawFile(path, map_path):
+ mem_map = []
+ with open(map_path, mode="rt") as f_map:
+ print >> sys.stderr, "%s: reading map %s" % (prog_name, map_path)
+ bits = int(f_map.readline())
+ for line in f_map:
+ parts = line.rstrip().split()
+ mem_map.append((int(parts[0], 16),
+ int(parts[1], 16),
+ int(parts[2], 16),
+ ' '.join(parts[3:])))
+ mem_map.sort(key=lambda m : m[0])
+ mem_map_keys = [m[0] for m in mem_map]
+
+ with open(path, mode="rb") as f:
+ print >> sys.stderr, "%s: unpacking %s" % (prog_name, path)
+
+ f.seek(0, 2)
+ size = f.tell()
+ f.seek(0, 0)
+ if bits == 64:
+ typecode = 'L'
+ else:
+ typecode = 'I'
+ pcs = array.array(typecode, f.read(size))
+ mem_map_pcs = [[] for i in range(0, len(mem_map))]
+
+ for pc in pcs:
+ if pc == 0: continue
+ map_idx = bisect.bisect(mem_map_keys, pc) - 1
+ (start, end, base, module_path) = mem_map[map_idx]
+ assert pc >= start
+ if pc >= end:
+ print >> sys.stderr, "warning: %s: pc %x outside of any known mapping" % (prog_name, pc)
+ continue
+ mem_map_pcs[map_idx].append(pc - base)
+
+ for ((start, end, base, module_path), pc_list) in zip(mem_map, mem_map_pcs):
+ if len(pc_list) == 0: continue
+ assert path.endswith('.sancov.raw')
+ dst_path = module_path + '.' + os.path.basename(path)[:-4]
+ print "writing %d PCs to %s" % (len(pc_list), dst_path)
+ arr = array.array('I')
+ arr.fromlist(sorted(pc_list))
+ with open(dst_path, 'ab') as f2:
+ arr.tofile(f2)
+
+def RawUnpack(files):
+ for f in files:
+ if not f.endswith('.sancov.raw'):
+ raise Exception('Unexpected raw file name %s' % f)
+ f_map = f[:-3] + 'map'
+ UnpackOneRawFile(f, f_map)
+
if __name__ == '__main__':
prog_name = sys.argv[0]
if len(sys.argv) <= 2:
@@ -52,5 +139,9 @@ if __name__ == '__main__':
PrintFiles(sys.argv[2:])
elif sys.argv[1] == "merge":
MergeAndPrint(sys.argv[2:])
+ elif sys.argv[1] == "unpack":
+ Unpack(sys.argv[2:])
+ elif sys.argv[1] == "rawunpack":
+ RawUnpack(sys.argv[2:])
else:
Usage()
diff --git a/lib/sanitizer_common/tests/CMakeLists.txt b/lib/sanitizer_common/tests/CMakeLists.txt
index 5b66917b05b0..bb7a399b0ec6 100644
--- a/lib/sanitizer_common/tests/CMakeLists.txt
+++ b/lib/sanitizer_common/tests/CMakeLists.txt
@@ -1,10 +1,16 @@
include(CompilerRTCompile)
+clang_compiler_add_cxx_check()
+
set(SANITIZER_UNITTESTS
sanitizer_allocator_test.cc
sanitizer_atomic_test.cc
+ sanitizer_bitvector_test.cc
+ sanitizer_bvgraph_test.cc
sanitizer_common_test.cc
+ sanitizer_deadlock_detector_test.cc
sanitizer_flags_test.cc
+ sanitizer_format_interceptor_test.cc
sanitizer_ioctl_test.cc
sanitizer_libc_test.cc
sanitizer_linux_test.cc
@@ -13,8 +19,9 @@ set(SANITIZER_UNITTESTS
sanitizer_nolibc_test.cc
sanitizer_posix_test.cc
sanitizer_printf_test.cc
- sanitizer_scanf_interceptor_test.cc
+ sanitizer_procmaps_test.cc
sanitizer_stackdepot_test.cc
+ sanitizer_stacktrace_printer_test.cc
sanitizer_stacktrace_test.cc
sanitizer_stoptheworld_test.cc
sanitizer_suppressions_test.cc
@@ -22,22 +29,47 @@ set(SANITIZER_UNITTESTS
sanitizer_thread_registry_test.cc)
set(SANITIZER_TEST_HEADERS
+ sanitizer_pthread_wrappers.h
+ sanitizer_test_config.h
sanitizer_test_utils.h)
foreach(header ${SANITIZER_HEADERS})
list(APPEND SANITIZER_TEST_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/../${header})
endforeach()
set(SANITIZER_TEST_CFLAGS_COMMON
- ${COMPILER_RT_GTEST_INCLUDE_CFLAGS}
+ ${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/sanitizer_common
- -DGTEST_HAS_RTTI=0
- -O2 -g -fno-rtti
- -Wall -Werror -Werror=sign-compare)
+ -fno-rtti
+ -O2
+ -Werror=sign-compare
+ -Wno-non-virtual-dtor)
+
+# -gline-tables-only must be enough for these tests, so use it if possible.
+if(COMPILER_RT_TEST_COMPILER_ID MATCHES "Clang")
+ list(APPEND ASAN_UNITTEST_COMMON_CFLAGS -gline-tables-only)
+else()
+ list(APPEND ASAN_UNITTEST_COMMON_CFLAGS -g)
+endif()
+
+if(NOT MSVC)
+ list(APPEND SANITIZER_TEST_LINK_FLAGS_COMMON --driver-mode=g++)
+endif()
+
+set(SANITIZER_TEST_LINK_LIBS)
+append_list_if(ANDROID log SANITIZER_TEST_LINK_LIBS)
+# NDK r10 requires -latomic almost always.
+append_list_if(ANDROID atomic SANITIZER_TEST_LINK_LIBS)
-set(SANITIZER_TEST_LINK_FLAGS_COMMON
- -lstdc++ -ldl)
+append_list_if(COMPILER_RT_HAS_LIBDL -ldl SANITIZER_TEST_LINK_FLAGS_COMMON)
+append_list_if(COMPILER_RT_HAS_LIBPTHREAD -pthread SANITIZER_TEST_LINK_FLAGS_COMMON)
+# x86_64 FreeBSD 9.2 additionally requires libc++ to build the tests. Also,
+# 'libm' shall be specified explicitly to build i386 tests.
+if(CMAKE_SYSTEM MATCHES "FreeBSD-9.2-RELEASE")
+ list(APPEND SANITIZER_TEST_LINK_FLAGS_COMMON "-lc++ -lm")
+endif()
include_directories(..)
include_directories(../..)
@@ -57,7 +89,11 @@ function(get_sanitizer_common_lib_for_arch arch lib lib_name)
set(tgt_name "RTSanitizerCommon.test.${arch}")
endif()
set(${lib} "${tgt_name}" PARENT_SCOPE)
- set(${lib_name} "lib${tgt_name}.a" PARENT_SCOPE)
+ if(NOT MSVC)
+ set(${lib_name} "lib${tgt_name}.a" PARENT_SCOPE)
+ else()
+ set(${lib_name} "${tgt_name}.lib" PARENT_SCOPE)
+ endif()
endfunction()
# Sanitizer_common unit tests testsuite.
@@ -70,14 +106,17 @@ macro(add_sanitizer_tests_for_arch arch)
get_target_flags_for_arch(${arch} TARGET_FLAGS)
set(SANITIZER_TEST_SOURCES ${SANITIZER_UNITTESTS}
${COMPILER_RT_GTEST_SOURCE})
+ set(SANITIZER_TEST_COMPILE_DEPS ${SANITIZER_TEST_HEADERS})
+ if(NOT COMPILER_RT_STANDALONE_BUILD)
+ list(APPEND SANITIZER_TEST_COMPILE_DEPS gtest)
+ endif()
set(SANITIZER_TEST_OBJECTS)
foreach(source ${SANITIZER_TEST_SOURCES})
get_filename_component(basename ${source} NAME)
set(output_obj "${basename}.${arch}.o")
clang_compile(${output_obj} ${source}
CFLAGS ${SANITIZER_TEST_CFLAGS_COMMON} ${TARGET_FLAGS}
- DEPS gtest ${SANITIZER_RUNTIME_LIBRARIES}
- ${SANITIZER_TEST_HEADERS})
+ DEPS ${SANITIZER_TEST_COMPILE_DEPS})
list(APPEND SANITIZER_TEST_OBJECTS ${output_obj})
endforeach()
get_sanitizer_common_lib_for_arch(${arch} SANITIZER_COMMON_LIB
@@ -89,7 +128,7 @@ macro(add_sanitizer_tests_for_arch arch)
${SANITIZER_COMMON_LIB_NAME}
DEPS ${SANITIZER_TEST_OBJECTS} ${SANITIZER_COMMON_LIB}
LINK_FLAGS ${SANITIZER_TEST_LINK_FLAGS_COMMON}
- -lpthread ${TARGET_FLAGS})
+ ${TARGET_FLAGS})
if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux" AND "${arch}" STREQUAL "x86_64")
# Test that the libc-independent part of sanitizer_common is indeed
@@ -98,7 +137,7 @@ macro(add_sanitizer_tests_for_arch arch)
clang_compile(sanitizer_nolibc_test_main.${arch}.o
sanitizer_nolibc_test_main.cc
CFLAGS ${SANITIZER_TEST_CFLAGS_COMMON} ${TARGET_FLAGS}
- DEPS ${SANITIZER_RUNTIME_LIBRARIES} ${SANITIZER_TEST_HEADERS})
+ DEPS ${SANITIZER_TEST_COMPILE_DEPS})
add_compiler_rt_test(SanitizerUnitTests "Sanitizer-${arch}-Test-Nolibc"
OBJECTS sanitizer_nolibc_test_main.${arch}.o
-Wl,-whole-archive
@@ -110,7 +149,7 @@ macro(add_sanitizer_tests_for_arch arch)
endif()
endmacro()
-if(COMPILER_RT_CAN_EXECUTE_TESTS)
+if(COMPILER_RT_CAN_EXECUTE_TESTS AND NOT ANDROID)
# We use just-built clang to build sanitizer_common unittests, so we must
# be sure that produced binaries would work.
if(APPLE)
@@ -136,34 +175,24 @@ if(COMPILER_RT_CAN_EXECUTE_TESTS)
if(CAN_TARGET_i386)
add_sanitizer_tests_for_arch(i386)
endif()
-
- # Run unittests as a part of lit testsuite.
- configure_lit_site_cfg(
- ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
- ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg
- )
-
- add_lit_testsuite(check-sanitizer "Running sanitizer library unittests"
- ${CMAKE_CURRENT_BINARY_DIR}
- DEPENDS SanitizerUnitTests
- )
- set_target_properties(check-sanitizer PROPERTIES FOLDER "Sanitizer unittests")
endif()
if(ANDROID)
- # We assume that unit tests on Android are built in a build
- # tree with fresh Clang as a host compiler.
- add_executable(SanitizerTest
- ${SANITIZER_UNITTESTS}
- ${COMPILER_RT_GTEST_SOURCE}
- $<TARGET_OBJECTS:RTSanitizerCommon.arm.android>)
- set_target_compile_flags(SanitizerTest
- ${SANITIZER_COMMON_CFLAGS}
- ${SANITIZER_TEST_CFLAGS_COMMON})
- # Setup correct output directory and link flags.
- set_target_properties(SanitizerTest PROPERTIES
- RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
- set_target_link_flags(SanitizerTest ${SANITIZER_TEST_LINK_FLAGS_COMMON})
- # Add unit test to test suite.
- add_dependencies(SanitizerUnitTests SanitizerTest)
+ foreach(arch ${SANITIZER_COMMON_SUPPORTED_ARCH})
+ add_executable(SanitizerTest
+ ${SANITIZER_UNITTESTS}
+ ${COMPILER_RT_GTEST_SOURCE}
+ $<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
+ $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>)
+ set_target_compile_flags(SanitizerTest
+ ${SANITIZER_COMMON_CFLAGS}
+ ${SANITIZER_TEST_CFLAGS_COMMON})
+ # Setup correct output directory and link flags.
+ set_target_properties(SanitizerTest PROPERTIES
+ RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
+ set_target_link_flags(SanitizerTest ${SANITIZER_TEST_LINK_FLAGS_COMMON})
+ target_link_libraries(SanitizerTest ${SANITIZER_TEST_LINK_LIBS})
+ # Add unit test to test suite.
+ add_dependencies(SanitizerUnitTests SanitizerTest)
+ endforeach()
endif()
diff --git a/lib/sanitizer_common/tests/lit.site.cfg.in b/lib/sanitizer_common/tests/lit.site.cfg.in
deleted file mode 100644
index 5ceb9e4c5c28..000000000000
--- a/lib/sanitizer_common/tests/lit.site.cfg.in
+++ /dev/null
@@ -1,14 +0,0 @@
-## Autogenerated by LLVM/Clang configuration.
-# Do not edit!
-
-# Load common config for all compiler-rt unit tests.
-lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/lib/lit.common.unit.configured")
-
-# Setup config name.
-config.name = 'SanitizerCommon-Unit'
-
-# Setup test source and exec root. For unit tests, we define
-# it as build directory with sanitizer_common tests.
-config.test_exec_root = os.path.join("@COMPILER_RT_BINARY_DIR@", "lib",
- "sanitizer_common", "tests")
-config.test_source_root = config.test_exec_root
diff --git a/lib/sanitizer_common/tests/sanitizer_allocator_test.cc b/lib/sanitizer_common/tests/sanitizer_allocator_test.cc
index d92a07fe4c2d..f61d58dea7d9 100644
--- a/lib/sanitizer_common/tests/sanitizer_allocator_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_allocator_test.cc
@@ -17,11 +17,11 @@
#include "sanitizer_common/sanitizer_flags.h"
#include "sanitizer_test_utils.h"
+#include "sanitizer_pthread_wrappers.h"
#include "gtest/gtest.h"
#include <stdlib.h>
-#include <pthread.h>
#include <algorithm>
#include <vector>
#include <set>
@@ -328,6 +328,7 @@ TEST(SanitizerCommon, SizeClassAllocator64Overflow) {
}
#endif
+#if !defined(_WIN32) // FIXME: This currently fails on Windows.
TEST(SanitizerCommon, LargeMmapAllocator) {
LargeMmapAllocator<> a;
a.Init();
@@ -403,6 +404,7 @@ TEST(SanitizerCommon, LargeMmapAllocator) {
CHECK_NE(p, (char *)a.GetBlockBegin(p + page_size));
a.Deallocate(&stats, p);
}
+#endif
template
<class PrimaryAllocator, class SecondaryAllocator, class AllocatorCache>
@@ -477,11 +479,13 @@ TEST(SanitizerCommon, CombinedAllocator64Compact) {
}
#endif
+#if !defined(_WIN32) // FIXME: This currently fails on Windows.
TEST(SanitizerCommon, CombinedAllocator32Compact) {
TestCombinedAllocator<Allocator32Compact,
LargeMmapAllocator<>,
SizeClassAllocatorLocalCache<Allocator32Compact> > ();
}
+#endif
template <class AllocatorCache>
void TestSizeClassAllocatorLocalCache() {
@@ -553,8 +557,8 @@ TEST(SanitizerCommon, AllocatorLeakTest) {
uptr total_used_memory = 0;
for (int i = 0; i < 100; i++) {
pthread_t t;
- EXPECT_EQ(0, pthread_create(&t, 0, AllocatorLeakTestWorker, &a));
- EXPECT_EQ(0, pthread_join(t, 0));
+ PTHREAD_CREATE(&t, 0, AllocatorLeakTestWorker, &a);
+ PTHREAD_JOIN(t, 0);
if (i == 0)
total_used_memory = a.TotalMemoryUsed();
EXPECT_EQ(a.TotalMemoryUsed(), total_used_memory);
@@ -595,8 +599,8 @@ TEST(Allocator, AllocatorCacheDeallocNewThread) {
params->allocator = &allocator;
params->class_id = class_id;
pthread_t t;
- EXPECT_EQ(0, pthread_create(&t, 0, DeallocNewThreadWorker, params));
- EXPECT_EQ(0, pthread_join(t, 0));
+ PTHREAD_CREATE(&t, 0, DeallocNewThreadWorker, params);
+ PTHREAD_JOIN(t, 0);
}
#endif
@@ -625,9 +629,9 @@ TEST(Allocator, Stress) {
}
}
-TEST(Allocator, InternalAllocFailure) {
- EXPECT_DEATH(Ident(InternalAlloc(10 << 20)),
- "Unexpected mmap in InternalAllocator!");
+TEST(Allocator, LargeAlloc) {
+ void *p = InternalAlloc(10 << 20);
+ InternalFree(p);
}
TEST(Allocator, ScopedBuffer) {
@@ -794,4 +798,65 @@ TEST(SanitizerCommon, SizeClassAllocator64PopulateFreeListOOM) {
}
#endif
+TEST(SanitizerCommon, TwoLevelByteMap) {
+ const u64 kSize1 = 1 << 6, kSize2 = 1 << 12;
+ const u64 n = kSize1 * kSize2;
+ TwoLevelByteMap<kSize1, kSize2> m;
+ m.TestOnlyInit();
+ for (u64 i = 0; i < n; i += 7) {
+ m.set(i, (i % 100) + 1);
+ }
+ for (u64 j = 0; j < n; j++) {
+ if (j % 7)
+ EXPECT_EQ(m[j], 0);
+ else
+ EXPECT_EQ(m[j], (j % 100) + 1);
+ }
+
+ m.TestOnlyUnmap();
+}
+
+
+typedef TwoLevelByteMap<1 << 12, 1 << 13, TestMapUnmapCallback> TestByteMap;
+
+struct TestByteMapParam {
+ TestByteMap *m;
+ size_t shard;
+ size_t num_shards;
+};
+
+void *TwoLevelByteMapUserThread(void *param) {
+ TestByteMapParam *p = (TestByteMapParam*)param;
+ for (size_t i = p->shard; i < p->m->size(); i += p->num_shards) {
+ size_t val = (i % 100) + 1;
+ p->m->set(i, val);
+ EXPECT_EQ((*p->m)[i], val);
+ }
+ return 0;
+}
+
+TEST(SanitizerCommon, ThreadedTwoLevelByteMap) {
+ TestByteMap m;
+ m.TestOnlyInit();
+ TestMapUnmapCallback::map_count = 0;
+ TestMapUnmapCallback::unmap_count = 0;
+ static const int kNumThreads = 4;
+ pthread_t t[kNumThreads];
+ TestByteMapParam p[kNumThreads];
+ for (int i = 0; i < kNumThreads; i++) {
+ p[i].m = &m;
+ p[i].shard = i;
+ p[i].num_shards = kNumThreads;
+ PTHREAD_CREATE(&t[i], 0, TwoLevelByteMapUserThread, &p[i]);
+ }
+ for (int i = 0; i < kNumThreads; i++) {
+ PTHREAD_JOIN(t[i], 0);
+ }
+ EXPECT_EQ((uptr)TestMapUnmapCallback::map_count, m.size1());
+ EXPECT_EQ((uptr)TestMapUnmapCallback::unmap_count, 0UL);
+ m.TestOnlyUnmap();
+ EXPECT_EQ((uptr)TestMapUnmapCallback::map_count, m.size1());
+ EXPECT_EQ((uptr)TestMapUnmapCallback::unmap_count, m.size1());
+}
+
#endif // #if TSAN_DEBUG==0
diff --git a/lib/sanitizer_common/tests/sanitizer_allocator_testlib.cc b/lib/sanitizer_common/tests/sanitizer_allocator_testlib.cc
index f6a944f68f5e..0cc3b9ba6944 100644
--- a/lib/sanitizer_common/tests/sanitizer_allocator_testlib.cc
+++ b/lib/sanitizer_common/tests/sanitizer_allocator_testlib.cc
@@ -156,7 +156,7 @@ void *operator new(size_t size) ALIAS("malloc");
void *operator new[](size_t size) ALIAS("malloc");
void *operator new(size_t size, std::nothrow_t const&) ALIAS("malloc");
void *operator new[](size_t size, std::nothrow_t const&) ALIAS("malloc");
-void operator delete(void *ptr) ALIAS("free");
-void operator delete[](void *ptr) ALIAS("free");
+void operator delete(void *ptr) throw() ALIAS("free");
+void operator delete[](void *ptr) throw() ALIAS("free");
void operator delete(void *ptr, std::nothrow_t const&) ALIAS("free");
void operator delete[](void *ptr, std::nothrow_t const&) ALIAS("free");
diff --git a/lib/sanitizer_common/tests/sanitizer_atomic_test.cc b/lib/sanitizer_common/tests/sanitizer_atomic_test.cc
index a4a97c43e00f..56bcd35c826c 100644
--- a/lib/sanitizer_common/tests/sanitizer_atomic_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_atomic_test.cc
@@ -15,6 +15,79 @@
namespace __sanitizer {
+template<typename T>
+struct ValAndMagic {
+ typename T::Type magic0;
+ T a;
+ typename T::Type magic1;
+
+ static ValAndMagic<T> *sink;
+};
+
+template<typename T>
+ValAndMagic<T> *ValAndMagic<T>::sink;
+
+template<typename T, memory_order load_mo, memory_order store_mo>
+void CheckStoreLoad() {
+ typedef typename T::Type Type;
+ ValAndMagic<T> val;
+ // Prevent the compiler from scalarizing the struct.
+ ValAndMagic<T>::sink = &val;
+ // Ensure that surrounding memory is not overwritten.
+ val.magic0 = val.magic1 = (Type)-3;
+ for (u64 i = 0; i < 100; i++) {
+ // Generate a value that occupies all bytes of the variable.
+ u64 v = i;
+ v |= v << 8;
+ v |= v << 16;
+ v |= v << 32;
+ val.a.val_dont_use = (Type)v;
+ EXPECT_EQ(atomic_load(&val.a, load_mo), (Type)v);
+ val.a.val_dont_use = (Type)-1;
+ atomic_store(&val.a, (Type)v, store_mo);
+ EXPECT_EQ(val.a.val_dont_use, (Type)v);
+ }
+ EXPECT_EQ(val.magic0, (Type)-3);
+ EXPECT_EQ(val.magic1, (Type)-3);
+}
+
+TEST(SanitizerCommon, AtomicStoreLoad) {
+ CheckStoreLoad<atomic_uint8_t, memory_order_relaxed, memory_order_relaxed>();
+ CheckStoreLoad<atomic_uint8_t, memory_order_consume, memory_order_relaxed>();
+ CheckStoreLoad<atomic_uint8_t, memory_order_acquire, memory_order_relaxed>();
+ CheckStoreLoad<atomic_uint8_t, memory_order_relaxed, memory_order_release>();
+ CheckStoreLoad<atomic_uint8_t, memory_order_seq_cst, memory_order_seq_cst>();
+
+ CheckStoreLoad<atomic_uint16_t, memory_order_relaxed, memory_order_relaxed>();
+ CheckStoreLoad<atomic_uint16_t, memory_order_consume, memory_order_relaxed>();
+ CheckStoreLoad<atomic_uint16_t, memory_order_acquire, memory_order_relaxed>();
+ CheckStoreLoad<atomic_uint16_t, memory_order_relaxed, memory_order_release>();
+ CheckStoreLoad<atomic_uint16_t, memory_order_seq_cst, memory_order_seq_cst>();
+
+ CheckStoreLoad<atomic_uint32_t, memory_order_relaxed, memory_order_relaxed>();
+ CheckStoreLoad<atomic_uint32_t, memory_order_consume, memory_order_relaxed>();
+ CheckStoreLoad<atomic_uint32_t, memory_order_acquire, memory_order_relaxed>();
+ CheckStoreLoad<atomic_uint32_t, memory_order_relaxed, memory_order_release>();
+ CheckStoreLoad<atomic_uint32_t, memory_order_seq_cst, memory_order_seq_cst>();
+
+ CheckStoreLoad<atomic_uint64_t, memory_order_relaxed, memory_order_relaxed>();
+ CheckStoreLoad<atomic_uint64_t, memory_order_consume, memory_order_relaxed>();
+ CheckStoreLoad<atomic_uint64_t, memory_order_acquire, memory_order_relaxed>();
+ CheckStoreLoad<atomic_uint64_t, memory_order_relaxed, memory_order_release>();
+ CheckStoreLoad<atomic_uint64_t, memory_order_seq_cst, memory_order_seq_cst>();
+
+ CheckStoreLoad<atomic_uintptr_t, memory_order_relaxed, memory_order_relaxed>
+ ();
+ CheckStoreLoad<atomic_uintptr_t, memory_order_consume, memory_order_relaxed>
+ ();
+ CheckStoreLoad<atomic_uintptr_t, memory_order_acquire, memory_order_relaxed>
+ ();
+ CheckStoreLoad<atomic_uintptr_t, memory_order_relaxed, memory_order_release>
+ ();
+ CheckStoreLoad<atomic_uintptr_t, memory_order_seq_cst, memory_order_seq_cst>
+ ();
+}
+
// Clang crashes while compiling this test for Android:
// http://llvm.org/bugs/show_bug.cgi?id=15587
#if !SANITIZER_ANDROID
diff --git a/lib/sanitizer_common/tests/sanitizer_bitvector_test.cc b/lib/sanitizer_common/tests/sanitizer_bitvector_test.cc
new file mode 100644
index 000000000000..706b4c58968e
--- /dev/null
+++ b/lib/sanitizer_common/tests/sanitizer_bitvector_test.cc
@@ -0,0 +1,176 @@
+//===-- sanitizer_bitvector_test.cc ---------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of Sanitizer runtime.
+// Tests for sanitizer_bitvector.h.
+//
+//===----------------------------------------------------------------------===//
+#include "sanitizer_common/sanitizer_bitvector.h"
+
+#include "sanitizer_test_utils.h"
+
+#include "gtest/gtest.h"
+
+#include <algorithm>
+#include <vector>
+#include <set>
+
+using namespace __sanitizer;
+using namespace std;
+
+
+// Check the 'bv' == 's' and that the indexes go in increasing order.
+// Also check the BV::Iterator
+template <class BV>
+static void CheckBV(const BV &bv, const set<uptr> &s) {
+ BV t;
+ t.copyFrom(bv);
+ set<uptr> t_s(s);
+ uptr last_idx = bv.size();
+ uptr count = 0;
+ for (typename BV::Iterator it(bv); it.hasNext();) {
+ uptr idx = it.next();
+ count++;
+ if (last_idx != bv.size())
+ EXPECT_LT(last_idx, idx);
+ last_idx = idx;
+ EXPECT_TRUE(s.count(idx));
+ }
+ EXPECT_EQ(count, s.size());
+
+ last_idx = bv.size();
+ while (!t.empty()) {
+ uptr idx = t.getAndClearFirstOne();
+ if (last_idx != bv.size())
+ EXPECT_LT(last_idx, idx);
+ last_idx = idx;
+ EXPECT_TRUE(t_s.erase(idx));
+ }
+ EXPECT_TRUE(t_s.empty());
+}
+
+template <class BV>
+void Print(const BV &bv) {
+ BV t;
+ t.copyFrom(bv);
+ while (!t.empty()) {
+ uptr idx = t.getAndClearFirstOne();
+ fprintf(stderr, "%zd ", idx);
+ }
+ fprintf(stderr, "\n");
+}
+
+void Print(const set<uptr> &s) {
+ for (set<uptr>::iterator it = s.begin(); it != s.end(); ++it) {
+ fprintf(stderr, "%zd ", *it);
+ }
+ fprintf(stderr, "\n");
+}
+
+template <class BV>
+void TestBitVector(uptr expected_size) {
+ BV bv, bv1, t_bv;
+ EXPECT_EQ(expected_size, BV::kSize);
+ bv.clear();
+ EXPECT_TRUE(bv.empty());
+ bv.setBit(5);
+ EXPECT_FALSE(bv.empty());
+ EXPECT_FALSE(bv.getBit(4));
+ EXPECT_FALSE(bv.getBit(6));
+ EXPECT_TRUE(bv.getBit(5));
+ bv.clearBit(5);
+ EXPECT_FALSE(bv.getBit(5));
+
+ // test random bits
+ bv.clear();
+ set<uptr> s;
+ for (uptr it = 0; it < 1000; it++) {
+ uptr bit = ((uptr)my_rand() % bv.size());
+ EXPECT_EQ(bv.getBit(bit), s.count(bit) == 1);
+ switch (my_rand() % 2) {
+ case 0:
+ EXPECT_EQ(bv.setBit(bit), s.insert(bit).second);
+ break;
+ case 1:
+ size_t old_size = s.size();
+ s.erase(bit);
+ EXPECT_EQ(bv.clearBit(bit), old_size > s.size());
+ break;
+ }
+ EXPECT_EQ(bv.getBit(bit), s.count(bit) == 1);
+ }
+
+ vector<uptr>bits(bv.size());
+ // Test setUnion, setIntersection, setDifference,
+ // intersectsWith, and getAndClearFirstOne.
+ for (uptr it = 0; it < 30; it++) {
+ // iota
+ for (size_t j = 0; j < bits.size(); j++) bits[j] = j;
+ random_shuffle(bits.begin(), bits.end());
+ set<uptr> s, s1, t_s;
+ bv.clear();
+ bv1.clear();
+ uptr n_bits = ((uptr)my_rand() % bv.size()) + 1;
+ uptr n_bits1 = (uptr)my_rand() % (bv.size() / 2);
+ EXPECT_TRUE(n_bits > 0 && n_bits <= bv.size());
+ EXPECT_TRUE(n_bits1 < bv.size() / 2);
+ for (uptr i = 0; i < n_bits; i++) {
+ bv.setBit(bits[i]);
+ s.insert(bits[i]);
+ }
+ CheckBV(bv, s);
+ for (uptr i = 0; i < n_bits1; i++) {
+ bv1.setBit(bits[bv.size() / 2 + i]);
+ s1.insert(bits[bv.size() / 2 + i]);
+ }
+ CheckBV(bv1, s1);
+
+ vector<uptr> vec;
+ set_intersection(s.begin(), s.end(), s1.begin(), s1.end(),
+ back_insert_iterator<vector<uptr> >(vec));
+ EXPECT_EQ(bv.intersectsWith(bv1), !vec.empty());
+
+ // setUnion
+ t_s = s;
+ t_bv.copyFrom(bv);
+ t_s.insert(s1.begin(), s1.end());
+ EXPECT_EQ(t_bv.setUnion(bv1), s.size() != t_s.size());
+ CheckBV(t_bv, t_s);
+
+ // setIntersection
+ t_s = set<uptr>(vec.begin(), vec.end());
+ t_bv.copyFrom(bv);
+ EXPECT_EQ(t_bv.setIntersection(bv1), s.size() != t_s.size());
+ CheckBV(t_bv, t_s);
+
+ // setDifference
+ vec.clear();
+ set_difference(s.begin(), s.end(), s1.begin(), s1.end(),
+ back_insert_iterator<vector<uptr> >(vec));
+ t_s = set<uptr>(vec.begin(), vec.end());
+ t_bv.copyFrom(bv);
+ EXPECT_EQ(t_bv.setDifference(bv1), s.size() != t_s.size());
+ CheckBV(t_bv, t_s);
+ }
+}
+
+TEST(SanitizerCommon, BasicBitVector) {
+ TestBitVector<BasicBitVector<u8> >(8);
+ TestBitVector<BasicBitVector<u16> >(16);
+ TestBitVector<BasicBitVector<> >(SANITIZER_WORDSIZE);
+}
+
+TEST(SanitizerCommon, TwoLevelBitVector) {
+ uptr ws = SANITIZER_WORDSIZE;
+ TestBitVector<TwoLevelBitVector<1, BasicBitVector<u8> > >(8 * 8);
+ TestBitVector<TwoLevelBitVector<> >(ws * ws);
+ TestBitVector<TwoLevelBitVector<2> >(ws * ws * 2);
+ TestBitVector<TwoLevelBitVector<3> >(ws * ws * 3);
+ TestBitVector<TwoLevelBitVector<3, BasicBitVector<u16> > >(16 * 16 * 3);
+}
diff --git a/lib/sanitizer_common/tests/sanitizer_bvgraph_test.cc b/lib/sanitizer_common/tests/sanitizer_bvgraph_test.cc
new file mode 100644
index 000000000000..3b39f8dd734a
--- /dev/null
+++ b/lib/sanitizer_common/tests/sanitizer_bvgraph_test.cc
@@ -0,0 +1,339 @@
+//===-- sanitizer_bvgraph_test.cc -----------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of Sanitizer runtime.
+// Tests for sanitizer_bvgraph.h.
+//
+//===----------------------------------------------------------------------===//
+#include "sanitizer_common/sanitizer_bvgraph.h"
+
+#include "sanitizer_test_utils.h"
+
+#include "gtest/gtest.h"
+
+#include <algorithm>
+#include <vector>
+#include <set>
+
+using namespace __sanitizer;
+using namespace std;
+
+typedef BasicBitVector<u8> BV1;
+typedef BasicBitVector<> BV2;
+typedef TwoLevelBitVector<> BV3;
+typedef TwoLevelBitVector<3, BasicBitVector<u8> > BV4;
+
+template<class G>
+void PrintGraph(const G &g) {
+ for (uptr i = 0; i < g.size(); i++) {
+ for (uptr j = 0; j < g.size(); j++) {
+ fprintf(stderr, "%d", g.hasEdge(i, j));
+ }
+ fprintf(stderr, "\n");
+ }
+}
+
+
+class SimpleGraph {
+ public:
+ void clear() { s_.clear(); }
+ bool addEdge(uptr from, uptr to) {
+ return s_.insert(idx(from, to)).second;
+ }
+ bool removeEdge(uptr from, uptr to) {
+ return s_.erase(idx(from, to));
+ }
+ template <class G>
+ void checkSameAs(G *g) {
+ for (set<uptr>::iterator it = s_.begin(); it != s_.end(); ++it) {
+ uptr from = *it >> 16;
+ uptr to = *it & ((1 << 16) - 1);
+ EXPECT_TRUE(g->removeEdge(from, to));
+ }
+ EXPECT_TRUE(g->empty());
+ }
+ private:
+ uptr idx(uptr from, uptr to) {
+ CHECK_LE(from|to, 1 << 16);
+ return (from << 16) + to;
+ }
+ set<uptr> s_;
+};
+
+template <class BV>
+void BasicTest() {
+ BVGraph<BV> g;
+ g.clear();
+ BV target;
+ SimpleGraph s_g;
+ set<uptr> s;
+ set<uptr> s_target;
+ int num_reachable = 0;
+ for (int it = 0; it < 1000; it++) {
+ target.clear();
+ s_target.clear();
+ for (int t = 0; t < 4; t++) {
+ uptr idx = (uptr)my_rand() % g.size();
+ EXPECT_EQ(target.setBit(idx), s_target.insert(idx).second);
+ }
+ uptr from = my_rand() % g.size();
+ uptr to = my_rand() % g.size();
+ EXPECT_EQ(g.addEdge(from, to), s_g.addEdge(from, to));
+ EXPECT_TRUE(g.hasEdge(from, to));
+ for (int i = 0; i < 10; i++) {
+ from = my_rand() % g.size();
+ bool is_reachable = g.isReachable(from, target);
+ if (is_reachable) {
+ uptr path[BV::kSize];
+ uptr len;
+ for (len = 1; len < BV::kSize; len++) {
+ if (g.findPath(from, target, path, len) == len)
+ break;
+ }
+ EXPECT_LT(len, BV::kSize);
+ EXPECT_TRUE(target.getBit(path[len - 1]));
+ // fprintf(stderr, "reachable: %zd; path %zd {%zd %zd %zd}\n",
+ // from, len, path[0], path[1], path[2]);
+ num_reachable++;
+ }
+ }
+ }
+ EXPECT_GT(num_reachable, 0);
+}
+
+TEST(BVGraph, BasicTest) {
+ BasicTest<BV1>();
+ BasicTest<BV2>();
+ BasicTest<BV3>();
+ BasicTest<BV4>();
+}
+
+template <class BV>
+void RemoveEdges() {
+ SimpleGraph s_g;
+ BVGraph<BV> g;
+ g.clear();
+ BV bv;
+ set<uptr> s;
+ for (int it = 0; it < 100; it++) {
+ s.clear();
+ bv.clear();
+ s_g.clear();
+ g.clear();
+ for (uptr j = 0; j < g.size() * 2; j++) {
+ uptr from = my_rand() % g.size();
+ uptr to = my_rand() % g.size();
+ EXPECT_EQ(g.addEdge(from, to), s_g.addEdge(from, to));
+ }
+ for (uptr j = 0; j < 5; j++) {
+ uptr idx = my_rand() % g.size();
+ s.insert(idx);
+ bv.setBit(idx);
+ }
+
+ if (it % 2) {
+ g.removeEdgesFrom(bv);
+ for (set<uptr>::iterator from = s.begin(); from != s.end(); ++from) {
+ for (uptr to = 0; to < g.size(); to++)
+ s_g.removeEdge(*from, to);
+ }
+ } else {
+ g.removeEdgesTo(bv);
+ for (set<uptr>::iterator to = s.begin(); to != s.end(); ++to) {
+ for (uptr from = 0; from < g.size(); from++)
+ s_g.removeEdge(from, *to);
+ }
+ }
+ s_g.checkSameAs(&g);
+ }
+}
+
+TEST(BVGraph, RemoveEdges) {
+ RemoveEdges<BV1>();
+ RemoveEdges<BV2>();
+ RemoveEdges<BV3>();
+ RemoveEdges<BV4>();
+}
+
+template <class BV>
+void Test_isReachable() {
+ uptr path[5];
+ BVGraph<BV> g;
+ g.clear();
+ BV target;
+ target.clear();
+ uptr t0 = 0;
+ uptr t1 = g.size() - 1;
+ target.setBit(t0);
+ target.setBit(t1);
+
+ uptr f0 = 1;
+ uptr f1 = 2;
+ uptr f2 = g.size() / 2;
+ uptr f3 = g.size() - 2;
+
+ EXPECT_FALSE(g.isReachable(f0, target));
+ EXPECT_FALSE(g.isReachable(f1, target));
+ EXPECT_FALSE(g.isReachable(f2, target));
+ EXPECT_FALSE(g.isReachable(f3, target));
+
+ g.addEdge(f0, f1);
+ g.addEdge(f1, f2);
+ g.addEdge(f2, f3);
+ EXPECT_FALSE(g.isReachable(f0, target));
+ EXPECT_FALSE(g.isReachable(f1, target));
+ EXPECT_FALSE(g.isReachable(f2, target));
+ EXPECT_FALSE(g.isReachable(f3, target));
+
+ g.addEdge(f1, t0);
+ EXPECT_TRUE(g.isReachable(f0, target));
+ EXPECT_TRUE(g.isReachable(f1, target));
+ EXPECT_FALSE(g.isReachable(f2, target));
+ EXPECT_FALSE(g.isReachable(f3, target));
+ EXPECT_EQ(g.findPath(f0, target, path, ARRAY_SIZE(path)), 3U);
+ EXPECT_EQ(path[0], f0);
+ EXPECT_EQ(path[1], f1);
+ EXPECT_EQ(path[2], t0);
+ EXPECT_EQ(g.findPath(f1, target, path, ARRAY_SIZE(path)), 2U);
+ EXPECT_EQ(path[0], f1);
+ EXPECT_EQ(path[1], t0);
+
+ g.addEdge(f3, t1);
+ EXPECT_TRUE(g.isReachable(f0, target));
+ EXPECT_TRUE(g.isReachable(f1, target));
+ EXPECT_TRUE(g.isReachable(f2, target));
+ EXPECT_TRUE(g.isReachable(f3, target));
+}
+
+TEST(BVGraph, isReachable) {
+ Test_isReachable<BV1>();
+ Test_isReachable<BV2>();
+ Test_isReachable<BV3>();
+ Test_isReachable<BV4>();
+}
+
+template <class BV>
+void LongCycle() {
+ BVGraph<BV> g;
+ g.clear();
+ vector<uptr> path_vec(g.size());
+ uptr *path = path_vec.data();
+ uptr start = 5;
+ for (uptr i = start; i < g.size() - 1; i++) {
+ g.addEdge(i, i + 1);
+ for (uptr j = 0; j < start; j++)
+ g.addEdge(i, j);
+ }
+ // Bad graph that looks like this:
+ // 00000000000000
+ // 00000000000000
+ // 00000000000000
+ // 00000000000000
+ // 00000000000000
+ // 11111010000000
+ // 11111001000000
+ // 11111000100000
+ // 11111000010000
+ // 11111000001000
+ // 11111000000100
+ // 11111000000010
+ // 11111000000001
+ // if (g.size() <= 64) PrintGraph(g);
+ BV target;
+ for (uptr i = start + 1; i < g.size(); i += 11) {
+ // if ((i & (i - 1)) == 0) fprintf(stderr, "Path: : %zd\n", i);
+ target.clear();
+ target.setBit(i);
+ EXPECT_TRUE(g.isReachable(start, target));
+ EXPECT_EQ(g.findPath(start, target, path, g.size()), i - start + 1);
+ }
+}
+
+TEST(BVGraph, LongCycle) {
+ LongCycle<BV1>();
+ LongCycle<BV2>();
+ LongCycle<BV3>();
+ LongCycle<BV4>();
+}
+
+template <class BV>
+void ShortestPath() {
+ uptr path[8];
+ BVGraph<BV> g;
+ g.clear();
+ BV t7;
+ t7.clear();
+ t7.setBit(7);
+ // 1=>2=>3=>4=>5=>6=>7
+ // 1=>7
+ g.addEdge(1, 2);
+ g.addEdge(2, 3);
+ g.addEdge(3, 4);
+ g.addEdge(4, 5);
+ g.addEdge(5, 6);
+ g.addEdge(6, 7);
+ g.addEdge(1, 7);
+ EXPECT_TRUE(g.isReachable(1, t7));
+ // No path of length 1.
+ EXPECT_EQ(0U, g.findPath(1, t7, path, 1));
+ // Trying to find a path of len 2..6 gives path of len 2.
+ EXPECT_EQ(2U, g.findPath(1, t7, path, 2));
+ EXPECT_EQ(2U, g.findPath(1, t7, path, 3));
+ EXPECT_EQ(2U, g.findPath(1, t7, path, 4));
+ EXPECT_EQ(2U, g.findPath(1, t7, path, 5));
+ EXPECT_EQ(2U, g.findPath(1, t7, path, 6));
+ // Trying to find a path of len 7 gives path of len 7, because this is DFS.
+ EXPECT_EQ(7U, g.findPath(1, t7, path, 7));
+ // But findShortestPath will find the shortest path.
+ EXPECT_EQ(2U, g.findShortestPath(1, t7, path, 2));
+ EXPECT_EQ(2U, g.findShortestPath(1, t7, path, 7));
+}
+
+TEST(BVGraph, ShortestPath) {
+ ShortestPath<BV1>();
+ ShortestPath<BV2>();
+ ShortestPath<BV3>();
+ ShortestPath<BV4>();
+}
+
+template <class BV>
+void RunAddEdgesTest() {
+ BVGraph<BV> g;
+ BV from;
+ const int kMaxEdges = 10;
+ uptr added_edges[kMaxEdges];
+ g.clear();
+ from.clear();
+ EXPECT_EQ(0U, g.addEdges(from, 0, added_edges, kMaxEdges));
+ EXPECT_EQ(0U, g.addEdges(from, 1, added_edges, kMaxEdges));
+ from.setBit(0);
+ EXPECT_EQ(1U, g.addEdges(from, 1, added_edges, kMaxEdges));
+ EXPECT_EQ(0U, added_edges[0]);
+ EXPECT_EQ(0U, g.addEdges(from, 1, added_edges, kMaxEdges));
+
+ from.clear();
+ from.setBit(1);
+ EXPECT_EQ(1U, g.addEdges(from, 4, added_edges, kMaxEdges));
+ EXPECT_TRUE(g.hasEdge(1, 4));
+ EXPECT_FALSE(g.hasEdge(1, 5));
+ EXPECT_EQ(1U, added_edges[0]);
+ from.setBit(2);
+ from.setBit(3);
+ EXPECT_EQ(2U, g.addEdges(from, 4, added_edges, kMaxEdges));
+ EXPECT_TRUE(g.hasEdge(2, 4));
+ EXPECT_FALSE(g.hasEdge(2, 5));
+ EXPECT_TRUE(g.hasEdge(3, 4));
+ EXPECT_FALSE(g.hasEdge(3, 5));
+ EXPECT_EQ(2U, added_edges[0]);
+ EXPECT_EQ(3U, added_edges[1]);
+}
+
+TEST(BVGraph, AddEdgesTest) {
+ RunAddEdgesTest<BV2>();
+}
diff --git a/lib/sanitizer_common/tests/sanitizer_common_test.cc b/lib/sanitizer_common/tests/sanitizer_common_test.cc
index 608f90487a7b..e08a38c82450 100644
--- a/lib/sanitizer_common/tests/sanitizer_common_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_common_test.cc
@@ -15,6 +15,9 @@
#include "sanitizer_common/sanitizer_flags.h"
#include "sanitizer_common/sanitizer_libc.h"
#include "sanitizer_common/sanitizer_platform.h"
+
+#include "sanitizer_pthread_wrappers.h"
+
#include "gtest/gtest.h"
namespace __sanitizer {
@@ -113,6 +116,9 @@ TEST(SanitizerCommon, InternalMmapVector) {
vector.pop_back();
EXPECT_EQ((uptr)i, vector.size());
}
+ InternalMmapVector<uptr> empty_vector(0);
+ CHECK_GT(empty_vector.capacity(), 0U);
+ CHECK_EQ(0U, empty_vector.size());
}
void TestThreadInfo(bool main) {
@@ -156,8 +162,8 @@ TEST(SanitizerCommon, ThreadStackTlsMain) {
TEST(SanitizerCommon, ThreadStackTlsWorker) {
InitTlsSize();
pthread_t t;
- pthread_create(&t, 0, WorkerThread, 0);
- pthread_join(t, 0);
+ PTHREAD_CREATE(&t, 0, WorkerThread, 0);
+ PTHREAD_JOIN(t, 0);
}
bool UptrLess(uptr a, uptr b) {
@@ -220,40 +226,4 @@ TEST(SanitizerCommon, InternalScopedString) {
EXPECT_STREQ("012345678", str.data());
}
-TEST(SanitizerCommon, PrintSourceLocation) {
- InternalScopedString str(128);
- PrintSourceLocation(&str, "/dir/file.cc", 10, 5);
- EXPECT_STREQ("/dir/file.cc:10:5", str.data());
-
- str.clear();
- PrintSourceLocation(&str, "/dir/file.cc", 11, 0);
- EXPECT_STREQ("/dir/file.cc:11", str.data());
-
- str.clear();
- PrintSourceLocation(&str, "/dir/file.cc", 0, 0);
- EXPECT_STREQ("/dir/file.cc", str.data());
-
- // Check that we strip file prefix if necessary.
- const char *old_strip_path_prefix = common_flags()->strip_path_prefix;
- common_flags()->strip_path_prefix = "/dir/";
- str.clear();
- PrintSourceLocation(&str, "/dir/file.cc", 10, 5);
- EXPECT_STREQ("file.cc:10:5", str.data());
- common_flags()->strip_path_prefix = old_strip_path_prefix;
-}
-
-TEST(SanitizerCommon, PrintModuleAndOffset) {
- InternalScopedString str(128);
- PrintModuleAndOffset(&str, "/dir/exe", 0x123);
- EXPECT_STREQ("(/dir/exe+0x123)", str.data());
-
- // Check that we strip file prefix if necessary.
- const char *old_strip_path_prefix = common_flags()->strip_path_prefix;
- common_flags()->strip_path_prefix = "/dir/";
- str.clear();
- PrintModuleAndOffset(&str, "/dir/exe", 0x123);
- EXPECT_STREQ("(exe+0x123)", str.data());
- common_flags()->strip_path_prefix = old_strip_path_prefix;
-}
-
} // namespace __sanitizer
diff --git a/lib/sanitizer_common/tests/sanitizer_deadlock_detector_test.cc b/lib/sanitizer_common/tests/sanitizer_deadlock_detector_test.cc
new file mode 100644
index 000000000000..8c8363353507
--- /dev/null
+++ b/lib/sanitizer_common/tests/sanitizer_deadlock_detector_test.cc
@@ -0,0 +1,496 @@
+//===-- sanitizer_deadlock_detector_test.cc -------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of Sanitizer runtime.
+// Tests for sanitizer_deadlock_detector.h
+//
+//===----------------------------------------------------------------------===//
+#include "sanitizer_common/sanitizer_deadlock_detector.h"
+
+#include "sanitizer_test_utils.h"
+
+#include "gtest/gtest.h"
+
+#include <algorithm>
+#include <vector>
+#include <set>
+
+using namespace __sanitizer;
+using namespace std;
+
+typedef BasicBitVector<u8> BV1;
+typedef BasicBitVector<> BV2;
+typedef TwoLevelBitVector<> BV3;
+typedef TwoLevelBitVector<3, BasicBitVector<u8> > BV4;
+
+// Poor man's unique_ptr.
+template<class BV>
+struct ScopedDD {
+ ScopedDD() {
+ dp = new DeadlockDetector<BV>;
+ dp->clear();
+ dtls.clear();
+ }
+ ~ScopedDD() { delete dp; }
+ DeadlockDetector<BV> *dp;
+ DeadlockDetectorTLS<BV> dtls;
+};
+
+template <class BV>
+void RunBasicTest() {
+ uptr path[10];
+ ScopedDD<BV> sdd;
+ DeadlockDetector<BV> &d = *sdd.dp;
+ DeadlockDetectorTLS<BV> &dtls = sdd.dtls;
+ set<uptr> s;
+ for (size_t i = 0; i < d.size() * 3; i++) {
+ uptr node = d.newNode(0);
+ EXPECT_TRUE(s.insert(node).second);
+ }
+
+ d.clear();
+ s.clear();
+ // Add size() nodes.
+ for (size_t i = 0; i < d.size(); i++) {
+ uptr node = d.newNode(0);
+ EXPECT_TRUE(s.insert(node).second);
+ }
+ // Remove all nodes.
+ for (set<uptr>::iterator it = s.begin(); it != s.end(); ++it)
+ d.removeNode(*it);
+ // The nodes should be reused.
+ for (size_t i = 0; i < d.size(); i++) {
+ uptr node = d.newNode(0);
+ EXPECT_FALSE(s.insert(node).second);
+ }
+
+ // Cycle: n1->n2->n1
+ {
+ d.clear();
+ dtls.clear();
+ uptr n1 = d.newNode(1);
+ uptr n2 = d.newNode(2);
+ EXPECT_FALSE(d.onLock(&dtls, n1));
+ EXPECT_FALSE(d.onLock(&dtls, n2));
+ d.onUnlock(&dtls, n2);
+ d.onUnlock(&dtls, n1);
+
+ EXPECT_FALSE(d.onLock(&dtls, n2));
+ EXPECT_EQ(0U, d.findPathToLock(&dtls, n1, path, 1));
+ EXPECT_EQ(2U, d.findPathToLock(&dtls, n1, path, 10));
+ EXPECT_EQ(2U, d.findPathToLock(&dtls, n1, path, 2));
+ EXPECT_TRUE(d.onLock(&dtls, n1));
+ EXPECT_EQ(path[0], n1);
+ EXPECT_EQ(path[1], n2);
+ EXPECT_EQ(d.getData(n1), 1U);
+ EXPECT_EQ(d.getData(n2), 2U);
+ d.onUnlock(&dtls, n1);
+ d.onUnlock(&dtls, n2);
+ }
+
+ // Cycle: n1->n2->n3->n1
+ {
+ d.clear();
+ dtls.clear();
+ uptr n1 = d.newNode(1);
+ uptr n2 = d.newNode(2);
+ uptr n3 = d.newNode(3);
+
+ EXPECT_FALSE(d.onLock(&dtls, n1));
+ EXPECT_FALSE(d.onLock(&dtls, n2));
+ d.onUnlock(&dtls, n2);
+ d.onUnlock(&dtls, n1);
+
+ EXPECT_FALSE(d.onLock(&dtls, n2));
+ EXPECT_FALSE(d.onLock(&dtls, n3));
+ d.onUnlock(&dtls, n3);
+ d.onUnlock(&dtls, n2);
+
+ EXPECT_FALSE(d.onLock(&dtls, n3));
+ EXPECT_EQ(0U, d.findPathToLock(&dtls, n1, path, 2));
+ EXPECT_EQ(3U, d.findPathToLock(&dtls, n1, path, 10));
+ EXPECT_TRUE(d.onLock(&dtls, n1));
+ EXPECT_EQ(path[0], n1);
+ EXPECT_EQ(path[1], n2);
+ EXPECT_EQ(path[2], n3);
+ EXPECT_EQ(d.getData(n1), 1U);
+ EXPECT_EQ(d.getData(n2), 2U);
+ EXPECT_EQ(d.getData(n3), 3U);
+ d.onUnlock(&dtls, n1);
+ d.onUnlock(&dtls, n3);
+ }
+}
+
+TEST(DeadlockDetector, BasicTest) {
+ RunBasicTest<BV1>();
+ RunBasicTest<BV2>();
+ RunBasicTest<BV3>();
+ RunBasicTest<BV4>();
+}
+
+template <class BV>
+void RunRemoveNodeTest() {
+ ScopedDD<BV> sdd;
+ DeadlockDetector<BV> &d = *sdd.dp;
+ DeadlockDetectorTLS<BV> &dtls = sdd.dtls;
+
+ uptr l0 = d.newNode(0);
+ uptr l1 = d.newNode(1);
+ uptr l2 = d.newNode(2);
+ uptr l3 = d.newNode(3);
+ uptr l4 = d.newNode(4);
+ uptr l5 = d.newNode(5);
+
+ // l0=>l1=>l2
+ d.onLock(&dtls, l0);
+ d.onLock(&dtls, l1);
+ d.onLock(&dtls, l2);
+ d.onUnlock(&dtls, l1);
+ d.onUnlock(&dtls, l0);
+ d.onUnlock(&dtls, l2);
+ // l3=>l4=>l5
+ d.onLock(&dtls, l3);
+ d.onLock(&dtls, l4);
+ d.onLock(&dtls, l5);
+ d.onUnlock(&dtls, l4);
+ d.onUnlock(&dtls, l3);
+ d.onUnlock(&dtls, l5);
+
+ set<uptr> locks;
+ locks.insert(l0);
+ locks.insert(l1);
+ locks.insert(l2);
+ locks.insert(l3);
+ locks.insert(l4);
+ locks.insert(l5);
+ for (uptr i = 6; i < d.size(); i++) {
+ uptr lt = d.newNode(i);
+ locks.insert(lt);
+ d.onLock(&dtls, lt);
+ d.onUnlock(&dtls, lt);
+ d.removeNode(lt);
+ }
+ EXPECT_EQ(locks.size(), d.size());
+ // l2=>l0
+ EXPECT_FALSE(d.onLock(&dtls, l2));
+ EXPECT_TRUE(d.onLock(&dtls, l0));
+ d.onUnlock(&dtls, l2);
+ d.onUnlock(&dtls, l0);
+ // l4=>l3
+ EXPECT_FALSE(d.onLock(&dtls, l4));
+ EXPECT_TRUE(d.onLock(&dtls, l3));
+ d.onUnlock(&dtls, l4);
+ d.onUnlock(&dtls, l3);
+
+ EXPECT_EQ(d.size(), d.testOnlyGetEpoch());
+
+ d.removeNode(l2);
+ d.removeNode(l3);
+ locks.clear();
+ // make sure no edges from or to l0,l1,l4,l5 left.
+ for (uptr i = 4; i < d.size(); i++) {
+ uptr lt = d.newNode(i);
+ locks.insert(lt);
+ uptr a, b;
+ // l0 => lt?
+ a = l0; b = lt;
+ EXPECT_FALSE(d.onLock(&dtls, a));
+ EXPECT_FALSE(d.onLock(&dtls, b));
+ d.onUnlock(&dtls, a);
+ d.onUnlock(&dtls, b);
+ // l1 => lt?
+ a = l1; b = lt;
+ EXPECT_FALSE(d.onLock(&dtls, a));
+ EXPECT_FALSE(d.onLock(&dtls, b));
+ d.onUnlock(&dtls, a);
+ d.onUnlock(&dtls, b);
+ // lt => l4?
+ a = lt; b = l4;
+ EXPECT_FALSE(d.onLock(&dtls, a));
+ EXPECT_FALSE(d.onLock(&dtls, b));
+ d.onUnlock(&dtls, a);
+ d.onUnlock(&dtls, b);
+ // lt => l5?
+ a = lt; b = l5;
+ EXPECT_FALSE(d.onLock(&dtls, a));
+ EXPECT_FALSE(d.onLock(&dtls, b));
+ d.onUnlock(&dtls, a);
+ d.onUnlock(&dtls, b);
+
+ d.removeNode(lt);
+ }
+ // Still the same epoch.
+ EXPECT_EQ(d.size(), d.testOnlyGetEpoch());
+ EXPECT_EQ(locks.size(), d.size() - 4);
+ // l2 and l3 should have ben reused.
+ EXPECT_EQ(locks.count(l2), 1U);
+ EXPECT_EQ(locks.count(l3), 1U);
+}
+
+TEST(DeadlockDetector, RemoveNodeTest) {
+ RunRemoveNodeTest<BV1>();
+ RunRemoveNodeTest<BV2>();
+ RunRemoveNodeTest<BV3>();
+ RunRemoveNodeTest<BV4>();
+}
+
+template <class BV>
+void RunMultipleEpochsTest() {
+ ScopedDD<BV> sdd;
+ DeadlockDetector<BV> &d = *sdd.dp;
+ DeadlockDetectorTLS<BV> &dtls = sdd.dtls;
+
+ set<uptr> locks;
+ for (uptr i = 0; i < d.size(); i++) {
+ EXPECT_TRUE(locks.insert(d.newNode(i)).second);
+ }
+ EXPECT_EQ(d.testOnlyGetEpoch(), d.size());
+ for (uptr i = 0; i < d.size(); i++) {
+ EXPECT_TRUE(locks.insert(d.newNode(i)).second);
+ EXPECT_EQ(d.testOnlyGetEpoch(), d.size() * 2);
+ }
+ locks.clear();
+
+ uptr l0 = d.newNode(0);
+ uptr l1 = d.newNode(0);
+ d.onLock(&dtls, l0);
+ d.onLock(&dtls, l1);
+ d.onUnlock(&dtls, l0);
+ EXPECT_EQ(d.testOnlyGetEpoch(), 3 * d.size());
+ for (uptr i = 0; i < d.size(); i++) {
+ EXPECT_TRUE(locks.insert(d.newNode(i)).second);
+ }
+ EXPECT_EQ(d.testOnlyGetEpoch(), 4 * d.size());
+
+#if TSAN_DEBUG == 0
+ // EXPECT_DEATH clones a thread with 4K stack,
+ // which is overflown by tsan memory accesses functions in debug mode.
+
+ // Can not handle the locks from the previous epoch.
+ // The caller should update the lock id.
+ EXPECT_DEATH(d.onLock(&dtls, l0), "CHECK failed.*current_epoch_");
+#endif
+}
+
+TEST(DeadlockDetector, MultipleEpochsTest) {
+ RunMultipleEpochsTest<BV1>();
+ RunMultipleEpochsTest<BV2>();
+ RunMultipleEpochsTest<BV3>();
+ RunMultipleEpochsTest<BV4>();
+}
+
+template <class BV>
+void RunCorrectEpochFlush() {
+ ScopedDD<BV> sdd;
+ DeadlockDetector<BV> &d = *sdd.dp;
+ DeadlockDetectorTLS<BV> &dtls = sdd.dtls;
+ vector<uptr> locks1;
+ for (uptr i = 0; i < d.size(); i++)
+ locks1.push_back(d.newNode(i));
+ EXPECT_EQ(d.testOnlyGetEpoch(), d.size());
+ d.onLock(&dtls, locks1[3]);
+ d.onLock(&dtls, locks1[4]);
+ d.onLock(&dtls, locks1[5]);
+
+ // We have a new epoch, old locks in dtls will have to be forgotten.
+ uptr l0 = d.newNode(0);
+ EXPECT_EQ(d.testOnlyGetEpoch(), d.size() * 2);
+ uptr l1 = d.newNode(0);
+ EXPECT_EQ(d.testOnlyGetEpoch(), d.size() * 2);
+ d.onLock(&dtls, l0);
+ d.onLock(&dtls, l1);
+ EXPECT_TRUE(d.testOnlyHasEdgeRaw(0, 1));
+ EXPECT_FALSE(d.testOnlyHasEdgeRaw(1, 0));
+ EXPECT_FALSE(d.testOnlyHasEdgeRaw(3, 0));
+ EXPECT_FALSE(d.testOnlyHasEdgeRaw(4, 0));
+ EXPECT_FALSE(d.testOnlyHasEdgeRaw(5, 0));
+}
+
+TEST(DeadlockDetector, CorrectEpochFlush) {
+ RunCorrectEpochFlush<BV1>();
+ RunCorrectEpochFlush<BV2>();
+}
+
+template <class BV>
+void RunTryLockTest() {
+ ScopedDD<BV> sdd;
+ DeadlockDetector<BV> &d = *sdd.dp;
+ DeadlockDetectorTLS<BV> &dtls = sdd.dtls;
+
+ uptr l0 = d.newNode(0);
+ uptr l1 = d.newNode(0);
+ uptr l2 = d.newNode(0);
+ EXPECT_FALSE(d.onLock(&dtls, l0));
+ EXPECT_FALSE(d.onTryLock(&dtls, l1));
+ EXPECT_FALSE(d.onLock(&dtls, l2));
+ EXPECT_TRUE(d.isHeld(&dtls, l0));
+ EXPECT_TRUE(d.isHeld(&dtls, l1));
+ EXPECT_TRUE(d.isHeld(&dtls, l2));
+ EXPECT_FALSE(d.testOnlyHasEdge(l0, l1));
+ EXPECT_TRUE(d.testOnlyHasEdge(l1, l2));
+ d.onUnlock(&dtls, l0);
+ d.onUnlock(&dtls, l1);
+ d.onUnlock(&dtls, l2);
+}
+
+TEST(DeadlockDetector, TryLockTest) {
+ RunTryLockTest<BV1>();
+ RunTryLockTest<BV2>();
+}
+
+template <class BV>
+void RunOnFirstLockTest() {
+ ScopedDD<BV> sdd;
+ DeadlockDetector<BV> &d = *sdd.dp;
+ DeadlockDetectorTLS<BV> &dtls = sdd.dtls;
+
+ uptr l0 = d.newNode(0);
+ uptr l1 = d.newNode(0);
+ EXPECT_FALSE(d.onFirstLock(&dtls, l0)); // dtls has old epoch.
+ d.onLock(&dtls, l0);
+ d.onUnlock(&dtls, l0);
+
+ EXPECT_TRUE(d.onFirstLock(&dtls, l0)); // Ok, same ecpoch, first lock.
+ EXPECT_FALSE(d.onFirstLock(&dtls, l1)); // Second lock.
+ d.onLock(&dtls, l1);
+ d.onUnlock(&dtls, l1);
+ d.onUnlock(&dtls, l0);
+
+ EXPECT_TRUE(d.onFirstLock(&dtls, l0)); // Ok
+ d.onUnlock(&dtls, l0);
+
+ vector<uptr> locks1;
+ for (uptr i = 0; i < d.size(); i++)
+ locks1.push_back(d.newNode(i));
+
+ EXPECT_TRUE(d.onFirstLock(&dtls, l0)); // Epoch has changed, but not in dtls.
+
+ uptr l3 = d.newNode(0);
+ d.onLock(&dtls, l3);
+ d.onUnlock(&dtls, l3);
+
+ EXPECT_FALSE(d.onFirstLock(&dtls, l0)); // Epoch has changed in dtls.
+}
+
+TEST(DeadlockDetector, onFirstLockTest) {
+ RunOnFirstLockTest<BV2>();
+}
+
+template <class BV>
+void RunRecusriveLockTest() {
+ ScopedDD<BV> sdd;
+ DeadlockDetector<BV> &d = *sdd.dp;
+ DeadlockDetectorTLS<BV> &dtls = sdd.dtls;
+
+ uptr l0 = d.newNode(0);
+ uptr l1 = d.newNode(0);
+ uptr l2 = d.newNode(0);
+ uptr l3 = d.newNode(0);
+
+ EXPECT_FALSE(d.onLock(&dtls, l0));
+ EXPECT_FALSE(d.onLock(&dtls, l1));
+ EXPECT_FALSE(d.onLock(&dtls, l0)); // Recurisve.
+ EXPECT_FALSE(d.onLock(&dtls, l2));
+ d.onUnlock(&dtls, l0);
+ EXPECT_FALSE(d.onLock(&dtls, l3));
+ d.onUnlock(&dtls, l0);
+ d.onUnlock(&dtls, l1);
+ d.onUnlock(&dtls, l2);
+ d.onUnlock(&dtls, l3);
+ EXPECT_TRUE(d.testOnlyHasEdge(l0, l1));
+ EXPECT_TRUE(d.testOnlyHasEdge(l0, l2));
+ EXPECT_TRUE(d.testOnlyHasEdge(l0, l3));
+}
+
+TEST(DeadlockDetector, RecusriveLockTest) {
+ RunRecusriveLockTest<BV2>();
+}
+
+template <class BV>
+void RunLockContextTest() {
+ ScopedDD<BV> sdd;
+ DeadlockDetector<BV> &d = *sdd.dp;
+ DeadlockDetectorTLS<BV> &dtls = sdd.dtls;
+
+ uptr l0 = d.newNode(0);
+ uptr l1 = d.newNode(0);
+ uptr l2 = d.newNode(0);
+ uptr l3 = d.newNode(0);
+ uptr l4 = d.newNode(0);
+ EXPECT_FALSE(d.onLock(&dtls, l0, 10));
+ EXPECT_FALSE(d.onLock(&dtls, l1, 11));
+ EXPECT_FALSE(d.onLock(&dtls, l2, 12));
+ EXPECT_FALSE(d.onLock(&dtls, l3, 13));
+ EXPECT_EQ(10U, d.findLockContext(&dtls, l0));
+ EXPECT_EQ(11U, d.findLockContext(&dtls, l1));
+ EXPECT_EQ(12U, d.findLockContext(&dtls, l2));
+ EXPECT_EQ(13U, d.findLockContext(&dtls, l3));
+ d.onUnlock(&dtls, l0);
+ EXPECT_EQ(0U, d.findLockContext(&dtls, l0));
+ EXPECT_EQ(11U, d.findLockContext(&dtls, l1));
+ EXPECT_EQ(12U, d.findLockContext(&dtls, l2));
+ EXPECT_EQ(13U, d.findLockContext(&dtls, l3));
+ d.onUnlock(&dtls, l2);
+ EXPECT_EQ(0U, d.findLockContext(&dtls, l0));
+ EXPECT_EQ(11U, d.findLockContext(&dtls, l1));
+ EXPECT_EQ(0U, d.findLockContext(&dtls, l2));
+ EXPECT_EQ(13U, d.findLockContext(&dtls, l3));
+
+ EXPECT_FALSE(d.onLock(&dtls, l4, 14));
+ EXPECT_EQ(14U, d.findLockContext(&dtls, l4));
+}
+
+TEST(DeadlockDetector, LockContextTest) {
+ RunLockContextTest<BV2>();
+}
+
+template <class BV>
+void RunRemoveEdgesTest() {
+ ScopedDD<BV> sdd;
+ DeadlockDetector<BV> &d = *sdd.dp;
+ DeadlockDetectorTLS<BV> &dtls = sdd.dtls;
+ vector<uptr> node(BV::kSize);
+ u32 stk_from = 0, stk_to = 0;
+ int unique_tid = 0;
+ for (size_t i = 0; i < BV::kSize; i++)
+ node[i] = d.newNode(0);
+
+ for (size_t i = 0; i < BV::kSize; i++)
+ EXPECT_FALSE(d.onLock(&dtls, node[i], i + 1));
+ for (size_t i = 0; i < BV::kSize; i++) {
+ for (uptr j = i + 1; j < BV::kSize; j++) {
+ EXPECT_TRUE(
+ d.findEdge(node[i], node[j], &stk_from, &stk_to, &unique_tid));
+ EXPECT_EQ(stk_from, i + 1);
+ EXPECT_EQ(stk_to, j + 1);
+ }
+ }
+ EXPECT_EQ(d.testOnlyGetEpoch(), d.size());
+ // Remove and re-create half of the nodes.
+ for (uptr i = 1; i < BV::kSize; i += 2)
+ d.removeNode(node[i]);
+ for (uptr i = 1; i < BV::kSize; i += 2)
+ node[i] = d.newNode(0);
+ EXPECT_EQ(d.testOnlyGetEpoch(), d.size());
+ // The edges from or to the removed nodes should be gone.
+ for (size_t i = 0; i < BV::kSize; i++) {
+ for (uptr j = i + 1; j < BV::kSize; j++) {
+ if ((i % 2) || (j % 2))
+ EXPECT_FALSE(
+ d.findEdge(node[i], node[j], &stk_from, &stk_to, &unique_tid));
+ else
+ EXPECT_TRUE(
+ d.findEdge(node[i], node[j], &stk_from, &stk_to, &unique_tid));
+ }
+ }
+}
+
+TEST(DeadlockDetector, RemoveEdgesTest) {
+ RunRemoveEdgesTest<BV1>();
+}
diff --git a/lib/sanitizer_common/tests/sanitizer_flags_test.cc b/lib/sanitizer_common/tests/sanitizer_flags_test.cc
index cd3cac11bc80..1055f5d24d6b 100644
--- a/lib/sanitizer_common/tests/sanitizer_flags_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_flags_test.cc
@@ -24,14 +24,14 @@ static const char kFlagName[] = "flag_name";
template <typename T>
static void TestFlag(T start_value, const char *env, T final_value) {
T flag = start_value;
- ParseFlag(env, &flag, kFlagName);
+ ParseFlag(env, &flag, kFlagName, "flag description");
EXPECT_EQ(final_value, flag);
}
static void TestStrFlag(const char *start_value, const char *env,
const char *final_value) {
const char *flag = start_value;
- ParseFlag(env, &flag, kFlagName);
+ ParseFlag(env, &flag, kFlagName, "flag description");
EXPECT_EQ(0, internal_strcmp(final_value, flag));
}
@@ -49,7 +49,7 @@ TEST(SanitizerCommon, BooleanFlags) {
TEST(SanitizerCommon, IntFlags) {
TestFlag(-11, 0, -11);
- TestFlag(-11, "flag_name", 0);
+ TestFlag(-11, "flag_name", -11);
TestFlag(-11, "--flag_name=", 0);
TestFlag(-11, "--flag_name=42", 42);
TestFlag(-11, "--flag_name=-42", -42);
@@ -57,7 +57,7 @@ TEST(SanitizerCommon, IntFlags) {
TEST(SanitizerCommon, StrFlags) {
TestStrFlag("zzz", 0, "zzz");
- TestStrFlag("zzz", "flag_name", "");
+ TestStrFlag("zzz", "flag_name", "zzz");
TestStrFlag("zzz", "--flag_name=", "");
TestStrFlag("", "--flag_name=abc", "abc");
TestStrFlag("", "--flag_name='abc zxc'", "abc zxc");
@@ -70,8 +70,8 @@ static void TestTwoFlags(const char *env, bool expected_flag1,
const char *expected_flag2) {
bool flag1 = !expected_flag1;
const char *flag2 = "";
- ParseFlag(env, &flag1, "flag1");
- ParseFlag(env, &flag2, "flag2");
+ ParseFlag(env, &flag1, "flag1", "flag1 description");
+ ParseFlag(env, &flag2, "flag2", "flag2 description");
EXPECT_EQ(expected_flag1, flag1);
EXPECT_EQ(0, internal_strcmp(flag2, expected_flag2));
}
diff --git a/lib/sanitizer_common/tests/sanitizer_format_interceptor_test.cc b/lib/sanitizer_common/tests/sanitizer_format_interceptor_test.cc
new file mode 100644
index 000000000000..13918aff1009
--- /dev/null
+++ b/lib/sanitizer_common/tests/sanitizer_format_interceptor_test.cc
@@ -0,0 +1,259 @@
+//===-- sanitizer_format_interceptor_test.cc ------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Tests for *scanf interceptors implementation in sanitizer_common.
+//
+//===----------------------------------------------------------------------===//
+#include <algorithm>
+#include <vector>
+
+#include "interception/interception.h"
+#include "sanitizer_test_utils.h"
+#include "sanitizer_common/sanitizer_libc.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "gtest/gtest.h"
+
+using namespace __sanitizer;
+
+#define COMMON_INTERCEPTOR_READ_WRITE_RANGE(ctx, ptr, size) \
+ do { \
+ ((std::vector<unsigned> *)ctx)->push_back(size); \
+ ptr = ptr; \
+ } while (0)
+
+#define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) \
+ COMMON_INTERCEPTOR_READ_WRITE_RANGE(ctx, ptr, size)
+
+#define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \
+ COMMON_INTERCEPTOR_READ_WRITE_RANGE(ctx, ptr, size)
+
+#define SANITIZER_INTERCEPT_PRINTF 1
+#include "sanitizer_common/sanitizer_common_interceptors_format.inc"
+
+static const unsigned I = sizeof(int);
+static const unsigned L = sizeof(long);
+static const unsigned LL = sizeof(long long);
+static const unsigned S = sizeof(short);
+static const unsigned C = sizeof(char);
+static const unsigned LC = sizeof(wchar_t);
+static const unsigned D = sizeof(double);
+static const unsigned LD = sizeof(long double);
+static const unsigned F = sizeof(float);
+static const unsigned P = sizeof(char *);
+
+static void verifyFormatResults(const char *format, unsigned n,
+ const std::vector<unsigned> &computed_sizes,
+ va_list expected_sizes) {
+ // "+ 1" because of format string
+ ASSERT_EQ(n + 1,
+ computed_sizes.size()) << "Unexpected number of format arguments: '"
+ << format << "'";
+ for (unsigned i = 0; i < n; ++i)
+ EXPECT_EQ(va_arg(expected_sizes, unsigned), computed_sizes[i + 1])
+ << "Unexpect write size for argument " << i << ", format string '"
+ << format << "'";
+}
+
+static const char test_buf[] = "Test string.";
+static const size_t test_buf_size = sizeof(test_buf);
+
+static const unsigned SCANF_ARGS_MAX = 16;
+
+static void testScanf3(void *ctx, int result, bool allowGnuMalloc,
+ const char *format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ scanf_common(ctx, result, allowGnuMalloc, format, ap);
+ va_end(ap);
+}
+
+static void testScanf2(const char *format, int scanf_result,
+ bool allowGnuMalloc, unsigned n,
+ va_list expected_sizes) {
+ std::vector<unsigned> scanf_sizes;
+ // 16 args should be enough.
+ testScanf3((void *)&scanf_sizes, scanf_result, allowGnuMalloc, format,
+ test_buf, test_buf, test_buf, test_buf, test_buf, test_buf,
+ test_buf, test_buf, test_buf, test_buf, test_buf, test_buf,
+ test_buf, test_buf, test_buf, test_buf);
+ verifyFormatResults(format, n, scanf_sizes, expected_sizes);
+}
+
+static void testScanf(const char *format, unsigned n, ...) {
+ va_list ap;
+ va_start(ap, n);
+ testScanf2(format, SCANF_ARGS_MAX, /* allowGnuMalloc */ true, n, ap);
+ va_end(ap);
+}
+
+static void testScanfPartial(const char *format, int scanf_result, unsigned n,
+ ...) {
+ va_list ap;
+ va_start(ap, n);
+ testScanf2(format, scanf_result, /* allowGnuMalloc */ true, n, ap);
+ va_end(ap);
+}
+
+static void testScanfNoGnuMalloc(const char *format, unsigned n, ...) {
+ va_list ap;
+ va_start(ap, n);
+ testScanf2(format, SCANF_ARGS_MAX, /* allowGnuMalloc */ false, n, ap);
+ va_end(ap);
+}
+
+TEST(SanitizerCommonInterceptors, Scanf) {
+ testScanf("%d", 1, I);
+ testScanf("%d%d%d", 3, I, I, I);
+ testScanf("ab%u%dc", 2, I, I);
+ testScanf("%ld", 1, L);
+ testScanf("%llu", 1, LL);
+ testScanf("%qd", 1, LL);
+ testScanf("a %hd%hhx", 2, S, C);
+ testScanf("%c", 1, C);
+ testScanf("%lc", 1, LC);
+
+ testScanf("%%", 0);
+ testScanf("a%%", 0);
+ testScanf("a%%b", 0);
+ testScanf("a%%%%b", 0);
+ testScanf("a%%b%%", 0);
+ testScanf("a%%%%%%b", 0);
+ testScanf("a%%%%%b", 0);
+ testScanf("a%%%%%f", 1, F);
+ testScanf("a%%%lxb", 1, L);
+ testScanf("a%lf%%%lxb", 2, D, L);
+ testScanf("%nf", 1, I);
+
+ testScanf("%10s", 1, 11);
+ testScanf("%10c", 1, 10);
+ testScanf("%10ls", 1, 11 * LC);
+ testScanf("%10lc", 1, 10 * LC);
+ testScanf("%%10s", 0);
+ testScanf("%*10s", 0);
+ testScanf("%*d", 0);
+
+ testScanf("%4d%8f%c", 3, I, F, C);
+ testScanf("%s%d", 2, test_buf_size, I);
+ testScanf("%[abc]", 1, test_buf_size);
+ testScanf("%4[bcdef]", 1, 5);
+ testScanf("%[]]", 1, test_buf_size);
+ testScanf("%8[^]%d0-9-]%c", 2, 9, C);
+
+ testScanf("%*[^:]%n:%d:%1[ ]%n", 4, I, I, 2, I);
+
+ testScanf("%*d%u", 1, I);
+
+ testScanf("%c%d", 2, C, I);
+ testScanf("%A%lf", 2, F, D);
+
+ testScanf("%ms %Lf", 2, P, LD);
+ testScanf("s%Las", 1, LD);
+ testScanf("%ar", 1, F);
+
+ // In the cases with std::min below the format spec can be interpreted as
+ // either floating-something, or (GNU extension) callee-allocated string.
+ // Our conservative implementation reports one of the two possibilities with
+ // the least store range.
+ testScanf("%a[", 0);
+ testScanf("%a[]", 0);
+ testScanf("%a[]]", 1, std::min(F, P));
+ testScanf("%a[abc]", 1, std::min(F, P));
+ testScanf("%a[^abc]", 1, std::min(F, P));
+ testScanf("%a[ab%c] %d", 0);
+ testScanf("%a[^ab%c] %d", 0);
+ testScanf("%as", 1, std::min(F, P));
+ testScanf("%aS", 1, std::min(F, P));
+ testScanf("%a13S", 1, std::min(F, P));
+ testScanf("%alS", 1, std::min(F, P));
+
+ testScanfNoGnuMalloc("s%Las", 1, LD);
+ testScanfNoGnuMalloc("%ar", 1, F);
+ testScanfNoGnuMalloc("%a[", 1, F);
+ testScanfNoGnuMalloc("%a[]", 1, F);
+ testScanfNoGnuMalloc("%a[]]", 1, F);
+ testScanfNoGnuMalloc("%a[abc]", 1, F);
+ testScanfNoGnuMalloc("%a[^abc]", 1, F);
+ testScanfNoGnuMalloc("%a[ab%c] %d", 3, F, C, I);
+ testScanfNoGnuMalloc("%a[^ab%c] %d", 3, F, C, I);
+ testScanfNoGnuMalloc("%as", 1, F);
+ testScanfNoGnuMalloc("%aS", 1, F);
+ testScanfNoGnuMalloc("%a13S", 1, F);
+ testScanfNoGnuMalloc("%alS", 1, F);
+
+ testScanf("%5$d", 0);
+ testScanf("%md", 0);
+ testScanf("%m10s", 0);
+
+ testScanfPartial("%d%d%d%d //1\n", 1, 1, I);
+ testScanfPartial("%d%d%d%d //2\n", 2, 2, I, I);
+ testScanfPartial("%d%d%d%d //3\n", 3, 3, I, I, I);
+ testScanfPartial("%d%d%d%d //4\n", 4, 4, I, I, I, I);
+
+ testScanfPartial("%d%n%n%d //1\n", 1, 3, I, I, I);
+ testScanfPartial("%d%n%n%d //2\n", 2, 4, I, I, I, I);
+
+ testScanfPartial("%d%n%n%d %s %s", 3, 5, I, I, I, I, test_buf_size);
+ testScanfPartial("%d%n%n%d %s %s", 4, 6, I, I, I, I, test_buf_size,
+ test_buf_size);
+}
+
+static void testPrintf3(void *ctx, const char *format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ printf_common(ctx, format, ap);
+ va_end(ap);
+}
+
+static void testPrintf2(const char *format, unsigned n,
+ va_list expected_sizes) {
+ std::vector<unsigned> printf_sizes;
+ // 16 args should be enough.
+ testPrintf3((void *)&printf_sizes, format,
+ test_buf, test_buf, test_buf, test_buf, test_buf, test_buf,
+ test_buf, test_buf, test_buf, test_buf, test_buf, test_buf,
+ test_buf, test_buf, test_buf, test_buf);
+ verifyFormatResults(format, n, printf_sizes, expected_sizes);
+}
+
+static void testPrintf(const char *format, unsigned n, ...) {
+ va_list ap;
+ va_start(ap, n);
+ testPrintf2(format, n, ap);
+ va_end(ap);
+}
+
+TEST(SanitizerCommonInterceptors, Printf) {
+ // Only test functionality which differs from scanf
+
+ // Indexed arguments
+ testPrintf("%5$d", 0);
+ testPrintf("%.*5$d", 0);
+
+ // errno
+ testPrintf("%0-m", 0);
+
+ // Dynamic width
+ testPrintf("%*n", 1, I);
+ testPrintf("%*.10n", 1, I);
+
+ // Precision
+ testPrintf("%10.10n", 1, I);
+ testPrintf("%.3s", 1, 3);
+ testPrintf("%.20s", 1, test_buf_size);
+
+ // Dynamic precision
+ testPrintf("%.*n", 1, I);
+ testPrintf("%10.*n", 1, I);
+
+ // Dynamic precision for strings is not implemented yet.
+ testPrintf("%.*s", 1, 0);
+
+ // Checks for wide-character strings are not implemented yet.
+ testPrintf("%ls", 1, 0);
+}
diff --git a/lib/sanitizer_common/tests/sanitizer_ioctl_test.cc b/lib/sanitizer_common/tests/sanitizer_ioctl_test.cc
index 154d9860b79f..22fa5228dfbd 100644
--- a/lib/sanitizer_common/tests/sanitizer_ioctl_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_ioctl_test.cc
@@ -47,6 +47,7 @@ static struct IoctlInit {
// Avoid unused function warnings.
(void)&ioctl_common_pre;
(void)&ioctl_common_post;
+ (void)&ioctl_decode;
}
} ioctl_static_initializer;
@@ -74,4 +75,29 @@ TEST(SanitizerIoctl, Fixup) {
EXPECT_EQ(EVIOCGKEY(0), desc->req);
}
+// Test decoding KVM ioctl numbers.
+TEST(SanitizerIoctl, KVM_GET_MP_STATE) {
+ ioctl_desc desc;
+ bool res = ioctl_decode(0x8004ae98U, &desc);
+ EXPECT_TRUE(res);
+ EXPECT_EQ(ioctl_desc::WRITE, desc.type);
+ EXPECT_EQ(4U, desc.size);
+}
+
+TEST(SanitizerIoctl, KVM_GET_LAPIC) {
+ ioctl_desc desc;
+ bool res = ioctl_decode(0x8400ae8eU, &desc);
+ EXPECT_TRUE(res);
+ EXPECT_EQ(ioctl_desc::WRITE, desc.type);
+ EXPECT_EQ(1024U, desc.size);
+}
+
+TEST(SanitizerIoctl, KVM_GET_MSR_INDEX_LIST) {
+ ioctl_desc desc;
+ bool res = ioctl_decode(0xc004ae02U, &desc);
+ EXPECT_TRUE(res);
+ EXPECT_EQ(ioctl_desc::READWRITE, desc.type);
+ EXPECT_EQ(4U, desc.size);
+}
+
#endif // SANITIZER_LINUX
diff --git a/lib/sanitizer_common/tests/sanitizer_libc_test.cc b/lib/sanitizer_common/tests/sanitizer_libc_test.cc
index c4f3d8033c2d..660710d5bb7e 100644
--- a/lib/sanitizer_common/tests/sanitizer_libc_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_libc_test.cc
@@ -55,6 +55,8 @@ struct stat_and_more {
unsigned char z;
};
+// FIXME: File manipulations are not yet supported on Windows
+#if !defined(_WIN32)
TEST(SanitizerCommon, FileOps) {
const char *str1 = "qwerty";
uptr len1 = internal_strlen(str1);
@@ -114,6 +116,7 @@ TEST(SanitizerCommon, FileOps) {
EXPECT_EQ(0, internal_memcmp(buf, str2, len2));
internal_close(fd);
}
+#endif
TEST(SanitizerCommon, InternalStrFunctions) {
const char *haystack = "haystack";
diff --git a/lib/sanitizer_common/tests/sanitizer_mutex_test.cc b/lib/sanitizer_common/tests/sanitizer_mutex_test.cc
index 06f742b41796..d14e7c2fba21 100644
--- a/lib/sanitizer_common/tests/sanitizer_mutex_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_mutex_test.cc
@@ -12,6 +12,9 @@
//===----------------------------------------------------------------------===//
#include "sanitizer_common/sanitizer_mutex.h"
#include "sanitizer_common/sanitizer_common.h"
+
+#include "sanitizer_pthread_wrappers.h"
+
#include "gtest/gtest.h"
#include <string.h>
@@ -103,9 +106,9 @@ TEST(SanitizerCommon, SpinMutex) {
TestData<SpinMutex> data(&mtx);
pthread_t threads[kThreads];
for (int i = 0; i < kThreads; i++)
- pthread_create(&threads[i], 0, lock_thread<SpinMutex>, &data);
+ PTHREAD_CREATE(&threads[i], 0, lock_thread<SpinMutex>, &data);
for (int i = 0; i < kThreads; i++)
- pthread_join(threads[i], 0);
+ PTHREAD_JOIN(threads[i], 0);
}
TEST(SanitizerCommon, SpinMutexTry) {
@@ -114,9 +117,9 @@ TEST(SanitizerCommon, SpinMutexTry) {
TestData<SpinMutex> data(&mtx);
pthread_t threads[kThreads];
for (int i = 0; i < kThreads; i++)
- pthread_create(&threads[i], 0, try_thread<SpinMutex>, &data);
+ PTHREAD_CREATE(&threads[i], 0, try_thread<SpinMutex>, &data);
for (int i = 0; i < kThreads; i++)
- pthread_join(threads[i], 0);
+ PTHREAD_JOIN(threads[i], 0);
}
TEST(SanitizerCommon, BlockingMutex) {
@@ -125,9 +128,9 @@ TEST(SanitizerCommon, BlockingMutex) {
TestData<BlockingMutex> data(mtx);
pthread_t threads[kThreads];
for (int i = 0; i < kThreads; i++)
- pthread_create(&threads[i], 0, lock_thread<BlockingMutex>, &data);
+ PTHREAD_CREATE(&threads[i], 0, lock_thread<BlockingMutex>, &data);
for (int i = 0; i < kThreads; i++)
- pthread_join(threads[i], 0);
+ PTHREAD_JOIN(threads[i], 0);
check_locked(mtx);
}
diff --git a/lib/sanitizer_common/tests/sanitizer_posix_test.cc b/lib/sanitizer_common/tests/sanitizer_posix_test.cc
index 035899c83022..56ce416141fa 100644
--- a/lib/sanitizer_common/tests/sanitizer_posix_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_posix_test.cc
@@ -18,6 +18,7 @@
#include "gtest/gtest.h"
#include <pthread.h>
+#include <sys/mman.h>
namespace __sanitizer {
@@ -57,6 +58,23 @@ TEST(SanitizerCommon, PthreadDestructorIterations) {
EXPECT_FALSE(destructor_executed);
}
+TEST(SanitizerCommon, IsAccessibleMemoryRange) {
+ const int page_size = GetPageSize();
+ uptr mem = (uptr)mmap(0, 3 * page_size, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANON, -1, 0);
+ // Protect the middle page.
+ mprotect((void *)(mem + page_size), page_size, PROT_NONE);
+ EXPECT_TRUE(IsAccessibleMemoryRange(mem, page_size - 1));
+ EXPECT_TRUE(IsAccessibleMemoryRange(mem, page_size));
+ EXPECT_FALSE(IsAccessibleMemoryRange(mem, page_size + 1));
+ EXPECT_TRUE(IsAccessibleMemoryRange(mem + page_size - 1, 1));
+ EXPECT_FALSE(IsAccessibleMemoryRange(mem + page_size - 1, 2));
+ EXPECT_FALSE(IsAccessibleMemoryRange(mem + 2 * page_size - 1, 1));
+ EXPECT_TRUE(IsAccessibleMemoryRange(mem + 2 * page_size, page_size));
+ EXPECT_FALSE(IsAccessibleMemoryRange(mem, 3 * page_size));
+ EXPECT_FALSE(IsAccessibleMemoryRange(0x0, 2));
+}
+
} // namespace __sanitizer
#endif // SANITIZER_POSIX
diff --git a/lib/sanitizer_common/tests/sanitizer_printf_test.cc b/lib/sanitizer_common/tests/sanitizer_printf_test.cc
index 2c478cc74286..d0b46ac94ff2 100644
--- a/lib/sanitizer_common/tests/sanitizer_printf_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_printf_test.cc
@@ -103,6 +103,11 @@ TEST(Printf, OverflowPtr) {
EXPECT_EQ(buf[9], 0);
}
+#if defined(_WIN32)
+// Oh well, MSVS headers don't define snprintf.
+# define snprintf _snprintf
+#endif
+
template<typename T>
static void TestAgainstLibc(const char *fmt, T arg1, T arg2) {
char buf[1024];
@@ -115,12 +120,14 @@ static void TestAgainstLibc(const char *fmt, T arg1, T arg2) {
TEST(Printf, MinMax) {
TestAgainstLibc<int>("%d-%d", INT_MIN, INT_MAX); // NOLINT
- TestAgainstLibc<long>("%zd-%zd", LONG_MIN, LONG_MAX); // NOLINT
TestAgainstLibc<unsigned>("%u-%u", 0, UINT_MAX); // NOLINT
- TestAgainstLibc<unsigned long>("%zu-%zu", 0, ULONG_MAX); // NOLINT
TestAgainstLibc<unsigned>("%x-%x", 0, UINT_MAX); // NOLINT
+#if !defined(_WIN32)
+ // %z* format doesn't seem to be supported by MSVS.
+ TestAgainstLibc<long>("%zd-%zd", LONG_MIN, LONG_MAX); // NOLINT
+ TestAgainstLibc<unsigned long>("%zu-%zu", 0, ULONG_MAX); // NOLINT
TestAgainstLibc<unsigned long>("%zx-%zx", 0, ULONG_MAX); // NOLINT
- Report("%zd\n", LONG_MIN);
+#endif
}
TEST(Printf, Padding) {
@@ -136,4 +143,14 @@ TEST(Printf, Padding) {
TestAgainstLibc<int>("%03d - %03d", -12, -1234);
}
+TEST(Printf, Precision) {
+ char buf[1024];
+ uptr len = internal_snprintf(buf, sizeof(buf), "%.*s", 3, "12345");
+ EXPECT_EQ(3U, len);
+ EXPECT_STREQ("123", buf);
+ len = internal_snprintf(buf, sizeof(buf), "%.*s", 6, "12345");
+ EXPECT_EQ(5U, len);
+ EXPECT_STREQ("12345", buf);
+}
+
} // namespace __sanitizer
diff --git a/lib/sanitizer_common/tests/sanitizer_procmaps_test.cc b/lib/sanitizer_common/tests/sanitizer_procmaps_test.cc
index d16e2eebf98e..495b726dcc45 100644
--- a/lib/sanitizer_common/tests/sanitizer_procmaps_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_procmaps_test.cc
@@ -10,21 +10,48 @@
// This file is a part of ThreadSanitizer/AddressSanitizer runtime.
//
//===----------------------------------------------------------------------===//
+#if !defined(_WIN32) // There are no /proc/maps on Windows.
+
#include "sanitizer_common/sanitizer_procmaps.h"
-//#include "sanitizer_common/sanitizer_internal_defs.h"
-//#include "sanitizer_common/sanitizer_libc.h"
#include "gtest/gtest.h"
+#include <stdlib.h>
+
+static void noop() {}
+extern const char *argv0;
+
namespace __sanitizer {
-#ifdef SANITIZER_LINUX
-TEST(ProcMaps, CodeRange) {
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+TEST(MemoryMappingLayout, CodeRange) {
uptr start, end;
bool res = GetCodeRangeForFile("[vdso]", &start, &end);
EXPECT_EQ(res, true);
- EXPECT_GT(start, (uptr)0);
+ EXPECT_GT(start, 0U);
EXPECT_LT(start, end);
}
#endif
+TEST(MemoryMappingLayout, DumpListOfModules) {
+ const char *last_slash = strrchr(argv0, '/');
+ const char *binary_name = last_slash ? last_slash + 1 : argv0;
+ MemoryMappingLayout memory_mapping(false);
+ const uptr kMaxModules = 100;
+ LoadedModule *modules =
+ (LoadedModule *)malloc(kMaxModules * sizeof(LoadedModule));
+ uptr n_modules = memory_mapping.DumpListOfModules(modules, kMaxModules, 0);
+ EXPECT_GT(n_modules, 0U);
+ bool found = false;
+ for (uptr i = 0; i < n_modules; ++i) {
+ if (modules[i].containsAddress((uptr)&noop)) {
+ // Verify that the module name is sane.
+ if (strstr(modules[i].full_name(), binary_name) != 0)
+ found = true;
+ }
+ }
+ EXPECT_TRUE(found);
+ free(modules);
+}
+
} // namespace __sanitizer
+#endif // !defined(_WIN32)
diff --git a/lib/sanitizer_common/tests/sanitizer_pthread_wrappers.h b/lib/sanitizer_common/tests/sanitizer_pthread_wrappers.h
new file mode 100644
index 000000000000..47b0f97de840
--- /dev/null
+++ b/lib/sanitizer_common/tests/sanitizer_pthread_wrappers.h
@@ -0,0 +1,66 @@
+//===-- sanitizer_pthread_wrappers.h ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of *Sanitizer runtime.
+// It provides handy wrappers for thread manipulation, that:
+// a) assert on any failure rather than returning an error code
+// b) defines pthread-like interface on platforms where where <pthread.h>
+// is not supplied by default.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_PTHREAD_WRAPPERS_H
+#define SANITIZER_PTHREAD_WRAPPERS_H
+
+#include "sanitizer_test_utils.h"
+
+#if !defined(_WIN32)
+# include <pthread.h>
+// Simply forward the arguments and check that the pthread functions succeed.
+# define PTHREAD_CREATE(a, b, c, d) ASSERT_EQ(0, pthread_create(a, b, c, d))
+# define PTHREAD_JOIN(a, b) ASSERT_EQ(0, pthread_join(a, b))
+#else
+typedef HANDLE pthread_t;
+
+struct PthreadHelperCreateThreadInfo {
+ void *(*start_routine)(void *);
+ void *arg;
+};
+
+inline DWORD WINAPI PthreadHelperThreadProc(void *arg) {
+ PthreadHelperCreateThreadInfo *start_data =
+ reinterpret_cast<PthreadHelperCreateThreadInfo*>(arg);
+ void *ret = (start_data->start_routine)(start_data->arg);
+ delete start_data;
+ return (DWORD)ret;
+}
+
+inline void PTHREAD_CREATE(pthread_t *thread, void *attr,
+ void *(*start_routine)(void *), void *arg) {
+ ASSERT_EQ(0, attr) << "Thread attributes are not supported yet.";
+ PthreadHelperCreateThreadInfo *data = new PthreadHelperCreateThreadInfo;
+ data->start_routine = start_routine;
+ data->arg = arg;
+ *thread = CreateThread(0, 0, PthreadHelperThreadProc, data, 0, 0);
+ ASSERT_NE(nullptr, *thread) << "Failed to create a thread.";
+}
+
+inline void PTHREAD_JOIN(pthread_t thread, void **value_ptr) {
+ ASSERT_EQ(0, value_ptr) << "Nonzero value_ptr is not supported yet.";
+ ASSERT_EQ(WAIT_OBJECT_0, WaitForSingleObject(thread, INFINITE));
+ ASSERT_NE(0, CloseHandle(thread));
+}
+
+inline void pthread_exit(void *retval) {
+ ASSERT_EQ(0, retval) << "Nonzero retval is not supported yet.";
+ ExitThread((DWORD)retval);
+}
+#endif // _WIN32
+
+#endif // SANITIZER_PTHREAD_WRAPPERS_H
diff --git a/lib/sanitizer_common/tests/sanitizer_scanf_interceptor_test.cc b/lib/sanitizer_common/tests/sanitizer_scanf_interceptor_test.cc
deleted file mode 100644
index e0354062508f..000000000000
--- a/lib/sanitizer_common/tests/sanitizer_scanf_interceptor_test.cc
+++ /dev/null
@@ -1,178 +0,0 @@
-//===-- sanitizer_scanf_interceptor_test.cc -------------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// Tests for *scanf interceptors implementation in sanitizer_common.
-//
-//===----------------------------------------------------------------------===//
-#include <vector>
-
-#include "interception/interception.h"
-#include "sanitizer_test_utils.h"
-#include "sanitizer_common/sanitizer_libc.h"
-#include "gtest/gtest.h"
-
-using namespace __sanitizer;
-
-#define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \
- ((std::vector<unsigned> *)ctx)->push_back(size)
-
-#include "sanitizer_common/sanitizer_common_interceptors_scanf.inc"
-
-static const char scanf_buf[] = "Test string.";
-static size_t scanf_buf_size = sizeof(scanf_buf);
-static const unsigned SCANF_ARGS_MAX = 16;
-
-static void testScanf3(void *ctx, int result, bool allowGnuMalloc,
- const char *format, ...) {
- va_list ap;
- va_start(ap, format);
- scanf_common(ctx, result, allowGnuMalloc, format, ap);
- va_end(ap);
-}
-
-static void testScanf2(const char *format, int scanf_result,
- bool allowGnuMalloc, unsigned n,
- va_list expected_sizes) {
- std::vector<unsigned> scanf_sizes;
- // 16 args should be enough.
- testScanf3((void *)&scanf_sizes, scanf_result, allowGnuMalloc, format,
- scanf_buf, scanf_buf, scanf_buf, scanf_buf, scanf_buf, scanf_buf,
- scanf_buf, scanf_buf, scanf_buf, scanf_buf, scanf_buf, scanf_buf,
- scanf_buf, scanf_buf, scanf_buf, scanf_buf);
- ASSERT_EQ(n, scanf_sizes.size()) << "Unexpected number of format arguments: '"
- << format << "'";
- for (unsigned i = 0; i < n; ++i)
- EXPECT_EQ(va_arg(expected_sizes, unsigned), scanf_sizes[i])
- << "Unexpect write size for argument " << i << ", format string '"
- << format << "'";
-}
-
-static void testScanf(const char *format, unsigned n, ...) {
- va_list ap;
- va_start(ap, n);
- testScanf2(format, SCANF_ARGS_MAX, /* allowGnuMalloc */ true, n, ap);
- va_end(ap);
-}
-
-static void testScanfPartial(const char *format, int scanf_result, unsigned n,
- ...) {
- va_list ap;
- va_start(ap, n);
- testScanf2(format, scanf_result, /* allowGnuMalloc */ true, n, ap);
- va_end(ap);
-}
-
-static void testScanfNoGnuMalloc(const char *format, unsigned n, ...) {
- va_list ap;
- va_start(ap, n);
- testScanf2(format, SCANF_ARGS_MAX, /* allowGnuMalloc */ false, n, ap);
- va_end(ap);
-}
-
-TEST(SanitizerCommonInterceptors, Scanf) {
- const unsigned I = sizeof(int); // NOLINT
- const unsigned L = sizeof(long); // NOLINT
- const unsigned LL = sizeof(long long); // NOLINT
- const unsigned S = sizeof(short); // NOLINT
- const unsigned C = sizeof(char); // NOLINT
- const unsigned D = sizeof(double); // NOLINT
- const unsigned LD = sizeof(long double); // NOLINT
- const unsigned F = sizeof(float); // NOLINT
- const unsigned P = sizeof(char *); // NOLINT
-
- testScanf("%d", 1, I);
- testScanf("%d%d%d", 3, I, I, I);
- testScanf("ab%u%dc", 2, I, I);
- testScanf("%ld", 1, L);
- testScanf("%llu", 1, LL);
- testScanf("a %hd%hhx", 2, S, C);
- testScanf("%c", 1, C);
-
- testScanf("%%", 0);
- testScanf("a%%", 0);
- testScanf("a%%b", 0);
- testScanf("a%%%%b", 0);
- testScanf("a%%b%%", 0);
- testScanf("a%%%%%%b", 0);
- testScanf("a%%%%%b", 0);
- testScanf("a%%%%%f", 1, F);
- testScanf("a%%%lxb", 1, L);
- testScanf("a%lf%%%lxb", 2, D, L);
- testScanf("%nf", 1, I);
-
- testScanf("%10s", 1, 11);
- testScanf("%10c", 1, 10);
- testScanf("%%10s", 0);
- testScanf("%*10s", 0);
- testScanf("%*d", 0);
-
- testScanf("%4d%8f%c", 3, I, F, C);
- testScanf("%s%d", 2, scanf_buf_size, I);
- testScanf("%[abc]", 1, scanf_buf_size);
- testScanf("%4[bcdef]", 1, 5);
- testScanf("%[]]", 1, scanf_buf_size);
- testScanf("%8[^]%d0-9-]%c", 2, 9, C);
-
- testScanf("%*[^:]%n:%d:%1[ ]%n", 4, I, I, 2, I);
-
- testScanf("%*d%u", 1, I);
-
- testScanf("%c%d", 2, C, I);
- testScanf("%A%lf", 2, F, D);
-
- testScanf("%ms %Lf", 2, P, LD);
- testScanf("s%Las", 1, LD);
- testScanf("%ar", 1, F);
-
- // In the cases with std::min below the format spec can be interpreted as
- // either floating-something, or (GNU extension) callee-allocated string.
- // Our conservative implementation reports one of the two possibilities with
- // the least store range.
- testScanf("%a[", 0);
- testScanf("%a[]", 0);
- testScanf("%a[]]", 1, std::min(F, P));
- testScanf("%a[abc]", 1, std::min(F, P));
- testScanf("%a[^abc]", 1, std::min(F, P));
- testScanf("%a[ab%c] %d", 0);
- testScanf("%a[^ab%c] %d", 0);
- testScanf("%as", 1, std::min(F, P));
- testScanf("%aS", 1, std::min(F, P));
- testScanf("%a13S", 1, std::min(F, P));
- testScanf("%alS", 1, std::min(F, P));
-
- testScanfNoGnuMalloc("s%Las", 1, LD);
- testScanfNoGnuMalloc("%ar", 1, F);
- testScanfNoGnuMalloc("%a[", 1, F);
- testScanfNoGnuMalloc("%a[]", 1, F);
- testScanfNoGnuMalloc("%a[]]", 1, F);
- testScanfNoGnuMalloc("%a[abc]", 1, F);
- testScanfNoGnuMalloc("%a[^abc]", 1, F);
- testScanfNoGnuMalloc("%a[ab%c] %d", 3, F, C, I);
- testScanfNoGnuMalloc("%a[^ab%c] %d", 3, F, C, I);
- testScanfNoGnuMalloc("%as", 1, F);
- testScanfNoGnuMalloc("%aS", 1, F);
- testScanfNoGnuMalloc("%a13S", 1, F);
- testScanfNoGnuMalloc("%alS", 1, F);
-
- testScanf("%5$d", 0);
- testScanf("%md", 0);
- testScanf("%m10s", 0);
-
- testScanfPartial("%d%d%d%d //1\n", 1, 1, I);
- testScanfPartial("%d%d%d%d //2\n", 2, 2, I, I);
- testScanfPartial("%d%d%d%d //3\n", 3, 3, I, I, I);
- testScanfPartial("%d%d%d%d //4\n", 4, 4, I, I, I, I);
-
- testScanfPartial("%d%n%n%d //1\n", 1, 3, I, I, I);
- testScanfPartial("%d%n%n%d //2\n", 2, 4, I, I, I, I);
-
- testScanfPartial("%d%n%n%d %s %s", 3, 5, I, I, I, I, scanf_buf_size);
- testScanfPartial("%d%n%n%d %s %s", 4, 6, I, I, I, I, scanf_buf_size,
- scanf_buf_size);
-}
diff --git a/lib/sanitizer_common/tests/sanitizer_stackdepot_test.cc b/lib/sanitizer_common/tests/sanitizer_stackdepot_test.cc
index 5c075d53ebff..513432fac214 100644
--- a/lib/sanitizer_common/tests/sanitizer_stackdepot_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_stackdepot_test.cc
@@ -18,74 +18,75 @@
namespace __sanitizer {
TEST(SanitizerCommon, StackDepotBasic) {
- uptr s1[] = {1, 2, 3, 4, 5};
- u32 i1 = StackDepotPut(s1, ARRAY_SIZE(s1));
- uptr sz1 = 0;
- const uptr *sp1 = StackDepotGet(i1, &sz1);
- EXPECT_NE(sp1, (uptr*)0);
- EXPECT_EQ(sz1, ARRAY_SIZE(s1));
- EXPECT_EQ(internal_memcmp(sp1, s1, sizeof(s1)), 0);
+ uptr array[] = {1, 2, 3, 4, 5};
+ StackTrace s1(array, ARRAY_SIZE(array));
+ u32 i1 = StackDepotPut(s1);
+ StackTrace stack = StackDepotGet(i1);
+ EXPECT_NE(stack.trace, (uptr*)0);
+ EXPECT_EQ(ARRAY_SIZE(array), stack.size);
+ EXPECT_EQ(0, internal_memcmp(stack.trace, array, sizeof(array)));
}
TEST(SanitizerCommon, StackDepotAbsent) {
- uptr sz1 = 0;
- const uptr *sp1 = StackDepotGet((1 << 30) - 1, &sz1);
- EXPECT_EQ(sp1, (uptr*)0);
+ StackTrace stack = StackDepotGet((1 << 30) - 1);
+ EXPECT_EQ((uptr*)0, stack.trace);
}
TEST(SanitizerCommon, StackDepotEmptyStack) {
- u32 i1 = StackDepotPut(0, 0);
- uptr sz1 = 0;
- const uptr *sp1 = StackDepotGet(i1, &sz1);
- EXPECT_EQ(sp1, (uptr*)0);
+ u32 i1 = StackDepotPut(StackTrace());
+ StackTrace stack = StackDepotGet(i1);
+ EXPECT_EQ((uptr*)0, stack.trace);
}
TEST(SanitizerCommon, StackDepotZeroId) {
- uptr sz1 = 0;
- const uptr *sp1 = StackDepotGet(0, &sz1);
- EXPECT_EQ(sp1, (uptr*)0);
+ StackTrace stack = StackDepotGet(0);
+ EXPECT_EQ((uptr*)0, stack.trace);
}
TEST(SanitizerCommon, StackDepotSame) {
- uptr s1[] = {1, 2, 3, 4, 6};
- u32 i1 = StackDepotPut(s1, ARRAY_SIZE(s1));
- u32 i2 = StackDepotPut(s1, ARRAY_SIZE(s1));
+ uptr array[] = {1, 2, 3, 4, 6};
+ StackTrace s1(array, ARRAY_SIZE(array));
+ u32 i1 = StackDepotPut(s1);
+ u32 i2 = StackDepotPut(s1);
EXPECT_EQ(i1, i2);
- uptr sz1 = 0;
- const uptr *sp1 = StackDepotGet(i1, &sz1);
- EXPECT_NE(sp1, (uptr*)0);
- EXPECT_EQ(sz1, ARRAY_SIZE(s1));
- EXPECT_EQ(internal_memcmp(sp1, s1, sizeof(s1)), 0);
+ StackTrace stack = StackDepotGet(i1);
+ EXPECT_NE(stack.trace, (uptr*)0);
+ EXPECT_EQ(ARRAY_SIZE(array), stack.size);
+ EXPECT_EQ(0, internal_memcmp(stack.trace, array, sizeof(array)));
}
TEST(SanitizerCommon, StackDepotSeveral) {
- uptr s1[] = {1, 2, 3, 4, 7};
- u32 i1 = StackDepotPut(s1, ARRAY_SIZE(s1));
- uptr s2[] = {1, 2, 3, 4, 8, 9};
- u32 i2 = StackDepotPut(s2, ARRAY_SIZE(s2));
+ uptr array1[] = {1, 2, 3, 4, 7};
+ StackTrace s1(array1, ARRAY_SIZE(array1));
+ u32 i1 = StackDepotPut(s1);
+ uptr array2[] = {1, 2, 3, 4, 8, 9};
+ StackTrace s2(array2, ARRAY_SIZE(array2));
+ u32 i2 = StackDepotPut(s2);
EXPECT_NE(i1, i2);
}
TEST(SanitizerCommon, StackDepotReverseMap) {
- uptr s1[] = {1, 2, 3, 4, 5};
- uptr s2[] = {7, 1, 3, 0};
- uptr s3[] = {10, 2, 5, 3};
- uptr s4[] = {1, 3, 2, 5};
+ uptr array1[] = {1, 2, 3, 4, 5};
+ uptr array2[] = {7, 1, 3, 0};
+ uptr array3[] = {10, 2, 5, 3};
+ uptr array4[] = {1, 3, 2, 5};
u32 ids[4] = {0};
- ids[0] = StackDepotPut(s1, ARRAY_SIZE(s1));
- ids[1] = StackDepotPut(s2, ARRAY_SIZE(s2));
- ids[2] = StackDepotPut(s3, ARRAY_SIZE(s3));
- ids[3] = StackDepotPut(s4, ARRAY_SIZE(s4));
+ StackTrace s1(array1, ARRAY_SIZE(array1));
+ StackTrace s2(array2, ARRAY_SIZE(array2));
+ StackTrace s3(array3, ARRAY_SIZE(array3));
+ StackTrace s4(array4, ARRAY_SIZE(array4));
+ ids[0] = StackDepotPut(s1);
+ ids[1] = StackDepotPut(s2);
+ ids[2] = StackDepotPut(s3);
+ ids[3] = StackDepotPut(s4);
StackDepotReverseMap map;
for (uptr i = 0; i < 4; i++) {
- uptr sz_depot, sz_map;
- const uptr *sp_depot, *sp_map;
- sp_depot = StackDepotGet(ids[i], &sz_depot);
- sp_map = map.Get(ids[i], &sz_map);
- EXPECT_EQ(sz_depot, sz_map);
- EXPECT_EQ(sp_depot, sp_map);
+ StackTrace stack = StackDepotGet(ids[i]);
+ StackTrace from_map = map.Get(ids[i]);
+ EXPECT_EQ(stack.size, from_map.size);
+ EXPECT_EQ(stack.trace, from_map.trace);
}
}
diff --git a/lib/sanitizer_common/tests/sanitizer_stacktrace_printer_test.cc b/lib/sanitizer_common/tests/sanitizer_stacktrace_printer_test.cc
new file mode 100644
index 000000000000..cc9a9edbbb46
--- /dev/null
+++ b/lib/sanitizer_common/tests/sanitizer_stacktrace_printer_test.cc
@@ -0,0 +1,122 @@
+//===-- sanitizer_common_printer_test.cc ----------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of sanitizer_common test suite.
+//
+//===----------------------------------------------------------------------===//
+#include "sanitizer_common/sanitizer_stacktrace_printer.h"
+
+#include "gtest/gtest.h"
+
+namespace __sanitizer {
+
+TEST(SanitizerStacktracePrinter, RenderSourceLocation) {
+ InternalScopedString str(128);
+ RenderSourceLocation(&str, "/dir/file.cc", 10, 5, "");
+ EXPECT_STREQ("/dir/file.cc:10:5", str.data());
+
+ str.clear();
+ RenderSourceLocation(&str, "/dir/file.cc", 11, 0, "");
+ EXPECT_STREQ("/dir/file.cc:11", str.data());
+
+ str.clear();
+ RenderSourceLocation(&str, "/dir/file.cc", 0, 0, "");
+ EXPECT_STREQ("/dir/file.cc", str.data());
+
+ str.clear();
+ RenderSourceLocation(&str, "/dir/file.cc", 10, 5, "/dir/");
+ EXPECT_STREQ("file.cc:10:5", str.data());
+}
+
+TEST(SanitizerStacktracePrinter, RenderModuleLocation) {
+ InternalScopedString str(128);
+ RenderModuleLocation(&str, "/dir/exe", 0x123, "");
+ EXPECT_STREQ("(/dir/exe+0x123)", str.data());
+
+ // Check that we strip file prefix if necessary.
+ str.clear();
+ RenderModuleLocation(&str, "/dir/exe", 0x123, "/dir/");
+ EXPECT_STREQ("(exe+0x123)", str.data());
+}
+
+TEST(SanitizerStacktracePrinter, RenderFrame) {
+ int frame_no = 42;
+ AddressInfo info;
+ info.address = 0x400000;
+ info.module = internal_strdup("/path/to/my/module");
+ info.module_offset = 0x200;
+ info.function = internal_strdup("function_foo");
+ info.function_offset = 0x100;
+ info.file = internal_strdup("/path/to/my/source");
+ info.line = 10;
+ info.column = 5;
+ InternalScopedString str(256);
+
+ // Dump all the AddressInfo fields.
+ RenderFrame(&str, "%% Frame:%n PC:%p Module:%m ModuleOffset:%o "
+ "Function:%f FunctionOffset:%q Source:%s Line:%l "
+ "Column:%c",
+ frame_no, info, "/path/to/", "function_");
+ EXPECT_STREQ("% Frame:42 PC:0x400000 Module:my/module ModuleOffset:0x200 "
+ "Function:foo FunctionOffset:0x100 Source:my/source Line:10 "
+ "Column:5",
+ str.data());
+ info.Clear();
+ str.clear();
+
+ // Test special format specifiers.
+ info.address = 0x400000;
+ RenderFrame(&str, "%M", frame_no, info);
+ EXPECT_NE(nullptr, internal_strstr(str.data(), "400000"));
+ str.clear();
+
+ RenderFrame(&str, "%L", frame_no, info);
+ EXPECT_STREQ("(<unknown module>)", str.data());
+ str.clear();
+
+ info.module = internal_strdup("/path/to/module");
+ info.module_offset = 0x200;
+ RenderFrame(&str, "%M", frame_no, info);
+ EXPECT_NE(nullptr, internal_strstr(str.data(), "(module+0x"));
+ EXPECT_NE(nullptr, internal_strstr(str.data(), "200"));
+ str.clear();
+
+ RenderFrame(&str, "%L", frame_no, info);
+ EXPECT_STREQ("(/path/to/module+0x200)", str.data());
+ str.clear();
+
+ info.function = internal_strdup("my_function");
+ RenderFrame(&str, "%F", frame_no, info);
+ EXPECT_STREQ("in my_function", str.data());
+ str.clear();
+
+ info.function_offset = 0x100;
+ RenderFrame(&str, "%F %S", frame_no, info);
+ EXPECT_STREQ("in my_function+0x100 <null>", str.data());
+ str.clear();
+
+ info.file = internal_strdup("my_file");
+ RenderFrame(&str, "%F %S", frame_no, info);
+ EXPECT_STREQ("in my_function my_file", str.data());
+ str.clear();
+
+ info.line = 10;
+ RenderFrame(&str, "%F %S", frame_no, info);
+ EXPECT_STREQ("in my_function my_file:10", str.data());
+ str.clear();
+
+ info.column = 5;
+ RenderFrame(&str, "%S %L", frame_no, info);
+ EXPECT_STREQ("my_file:10:5 my_file:10:5", str.data());
+ str.clear();
+
+ info.Clear();
+}
+
+} // namespace __sanitizer
diff --git a/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc b/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc
index 2b842cd8134a..ac820c25a0f8 100644
--- a/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc
@@ -20,19 +20,22 @@ namespace __sanitizer {
class FastUnwindTest : public ::testing::Test {
protected:
virtual void SetUp();
+ virtual void TearDown();
bool TryFastUnwind(uptr max_depth) {
if (!StackTrace::WillUseFastUnwind(true))
return false;
- trace.Unwind(max_depth, start_pc, (uptr)&fake_stack[0], fake_top,
+ trace.Unwind(max_depth, start_pc, (uptr)&fake_stack[0], 0, fake_top,
fake_bottom, true);
return true;
}
- uptr fake_stack[10];
+ void *mapping;
+ uptr *fake_stack;
+ const uptr fake_stack_size = 10;
uptr start_pc;
uptr fake_top;
uptr fake_bottom;
- StackTrace trace;
+ BufferedStackTrace trace;
};
static uptr PC(uptr idx) {
@@ -40,22 +43,34 @@ static uptr PC(uptr idx) {
}
void FastUnwindTest::SetUp() {
+ size_t ps = GetPageSize();
+ mapping = MmapOrDie(2 * ps, "FastUnwindTest");
+ Mprotect((uptr)mapping, ps);
+
+ // Unwinder may peek 1 word down from the starting FP.
+ fake_stack = (uptr *)((uptr)mapping + ps + sizeof(uptr));
+
// Fill an array of pointers with fake fp+retaddr pairs. Frame pointers have
// even indices.
- for (uptr i = 0; i+1 < ARRAY_SIZE(fake_stack); i += 2) {
+ for (uptr i = 0; i + 1 < fake_stack_size; i += 2) {
fake_stack[i] = (uptr)&fake_stack[i+2]; // fp
fake_stack[i+1] = PC(i + 1); // retaddr
}
- // Mark the last fp as zero to terminate the stack trace.
- fake_stack[RoundDownTo(ARRAY_SIZE(fake_stack) - 1, 2)] = 0;
+ // Mark the last fp point back up to terminate the stack trace.
+ fake_stack[RoundDownTo(fake_stack_size - 1, 2)] = (uptr)&fake_stack[0];
// Top is two slots past the end because FastUnwindStack subtracts two.
- fake_top = (uptr)&fake_stack[ARRAY_SIZE(fake_stack) + 2];
+ fake_top = (uptr)&fake_stack[fake_stack_size + 2];
// Bottom is one slot before the start because FastUnwindStack uses >.
- fake_bottom = (uptr)&fake_stack[-1];
+ fake_bottom = (uptr)mapping;
start_pc = PC(0);
}
+void FastUnwindTest::TearDown() {
+ size_t ps = GetPageSize();
+ UnmapOrDie(mapping, 2 * ps);
+}
+
TEST_F(FastUnwindTest, Basic) {
if (!TryFastUnwind(kStackTraceMax))
return;
@@ -102,4 +117,38 @@ TEST_F(FastUnwindTest, OneFrameStackTrace) {
EXPECT_EQ((uptr)&fake_stack[0], trace.top_frame_bp);
}
+TEST_F(FastUnwindTest, ZeroFramesStackTrace) {
+ if (!TryFastUnwind(0))
+ return;
+ EXPECT_EQ(0U, trace.size);
+ EXPECT_EQ(0U, trace.top_frame_bp);
+}
+
+TEST_F(FastUnwindTest, FPBelowPrevFP) {
+ // The next FP points to unreadable memory inside the stack limits, but below
+ // current FP.
+ fake_stack[0] = (uptr)&fake_stack[-50];
+ fake_stack[1] = PC(1);
+ if (!TryFastUnwind(3))
+ return;
+ EXPECT_EQ(2U, trace.size);
+ EXPECT_EQ(PC(0), trace.trace[0]);
+ EXPECT_EQ(PC(1), trace.trace[1]);
+}
+
+TEST(SlowUnwindTest, ShortStackTrace) {
+ if (StackTrace::WillUseFastUnwind(false))
+ return;
+ BufferedStackTrace stack;
+ uptr pc = StackTrace::GetCurrentPc();
+ uptr bp = GET_CURRENT_FRAME();
+ stack.Unwind(0, pc, bp, 0, 0, 0, false);
+ EXPECT_EQ(0U, stack.size);
+ EXPECT_EQ(0U, stack.top_frame_bp);
+ stack.Unwind(1, pc, bp, 0, 0, 0, false);
+ EXPECT_EQ(1U, stack.size);
+ EXPECT_EQ(pc, stack.trace[0]);
+ EXPECT_EQ(bp, stack.top_frame_bp);
+}
+
} // namespace __sanitizer
diff --git a/lib/sanitizer_common/tests/sanitizer_suppressions_test.cc b/lib/sanitizer_common/tests/sanitizer_suppressions_test.cc
index ea8741d4f01a..0699243283df 100644
--- a/lib/sanitizer_common/tests/sanitizer_suppressions_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_suppressions_test.cc
@@ -66,9 +66,21 @@ TEST(Suppressions, TypeStrings) {
CHECK(!internal_strcmp(SuppressionTypeString(SuppressionSignal), "signal"));
CHECK(!internal_strcmp(SuppressionTypeString(SuppressionLeak), "leak"));
CHECK(!internal_strcmp(SuppressionTypeString(SuppressionLib),
- "called_from_lib"));
+ "called_from_lib"));
+ CHECK(
+ !internal_strcmp(SuppressionTypeString(SuppressionDeadlock), "deadlock"));
+ CHECK(!internal_strcmp(SuppressionTypeString(SuppressionVptrCheck),
+ "vptr_check"));
+ CHECK(!internal_strcmp(SuppressionTypeString(SuppressionInterceptorName),
+ "interceptor_name"));
+ CHECK(
+ !internal_strcmp(SuppressionTypeString(SuppressionInterceptorViaFunction),
+ "interceptor_via_fun"));
+ CHECK(
+ !internal_strcmp(SuppressionTypeString(SuppressionInterceptorViaLibrary),
+ "interceptor_via_lib"));
// Ensure this test is up-to-date when suppression types are added.
- CHECK_EQ(SuppressionTypeCount, 7);
+ CHECK_EQ(12, SuppressionTypeCount);
}
class SuppressionContextTest : public ::testing::Test {
@@ -149,4 +161,14 @@ TEST_F(SuppressionContextTest, ParseType) {
EXPECT_EQ(0, strcmp((*Suppressions())[0].templ, "foo"));
}
+TEST_F(SuppressionContextTest, HasSuppressionType) {
+ ctx_->Parse(
+ "race:foo\n"
+ "thread:bar\n");
+ EXPECT_TRUE(ctx_->HasSuppressionType(SuppressionRace));
+ EXPECT_TRUE(ctx_->HasSuppressionType(SuppressionThread));
+ EXPECT_FALSE(ctx_->HasSuppressionType(SuppressionMutex));
+ EXPECT_FALSE(ctx_->HasSuppressionType(SuppressionSignal));
+}
+
} // namespace __sanitizer
diff --git a/lib/sanitizer_common/tests/sanitizer_test_config.h b/lib/sanitizer_common/tests/sanitizer_test_config.h
new file mode 100644
index 000000000000..bdf614606d6a
--- /dev/null
+++ b/lib/sanitizer_common/tests/sanitizer_test_config.h
@@ -0,0 +1,30 @@
+//===-- sanitizer_test_config.h ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of *Sanitizer runtime.
+//
+//===----------------------------------------------------------------------===//
+#if !defined(INCLUDED_FROM_SANITIZER_TEST_UTILS_H)
+# error "This file should be included into sanitizer_test_utils.h only"
+#endif
+
+#ifndef SANITIZER_TEST_CONFIG_H
+#define SANITIZER_TEST_CONFIG_H
+
+#include <vector>
+#include <string>
+#include <map>
+
+#if SANITIZER_USE_DEJAGNU_GTEST
+# include "dejagnu-gtest.h"
+#else
+# include "gtest/gtest.h"
+#endif
+
+#endif // SANITIZER_TEST_CONFIG_H
diff --git a/lib/sanitizer_common/tests/sanitizer_test_utils.h b/lib/sanitizer_common/tests/sanitizer_test_utils.h
index 17adb2647656..64db37f341d3 100644
--- a/lib/sanitizer_common/tests/sanitizer_test_utils.h
+++ b/lib/sanitizer_common/tests/sanitizer_test_utils.h
@@ -16,21 +16,34 @@
#define SANITIZER_TEST_UTILS_H
#if defined(_WIN32)
-typedef unsigned __int8 uint8_t;
-typedef unsigned __int16 uint16_t;
-typedef unsigned __int32 uint32_t;
-typedef unsigned __int64 uint64_t;
-typedef __int8 int8_t;
-typedef __int16 int16_t;
-typedef __int32 int32_t;
-typedef __int64 int64_t;
+// <windows.h> should always be the first include on Windows.
+# include <windows.h>
+// MSVS headers define max/min as macros, so std::max/min gets crazy.
+# undef max
+# undef min
+#endif
+
+#if !defined(SANITIZER_EXTERNAL_TEST_CONFIG)
+# define INCLUDED_FROM_SANITIZER_TEST_UTILS_H
+# include "sanitizer_test_config.h"
+# undef INCLUDED_FROM_SANITIZER_TEST_UTILS_H
+#endif
+
+#include <stdint.h>
+
+#if defined(_MSC_VER)
# define NOINLINE __declspec(noinline)
-# define USED
-#else // defined(_WIN32)
+#else // defined(_MSC_VER)
# define NOINLINE __attribute__((noinline))
+#endif // defined(_MSC_VER)
+
+#if !defined(_MSC_VER) || defined(__clang__)
+# define UNUSED __attribute__((unused))
# define USED __attribute__((used))
-#include <stdint.h>
-#endif // defined(_WIN32)
+#else
+# define UNUSED
+# define USED
+#endif
#if !defined(__has_feature)
#define __has_feature(x) 0
@@ -53,7 +66,9 @@ typedef __int64 int64_t;
// Make the compiler thinks that something is going on there.
inline void break_optimization(void *arg) {
+#if !defined(_WIN32) || defined(__clang__)
__asm__ __volatile__("" : : "r" (arg) : "memory");
+#endif
}
// This function returns its parameter but in such a way that compiler
@@ -78,5 +93,29 @@ static inline uint32_t my_rand() {
return my_rand_r(&global_seed);
}
+// Set availability of platform-specific functions.
+
+#if !defined(__APPLE__) && !defined(__ANDROID__) && !defined(_WIN32)
+# define SANITIZER_TEST_HAS_POSIX_MEMALIGN 1
+#else
+# define SANITIZER_TEST_HAS_POSIX_MEMALIGN 0
+#endif
+
+#if !defined(__APPLE__) && !defined(__FreeBSD__) && \
+ !defined(__ANDROID__) && !defined(_WIN32)
+# define SANITIZER_TEST_HAS_MEMALIGN 1
+# define SANITIZER_TEST_HAS_PVALLOC 1
+# define SANITIZER_TEST_HAS_MALLOC_USABLE_SIZE 1
+#else
+# define SANITIZER_TEST_HAS_MEMALIGN 0
+# define SANITIZER_TEST_HAS_PVALLOC 0
+# define SANITIZER_TEST_HAS_MALLOC_USABLE_SIZE 0
+#endif
+
+#if !defined(__APPLE__)
+# define SANITIZER_TEST_HAS_STRNLEN 1
+#else
+# define SANITIZER_TEST_HAS_STRNLEN 0
+#endif
#endif // SANITIZER_TEST_UTILS_H
diff --git a/lib/sanitizer_common/tests/sanitizer_thread_registry_test.cc b/lib/sanitizer_common/tests/sanitizer_thread_registry_test.cc
index ddc8dba5d3e0..58c627a704ff 100644
--- a/lib/sanitizer_common/tests/sanitizer_thread_registry_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_thread_registry_test.cc
@@ -11,6 +11,9 @@
//
//===----------------------------------------------------------------------===//
#include "sanitizer_common/sanitizer_thread_registry.h"
+
+#include "sanitizer_pthread_wrappers.h"
+
#include "gtest/gtest.h"
#include <vector>
@@ -48,7 +51,7 @@ static uptr get_uid(u32 tid) {
static bool HasName(ThreadContextBase *tctx, void *arg) {
char *name = (char*)arg;
- return (tctx->name && 0 == internal_strcmp(tctx->name, name));
+ return (0 == internal_strcmp(tctx->name, name));
}
static bool HasUid(ThreadContextBase *tctx, void *arg) {
@@ -104,13 +107,13 @@ static void TestRegistry(ThreadRegistry *registry, bool has_quarantine) {
registry->FindThread(HasUid, (void*)0x1234));
// Detach and finish and join remaining threads.
for (u32 i = 6; i <= 10; i++) {
- registry->DetachThread(i);
+ registry->DetachThread(i, 0);
registry->FinishThread(i);
}
for (u32 i = 0; i < new_tids.size(); i++) {
u32 tid = new_tids[i];
registry->StartThread(tid, 0, 0);
- registry->DetachThread(tid);
+ registry->DetachThread(tid, 0);
registry->FinishThread(tid);
}
CheckThreadQuantity(registry, exp_total, 1, 1);
@@ -203,10 +206,10 @@ static void ThreadedTestRegistry(ThreadRegistry *registry) {
for (int i = 0; i < kNumShards; i++) {
args[i].registry = registry;
args[i].shard = i + 1;
- pthread_create(&threads[i], 0, RunThread, &args[i]);
+ PTHREAD_CREATE(&threads[i], 0, RunThread, &args[i]);
}
for (int i = 0; i < kNumShards; i++) {
- pthread_join(threads[i], 0);
+ PTHREAD_JOIN(threads[i], 0);
}
// Check that each thread created/started/joined correct amount
// of "threads" in thread_registry.
diff --git a/lib/subdf3.c b/lib/subdf3.c
deleted file mode 100644
index 66fb1a54fca1..000000000000
--- a/lib/subdf3.c
+++ /dev/null
@@ -1,29 +0,0 @@
-//===-- lib/adddf3.c - Double-precision subtraction ---------------*- 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 double-precision soft-float subtraction with the
-// IEEE-754 default rounding (to nearest, ties to even).
-//
-//===----------------------------------------------------------------------===//
-
-#define DOUBLE_PRECISION
-#include "fp_lib.h"
-
-fp_t COMPILER_RT_ABI __adddf3(fp_t a, fp_t b);
-
-
-ARM_EABI_FNALIAS(dsub, subdf3)
-
-// Subtraction; flip the sign bit of b and add.
-COMPILER_RT_ABI fp_t
-__subdf3(fp_t a, fp_t b) {
- return __adddf3(a, fromRep(toRep(b) ^ signBit));
-}
-
-/* FIXME: rsub for ARM EABI */
diff --git a/lib/subsf3.c b/lib/subsf3.c
deleted file mode 100644
index 3659cd8b8222..000000000000
--- a/lib/subsf3.c
+++ /dev/null
@@ -1,28 +0,0 @@
-//===-- lib/subsf3.c - Single-precision subtraction ---------------*- 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 single-precision soft-float subtraction with the
-// IEEE-754 default rounding (to nearest, ties to even).
-//
-//===----------------------------------------------------------------------===//
-
-#define SINGLE_PRECISION
-#include "fp_lib.h"
-
-fp_t COMPILER_RT_ABI __addsf3(fp_t a, fp_t b);
-
-ARM_EABI_FNALIAS(fsub, subsf3)
-
-// Subtraction; flip the sign bit of b and add.
-COMPILER_RT_ABI fp_t
-__subsf3(fp_t a, fp_t b) {
- return __addsf3(a, fromRep(toRep(b) ^ signBit));
-}
-
-/* FIXME: rsub for ARM EABI */
diff --git a/lib/subvdi3.c b/lib/subvdi3.c
deleted file mode 100644
index 0f1f924effc7..000000000000
--- a/lib/subvdi3.c
+++ /dev/null
@@ -1,36 +0,0 @@
-/* ===-- subvdi3.c - Implement __subvdi3 -----------------------------------===
- *
- * 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 __subvdi3 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-/* Returns: a - b */
-
-/* Effects: aborts if a - b overflows */
-
-COMPILER_RT_ABI di_int
-__subvdi3(di_int a, di_int b)
-{
- di_int s = a - b;
- if (b >= 0)
- {
- if (s > a)
- compilerrt_abort();
- }
- else
- {
- if (s <= a)
- compilerrt_abort();
- }
- return s;
-}
diff --git a/lib/subvsi3.c b/lib/subvsi3.c
deleted file mode 100644
index ec4594c9f0e9..000000000000
--- a/lib/subvsi3.c
+++ /dev/null
@@ -1,36 +0,0 @@
-/* ===-- subvsi3.c - Implement __subvsi3 -----------------------------------===
- *
- * 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 __subvsi3 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-/* Returns: a - b */
-
-/* Effects: aborts if a - b overflows */
-
-COMPILER_RT_ABI si_int
-__subvsi3(si_int a, si_int b)
-{
- si_int s = a - b;
- if (b >= 0)
- {
- if (s > a)
- compilerrt_abort();
- }
- else
- {
- if (s <= a)
- compilerrt_abort();
- }
- return s;
-}
diff --git a/lib/subvti3.c b/lib/subvti3.c
deleted file mode 100644
index b32df5e6c7e9..000000000000
--- a/lib/subvti3.c
+++ /dev/null
@@ -1,40 +0,0 @@
-/* ===-- subvti3.c - Implement __subvti3 -----------------------------------===
- *
- * 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 __subvti3 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-#if __x86_64
-
-/* Returns: a - b */
-
-/* Effects: aborts if a - b overflows */
-
-ti_int
-__subvti3(ti_int a, ti_int b)
-{
- ti_int s = a - b;
- if (b >= 0)
- {
- if (s > a)
- compilerrt_abort();
- }
- else
- {
- if (s <= a)
- compilerrt_abort();
- }
- return s;
-}
-
-#endif /* __x86_64 */
diff --git a/lib/trampoline_setup.c b/lib/trampoline_setup.c
deleted file mode 100644
index e0765b16b0b0..000000000000
--- a/lib/trampoline_setup.c
+++ /dev/null
@@ -1,47 +0,0 @@
-/* ===----- trampoline_setup.c - Implement __trampoline_setup -------------===
- *
- * 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 "int_lib.h"
-
-extern void __clear_cache(void* start, void* end);
-
-/*
- * The ppc compiler generates calls to __trampoline_setup() when creating
- * trampoline functions on the stack for use with nested functions.
- * This function creates a custom 40-byte trampoline function on the stack
- * which loads r11 with a pointer to the outer function's locals
- * and then jumps to the target nested function.
- */
-
-#if __ppc__ && !defined(__powerpc64__)
-void __trampoline_setup(uint32_t* trampOnStack, int trampSizeAllocated,
- const void* realFunc, void* localsPtr)
-{
- /* should never happen, but if compiler did not allocate */
- /* enough space on stack for the trampoline, abort */
- if ( trampSizeAllocated < 40 )
- compilerrt_abort();
-
- /* create trampoline */
- trampOnStack[0] = 0x7c0802a6; /* mflr r0 */
- trampOnStack[1] = 0x4800000d; /* bl Lbase */
- trampOnStack[2] = (uint32_t)realFunc;
- trampOnStack[3] = (uint32_t)localsPtr;
- trampOnStack[4] = 0x7d6802a6; /* Lbase: mflr r11 */
- trampOnStack[5] = 0x818b0000; /* lwz r12,0(r11) */
- trampOnStack[6] = 0x7c0803a6; /* mtlr r0 */
- trampOnStack[7] = 0x7d8903a6; /* mtctr r12 */
- trampOnStack[8] = 0x816b0004; /* lwz r11,4(r11) */
- trampOnStack[9] = 0x4e800420; /* bctr */
-
- /* clear instruction cache */
- __clear_cache(trampOnStack, &trampOnStack[10]);
-}
-#endif /* __ppc__ && !defined(__powerpc64__) */
diff --git a/lib/truncdfsf2.c b/lib/truncdfsf2.c
deleted file mode 100644
index 61c909a22d8a..000000000000
--- a/lib/truncdfsf2.c
+++ /dev/null
@@ -1,168 +0,0 @@
-//===-- lib/truncdfsf2.c - double -> single 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 a fairly generic conversion from a wider to a narrower
-// IEEE-754 floating-point type in the default (round to nearest, ties to even)
-// rounding mode. The constants and types defined following the includes below
-// parameterize the conversion.
-//
-// This routine can be trivially adapted to support conversions to
-// half-precision or from quad-precision. It does not support types that don't
-// use the usual IEEE-754 interchange formats; specifically, some work would be
-// needed to adapt it to (for example) the Intel 80-bit format or PowerPC
-// double-double format.
-//
-// Note please, however, that this implementation is only intended to support
-// *narrowing* operations; if you need to convert to a *wider* floating-point
-// type (e.g. float -> double), then this routine will not do what you want it
-// to.
-//
-// It also requires that integer types at least as large as both formats
-// are available on the target platform; this may pose a problem when trying
-// to add support for quad on some 32-bit systems, for example.
-//
-// Finally, the following assumptions are made:
-//
-// 1. floating-point types and integer types have the same endianness on the
-// target platform
-//
-// 2. quiet NaNs, if supported, are indicated by the leading bit of the
-// significand field being set
-//
-//===----------------------------------------------------------------------===//
-
-#include "int_lib.h"
-
-typedef double src_t;
-typedef uint64_t src_rep_t;
-#define SRC_REP_C UINT64_C
-static const int srcSigBits = 52;
-
-typedef float dst_t;
-typedef uint32_t dst_rep_t;
-#define DST_REP_C UINT32_C
-static const int dstSigBits = 23;
-
-// 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) {
- const union { src_t f; src_rep_t i; } rep = {.f = x};
- return rep.i;
-}
-
-static inline dst_t dstFromRep(dst_rep_t x) {
- const union { dst_t f; dst_rep_t i; } rep = {.i = x};
- return rep.f;
-}
-
-// End helper routines. Conversion implementation follows.
-
-ARM_EABI_FNALIAS(d2f, truncdfsf2)
-
-COMPILER_RT_ABI dst_t
-__truncdfsf2(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;
- const int srcExpBits = srcBits - srcSigBits - 1;
- const int srcInfExp = (1 << srcExpBits) - 1;
- const int srcExpBias = srcInfExp >> 1;
-
- const src_rep_t srcMinNormal = SRC_REP_C(1) << srcSigBits;
- const src_rep_t significandMask = srcMinNormal - 1;
- const src_rep_t srcInfinity = (src_rep_t)srcInfExp << srcSigBits;
- const src_rep_t srcSignMask = SRC_REP_C(1) << (srcSigBits + srcExpBits);
- const src_rep_t srcAbsMask = srcSignMask - 1;
- const src_rep_t roundMask = (SRC_REP_C(1) << (srcSigBits - dstSigBits)) - 1;
- const src_rep_t halfway = SRC_REP_C(1) << (srcSigBits - dstSigBits - 1);
-
- const int dstBits = sizeof(dst_t)*CHAR_BIT;
- const int dstExpBits = dstBits - dstSigBits - 1;
- const int dstInfExp = (1 << dstExpBits) - 1;
- const int dstExpBias = dstInfExp >> 1;
-
- const int underflowExponent = srcExpBias + 1 - dstExpBias;
- const int overflowExponent = srcExpBias + dstInfExp - dstExpBias;
- const src_rep_t underflow = (src_rep_t)underflowExponent << srcSigBits;
- const src_rep_t overflow = (src_rep_t)overflowExponent << srcSigBits;
-
- const dst_rep_t dstQNaN = DST_REP_C(1) << (dstSigBits - 1);
- const dst_rep_t dstNaNCode = dstQNaN - 1;
-
- // Break a into a sign and representation of the absolute value
- const src_rep_t aRep = srcToRep(a);
- const src_rep_t aAbs = aRep & srcAbsMask;
- const src_rep_t sign = aRep & srcSignMask;
- dst_rep_t absResult;
-
- if (aAbs - underflow < aAbs - overflow) {
- // The exponent of a is within the range of normal numbers in the
- // destination format. We can convert by simply right-shifting with
- // rounding and adjusting the exponent.
- absResult = aAbs >> (srcSigBits - dstSigBits);
- absResult -= (dst_rep_t)(srcExpBias - dstExpBias) << dstSigBits;
-
- const src_rep_t roundBits = aAbs & roundMask;
-
- // Round to nearest
- if (roundBits > halfway)
- absResult++;
-
- // Ties to even
- else if (roundBits == halfway)
- absResult += absResult & 1;
- }
-
- else if (aAbs > srcInfinity) {
- // a is NaN.
- // Conjure the result by beginning with infinity, setting the qNaN
- // bit and inserting the (truncated) trailing NaN field.
- absResult = (dst_rep_t)dstInfExp << dstSigBits;
- absResult |= dstQNaN;
- absResult |= aAbs & dstNaNCode;
- }
-
- else if (aAbs > overflow) {
- // a overflows to infinity.
- absResult = (dst_rep_t)dstInfExp << dstSigBits;
- }
-
- else {
- // a underflows on conversion to the destination type or is an exact
- // zero. The result may be a denormal or zero. Extract the exponent
- // to get the shift amount for the denormalization.
- const int aExp = aAbs >> srcSigBits;
- const int shift = srcExpBias - dstExpBias - aExp + 1;
-
- const src_rep_t significand = (aRep & significandMask) | srcMinNormal;
-
- // Right shift by the denormalization amount with sticky.
- if (shift > srcSigBits) {
- absResult = 0;
- } else {
- const bool sticky = significand << (srcBits - shift);
- src_rep_t denormalizedSignificand = significand >> shift | sticky;
- absResult = denormalizedSignificand >> (srcSigBits - dstSigBits);
- const src_rep_t roundBits = denormalizedSignificand & roundMask;
- // Round to nearest
- if (roundBits > halfway)
- absResult++;
- // Ties to even
- else if (roundBits == halfway)
- absResult += absResult & 1;
- }
- }
-
- // Apply the signbit to (dst_t)abs(a).
- const dst_rep_t result = absResult | sign >> (srcBits - dstBits);
- return dstFromRep(result);
-
-}
diff --git a/lib/tsan/CMakeLists.txt b/lib/tsan/CMakeLists.txt
index fc1944b02fa5..deaabc2380fd 100644
--- a/lib/tsan/CMakeLists.txt
+++ b/lib/tsan/CMakeLists.txt
@@ -2,31 +2,22 @@
include_directories(..)
+set(TSAN_CFLAGS ${SANITIZER_COMMON_CFLAGS})
# SANITIZER_COMMON_CFLAGS contains -fPIC, but it's performance-critical for
# TSan runtime to be built with -fPIE to reduce the number of register spills.
-set(TSAN_CFLAGS
- ${SANITIZER_COMMON_CFLAGS}
- -fPIE
- -fno-rtti)
+append_list_if(COMPILER_RT_HAS_FPIE_FLAG -fPIE TSAN_CFLAGS)
+append_no_rtti_flag(TSAN_CFLAGS)
-set(TSAN_RTL_CFLAGS
- ${TSAN_CFLAGS}
- -Wframe-larger-than=512)
-if(SUPPORTS_GLOBAL_CONSTRUCTORS_FLAG)
- list(APPEND TSAN_RTL_CFLAGS -Wglobal-constructors)
-endif()
+set(TSAN_RTL_CFLAGS ${TSAN_CFLAGS})
+append_list_if(COMPILER_RT_HAS_WFRAME_LARGER_THAN_FLAG -Wframe-larger-than=512 TSAN_RTL_CFLAGS)
+append_list_if(COMPILER_RT_HAS_WGLOBAL_CONSTRUCTORS_FLAG -Wglobal-constructors TSAN_RTL_CFLAGS)
# FIXME: Add support for --sysroot=. compile flag:
-if("${CMAKE_BUILD_TYPE}" EQUAL "Release")
- set(TSAN_COMMON_DEFINITIONS DEBUG=0)
-else()
- set(TSAN_COMMON_DEFINITIONS DEBUG=1)
-endif()
-
set(TSAN_SOURCES
rtl/tsan_clock.cc
rtl/tsan_flags.cc
rtl/tsan_fd.cc
+ rtl/tsan_ignoreset.cc
rtl/tsan_interceptors.cc
rtl/tsan_interface_ann.cc
rtl/tsan_interface_atomic.cc
@@ -41,6 +32,7 @@ set(TSAN_SOURCES
rtl/tsan_rtl_mutex.cc
rtl/tsan_rtl_report.cc
rtl/tsan_rtl_thread.cc
+ rtl/tsan_stack_trace.cc
rtl/tsan_stat.cc
rtl/tsan_suppressions.cc
rtl/tsan_symbolize.cc
@@ -51,11 +43,37 @@ if(APPLE)
elseif(UNIX)
# Assume Linux
list(APPEND TSAN_SOURCES
- rtl/tsan_platform_linux.cc
- rtl/tsan_symbolize_addr2line_linux.cc)
+ rtl/tsan_platform_linux.cc)
endif()
+set(TSAN_HEADERS
+ rtl/tsan_clock.h
+ rtl/tsan_defs.h
+ rtl/tsan_dense_alloc.h
+ rtl/tsan_fd.h
+ rtl/tsan_flags.h
+ rtl/tsan_ignoreset.h
+ rtl/tsan_interface_ann.h
+ rtl/tsan_interface.h
+ rtl/tsan_interface_inl.h
+ rtl/tsan_interface_java.h
+ rtl/tsan_mman.h
+ rtl/tsan_mutex.h
+ rtl/tsan_mutexset.h
+ rtl/tsan_platform.h
+ rtl/tsan_report.h
+ rtl/tsan_rtl.h
+ rtl/tsan_stack_trace.h
+ rtl/tsan_stat.h
+ rtl/tsan_suppressions.h
+ rtl/tsan_symbolize.h
+ rtl/tsan_sync.h
+ rtl/tsan_trace.h
+ rtl/tsan_update_shadow_word_inl.h
+ rtl/tsan_vector.h)
+
set(TSAN_RUNTIME_LIBRARIES)
+add_custom_target(tsan)
# TSan is currently supported on 64-bit Linux only.
if(CAN_TARGET_x86_64 AND UNIX AND NOT APPLE)
set(TSAN_ASM_SOURCES rtl/tsan_rtl_amd64.S)
@@ -63,19 +81,31 @@ if(CAN_TARGET_x86_64 AND UNIX AND NOT APPLE)
set_source_files_properties(${TSAN_ASM_SOURCES} PROPERTIES
LANGUAGE C)
set(arch "x86_64")
- add_compiler_rt_static_runtime(clang_rt.tsan-${arch} ${arch}
+ add_compiler_rt_runtime(clang_rt.tsan-${arch} ${arch} STATIC
SOURCES ${TSAN_SOURCES} ${TSAN_ASM_SOURCES}
$<TARGET_OBJECTS:RTInterception.${arch}>
$<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
$<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>
CFLAGS ${TSAN_RTL_CFLAGS}
DEFS ${TSAN_COMMON_DEFINITIONS})
+ list(APPEND TSAN_RUNTIME_LIBRARIES clang_rt.tsan-${arch})
add_sanitizer_rt_symbols(clang_rt.tsan-${arch} rtl/tsan.syms.extra)
- list(APPEND TSAN_RUNTIME_LIBRARIES clang_rt.tsan-${arch}
+ add_dependencies(tsan clang_rt.tsan-${arch}
clang_rt.tsan-${arch}-symbols)
endif()
-if(LLVM_INCLUDE_TESTS)
+add_dependencies(compiler-rt tsan)
+
+# Build libcxx instrumented with TSan.
+if(TSAN_SUPPORTED_ARCH AND
+ COMPILER_RT_HAS_LIBCXX_SOURCES AND
+ COMPILER_RT_TEST_COMPILER_ID STREQUAL "Clang")
+ set(LIBCXX_PREFIX ${CMAKE_CURRENT_BINARY_DIR}/libcxx_tsan)
+ add_custom_libcxx(libcxx_tsan ${LIBCXX_PREFIX}
+ DEPS ${TSAN_RUNTIME_LIBRARIES}
+ CFLAGS -fsanitize=thread)
+endif()
+
+if(COMPILER_RT_INCLUDE_TESTS)
add_subdirectory(tests)
endif()
-add_subdirectory(lit_tests)
diff --git a/lib/tsan/Makefile.old b/lib/tsan/Makefile.old
index c10d49842cac..b982e663a0cf 100644
--- a/lib/tsan/Makefile.old
+++ b/lib/tsan/Makefile.old
@@ -1,6 +1,6 @@
DEBUG=0
-LDFLAGS=-ldl -lpthread -pie
-CXXFLAGS = -fPIE -fno-rtti -g -Wall -Werror \
+LDFLAGS=-ldl -lrt -lpthread -pie
+CXXFLAGS = -std=c++11 -fPIE -fno-rtti -g -Wall -Werror \
-DGTEST_HAS_RTTI=0 -DTSAN_DEBUG=$(DEBUG) -DSANITIZER_DEBUG=$(DEBUG)
CLANG=clang
FILECHECK=FileCheck
@@ -31,6 +31,7 @@ RTL_TEST_OBJ=$(patsubst %.cc,%.o,$(RTL_TEST_SRC))
UNIT_TEST_SRC=$(wildcard tests/unit/*_test.cc)
UNIT_TEST_OBJ=$(patsubst %.cc,%.o,$(UNIT_TEST_SRC))
UNIT_TEST_HDR=$(wildcard rtl/*.h) $(wildcard ../sanitizer_common/*.h)
+LIT_TESTS_PATH=../../test/tsan
INCLUDES=-Irtl -I.. -I../../include $(GTEST_INCLUDE)
@@ -60,7 +61,7 @@ test: libtsan tsan_test
run: all
(ulimit -s 8192; ./tsan_test)
- CC=$(CLANG) CXX=$(CLANG)++ FILECHECK=$(FILECHECK) ./lit_tests/test_output.sh
+ CC=$(CLANG) CXX=$(CLANG)++ FILECHECK=$(FILECHECK) $(LIT_TESTS_PATH)/test_output.sh
presubmit:
../sanitizer_common/scripts/check_lint.sh
@@ -70,12 +71,14 @@ presubmit:
# Release build with clang.
$(MAKE) -f Makefile.old clean
$(MAKE) -f Makefile.old run DEBUG=0 -j 16 CC=$(CLANG) CXX=$(CLANG)++
+ ./check_memcpy.sh
# Debug build with gcc
$(MAKE) -f Makefile.old clean
$(MAKE) -f Makefile.old run DEBUG=1 -j 16 CC=gcc CXX=g++
# Release build with gcc
$(MAKE) -f Makefile.old clean
$(MAKE) -f Makefile.old run DEBUG=0 -j 16 CC=gcc CXX=g++
+ ./check_memcpy.sh
./check_analyze.sh
# Sanity check for Go runtime
(cd go && ./buildgo.sh)
diff --git a/lib/tsan/check_analyze.sh b/lib/tsan/check_analyze.sh
index 39d570b97673..08bfc7a76313 100755
--- a/lib/tsan/check_analyze.sh
+++ b/lib/tsan/check_analyze.sh
@@ -8,11 +8,11 @@ PrintRes() {
PrintRes
-mops="write1 \
+wmops="write1 \
write2 \
write4 \
- write8 \
- read1 \
+ write8"
+rmops="read1 \
read2 \
read4 \
read8"
@@ -27,10 +27,16 @@ check() {
fi
}
-for f in $mops; do
- check $f rsp 1 # To read caller pc.
- check $f push 0
- check $f pop 0
+for f in $wmops; do
+ check $f rsp 3
+ check $f push 1
+ check $f pop 5
+done
+
+for f in $rmops; do
+ check $f rsp 3
+ check $f push 1
+ check $f pop 4
done
for f in $func; do
diff --git a/lib/tsan/check_cmake.sh b/lib/tsan/check_cmake.sh
index 7e858efee913..7668c5b49e1a 100755
--- a/lib/tsan/check_cmake.sh
+++ b/lib/tsan/check_cmake.sh
@@ -3,11 +3,11 @@ set -u
set -e
ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
-if [ -d "$ROOT/build" ]; then
- cd $ROOT/build
+if [ -d "$ROOT/llvm-build" ]; then
+ cd $ROOT/llvm-build
else
- mkdir -p $ROOT/build
- cd $ROOT/build
+ mkdir -p $ROOT/llvm-build
+ cd $ROOT/llvm-build
CC=clang CXX=clang++ cmake -G Ninja -DLLVM_ENABLE_WERROR=ON -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_ASSERTIONS=ON $ROOT/../../../..
fi
ninja
diff --git a/lib/tsan/check_memcpy.sh b/lib/tsan/check_memcpy.sh
new file mode 100755
index 000000000000..101df1166b7c
--- /dev/null
+++ b/lib/tsan/check_memcpy.sh
@@ -0,0 +1,31 @@
+#!/bin/bash
+
+# Ensure that tsan runtime does not contain compiler-emitted memcpy and memset calls.
+
+set -eu
+
+ROOTDIR=$(dirname $0)
+TEST_DIR=$ROOTDIR/../../test/tsan
+
+: ${CXX:=clang++}
+CFLAGS="-fsanitize=thread -fPIE -O1 -g"
+LDFLAGS="-pie -lpthread -ldl -lrt -lm -Wl,--whole-archive $ROOTDIR/rtl/libtsan.a -Wl,--no-whole-archive"
+
+SRC=$TEST_DIR/simple_race.cc
+OBJ=$SRC.o
+EXE=$SRC.exe
+$CXX $SRC $CFLAGS -c -o $OBJ
+$CXX $OBJ $LDFLAGS -o $EXE
+
+NCALL=$(objdump -d $EXE | egrep "callq .*<__interceptor_mem(cpy|set)>" | wc -l)
+if [ "$NCALL" != "0" ]; then
+ echo FAIL: found $NCALL memcpy/memset calls
+ exit 1
+fi
+
+# tail calls
+NCALL=$(objdump -d $EXE | egrep "jmpq .*<__interceptor_mem(cpy|set)>" | wc -l)
+if [ "$NCALL" != "0" ]; then
+ echo FAIL: found $NCALL memcpy/memset calls
+ exit 1
+fi
diff --git a/lib/tsan/dd/CMakeLists.txt b/lib/tsan/dd/CMakeLists.txt
new file mode 100644
index 000000000000..981c1fb0bb5e
--- /dev/null
+++ b/lib/tsan/dd/CMakeLists.txt
@@ -0,0 +1,41 @@
+# Build for the experimental deadlock detector runtime library.
+
+include_directories(../..)
+
+set(DD_CFLAGS ${SANITIZER_COMMON_CFLAGS})
+append_no_rtti_flag(DD_CFLAGS)
+
+set(DD_SOURCES
+ dd_rtl.cc
+ dd_interceptors.cc
+)
+
+set(DD_LINKLIBS)
+append_list_if(COMPILER_RT_HAS_LIBDL dl DD_LINKLIBS)
+append_list_if(COMPILER_RT_HAS_LIBPTHREAD pthread DD_LINKLIBS)
+
+add_custom_target(dd)
+# Deadlock detector is currently supported on 64-bit Linux only.
+if(CAN_TARGET_x86_64 AND UNIX AND NOT APPLE AND NOT ANDROID)
+ set(arch "x86_64")
+ add_compiler_rt_runtime(clang_rt.dd-${arch} ${arch} STATIC
+ SOURCES ${DD_SOURCES}
+ $<TARGET_OBJECTS:RTInterception.${arch}>
+ $<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
+ $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>
+ CFLAGS ${DD_CFLAGS})
+ add_dependencies(dd clang_rt.dd-${arch})
+
+ add_compiler_rt_object_library(RTDD ${arch}
+ SOURCES ${DD_SOURCES} CFLAGS ${DD_CFLAGS})
+
+ add_compiler_rt_runtime(clang_rt.dyndd-${arch} ${arch} SHARED
+ SOURCES $<TARGET_OBJECTS:RTDD.${arch}>
+ $<TARGET_OBJECTS:RTInterception.${arch}>
+ $<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
+ $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>)
+ target_link_libraries(clang_rt.dyndd-${arch} ${DD_LINKLIBS})
+ add_dependencies(dd clang_rt.dyndd-${arch})
+endif()
+
+add_dependencies(compiler-rt dd)
diff --git a/lib/tsan/dd/dd_interceptors.cc b/lib/tsan/dd/dd_interceptors.cc
new file mode 100644
index 000000000000..8151f7fd3c67
--- /dev/null
+++ b/lib/tsan/dd/dd_interceptors.cc
@@ -0,0 +1,333 @@
+//===-- dd_interceptors.cc ------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "dd_rtl.h"
+#include "interception/interception.h"
+#include "sanitizer_common/sanitizer_procmaps.h"
+#include <pthread.h>
+#include <stdlib.h>
+
+using namespace __dsan;
+
+extern "C" void *__libc_malloc(uptr size);
+extern "C" void __libc_free(void *ptr);
+
+__attribute__((tls_model("initial-exec")))
+static __thread Thread *thr;
+__attribute__((tls_model("initial-exec")))
+static __thread volatile int initing;
+static bool inited;
+static uptr g_data_start;
+static uptr g_data_end;
+
+static bool InitThread() {
+ if (initing)
+ return false;
+ if (thr != 0)
+ return true;
+ initing = true;
+ if (!inited) {
+ inited = true;
+ Initialize();
+ }
+ thr = (Thread*)InternalAlloc(sizeof(*thr));
+ internal_memset(thr, 0, sizeof(*thr));
+ ThreadInit(thr);
+ initing = false;
+ return true;
+}
+
+INTERCEPTOR(int, pthread_mutex_destroy, pthread_mutex_t *m) {
+ InitThread();
+ MutexDestroy(thr, (uptr)m);
+ return REAL(pthread_mutex_destroy)(m);
+}
+
+INTERCEPTOR(int, pthread_mutex_lock, pthread_mutex_t *m) {
+ InitThread();
+ MutexBeforeLock(thr, (uptr)m, true);
+ int res = REAL(pthread_mutex_lock)(m);
+ MutexAfterLock(thr, (uptr)m, true, false);
+ return res;
+}
+
+INTERCEPTOR(int, pthread_mutex_trylock, pthread_mutex_t *m) {
+ InitThread();
+ int res = REAL(pthread_mutex_trylock)(m);
+ if (res == 0)
+ MutexAfterLock(thr, (uptr)m, true, true);
+ return res;
+}
+
+INTERCEPTOR(int, pthread_mutex_unlock, pthread_mutex_t *m) {
+ InitThread();
+ MutexBeforeUnlock(thr, (uptr)m, true);
+ return REAL(pthread_mutex_unlock)(m);
+}
+
+INTERCEPTOR(int, pthread_spin_destroy, pthread_spinlock_t *m) {
+ InitThread();
+ int res = REAL(pthread_spin_destroy)(m);
+ MutexDestroy(thr, (uptr)m);
+ return res;
+}
+
+INTERCEPTOR(int, pthread_spin_lock, pthread_spinlock_t *m) {
+ InitThread();
+ MutexBeforeLock(thr, (uptr)m, true);
+ int res = REAL(pthread_spin_lock)(m);
+ MutexAfterLock(thr, (uptr)m, true, false);
+ return res;
+}
+
+INTERCEPTOR(int, pthread_spin_trylock, pthread_spinlock_t *m) {
+ InitThread();
+ int res = REAL(pthread_spin_trylock)(m);
+ if (res == 0)
+ MutexAfterLock(thr, (uptr)m, true, true);
+ return res;
+}
+
+INTERCEPTOR(int, pthread_spin_unlock, pthread_spinlock_t *m) {
+ InitThread();
+ MutexBeforeUnlock(thr, (uptr)m, true);
+ return REAL(pthread_spin_unlock)(m);
+}
+
+INTERCEPTOR(int, pthread_rwlock_destroy, pthread_rwlock_t *m) {
+ InitThread();
+ MutexDestroy(thr, (uptr)m);
+ return REAL(pthread_rwlock_destroy)(m);
+}
+
+INTERCEPTOR(int, pthread_rwlock_rdlock, pthread_rwlock_t *m) {
+ InitThread();
+ MutexBeforeLock(thr, (uptr)m, false);
+ int res = REAL(pthread_rwlock_rdlock)(m);
+ MutexAfterLock(thr, (uptr)m, false, false);
+ return res;
+}
+
+INTERCEPTOR(int, pthread_rwlock_tryrdlock, pthread_rwlock_t *m) {
+ InitThread();
+ int res = REAL(pthread_rwlock_tryrdlock)(m);
+ if (res == 0)
+ MutexAfterLock(thr, (uptr)m, false, true);
+ return res;
+}
+
+INTERCEPTOR(int, pthread_rwlock_timedrdlock, pthread_rwlock_t *m,
+ const timespec *abstime) {
+ InitThread();
+ int res = REAL(pthread_rwlock_timedrdlock)(m, abstime);
+ if (res == 0)
+ MutexAfterLock(thr, (uptr)m, false, true);
+ return res;
+}
+
+INTERCEPTOR(int, pthread_rwlock_wrlock, pthread_rwlock_t *m) {
+ InitThread();
+ MutexBeforeLock(thr, (uptr)m, true);
+ int res = REAL(pthread_rwlock_wrlock)(m);
+ MutexAfterLock(thr, (uptr)m, true, false);
+ return res;
+}
+
+INTERCEPTOR(int, pthread_rwlock_trywrlock, pthread_rwlock_t *m) {
+ InitThread();
+ int res = REAL(pthread_rwlock_trywrlock)(m);
+ if (res == 0)
+ MutexAfterLock(thr, (uptr)m, true, true);
+ return res;
+}
+
+INTERCEPTOR(int, pthread_rwlock_timedwrlock, pthread_rwlock_t *m,
+ const timespec *abstime) {
+ InitThread();
+ int res = REAL(pthread_rwlock_timedwrlock)(m, abstime);
+ if (res == 0)
+ MutexAfterLock(thr, (uptr)m, true, true);
+ return res;
+}
+
+INTERCEPTOR(int, pthread_rwlock_unlock, pthread_rwlock_t *m) {
+ InitThread();
+ MutexBeforeUnlock(thr, (uptr)m, true); // note: not necessary write unlock
+ return REAL(pthread_rwlock_unlock)(m);
+}
+
+static pthread_cond_t *init_cond(pthread_cond_t *c, bool force = false) {
+ atomic_uintptr_t *p = (atomic_uintptr_t*)c;
+ uptr cond = atomic_load(p, memory_order_acquire);
+ if (!force && cond != 0)
+ return (pthread_cond_t*)cond;
+ void *newcond = malloc(sizeof(pthread_cond_t));
+ internal_memset(newcond, 0, sizeof(pthread_cond_t));
+ if (atomic_compare_exchange_strong(p, &cond, (uptr)newcond,
+ memory_order_acq_rel))
+ return (pthread_cond_t*)newcond;
+ free(newcond);
+ return (pthread_cond_t*)cond;
+}
+
+INTERCEPTOR(int, pthread_cond_init, pthread_cond_t *c,
+ const pthread_condattr_t *a) {
+ InitThread();
+ pthread_cond_t *cond = init_cond(c, true);
+ return REAL(pthread_cond_init)(cond, a);
+}
+
+INTERCEPTOR(int, pthread_cond_wait, pthread_cond_t *c, pthread_mutex_t *m) {
+ InitThread();
+ pthread_cond_t *cond = init_cond(c);
+ MutexBeforeUnlock(thr, (uptr)m, true);
+ MutexBeforeLock(thr, (uptr)m, true);
+ int res = REAL(pthread_cond_wait)(cond, m);
+ MutexAfterLock(thr, (uptr)m, true, false);
+ return res;
+}
+
+INTERCEPTOR(int, pthread_cond_timedwait, pthread_cond_t *c, pthread_mutex_t *m,
+ const timespec *abstime) {
+ InitThread();
+ pthread_cond_t *cond = init_cond(c);
+ MutexBeforeUnlock(thr, (uptr)m, true);
+ MutexBeforeLock(thr, (uptr)m, true);
+ int res = REAL(pthread_cond_timedwait)(cond, m, abstime);
+ MutexAfterLock(thr, (uptr)m, true, false);
+ return res;
+}
+
+INTERCEPTOR(int, pthread_cond_signal, pthread_cond_t *c) {
+ InitThread();
+ pthread_cond_t *cond = init_cond(c);
+ return REAL(pthread_cond_signal)(cond);
+}
+
+INTERCEPTOR(int, pthread_cond_broadcast, pthread_cond_t *c) {
+ InitThread();
+ pthread_cond_t *cond = init_cond(c);
+ return REAL(pthread_cond_broadcast)(cond);
+}
+
+INTERCEPTOR(int, pthread_cond_destroy, pthread_cond_t *c) {
+ InitThread();
+ pthread_cond_t *cond = init_cond(c);
+ int res = REAL(pthread_cond_destroy)(cond);
+ free(cond);
+ atomic_store((atomic_uintptr_t*)c, 0, memory_order_relaxed);
+ return res;
+}
+
+// for symbolizer
+INTERCEPTOR(char*, realpath, const char *path, char *resolved_path) {
+ InitThread();
+ return REAL(realpath)(path, resolved_path);
+}
+
+INTERCEPTOR(SSIZE_T, read, int fd, void *ptr, SIZE_T count) {
+ InitThread();
+ return REAL(read)(fd, ptr, count);
+}
+
+INTERCEPTOR(SSIZE_T, pread, int fd, void *ptr, SIZE_T count, OFF_T offset) {
+ InitThread();
+ return REAL(pread)(fd, ptr, count, offset);
+}
+
+extern "C" {
+void __dsan_before_mutex_lock(uptr m, int writelock) {
+ if (!InitThread())
+ return;
+ MutexBeforeLock(thr, m, writelock);
+}
+
+void __dsan_after_mutex_lock(uptr m, int writelock, int trylock) {
+ if (!InitThread())
+ return;
+ MutexAfterLock(thr, m, writelock, trylock);
+}
+
+void __dsan_before_mutex_unlock(uptr m, int writelock) {
+ if (!InitThread())
+ return;
+ MutexBeforeUnlock(thr, m, writelock);
+}
+
+void __dsan_mutex_destroy(uptr m) {
+ if (!InitThread())
+ return;
+ // if (m >= g_data_start && m < g_data_end)
+ // return;
+ MutexDestroy(thr, m);
+}
+} // extern "C"
+
+namespace __dsan {
+
+static void InitDataSeg() {
+ MemoryMappingLayout proc_maps(true);
+ uptr start, end, offset;
+ char name[128];
+ bool prev_is_data = false;
+ while (proc_maps.Next(&start, &end, &offset, name, ARRAY_SIZE(name),
+ /*protection*/ 0)) {
+ bool is_data = offset != 0 && name[0] != 0;
+ // BSS may get merged with [heap] in /proc/self/maps. This is not very
+ // reliable.
+ bool is_bss = offset == 0 &&
+ (name[0] == 0 || internal_strcmp(name, "[heap]") == 0) && prev_is_data;
+ if (g_data_start == 0 && is_data)
+ g_data_start = start;
+ if (is_bss)
+ g_data_end = end;
+ prev_is_data = is_data;
+ }
+ VPrintf(1, "guessed data_start=%p data_end=%p\n", g_data_start, g_data_end);
+ CHECK_LT(g_data_start, g_data_end);
+ CHECK_GE((uptr)&g_data_start, g_data_start);
+ CHECK_LT((uptr)&g_data_start, g_data_end);
+}
+
+void InitializeInterceptors() {
+ INTERCEPT_FUNCTION(pthread_mutex_destroy);
+ INTERCEPT_FUNCTION(pthread_mutex_lock);
+ INTERCEPT_FUNCTION(pthread_mutex_trylock);
+ INTERCEPT_FUNCTION(pthread_mutex_unlock);
+
+ INTERCEPT_FUNCTION(pthread_spin_destroy);
+ INTERCEPT_FUNCTION(pthread_spin_lock);
+ INTERCEPT_FUNCTION(pthread_spin_trylock);
+ INTERCEPT_FUNCTION(pthread_spin_unlock);
+
+ INTERCEPT_FUNCTION(pthread_rwlock_destroy);
+ INTERCEPT_FUNCTION(pthread_rwlock_rdlock);
+ INTERCEPT_FUNCTION(pthread_rwlock_tryrdlock);
+ INTERCEPT_FUNCTION(pthread_rwlock_timedrdlock);
+ INTERCEPT_FUNCTION(pthread_rwlock_wrlock);
+ INTERCEPT_FUNCTION(pthread_rwlock_trywrlock);
+ INTERCEPT_FUNCTION(pthread_rwlock_timedwrlock);
+ INTERCEPT_FUNCTION(pthread_rwlock_unlock);
+
+ INTERCEPT_FUNCTION_VER(pthread_cond_init, "GLIBC_2.3.2");
+ INTERCEPT_FUNCTION_VER(pthread_cond_signal, "GLIBC_2.3.2");
+ INTERCEPT_FUNCTION_VER(pthread_cond_broadcast, "GLIBC_2.3.2");
+ INTERCEPT_FUNCTION_VER(pthread_cond_wait, "GLIBC_2.3.2");
+ INTERCEPT_FUNCTION_VER(pthread_cond_timedwait, "GLIBC_2.3.2");
+ INTERCEPT_FUNCTION_VER(pthread_cond_destroy, "GLIBC_2.3.2");
+
+ // for symbolizer
+ INTERCEPT_FUNCTION(realpath);
+ INTERCEPT_FUNCTION(read);
+ INTERCEPT_FUNCTION(pread);
+
+ InitDataSeg();
+}
+
+} // namespace __dsan
diff --git a/lib/tsan/dd/dd_rtl.cc b/lib/tsan/dd/dd_rtl.cc
new file mode 100644
index 000000000000..41b75bf755b8
--- /dev/null
+++ b/lib/tsan/dd/dd_rtl.cc
@@ -0,0 +1,151 @@
+//===-- dd_rtl.cc ---------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "dd_rtl.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_placement_new.h"
+#include "sanitizer_common/sanitizer_flags.h"
+#include "sanitizer_common/sanitizer_stacktrace.h"
+#include "sanitizer_common/sanitizer_stackdepot.h"
+
+namespace __dsan {
+
+static Context *ctx;
+
+static u32 CurrentStackTrace(Thread *thr, uptr skip) {
+ BufferedStackTrace stack;
+ thr->ignore_interceptors = true;
+ stack.Unwind(1000, 0, 0, 0, 0, 0, false);
+ thr->ignore_interceptors = false;
+ if (stack.size <= skip)
+ return 0;
+ return StackDepotPut(StackTrace(stack.trace + skip, stack.size - skip));
+}
+
+static void PrintStackTrace(Thread *thr, u32 stk) {
+ StackTrace stack = StackDepotGet(stk);
+ thr->ignore_interceptors = true;
+ stack.Print();
+ thr->ignore_interceptors = false;
+}
+
+static void ReportDeadlock(Thread *thr, DDReport *rep) {
+ if (rep == 0)
+ return;
+ BlockingMutexLock lock(&ctx->report_mutex);
+ Printf("==============================\n");
+ Printf("WARNING: lock-order-inversion (potential deadlock)\n");
+ for (int i = 0; i < rep->n; i++) {
+ Printf("Thread %d locks mutex %llu while holding mutex %llu:\n",
+ rep->loop[i].thr_ctx, rep->loop[i].mtx_ctx1, rep->loop[i].mtx_ctx0);
+ PrintStackTrace(thr, rep->loop[i].stk[1]);
+ if (rep->loop[i].stk[0]) {
+ Printf("Mutex %llu was acquired here:\n",
+ rep->loop[i].mtx_ctx0);
+ PrintStackTrace(thr, rep->loop[i].stk[0]);
+ }
+ }
+ Printf("==============================\n");
+}
+
+Callback::Callback(Thread *thr)
+ : thr(thr) {
+ lt = thr->dd_lt;
+ pt = thr->dd_pt;
+}
+
+u32 Callback::Unwind() {
+ return CurrentStackTrace(thr, 3);
+}
+
+void InitializeFlags(Flags *f, const char *env) {
+ internal_memset(f, 0, sizeof(*f));
+
+ // Default values.
+ f->second_deadlock_stack = false;
+
+ CommonFlags *cf = common_flags();
+ SetCommonFlagsDefaults(cf);
+ // Override some common flags defaults.
+ cf->allow_addr2line = true;
+
+ // Override from command line.
+ ParseFlag(env, &f->second_deadlock_stack, "second_deadlock_stack", "");
+ ParseCommonFlagsFromString(cf, env);
+}
+
+void Initialize() {
+ static u64 ctx_mem[sizeof(Context) / sizeof(u64) + 1];
+ ctx = new(ctx_mem) Context();
+
+ InitializeInterceptors();
+ InitializeFlags(flags(), GetEnv("DSAN_OPTIONS"));
+ ctx->dd = DDetector::Create(flags());
+}
+
+void ThreadInit(Thread *thr) {
+ static atomic_uintptr_t id_gen;
+ uptr id = atomic_fetch_add(&id_gen, 1, memory_order_relaxed);
+ thr->dd_pt = ctx->dd->CreatePhysicalThread();
+ thr->dd_lt = ctx->dd->CreateLogicalThread(id);
+}
+
+void ThreadDestroy(Thread *thr) {
+ ctx->dd->DestroyPhysicalThread(thr->dd_pt);
+ ctx->dd->DestroyLogicalThread(thr->dd_lt);
+}
+
+void MutexBeforeLock(Thread *thr, uptr m, bool writelock) {
+ if (thr->ignore_interceptors)
+ return;
+ Callback cb(thr);
+ {
+ MutexHashMap::Handle h(&ctx->mutex_map, m);
+ if (h.created())
+ ctx->dd->MutexInit(&cb, &h->dd);
+ ctx->dd->MutexBeforeLock(&cb, &h->dd, writelock);
+ }
+ ReportDeadlock(thr, ctx->dd->GetReport(&cb));
+}
+
+void MutexAfterLock(Thread *thr, uptr m, bool writelock, bool trylock) {
+ if (thr->ignore_interceptors)
+ return;
+ Callback cb(thr);
+ {
+ MutexHashMap::Handle h(&ctx->mutex_map, m);
+ if (h.created())
+ ctx->dd->MutexInit(&cb, &h->dd);
+ ctx->dd->MutexAfterLock(&cb, &h->dd, writelock, trylock);
+ }
+ ReportDeadlock(thr, ctx->dd->GetReport(&cb));
+}
+
+void MutexBeforeUnlock(Thread *thr, uptr m, bool writelock) {
+ if (thr->ignore_interceptors)
+ return;
+ Callback cb(thr);
+ {
+ MutexHashMap::Handle h(&ctx->mutex_map, m);
+ ctx->dd->MutexBeforeUnlock(&cb, &h->dd, writelock);
+ }
+ ReportDeadlock(thr, ctx->dd->GetReport(&cb));
+}
+
+void MutexDestroy(Thread *thr, uptr m) {
+ if (thr->ignore_interceptors)
+ return;
+ Callback cb(thr);
+ MutexHashMap::Handle h(&ctx->mutex_map, m, true);
+ if (!h.exists())
+ return;
+ ctx->dd->MutexDestroy(&cb, &h->dd);
+}
+
+} // namespace __dsan
diff --git a/lib/tsan/dd/dd_rtl.h b/lib/tsan/dd/dd_rtl.h
new file mode 100644
index 000000000000..bb1b20205b54
--- /dev/null
+++ b/lib/tsan/dd/dd_rtl.h
@@ -0,0 +1,67 @@
+//===-- dd_rtl.h ----------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef DD_RTL_H
+#define DD_RTL_H
+
+#include "sanitizer_common/sanitizer_internal_defs.h"
+#include "sanitizer_common/sanitizer_deadlock_detector_interface.h"
+#include "sanitizer_common/sanitizer_flags.h"
+#include "sanitizer_common/sanitizer_allocator_internal.h"
+#include "sanitizer_common/sanitizer_addrhashmap.h"
+#include "sanitizer_common/sanitizer_mutex.h"
+
+namespace __dsan {
+
+typedef DDFlags Flags;
+
+struct Mutex {
+ DDMutex dd;
+};
+
+struct Thread {
+ DDPhysicalThread *dd_pt;
+ DDLogicalThread *dd_lt;
+
+ bool ignore_interceptors;
+};
+
+struct Callback : DDCallback {
+ Thread *thr;
+
+ Callback(Thread *thr);
+ virtual u32 Unwind();
+};
+
+typedef AddrHashMap<Mutex, 31051> MutexHashMap;
+
+struct Context {
+ DDetector *dd;
+
+ BlockingMutex report_mutex;
+ MutexHashMap mutex_map;
+};
+
+inline Flags* flags() {
+ static Flags flags;
+ return &flags;
+}
+
+void Initialize();
+void InitializeInterceptors();
+
+void ThreadInit(Thread *thr);
+void ThreadDestroy(Thread *thr);
+
+void MutexBeforeLock(Thread *thr, uptr m, bool writelock);
+void MutexAfterLock(Thread *thr, uptr m, bool writelock, bool trylock);
+void MutexBeforeUnlock(Thread *thr, uptr m, bool writelock);
+void MutexDestroy(Thread *thr, uptr m);
+
+} // namespace __dsan
+#endif // DD_RTL_H
diff --git a/lib/tsan/go/build.bat b/lib/tsan/go/build.bat
new file mode 100644
index 000000000000..8f8087fc6352
--- /dev/null
+++ b/lib/tsan/go/build.bat
@@ -0,0 +1,4 @@
+type tsan_go.cc ..\rtl\tsan_interface_atomic.cc ..\rtl\tsan_clock.cc ..\rtl\tsan_flags.cc ..\rtl\tsan_md5.cc ..\rtl\tsan_mutex.cc ..\rtl\tsan_report.cc ..\rtl\tsan_rtl.cc ..\rtl\tsan_rtl_mutex.cc ..\rtl\tsan_rtl_report.cc ..\rtl\tsan_rtl_thread.cc ..\rtl\tsan_stat.cc ..\rtl\tsan_suppressions.cc ..\rtl\tsan_sync.cc ..\rtl\tsan_stack_trace.cc ..\..\sanitizer_common\sanitizer_allocator.cc ..\..\sanitizer_common\sanitizer_common.cc ..\..\sanitizer_common\sanitizer_flags.cc ..\..\sanitizer_common\sanitizer_stacktrace.cc ..\..\sanitizer_common\sanitizer_libc.cc ..\..\sanitizer_common\sanitizer_printf.cc ..\..\sanitizer_common\sanitizer_suppressions.cc ..\..\sanitizer_common\sanitizer_thread_registry.cc ..\rtl\tsan_platform_windows.cc ..\..\sanitizer_common\sanitizer_win.cc ..\..\sanitizer_common\sanitizer_deadlock_detector1.cc ..\..\sanitizer_common\sanitizer_stackdepot.cc ..\..\sanitizer_common\sanitizer_persistent_allocator.cc > gotsan.cc
+
+gcc -c -o race_windows_amd64.syso gotsan.cc -I..\rtl -I..\.. -I..\..\sanitizer_common -I..\..\..\include -m64 -Wall -fno-exceptions -fno-rtti -DSANITIZER_GO -DTSAN_SHADOW_COUNT=4 -Wno-error=attributes -Wno-attributes -Wno-format -DTSAN_DEBUG=0 -O3 -fomit-frame-pointer
+
diff --git a/lib/tsan/go/buildgo.sh b/lib/tsan/go/buildgo.sh
index bd03fc0b65e0..4df2e96c5a8c 100755
--- a/lib/tsan/go/buildgo.sh
+++ b/lib/tsan/go/buildgo.sh
@@ -1,10 +1,10 @@
-#!/bin/bash
set -e
SRCS="
tsan_go.cc
../rtl/tsan_clock.cc
../rtl/tsan_flags.cc
+ ../rtl/tsan_interface_atomic.cc
../rtl/tsan_md5.cc
../rtl/tsan_mutex.cc
../rtl/tsan_report.cc
@@ -12,43 +12,64 @@ SRCS="
../rtl/tsan_rtl_mutex.cc
../rtl/tsan_rtl_report.cc
../rtl/tsan_rtl_thread.cc
+ ../rtl/tsan_stack_trace.cc
../rtl/tsan_stat.cc
../rtl/tsan_suppressions.cc
../rtl/tsan_sync.cc
../../sanitizer_common/sanitizer_allocator.cc
../../sanitizer_common/sanitizer_common.cc
+ ../../sanitizer_common/sanitizer_deadlock_detector2.cc
../../sanitizer_common/sanitizer_flags.cc
../../sanitizer_common/sanitizer_libc.cc
+ ../../sanitizer_common/sanitizer_persistent_allocator.cc
../../sanitizer_common/sanitizer_printf.cc
../../sanitizer_common/sanitizer_suppressions.cc
../../sanitizer_common/sanitizer_thread_registry.cc
+ ../../sanitizer_common/sanitizer_stackdepot.cc
+ ../../sanitizer_common/sanitizer_stacktrace.cc
+ ../../sanitizer_common/sanitizer_symbolizer.cc
"
if [ "`uname -a | grep Linux`" != "" ]; then
SUFFIX="linux_amd64"
- OSCFLAGS="-fPIC -ffreestanding -Wno-maybe-uninitialized -Werror"
+ OSCFLAGS="-fPIC -ffreestanding -Wno-maybe-uninitialized -Wno-unused-const-variable -Werror -Wno-unknown-warning-option"
OSLDFLAGS="-lpthread -fPIC -fpie"
SRCS+="
../rtl/tsan_platform_linux.cc
../../sanitizer_common/sanitizer_posix.cc
../../sanitizer_common/sanitizer_posix_libcdep.cc
+ ../../sanitizer_common/sanitizer_procmaps_common.cc
+ ../../sanitizer_common/sanitizer_procmaps_linux.cc
../../sanitizer_common/sanitizer_linux.cc
- ../../sanitizer_common/sanitizer_linux_libcdep.cc
../../sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
"
+elif [ "`uname -a | grep FreeBSD`" != "" ]; then
+ SUFFIX="freebsd_amd64"
+ OSCFLAGS="-fno-strict-aliasing -fPIC -Werror"
+ OSLDFLAGS="-lpthread -fPIC -fpie"
+ SRCS+="
+ ../rtl/tsan_platform_linux.cc
+ ../../sanitizer_common/sanitizer_posix.cc
+ ../../sanitizer_common/sanitizer_posix_libcdep.cc
+ ../../sanitizer_common/sanitizer_procmaps_common.cc
+ ../../sanitizer_common/sanitizer_procmaps_freebsd.cc
+ ../../sanitizer_common/sanitizer_linux.cc
+ ../../sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
+ "
elif [ "`uname -a | grep Darwin`" != "" ]; then
SUFFIX="darwin_amd64"
- OSCFLAGS="-fPIC"
+ OSCFLAGS="-fPIC -Wno-unused-const-variable -Wno-unknown-warning-option"
OSLDFLAGS="-lpthread -fPIC -fpie"
SRCS+="
../rtl/tsan_platform_mac.cc
- ../../sanitizer_common/sanitizer_posix.cc
../../sanitizer_common/sanitizer_mac.cc
+ ../../sanitizer_common/sanitizer_posix.cc
../../sanitizer_common/sanitizer_posix_libcdep.cc
+ ../../sanitizer_common/sanitizer_procmaps_mac.cc
"
elif [ "`uname -a | grep MINGW`" != "" ]; then
SUFFIX="windows_amd64"
- OSCFLAGS="-Wno-error=attributes -Wno-attributes"
+ OSCFLAGS="-Wno-error=attributes -Wno-attributes -Wno-unused-const-variable -Wno-unknown-warning-option"
OSLDFLAGS=""
SRCS+="
../rtl/tsan_platform_windows.cc
@@ -66,18 +87,17 @@ for F in $SRCS; do
cat $F >> gotsan.cc
done
-FLAGS=" -I../rtl -I../.. -I../../sanitizer_common -I../../../include -m64 -Wall -fno-exceptions -fno-rtti -DTSAN_GO -DSANITIZER_GO -DTSAN_SHADOW_COUNT=4 $OSCFLAGS"
+FLAGS=" -I../rtl -I../.. -I../../sanitizer_common -I../../../include -std=c++11 -m64 -Wall -fno-exceptions -fno-rtti -DSANITIZER_GO -DTSAN_SHADOW_COUNT=4 -DSANITIZER_DEADLOCK_DETECTOR_VERSION=2 $OSCFLAGS"
if [ "$DEBUG" == "" ]; then
- FLAGS+=" -DTSAN_DEBUG=0 -O3 -fomit-frame-pointer"
+ FLAGS+=" -DTSAN_DEBUG=0 -O3 -msse3 -fomit-frame-pointer"
else
FLAGS+=" -DTSAN_DEBUG=1 -g"
fi
-echo gcc gotsan.cc -S -o tmp.s $FLAGS $CFLAGS
-gcc gotsan.cc -S -o tmp.s $FLAGS $CFLAGS
-cat tmp.s $ASMS > gotsan.s
-echo as gotsan.s -o race_$SUFFIX.syso
-as gotsan.s -o race_$SUFFIX.syso
+CC=${CC:-gcc}
+
+echo $CC gotsan.cc -c -o race_$SUFFIX.syso $FLAGS $CFLAGS
+$CC gotsan.cc -c -o race_$SUFFIX.syso $FLAGS $CFLAGS
-gcc test.c race_$SUFFIX.syso -m64 -o test $OSLDFLAGS
+$CC test.c race_$SUFFIX.syso -m64 -o test $OSLDFLAGS
GORACE="exitcode=0 atexit_sleep_ms=0" ./test
diff --git a/lib/tsan/go/test.c b/lib/tsan/go/test.c
index 859b35d348e8..94433f1b8c22 100644
--- a/lib/tsan/go/test.c
+++ b/lib/tsan/go/test.c
@@ -13,7 +13,7 @@
#include <stdio.h>
-void __tsan_init(void **thr);
+void __tsan_init(void **thr, void (*cb)(void*));
void __tsan_fini();
void __tsan_map_shadow(void *addr, unsigned long size);
void __tsan_go_start(void *thr, void **chthr, void *pc);
@@ -22,27 +22,26 @@ void __tsan_read(void *thr, void *addr, void *pc);
void __tsan_write(void *thr, void *addr, void *pc);
void __tsan_func_enter(void *thr, void *pc);
void __tsan_func_exit(void *thr);
-void __tsan_malloc(void *thr, void *p, unsigned long sz, void *pc);
-void __tsan_free(void *p);
+void __tsan_malloc(void *p, unsigned long sz);
void __tsan_acquire(void *thr, void *addr);
void __tsan_release(void *thr, void *addr);
void __tsan_release_merge(void *thr, void *addr);
-int __tsan_symbolize(void *pc, char **img, char **rtn, char **file, int *l) {
- return 0;
-}
+void symbolize_cb(void *ctx) {}
-char buf[10];
+char buf0[100<<10];
void foobar() {}
void barfoo() {}
int main(void) {
void *thr0 = 0;
- __tsan_init(&thr0);
- __tsan_map_shadow(buf, sizeof(buf) + 4096);
+ char *buf = (char*)((unsigned long)buf0 + (64<<10) - 1 & ~((64<<10) - 1));
+ __tsan_malloc(buf, 10);
+ __tsan_init(&thr0, symbolize_cb);
+ __tsan_map_shadow(buf, 4096);
__tsan_func_enter(thr0, (char*)&main + 1);
- __tsan_malloc(thr0, buf, 10, 0);
+ __tsan_malloc(buf, 10);
__tsan_release(thr0, buf);
__tsan_release_merge(thr0, buf);
void *thr1 = 0;
@@ -60,7 +59,6 @@ int main(void) {
__tsan_read(thr2, buf, (char*)&barfoo + 1);
__tsan_func_exit(thr2);
__tsan_go_end(thr2);
- __tsan_free(buf);
__tsan_func_exit(thr0);
__tsan_fini();
return 0;
diff --git a/lib/tsan/go/tsan_go.cc b/lib/tsan/go/tsan_go.cc
index df54bb8e216c..cccf72cedd27 100644
--- a/lib/tsan/go/tsan_go.cc
+++ b/lib/tsan/go/tsan_go.cc
@@ -28,19 +28,15 @@ bool IsExpectedReport(uptr addr, uptr size) {
return false;
}
-void internal_start_thread(void(*func)(void*), void *arg) {
+void *internal_start_thread(void(*func)(void*), void *arg) {
+ return 0;
}
-ReportLocation *SymbolizeData(uptr addr) {
- return 0;
+void internal_join_thread(void *th) {
}
-ReportStack *NewReportStackEntry(uptr addr) {
- ReportStack *ent = (ReportStack*)internal_alloc(MBlockReportStack,
- sizeof(ReportStack));
- internal_memset(ent, 0, sizeof(*ent));
- ent->pc = addr;
- return ent;
+ReportLocation *SymbolizeData(uptr addr) {
+ return 0;
}
void *internal_alloc(MBlockType typ, uptr sz) {
@@ -51,25 +47,31 @@ void internal_free(void *p) {
InternalFree(p);
}
+struct SymbolizeContext {
+ uptr pc;
+ char *func;
+ char *file;
+ uptr line;
+ uptr off;
+ uptr res;
+};
+
// Callback into Go.
-extern "C" int __tsan_symbolize(uptr pc, char **func, char **file,
- int *line, int *off);
-
-ReportStack *SymbolizeCode(uptr addr) {
- ReportStack *s = (ReportStack*)internal_alloc(MBlockReportStack,
- sizeof(ReportStack));
- internal_memset(s, 0, sizeof(*s));
- s->pc = addr;
- char *func = 0, *file = 0;
- int line = 0, off = 0;
- if (__tsan_symbolize(addr, &func, &file, &line, &off)) {
- s->offset = off;
- s->func = internal_strdup(func ? func : "??");
- s->file = internal_strdup(file ? file : "-");
- s->line = line;
- s->col = 0;
- free(func);
- free(file);
+static void (*symbolize_cb)(SymbolizeContext *ctx);
+
+SymbolizedStack *SymbolizeCode(uptr addr) {
+ SymbolizedStack *s = SymbolizedStack::New(addr);
+ SymbolizeContext ctx;
+ internal_memset(&ctx, 0, sizeof(ctx));
+ ctx.pc = addr;
+ symbolize_cb(&ctx);
+ if (ctx.res) {
+ AddressInfo &info = s->info;
+ info.module_offset = ctx.off;
+ info.function = internal_strdup(ctx.func ? ctx.func : "??");
+ info.file = internal_strdup(ctx.file ? ctx.file : "-");
+ info.line = ctx.line;
+ info.column = 0;
}
return s;
}
@@ -77,6 +79,7 @@ ReportStack *SymbolizeCode(uptr addr) {
extern "C" {
static ThreadState *main_thr;
+static bool inited;
static ThreadState *AllocGoroutine() {
ThreadState *thr = (ThreadState*)internal_alloc(MBlockThreadContex,
@@ -85,20 +88,18 @@ static ThreadState *AllocGoroutine() {
return thr;
}
-void __tsan_init(ThreadState **thrp) {
+void __tsan_init(ThreadState **thrp, void (*cb)(SymbolizeContext *cb)) {
+ symbolize_cb = cb;
ThreadState *thr = AllocGoroutine();
main_thr = *thrp = thr;
- thr->in_rtl++;
Initialize(thr);
- thr->in_rtl--;
+ inited = true;
}
void __tsan_fini() {
// FIXME: Not necessary thread 0.
ThreadState *thr = main_thr;
- thr->in_rtl++;
int res = Finalize(thr);
- thr->in_rtl--;
exit(res);
}
@@ -110,19 +111,31 @@ void __tsan_read(ThreadState *thr, void *addr, void *pc) {
MemoryRead(thr, (uptr)pc, (uptr)addr, kSizeLog1);
}
+void __tsan_read_pc(ThreadState *thr, void *addr, uptr callpc, uptr pc) {
+ if (callpc != 0)
+ FuncEntry(thr, callpc);
+ MemoryRead(thr, (uptr)pc, (uptr)addr, kSizeLog1);
+ if (callpc != 0)
+ FuncExit(thr);
+}
+
void __tsan_write(ThreadState *thr, void *addr, void *pc) {
MemoryWrite(thr, (uptr)pc, (uptr)addr, kSizeLog1);
}
-void __tsan_read_range(ThreadState *thr, void *addr, uptr size, uptr step,
- void *pc) {
- (void)step;
+void __tsan_write_pc(ThreadState *thr, void *addr, uptr callpc, uptr pc) {
+ if (callpc != 0)
+ FuncEntry(thr, callpc);
+ MemoryWrite(thr, (uptr)pc, (uptr)addr, kSizeLog1);
+ if (callpc != 0)
+ FuncExit(thr);
+}
+
+void __tsan_read_range(ThreadState *thr, void *addr, uptr size, uptr pc) {
MemoryAccessRange(thr, (uptr)pc, (uptr)addr, size, false);
}
-void __tsan_write_range(ThreadState *thr, void *addr, uptr size, uptr step,
- void *pc) {
- (void)step;
+void __tsan_write_range(ThreadState *thr, void *addr, uptr size, uptr pc) {
MemoryAccessRange(thr, (uptr)pc, (uptr)addr, size, true);
}
@@ -134,58 +147,65 @@ void __tsan_func_exit(ThreadState *thr) {
FuncExit(thr);
}
-void __tsan_malloc(ThreadState *thr, void *p, uptr sz, void *pc) {
- if (thr == 0) // probably before __tsan_init()
+void __tsan_malloc(void *p, uptr sz) {
+ if (!inited)
return;
- thr->in_rtl++;
- MemoryResetRange(thr, (uptr)pc, (uptr)p, sz);
- thr->in_rtl--;
-}
-
-void __tsan_free(void *p) {
- (void)p;
+ MemoryResetRange(0, 0, (uptr)p, sz);
}
void __tsan_go_start(ThreadState *parent, ThreadState **pthr, void *pc) {
ThreadState *thr = AllocGoroutine();
*pthr = thr;
- thr->in_rtl++;
- parent->in_rtl++;
int goid = ThreadCreate(parent, (uptr)pc, 0, true);
ThreadStart(thr, goid, 0);
- parent->in_rtl--;
- thr->in_rtl--;
}
void __tsan_go_end(ThreadState *thr) {
- thr->in_rtl++;
ThreadFinish(thr);
- thr->in_rtl--;
internal_free(thr);
}
void __tsan_acquire(ThreadState *thr, void *addr) {
- thr->in_rtl++;
Acquire(thr, 0, (uptr)addr);
- thr->in_rtl--;
}
void __tsan_release(ThreadState *thr, void *addr) {
- thr->in_rtl++;
ReleaseStore(thr, 0, (uptr)addr);
- thr->in_rtl--;
}
void __tsan_release_merge(ThreadState *thr, void *addr) {
- thr->in_rtl++;
Release(thr, 0, (uptr)addr);
- thr->in_rtl--;
}
void __tsan_finalizer_goroutine(ThreadState *thr) {
AcquireGlobal(thr, 0);
}
+void __tsan_mutex_before_lock(ThreadState *thr, uptr addr, uptr write) {
+}
+
+void __tsan_mutex_after_lock(ThreadState *thr, uptr addr, uptr write) {
+ if (write)
+ MutexLock(thr, 0, addr);
+ else
+ MutexReadLock(thr, 0, addr);
+}
+
+void __tsan_mutex_before_unlock(ThreadState *thr, uptr addr, uptr write) {
+ if (write)
+ MutexUnlock(thr, 0, addr);
+ else
+ MutexReadUnlock(thr, 0, addr);
+}
+
+void __tsan_go_ignore_sync_begin(ThreadState *thr) {
+ ThreadIgnoreSyncBegin(thr, 0);
+}
+
+void __tsan_go_ignore_sync_end(ThreadState *thr) {
+ ThreadIgnoreSyncEnd(thr, 0);
+}
+
} // extern "C"
} // namespace __tsan
diff --git a/lib/tsan/lit_tests/CMakeLists.txt b/lib/tsan/lit_tests/CMakeLists.txt
deleted file mode 100644
index 1f2fbf98e080..000000000000
--- a/lib/tsan/lit_tests/CMakeLists.txt
+++ /dev/null
@@ -1,35 +0,0 @@
-configure_lit_site_cfg(
- ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
- ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg
- )
-
-configure_lit_site_cfg(
- ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.in
- ${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg
- )
-
-if(COMPILER_RT_CAN_EXECUTE_TESTS AND CAN_TARGET_x86_64)
- # Run TSan output tests only if we're sure we can produce working binaries.
- set(TSAN_TEST_DEPS
- ${SANITIZER_COMMON_LIT_TEST_DEPS}
- ${TSAN_RUNTIME_LIBRARIES})
- set(TSAN_TEST_PARAMS
- tsan_site_config=${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg
- )
- if(LLVM_INCLUDE_TESTS)
- list(APPEND TSAN_TEST_DEPS TsanUnitTests)
- endif()
- add_lit_testsuite(check-tsan "Running ThreadSanitizer tests"
- ${CMAKE_CURRENT_BINARY_DIR}
- PARAMS ${TSAN_TEST_PARAMS}
- DEPENDS ${TSAN_TEST_DEPS}
- )
- set_target_properties(check-tsan PROPERTIES FOLDER "TSan unittests")
-elseif(LLVM_INCLUDE_TESTS AND CAN_TARGET_x86_64)
- # Otherwise run only TSan unit tests (they are linked using the
- # host compiler).
- add_lit_testsuite(check-tsan "Running ThreadSanitizer tests"
- ${CMAKE_CURRENT_BINARY_DIR}/Unit
- DEPENDS TsanUnitTests llvm-symbolizer)
- set_target_properties(check-tsan PROPERTIES FOLDER "TSan unittests")
-endif()
diff --git a/lib/tsan/lit_tests/Helpers/blacklist.txt b/lib/tsan/lit_tests/Helpers/blacklist.txt
deleted file mode 100644
index 22225e542ff3..000000000000
--- a/lib/tsan/lit_tests/Helpers/blacklist.txt
+++ /dev/null
@@ -1 +0,0 @@
-fun:*Blacklisted_Thread2*
diff --git a/lib/tsan/lit_tests/Helpers/lit.local.cfg b/lib/tsan/lit_tests/Helpers/lit.local.cfg
deleted file mode 100644
index 9246b10352a7..000000000000
--- a/lib/tsan/lit_tests/Helpers/lit.local.cfg
+++ /dev/null
@@ -1,2 +0,0 @@
-# Files in this directory are helper files for other output tests.
-config.suffixes = []
diff --git a/lib/tsan/lit_tests/SharedLibs/lit.local.cfg b/lib/tsan/lit_tests/SharedLibs/lit.local.cfg
deleted file mode 100644
index b3677c17a0f2..000000000000
--- a/lib/tsan/lit_tests/SharedLibs/lit.local.cfg
+++ /dev/null
@@ -1,4 +0,0 @@
-# Sources in this directory are compiled as shared libraries and used by
-# tests in parent directory.
-
-config.suffixes = []
diff --git a/lib/tsan/lit_tests/SharedLibs/load_shared_lib-so.cc b/lib/tsan/lit_tests/SharedLibs/load_shared_lib-so.cc
deleted file mode 100644
index d05aa6a40d18..000000000000
--- a/lib/tsan/lit_tests/SharedLibs/load_shared_lib-so.cc
+++ /dev/null
@@ -1,22 +0,0 @@
-//===----------- load_shared_lib-so.cc --------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file is a part of ThreadSanitizer (TSan), a race detector.
-//
-//===----------------------------------------------------------------------===//
-
-#include <stddef.h>
-
-int GLOB_SHARED = 0;
-
-extern "C"
-void *write_from_so(void *unused) {
- GLOB_SHARED++;
- return NULL;
-}
diff --git a/lib/tsan/lit_tests/Unit/lit.cfg b/lib/tsan/lit_tests/Unit/lit.cfg
deleted file mode 100644
index 36585df1c671..000000000000
--- a/lib/tsan/lit_tests/Unit/lit.cfg
+++ /dev/null
@@ -1,23 +0,0 @@
-# -*- Python -*-
-
-import os
-
-def get_required_attr(config, attr_name):
- attr_value = getattr(config, attr_name, None)
- if not attr_value:
- lit_config.fatal(
- "No attribute %r in test configuration! You may need to run "
- "tests from your build directory or add this attribute "
- "to lit.site.cfg " % attr_name)
- return attr_value
-
-# Setup config name.
-config.name = 'ThreadSanitizer-Unit'
-
-# Setup test source and exec root. For unit tests, we define
-# it as build directory with TSan unit tests.
-llvm_obj_root = get_required_attr(config, "llvm_obj_root")
-config.test_exec_root = os.path.join(llvm_obj_root, "projects",
- "compiler-rt", "lib",
- "tsan", "tests")
-config.test_source_root = config.test_exec_root
diff --git a/lib/tsan/lit_tests/Unit/lit.site.cfg.in b/lib/tsan/lit_tests/Unit/lit.site.cfg.in
deleted file mode 100644
index 3701a2cad74c..000000000000
--- a/lib/tsan/lit_tests/Unit/lit.site.cfg.in
+++ /dev/null
@@ -1,8 +0,0 @@
-## Autogenerated by LLVM/Clang configuration.
-# Do not edit!
-
-# Load common config for all compiler-rt unit tests.
-lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/lib/lit.common.unit.configured")
-
-# Load tool-specific config that would do the real work.
-lit_config.load_config(config, "@CMAKE_CURRENT_SOURCE_DIR@/Unit/lit.cfg")
diff --git a/lib/tsan/lit_tests/aligned_vs_unaligned_race.cc b/lib/tsan/lit_tests/aligned_vs_unaligned_race.cc
deleted file mode 100644
index f4533d08306c..000000000000
--- a/lib/tsan/lit_tests/aligned_vs_unaligned_race.cc
+++ /dev/null
@@ -1,34 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
-// Race between an aligned access and an unaligned access, which
-// touches the same memory region.
-// This is a real race which is not detected by tsan.
-// https://code.google.com/p/thread-sanitizer/issues/detail?id=17
-#include <pthread.h>
-#include <stdio.h>
-#include <stdint.h>
-
-uint64_t Global[2];
-
-void *Thread1(void *x) {
- Global[1]++;
- return NULL;
-}
-
-void *Thread2(void *x) {
- char *p1 = reinterpret_cast<char *>(&Global[0]);
- uint64_t *p4 = reinterpret_cast<uint64_t *>(p1 + 1);
- (*p4)++;
- return NULL;
-}
-
-int main() {
- pthread_t t[2];
- pthread_create(&t[0], NULL, Thread1, NULL);
- pthread_create(&t[1], NULL, Thread2, NULL);
- pthread_join(t[0], NULL);
- pthread_join(t[1], NULL);
- printf("Pass\n");
- // CHECK-NOT: ThreadSanitizer: data race
- // CHECK: Pass
- return 0;
-}
diff --git a/lib/tsan/lit_tests/allocator_returns_null.cc b/lib/tsan/lit_tests/allocator_returns_null.cc
deleted file mode 100644
index 4b5eb5504c27..000000000000
--- a/lib/tsan/lit_tests/allocator_returns_null.cc
+++ /dev/null
@@ -1,64 +0,0 @@
-// Test the behavior of malloc/calloc/realloc when the allocation size is huge.
-// By default (allocator_may_return_null=0) the process shoudl crash.
-// With allocator_may_return_null=1 the allocator should return 0.
-//
-// RUN: %clangxx_tsan -O0 %s -o %t
-// RUN: not %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mCRASH
-// RUN: TSAN_OPTIONS=allocator_may_return_null=0 not %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mCRASH
-// RUN: TSAN_OPTIONS=allocator_may_return_null=0 not %t calloc 2>&1 | FileCheck %s --check-prefix=CHECK-cCRASH
-// RUN: TSAN_OPTIONS=allocator_may_return_null=0 not %t calloc-overflow 2>&1 | FileCheck %s --check-prefix=CHECK-coCRASH
-// RUN: TSAN_OPTIONS=allocator_may_return_null=0 not %t realloc 2>&1 | FileCheck %s --check-prefix=CHECK-rCRASH
-// RUN: TSAN_OPTIONS=allocator_may_return_null=0 not %t realloc-after-malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mrCRASH
-
-#include <limits.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#include <assert.h>
-#include <limits>
-int main(int argc, char **argv) {
- volatile size_t size = std::numeric_limits<size_t>::max() - 10000;
- assert(argc == 2);
- char *x = 0;
- if (!strcmp(argv[1], "malloc")) {
- fprintf(stderr, "malloc:\n");
- x = (char*)malloc(size);
- }
- if (!strcmp(argv[1], "calloc")) {
- fprintf(stderr, "calloc:\n");
- x = (char*)calloc(size / 4, 4);
- }
-
- if (!strcmp(argv[1], "calloc-overflow")) {
- fprintf(stderr, "calloc-overflow:\n");
- volatile size_t kMaxSizeT = std::numeric_limits<size_t>::max();
- size_t kArraySize = 4096;
- volatile size_t kArraySize2 = kMaxSizeT / kArraySize + 10;
- x = (char*)calloc(kArraySize, kArraySize2);
- }
-
- if (!strcmp(argv[1], "realloc")) {
- fprintf(stderr, "realloc:\n");
- x = (char*)realloc(0, size);
- }
- if (!strcmp(argv[1], "realloc-after-malloc")) {
- fprintf(stderr, "realloc-after-malloc:\n");
- char *t = (char*)malloc(100);
- *t = 42;
- x = (char*)realloc(t, size);
- assert(*t == 42);
- }
- fprintf(stderr, "x: %p\n", x);
- return x != 0;
-}
-// CHECK-mCRASH: malloc:
-// CHECK-mCRASH: ThreadSanitizer's allocator is terminating the process
-// CHECK-cCRASH: calloc:
-// CHECK-cCRASH: ThreadSanitizer's allocator is terminating the process
-// CHECK-coCRASH: calloc-overflow:
-// CHECK-coCRASH: ThreadSanitizer's allocator is terminating the process
-// CHECK-rCRASH: realloc:
-// CHECK-rCRASH: ThreadSanitizer's allocator is terminating the process
-// CHECK-mrCRASH: realloc-after-malloc:
-// CHECK-mrCRASH: ThreadSanitizer's allocator is terminating the process
-
diff --git a/lib/tsan/lit_tests/atomic_free.cc b/lib/tsan/lit_tests/atomic_free.cc
deleted file mode 100644
index 87d559362af4..000000000000
--- a/lib/tsan/lit_tests/atomic_free.cc
+++ /dev/null
@@ -1,19 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <unistd.h>
-
-void *Thread(void *a) {
- __atomic_fetch_add((int*)a, 1, __ATOMIC_SEQ_CST);
- return 0;
-}
-
-int main() {
- int *a = new int(0);
- pthread_t t;
- pthread_create(&t, 0, Thread, a);
- sleep(1);
- delete a;
- pthread_join(t, 0);
-}
-
-// CHECK: WARNING: ThreadSanitizer: data race
diff --git a/lib/tsan/lit_tests/atomic_free2.cc b/lib/tsan/lit_tests/atomic_free2.cc
deleted file mode 100644
index 961ff38c843b..000000000000
--- a/lib/tsan/lit_tests/atomic_free2.cc
+++ /dev/null
@@ -1,19 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <unistd.h>
-
-void *Thread(void *a) {
- sleep(1);
- __atomic_fetch_add((int*)a, 1, __ATOMIC_SEQ_CST);
- return 0;
-}
-
-int main() {
- int *a = new int(0);
- pthread_t t;
- pthread_create(&t, 0, Thread, a);
- delete a;
- pthread_join(t, 0);
-}
-
-// CHECK: WARNING: ThreadSanitizer: heap-use-after-free
diff --git a/lib/tsan/lit_tests/atomic_norace.cc b/lib/tsan/lit_tests/atomic_norace.cc
deleted file mode 100644
index 265459b0758e..000000000000
--- a/lib/tsan/lit_tests/atomic_norace.cc
+++ /dev/null
@@ -1,61 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stdio.h>
-#include <unistd.h>
-
-const int kTestCount = 4;
-typedef long long T;
-T atomics[kTestCount * 2];
-
-void Test(int test, T *p, bool main_thread) {
- volatile T sink;
- if (test == 0) {
- if (main_thread)
- __atomic_fetch_add(p, 1, __ATOMIC_RELAXED);
- else
- __atomic_fetch_add(p, 1, __ATOMIC_RELAXED);
- } else if (test == 1) {
- if (main_thread)
- __atomic_exchange_n(p, 1, __ATOMIC_ACQ_REL);
- else
- __atomic_exchange_n(p, 1, __ATOMIC_ACQ_REL);
- } else if (test == 2) {
- if (main_thread)
- sink = __atomic_load_n(p, __ATOMIC_SEQ_CST);
- else
- __atomic_store_n(p, 1, __ATOMIC_SEQ_CST);
- } else if (test == 3) {
- if (main_thread)
- sink = __atomic_load_n(p, __ATOMIC_SEQ_CST);
- else
- sink = *p;
- }
-}
-
-void *Thread(void *p) {
- for (int i = 0; i < kTestCount; i++) {
- Test(i, &atomics[i], false);
- }
- sleep(2);
- for (int i = 0; i < kTestCount; i++) {
- fprintf(stderr, "Test %d reverse\n", i);
- Test(i, &atomics[kTestCount + i], false);
- }
- return 0;
-}
-
-int main() {
- pthread_t t;
- pthread_create(&t, 0, Thread, 0);
- sleep(1);
- for (int i = 0; i < kTestCount; i++) {
- fprintf(stderr, "Test %d\n", i);
- Test(i, &atomics[i], true);
- }
- for (int i = 0; i < kTestCount; i++) {
- Test(i, &atomics[kTestCount + i], true);
- }
- pthread_join(t, 0);
-}
-
-// CHECK-NOT: ThreadSanitizer: data race
diff --git a/lib/tsan/lit_tests/atomic_race.cc b/lib/tsan/lit_tests/atomic_race.cc
deleted file mode 100644
index 0dfe4d93df6e..000000000000
--- a/lib/tsan/lit_tests/atomic_race.cc
+++ /dev/null
@@ -1,80 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <unistd.h>
-#include <stdio.h>
-
-const int kTestCount = 4;
-typedef long long T;
-T atomics[kTestCount * 2];
-
-void Test(int test, T *p, bool main_thread) {
- volatile T sink;
- if (test == 0) {
- if (main_thread)
- __atomic_fetch_add(p, 1, __ATOMIC_RELAXED);
- else
- *p = 42;
- } else if (test == 1) {
- if (main_thread)
- __atomic_fetch_add(p, 1, __ATOMIC_RELAXED);
- else
- sink = *p;
- } else if (test == 2) {
- if (main_thread)
- sink = __atomic_load_n(p, __ATOMIC_SEQ_CST);
- else
- *p = 42;
- } else if (test == 3) {
- if (main_thread)
- __atomic_store_n(p, 1, __ATOMIC_SEQ_CST);
- else
- sink = *p;
- }
-}
-
-void *Thread(void *p) {
- for (int i = 0; i < kTestCount; i++) {
- Test(i, &atomics[i], false);
- }
- sleep(2);
- for (int i = 0; i < kTestCount; i++) {
- fprintf(stderr, "Test %d reverse\n", i);
- Test(i, &atomics[kTestCount + i], false);
- }
- return 0;
-}
-
-int main() {
- pthread_t t;
- pthread_create(&t, 0, Thread, 0);
- sleep(1);
- for (int i = 0; i < kTestCount; i++) {
- fprintf(stderr, "Test %d\n", i);
- Test(i, &atomics[i], true);
- }
- for (int i = 0; i < kTestCount; i++) {
- Test(i, &atomics[kTestCount + i], true);
- }
- pthread_join(t, 0);
-}
-
-// CHECK: Test 0
-// CHECK: ThreadSanitizer: data race
-// CHECK-NOT: SUMMARY{{.*}}tsan_interface_atomic
-// CHECK: Test 1
-// CHECK: ThreadSanitizer: data race
-// CHECK-NOT: SUMMARY{{.*}}tsan_interface_atomic
-// CHECK: Test 2
-// CHECK: ThreadSanitizer: data race
-// CHECK-NOT: SUMMARY{{.*}}tsan_interface_atomic
-// CHECK: Test 3
-// CHECK: ThreadSanitizer: data race
-// CHECK-NOT: SUMMARY{{.*}}tsan_interface_atomic
-// CHECK: Test 0 reverse
-// CHECK: ThreadSanitizer: data race
-// CHECK: Test 1 reverse
-// CHECK: ThreadSanitizer: data race
-// CHECK: Test 2 reverse
-// CHECK: ThreadSanitizer: data race
-// CHECK: Test 3 reverse
-// CHECK: ThreadSanitizer: data race
diff --git a/lib/tsan/lit_tests/atomic_stack.cc b/lib/tsan/lit_tests/atomic_stack.cc
deleted file mode 100644
index 841f74b891ab..000000000000
--- a/lib/tsan/lit_tests/atomic_stack.cc
+++ /dev/null
@@ -1,29 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <unistd.h>
-
-int Global;
-
-void *Thread1(void *x) {
- sleep(1);
- __atomic_fetch_add(&Global, 1, __ATOMIC_RELAXED);
- return NULL;
-}
-
-void *Thread2(void *x) {
- Global++;
- return NULL;
-}
-
-int main() {
- pthread_t t[2];
- pthread_create(&t[0], NULL, Thread1, NULL);
- pthread_create(&t[1], NULL, Thread2, NULL);
- pthread_join(t[0], NULL);
- pthread_join(t[1], NULL);
-}
-
-// CHECK: WARNING: ThreadSanitizer: data race
-// CHECK: Atomic write of size 4
-// CHECK: #0 __tsan_atomic32_fetch_add
-// CHECK: #1 Thread1
diff --git a/lib/tsan/lit_tests/benign_race.cc b/lib/tsan/lit_tests/benign_race.cc
deleted file mode 100644
index a4d4d23c362a..000000000000
--- a/lib/tsan/lit_tests/benign_race.cc
+++ /dev/null
@@ -1,39 +0,0 @@
-// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stdio.h>
-#include <unistd.h>
-
-int Global;
-int WTFGlobal;
-
-extern "C" {
-void AnnotateBenignRaceSized(const char *f, int l,
- void *mem, unsigned int size, const char *desc);
-void WTFAnnotateBenignRaceSized(const char *f, int l,
- void *mem, unsigned int size,
- const char *desc);
-}
-
-
-void *Thread(void *x) {
- Global = 42;
- WTFGlobal = 142;
- return 0;
-}
-
-int main() {
- AnnotateBenignRaceSized(__FILE__, __LINE__,
- &Global, sizeof(Global), "Race on Global");
- WTFAnnotateBenignRaceSized(__FILE__, __LINE__,
- &WTFGlobal, sizeof(WTFGlobal),
- "Race on WTFGlobal");
- pthread_t t;
- pthread_create(&t, 0, Thread, 0);
- sleep(1);
- Global = 43;
- WTFGlobal = 143;
- pthread_join(t, 0);
- printf("OK\n");
-}
-
-// CHECK-NOT: WARNING: ThreadSanitizer: data race
diff --git a/lib/tsan/lit_tests/blacklist.cc b/lib/tsan/lit_tests/blacklist.cc
deleted file mode 100644
index 5baf926e6272..000000000000
--- a/lib/tsan/lit_tests/blacklist.cc
+++ /dev/null
@@ -1,31 +0,0 @@
-// Test blacklist functionality for TSan.
-
-// RUN: %clangxx_tsan -O1 %s \
-// RUN: -fsanitize-blacklist=%p/Helpers/blacklist.txt \
-// RUN: -o %t && %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stdio.h>
-
-int Global;
-
-void *Thread1(void *x) {
- Global++;
- return NULL;
-}
-
-void *Blacklisted_Thread2(void *x) {
- Global--;
- return NULL;
-}
-
-int main() {
- pthread_t t[2];
- pthread_create(&t[0], NULL, Thread1, NULL);
- pthread_create(&t[1], NULL, Blacklisted_Thread2, NULL);
- pthread_join(t[0], NULL);
- pthread_join(t[1], NULL);
- printf("PASS\n");
- return 0;
-}
-
-// CHECK-NOT: ThreadSanitizer: data race
diff --git a/lib/tsan/lit_tests/cond.c b/lib/tsan/lit_tests/cond.c
deleted file mode 100644
index 52c87a413eb7..000000000000
--- a/lib/tsan/lit_tests/cond.c
+++ /dev/null
@@ -1,53 +0,0 @@
-// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
-// CHECK-NOT: WARNING: ThreadSanitizer: data race
-// CHECK-NOT: ThreadSanitizer WARNING: double lock
-// CHECK-NOT: ThreadSanitizer WARNING: mutex unlock by another thread
-// CHECK: OK
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <pthread.h>
-
-pthread_mutex_t m;
-pthread_cond_t c;
-int x;
-
-void *thr1(void *p) {
- int i;
-
- for (i = 0; i < 10; i += 2) {
- pthread_mutex_lock(&m);
- while (x != i)
- pthread_cond_wait(&c, &m);
- x = i + 1;
- pthread_cond_signal(&c);
- pthread_mutex_unlock(&m);
- }
- return 0;
-}
-
-void *thr2(void *p) {
- int i;
-
- for (i = 1; i < 10; i += 2) {
- pthread_mutex_lock(&m);
- while (x != i)
- pthread_cond_wait(&c, &m);
- x = i + 1;
- pthread_mutex_unlock(&m);
- pthread_cond_broadcast(&c);
- }
- return 0;
-}
-
-int main() {
- pthread_t th1, th2;
-
- pthread_mutex_init(&m, 0);
- pthread_cond_init(&c, 0);
- pthread_create(&th1, 0, thr1, 0);
- pthread_create(&th2, 0, thr2, 0);
- pthread_join(th1, 0);
- pthread_join(th2, 0);
- fprintf(stderr, "OK\n");
-}
diff --git a/lib/tsan/lit_tests/cond_race.cc b/lib/tsan/lit_tests/cond_race.cc
deleted file mode 100644
index 1e2acb243279..000000000000
--- a/lib/tsan/lit_tests/cond_race.cc
+++ /dev/null
@@ -1,36 +0,0 @@
-// RUN: %clang_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-// CHECK: ThreadSanitizer: data race
-// CHECK: pthread_cond_signal
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <pthread.h>
-
-struct Ctx {
- pthread_mutex_t m;
- pthread_cond_t c;
- bool done;
-};
-
-void *thr(void *p) {
- Ctx *c = (Ctx*)p;
- pthread_mutex_lock(&c->m);
- c->done = true;
- pthread_mutex_unlock(&c->m);
- pthread_cond_signal(&c->c);
- return 0;
-}
-
-int main() {
- Ctx *c = new Ctx();
- pthread_mutex_init(&c->m, 0);
- pthread_cond_init(&c->c, 0);
- pthread_t th;
- pthread_create(&th, 0, thr, c);
- pthread_mutex_lock(&c->m);
- while (!c->done)
- pthread_cond_wait(&c->c, &c->m);
- pthread_mutex_unlock(&c->m);
- delete c;
- pthread_join(th, 0);
-}
diff --git a/lib/tsan/lit_tests/cond_version.c b/lib/tsan/lit_tests/cond_version.c
deleted file mode 100644
index 1f966bfacb8d..000000000000
--- a/lib/tsan/lit_tests/cond_version.c
+++ /dev/null
@@ -1,44 +0,0 @@
-// RUN: %clang_tsan -O1 %s -o %t -lrt && %t 2>&1 | FileCheck %s
-// Test that pthread_cond is properly intercepted,
-// previously there were issues with versioned symbols.
-// CHECK: OK
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <pthread.h>
-#include <time.h>
-#include <errno.h>
-
-int main() {
- typedef unsigned long long u64;
- pthread_mutex_t m;
- pthread_cond_t c;
- pthread_condattr_t at;
- struct timespec ts0, ts1, ts2;
- int res;
- u64 sleep;
-
- pthread_mutex_init(&m, 0);
- pthread_condattr_init(&at);
- pthread_condattr_setclock(&at, CLOCK_MONOTONIC);
- pthread_cond_init(&c, &at);
-
- clock_gettime(CLOCK_MONOTONIC, &ts0);
- ts1 = ts0;
- ts1.tv_sec += 2;
-
- pthread_mutex_lock(&m);
- do {
- res = pthread_cond_timedwait(&c, &m, &ts1);
- } while (res == 0);
- pthread_mutex_unlock(&m);
-
- clock_gettime(CLOCK_MONOTONIC, &ts2);
- sleep = (u64)ts2.tv_sec * 1000000000 + ts2.tv_nsec -
- ((u64)ts0.tv_sec * 1000000000 + ts0.tv_nsec);
- if (res != ETIMEDOUT)
- exit(printf("bad return value %d, want %d\n", res, ETIMEDOUT));
- if (sleep < 1000000000)
- exit(printf("bad sleep duration %lluns, want %dns\n", sleep, 1000000000));
- fprintf(stderr, "OK\n");
-}
diff --git a/lib/tsan/lit_tests/deep_stack1.cc b/lib/tsan/lit_tests/deep_stack1.cc
deleted file mode 100644
index 3048aa8745bb..000000000000
--- a/lib/tsan/lit_tests/deep_stack1.cc
+++ /dev/null
@@ -1,44 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t -DORDER1 && not %t 2>&1 | FileCheck %s
-// RUN: %clangxx_tsan -O1 %s -o %t -DORDER2 && not %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stdio.h>
-#include <unistd.h>
-
-volatile int X;
-volatile int N;
-void (*volatile F)();
-
-static void foo() {
- if (--N == 0)
- X = 42;
- else
- F();
-}
-
-void *Thread(void *p) {
-#ifdef ORDER1
- sleep(1);
-#endif
- F();
- return 0;
-}
-
-int main() {
- N = 50000;
- F = foo;
- pthread_t t;
- pthread_attr_t a;
- pthread_attr_init(&a);
- pthread_attr_setstacksize(&a, N * 256 + (1 << 20));
- pthread_create(&t, &a, Thread, 0);
-#ifdef ORDER2
- sleep(1);
-#endif
- X = 43;
- pthread_join(t, 0);
-}
-
-// CHECK: WARNING: ThreadSanitizer: data race
-// CHECK: #100 foo
-// We must output suffucuently large stack (at least 100 frames)
-
diff --git a/lib/tsan/lit_tests/default_options.cc b/lib/tsan/lit_tests/default_options.cc
deleted file mode 100644
index 62c6c028f9e4..000000000000
--- a/lib/tsan/lit_tests/default_options.cc
+++ /dev/null
@@ -1,32 +0,0 @@
-// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stdio.h>
-
-extern "C" const char *__tsan_default_options() {
- return "report_bugs=0";
-}
-
-int Global;
-
-void *Thread1(void *x) {
- Global = 42;
- return NULL;
-}
-
-void *Thread2(void *x) {
- Global = 43;
- return NULL;
-}
-
-int main() {
- pthread_t t[2];
- pthread_create(&t[0], NULL, Thread1, NULL);
- pthread_create(&t[1], NULL, Thread2, NULL);
- pthread_join(t[0], NULL);
- pthread_join(t[1], NULL);
- fprintf(stderr, "DONE\n");
- return 0;
-}
-
-// CHECK-NOT: WARNING: ThreadSanitizer: data race
-// CHECK: DONE
diff --git a/lib/tsan/lit_tests/fd_close_norace.cc b/lib/tsan/lit_tests/fd_close_norace.cc
deleted file mode 100644
index a8b1a6d7b9e2..000000000000
--- a/lib/tsan/lit_tests/fd_close_norace.cc
+++ /dev/null
@@ -1,33 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-
-void *Thread1(void *x) {
- int f = open("/dev/random", O_RDONLY);
- close(f);
- return NULL;
-}
-
-void *Thread2(void *x) {
- sleep(1);
- int f = open("/dev/random", O_RDONLY);
- close(f);
- return NULL;
-}
-
-int main() {
- pthread_t t[2];
- pthread_create(&t[0], NULL, Thread1, NULL);
- pthread_create(&t[1], NULL, Thread2, NULL);
- pthread_join(t[0], NULL);
- pthread_join(t[1], NULL);
- printf("OK\n");
-}
-
-// CHECK-NOT: WARNING: ThreadSanitizer: data race
-
-
diff --git a/lib/tsan/lit_tests/fd_close_norace2.cc b/lib/tsan/lit_tests/fd_close_norace2.cc
deleted file mode 100644
index b42b334a27c0..000000000000
--- a/lib/tsan/lit_tests/fd_close_norace2.cc
+++ /dev/null
@@ -1,30 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stdio.h>
-#include <unistd.h>
-
-int pipes[2];
-
-void *Thread(void *x) {
- // wait for shutown signal
- while (read(pipes[0], &x, 1) != 1) {
- }
- close(pipes[0]);
- close(pipes[1]);
- return 0;
-}
-
-int main() {
- if (pipe(pipes))
- return 1;
- pthread_t t;
- pthread_create(&t, 0, Thread, 0);
- // send shutdown signal
- while (write(pipes[1], &t, 1) != 1) {
- }
- pthread_join(t, 0);
- printf("OK\n");
-}
-
-// CHECK-NOT: WARNING: ThreadSanitizer: data race
-// CHECK: OK
diff --git a/lib/tsan/lit_tests/fd_dup_norace.cc b/lib/tsan/lit_tests/fd_dup_norace.cc
deleted file mode 100644
index 8826f90fc485..000000000000
--- a/lib/tsan/lit_tests/fd_dup_norace.cc
+++ /dev/null
@@ -1,34 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-
-int fds[2];
-
-void *Thread1(void *x) {
- char buf;
- read(fds[0], &buf, 1);
- close(fds[0]);
- return 0;
-}
-
-void *Thread2(void *x) {
- close(fds[1]);
- return 0;
-}
-
-int main() {
- fds[0] = open("/dev/random", O_RDONLY);
- fds[1] = dup2(fds[0], 100);
- pthread_t t[2];
- pthread_create(&t[0], NULL, Thread1, NULL);
- pthread_create(&t[1], NULL, Thread2, NULL);
- pthread_join(t[0], NULL);
- pthread_join(t[1], NULL);
- printf("OK\n");
-}
-
-// CHECK-NOT: WARNING: ThreadSanitizer: data race
diff --git a/lib/tsan/lit_tests/fd_location.cc b/lib/tsan/lit_tests/fd_location.cc
deleted file mode 100644
index 2b1e9c56e361..000000000000
--- a/lib/tsan/lit_tests/fd_location.cc
+++ /dev/null
@@ -1,33 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stdio.h>
-#include <unistd.h>
-
-int fds[2];
-
-void *Thread1(void *x) {
- write(fds[1], "a", 1);
- return NULL;
-}
-
-void *Thread2(void *x) {
- sleep(1);
- close(fds[0]);
- close(fds[1]);
- return NULL;
-}
-
-int main() {
- pipe(fds);
- pthread_t t[2];
- pthread_create(&t[0], NULL, Thread1, NULL);
- pthread_create(&t[1], NULL, Thread2, NULL);
- pthread_join(t[0], NULL);
- pthread_join(t[1], NULL);
-}
-
-// CHECK: WARNING: ThreadSanitizer: data race
-// CHECK: Location is file descriptor {{[0-9]+}} created by main thread at:
-// CHECK: #0 pipe
-// CHECK: #1 main
-
diff --git a/lib/tsan/lit_tests/fd_pipe_norace.cc b/lib/tsan/lit_tests/fd_pipe_norace.cc
deleted file mode 100644
index 2da69ea21112..000000000000
--- a/lib/tsan/lit_tests/fd_pipe_norace.cc
+++ /dev/null
@@ -1,33 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stdio.h>
-#include <unistd.h>
-
-int fds[2];
-int X;
-
-void *Thread1(void *x) {
- X = 42;
- write(fds[1], "a", 1);
- return NULL;
-}
-
-void *Thread2(void *x) {
- char buf;
- while (read(fds[0], &buf, 1) != 1) {
- }
- X = 43;
- return NULL;
-}
-
-int main() {
- pipe(fds);
- pthread_t t[2];
- pthread_create(&t[0], NULL, Thread1, NULL);
- pthread_create(&t[1], NULL, Thread2, NULL);
- pthread_join(t[0], NULL);
- pthread_join(t[1], NULL);
- printf("OK\n");
-}
-
-// CHECK-NOT: WARNING: ThreadSanitizer: data race
diff --git a/lib/tsan/lit_tests/fd_pipe_race.cc b/lib/tsan/lit_tests/fd_pipe_race.cc
deleted file mode 100644
index 4dd2b77861ab..000000000000
--- a/lib/tsan/lit_tests/fd_pipe_race.cc
+++ /dev/null
@@ -1,37 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stdio.h>
-#include <unistd.h>
-
-int fds[2];
-
-void *Thread1(void *x) {
- write(fds[1], "a", 1);
- return NULL;
-}
-
-void *Thread2(void *x) {
- sleep(1);
- close(fds[0]);
- close(fds[1]);
- return NULL;
-}
-
-int main() {
- pipe(fds);
- pthread_t t[2];
- pthread_create(&t[0], NULL, Thread1, NULL);
- pthread_create(&t[1], NULL, Thread2, NULL);
- pthread_join(t[0], NULL);
- pthread_join(t[1], NULL);
-}
-
-// CHECK: WARNING: ThreadSanitizer: data race
-// CHECK: Write of size 8
-// CHECK: #0 close
-// CHECK: #1 Thread2
-// CHECK: Previous read of size 8
-// CHECK: #0 write
-// CHECK: #1 Thread1
-
-
diff --git a/lib/tsan/lit_tests/fd_socket_connect_norace.cc b/lib/tsan/lit_tests/fd_socket_connect_norace.cc
deleted file mode 100644
index 065299a9c6b6..000000000000
--- a/lib/tsan/lit_tests/fd_socket_connect_norace.cc
+++ /dev/null
@@ -1,45 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-
-struct sockaddr_in addr;
-int X;
-
-void *ClientThread(void *x) {
- int c = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
- X = 42;
- if (connect(c, (struct sockaddr*)&addr, sizeof(addr))) {
- perror("connect");
- exit(1);
- }
- close(c);
- return NULL;
-}
-
-int main() {
- int s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
- addr.sin_family = AF_INET;
- inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr);
- addr.sin_port = INADDR_ANY;
- socklen_t len = sizeof(addr);
- bind(s, (sockaddr*)&addr, len);
- getsockname(s, (sockaddr*)&addr, &len);
- listen(s, 10);
- pthread_t t;
- pthread_create(&t, 0, ClientThread, 0);
- int c = accept(s, 0, 0);
- X = 42;
- pthread_join(t, 0);
- close(c);
- close(s);
- printf("OK\n");
-}
-
-// CHECK-NOT: WARNING: ThreadSanitizer: data race
-
diff --git a/lib/tsan/lit_tests/fd_socket_norace.cc b/lib/tsan/lit_tests/fd_socket_norace.cc
deleted file mode 100644
index 243fc9de2238..000000000000
--- a/lib/tsan/lit_tests/fd_socket_norace.cc
+++ /dev/null
@@ -1,52 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-
-struct sockaddr_in addr;
-int X;
-
-void *ClientThread(void *x) {
- X = 42;
- int c = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
- if (connect(c, (struct sockaddr*)&addr, sizeof(addr))) {
- perror("connect");
- exit(1);
- }
- if (send(c, "a", 1, 0) != 1) {
- perror("send");
- exit(1);
- }
- close(c);
- return NULL;
-}
-
-int main() {
- int s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
- addr.sin_family = AF_INET;
- inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr);
- addr.sin_port = INADDR_ANY;
- socklen_t len = sizeof(addr);
- bind(s, (sockaddr*)&addr, len);
- getsockname(s, (sockaddr*)&addr, &len);
- listen(s, 10);
- pthread_t t;
- pthread_create(&t, 0, ClientThread, 0);
- int c = accept(s, 0, 0);
- char buf;
- while (read(c, &buf, 1) != 1) {
- }
- X = 43;
- close(c);
- close(s);
- pthread_join(t, 0);
- printf("OK\n");
-}
-
-// CHECK-NOT: WARNING: ThreadSanitizer: data race
-
diff --git a/lib/tsan/lit_tests/fd_socketpair_norace.cc b/lib/tsan/lit_tests/fd_socketpair_norace.cc
deleted file mode 100644
index f91e4eca0fe9..000000000000
--- a/lib/tsan/lit_tests/fd_socketpair_norace.cc
+++ /dev/null
@@ -1,37 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-
-int fds[2];
-int X;
-
-void *Thread1(void *x) {
- X = 42;
- write(fds[1], "a", 1);
- close(fds[1]);
- return NULL;
-}
-
-void *Thread2(void *x) {
- char buf;
- while (read(fds[0], &buf, 1) != 1) {
- }
- X = 43;
- close(fds[0]);
- return NULL;
-}
-
-int main() {
- socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
- pthread_t t[2];
- pthread_create(&t[0], NULL, Thread1, NULL);
- pthread_create(&t[1], NULL, Thread2, NULL);
- pthread_join(t[0], NULL);
- pthread_join(t[1], NULL);
- printf("OK\n");
-}
-
-// CHECK-NOT: WARNING: ThreadSanitizer: data race
diff --git a/lib/tsan/lit_tests/fd_stdout_race.cc b/lib/tsan/lit_tests/fd_stdout_race.cc
deleted file mode 100644
index 4b512bb78874..000000000000
--- a/lib/tsan/lit_tests/fd_stdout_race.cc
+++ /dev/null
@@ -1,41 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-
-int X;
-
-void *Thread1(void *x) {
- sleep(1);
- int f = open("/dev/random", O_RDONLY);
- char buf;
- read(f, &buf, 1);
- close(f);
- X = 42;
- return NULL;
-}
-
-void *Thread2(void *x) {
- X = 43;
- write(STDOUT_FILENO, "a", 1);
- return NULL;
-}
-
-int main() {
- pthread_t t[2];
- pthread_create(&t[0], NULL, Thread1, NULL);
- pthread_create(&t[1], NULL, Thread2, NULL);
- pthread_join(t[0], NULL);
- pthread_join(t[1], NULL);
-}
-
-// CHECK: WARNING: ThreadSanitizer: data race
-// CHECK: Write of size 4
-// CHECK: #0 Thread1
-// CHECK: Previous write of size 4
-// CHECK: #0 Thread2
-
-
diff --git a/lib/tsan/lit_tests/free_race.c b/lib/tsan/lit_tests/free_race.c
deleted file mode 100644
index d1db9fece90a..000000000000
--- a/lib/tsan/lit_tests/free_race.c
+++ /dev/null
@@ -1,49 +0,0 @@
-// RUN: %clang_tsan -O1 %s -o %t
-// RUN: not %t 2>&1 | FileCheck %s --check-prefix=CHECK-NOZUPP
-// RUN: TSAN_OPTIONS="suppressions=%s.supp print_suppressions=1" %t 2>&1 | FileCheck %s --check-prefix=CHECK-SUPP
-
-#include <pthread.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <stddef.h>
-#include <unistd.h>
-
-int *mem;
-pthread_mutex_t mtx;
-
-void *Thread1(void *x) {
- pthread_mutex_lock(&mtx);
- free(mem);
- pthread_mutex_unlock(&mtx);
- return NULL;
-}
-
-void *Thread2(void *x) {
- sleep(1);
- pthread_mutex_lock(&mtx);
- mem[0] = 42;
- pthread_mutex_unlock(&mtx);
- return NULL;
-}
-
-int main() {
- mem = (int*)malloc(100);
- pthread_mutex_init(&mtx, 0);
- pthread_t t;
- pthread_create(&t, NULL, Thread1, NULL);
- Thread2(0);
- pthread_join(t, NULL);
- pthread_mutex_destroy(&mtx);
- return 0;
-}
-
-// CHECK-NOZUPP: WARNING: ThreadSanitizer: heap-use-after-free
-// CHECK-NOZUPP: Write of size 4 at {{.*}} by main thread{{.*}}:
-// CHECK-NOZUPP: #0 Thread2
-// CHECK-NOZUPP: #1 main
-// CHECK-NOZUPP: Previous write of size 8 at {{.*}} by thread T1{{.*}}:
-// CHECK-NOZUPP: #0 free
-// CHECK-NOZUPP: #{{(1|2)}} Thread1
-// CHECK-NOZUPP: SUMMARY: ThreadSanitizer: heap-use-after-free{{.*}}Thread2
-// CHECK-SUPP: ThreadSanitizer: Matched 1 suppressions
-// CHECK-SUPP: 1 race:^Thread2$
diff --git a/lib/tsan/lit_tests/free_race.c.supp b/lib/tsan/lit_tests/free_race.c.supp
deleted file mode 100644
index f5d6a4969a41..000000000000
--- a/lib/tsan/lit_tests/free_race.c.supp
+++ /dev/null
@@ -1,2 +0,0 @@
-# Suppression for a use-after-free in free_race.c
-race:^Thread2$
diff --git a/lib/tsan/lit_tests/free_race2.c b/lib/tsan/lit_tests/free_race2.c
deleted file mode 100644
index 2b9a41927a47..000000000000
--- a/lib/tsan/lit_tests/free_race2.c
+++ /dev/null
@@ -1,26 +0,0 @@
-// RUN: %clang_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-#include <stdlib.h>
-
-void __attribute__((noinline)) foo(int *mem) {
- free(mem);
-}
-
-void __attribute__((noinline)) bar(int *mem) {
- mem[0] = 42;
-}
-
-int main() {
- int *mem = (int*)malloc(100);
- foo(mem);
- bar(mem);
- return 0;
-}
-
-// CHECK: WARNING: ThreadSanitizer: heap-use-after-free
-// CHECK: Write of size 4 at {{.*}} by main thread:
-// CHECK: #0 bar
-// CHECK: #1 main
-// CHECK: Previous write of size 8 at {{.*}} by main thread:
-// CHECK: #0 free
-// CHECK: #{{1|2}} foo
-// CHECK: #{{2|3}} main
diff --git a/lib/tsan/lit_tests/global_race.cc b/lib/tsan/lit_tests/global_race.cc
deleted file mode 100644
index ac2016155575..000000000000
--- a/lib/tsan/lit_tests/global_race.cc
+++ /dev/null
@@ -1,42 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stdio.h>
-#include <stddef.h>
-
-int GlobalData[10];
-int x;
-namespace XXX {
- struct YYY {
- static int ZZZ[10];
- };
- int YYY::ZZZ[10];
-}
-
-void *Thread(void *a) {
- GlobalData[2] = 42;
- x = 1;
- XXX::YYY::ZZZ[0] = 1;
- return 0;
-}
-
-int main() {
- fprintf(stderr, "addr=%p\n", GlobalData);
- fprintf(stderr, "addr2=%p\n", &x);
- fprintf(stderr, "addr3=%p\n", XXX::YYY::ZZZ);
- pthread_t t;
- pthread_create(&t, 0, Thread, 0);
- GlobalData[2] = 43;
- x = 0;
- XXX::YYY::ZZZ[0] = 0;
- pthread_join(t, 0);
-}
-
-// CHECK: addr=[[ADDR:0x[0-9,a-f]+]]
-// CHECK: addr2=[[ADDR2:0x[0-9,a-f]+]]
-// CHECK: addr3=[[ADDR3:0x[0-9,a-f]+]]
-// CHECK: WARNING: ThreadSanitizer: data race
-// CHECK: Location is global 'GlobalData' of size 40 at [[ADDR]] ({{.*}}+0x{{[0-9,a-f]+}})
-// CHECK: WARNING: ThreadSanitizer: data race
-// CHECK: Location is global 'x' of size 4 at [[ADDR2]] ({{.*}}+0x{{[0-9,a-f]+}})
-// CHECK: WARNING: ThreadSanitizer: data race
-// CHECK: Location is global 'XXX::YYY::ZZZ' of size 40 at [[ADDR3]] ({{.*}}+0x{{[0-9,a-f]+}})
diff --git a/lib/tsan/lit_tests/halt_on_error.cc b/lib/tsan/lit_tests/halt_on_error.cc
deleted file mode 100644
index fddaffff29aa..000000000000
--- a/lib/tsan/lit_tests/halt_on_error.cc
+++ /dev/null
@@ -1,25 +0,0 @@
-// RUN: %clang_tsan -O1 %s -o %t && TSAN_OPTIONS="$TSAN_OPTIONS halt_on_error=1" not %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stdio.h>
-
-int X;
-
-void *Thread(void *x) {
- X = 42;
- return 0;
-}
-
-int main() {
- fprintf(stderr, "BEFORE\n");
- pthread_t t;
- pthread_create(&t, 0, Thread, 0);
- X = 43;
- pthread_join(t, 0);
- fprintf(stderr, "AFTER\n");
- return 0;
-}
-
-// CHECK: BEFORE
-// CHECK: WARNING: ThreadSanitizer: data race
-// CHECK-NOT: AFTER
-
diff --git a/lib/tsan/lit_tests/heap_race.cc b/lib/tsan/lit_tests/heap_race.cc
deleted file mode 100644
index cc2c1fee532b..000000000000
--- a/lib/tsan/lit_tests/heap_race.cc
+++ /dev/null
@@ -1,20 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stdio.h>
-#include <stddef.h>
-
-void *Thread(void *a) {
- ((int*)a)[0]++;
- return NULL;
-}
-
-int main() {
- int *p = new int(42);
- pthread_t t;
- pthread_create(&t, NULL, Thread, p);
- p[0]++;
- pthread_join(t, NULL);
- delete p;
-}
-
-// CHECK: WARNING: ThreadSanitizer: data race
diff --git a/lib/tsan/lit_tests/ignore_free.cc b/lib/tsan/lit_tests/ignore_free.cc
deleted file mode 100644
index 60369cc1baa5..000000000000
--- a/lib/tsan/lit_tests/ignore_free.cc
+++ /dev/null
@@ -1,35 +0,0 @@
-// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-
-extern "C" {
-void AnnotateIgnoreReadsBegin(const char *f, int l);
-void AnnotateIgnoreReadsEnd(const char *f, int l);
-void AnnotateIgnoreWritesBegin(const char *f, int l);
-void AnnotateIgnoreWritesEnd(const char *f, int l);
-}
-
-void *Thread(void *p) {
- *(int*)p = 42;
- return 0;
-}
-
-int main() {
- int *p = new int(0);
- pthread_t t;
- pthread_create(&t, 0, Thread, p);
- sleep(1);
- AnnotateIgnoreReadsBegin(__FILE__, __LINE__);
- AnnotateIgnoreWritesBegin(__FILE__, __LINE__);
- free(p);
- AnnotateIgnoreReadsEnd(__FILE__, __LINE__);
- AnnotateIgnoreWritesEnd(__FILE__, __LINE__);
- pthread_join(t, 0);
- fprintf(stderr, "OK\n");
- return 0;
-}
-
-// CHECK-NOT: WARNING: ThreadSanitizer: data race
-// CHECK: OK
diff --git a/lib/tsan/lit_tests/ignore_lib0.cc b/lib/tsan/lit_tests/ignore_lib0.cc
deleted file mode 100644
index ea0f061e609d..000000000000
--- a/lib/tsan/lit_tests/ignore_lib0.cc
+++ /dev/null
@@ -1,30 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -DLIB -fPIC -fno-sanitize=thread -shared -o %T/libignore_lib0.so
-// RUN: %clangxx_tsan -O1 %s -L%T -lignore_lib0 -o %t
-// RUN: echo running w/o suppressions:
-// RUN: LD_LIBRARY_PATH=%T not %t 2>&1 | FileCheck %s --check-prefix=CHECK-NOSUPP
-// RUN: echo running with suppressions:
-// RUN: LD_LIBRARY_PATH=%T TSAN_OPTIONS="$TSAN_OPTIONS suppressions=%s.supp" %t 2>&1 | FileCheck %s --check-prefix=CHECK-WITHSUPP
-
-// Tests that interceptors coming from a library specified in called_from_lib
-// suppression are ignored.
-
-#ifndef LIB
-
-extern "C" void libfunc();
-
-int main() {
- libfunc();
-}
-
-#else // #ifdef LIB
-
-#include "ignore_lib_lib.h"
-
-#endif // #ifdef LIB
-
-// CHECK-NOSUPP: WARNING: ThreadSanitizer: data race
-// CHECK-NOSUPP: OK
-
-// CHECK-WITHSUPP-NOT: WARNING: ThreadSanitizer: data race
-// CHECK-WITHSUPP: OK
-
diff --git a/lib/tsan/lit_tests/ignore_lib0.cc.supp b/lib/tsan/lit_tests/ignore_lib0.cc.supp
deleted file mode 100644
index 7728c926b7de..000000000000
--- a/lib/tsan/lit_tests/ignore_lib0.cc.supp
+++ /dev/null
@@ -1,2 +0,0 @@
-called_from_lib:/libignore_lib0.so
-
diff --git a/lib/tsan/lit_tests/ignore_lib1.cc b/lib/tsan/lit_tests/ignore_lib1.cc
deleted file mode 100644
index c4f2e7344135..000000000000
--- a/lib/tsan/lit_tests/ignore_lib1.cc
+++ /dev/null
@@ -1,42 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -DLIB -fPIC -fno-sanitize=thread -shared -o %T/libignore_lib1.so
-// RUN: %clangxx_tsan -O1 %s -o %t
-// RUN: echo running w/o suppressions:
-// RUN: not %t 2>&1 | FileCheck %s --check-prefix=CHECK-NOSUPP
-// RUN: echo running with suppressions:
-// RUN: TSAN_OPTIONS="$TSAN_OPTIONS suppressions=%s.supp" %t 2>&1 | FileCheck %s --check-prefix=CHECK-WITHSUPP
-
-// Tests that interceptors coming from a dynamically loaded library specified
-// in called_from_lib suppression are ignored.
-
-#ifndef LIB
-
-#include <dlfcn.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <errno.h>
-#include <libgen.h>
-#include <string>
-
-int main(int argc, char **argv) {
- std::string lib = std::string(dirname(argv[0])) + "/libignore_lib1.so";
- void *h = dlopen(lib.c_str(), RTLD_GLOBAL | RTLD_NOW);
- if (h == 0)
- exit(printf("failed to load the library (%d)\n", errno));
- void (*f)() = (void(*)())dlsym(h, "libfunc");
- if (f == 0)
- exit(printf("failed to find the func (%d)\n", errno));
- f();
-}
-
-#else // #ifdef LIB
-
-#include "ignore_lib_lib.h"
-
-#endif // #ifdef LIB
-
-// CHECK-NOSUPP: WARNING: ThreadSanitizer: data race
-// CHECK-NOSUPP: OK
-
-// CHECK-WITHSUPP-NOT: WARNING: ThreadSanitizer: data race
-// CHECK-WITHSUPP: OK
-
diff --git a/lib/tsan/lit_tests/ignore_lib1.cc.supp b/lib/tsan/lit_tests/ignore_lib1.cc.supp
deleted file mode 100644
index 9f4119ec0bc4..000000000000
--- a/lib/tsan/lit_tests/ignore_lib1.cc.supp
+++ /dev/null
@@ -1,2 +0,0 @@
-called_from_lib:/libignore_lib1.so$
-
diff --git a/lib/tsan/lit_tests/ignore_lib2.cc b/lib/tsan/lit_tests/ignore_lib2.cc
deleted file mode 100644
index 97f9419e4d89..000000000000
--- a/lib/tsan/lit_tests/ignore_lib2.cc
+++ /dev/null
@@ -1,33 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -DLIB -fPIC -fno-sanitize=thread -shared -o %T/libignore_lib2_0.so
-// RUN: %clangxx_tsan -O1 %s -DLIB -fPIC -fno-sanitize=thread -shared -o %T/libignore_lib2_1.so
-// RUN: %clangxx_tsan -O1 %s -o %t
-// RUN: TSAN_OPTIONS="$TSAN_OPTIONS suppressions=%s.supp" not %t 2>&1 | FileCheck %s
-
-// Tests that called_from_lib suppression matched against 2 libraries
-// causes program crash (this is not supported).
-
-#ifndef LIB
-
-#include <dlfcn.h>
-#include <stdio.h>
-#include <libgen.h>
-#include <string>
-
-int main(int argc, char **argv) {
- std::string lib0 = std::string(dirname(argv[0])) + "/libignore_lib2_0.so";
- std::string lib1 = std::string(dirname(argv[0])) + "/libignore_lib2_1.so";
- dlopen(lib0.c_str(), RTLD_GLOBAL | RTLD_NOW);
- dlopen(lib1.c_str(), RTLD_GLOBAL | RTLD_NOW);
- fprintf(stderr, "OK\n");
-}
-
-#else // #ifdef LIB
-
-extern "C" void libfunc() {
-}
-
-#endif // #ifdef LIB
-
-// CHECK: ThreadSanitizer: called_from_lib suppression 'ignore_lib2' is matched against 2 libraries
-// CHECK-NOT: OK
-
diff --git a/lib/tsan/lit_tests/ignore_lib2.cc.supp b/lib/tsan/lit_tests/ignore_lib2.cc.supp
deleted file mode 100644
index 1419c71c67ef..000000000000
--- a/lib/tsan/lit_tests/ignore_lib2.cc.supp
+++ /dev/null
@@ -1,2 +0,0 @@
-called_from_lib:ignore_lib2
-
diff --git a/lib/tsan/lit_tests/ignore_lib3.cc b/lib/tsan/lit_tests/ignore_lib3.cc
deleted file mode 100644
index 8f237fcc81fd..000000000000
--- a/lib/tsan/lit_tests/ignore_lib3.cc
+++ /dev/null
@@ -1,33 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -DLIB -fPIC -fno-sanitize=thread -shared -o %T/libignore_lib3.so
-// RUN: %clangxx_tsan -O1 %s -o %t
-// RUN: TSAN_OPTIONS="$TSAN_OPTIONS suppressions=%s.supp" not %t 2>&1 | FileCheck %s
-
-// Tests that unloading of a library matched against called_from_lib suppression
-// causes program crash (this is not supported).
-
-#ifndef LIB
-
-#include <dlfcn.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <errno.h>
-#include <libgen.h>
-#include <string>
-
-int main(int argc, char **argv) {
- std::string lib = std::string(dirname(argv[0])) + "/libignore_lib3.so";
- void *h = dlopen(lib.c_str(), RTLD_GLOBAL | RTLD_NOW);
- dlclose(h);
- fprintf(stderr, "OK\n");
-}
-
-#else // #ifdef LIB
-
-extern "C" void libfunc() {
-}
-
-#endif // #ifdef LIB
-
-// CHECK: ThreadSanitizer: library {{.*}} that was matched against called_from_lib suppression 'ignore_lib3.so' is unloaded
-// CHECK-NOT: OK
-
diff --git a/lib/tsan/lit_tests/ignore_lib3.cc.supp b/lib/tsan/lit_tests/ignore_lib3.cc.supp
deleted file mode 100644
index 975dbcef99fe..000000000000
--- a/lib/tsan/lit_tests/ignore_lib3.cc.supp
+++ /dev/null
@@ -1,2 +0,0 @@
-called_from_lib:ignore_lib3.so
-
diff --git a/lib/tsan/lit_tests/ignore_lib_lib.h b/lib/tsan/lit_tests/ignore_lib_lib.h
deleted file mode 100644
index 2bfe84dfc0ec..000000000000
--- a/lib/tsan/lit_tests/ignore_lib_lib.h
+++ /dev/null
@@ -1,25 +0,0 @@
-#include <pthread.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-
-void *volatile mem;
-volatile int len;
-
-void *Thread(void *p) {
- while ((p = __atomic_load_n(&mem, __ATOMIC_ACQUIRE)) == 0)
- usleep(100);
- memset(p, 0, len);
- return 0;
-}
-
-extern "C" void libfunc() {
- pthread_t t;
- pthread_create(&t, 0, Thread, 0);
- len = 10;
- __atomic_store_n(&mem, malloc(len), __ATOMIC_RELEASE);
- pthread_join(t, 0);
- free(mem);
- fprintf(stderr, "OK\n");
-}
diff --git a/lib/tsan/lit_tests/ignore_malloc.cc b/lib/tsan/lit_tests/ignore_malloc.cc
deleted file mode 100644
index 63bd4241b59e..000000000000
--- a/lib/tsan/lit_tests/ignore_malloc.cc
+++ /dev/null
@@ -1,38 +0,0 @@
-// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-
-extern "C" {
-void AnnotateIgnoreReadsBegin(const char *f, int l);
-void AnnotateIgnoreReadsEnd(const char *f, int l);
-void AnnotateIgnoreWritesBegin(const char *f, int l);
-void AnnotateIgnoreWritesEnd(const char *f, int l);
-}
-
-int *g;
-
-void *Thread(void *a) {
- int *p = 0;
- while ((p = __atomic_load_n(&g, __ATOMIC_RELAXED)) == 0)
- usleep(100);
- *p = 42;
- return 0;
-}
-
-int main() {
- pthread_t t;
- pthread_create(&t, 0, Thread, 0);
- AnnotateIgnoreWritesBegin(__FILE__, __LINE__);
- int *p = new int(0);
- AnnotateIgnoreWritesEnd(__FILE__, __LINE__);
- __atomic_store_n(&g, p, __ATOMIC_RELAXED);
- pthread_join(t, 0);
- delete p;
- fprintf(stderr, "OK\n");
- return 0;
-}
-
-// CHECK-NOT: WARNING: ThreadSanitizer: data race
-// CHECK: OK
diff --git a/lib/tsan/lit_tests/ignore_race.cc b/lib/tsan/lit_tests/ignore_race.cc
deleted file mode 100644
index 23d74d0ed840..000000000000
--- a/lib/tsan/lit_tests/ignore_race.cc
+++ /dev/null
@@ -1,31 +0,0 @@
-// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stdio.h>
-#include <unistd.h>
-
-int Global;
-
-extern "C" void AnnotateIgnoreWritesBegin(const char *f, int l);
-extern "C" void AnnotateIgnoreWritesEnd(const char *f, int l);
-extern "C" void AnnotateIgnoreReadsBegin(const char *f, int l);
-extern "C" void AnnotateIgnoreReadsEnd(const char *f, int l);
-
-void *Thread(void *x) {
- AnnotateIgnoreWritesBegin(__FILE__, __LINE__);
- AnnotateIgnoreReadsBegin(__FILE__, __LINE__);
- Global = 42;
- AnnotateIgnoreReadsEnd(__FILE__, __LINE__);
- AnnotateIgnoreWritesEnd(__FILE__, __LINE__);
- return 0;
-}
-
-int main() {
- pthread_t t;
- pthread_create(&t, 0, Thread, 0);
- sleep(1);
- Global = 43;
- pthread_join(t, 0);
- printf("OK\n");
-}
-
-// CHECK-NOT: WARNING: ThreadSanitizer: data race
diff --git a/lib/tsan/lit_tests/ignore_sync.cc b/lib/tsan/lit_tests/ignore_sync.cc
deleted file mode 100644
index 67f2d906d9c7..000000000000
--- a/lib/tsan/lit_tests/ignore_sync.cc
+++ /dev/null
@@ -1,30 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stdio.h>
-
-extern "C" void AnnotateIgnoreSyncBegin(const char*, int);
-extern "C" void AnnotateIgnoreSyncEnd(const char*, int);
-
-int Global;
-pthread_mutex_t Mutex = PTHREAD_MUTEX_INITIALIZER;
-
-void *Thread(void *x) {
- AnnotateIgnoreSyncBegin(0, 0);
- pthread_mutex_lock(&Mutex);
- Global++;
- pthread_mutex_unlock(&Mutex);
- AnnotateIgnoreSyncEnd(0, 0);
- return 0;
-}
-
-int main() {
- pthread_t t;
- pthread_create(&t, 0, Thread, 0);
- pthread_mutex_lock(&Mutex);
- Global++;
- pthread_mutex_unlock(&Mutex);
- pthread_join(t, 0);
-}
-
-// CHECK: WARNING: ThreadSanitizer: data race
-
diff --git a/lib/tsan/lit_tests/inlined_memcpy_race.cc b/lib/tsan/lit_tests/inlined_memcpy_race.cc
deleted file mode 100644
index 5dda36e4b9e7..000000000000
--- a/lib/tsan/lit_tests/inlined_memcpy_race.cc
+++ /dev/null
@@ -1,55 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-
-int x[4], y[4], z[4];
-
-void *MemCpyThread(void *a) {
- memcpy((int*)a, z, 16);
- return NULL;
-}
-
-void *MemMoveThread(void *a) {
- memmove((int*)a, z, 16);
- return NULL;
-}
-
-void *MemSetThread(void *a) {
- sleep(1);
- memset((int*)a, 0, 16);
- return NULL;
-}
-
-int main() {
- pthread_t t[2];
- // Race on x between memcpy and memset
- pthread_create(&t[0], NULL, MemCpyThread, x);
- pthread_create(&t[1], NULL, MemSetThread, x);
- pthread_join(t[0], NULL);
- pthread_join(t[1], NULL);
- // Race on y between memmove and memset
- pthread_create(&t[0], NULL, MemMoveThread, y);
- pthread_create(&t[1], NULL, MemSetThread, y);
- pthread_join(t[0], NULL);
- pthread_join(t[1], NULL);
-
- printf("PASS\n");
- return 0;
-}
-
-// CHECK: WARNING: ThreadSanitizer: data race
-// CHECK: #0 memset
-// CHECK: #1 MemSetThread
-// CHECK: Previous write
-// CHECK: #0 memcpy
-// CHECK: #1 MemCpyThread
-
-// CHECK: WARNING: ThreadSanitizer: data race
-// CHECK: #0 memset
-// CHECK: #1 MemSetThread
-// CHECK: Previous write
-// CHECK: #0 memmove
-// CHECK: #1 MemMoveThread
diff --git a/lib/tsan/lit_tests/java.h b/lib/tsan/lit_tests/java.h
deleted file mode 100644
index 7aa0bca32cec..000000000000
--- a/lib/tsan/lit_tests/java.h
+++ /dev/null
@@ -1,20 +0,0 @@
-#include <pthread.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-
-extern "C" {
-typedef unsigned long jptr; // NOLINT
-void __tsan_java_preinit(const char *libjvm_path);
-void __tsan_java_init(jptr heap_begin, jptr heap_size);
-int __tsan_java_fini();
-void __tsan_java_alloc(jptr ptr, jptr size);
-void __tsan_java_free(jptr ptr, jptr size);
-void __tsan_java_move(jptr src, jptr dst, jptr size);
-void __tsan_java_mutex_lock(jptr addr);
-void __tsan_java_mutex_unlock(jptr addr);
-void __tsan_java_mutex_read_lock(jptr addr);
-void __tsan_java_mutex_read_unlock(jptr addr);
-void __tsan_java_mutex_lock_rec(jptr addr, int rec);
-int __tsan_java_mutex_unlock_rec(jptr addr);
-}
diff --git a/lib/tsan/lit_tests/java_alloc.cc b/lib/tsan/lit_tests/java_alloc.cc
deleted file mode 100644
index 4dbce70c31eb..000000000000
--- a/lib/tsan/lit_tests/java_alloc.cc
+++ /dev/null
@@ -1,32 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
-#include "java.h"
-
-int const kHeapSize = 1024 * 1024;
-
-void stress(jptr addr) {
- for (jptr sz = 8; sz <= 32; sz <<= 1) {
- for (jptr i = 0; i < kHeapSize / 4 / sz; i++) {
- __tsan_java_alloc(addr + i * sz, sz);
- }
- __tsan_java_move(addr, addr + kHeapSize / 2, kHeapSize / 4);
- __tsan_java_free(addr + kHeapSize / 2, kHeapSize / 4);
- }
-}
-
-void *Thread(void *p) {
- stress((jptr)p);
- return 0;
-}
-
-int main() {
- jptr jheap = (jptr)malloc(kHeapSize);
- __tsan_java_init(jheap, kHeapSize);
- pthread_t th;
- pthread_create(&th, 0, Thread, (void*)(jheap + kHeapSize / 4));
- stress(jheap);
- pthread_join(th, 0);
- printf("OK\n");
- return __tsan_java_fini();
-}
-
-// CHECK-NOT: WARNING: ThreadSanitizer: data race
diff --git a/lib/tsan/lit_tests/java_lock.cc b/lib/tsan/lit_tests/java_lock.cc
deleted file mode 100644
index d9db103504de..000000000000
--- a/lib/tsan/lit_tests/java_lock.cc
+++ /dev/null
@@ -1,35 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
-#include "java.h"
-#include <unistd.h>
-
-jptr varaddr;
-jptr lockaddr;
-
-void *Thread(void *p) {
- sleep(1);
- __tsan_java_mutex_lock(lockaddr);
- *(int*)varaddr = 42;
- __tsan_java_mutex_unlock(lockaddr);
- return 0;
-}
-
-int main() {
- int const kHeapSize = 1024 * 1024;
- void *jheap = malloc(kHeapSize);
- __tsan_java_init((jptr)jheap, kHeapSize);
- const int kBlockSize = 16;
- __tsan_java_alloc((jptr)jheap, kBlockSize);
- varaddr = (jptr)jheap;
- lockaddr = (jptr)jheap + 8;
- pthread_t th;
- pthread_create(&th, 0, Thread, 0);
- __tsan_java_mutex_lock(lockaddr);
- *(int*)varaddr = 43;
- __tsan_java_mutex_unlock(lockaddr);
- pthread_join(th, 0);
- __tsan_java_free((jptr)jheap, kBlockSize);
- printf("OK\n");
- return __tsan_java_fini();
-}
-
-// CHECK-NOT: WARNING: ThreadSanitizer: data race
diff --git a/lib/tsan/lit_tests/java_lock_move.cc b/lib/tsan/lit_tests/java_lock_move.cc
deleted file mode 100644
index 48b5a5a88d33..000000000000
--- a/lib/tsan/lit_tests/java_lock_move.cc
+++ /dev/null
@@ -1,40 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
-#include "java.h"
-
-jptr varaddr;
-jptr lockaddr;
-jptr varaddr2;
-jptr lockaddr2;
-
-void *Thread(void *p) {
- sleep(1);
- __tsan_java_mutex_lock(lockaddr2);
- *(int*)varaddr2 = 42;
- __tsan_java_mutex_unlock(lockaddr2);
- return 0;
-}
-
-int main() {
- int const kHeapSize = 1024 * 1024;
- void *jheap = malloc(kHeapSize);
- __tsan_java_init((jptr)jheap, kHeapSize);
- const int kBlockSize = 64;
- int const kMove = 1024;
- __tsan_java_alloc((jptr)jheap, kBlockSize);
- varaddr = (jptr)jheap;
- lockaddr = (jptr)jheap + 46;
- varaddr2 = varaddr + kMove;
- lockaddr2 = lockaddr + kMove;
- pthread_t th;
- pthread_create(&th, 0, Thread, 0);
- __tsan_java_mutex_lock(lockaddr);
- *(int*)varaddr = 43;
- __tsan_java_mutex_unlock(lockaddr);
- __tsan_java_move(varaddr, varaddr2, kBlockSize);
- pthread_join(th, 0);
- __tsan_java_free(varaddr2, kBlockSize);
- printf("OK\n");
- return __tsan_java_fini();
-}
-
-// CHECK-NOT: WARNING: ThreadSanitizer: data race
diff --git a/lib/tsan/lit_tests/java_lock_rec.cc b/lib/tsan/lit_tests/java_lock_rec.cc
deleted file mode 100644
index 5cc80d4a33ef..000000000000
--- a/lib/tsan/lit_tests/java_lock_rec.cc
+++ /dev/null
@@ -1,54 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
-#include "java.h"
-#include <unistd.h>
-
-jptr varaddr;
-jptr lockaddr;
-
-void *Thread(void *p) {
- __tsan_java_mutex_lock(lockaddr);
- __tsan_java_mutex_lock(lockaddr);
- *(int*)varaddr = 42;
- int rec = __tsan_java_mutex_unlock_rec(lockaddr);
- if (rec != 2) {
- printf("FAILED 0 rec=%d\n", rec);
- exit(1);
- }
- sleep(2);
- __tsan_java_mutex_lock_rec(lockaddr, rec);
- if (*(int*)varaddr != 43) {
- printf("FAILED 3 var=%d\n", *(int*)varaddr);
- exit(1);
- }
- __tsan_java_mutex_unlock(lockaddr);
- __tsan_java_mutex_unlock(lockaddr);
- return 0;
-}
-
-int main() {
- int const kHeapSize = 1024 * 1024;
- void *jheap = malloc(kHeapSize);
- __tsan_java_init((jptr)jheap, kHeapSize);
- const int kBlockSize = 16;
- __tsan_java_alloc((jptr)jheap, kBlockSize);
- varaddr = (jptr)jheap;
- *(int*)varaddr = 0;
- lockaddr = (jptr)jheap + 8;
- pthread_t th;
- pthread_create(&th, 0, Thread, 0);
- sleep(1);
- __tsan_java_mutex_lock(lockaddr);
- if (*(int*)varaddr != 42) {
- printf("FAILED 1 var=%d\n", *(int*)varaddr);
- exit(1);
- }
- *(int*)varaddr = 43;
- __tsan_java_mutex_unlock(lockaddr);
- pthread_join(th, 0);
- __tsan_java_free((jptr)jheap, kBlockSize);
- printf("OK\n");
- return __tsan_java_fini();
-}
-
-// CHECK-NOT: WARNING: ThreadSanitizer: data race
-// CHECK-NOT: FAILED
diff --git a/lib/tsan/lit_tests/java_lock_rec_race.cc b/lib/tsan/lit_tests/java_lock_rec_race.cc
deleted file mode 100644
index a868e260c86d..000000000000
--- a/lib/tsan/lit_tests/java_lock_rec_race.cc
+++ /dev/null
@@ -1,48 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-#include "java.h"
-#include <unistd.h>
-
-jptr varaddr;
-jptr lockaddr;
-
-void *Thread(void *p) {
- __tsan_java_mutex_lock(lockaddr);
- __tsan_java_mutex_lock(lockaddr);
- __tsan_java_mutex_lock(lockaddr);
- int rec = __tsan_java_mutex_unlock_rec(lockaddr);
- if (rec != 3) {
- printf("FAILED 0 rec=%d\n", rec);
- exit(1);
- }
- *(int*)varaddr = 42;
- sleep(2);
- __tsan_java_mutex_lock_rec(lockaddr, rec);
- __tsan_java_mutex_unlock(lockaddr);
- __tsan_java_mutex_unlock(lockaddr);
- __tsan_java_mutex_unlock(lockaddr);
- return 0;
-}
-
-int main() {
- int const kHeapSize = 1024 * 1024;
- void *jheap = malloc(kHeapSize);
- __tsan_java_init((jptr)jheap, kHeapSize);
- const int kBlockSize = 16;
- __tsan_java_alloc((jptr)jheap, kBlockSize);
- varaddr = (jptr)jheap;
- *(int*)varaddr = 0;
- lockaddr = (jptr)jheap + 8;
- pthread_t th;
- pthread_create(&th, 0, Thread, 0);
- sleep(1);
- __tsan_java_mutex_lock(lockaddr);
- *(int*)varaddr = 43;
- __tsan_java_mutex_unlock(lockaddr);
- pthread_join(th, 0);
- __tsan_java_free((jptr)jheap, kBlockSize);
- printf("OK\n");
- return __tsan_java_fini();
-}
-
-// CHECK: WARNING: ThreadSanitizer: data race
-// CHECK-NOT: FAILED
diff --git a/lib/tsan/lit_tests/java_race.cc b/lib/tsan/lit_tests/java_race.cc
deleted file mode 100644
index 4841a7db0a9c..000000000000
--- a/lib/tsan/lit_tests/java_race.cc
+++ /dev/null
@@ -1,23 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-#include "java.h"
-
-void *Thread(void *p) {
- *(int*)p = 42;
- return 0;
-}
-
-int main() {
- int const kHeapSize = 1024 * 1024;
- void *jheap = malloc(kHeapSize);
- __tsan_java_init((jptr)jheap, kHeapSize);
- const int kBlockSize = 16;
- __tsan_java_alloc((jptr)jheap, kBlockSize);
- pthread_t th;
- pthread_create(&th, 0, Thread, jheap);
- *(int*)jheap = 43;
- pthread_join(th, 0);
- __tsan_java_free((jptr)jheap, kBlockSize);
- return __tsan_java_fini();
-}
-
-// CHECK: WARNING: ThreadSanitizer: data race
diff --git a/lib/tsan/lit_tests/java_race_move.cc b/lib/tsan/lit_tests/java_race_move.cc
deleted file mode 100644
index 6da8a106483c..000000000000
--- a/lib/tsan/lit_tests/java_race_move.cc
+++ /dev/null
@@ -1,31 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-#include "java.h"
-
-jptr varaddr;
-jptr varaddr2;
-
-void *Thread(void *p) {
- sleep(1);
- *(int*)varaddr2 = 42;
- return 0;
-}
-
-int main() {
- int const kHeapSize = 1024 * 1024;
- void *jheap = malloc(kHeapSize);
- __tsan_java_init((jptr)jheap, kHeapSize);
- const int kBlockSize = 64;
- int const kMove = 1024;
- __tsan_java_alloc((jptr)jheap, kBlockSize);
- varaddr = (jptr)jheap + 16;
- varaddr2 = varaddr + kMove;
- pthread_t th;
- pthread_create(&th, 0, Thread, 0);
- *(int*)varaddr = 43;
- __tsan_java_move(varaddr, varaddr2, kBlockSize);
- pthread_join(th, 0);
- __tsan_java_free(varaddr2, kBlockSize);
- return __tsan_java_fini();
-}
-
-// CHECK: WARNING: ThreadSanitizer: data race
diff --git a/lib/tsan/lit_tests/java_rwlock.cc b/lib/tsan/lit_tests/java_rwlock.cc
deleted file mode 100644
index d1f38733ba03..000000000000
--- a/lib/tsan/lit_tests/java_rwlock.cc
+++ /dev/null
@@ -1,35 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
-#include "java.h"
-#include <unistd.h>
-
-jptr varaddr;
-jptr lockaddr;
-
-void *Thread(void *p) {
- sleep(1);
- __tsan_java_mutex_read_lock(lockaddr);
- *(int*)varaddr = 42;
- __tsan_java_mutex_read_unlock(lockaddr);
- return 0;
-}
-
-int main() {
- int const kHeapSize = 1024 * 1024;
- void *jheap = malloc(kHeapSize);
- __tsan_java_init((jptr)jheap, kHeapSize);
- const int kBlockSize = 16;
- __tsan_java_alloc((jptr)jheap, kBlockSize);
- varaddr = (jptr)jheap;
- lockaddr = (jptr)jheap + 8;
- pthread_t th;
- pthread_create(&th, 0, Thread, 0);
- __tsan_java_mutex_lock(lockaddr);
- *(int*)varaddr = 43;
- __tsan_java_mutex_unlock(lockaddr);
- pthread_join(th, 0);
- __tsan_java_free((jptr)jheap, kBlockSize);
- printf("OK\n");
- return __tsan_java_fini();
-}
-
-// CHECK-NOT: WARNING: ThreadSanitizer: data race
diff --git a/lib/tsan/lit_tests/lit.cfg b/lib/tsan/lit_tests/lit.cfg
deleted file mode 100644
index c4193639f493..000000000000
--- a/lib/tsan/lit_tests/lit.cfg
+++ /dev/null
@@ -1,81 +0,0 @@
-# -*- Python -*-
-
-import os
-
-import lit.util
-
-def get_required_attr(config, attr_name):
- attr_value = getattr(config, attr_name, None)
- if not attr_value:
- lit_config.fatal(
- "No attribute %r in test configuration! You may need to run "
- "tests from your build directory or add this attribute "
- "to lit.site.cfg " % attr_name)
- return attr_value
-
-# Setup config name.
-config.name = 'ThreadSanitizer'
-
-# Setup source root.
-config.test_source_root = os.path.dirname(__file__)
-
-def DisplayNoConfigMessage():
- lit_config.fatal("No site specific configuration available! " +
- "Try running your test from the build tree or running " +
- "make check-tsan")
-
-# Figure out LLVM source root.
-llvm_src_root = getattr(config, 'llvm_src_root', None)
-if llvm_src_root is None:
- # We probably haven't loaded the site-specific configuration: the user
- # is likely trying to run a test file directly, and the site configuration
- # wasn't created by the build system.
- tsan_site_cfg = lit_config.params.get('tsan_site_config', None)
- if (tsan_site_cfg) and (os.path.exists(tsan_site_cfg)):
- lit_config.load_config(config, tsan_site_cfg)
- raise SystemExit
-
- # Try to guess the location of site-specific configuration using llvm-config
- # util that can point where the build tree is.
- llvm_config = lit.util.which("llvm-config", config.environment["PATH"])
- if not llvm_config:
- DisplayNoConfigMessage()
-
- # Find out the presumed location of generated site config.
- llvm_obj_root = lit.util.capture(["llvm-config", "--obj-root"]).strip()
- tsan_site_cfg = os.path.join(llvm_obj_root, "projects", "compiler-rt",
- "lib", "tsan", "lit_tests", "lit.site.cfg")
- if (not tsan_site_cfg) or (not os.path.exists(tsan_site_cfg)):
- DisplayNoConfigMessage()
-
- lit_config.load_config(config, tsan_site_cfg)
- raise SystemExit
-
-# Setup environment variables for running ThreadSanitizer.
-tsan_options = "atexit_sleep_ms=0"
-
-config.environment['TSAN_OPTIONS'] = tsan_options
-
-# Setup default compiler flags used with -fsanitize=thread option.
-# FIXME: Review the set of required flags and check if it can be reduced.
-clang_tsan_cflags = ("-fsanitize=thread "
- + "-g "
- + "-Wall "
- + "-lpthread "
- + "-ldl "
- + "-m64 ")
-clang_tsan_cxxflags = "--driver-mode=g++ " + clang_tsan_cflags
-config.substitutions.append( ("%clangxx_tsan ", (" " + config.clang + " " +
- clang_tsan_cxxflags + " ")) )
-config.substitutions.append( ("%clang_tsan ", (" " + config.clang + " " +
- clang_tsan_cflags + " ")) )
-
-# Define CHECK-%os to check for OS-dependent output.
-config.substitutions.append( ('CHECK-%os', ("CHECK-" + config.host_os)))
-
-# Default test suffixes.
-config.suffixes = ['.c', '.cc', '.cpp']
-
-# ThreadSanitizer tests are currently supported on Linux only.
-if config.host_os not in ['Linux']:
- config.unsupported = True
diff --git a/lib/tsan/lit_tests/lit.site.cfg.in b/lib/tsan/lit_tests/lit.site.cfg.in
deleted file mode 100644
index b0e427446eaa..000000000000
--- a/lib/tsan/lit_tests/lit.site.cfg.in
+++ /dev/null
@@ -1,8 +0,0 @@
-## Autogenerated by LLVM/Clang configuration.
-# Do not edit!
-
-# Load common config for all compiler-rt lit tests.
-lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/lib/lit.common.configured")
-
-# Load tool-specific config that would do the real work.
-lit_config.load_config(config, "@CMAKE_CURRENT_SOURCE_DIR@/lit.cfg")
diff --git a/lib/tsan/lit_tests/load_shared_lib.cc b/lib/tsan/lit_tests/load_shared_lib.cc
deleted file mode 100644
index d60cd5700a8a..000000000000
--- a/lib/tsan/lit_tests/load_shared_lib.cc
+++ /dev/null
@@ -1,44 +0,0 @@
-// Check that if the list of shared libraries changes between the two race
-// reports, the second report occurring in a new shared library is still
-// symbolized correctly.
-
-// RUN: %clangxx_tsan -O1 %p/SharedLibs/load_shared_lib-so.cc \
-// RUN: -fPIC -shared -o %t-so.so
-// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-
-#include <dlfcn.h>
-#include <pthread.h>
-#include <stdio.h>
-
-#include <string>
-
-int GLOB = 0;
-
-void *write_glob(void *unused) {
- GLOB++;
- return NULL;
-}
-
-void race_two_threads(void *(*access_callback)(void *unused)) {
- pthread_t t1, t2;
- pthread_create(&t1, NULL, access_callback, NULL);
- pthread_create(&t2, NULL, access_callback, NULL);
- pthread_join(t1, NULL);
- pthread_join(t2, NULL);
-}
-
-int main(int argc, char *argv[]) {
- std::string path = std::string(argv[0]) + std::string("-so.so");
- race_two_threads(write_glob);
- // CHECK: write_glob
- void *lib = dlopen(path.c_str(), RTLD_NOW);
- if (!lib) {
- printf("error in dlopen(): %s\n", dlerror());
- return 1;
- }
- void *(*write_from_so)(void *unused);
- *(void **)&write_from_so = dlsym(lib, "write_from_so");
- race_two_threads(write_from_so);
- // CHECK: write_from_so
- return 0;
-}
diff --git a/lib/tsan/lit_tests/longjmp.cc b/lib/tsan/lit_tests/longjmp.cc
deleted file mode 100644
index d9ca4ca5e6e9..000000000000
--- a/lib/tsan/lit_tests/longjmp.cc
+++ /dev/null
@@ -1,22 +0,0 @@
-// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
-#include <stdio.h>
-#include <stdlib.h>
-#include <setjmp.h>
-
-int foo(jmp_buf env) {
- longjmp(env, 42);
-}
-
-int main() {
- jmp_buf env;
- if (setjmp(env) == 42) {
- printf("JUMPED\n");
- return 0;
- }
- foo(env);
- printf("FAILED\n");
- return 0;
-}
-
-// CHECK-NOT: FAILED
-// CHECK: JUMPED
diff --git a/lib/tsan/lit_tests/longjmp2.cc b/lib/tsan/lit_tests/longjmp2.cc
deleted file mode 100644
index 0d551fa19d94..000000000000
--- a/lib/tsan/lit_tests/longjmp2.cc
+++ /dev/null
@@ -1,24 +0,0 @@
-// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
-#include <stdio.h>
-#include <stdlib.h>
-#include <setjmp.h>
-
-int foo(sigjmp_buf env) {
- printf("env=%p\n", env);
- siglongjmp(env, 42);
-}
-
-int main() {
- sigjmp_buf env;
- printf("env=%p\n", env);
- if (sigsetjmp(env, 1) == 42) {
- printf("JUMPED\n");
- return 0;
- }
- foo(env);
- printf("FAILED\n");
- return 0;
-}
-
-// CHECK-NOT: FAILED
-// CHECK: JUMPED
diff --git a/lib/tsan/lit_tests/longjmp3.cc b/lib/tsan/lit_tests/longjmp3.cc
deleted file mode 100644
index ae2cfd05fe1a..000000000000
--- a/lib/tsan/lit_tests/longjmp3.cc
+++ /dev/null
@@ -1,48 +0,0 @@
-// RUN: %clang_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <setjmp.h>
-
-void bar(jmp_buf env) {
- volatile int x = 42;
- longjmp(env, 42);
- x++;
-}
-
-void foo(jmp_buf env) {
- volatile int x = 42;
- bar(env);
- x++;
-}
-
-void badguy() {
- pthread_mutex_t mtx;
- pthread_mutex_init(&mtx, 0);
- pthread_mutex_lock(&mtx);
- pthread_mutex_destroy(&mtx);
-}
-
-void mymain() {
- jmp_buf env;
- if (setjmp(env) == 42) {
- badguy();
- return;
- }
- foo(env);
- printf("FAILED\n");
-}
-
-int main() {
- volatile int x = 42;
- mymain();
- return x;
-}
-
-// CHECK-NOT: FAILED
-// CHECK: WARNING: ThreadSanitizer: destroy of a locked mutex
-// CHECK: #0 pthread_mutex_destroy
-// CHECK: #1 badguy
-// CHECK: #2 mymain
-// CHECK: #3 main
-
diff --git a/lib/tsan/lit_tests/longjmp4.cc b/lib/tsan/lit_tests/longjmp4.cc
deleted file mode 100644
index 6b0526ef3a66..000000000000
--- a/lib/tsan/lit_tests/longjmp4.cc
+++ /dev/null
@@ -1,51 +0,0 @@
-// RUN: %clang_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <setjmp.h>
-#include <string.h>
-
-void bar(jmp_buf env) {
- volatile int x = 42;
- jmp_buf env2;
- memcpy(env2, env, sizeof(jmp_buf));
- longjmp(env2, 42);
- x++;
-}
-
-void foo(jmp_buf env) {
- volatile int x = 42;
- bar(env);
- x++;
-}
-
-void badguy() {
- pthread_mutex_t mtx;
- pthread_mutex_init(&mtx, 0);
- pthread_mutex_lock(&mtx);
- pthread_mutex_destroy(&mtx);
-}
-
-void mymain() {
- jmp_buf env;
- if (setjmp(env) == 42) {
- badguy();
- return;
- }
- foo(env);
- printf("FAILED\n");
-}
-
-int main() {
- volatile int x = 42;
- mymain();
- return x;
-}
-
-// CHECK-NOT: FAILED
-// CHECK: WARNING: ThreadSanitizer: destroy of a locked mutex
-// CHECK: #0 pthread_mutex_destroy
-// CHECK: #1 badguy
-// CHECK: #2 mymain
-// CHECK: #3 main
-
diff --git a/lib/tsan/lit_tests/malloc_overflow.cc b/lib/tsan/lit_tests/malloc_overflow.cc
deleted file mode 100644
index afbebc8bec44..000000000000
--- a/lib/tsan/lit_tests/malloc_overflow.cc
+++ /dev/null
@@ -1,23 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t
-// RUN: TSAN_OPTIONS=allocator_may_return_null=1 %t 2>&1 | FileCheck %s
-#include <stdio.h>
-#include <stdlib.h>
-
-int main() {
- void *p = malloc((size_t)-1);
- if (p != 0)
- printf("FAIL malloc(-1) = %p\n", p);
- p = malloc((size_t)-1 / 2);
- if (p != 0)
- printf("FAIL malloc(-1/2) = %p\n", p);
- p = calloc((size_t)-1, (size_t)-1);
- if (p != 0)
- printf("FAIL calloc(-1, -1) = %p\n", p);
- p = calloc((size_t)-1 / 2, (size_t)-1 / 2);
- if (p != 0)
- printf("FAIL calloc(-1/2, -1/2) = %p\n", p);
- printf("OK\n");
-}
-
-// CHECK-NOT: FAIL
-// CHECK-NOT: failed to allocate
diff --git a/lib/tsan/lit_tests/malloc_stack.cc b/lib/tsan/lit_tests/malloc_stack.cc
deleted file mode 100644
index 3603497ef311..000000000000
--- a/lib/tsan/lit_tests/malloc_stack.cc
+++ /dev/null
@@ -1,25 +0,0 @@
-// RUN: %clang_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <unistd.h>
-
-_Atomic(int*) p;
-
-void *thr(void *a) {
- sleep(1);
- int *pp = __c11_atomic_load(&p, __ATOMIC_RELAXED);
- *pp = 42;
- return 0;
-}
-
-int main() {
- pthread_t th;
- pthread_create(&th, 0, thr, p);
- __c11_atomic_store(&p, new int, __ATOMIC_RELAXED);
- pthread_join(th, 0);
-}
-
-// CHECK: data race
-// CHECK: Previous write
-// CHECK: #0 operator new
-// CHECK: Location is heap block
-// CHECK: #0 operator new
diff --git a/lib/tsan/lit_tests/memcpy_race.cc b/lib/tsan/lit_tests/memcpy_race.cc
deleted file mode 100644
index 8f39113674d6..000000000000
--- a/lib/tsan/lit_tests/memcpy_race.cc
+++ /dev/null
@@ -1,42 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-
-char *data = new char[10];
-char *data1 = new char[10];
-char *data2 = new char[10];
-
-void *Thread1(void *x) {
- static volatile int size = 1;
- memcpy(data+5, data1, size);
- return NULL;
-}
-
-void *Thread2(void *x) {
- static volatile int size = 4;
- sleep(1);
- memcpy(data+3, data2, size);
- return NULL;
-}
-
-int main() {
- fprintf(stderr, "addr=%p\n", &data[5]);
- pthread_t t[2];
- pthread_create(&t[0], NULL, Thread1, NULL);
- pthread_create(&t[1], NULL, Thread2, NULL);
- pthread_join(t[0], NULL);
- pthread_join(t[1], NULL);
- return 0;
-}
-
-// CHECK: addr=[[ADDR:0x[0-9,a-f]+]]
-// CHECK: WARNING: ThreadSanitizer: data race
-// CHECK: Write of size 1 at [[ADDR]] by thread T2:
-// CHECK: #0 memcpy
-// CHECK: #1 Thread2
-// CHECK: Previous write of size 1 at [[ADDR]] by thread T1:
-// CHECK: #0 memcpy
-// CHECK: #1 Thread1
diff --git a/lib/tsan/lit_tests/mop_with_offset.cc b/lib/tsan/lit_tests/mop_with_offset.cc
deleted file mode 100644
index 2b6a4ff50aaf..000000000000
--- a/lib/tsan/lit_tests/mop_with_offset.cc
+++ /dev/null
@@ -1,36 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <unistd.h>
-
-void *Thread1(void *x) {
- int *p = (int*)x;
- p[0] = 1;
- return NULL;
-}
-
-void *Thread2(void *x) {
- sleep(1);
- char *p = (char*)x;
- p[2] = 1;
- return NULL;
-}
-
-int main() {
- int *data = new int(42);
- fprintf(stderr, "ptr1=%p\n", data);
- fprintf(stderr, "ptr2=%p\n", (char*)data + 2);
- pthread_t t[2];
- pthread_create(&t[0], NULL, Thread1, data);
- pthread_create(&t[1], NULL, Thread2, data);
- pthread_join(t[0], NULL);
- pthread_join(t[1], NULL);
- delete data;
-}
-
-// CHECK: ptr1=[[PTR1:0x[0-9,a-f]+]]
-// CHECK: ptr2=[[PTR2:0x[0-9,a-f]+]]
-// CHECK: WARNING: ThreadSanitizer: data race
-// CHECK: Write of size 1 at [[PTR2]] by thread T2:
-// CHECK: Previous write of size 4 at [[PTR1]] by thread T1:
diff --git a/lib/tsan/lit_tests/mop_with_offset2.cc b/lib/tsan/lit_tests/mop_with_offset2.cc
deleted file mode 100644
index 037c4db5f524..000000000000
--- a/lib/tsan/lit_tests/mop_with_offset2.cc
+++ /dev/null
@@ -1,36 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <unistd.h>
-
-void *Thread1(void *x) {
- sleep(1);
- int *p = (int*)x;
- p[0] = 1;
- return NULL;
-}
-
-void *Thread2(void *x) {
- char *p = (char*)x;
- p[2] = 1;
- return NULL;
-}
-
-int main() {
- int *data = new int(42);
- fprintf(stderr, "ptr1=%p\n", data);
- fprintf(stderr, "ptr2=%p\n", (char*)data + 2);
- pthread_t t[2];
- pthread_create(&t[0], NULL, Thread1, data);
- pthread_create(&t[1], NULL, Thread2, data);
- pthread_join(t[0], NULL);
- pthread_join(t[1], NULL);
- delete data;
-}
-
-// CHECK: ptr1=[[PTR1:0x[0-9,a-f]+]]
-// CHECK: ptr2=[[PTR2:0x[0-9,a-f]+]]
-// CHECK: WARNING: ThreadSanitizer: data race
-// CHECK: Write of size 4 at [[PTR1]] by thread T1:
-// CHECK: Previous write of size 1 at [[PTR2]] by thread T2:
diff --git a/lib/tsan/lit_tests/mutex_destroy_locked.cc b/lib/tsan/lit_tests/mutex_destroy_locked.cc
deleted file mode 100644
index 9b020d31b94c..000000000000
--- a/lib/tsan/lit_tests/mutex_destroy_locked.cc
+++ /dev/null
@@ -1,22 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <unistd.h>
-
-int main() {
- pthread_mutex_t m;
- pthread_mutex_init(&m, 0);
- pthread_mutex_lock(&m);
- pthread_mutex_destroy(&m);
- return 0;
-}
-
-// CHECK: WARNING: ThreadSanitizer: destroy of a locked mutex
-// CHECK: #0 pthread_mutex_destroy
-// CHECK: #1 main
-// CHECK: and:
-// CHECK: #0 pthread_mutex_lock
-// CHECK: #1 main
-// CHECK: Mutex {{.*}} created at:
-// CHECK: #0 pthread_mutex_init
-// CHECK: #1 main
-// CHECK: SUMMARY: ThreadSanitizer: destroy of a locked mutex{{.*}}main
diff --git a/lib/tsan/lit_tests/mutex_robust.cc b/lib/tsan/lit_tests/mutex_robust.cc
deleted file mode 100644
index b826616076ae..000000000000
--- a/lib/tsan/lit_tests/mutex_robust.cc
+++ /dev/null
@@ -1,36 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <errno.h>
-
-pthread_mutex_t m;
-
-void *thr(void *p) {
- pthread_mutex_lock(&m);
- return 0;
-}
-
-int main() {
- pthread_mutexattr_t a;
- pthread_mutexattr_init(&a);
- pthread_mutexattr_setrobust(&a, PTHREAD_MUTEX_ROBUST);
- pthread_mutex_init(&m, &a);
- pthread_t th;
- pthread_create(&th, 0, thr, 0);
- sleep(1);
- if (pthread_mutex_lock(&m) != EOWNERDEAD) {
- fprintf(stderr, "not EOWNERDEAD\n");
- exit(1);
- }
- pthread_join(th, 0);
- fprintf(stderr, "DONE\n");
-}
-
-// This is a correct code, and tsan must not bark.
-// CHECK-NOT: WARNING: ThreadSanitizer
-// CHECK-NOT: EOWNERDEAD
-// CHECK: DONE
-// CHECK-NOT: WARNING: ThreadSanitizer
-
diff --git a/lib/tsan/lit_tests/mutex_robust2.cc b/lib/tsan/lit_tests/mutex_robust2.cc
deleted file mode 100644
index 5bd7ff682d1b..000000000000
--- a/lib/tsan/lit_tests/mutex_robust2.cc
+++ /dev/null
@@ -1,41 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <errno.h>
-
-pthread_mutex_t m;
-int x;
-
-void *thr(void *p) {
- pthread_mutex_lock(&m);
- x = 42;
- return 0;
-}
-
-int main() {
- pthread_mutexattr_t a;
- pthread_mutexattr_init(&a);
- pthread_mutexattr_setrobust(&a, PTHREAD_MUTEX_ROBUST);
- pthread_mutex_init(&m, &a);
- pthread_t th;
- pthread_create(&th, 0, thr, 0);
- sleep(1);
- if (pthread_mutex_trylock(&m) != EOWNERDEAD) {
- fprintf(stderr, "not EOWNERDEAD\n");
- exit(1);
- }
- x = 43;
- pthread_join(th, 0);
- fprintf(stderr, "DONE\n");
-}
-
-// This is a false positive, tsan must not bark at the data race.
-// But currently it does.
-// CHECK-NOT: WARNING: ThreadSanitizer WARNING: double lock of mutex
-// CHECK: WARNING: ThreadSanitizer: data race
-// CHECK-NOT: EOWNERDEAD
-// CHECK: DONE
-// CHECK-NOT: WARNING: ThreadSanitizer
-
diff --git a/lib/tsan/lit_tests/mutexset1.cc b/lib/tsan/lit_tests/mutexset1.cc
deleted file mode 100644
index ca87a7ba047d..000000000000
--- a/lib/tsan/lit_tests/mutexset1.cc
+++ /dev/null
@@ -1,37 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stdio.h>
-#include <unistd.h>
-
-int Global;
-pthread_mutex_t mtx;
-
-void *Thread1(void *x) {
- sleep(1);
- pthread_mutex_lock(&mtx);
- Global++;
- pthread_mutex_unlock(&mtx);
- return NULL;
-}
-
-void *Thread2(void *x) {
- Global--;
- return NULL;
-}
-
-int main() {
- // CHECK: WARNING: ThreadSanitizer: data race
- // CHECK: Write of size 4 at {{.*}} by thread T1
- // CHECK: (mutexes: write [[M1:M[0-9]+]]):
- // CHECK: Previous write of size 4 at {{.*}} by thread T2:
- // CHECK: Mutex [[M1]] created at:
- // CHECK: #0 pthread_mutex_init
- // CHECK: #1 main {{.*}}/mutexset1.cc:[[@LINE+1]]
- pthread_mutex_init(&mtx, 0);
- pthread_t t[2];
- pthread_create(&t[0], NULL, Thread1, NULL);
- pthread_create(&t[1], NULL, Thread2, NULL);
- pthread_join(t[0], NULL);
- pthread_join(t[1], NULL);
- pthread_mutex_destroy(&mtx);
-}
diff --git a/lib/tsan/lit_tests/mutexset2.cc b/lib/tsan/lit_tests/mutexset2.cc
deleted file mode 100644
index 9ccf952b0050..000000000000
--- a/lib/tsan/lit_tests/mutexset2.cc
+++ /dev/null
@@ -1,37 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stdio.h>
-#include <unistd.h>
-
-int Global;
-pthread_mutex_t mtx;
-
-void *Thread1(void *x) {
- pthread_mutex_lock(&mtx);
- Global++;
- pthread_mutex_unlock(&mtx);
- return NULL;
-}
-
-void *Thread2(void *x) {
- sleep(1);
- Global--;
- return NULL;
-}
-
-int main() {
- // CHECK: WARNING: ThreadSanitizer: data race
- // CHECK: Write of size 4 at {{.*}} by thread T2:
- // CHECK: Previous write of size 4 at {{.*}} by thread T1
- // CHECK: (mutexes: write [[M1:M[0-9]+]]):
- // CHECK: Mutex [[M1]] created at:
- // CHECK: #0 pthread_mutex_init
- // CHECK: #1 main {{.*}}/mutexset2.cc:[[@LINE+1]]
- pthread_mutex_init(&mtx, 0);
- pthread_t t[2];
- pthread_create(&t[0], NULL, Thread1, NULL);
- pthread_create(&t[1], NULL, Thread2, NULL);
- pthread_join(t[0], NULL);
- pthread_join(t[1], NULL);
- pthread_mutex_destroy(&mtx);
-}
diff --git a/lib/tsan/lit_tests/mutexset3.cc b/lib/tsan/lit_tests/mutexset3.cc
deleted file mode 100644
index 272ddafb3c4a..000000000000
--- a/lib/tsan/lit_tests/mutexset3.cc
+++ /dev/null
@@ -1,45 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stdio.h>
-#include <unistd.h>
-
-int Global;
-pthread_mutex_t mtx1;
-pthread_mutex_t mtx2;
-
-void *Thread1(void *x) {
- sleep(1);
- pthread_mutex_lock(&mtx1);
- pthread_mutex_lock(&mtx2);
- Global++;
- pthread_mutex_unlock(&mtx2);
- pthread_mutex_unlock(&mtx1);
- return NULL;
-}
-
-void *Thread2(void *x) {
- Global--;
- return NULL;
-}
-
-int main() {
- // CHECK: WARNING: ThreadSanitizer: data race
- // CHECK: Write of size 4 at {{.*}} by thread T1
- // CHECK: (mutexes: write [[M1:M[0-9]+]], write [[M2:M[0-9]+]]):
- // CHECK: Previous write of size 4 at {{.*}} by thread T2:
- // CHECK: Mutex [[M1]] created at:
- // CHECK: #0 pthread_mutex_init
- // CHECK: #1 main {{.*}}/mutexset3.cc:[[@LINE+4]]
- // CHECK: Mutex [[M2]] created at:
- // CHECK: #0 pthread_mutex_init
- // CHECK: #1 main {{.*}}/mutexset3.cc:[[@LINE+2]]
- pthread_mutex_init(&mtx1, 0);
- pthread_mutex_init(&mtx2, 0);
- pthread_t t[2];
- pthread_create(&t[0], NULL, Thread1, NULL);
- pthread_create(&t[1], NULL, Thread2, NULL);
- pthread_join(t[0], NULL);
- pthread_join(t[1], NULL);
- pthread_mutex_destroy(&mtx1);
- pthread_mutex_destroy(&mtx2);
-}
diff --git a/lib/tsan/lit_tests/mutexset4.cc b/lib/tsan/lit_tests/mutexset4.cc
deleted file mode 100644
index be751fa92bf0..000000000000
--- a/lib/tsan/lit_tests/mutexset4.cc
+++ /dev/null
@@ -1,45 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stdio.h>
-#include <unistd.h>
-
-int Global;
-pthread_mutex_t mtx1;
-pthread_mutex_t mtx2;
-
-void *Thread1(void *x) {
- pthread_mutex_lock(&mtx1);
- pthread_mutex_lock(&mtx2);
- Global++;
- pthread_mutex_unlock(&mtx2);
- pthread_mutex_unlock(&mtx1);
- return NULL;
-}
-
-void *Thread2(void *x) {
- sleep(1);
- Global--;
- return NULL;
-}
-
-int main() {
- // CHECK: WARNING: ThreadSanitizer: data race
- // CHECK: Write of size 4 at {{.*}} by thread T2:
- // CHECK: Previous write of size 4 at {{.*}} by thread T1
- // CHECK: (mutexes: write [[M1:M[0-9]+]], write [[M2:M[0-9]+]]):
- // CHECK: Mutex [[M1]] created at:
- // CHECK: #0 pthread_mutex_init
- // CHECK: #1 main {{.*}}/mutexset4.cc:[[@LINE+4]]
- // CHECK: Mutex [[M2]] created at:
- // CHECK: #0 pthread_mutex_init
- // CHECK: #1 main {{.*}}/mutexset4.cc:[[@LINE+2]]
- pthread_mutex_init(&mtx1, 0);
- pthread_mutex_init(&mtx2, 0);
- pthread_t t[2];
- pthread_create(&t[0], NULL, Thread1, NULL);
- pthread_create(&t[1], NULL, Thread2, NULL);
- pthread_join(t[0], NULL);
- pthread_join(t[1], NULL);
- pthread_mutex_destroy(&mtx1);
- pthread_mutex_destroy(&mtx2);
-}
diff --git a/lib/tsan/lit_tests/mutexset5.cc b/lib/tsan/lit_tests/mutexset5.cc
deleted file mode 100644
index e013edb4656a..000000000000
--- a/lib/tsan/lit_tests/mutexset5.cc
+++ /dev/null
@@ -1,46 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stdio.h>
-#include <unistd.h>
-
-int Global;
-pthread_mutex_t mtx1;
-pthread_mutex_t mtx2;
-
-void *Thread1(void *x) {
- sleep(1);
- pthread_mutex_lock(&mtx1);
- Global++;
- pthread_mutex_unlock(&mtx1);
- return NULL;
-}
-
-void *Thread2(void *x) {
- pthread_mutex_lock(&mtx2);
- Global--;
- pthread_mutex_unlock(&mtx2);
- return NULL;
-}
-
-int main() {
- // CHECK: WARNING: ThreadSanitizer: data race
- // CHECK: Write of size 4 at {{.*}} by thread T1
- // CHECK: (mutexes: write [[M1:M[0-9]+]]):
- // CHECK: Previous write of size 4 at {{.*}} by thread T2
- // CHECK: (mutexes: write [[M2:M[0-9]+]]):
- // CHECK: Mutex [[M1]] created at:
- // CHECK: #0 pthread_mutex_init
- // CHECK: #1 main {{.*}}/mutexset5.cc:[[@LINE+4]]
- // CHECK: Mutex [[M2]] created at:
- // CHECK: #0 pthread_mutex_init
- // CHECK: #1 main {{.*}}/mutexset5.cc:[[@LINE+5]]
- pthread_mutex_init(&mtx1, 0);
- pthread_mutex_init(&mtx2, 0);
- pthread_t t[2];
- pthread_create(&t[0], NULL, Thread1, NULL);
- pthread_create(&t[1], NULL, Thread2, NULL);
- pthread_join(t[0], NULL);
- pthread_join(t[1], NULL);
- pthread_mutex_destroy(&mtx1);
- pthread_mutex_destroy(&mtx2);
-}
diff --git a/lib/tsan/lit_tests/mutexset6.cc b/lib/tsan/lit_tests/mutexset6.cc
deleted file mode 100644
index f5e6e66becf8..000000000000
--- a/lib/tsan/lit_tests/mutexset6.cc
+++ /dev/null
@@ -1,53 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stdio.h>
-#include <unistd.h>
-
-int Global;
-pthread_mutex_t mtx1;
-pthread_spinlock_t mtx2;
-pthread_rwlock_t mtx3;
-
-void *Thread1(void *x) {
- sleep(1);
- pthread_mutex_lock(&mtx1);
- Global++;
- pthread_mutex_unlock(&mtx1);
- return NULL;
-}
-
-void *Thread2(void *x) {
- pthread_mutex_lock(&mtx1);
- pthread_mutex_unlock(&mtx1);
- pthread_spin_lock(&mtx2);
- pthread_rwlock_rdlock(&mtx3);
- Global--;
- pthread_spin_unlock(&mtx2);
- pthread_rwlock_unlock(&mtx3);
- return NULL;
-}
-
-int main() {
- // CHECK: WARNING: ThreadSanitizer: data race
- // CHECK: Write of size 4 at {{.*}} by thread T1
- // CHECK: (mutexes: write [[M1:M[0-9]+]]):
- // CHECK: Previous write of size 4 at {{.*}} by thread T2
- // CHECK: (mutexes: write [[M2:M[0-9]+]], read [[M3:M[0-9]+]]):
- // CHECK: Mutex [[M1]] created at:
- // CHECK: #1 main {{.*}}/mutexset6.cc:[[@LINE+5]]
- // CHECK: Mutex [[M2]] created at:
- // CHECK: #1 main {{.*}}/mutexset6.cc:[[@LINE+4]]
- // CHECK: Mutex [[M3]] created at:
- // CHECK: #1 main {{.*}}/mutexset6.cc:[[@LINE+3]]
- pthread_mutex_init(&mtx1, 0);
- pthread_spin_init(&mtx2, 0);
- pthread_rwlock_init(&mtx3, 0);
- pthread_t t[2];
- pthread_create(&t[0], NULL, Thread1, NULL);
- pthread_create(&t[1], NULL, Thread2, NULL);
- pthread_join(t[0], NULL);
- pthread_join(t[1], NULL);
- pthread_mutex_destroy(&mtx1);
- pthread_spin_destroy(&mtx2);
- pthread_rwlock_destroy(&mtx3);
-}
diff --git a/lib/tsan/lit_tests/mutexset7.cc b/lib/tsan/lit_tests/mutexset7.cc
deleted file mode 100644
index 51451b215490..000000000000
--- a/lib/tsan/lit_tests/mutexset7.cc
+++ /dev/null
@@ -1,39 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stdio.h>
-#include <unistd.h>
-
-int Global;
-__thread int huge[1024*1024];
-
-void *Thread1(void *x) {
- sleep(1);
- Global++;
- return NULL;
-}
-
-void *Thread2(void *x) {
- pthread_mutex_t mtx;
- pthread_mutex_init(&mtx, 0);
- pthread_mutex_lock(&mtx);
- Global--;
- pthread_mutex_unlock(&mtx);
- pthread_mutex_destroy(&mtx);
- return NULL;
-}
-
-int main() {
- pthread_t t[2];
- pthread_create(&t[0], NULL, Thread1, NULL);
- pthread_create(&t[1], NULL, Thread2, NULL);
- pthread_join(t[0], NULL);
- pthread_join(t[1], NULL);
-}
-
-// CHECK: WARNING: ThreadSanitizer: data race
-// CHECK: Write of size 4 at {{.*}} by thread T1:
-// CHECK: Previous write of size 4 at {{.*}} by thread T2
-// CHECK: (mutexes: write [[M1:M[0-9]+]]):
-// CHECK: Mutex [[M1]] is already destroyed
-// CHECK-NOT: Mutex {{.*}} created at
-
diff --git a/lib/tsan/lit_tests/mutexset8.cc b/lib/tsan/lit_tests/mutexset8.cc
deleted file mode 100644
index 8822b050e939..000000000000
--- a/lib/tsan/lit_tests/mutexset8.cc
+++ /dev/null
@@ -1,39 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stdio.h>
-#include <unistd.h>
-
-int Global;
-pthread_mutex_t *mtx;
-
-void *Thread1(void *x) {
- sleep(1);
- pthread_mutex_lock(mtx);
- Global++;
- pthread_mutex_unlock(mtx);
- return NULL;
-}
-
-void *Thread2(void *x) {
- Global--;
- return NULL;
-}
-
-int main() {
- // CHECK: WARNING: ThreadSanitizer: data race
- // CHECK: Write of size 4 at {{.*}} by thread T1
- // CHECK: (mutexes: write [[M1:M[0-9]+]]):
- // CHECK: Previous write of size 4 at {{.*}} by thread T2:
- // CHECK: Mutex [[M1]] created at:
- // CHECK: #0 pthread_mutex_init
- // CHECK: #1 main {{.*}}/mutexset8.cc
- mtx = new pthread_mutex_t;
- pthread_mutex_init(mtx, 0);
- pthread_t t[2];
- pthread_create(&t[0], NULL, Thread1, NULL);
- pthread_create(&t[1], NULL, Thread2, NULL);
- pthread_join(t[0], NULL);
- pthread_join(t[1], NULL);
- pthread_mutex_destroy(mtx);
- delete mtx;
-}
diff --git a/lib/tsan/lit_tests/oob_race.cc b/lib/tsan/lit_tests/oob_race.cc
deleted file mode 100644
index 9d8e2220d9a5..000000000000
--- a/lib/tsan/lit_tests/oob_race.cc
+++ /dev/null
@@ -1,24 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stdio.h>
-
-const long kOffset = 64*1024;
-
-void *Thread(void *p) {
- ((char*)p)[-kOffset] = 43;
- return 0;
-}
-
-int main() {
- char *volatile p0 = new char[16];
- delete[] p0;
- char *p = new char[32];
- pthread_t th;
- pthread_create(&th, 0, Thread, p);
- p[-kOffset] = 42;
- pthread_join(th, 0);
-}
-
-// Used to crash with CHECK failed.
-// CHECK: WARNING: ThreadSanitizer: data race
-
diff --git a/lib/tsan/lit_tests/race_on_barrier.c b/lib/tsan/lit_tests/race_on_barrier.c
deleted file mode 100644
index 3c0199dec22e..000000000000
--- a/lib/tsan/lit_tests/race_on_barrier.c
+++ /dev/null
@@ -1,31 +0,0 @@
-// RUN: %clang_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stdio.h>
-#include <stddef.h>
-#include <unistd.h>
-
-pthread_barrier_t B;
-int Global;
-
-void *Thread1(void *x) {
- pthread_barrier_init(&B, 0, 2);
- pthread_barrier_wait(&B);
- return NULL;
-}
-
-void *Thread2(void *x) {
- sleep(1);
- pthread_barrier_wait(&B);
- return NULL;
-}
-
-int main() {
- pthread_t t;
- pthread_create(&t, NULL, Thread1, NULL);
- Thread2(0);
- pthread_join(t, NULL);
- pthread_barrier_destroy(&B);
- return 0;
-}
-
-// CHECK: WARNING: ThreadSanitizer: data race
diff --git a/lib/tsan/lit_tests/race_on_barrier2.c b/lib/tsan/lit_tests/race_on_barrier2.c
deleted file mode 100644
index 62773d43e66e..000000000000
--- a/lib/tsan/lit_tests/race_on_barrier2.c
+++ /dev/null
@@ -1,31 +0,0 @@
-// RUN: %clang_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stdio.h>
-#include <stddef.h>
-#include <unistd.h>
-
-pthread_barrier_t B;
-int Global;
-
-void *Thread1(void *x) {
- if (pthread_barrier_wait(&B) == PTHREAD_BARRIER_SERIAL_THREAD)
- pthread_barrier_destroy(&B);
- return NULL;
-}
-
-void *Thread2(void *x) {
- if (pthread_barrier_wait(&B) == PTHREAD_BARRIER_SERIAL_THREAD)
- pthread_barrier_destroy(&B);
- return NULL;
-}
-
-int main() {
- pthread_barrier_init(&B, 0, 2);
- pthread_t t;
- pthread_create(&t, NULL, Thread1, NULL);
- Thread2(0);
- pthread_join(t, NULL);
- return 0;
-}
-
-// CHECK: WARNING: ThreadSanitizer: data race
diff --git a/lib/tsan/lit_tests/race_on_heap.cc b/lib/tsan/lit_tests/race_on_heap.cc
deleted file mode 100644
index a84c0de96558..000000000000
--- a/lib/tsan/lit_tests/race_on_heap.cc
+++ /dev/null
@@ -1,47 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-void *Thread1(void *p) {
- *(int*)p = 42;
- return 0;
-}
-
-void *Thread2(void *p) {
- *(int*)p = 44;
- return 0;
-}
-
-void *alloc() {
- return malloc(99);
-}
-
-void *AllocThread(void* arg) {
- return alloc();
-}
-
-int main() {
- void *p = 0;
- pthread_t t[2];
- pthread_create(&t[0], 0, AllocThread, 0);
- pthread_join(t[0], &p);
- fprintf(stderr, "addr=%p\n", p);
- pthread_create(&t[0], 0, Thread1, (char*)p + 16);
- pthread_create(&t[1], 0, Thread2, (char*)p + 16);
- pthread_join(t[0], 0);
- pthread_join(t[1], 0);
- return 0;
-}
-
-// CHECK: addr=[[ADDR:0x[0-9,a-f]+]]
-// CHECK: WARNING: ThreadSanitizer: data race
-// ...
-// CHECK: Location is heap block of size 99 at [[ADDR]] allocated by thread T1:
-// CHCEKL #0 malloc
-// CHECK: #{{1|2}} alloc
-// CHECK: #{{2|3}} AllocThread
-// ...
-// CHECK: Thread T1 (tid={{.*}}, finished) created by main thread at:
-// CHECK: #0 pthread_create
-// CHECK: #1 main
diff --git a/lib/tsan/lit_tests/race_on_mutex.c b/lib/tsan/lit_tests/race_on_mutex.c
deleted file mode 100644
index e66341414831..000000000000
--- a/lib/tsan/lit_tests/race_on_mutex.c
+++ /dev/null
@@ -1,42 +0,0 @@
-// RUN: %clang_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stdio.h>
-#include <stddef.h>
-#include <unistd.h>
-
-pthread_mutex_t Mtx;
-int Global;
-
-void *Thread1(void *x) {
- pthread_mutex_init(&Mtx, 0);
- pthread_mutex_lock(&Mtx);
- Global = 42;
- pthread_mutex_unlock(&Mtx);
- return NULL;
-}
-
-void *Thread2(void *x) {
- sleep(1);
- pthread_mutex_lock(&Mtx);
- Global = 43;
- pthread_mutex_unlock(&Mtx);
- return NULL;
-}
-
-int main() {
- pthread_t t[2];
- pthread_create(&t[0], NULL, Thread1, NULL);
- pthread_create(&t[1], NULL, Thread2, NULL);
- pthread_join(t[0], NULL);
- pthread_join(t[1], NULL);
- pthread_mutex_destroy(&Mtx);
- return 0;
-}
-
-// CHECK: WARNING: ThreadSanitizer: data race
-// CHECK-NEXT: Atomic read of size 1 at {{.*}} by thread T2:
-// CHECK-NEXT: #0 pthread_mutex_lock
-// CHECK-NEXT: #1 Thread2{{.*}} {{.*}}race_on_mutex.c:20{{(:3)?}} ({{.*}})
-// CHECK: Previous write of size 1 at {{.*}} by thread T1:
-// CHECK-NEXT: #0 pthread_mutex_init {{.*}} ({{.*}})
-// CHECK-NEXT: #1 Thread1{{.*}} {{.*}}race_on_mutex.c:11{{(:3)?}} ({{.*}})
diff --git a/lib/tsan/lit_tests/race_on_mutex2.c b/lib/tsan/lit_tests/race_on_mutex2.c
deleted file mode 100644
index 80c395e1f9ce..000000000000
--- a/lib/tsan/lit_tests/race_on_mutex2.c
+++ /dev/null
@@ -1,24 +0,0 @@
-// RUN: %clang_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stdio.h>
-#include <stddef.h>
-#include <unistd.h>
-
-void *Thread(void *x) {
- pthread_mutex_lock((pthread_mutex_t*)x);
- pthread_mutex_unlock((pthread_mutex_t*)x);
- return 0;
-}
-
-int main() {
- pthread_mutex_t Mtx;
- pthread_mutex_init(&Mtx, 0);
- pthread_t t;
- pthread_create(&t, 0, Thread, &Mtx);
- sleep(1);
- pthread_mutex_destroy(&Mtx);
- pthread_join(t, 0);
- return 0;
-}
-
-// CHECK: WARNING: ThreadSanitizer: data race
diff --git a/lib/tsan/lit_tests/race_on_read.cc b/lib/tsan/lit_tests/race_on_read.cc
deleted file mode 100644
index 4ca4b25bfa81..000000000000
--- a/lib/tsan/lit_tests/race_on_read.cc
+++ /dev/null
@@ -1,32 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-
-int fd;
-char buf;
-
-void *Thread(void *x) {
- read(fd, &buf, 1);
- return NULL;
-}
-
-int main() {
- fd = open("/dev/random", O_RDONLY);
- if (fd < 0) return 1;
- pthread_t t[2];
- pthread_create(&t[0], NULL, Thread, NULL);
- pthread_create(&t[1], NULL, Thread, NULL);
- pthread_join(t[0], NULL);
- pthread_join(t[1], NULL);
- close(fd);
-}
-
-// CHECK: WARNING: ThreadSanitizer: data race
-// CHECK: Write of size 1
-// CHECK: #0 read
-// CHECK: Previous write of size 1
-// CHECK: #0 read
diff --git a/lib/tsan/lit_tests/race_on_write.cc b/lib/tsan/lit_tests/race_on_write.cc
deleted file mode 100644
index 8a56c8464b91..000000000000
--- a/lib/tsan/lit_tests/race_on_write.cc
+++ /dev/null
@@ -1,39 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-
-int fd;
-char buf;
-
-void *Thread1(void *x) {
- buf = 1;
- sleep(1);
- return NULL;
-}
-
-void *Thread2(void *x) {
- write(fd, &buf, 1);
- return NULL;
-}
-
-int main() {
- fd = open("/dev/null", O_WRONLY);
- if (fd < 0) return 1;
- pthread_t t[2];
- pthread_create(&t[0], NULL, Thread1, NULL);
- sleep(1);
- pthread_create(&t[1], NULL, Thread2, NULL);
- pthread_join(t[0], NULL);
- pthread_join(t[1], NULL);
- close(fd);
-}
-
-// CHECK: WARNING: ThreadSanitizer: data race
-// CHECK: Read of size 1
-// CHECK: #0 write
-// CHECK: Previous write of size 1
-// CHECK: #0 Thread1
diff --git a/lib/tsan/lit_tests/race_with_finished_thread.cc b/lib/tsan/lit_tests/race_with_finished_thread.cc
deleted file mode 100644
index c713c67a398e..000000000000
--- a/lib/tsan/lit_tests/race_with_finished_thread.cc
+++ /dev/null
@@ -1,43 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-
-// Ensure that we can restore a stack of a finished thread.
-
-int g_data;
-
-void __attribute__((noinline)) foobar(int *p) {
- *p = 42;
-}
-
-void *Thread1(void *x) {
- foobar(&g_data);
- return NULL;
-}
-
-void *Thread2(void *x) {
- sleep(1);
- g_data = 43;
- return NULL;
-}
-
-int main() {
- pthread_t t[2];
- pthread_create(&t[0], NULL, Thread1, NULL);
- pthread_create(&t[1], NULL, Thread2, NULL);
- pthread_join(t[0], NULL);
- pthread_join(t[1], NULL);
- return 0;
-}
-
-// CHECK: WARNING: ThreadSanitizer: data race
-// CHECK: Write of size 4 at {{.*}} by thread T2:
-// CHECK: Previous write of size 4 at {{.*}} by thread T1:
-// CHECK: #0 foobar
-// CHECK: #1 Thread1
-// CHECK: Thread T1 (tid={{.*}}, finished) created by main thread at:
-// CHECK: #0 pthread_create
-// CHECK: #1 main
diff --git a/lib/tsan/lit_tests/signal_errno.cc b/lib/tsan/lit_tests/signal_errno.cc
deleted file mode 100644
index 2febca38294e..000000000000
--- a/lib/tsan/lit_tests/signal_errno.cc
+++ /dev/null
@@ -1,43 +0,0 @@
-// RUN: %clang_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <signal.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <errno.h>
-
-pthread_t mainth;
-volatile int done;
-
-static void MyHandler(int, siginfo_t *s, void *c) {
- errno = 1;
- done = 1;
-}
-
-static void* sendsignal(void *p) {
- pthread_kill(mainth, SIGPROF);
- return 0;
-}
-
-int main() {
- mainth = pthread_self();
- struct sigaction act = {};
- act.sa_sigaction = &MyHandler;
- sigaction(SIGPROF, &act, 0);
- pthread_t th;
- pthread_create(&th, 0, sendsignal, 0);
- while (done == 0) {
- volatile char *p = (char*)malloc(1);
- p[0] = 0;
- free((void*)p);
- pthread_yield();
- }
- pthread_join(th, 0);
- return 0;
-}
-
-// CHECK: WARNING: ThreadSanitizer: signal handler spoils errno
-// CHECK: #0 MyHandler(int, siginfo{{(_t)?}}*, void*) {{.*}}signal_errno.cc
-// CHECK: SUMMARY: ThreadSanitizer: signal handler spoils errno{{.*}}MyHandler
-
diff --git a/lib/tsan/lit_tests/signal_malloc.cc b/lib/tsan/lit_tests/signal_malloc.cc
deleted file mode 100644
index ef180b8a25b6..000000000000
--- a/lib/tsan/lit_tests/signal_malloc.cc
+++ /dev/null
@@ -1,26 +0,0 @@
-// RUN: %clang_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-#include <stdio.h>
-#include <stdlib.h>
-#include <signal.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-static void handler(int, siginfo_t*, void*) {
- // CHECK: WARNING: ThreadSanitizer: signal-unsafe call inside of a signal
- // CHECK: #0 malloc
- // CHECK: #{{(1|2)}} handler(int, siginfo{{(_t)?}}*, void*) {{.*}}signal_malloc.cc:[[@LINE+2]]
- // CHECK: SUMMARY: ThreadSanitizer: signal-unsafe call inside of a signal{{.*}}handler
- volatile char *p = (char*)malloc(1);
- p[0] = 0;
- free((void*)p);
-}
-
-int main() {
- struct sigaction act = {};
- act.sa_sigaction = &handler;
- sigaction(SIGPROF, &act, 0);
- kill(getpid(), SIGPROF);
- sleep(1);
- return 0;
-}
-
diff --git a/lib/tsan/lit_tests/sigsuspend.cc b/lib/tsan/lit_tests/sigsuspend.cc
deleted file mode 100644
index 78d507fa0af5..000000000000
--- a/lib/tsan/lit_tests/sigsuspend.cc
+++ /dev/null
@@ -1,38 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-#include <assert.h>
-#include <stdlib.h>
-#include <signal.h>
-#include <unistd.h>
-#include <stdio.h>
-
-static bool signal_handler_ran = false;
-
-void do_nothing_signal_handler(int signum) {
- write(1, "HANDLER\n", 8);
- signal_handler_ran = true;
-}
-
-int main() {
- const int kSignalToTest = SIGSYS;
- assert(SIG_ERR != signal(kSignalToTest, do_nothing_signal_handler));
- sigset_t empty_set;
- assert(0 == sigemptyset(&empty_set));
- sigset_t one_signal = empty_set;
- assert(0 == sigaddset(&one_signal, kSignalToTest));
- sigset_t old_set;
- assert(0 == sigprocmask(SIG_BLOCK, &one_signal, &old_set));
- raise(kSignalToTest);
- assert(!signal_handler_ran);
- sigset_t all_but_one;
- assert(0 == sigfillset(&all_but_one));
- assert(0 == sigdelset(&all_but_one, kSignalToTest));
- sigsuspend(&all_but_one);
- assert(signal_handler_ran);
-
- // Restore the original set.
- assert(0 == sigprocmask(SIG_SETMASK, &old_set, NULL));
- printf("DONE");
-}
-
-// CHECK: HANDLER
-// CHECK: DONE
diff --git a/lib/tsan/lit_tests/simple_race.c b/lib/tsan/lit_tests/simple_race.c
deleted file mode 100644
index 80a83e01a294..000000000000
--- a/lib/tsan/lit_tests/simple_race.c
+++ /dev/null
@@ -1,26 +0,0 @@
-// RUN: %clang_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stdio.h>
-
-int Global;
-
-void *Thread1(void *x) {
- Global = 42;
- return NULL;
-}
-
-void *Thread2(void *x) {
- Global = 43;
- return NULL;
-}
-
-int main() {
- pthread_t t[2];
- pthread_create(&t[0], NULL, Thread1, NULL);
- pthread_create(&t[1], NULL, Thread2, NULL);
- pthread_join(t[0], NULL);
- pthread_join(t[1], NULL);
- return 0;
-}
-
-// CHECK: WARNING: ThreadSanitizer: data race
diff --git a/lib/tsan/lit_tests/simple_race.cc b/lib/tsan/lit_tests/simple_race.cc
deleted file mode 100644
index 47854cfd9a3e..000000000000
--- a/lib/tsan/lit_tests/simple_race.cc
+++ /dev/null
@@ -1,26 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stdio.h>
-
-int Global;
-
-void *Thread1(void *x) {
- Global++;
- return NULL;
-}
-
-void *Thread2(void *x) {
- Global--;
- return NULL;
-}
-
-int main() {
- pthread_t t[2];
- pthread_create(&t[0], NULL, Thread1, NULL);
- pthread_create(&t[1], NULL, Thread2, NULL);
- pthread_join(t[0], NULL);
- pthread_join(t[1], NULL);
-}
-
-// CHECK: WARNING: ThreadSanitizer: data race
-// CHECK: SUMMARY: ThreadSanitizer: data race{{.*}}Thread
diff --git a/lib/tsan/lit_tests/simple_stack.c b/lib/tsan/lit_tests/simple_stack.c
deleted file mode 100644
index a447e2880447..000000000000
--- a/lib/tsan/lit_tests/simple_stack.c
+++ /dev/null
@@ -1,66 +0,0 @@
-// RUN: %clang_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stdio.h>
-#include <unistd.h>
-
-int Global;
-
-void __attribute__((noinline)) foo1() {
- Global = 42;
-}
-
-void __attribute__((noinline)) bar1() {
- volatile int tmp = 42; (void)tmp;
- foo1();
-}
-
-void __attribute__((noinline)) foo2() {
- volatile int v = Global; (void)v;
-}
-
-void __attribute__((noinline)) bar2() {
- volatile int tmp = 42; (void)tmp;
- foo2();
-}
-
-void *Thread1(void *x) {
- sleep(1);
- bar1();
- return NULL;
-}
-
-void *Thread2(void *x) {
- bar2();
- return NULL;
-}
-
-void StartThread(pthread_t *t, void *(*f)(void*)) {
- pthread_create(t, NULL, f, NULL);
-}
-
-int main() {
- pthread_t t[2];
- StartThread(&t[0], Thread1);
- StartThread(&t[1], Thread2);
- pthread_join(t[0], NULL);
- pthread_join(t[1], NULL);
- return 0;
-}
-
-// CHECK: WARNING: ThreadSanitizer: data race
-// CHECK-NEXT: Write of size 4 at {{.*}} by thread T1:
-// CHECK-NEXT: #0 foo1{{.*}} {{.*}}simple_stack.c:9{{(:3)?}} ({{.*}})
-// CHECK-NEXT: #1 bar1{{.*}} {{.*}}simple_stack.c:14{{(:3)?}} ({{.*}})
-// CHECK-NEXT: #2 Thread1{{.*}} {{.*}}simple_stack.c:28{{(:3)?}} ({{.*}})
-// CHECK: Previous read of size 4 at {{.*}} by thread T2:
-// CHECK-NEXT: #0 foo2{{.*}} {{.*}}simple_stack.c:18{{(:26)?}} ({{.*}})
-// CHECK-NEXT: #1 bar2{{.*}} {{.*}}simple_stack.c:23{{(:3)?}} ({{.*}})
-// CHECK-NEXT: #2 Thread2{{.*}} {{.*}}simple_stack.c:33{{(:3)?}} ({{.*}})
-// CHECK: Thread T1 (tid={{.*}}, running) created by main thread at:
-// CHECK-NEXT: #0 pthread_create {{.*}} ({{.*}})
-// CHECK-NEXT: #1 StartThread{{.*}} {{.*}}simple_stack.c:38{{(:3)?}} ({{.*}})
-// CHECK-NEXT: #2 main{{.*}} {{.*}}simple_stack.c:43{{(:3)?}} ({{.*}})
-// CHECK: Thread T2 ({{.*}}) created by main thread at:
-// CHECK-NEXT: #0 pthread_create {{.*}} ({{.*}})
-// CHECK-NEXT: #1 StartThread{{.*}} {{.*}}simple_stack.c:38{{(:3)?}} ({{.*}})
-// CHECK-NEXT: #2 main{{.*}} {{.*}}simple_stack.c:44{{(:3)?}} ({{.*}})
diff --git a/lib/tsan/lit_tests/simple_stack2.cc b/lib/tsan/lit_tests/simple_stack2.cc
deleted file mode 100644
index 7a034c4cd6ed..000000000000
--- a/lib/tsan/lit_tests/simple_stack2.cc
+++ /dev/null
@@ -1,53 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stdio.h>
-#include <unistd.h>
-
-int Global;
-
-void __attribute__((noinline)) foo1() {
- Global = 42;
-}
-
-void __attribute__((noinline)) bar1() {
- volatile int tmp = 42;
- int tmp2 = tmp;
- (void)tmp2;
- foo1();
-}
-
-void __attribute__((noinline)) foo2() {
- volatile int tmp = Global;
- int tmp2 = tmp;
- (void)tmp2;
-}
-
-void __attribute__((noinline)) bar2() {
- volatile int tmp = 42;
- int tmp2 = tmp;
- (void)tmp2;
- foo2();
-}
-
-void *Thread1(void *x) {
- sleep(1);
- bar1();
- return NULL;
-}
-
-int main() {
- pthread_t t;
- pthread_create(&t, NULL, Thread1, NULL);
- bar2();
- pthread_join(t, NULL);
-}
-
-// CHECK: WARNING: ThreadSanitizer: data race
-// CHECK-NEXT: Write of size 4 at {{.*}} by thread T1:
-// CHECK-NEXT: #0 foo1{{.*}} {{.*}}simple_stack2.cc:9{{(:3)?}} ({{.*}})
-// CHECK-NEXT: #1 bar1{{.*}} {{.*}}simple_stack2.cc:16{{(:3)?}} ({{.*}})
-// CHECK-NEXT: #2 Thread1{{.*}} {{.*}}simple_stack2.cc:34{{(:3)?}} ({{.*}})
-// CHECK: Previous read of size 4 at {{.*}} by main thread:
-// CHECK-NEXT: #0 foo2{{.*}} {{.*}}simple_stack2.cc:20{{(:28)?}} ({{.*}})
-// CHECK-NEXT: #1 bar2{{.*}} {{.*}}simple_stack2.cc:29{{(:3)?}} ({{.*}})
-// CHECK-NEXT: #2 main{{.*}} {{.*}}simple_stack2.cc:41{{(:3)?}} ({{.*}})
diff --git a/lib/tsan/lit_tests/sleep_sync.cc b/lib/tsan/lit_tests/sleep_sync.cc
deleted file mode 100644
index 217a52a097ce..000000000000
--- a/lib/tsan/lit_tests/sleep_sync.cc
+++ /dev/null
@@ -1,30 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <unistd.h>
-
-int X = 0;
-
-void MySleep() {
- sleep(1);
-}
-
-void *Thread(void *p) {
- MySleep(); // Assume the main thread has done the write.
- X = 42;
- return 0;
-}
-
-int main() {
- pthread_t t;
- pthread_create(&t, 0, Thread, 0);
- X = 43;
- pthread_join(t, 0);
- return 0;
-}
-
-// CHECK: WARNING: ThreadSanitizer: data race
-// ...
-// CHECK: As if synchronized via sleep:
-// CHECK-NEXT: #0 sleep
-// CHECK-NEXT: #1 MySleep
-// CHECK-NEXT: #2 Thread
diff --git a/lib/tsan/lit_tests/sleep_sync2.cc b/lib/tsan/lit_tests/sleep_sync2.cc
deleted file mode 100644
index e22999279f9f..000000000000
--- a/lib/tsan/lit_tests/sleep_sync2.cc
+++ /dev/null
@@ -1,22 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <unistd.h>
-
-int X = 0;
-
-void *Thread(void *p) {
- X = 42;
- return 0;
-}
-
-int main() {
- pthread_t t;
- sleep(1);
- pthread_create(&t, 0, Thread, 0);
- X = 43;
- pthread_join(t, 0);
- return 0;
-}
-
-// CHECK: WARNING: ThreadSanitizer: data race
-// CHECK-NOT: As if synchronized via sleep
diff --git a/lib/tsan/lit_tests/stack_race.cc b/lib/tsan/lit_tests/stack_race.cc
deleted file mode 100644
index 7fabce22a85c..000000000000
--- a/lib/tsan/lit_tests/stack_race.cc
+++ /dev/null
@@ -1,20 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stddef.h>
-
-void *Thread(void *a) {
- *(int*)a = 43;
- return 0;
-}
-
-int main() {
- int Var = 42;
- pthread_t t;
- pthread_create(&t, 0, Thread, &Var);
- Var = 43;
- pthread_join(t, 0);
-}
-
-// CHECK: WARNING: ThreadSanitizer: data race
-// CHECK: Location is stack of main thread.
-
diff --git a/lib/tsan/lit_tests/stack_race2.cc b/lib/tsan/lit_tests/stack_race2.cc
deleted file mode 100644
index c759ec92774f..000000000000
--- a/lib/tsan/lit_tests/stack_race2.cc
+++ /dev/null
@@ -1,28 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stddef.h>
-#include <unistd.h>
-
-void *Thread2(void *a) {
- *(int*)a = 43;
- return 0;
-}
-
-void *Thread(void *a) {
- int Var = 42;
- pthread_t t;
- pthread_create(&t, 0, Thread2, &Var);
- Var = 42;
- pthread_join(t, 0);
- return 0;
-}
-
-int main() {
- pthread_t t;
- pthread_create(&t, 0, Thread, 0);
- pthread_join(t, 0);
-}
-
-// CHECK: WARNING: ThreadSanitizer: data race
-// CHECK: Location is stack of thread T1.
-
diff --git a/lib/tsan/lit_tests/static_init1.cc b/lib/tsan/lit_tests/static_init1.cc
deleted file mode 100644
index 4faf5bc54743..000000000000
--- a/lib/tsan/lit_tests/static_init1.cc
+++ /dev/null
@@ -1,27 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-struct P {
- int x;
- int y;
-};
-
-void *Thread(void *x) {
- static P p = {rand(), rand()};
- if (p.x > RAND_MAX || p.y > RAND_MAX)
- exit(1);
- return 0;
-}
-
-int main() {
- pthread_t t[2];
- pthread_create(&t[0], 0, Thread, 0);
- pthread_create(&t[1], 0, Thread, 0);
- pthread_join(t[0], 0);
- pthread_join(t[1], 0);
- printf("PASS\n");
-}
-
-// CHECK-NOT: WARNING: ThreadSanitizer: data race
diff --git a/lib/tsan/lit_tests/static_init2.cc b/lib/tsan/lit_tests/static_init2.cc
deleted file mode 100644
index 96ef821a7525..000000000000
--- a/lib/tsan/lit_tests/static_init2.cc
+++ /dev/null
@@ -1,33 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-struct Cache {
- int x;
- explicit Cache(int x)
- : x(x) {
- }
-};
-
-void foo(Cache *my) {
- static Cache *c = my ? my : new Cache(rand());
- if (c->x >= RAND_MAX)
- exit(1);
-}
-
-void *Thread(void *x) {
- foo(new Cache(rand()));
- return 0;
-}
-
-int main() {
- pthread_t t[2];
- pthread_create(&t[0], 0, Thread, 0);
- pthread_create(&t[1], 0, Thread, 0);
- pthread_join(t[0], 0);
- pthread_join(t[1], 0);
- printf("PASS\n");
-}
-
-// CHECK-NOT: WARNING: ThreadSanitizer: data race
diff --git a/lib/tsan/lit_tests/static_init3.cc b/lib/tsan/lit_tests/static_init3.cc
deleted file mode 100644
index 70a3c16878ca..000000000000
--- a/lib/tsan/lit_tests/static_init3.cc
+++ /dev/null
@@ -1,47 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <sched.h>
-
-struct Cache {
- int x;
-};
-
-Cache g_cache;
-
-Cache *CreateCache() {
- g_cache.x = rand();
- return &g_cache;
-}
-
-_Atomic(Cache*) queue;
-
-void *Thread1(void *x) {
- static Cache *c = CreateCache();
- __c11_atomic_store(&queue, c, 0);
- return 0;
-}
-
-void *Thread2(void *x) {
- Cache *c = 0;
- for (;;) {
- c = __c11_atomic_load(&queue, 0);
- if (c)
- break;
- sched_yield();
- }
- if (c->x >= RAND_MAX)
- exit(1);
- return 0;
-}
-
-int main() {
- pthread_t t[2];
- pthread_create(&t[0], 0, Thread1, 0);
- pthread_create(&t[1], 0, Thread2, 0);
- pthread_join(t[0], 0);
- pthread_join(t[1], 0);
-}
-
-// CHECK: WARNING: ThreadSanitizer: data race
diff --git a/lib/tsan/lit_tests/static_init4.cc b/lib/tsan/lit_tests/static_init4.cc
deleted file mode 100644
index 5ecc39926a23..000000000000
--- a/lib/tsan/lit_tests/static_init4.cc
+++ /dev/null
@@ -1,37 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <sched.h>
-
-struct Cache {
- int x;
- explicit Cache(int x)
- : x(x) {
- }
-};
-
-int g_other;
-
-Cache *CreateCache() {
- g_other = rand();
- return new Cache(rand());
-}
-
-void *Thread1(void *x) {
- static Cache *c = CreateCache();
- if (c->x == g_other)
- exit(1);
- return 0;
-}
-
-int main() {
- pthread_t t[2];
- pthread_create(&t[0], 0, Thread1, 0);
- pthread_create(&t[1], 0, Thread1, 0);
- pthread_join(t[0], 0);
- pthread_join(t[1], 0);
- printf("PASS\n");
-}
-
-// CHECK-NOT: WARNING: ThreadSanitizer: data race
diff --git a/lib/tsan/lit_tests/static_init5.cc b/lib/tsan/lit_tests/static_init5.cc
deleted file mode 100644
index 1d0ed6d54ca2..000000000000
--- a/lib/tsan/lit_tests/static_init5.cc
+++ /dev/null
@@ -1,42 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <sched.h>
-
-struct Cache {
- int x;
- explicit Cache(int x)
- : x(x) {
- }
-};
-
-void *AsyncInit(void *p) {
- return new Cache((int)(long)p);
-}
-
-Cache *CreateCache() {
- pthread_t t;
- pthread_create(&t, 0, AsyncInit, (void*)(long)rand());
- void *res;
- pthread_join(t, &res);
- return (Cache*)res;
-}
-
-void *Thread1(void *x) {
- static Cache *c = CreateCache();
- if (c->x >= RAND_MAX)
- exit(1);
- return 0;
-}
-
-int main() {
- pthread_t t[2];
- pthread_create(&t[0], 0, Thread1, 0);
- pthread_create(&t[1], 0, Thread1, 0);
- pthread_join(t[0], 0);
- pthread_join(t[1], 0);
- printf("PASS\n");
-}
-
-// CHECK-NOT: WARNING: ThreadSanitizer: data race
diff --git a/lib/tsan/lit_tests/static_init6.cc b/lib/tsan/lit_tests/static_init6.cc
deleted file mode 100644
index c9099f9b6790..000000000000
--- a/lib/tsan/lit_tests/static_init6.cc
+++ /dev/null
@@ -1,42 +0,0 @@
-// RUN: %clangxx_tsan -static-libstdc++ -O1 %s -o %t && %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <sched.h>
-
-struct Cache {
- int x;
- explicit Cache(int x)
- : x(x) {
- }
-};
-
-void *AsyncInit(void *p) {
- return new Cache((int)(long)p);
-}
-
-Cache *CreateCache() {
- pthread_t t;
- pthread_create(&t, 0, AsyncInit, (void*)(long)rand());
- void *res;
- pthread_join(t, &res);
- return (Cache*)res;
-}
-
-void *Thread1(void *x) {
- static Cache *c = CreateCache();
- if (c->x >= RAND_MAX)
- exit(1);
- return 0;
-}
-
-int main() {
- pthread_t t[2];
- pthread_create(&t[0], 0, Thread1, 0);
- pthread_create(&t[1], 0, Thread1, 0);
- pthread_join(t[0], 0);
- pthread_join(t[1], 0);
- printf("PASS\n");
-}
-
-// CHECK-NOT: WARNING: ThreadSanitizer: data race
diff --git a/lib/tsan/lit_tests/suppress_same_address.cc b/lib/tsan/lit_tests/suppress_same_address.cc
deleted file mode 100644
index c516f89529f3..000000000000
--- a/lib/tsan/lit_tests/suppress_same_address.cc
+++ /dev/null
@@ -1,27 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-#include <pthread.h>
-
-int X;
-
-void *Thread1(void *x) {
- X = 42;
- X = 66;
- X = 78;
- return 0;
-}
-
-void *Thread2(void *x) {
- X = 11;
- X = 99;
- X = 73;
- return 0;
-}
-
-int main() {
- pthread_t t;
- pthread_create(&t, 0, Thread1, 0);
- Thread2(0);
- pthread_join(t, 0);
-}
-
-// CHECK: ThreadSanitizer: reported 1 warnings
diff --git a/lib/tsan/lit_tests/suppress_same_stacks.cc b/lib/tsan/lit_tests/suppress_same_stacks.cc
deleted file mode 100644
index f0ab8b30435e..000000000000
--- a/lib/tsan/lit_tests/suppress_same_stacks.cc
+++ /dev/null
@@ -1,27 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-#include <pthread.h>
-
-volatile int N; // Prevent loop unrolling.
-int **data;
-
-void *Thread1(void *x) {
- for (int i = 0; i < N; i++)
- data[i][0] = 42;
- return 0;
-}
-
-int main() {
- N = 4;
- data = new int*[N];
- for (int i = 0; i < N; i++)
- data[i] = new int;
- pthread_t t;
- pthread_create(&t, 0, Thread1, 0);
- Thread1(0);
- pthread_join(t, 0);
- for (int i = 0; i < N; i++)
- delete data[i];
- delete[] data;
-}
-
-// CHECK: ThreadSanitizer: reported 1 warnings
diff --git a/lib/tsan/lit_tests/suppressions_global.cc b/lib/tsan/lit_tests/suppressions_global.cc
deleted file mode 100644
index 181cb56cf2e6..000000000000
--- a/lib/tsan/lit_tests/suppressions_global.cc
+++ /dev/null
@@ -1,29 +0,0 @@
-// RUN: %clang_tsan -O1 %s -o %t && TSAN_OPTIONS="$TSAN_OPTIONS suppressions=%s.supp" %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stdio.h>
-
-int RacyGlobal;
-
-void *Thread1(void *x) {
- RacyGlobal = 42;
- return NULL;
-}
-
-void *Thread2(void *x) {
- RacyGlobal = 43;
- return NULL;
-}
-
-int main() {
- pthread_t t[2];
- pthread_create(&t[0], NULL, Thread1, NULL);
- pthread_create(&t[1], NULL, Thread2, NULL);
- pthread_join(t[0], NULL);
- pthread_join(t[1], NULL);
- printf("OK\n");
- return 0;
-}
-
-// CHECK-NOT: failed to open suppressions file
-// CHECK-NOT: WARNING: ThreadSanitizer: data race
-
diff --git a/lib/tsan/lit_tests/suppressions_global.cc.supp b/lib/tsan/lit_tests/suppressions_global.cc.supp
deleted file mode 100644
index 5fa8a2e43a93..000000000000
--- a/lib/tsan/lit_tests/suppressions_global.cc.supp
+++ /dev/null
@@ -1,2 +0,0 @@
-race:RacyGlobal
-
diff --git a/lib/tsan/lit_tests/suppressions_race.cc b/lib/tsan/lit_tests/suppressions_race.cc
deleted file mode 100644
index c88e69bec6a3..000000000000
--- a/lib/tsan/lit_tests/suppressions_race.cc
+++ /dev/null
@@ -1,31 +0,0 @@
-// RUN: %clang_tsan -O1 %s -o %t && TSAN_OPTIONS="$TSAN_OPTIONS suppressions=%s.supp" %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stdio.h>
-#include <unistd.h>
-
-int Global;
-
-void *Thread1(void *x) {
- sleep(1);
- Global = 42;
- return NULL;
-}
-
-void *Thread2(void *x) {
- Global = 43;
- return NULL;
-}
-
-int main() {
- pthread_t t[2];
- pthread_create(&t[0], NULL, Thread1, NULL);
- pthread_create(&t[1], NULL, Thread2, NULL);
- pthread_join(t[0], NULL);
- pthread_join(t[1], NULL);
- printf("OK\n");
- return 0;
-}
-
-// CHECK-NOT: failed to open suppressions file
-// CHECK-NOT: WARNING: ThreadSanitizer: data race
-
diff --git a/lib/tsan/lit_tests/suppressions_race.cc.supp b/lib/tsan/lit_tests/suppressions_race.cc.supp
deleted file mode 100644
index cbdba76ea93a..000000000000
--- a/lib/tsan/lit_tests/suppressions_race.cc.supp
+++ /dev/null
@@ -1,2 +0,0 @@
-race:Thread1
-
diff --git a/lib/tsan/lit_tests/suppressions_race2.cc b/lib/tsan/lit_tests/suppressions_race2.cc
deleted file mode 100644
index 57146f96a428..000000000000
--- a/lib/tsan/lit_tests/suppressions_race2.cc
+++ /dev/null
@@ -1,31 +0,0 @@
-// RUN: %clang_tsan -O1 %s -o %t && TSAN_OPTIONS="$TSAN_OPTIONS suppressions=%s.supp" %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stdio.h>
-#include <unistd.h>
-
-int Global;
-
-void *Thread1(void *x) {
- Global = 42;
- return NULL;
-}
-
-void *Thread2(void *x) {
- sleep(1);
- Global = 43;
- return NULL;
-}
-
-int main() {
- pthread_t t[2];
- pthread_create(&t[0], NULL, Thread1, NULL);
- pthread_create(&t[1], NULL, Thread2, NULL);
- pthread_join(t[0], NULL);
- pthread_join(t[1], NULL);
- printf("OK\n");
- return 0;
-}
-
-// CHECK-NOT: failed to open suppressions file
-// CHECK-NOT: WARNING: ThreadSanitizer: data race
-
diff --git a/lib/tsan/lit_tests/suppressions_race2.cc.supp b/lib/tsan/lit_tests/suppressions_race2.cc.supp
deleted file mode 100644
index b3c4dbc59363..000000000000
--- a/lib/tsan/lit_tests/suppressions_race2.cc.supp
+++ /dev/null
@@ -1,2 +0,0 @@
-race:Thread2
-
diff --git a/lib/tsan/lit_tests/test_output.sh b/lib/tsan/lit_tests/test_output.sh
deleted file mode 100755
index 79e773aa2c98..000000000000
--- a/lib/tsan/lit_tests/test_output.sh
+++ /dev/null
@@ -1,58 +0,0 @@
-#!/bin/bash
-
-ulimit -s 8192
-set -e # fail on any error
-
-ROOTDIR=$(dirname $0)/..
-BLACKLIST=$ROOTDIR/lit_tests/Helpers/blacklist.txt
-
-# Assume clang and clang++ are in path.
-: ${CC:=clang}
-: ${CXX:=clang++}
-: ${FILECHECK:=FileCheck}
-
-# TODO: add testing for all of -O0...-O3
-CFLAGS="-fsanitize=thread -fsanitize-blacklist=$BLACKLIST -fPIE -O1 -g -Wall"
-LDFLAGS="-pie -lpthread -ldl -lrt -Wl,--whole-archive $ROOTDIR/rtl/libtsan.a -Wl,--no-whole-archive"
-
-test_file() {
- SRC=$1
- COMPILER=$2
- echo ----- TESTING $(basename $1)
- OBJ=$SRC.o
- EXE=$SRC.exe
- $COMPILER $SRC $CFLAGS -c -o $OBJ
- $COMPILER $OBJ $LDFLAGS -o $EXE
- RES=$($EXE 2>&1 || true)
- printf "%s\n" "$RES" | $FILECHECK $SRC
- if [ "$3" == "" ]; then
- rm -f $EXE $OBJ
- fi
-}
-
-if [ "$1" == "" ]; then
- for c in $ROOTDIR/lit_tests/*.{c,cc}; do
- if [[ $c == */failing_* ]]; then
- echo SKIPPING FAILING TEST $c
- continue
- fi
- if [[ $c == */load_shared_lib.cc ]]; then
- echo TEST $c is not supported
- continue
- fi
- if [ "`grep "TSAN_OPTIONS" $c`" ]; then
- echo SKIPPING $c -- requires TSAN_OPTIONS
- continue
- fi
- COMPILER=$CXX
- case $c in
- *.c) COMPILER=$CC
- esac
- test_file $c $COMPILER &
- done
- for job in `jobs -p`; do
- wait $job || exit 1
- done
-else
- test_file $ROOTDIR/lit_tests/$1 $CXX "DUMP"
-fi
diff --git a/lib/tsan/lit_tests/thread_end_with_ignore.cc b/lib/tsan/lit_tests/thread_end_with_ignore.cc
deleted file mode 100644
index 960a477c5ad3..000000000000
--- a/lib/tsan/lit_tests/thread_end_with_ignore.cc
+++ /dev/null
@@ -1,19 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stdio.h>
-
-extern "C" void AnnotateIgnoreReadsBegin(const char *f, int l);
-
-void *Thread(void *x) {
- AnnotateIgnoreReadsBegin("", 0);
- return 0;
-}
-
-int main() {
- pthread_t t;
- pthread_create(&t, 0, Thread, 0);
- pthread_join(t, 0);
-}
-
-// CHECK: ThreadSanitizer: thread T1 finished with ignores enabled
-
diff --git a/lib/tsan/lit_tests/thread_end_with_ignore2.cc b/lib/tsan/lit_tests/thread_end_with_ignore2.cc
deleted file mode 100644
index 8f743ae2f4a4..000000000000
--- a/lib/tsan/lit_tests/thread_end_with_ignore2.cc
+++ /dev/null
@@ -1,9 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
-extern "C" void AnnotateIgnoreWritesBegin(const char *f, int l);
-
-int main() {
- AnnotateIgnoreWritesBegin("", 0);
-}
-
-// CHECK: ThreadSanitizer: thread T0 finished with ignores enabled
-
diff --git a/lib/tsan/lit_tests/thread_leak.c b/lib/tsan/lit_tests/thread_leak.c
deleted file mode 100644
index c5e669e5d99f..000000000000
--- a/lib/tsan/lit_tests/thread_leak.c
+++ /dev/null
@@ -1,17 +0,0 @@
-// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stdio.h>
-
-void *Thread(void *x) {
- return 0;
-}
-
-int main() {
- pthread_t t;
- pthread_create(&t, 0, Thread, 0);
- pthread_join(t, 0);
- printf("PASS\n");
- return 0;
-}
-
-// CHECK-NOT: WARNING: ThreadSanitizer: thread leak
diff --git a/lib/tsan/lit_tests/thread_leak2.c b/lib/tsan/lit_tests/thread_leak2.c
deleted file mode 100644
index 39f6b5e02e39..000000000000
--- a/lib/tsan/lit_tests/thread_leak2.c
+++ /dev/null
@@ -1,17 +0,0 @@
-// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stdio.h>
-
-void *Thread(void *x) {
- return 0;
-}
-
-int main() {
- pthread_t t;
- pthread_create(&t, 0, Thread, 0);
- pthread_detach(t);
- printf("PASS\n");
- return 0;
-}
-
-// CHECK-NOT: WARNING: ThreadSanitizer: thread leak
diff --git a/lib/tsan/lit_tests/thread_leak3.c b/lib/tsan/lit_tests/thread_leak3.c
deleted file mode 100644
index 5f447dbdbdf3..000000000000
--- a/lib/tsan/lit_tests/thread_leak3.c
+++ /dev/null
@@ -1,17 +0,0 @@
-// RUN: %clang_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <unistd.h>
-
-void *Thread(void *x) {
- return 0;
-}
-
-int main() {
- pthread_t t;
- pthread_create(&t, 0, Thread, 0);
- sleep(1);
- return 0;
-}
-
-// CHECK: WARNING: ThreadSanitizer: thread leak
-// CHECK: SUMMARY: ThreadSanitizer: thread leak{{.*}}main
diff --git a/lib/tsan/lit_tests/thread_leak4.c b/lib/tsan/lit_tests/thread_leak4.c
deleted file mode 100644
index f9fad0360d34..000000000000
--- a/lib/tsan/lit_tests/thread_leak4.c
+++ /dev/null
@@ -1,18 +0,0 @@
-// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <unistd.h>
-#include <stdio.h>
-
-void *Thread(void *x) {
- sleep(10);
- return 0;
-}
-
-int main() {
- pthread_t t;
- pthread_create(&t, 0, Thread, 0);
- printf("OK\n");
- return 0;
-}
-
-// CHECK-NOT: WARNING: ThreadSanitizer: thread leak
diff --git a/lib/tsan/lit_tests/thread_leak5.c b/lib/tsan/lit_tests/thread_leak5.c
deleted file mode 100644
index 329f7233a38a..000000000000
--- a/lib/tsan/lit_tests/thread_leak5.c
+++ /dev/null
@@ -1,19 +0,0 @@
-// RUN: %clang_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <unistd.h>
-
-void *Thread(void *x) {
- return 0;
-}
-
-int main() {
- for (int i = 0; i < 5; i++) {
- pthread_t t;
- pthread_create(&t, 0, Thread, 0);
- }
- sleep(1);
- return 0;
-}
-
-// CHECK: WARNING: ThreadSanitizer: thread leak
-// CHECK: And 4 more similar thread leaks
diff --git a/lib/tsan/lit_tests/thread_name.cc b/lib/tsan/lit_tests/thread_name.cc
deleted file mode 100644
index 646ab5836241..000000000000
--- a/lib/tsan/lit_tests/thread_name.cc
+++ /dev/null
@@ -1,38 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stdio.h>
-#include <unistd.h>
-
-extern "C" void AnnotateThreadName(const char *f, int l, const char *name);
-
-int Global;
-
-void *Thread1(void *x) {
- sleep(1);
- AnnotateThreadName(__FILE__, __LINE__, "Thread1");
- Global++;
- return NULL;
-}
-
-void *Thread2(void *x) {
-#if SANITIZER_LINUX && __GLIBC_PREREQ(2, 12)
- pthread_setname_np(pthread_self(), "Thread2");
-#else
- AnnotateThreadName(__FILE__, __LINE__, "Thread2");
-#endif
- Global--;
- return NULL;
-}
-
-int main() {
- pthread_t t[2];
- pthread_create(&t[0], NULL, Thread1, NULL);
- pthread_create(&t[1], NULL, Thread2, NULL);
- pthread_join(t[0], NULL);
- pthread_join(t[1], NULL);
-}
-
-// CHECK: WARNING: ThreadSanitizer: data race
-// CHECK: Thread T1 'Thread1'
-// CHECK: Thread T2 'Thread2'
-
diff --git a/lib/tsan/lit_tests/thread_name2.cc b/lib/tsan/lit_tests/thread_name2.cc
deleted file mode 100644
index 8c5cb741f61f..000000000000
--- a/lib/tsan/lit_tests/thread_name2.cc
+++ /dev/null
@@ -1,32 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stdio.h>
-#include <unistd.h>
-
-int Global;
-
-void *Thread1(void *x) {
- sleep(1);
- Global++;
- return 0;
-}
-
-void *Thread2(void *x) {
- pthread_setname_np(pthread_self(), "foobar2");
- Global--;
- return 0;
-}
-
-int main() {
- pthread_t t[2];
- pthread_create(&t[0], 0, Thread1, 0);
- pthread_create(&t[1], 0, Thread2, 0);
- pthread_setname_np(t[0], "foobar1");
- pthread_join(t[0], NULL);
- pthread_join(t[1], NULL);
-}
-
-// CHECK: WARNING: ThreadSanitizer: data race
-// CHECK: Thread T1 'foobar1'
-// CHECK: Thread T2 'foobar2'
-
diff --git a/lib/tsan/lit_tests/tiny_race.c b/lib/tsan/lit_tests/tiny_race.c
deleted file mode 100644
index f77e1606c1dd..000000000000
--- a/lib/tsan/lit_tests/tiny_race.c
+++ /dev/null
@@ -1,21 +0,0 @@
-// RUN: %clang_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <unistd.h>
-
-int Global;
-
-void *Thread1(void *x) {
- sleep(1);
- Global = 42;
- return x;
-}
-
-int main() {
- pthread_t t;
- pthread_create(&t, 0, Thread1, 0);
- Global = 43;
- pthread_join(t, 0);
- return Global;
-}
-
-// CHECK: WARNING: ThreadSanitizer: data race
diff --git a/lib/tsan/lit_tests/tls_race.cc b/lib/tsan/lit_tests/tls_race.cc
deleted file mode 100644
index 3cbcc9dbba42..000000000000
--- a/lib/tsan/lit_tests/tls_race.cc
+++ /dev/null
@@ -1,19 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stddef.h>
-
-void *Thread(void *a) {
- *(int*)a = 43;
- return 0;
-}
-
-int main() {
- static __thread int Var = 42;
- pthread_t t;
- pthread_create(&t, 0, Thread, &Var);
- Var = 43;
- pthread_join(t, 0);
-}
-
-// CHECK: WARNING: ThreadSanitizer: data race
-// CHECK: Location is TLS of main thread.
diff --git a/lib/tsan/lit_tests/tls_race2.cc b/lib/tsan/lit_tests/tls_race2.cc
deleted file mode 100644
index 136087065c12..000000000000
--- a/lib/tsan/lit_tests/tls_race2.cc
+++ /dev/null
@@ -1,28 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stddef.h>
-#include <unistd.h>
-
-void *Thread2(void *a) {
- *(int*)a = 43;
- return 0;
-}
-
-void *Thread(void *a) {
- static __thread int Var = 42;
- pthread_t t;
- pthread_create(&t, 0, Thread2, &Var);
- Var = 42;
- pthread_join(t, 0);
- return 0;
-}
-
-int main() {
- pthread_t t;
- pthread_create(&t, 0, Thread, 0);
- pthread_join(t, 0);
-}
-
-// CHECK: WARNING: ThreadSanitizer: data race
-// CHECK: Location is TLS of thread T1.
-
diff --git a/lib/tsan/lit_tests/tsan-vs-gvn.cc b/lib/tsan/lit_tests/tsan-vs-gvn.cc
deleted file mode 100644
index 40ae724b78e1..000000000000
--- a/lib/tsan/lit_tests/tsan-vs-gvn.cc
+++ /dev/null
@@ -1,38 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_tsan -O2 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_tsan -O3 %s -o %t && %t 2>&1 | FileCheck %s
-//
-// Check that load widening is not tsan-hostile.
-#include <pthread.h>
-#include <stdio.h>
-#include <string.h>
-
-struct {
- int i;
- char c1, c2, c3, c4;
-} S;
-
-int G;
-
-void *Thread1(void *x) {
- G = S.c1 + S.c3;
- return NULL;
-}
-
-void *Thread2(void *x) {
- S.c2 = 1;
- return NULL;
-}
-
-int main() {
- pthread_t t[2];
- memset(&S, 123, sizeof(S));
- pthread_create(&t[0], NULL, Thread1, NULL);
- pthread_create(&t[1], NULL, Thread2, NULL);
- pthread_join(t[0], NULL);
- pthread_join(t[1], NULL);
- printf("PASS\n");
-}
-
-// CHECK-NOT: WARNING: ThreadSanitizer: data race
-// CHECK: PASS
diff --git a/lib/tsan/lit_tests/unaligned_norace.cc b/lib/tsan/lit_tests/unaligned_norace.cc
deleted file mode 100644
index 792224b80126..000000000000
--- a/lib/tsan/lit_tests/unaligned_norace.cc
+++ /dev/null
@@ -1,84 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-
-uint64_t objs[8*3*3*2][3];
-
-extern "C" {
-uint16_t __tsan_unaligned_read2(void *addr);
-uint32_t __tsan_unaligned_read4(void *addr);
-uint64_t __tsan_unaligned_read8(void *addr);
-void __tsan_unaligned_write2(void *addr, uint16_t v);
-void __tsan_unaligned_write4(void *addr, uint32_t v);
-void __tsan_unaligned_write8(void *addr, uint64_t v);
-}
-
-static void access(char *p, int sz, int rw) {
- if (rw) {
- switch (sz) {
- case 0: __tsan_unaligned_write2(p, 0); break;
- case 1: __tsan_unaligned_write4(p, 0); break;
- case 2: __tsan_unaligned_write8(p, 0); break;
- default: exit(1);
- }
- } else {
- switch (sz) {
- case 0: __tsan_unaligned_read2(p); break;
- case 1: __tsan_unaligned_read4(p); break;
- case 2: __tsan_unaligned_read8(p); break;
- default: exit(1);
- }
- }
-}
-
-static int accesssize(int sz) {
- switch (sz) {
- case 0: return 2;
- case 1: return 4;
- case 2: return 8;
- }
- exit(1);
-}
-
-void Test(bool main) {
- uint64_t *obj = objs[0];
- for (int off = 0; off < 8; off++) {
- for (int sz1 = 0; sz1 < 3; sz1++) {
- for (int sz2 = 0; sz2 < 3; sz2++) {
- for (int rw = 0; rw < 2; rw++) {
- char *p = (char*)obj + off;
- if (main) {
- // printf("thr=%d off=%d sz1=%d sz2=%d rw=%d p=%p\n",
- // main, off, sz1, sz2, rw, p);
- access(p, sz1, true);
- } else {
- p += accesssize(sz1);
- // printf("thr=%d off=%d sz1=%d sz2=%d rw=%d p=%p\n",
- // main, off, sz1, sz2, rw, p);
- access(p, sz2, rw);
- }
- obj += 3;
- }
- }
- }
- }
-}
-
-void *Thread(void *p) {
- (void)p;
- Test(false);
- return 0;
-}
-
-int main() {
- pthread_t th;
- pthread_create(&th, 0, Thread, 0);
- Test(true);
- pthread_join(th, 0);
- printf("OK\n");
-}
-
-// CHECK-NOT: WARNING: ThreadSanitizer:
-// CHECK: OK
diff --git a/lib/tsan/lit_tests/unaligned_race.cc b/lib/tsan/lit_tests/unaligned_race.cc
deleted file mode 100644
index 6ac87b577ec5..000000000000
--- a/lib/tsan/lit_tests/unaligned_race.cc
+++ /dev/null
@@ -1,135 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <unistd.h>
-
-uint64_t objs[8*2*(2 + 4 + 8)][2];
-
-extern "C" {
-uint16_t __sanitizer_unaligned_load16(void *addr);
-uint32_t __sanitizer_unaligned_load32(void *addr);
-uint64_t __sanitizer_unaligned_load64(void *addr);
-void __sanitizer_unaligned_store16(void *addr, uint16_t v);
-void __sanitizer_unaligned_store32(void *addr, uint32_t v);
-void __sanitizer_unaligned_store64(void *addr, uint64_t v);
-}
-
-// All this mess is to generate unique stack for each race,
-// otherwise tsan will suppress similar stacks.
-
-static void access(char *p, int sz, int rw) {
- if (rw) {
- switch (sz) {
- case 0: __sanitizer_unaligned_store16(p, 0); break;
- case 1: __sanitizer_unaligned_store32(p, 0); break;
- case 2: __sanitizer_unaligned_store64(p, 0); break;
- default: exit(1);
- }
- } else {
- switch (sz) {
- case 0: __sanitizer_unaligned_load16(p); break;
- case 1: __sanitizer_unaligned_load32(p); break;
- case 2: __sanitizer_unaligned_load64(p); break;
- default: exit(1);
- }
- }
-}
-
-static int accesssize(int sz) {
- switch (sz) {
- case 0: return 2;
- case 1: return 4;
- case 2: return 8;
- }
- exit(1);
-}
-
-template<int off, int off2>
-static void access3(bool main, int sz1, bool rw, char *p) {
- p += off;
- if (main) {
- access(p, sz1, true);
- } else {
- p += off2;
- if (rw) {
- *p = 42;
- } else {
- if (*p == 42)
- printf("bingo!\n");
- }
- }
-}
-
-template<int off>
-static void access2(bool main, int sz1, int off2, bool rw, char *obj) {
- if (off2 == 0)
- access3<off, 0>(main, sz1, rw, obj);
- else if (off2 == 1)
- access3<off, 1>(main, sz1, rw, obj);
- else if (off2 == 2)
- access3<off, 2>(main, sz1, rw, obj);
- else if (off2 == 3)
- access3<off, 3>(main, sz1, rw, obj);
- else if (off2 == 4)
- access3<off, 4>(main, sz1, rw, obj);
- else if (off2 == 5)
- access3<off, 5>(main, sz1, rw, obj);
- else if (off2 == 6)
- access3<off, 6>(main, sz1, rw, obj);
- else if (off2 == 7)
- access3<off, 7>(main, sz1, rw, obj);
-}
-
-static void access1(bool main, int off, int sz1, int off2, bool rw, char *obj) {
- if (off == 0)
- access2<0>(main, sz1, off2, rw, obj);
- else if (off == 1)
- access2<1>(main, sz1, off2, rw, obj);
- else if (off == 2)
- access2<2>(main, sz1, off2, rw, obj);
- else if (off == 3)
- access2<3>(main, sz1, off2, rw, obj);
- else if (off == 4)
- access2<4>(main, sz1, off2, rw, obj);
- else if (off == 5)
- access2<5>(main, sz1, off2, rw, obj);
- else if (off == 6)
- access2<6>(main, sz1, off2, rw, obj);
- else if (off == 7)
- access2<7>(main, sz1, off2, rw, obj);
-}
-
-void Test(bool main) {
- uint64_t *obj = objs[0];
- for (int off = 0; off < 8; off++) {
- for (int sz1 = 0; sz1 < 3; sz1++) {
- for (int off2 = 0; off2 < accesssize(sz1); off2++) {
- for (int rw = 0; rw < 2; rw++) {
- // printf("thr=%d off=%d sz1=%d off2=%d rw=%d p=%p\n",
- // main, off, sz1, off2, rw, obj);
- access1(main, off, sz1, off2, rw, (char*)obj);
- obj += 2;
- }
- }
- }
- }
-}
-
-void *Thread(void *p) {
- (void)p;
- sleep(1);
- Test(false);
- return 0;
-}
-
-int main() {
- pthread_t th;
- pthread_create(&th, 0, Thread, 0);
- Test(true);
- pthread_join(th, 0);
-}
-
-// CHECK: WARNING: ThreadSanitizer: data race
-// CHECK: ThreadSanitizer: reported 224 warnings
diff --git a/lib/tsan/lit_tests/user_fopen.cc b/lib/tsan/lit_tests/user_fopen.cc
deleted file mode 100644
index 794d598719b4..000000000000
--- a/lib/tsan/lit_tests/user_fopen.cc
+++ /dev/null
@@ -1,34 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
-#include <stdio.h>
-#include <stdlib.h>
-
-// defined by tsan.
-extern "C" FILE *__interceptor_fopen(const char *file, const char *mode);
-extern "C" int __interceptor_fileno(FILE *f);
-
-extern "C" FILE *fopen(const char *file, const char *mode) {
- static int first = 0;
- if (__sync_lock_test_and_set(&first, 1) == 0)
- printf("user fopen\n");
- return __interceptor_fopen(file, mode);
-}
-
-extern "C" int fileno(FILE *f) {
- static int first = 0;
- if (__sync_lock_test_and_set(&first, 1) == 0)
- printf("user fileno\n");
- return 1;
-}
-
-int main() {
- FILE *f = fopen("/dev/zero", "r");
- if (f) {
- char buf;
- fread(&buf, 1, 1, f);
- fclose(f);
- }
-}
-
-// CHECK: user fopen
-// CHECK-NOT: ThreadSanitizer
-
diff --git a/lib/tsan/lit_tests/user_malloc.cc b/lib/tsan/lit_tests/user_malloc.cc
deleted file mode 100644
index 0be6d54fb13a..000000000000
--- a/lib/tsan/lit_tests/user_malloc.cc
+++ /dev/null
@@ -1,27 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
-#include <stdio.h>
-
-// defined by tsan.
-extern "C" void *__interceptor_malloc(unsigned long size);
-extern "C" void __interceptor_free(void *p);
-
-extern "C" void *malloc(unsigned long size) {
- static int first = 0;
- if (__sync_lock_test_and_set(&first, 1) == 0)
- printf("user malloc\n");
- return __interceptor_malloc(size);
-}
-
-extern "C" void free(void *p) {
- __interceptor_free(p);
-}
-
-int main() {
- volatile char *p = (char*)malloc(10);
- p[0] = 0;
- free((void*)p);
-}
-
-// CHECK: user malloc
-// CHECK-NOT: ThreadSanitizer
-
diff --git a/lib/tsan/lit_tests/virtual_inheritance_compile_bug.cc b/lib/tsan/lit_tests/virtual_inheritance_compile_bug.cc
deleted file mode 100644
index 2275b8b8d211..000000000000
--- a/lib/tsan/lit_tests/virtual_inheritance_compile_bug.cc
+++ /dev/null
@@ -1,15 +0,0 @@
-// Regression test for http://code.google.com/p/thread-sanitizer/issues/detail?id=3.
-// The C++ variant is much more compact that the LLVM IR equivalent.
-
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
-#include <stdio.h>
-struct AAA { virtual long aaa () { return 0; } }; // NOLINT
-struct BBB: virtual AAA { unsigned long bbb; }; // NOLINT
-struct CCC: virtual AAA { };
-struct DDD: CCC, BBB { DDD(); }; // NOLINT
-DDD::DDD() { }
-int main() {
- DDD d;
- printf("OK\n");
-}
-// CHECK: OK
diff --git a/lib/tsan/lit_tests/vptr_benign_race.cc b/lib/tsan/lit_tests/vptr_benign_race.cc
deleted file mode 100644
index 8c9fc596e17b..000000000000
--- a/lib/tsan/lit_tests/vptr_benign_race.cc
+++ /dev/null
@@ -1,51 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <semaphore.h>
-#include <stdio.h>
-
-struct A {
- A() {
- sem_init(&sem_, 0, 0);
- }
- virtual void F() {
- }
- void Done() {
- sem_post(&sem_);
- }
- virtual ~A() {
- }
- sem_t sem_;
-};
-
-struct B : A {
- virtual void F() {
- }
- virtual ~B() {
- sem_wait(&sem_);
- sem_destroy(&sem_);
- }
-};
-
-static A *obj = new B;
-
-void *Thread1(void *x) {
- obj->F();
- obj->Done();
- return NULL;
-}
-
-void *Thread2(void *x) {
- delete obj;
- return NULL;
-}
-
-int main() {
- pthread_t t[2];
- pthread_create(&t[0], NULL, Thread1, NULL);
- pthread_create(&t[1], NULL, Thread2, NULL);
- pthread_join(t[0], NULL);
- pthread_join(t[1], NULL);
- fprintf(stderr, "PASS\n");
-}
-// CHECK: PASS
-// CHECK-NOT: WARNING: ThreadSanitizer: data race
diff --git a/lib/tsan/lit_tests/vptr_harmful_race.cc b/lib/tsan/lit_tests/vptr_harmful_race.cc
deleted file mode 100644
index 0105c4cedd99..000000000000
--- a/lib/tsan/lit_tests/vptr_harmful_race.cc
+++ /dev/null
@@ -1,51 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <semaphore.h>
-#include <stdio.h>
-#include <unistd.h>
-
-struct A {
- A() {
- sem_init(&sem_, 0, 0);
- }
- virtual void F() {
- }
- void Done() {
- sem_post(&sem_);
- }
- virtual ~A() {
- sem_wait(&sem_);
- sem_destroy(&sem_);
- }
- sem_t sem_;
-};
-
-struct B : A {
- virtual void F() {
- }
- virtual ~B() { }
-};
-
-static A *obj = new B;
-
-void *Thread1(void *x) {
- obj->F();
- obj->Done();
- return NULL;
-}
-
-void *Thread2(void *x) {
- sleep(1);
- delete obj;
- return NULL;
-}
-
-int main() {
- pthread_t t[2];
- pthread_create(&t[0], NULL, Thread1, NULL);
- pthread_create(&t[1], NULL, Thread2, NULL);
- pthread_join(t[0], NULL);
- pthread_join(t[1], NULL);
-}
-
-// CHECK: WARNING: ThreadSanitizer: data race on vptr
diff --git a/lib/tsan/lit_tests/vptr_harmful_race2.cc b/lib/tsan/lit_tests/vptr_harmful_race2.cc
deleted file mode 100644
index 378790c62340..000000000000
--- a/lib/tsan/lit_tests/vptr_harmful_race2.cc
+++ /dev/null
@@ -1,51 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <semaphore.h>
-#include <stdio.h>
-#include <unistd.h>
-
-struct A {
- A() {
- sem_init(&sem_, 0, 0);
- }
- virtual void F() {
- }
- void Done() {
- sem_post(&sem_);
- }
- virtual ~A() {
- sem_wait(&sem_);
- sem_destroy(&sem_);
- }
- sem_t sem_;
-};
-
-struct B : A {
- virtual void F() {
- }
- virtual ~B() { }
-};
-
-static A *obj = new B;
-
-void *Thread1(void *x) {
- sleep(1);
- obj->F();
- obj->Done();
- return NULL;
-}
-
-void *Thread2(void *x) {
- delete obj;
- return NULL;
-}
-
-int main() {
- pthread_t t[2];
- pthread_create(&t[0], NULL, Thread1, NULL);
- pthread_create(&t[1], NULL, Thread2, NULL);
- pthread_join(t[0], NULL);
- pthread_join(t[1], NULL);
-}
-
-// CHECK: WARNING: ThreadSanitizer: data race on vptr
diff --git a/lib/tsan/lit_tests/write_in_reader_lock.cc b/lib/tsan/lit_tests/write_in_reader_lock.cc
deleted file mode 100644
index e872fe3ff960..000000000000
--- a/lib/tsan/lit_tests/write_in_reader_lock.cc
+++ /dev/null
@@ -1,35 +0,0 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
-#include <pthread.h>
-#include <unistd.h>
-
-pthread_rwlock_t rwlock;
-int GLOB;
-
-void *Thread1(void *p) {
- (void)p;
- pthread_rwlock_rdlock(&rwlock);
- // Write under reader lock.
- sleep(1);
- GLOB++;
- pthread_rwlock_unlock(&rwlock);
- return 0;
-}
-
-int main(int argc, char *argv[]) {
- pthread_rwlock_init(&rwlock, NULL);
- pthread_rwlock_rdlock(&rwlock);
- pthread_t t;
- pthread_create(&t, 0, Thread1, 0);
- volatile int x = GLOB;
- (void)x;
- pthread_rwlock_unlock(&rwlock);
- pthread_join(t, 0);
- pthread_rwlock_destroy(&rwlock);
- return 0;
-}
-
-// CHECK: WARNING: ThreadSanitizer: data race
-// CHECK: Write of size 4 at {{.*}} by thread T1{{.*}}:
-// CHECK: #0 Thread1(void*) {{.*}}write_in_reader_lock.cc:13
-// CHECK: Previous read of size 4 at {{.*}} by main thread{{.*}}:
-// CHECK: #0 main {{.*}}write_in_reader_lock.cc:23
diff --git a/lib/tsan/rtl/Makefile.old b/lib/tsan/rtl/Makefile.old
index 33944ffe9675..79c761ce3f4e 100644
--- a/lib/tsan/rtl/Makefile.old
+++ b/lib/tsan/rtl/Makefile.old
@@ -1,4 +1,4 @@
-CXXFLAGS = -fPIE -g -Wall -Werror -fno-builtin -DTSAN_DEBUG=$(DEBUG) -DSANITIZER_DEBUG=$(DEBUG)
+CXXFLAGS = -std=c++11 -fPIE -g -Wall -Werror -fno-builtin -msse3 -DTSAN_DEBUG=$(DEBUG) -DSANITIZER_DEBUG=$(DEBUG)
CLANG=clang
ifeq ($(DEBUG), 0)
CXXFLAGS += -O3
@@ -49,6 +49,8 @@ LIBTSAN_OBJ=$(patsubst %.cc,%.o,$(LIBTSAN_SRC)) \
$(CXX) $(CXXFLAGS) $(INCLUDES) -c $< -o $@
%.o: $(COMMON)/%.cc Makefile.old $(LIBTSAN_HEADERS)
$(CXX) $(CXXFLAGS) $(INCLUDES) -c $< -o $@
+%.o: %.S
+ $(CXX) $(INCLUDES) -o $@ -c $<
libtsan.a: $(LIBTSAN_OBJ)
ar ru $@ $(LIBTSAN_OBJ)
diff --git a/lib/tsan/rtl/tsan_clock.cc b/lib/tsan/rtl/tsan_clock.cc
index f8745ec3200c..f2b39a182b39 100644
--- a/lib/tsan/rtl/tsan_clock.cc
+++ b/lib/tsan/rtl/tsan_clock.cc
@@ -12,100 +12,418 @@
//===----------------------------------------------------------------------===//
#include "tsan_clock.h"
#include "tsan_rtl.h"
+#include "sanitizer_common/sanitizer_placement_new.h"
-// It's possible to optimize clock operations for some important cases
-// so that they are O(1). The cases include singletons, once's, local mutexes.
-// First, SyncClock must be re-implemented to allow indexing by tid.
-// It must not necessarily be a full vector clock, though. For example it may
-// be a multi-level table.
-// Then, each slot in SyncClock must contain a dirty bit (it's united with
-// the clock value, so no space increase). The acquire algorithm looks
-// as follows:
-// void acquire(thr, tid, thr_clock, sync_clock) {
-// if (!sync_clock[tid].dirty)
-// return; // No new info to acquire.
-// // This handles constant reads of singleton pointers and
-// // stop-flags.
-// acquire_impl(thr_clock, sync_clock); // As usual, O(N).
-// sync_clock[tid].dirty = false;
-// sync_clock.dirty_count--;
-// }
-// The release operation looks as follows:
-// void release(thr, tid, thr_clock, sync_clock) {
-// // thr->sync_cache is a simple fixed-size hash-based cache that holds
-// // several previous sync_clock's.
-// if (thr->sync_cache[sync_clock] >= thr->last_acquire_epoch) {
-// // The thread did no acquire operations since last release on this clock.
-// // So update only the thread's slot (other slots can't possibly change).
-// sync_clock[tid].clock = thr->epoch;
-// if (sync_clock.dirty_count == sync_clock.cnt
-// || (sync_clock.dirty_count == sync_clock.cnt - 1
-// && sync_clock[tid].dirty == false))
-// // All dirty flags are set, bail out.
-// return;
-// set all dirty bits, but preserve the thread's bit. // O(N)
-// update sync_clock.dirty_count;
-// return;
+// SyncClock and ThreadClock implement vector clocks for sync variables
+// (mutexes, atomic variables, file descriptors, etc) and threads, respectively.
+// ThreadClock contains fixed-size vector clock for maximum number of threads.
+// SyncClock contains growable vector clock for currently necessary number of
+// threads.
+// Together they implement very simple model of operations, namely:
+//
+// void ThreadClock::acquire(const SyncClock *src) {
+// for (int i = 0; i < kMaxThreads; i++)
+// clock[i] = max(clock[i], src->clock[i]);
+// }
+//
+// void ThreadClock::release(SyncClock *dst) const {
+// for (int i = 0; i < kMaxThreads; i++)
+// dst->clock[i] = max(dst->clock[i], clock[i]);
+// }
+//
+// void ThreadClock::ReleaseStore(SyncClock *dst) const {
+// for (int i = 0; i < kMaxThreads; i++)
+// dst->clock[i] = clock[i];
// }
-// release_impl(thr_clock, sync_clock); // As usual, O(N).
-// set all dirty bits, but preserve the thread's bit.
-// // The previous step is combined with release_impl(), so that
-// // we scan the arrays only once.
-// update sync_clock.dirty_count;
-// }
+//
+// void ThreadClock::acq_rel(SyncClock *dst) {
+// acquire(dst);
+// release(dst);
+// }
+//
+// Conformance to this model is extensively verified in tsan_clock_test.cc.
+// However, the implementation is significantly more complex. The complexity
+// allows to implement important classes of use cases in O(1) instead of O(N).
+//
+// The use cases are:
+// 1. Singleton/once atomic that has a single release-store operation followed
+// by zillions of acquire-loads (the acquire-load is O(1)).
+// 2. Thread-local mutex (both lock and unlock can be O(1)).
+// 3. Leaf mutex (unlock is O(1)).
+// 4. A mutex shared by 2 threads (both lock and unlock can be O(1)).
+// 5. An atomic with a single writer (writes can be O(1)).
+// The implementation dynamically adopts to workload. So if an atomic is in
+// read-only phase, these reads will be O(1); if it later switches to read/write
+// phase, the implementation will correctly handle that by switching to O(N).
+//
+// Thread-safety note: all const operations on SyncClock's are conducted under
+// a shared lock; all non-const operations on SyncClock's are conducted under
+// an exclusive lock; ThreadClock's are private to respective threads and so
+// do not need any protection.
+//
+// Description of ThreadClock state:
+// clk_ - fixed size vector clock.
+// nclk_ - effective size of the vector clock (the rest is zeros).
+// tid_ - index of the thread associated with he clock ("current thread").
+// last_acquire_ - current thread time when it acquired something from
+// other threads.
+//
+// Description of SyncClock state:
+// clk_ - variable size vector clock, low kClkBits hold timestamp,
+// the remaining bits hold "acquired" flag (the actual value is thread's
+// reused counter);
+// if acquried == thr->reused_, then the respective thread has already
+// acquired this clock (except possibly dirty_tids_).
+// dirty_tids_ - holds up to two indeces in the vector clock that other threads
+// need to acquire regardless of "acquired" flag value;
+// release_store_tid_ - denotes that the clock state is a result of
+// release-store operation by the thread with release_store_tid_ index.
+// release_store_reused_ - reuse count of release_store_tid_.
+
+// We don't have ThreadState in these methods, so this is an ugly hack that
+// works only in C++.
+#ifndef SANITIZER_GO
+# define CPP_STAT_INC(typ) StatInc(cur_thread(), typ)
+#else
+# define CPP_STAT_INC(typ) (void)0
+#endif
namespace __tsan {
-ThreadClock::ThreadClock() {
- nclk_ = 0;
- for (uptr i = 0; i < (uptr)kMaxTidInClock; i++)
- clk_[i] = 0;
+const unsigned kInvalidTid = (unsigned)-1;
+
+ThreadClock::ThreadClock(unsigned tid, unsigned reused)
+ : tid_(tid)
+ , reused_(reused + 1) { // 0 has special meaning
+ CHECK_LT(tid, kMaxTidInClock);
+ CHECK_EQ(reused_, ((u64)reused_ << kClkBits) >> kClkBits);
+ nclk_ = tid_ + 1;
+ last_acquire_ = 0;
+ internal_memset(clk_, 0, sizeof(clk_));
+ clk_[tid_].reused = reused_;
}
-void ThreadClock::acquire(const SyncClock *src) {
+void ThreadClock::acquire(ClockCache *c, const SyncClock *src) {
DCHECK(nclk_ <= kMaxTid);
- DCHECK(src->clk_.Size() <= kMaxTid);
+ DCHECK(src->size_ <= kMaxTid);
+ CPP_STAT_INC(StatClockAcquire);
- const uptr nclk = src->clk_.Size();
- if (nclk == 0)
+ // Check if it's empty -> no need to do anything.
+ const uptr nclk = src->size_;
+ if (nclk == 0) {
+ CPP_STAT_INC(StatClockAcquireEmpty);
return;
+ }
+
+ // Check if we've already acquired src after the last release operation on src
+ bool acquired = false;
+ if (nclk > tid_) {
+ CPP_STAT_INC(StatClockAcquireLarge);
+ if (src->elem(tid_).reused == reused_) {
+ CPP_STAT_INC(StatClockAcquireRepeat);
+ for (unsigned i = 0; i < kDirtyTids; i++) {
+ unsigned tid = src->dirty_tids_[i];
+ if (tid != kInvalidTid) {
+ u64 epoch = src->elem(tid).epoch;
+ if (clk_[tid].epoch < epoch) {
+ clk_[tid].epoch = epoch;
+ acquired = true;
+ }
+ }
+ }
+ if (acquired) {
+ CPP_STAT_INC(StatClockAcquiredSomething);
+ last_acquire_ = clk_[tid_].epoch;
+ }
+ return;
+ }
+ }
+
+ // O(N) acquire.
+ CPP_STAT_INC(StatClockAcquireFull);
nclk_ = max(nclk_, nclk);
for (uptr i = 0; i < nclk; i++) {
- if (clk_[i] < src->clk_[i])
- clk_[i] = src->clk_[i];
+ u64 epoch = src->elem(i).epoch;
+ if (clk_[i].epoch < epoch) {
+ clk_[i].epoch = epoch;
+ acquired = true;
+ }
+ }
+
+ // Remember that this thread has acquired this clock.
+ if (nclk > tid_)
+ src->elem(tid_).reused = reused_;
+
+ if (acquired) {
+ CPP_STAT_INC(StatClockAcquiredSomething);
+ last_acquire_ = clk_[tid_].epoch;
}
}
-void ThreadClock::release(SyncClock *dst) const {
- DCHECK(nclk_ <= kMaxTid);
- DCHECK(dst->clk_.Size() <= kMaxTid);
+void ThreadClock::release(ClockCache *c, SyncClock *dst) const {
+ DCHECK_LE(nclk_, kMaxTid);
+ DCHECK_LE(dst->size_, kMaxTid);
+
+ if (dst->size_ == 0) {
+ // ReleaseStore will correctly set release_store_tid_,
+ // which can be important for future operations.
+ ReleaseStore(c, dst);
+ return;
+ }
+
+ CPP_STAT_INC(StatClockRelease);
+ // Check if we need to resize dst.
+ if (dst->size_ < nclk_)
+ dst->Resize(c, nclk_);
- if (dst->clk_.Size() < nclk_)
- dst->clk_.Resize(nclk_);
+ // Check if we had not acquired anything from other threads
+ // since the last release on dst. If so, we need to update
+ // only dst->elem(tid_).
+ if (dst->elem(tid_).epoch > last_acquire_) {
+ UpdateCurrentThread(dst);
+ if (dst->release_store_tid_ != tid_ ||
+ dst->release_store_reused_ != reused_)
+ dst->release_store_tid_ = kInvalidTid;
+ return;
+ }
+
+ // O(N) release.
+ CPP_STAT_INC(StatClockReleaseFull);
+ // First, remember whether we've acquired dst.
+ bool acquired = IsAlreadyAcquired(dst);
+ if (acquired)
+ CPP_STAT_INC(StatClockReleaseAcquired);
+ // Update dst->clk_.
for (uptr i = 0; i < nclk_; i++) {
- if (dst->clk_[i] < clk_[i])
- dst->clk_[i] = clk_[i];
+ ClockElem &ce = dst->elem(i);
+ ce.epoch = max(ce.epoch, clk_[i].epoch);
+ ce.reused = 0;
}
+ // Clear 'acquired' flag in the remaining elements.
+ if (nclk_ < dst->size_)
+ CPP_STAT_INC(StatClockReleaseClearTail);
+ for (uptr i = nclk_; i < dst->size_; i++)
+ dst->elem(i).reused = 0;
+ for (unsigned i = 0; i < kDirtyTids; i++)
+ dst->dirty_tids_[i] = kInvalidTid;
+ dst->release_store_tid_ = kInvalidTid;
+ dst->release_store_reused_ = 0;
+ // If we've acquired dst, remember this fact,
+ // so that we don't need to acquire it on next acquire.
+ if (acquired)
+ dst->elem(tid_).reused = reused_;
}
-void ThreadClock::ReleaseStore(SyncClock *dst) const {
+void ThreadClock::ReleaseStore(ClockCache *c, SyncClock *dst) const {
DCHECK(nclk_ <= kMaxTid);
- DCHECK(dst->clk_.Size() <= kMaxTid);
+ DCHECK(dst->size_ <= kMaxTid);
+ CPP_STAT_INC(StatClockStore);
- if (dst->clk_.Size() < nclk_)
- dst->clk_.Resize(nclk_);
- for (uptr i = 0; i < nclk_; i++)
- dst->clk_[i] = clk_[i];
- for (uptr i = nclk_; i < dst->clk_.Size(); i++)
- dst->clk_[i] = 0;
+ // Check if we need to resize dst.
+ if (dst->size_ < nclk_)
+ dst->Resize(c, nclk_);
+
+ if (dst->release_store_tid_ == tid_ &&
+ dst->release_store_reused_ == reused_ &&
+ dst->elem(tid_).epoch > last_acquire_) {
+ CPP_STAT_INC(StatClockStoreFast);
+ UpdateCurrentThread(dst);
+ return;
+ }
+
+ // O(N) release-store.
+ CPP_STAT_INC(StatClockStoreFull);
+ for (uptr i = 0; i < nclk_; i++) {
+ ClockElem &ce = dst->elem(i);
+ ce.epoch = clk_[i].epoch;
+ ce.reused = 0;
+ }
+ // Clear the tail of dst->clk_.
+ if (nclk_ < dst->size_) {
+ for (uptr i = nclk_; i < dst->size_; i++) {
+ ClockElem &ce = dst->elem(i);
+ ce.epoch = 0;
+ ce.reused = 0;
+ }
+ CPP_STAT_INC(StatClockStoreTail);
+ }
+ for (unsigned i = 0; i < kDirtyTids; i++)
+ dst->dirty_tids_[i] = kInvalidTid;
+ dst->release_store_tid_ = tid_;
+ dst->release_store_reused_ = reused_;
+ // Rememeber that we don't need to acquire it in future.
+ dst->elem(tid_).reused = reused_;
}
-void ThreadClock::acq_rel(SyncClock *dst) {
- acquire(dst);
- release(dst);
+void ThreadClock::acq_rel(ClockCache *c, SyncClock *dst) {
+ CPP_STAT_INC(StatClockAcquireRelease);
+ acquire(c, dst);
+ ReleaseStore(c, dst);
+}
+
+// Updates only single element related to the current thread in dst->clk_.
+void ThreadClock::UpdateCurrentThread(SyncClock *dst) const {
+ // Update the threads time, but preserve 'acquired' flag.
+ dst->elem(tid_).epoch = clk_[tid_].epoch;
+
+ for (unsigned i = 0; i < kDirtyTids; i++) {
+ if (dst->dirty_tids_[i] == tid_) {
+ CPP_STAT_INC(StatClockReleaseFast1);
+ return;
+ }
+ if (dst->dirty_tids_[i] == kInvalidTid) {
+ CPP_STAT_INC(StatClockReleaseFast2);
+ dst->dirty_tids_[i] = tid_;
+ return;
+ }
+ }
+ // Reset all 'acquired' flags, O(N).
+ CPP_STAT_INC(StatClockReleaseSlow);
+ for (uptr i = 0; i < dst->size_; i++)
+ dst->elem(i).reused = 0;
+ for (unsigned i = 0; i < kDirtyTids; i++)
+ dst->dirty_tids_[i] = kInvalidTid;
+}
+
+// Checks whether the current threads has already acquired src.
+bool ThreadClock::IsAlreadyAcquired(const SyncClock *src) const {
+ if (src->elem(tid_).reused != reused_)
+ return false;
+ for (unsigned i = 0; i < kDirtyTids; i++) {
+ unsigned tid = src->dirty_tids_[i];
+ if (tid != kInvalidTid) {
+ if (clk_[tid].epoch < src->elem(tid).epoch)
+ return false;
+ }
+ }
+ return true;
+}
+
+void SyncClock::Resize(ClockCache *c, uptr nclk) {
+ CPP_STAT_INC(StatClockReleaseResize);
+ if (RoundUpTo(nclk, ClockBlock::kClockCount) <=
+ RoundUpTo(size_, ClockBlock::kClockCount)) {
+ // Growing within the same block.
+ // Memory is already allocated, just increase the size.
+ size_ = nclk;
+ return;
+ }
+ if (nclk <= ClockBlock::kClockCount) {
+ // Grow from 0 to one-level table.
+ CHECK_EQ(size_, 0);
+ CHECK_EQ(tab_, 0);
+ CHECK_EQ(tab_idx_, 0);
+ size_ = nclk;
+ tab_idx_ = ctx->clock_alloc.Alloc(c);
+ tab_ = ctx->clock_alloc.Map(tab_idx_);
+ internal_memset(tab_, 0, sizeof(*tab_));
+ return;
+ }
+ // Growing two-level table.
+ if (size_ == 0) {
+ // Allocate first level table.
+ tab_idx_ = ctx->clock_alloc.Alloc(c);
+ tab_ = ctx->clock_alloc.Map(tab_idx_);
+ internal_memset(tab_, 0, sizeof(*tab_));
+ } else if (size_ <= ClockBlock::kClockCount) {
+ // Transform one-level table to two-level table.
+ u32 old = tab_idx_;
+ tab_idx_ = ctx->clock_alloc.Alloc(c);
+ tab_ = ctx->clock_alloc.Map(tab_idx_);
+ internal_memset(tab_, 0, sizeof(*tab_));
+ tab_->table[0] = old;
+ }
+ // At this point we have first level table allocated.
+ // Add second level tables as necessary.
+ for (uptr i = RoundUpTo(size_, ClockBlock::kClockCount);
+ i < nclk; i += ClockBlock::kClockCount) {
+ u32 idx = ctx->clock_alloc.Alloc(c);
+ ClockBlock *cb = ctx->clock_alloc.Map(idx);
+ internal_memset(cb, 0, sizeof(*cb));
+ CHECK_EQ(tab_->table[i/ClockBlock::kClockCount], 0);
+ tab_->table[i/ClockBlock::kClockCount] = idx;
+ }
+ size_ = nclk;
+}
+
+// Sets a single element in the vector clock.
+// This function is called only from weird places like AcquireGlobal.
+void ThreadClock::set(unsigned tid, u64 v) {
+ DCHECK_LT(tid, kMaxTid);
+ DCHECK_GE(v, clk_[tid].epoch);
+ clk_[tid].epoch = v;
+ if (nclk_ <= tid)
+ nclk_ = tid + 1;
+ last_acquire_ = clk_[tid_].epoch;
+}
+
+void ThreadClock::DebugDump(int(*printf)(const char *s, ...)) {
+ printf("clock=[");
+ for (uptr i = 0; i < nclk_; i++)
+ printf("%s%llu", i == 0 ? "" : ",", clk_[i].epoch);
+ printf("] reused=[");
+ for (uptr i = 0; i < nclk_; i++)
+ printf("%s%llu", i == 0 ? "" : ",", clk_[i].reused);
+ printf("] tid=%u/%u last_acq=%llu",
+ tid_, reused_, last_acquire_);
}
SyncClock::SyncClock()
- : clk_(MBlockClock) {
+ : release_store_tid_(kInvalidTid)
+ , release_store_reused_()
+ , tab_()
+ , tab_idx_()
+ , size_() {
+ for (uptr i = 0; i < kDirtyTids; i++)
+ dirty_tids_[i] = kInvalidTid;
+}
+
+SyncClock::~SyncClock() {
+ // Reset must be called before dtor.
+ CHECK_EQ(size_, 0);
+ CHECK_EQ(tab_, 0);
+ CHECK_EQ(tab_idx_, 0);
+}
+
+void SyncClock::Reset(ClockCache *c) {
+ if (size_ == 0) {
+ // nothing
+ } else if (size_ <= ClockBlock::kClockCount) {
+ // One-level table.
+ ctx->clock_alloc.Free(c, tab_idx_);
+ } else {
+ // Two-level table.
+ for (uptr i = 0; i < size_; i += ClockBlock::kClockCount)
+ ctx->clock_alloc.Free(c, tab_->table[i / ClockBlock::kClockCount]);
+ ctx->clock_alloc.Free(c, tab_idx_);
+ }
+ tab_ = 0;
+ tab_idx_ = 0;
+ size_ = 0;
+ release_store_tid_ = kInvalidTid;
+ release_store_reused_ = 0;
+ for (uptr i = 0; i < kDirtyTids; i++)
+ dirty_tids_[i] = kInvalidTid;
+}
+
+ClockElem &SyncClock::elem(unsigned tid) const {
+ DCHECK_LT(tid, size_);
+ if (size_ <= ClockBlock::kClockCount)
+ return tab_->clock[tid];
+ u32 idx = tab_->table[tid / ClockBlock::kClockCount];
+ ClockBlock *cb = ctx->clock_alloc.Map(idx);
+ return cb->clock[tid % ClockBlock::kClockCount];
+}
+
+void SyncClock::DebugDump(int(*printf)(const char *s, ...)) {
+ printf("clock=[");
+ for (uptr i = 0; i < size_; i++)
+ printf("%s%llu", i == 0 ? "" : ",", elem(i).epoch);
+ printf("] reused=[");
+ for (uptr i = 0; i < size_; i++)
+ printf("%s%llu", i == 0 ? "" : ",", elem(i).reused);
+ printf("] release_store_tid=%d/%d dirty_tids=%d/%d",
+ release_store_tid_, release_store_reused_,
+ dirty_tids_[0], dirty_tids_[1]);
}
} // namespace __tsan
diff --git a/lib/tsan/rtl/tsan_clock.h b/lib/tsan/rtl/tsan_clock.h
index 0ee93749b881..4e352cb81d11 100644
--- a/lib/tsan/rtl/tsan_clock.h
+++ b/lib/tsan/rtl/tsan_clock.h
@@ -14,65 +14,114 @@
#define TSAN_CLOCK_H
#include "tsan_defs.h"
-#include "tsan_vector.h"
+#include "tsan_dense_alloc.h"
namespace __tsan {
+struct ClockElem {
+ u64 epoch : kClkBits;
+ u64 reused : 64 - kClkBits;
+};
+
+struct ClockBlock {
+ static const uptr kSize = 512;
+ static const uptr kTableSize = kSize / sizeof(u32);
+ static const uptr kClockCount = kSize / sizeof(ClockElem);
+
+ union {
+ u32 table[kTableSize];
+ ClockElem clock[kClockCount];
+ };
+
+ ClockBlock() {
+ }
+};
+
+typedef DenseSlabAlloc<ClockBlock, 1<<16, 1<<10> ClockAlloc;
+typedef DenseSlabAllocCache ClockCache;
+
// The clock that lives in sync variables (mutexes, atomics, etc).
class SyncClock {
public:
SyncClock();
+ ~SyncClock();
uptr size() const {
- return clk_.Size();
+ return size_;
}
- void Reset() {
- clk_.Reset();
+ u64 get(unsigned tid) const {
+ return elem(tid).epoch;
}
+ void Resize(ClockCache *c, uptr nclk);
+ void Reset(ClockCache *c);
+
+ void DebugDump(int(*printf)(const char *s, ...));
+
private:
- Vector<u64> clk_;
friend struct ThreadClock;
+ static const uptr kDirtyTids = 2;
+
+ unsigned release_store_tid_;
+ unsigned release_store_reused_;
+ unsigned dirty_tids_[kDirtyTids];
+ // tab_ contains indirect pointer to a 512b block using DenseSlabAlloc.
+ // If size_ <= 64, then tab_ points to an array with 64 ClockElem's.
+ // Otherwise, tab_ points to an array with 128 u32 elements,
+ // each pointing to the second-level 512b block with 64 ClockElem's.
+ ClockBlock *tab_;
+ u32 tab_idx_;
+ u32 size_;
+
+ ClockElem &elem(unsigned tid) const;
};
// The clock that lives in threads.
struct ThreadClock {
public:
- ThreadClock();
+ typedef DenseSlabAllocCache Cache;
+
+ explicit ThreadClock(unsigned tid, unsigned reused = 0);
u64 get(unsigned tid) const {
DCHECK_LT(tid, kMaxTidInClock);
- return clk_[tid];
+ return clk_[tid].epoch;
}
- void set(unsigned tid, u64 v) {
- DCHECK_LT(tid, kMaxTid);
- DCHECK_GE(v, clk_[tid]);
- clk_[tid] = v;
- if (nclk_ <= tid)
- nclk_ = tid + 1;
+ void set(unsigned tid, u64 v);
+
+ void set(u64 v) {
+ DCHECK_GE(v, clk_[tid_].epoch);
+ clk_[tid_].epoch = v;
}
- void tick(unsigned tid) {
- DCHECK_LT(tid, kMaxTid);
- clk_[tid]++;
- if (nclk_ <= tid)
- nclk_ = tid + 1;
+ void tick() {
+ clk_[tid_].epoch++;
}
uptr size() const {
return nclk_;
}
- void acquire(const SyncClock *src);
- void release(SyncClock *dst) const;
- void acq_rel(SyncClock *dst);
- void ReleaseStore(SyncClock *dst) const;
+ void acquire(ClockCache *c, const SyncClock *src);
+ void release(ClockCache *c, SyncClock *dst) const;
+ void acq_rel(ClockCache *c, SyncClock *dst);
+ void ReleaseStore(ClockCache *c, SyncClock *dst) const;
+
+ void DebugReset();
+ void DebugDump(int(*printf)(const char *s, ...));
private:
+ static const uptr kDirtyTids = SyncClock::kDirtyTids;
+ const unsigned tid_;
+ const unsigned reused_;
+ u64 last_acquire_;
uptr nclk_;
- u64 clk_[kMaxTidInClock];
+ ClockElem clk_[kMaxTidInClock];
+
+ bool IsAlreadyAcquired(const SyncClock *src) const;
+ void UpdateCurrentThread(SyncClock *dst) const;
};
} // namespace __tsan
diff --git a/lib/tsan/rtl/tsan_defs.h b/lib/tsan/rtl/tsan_defs.h
index 1e53a8e02f0a..7ed3796b5012 100644
--- a/lib/tsan/rtl/tsan_defs.h
+++ b/lib/tsan/rtl/tsan_defs.h
@@ -24,7 +24,7 @@
namespace __tsan {
-#ifdef TSAN_GO
+#ifdef SANITIZER_GO
const bool kGoMode = true;
const bool kCppMode = false;
const char *const kTsanOptionsEnv = "GORACE";
@@ -41,8 +41,8 @@ const int kTidBits = 13;
const unsigned kMaxTid = 1 << kTidBits;
const unsigned kMaxTidInClock = kMaxTid * 2; // This includes msb 'freed' bit.
const int kClkBits = 42;
+const unsigned kMaxTidReuse = (1 << (64 - kClkBits)) - 1;
const uptr kShadowStackSize = 64 * 1024;
-const uptr kTraceStackSize = 256;
#ifdef TSAN_SHADOW_COUNT
# if TSAN_SHADOW_COUNT == 2 \
@@ -53,6 +53,7 @@ const uptr kShadowCnt = TSAN_SHADOW_COUNT;
# endif
#else
// Count of shadow values in a shadow cell.
+#define TSAN_SHADOW_COUNT 4
const uptr kShadowCnt = 4;
#endif
@@ -65,6 +66,19 @@ const uptr kShadowSize = 8;
// Shadow memory is kShadowMultiplier times larger than user memory.
const uptr kShadowMultiplier = kShadowSize * kShadowCnt / kShadowCell;
+// That many user bytes are mapped onto a single meta shadow cell.
+// Must be less or equal to minimal memory allocator alignment.
+const uptr kMetaShadowCell = 8;
+
+// Size of a single meta shadow value (u32).
+const uptr kMetaShadowSize = 4;
+
+#if defined(TSAN_NO_HISTORY) && TSAN_NO_HISTORY
+const bool kCollectHistory = false;
+#else
+const bool kCollectHistory = true;
+#endif
+
#if defined(TSAN_COLLECT_STATS) && TSAN_COLLECT_STATS
const bool kCollectStats = true;
#else
@@ -154,12 +168,20 @@ struct MD5Hash {
MD5Hash md5_hash(const void *data, uptr size);
struct ThreadState;
+class ThreadContext;
struct Context;
struct ReportStack;
class ReportDesc;
class RegionAlloc;
-class StackTrace;
-struct MBlock;
+
+// Descriptor of user's memory block.
+struct MBlock {
+ u64 siz;
+ u32 stk;
+ u16 tid;
+};
+
+COMPILER_CHECK(sizeof(MBlock) == 16);
} // namespace __tsan
diff --git a/lib/tsan/rtl/tsan_dense_alloc.h b/lib/tsan/rtl/tsan_dense_alloc.h
new file mode 100644
index 000000000000..a1cf84b8f166
--- /dev/null
+++ b/lib/tsan/rtl/tsan_dense_alloc.h
@@ -0,0 +1,137 @@
+//===-- tsan_dense_alloc.h --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of ThreadSanitizer (TSan), a race detector.
+//
+// A DenseSlabAlloc is a freelist-based allocator of fixed-size objects.
+// DenseSlabAllocCache is a thread-local cache for DenseSlabAlloc.
+// The only difference with traditional slab allocators is that DenseSlabAlloc
+// allocates/free indices of objects and provide a functionality to map
+// the index onto the real pointer. The index is u32, that is, 2 times smaller
+// than uptr (hense the Dense prefix).
+//===----------------------------------------------------------------------===//
+#ifndef TSAN_DENSE_ALLOC_H
+#define TSAN_DENSE_ALLOC_H
+
+#include "sanitizer_common/sanitizer_common.h"
+#include "tsan_defs.h"
+#include "tsan_mutex.h"
+
+namespace __tsan {
+
+class DenseSlabAllocCache {
+ static const uptr kSize = 128;
+ typedef u32 IndexT;
+ uptr pos;
+ IndexT cache[kSize];
+ template<typename T, uptr kL1Size, uptr kL2Size> friend class DenseSlabAlloc;
+};
+
+template<typename T, uptr kL1Size, uptr kL2Size>
+class DenseSlabAlloc {
+ public:
+ typedef DenseSlabAllocCache Cache;
+ typedef typename Cache::IndexT IndexT;
+
+ DenseSlabAlloc() {
+ // Check that kL1Size and kL2Size are sane.
+ CHECK_EQ(kL1Size & (kL1Size - 1), 0);
+ CHECK_EQ(kL2Size & (kL2Size - 1), 0);
+ CHECK_GE(1ull << (sizeof(IndexT) * 8), kL1Size * kL2Size);
+ // Check that it makes sense to use the dense alloc.
+ CHECK_GE(sizeof(T), sizeof(IndexT));
+ internal_memset(map_, 0, sizeof(map_));
+ freelist_ = 0;
+ fillpos_ = 0;
+ }
+
+ ~DenseSlabAlloc() {
+ for (uptr i = 0; i < kL1Size; i++) {
+ if (map_[i] != 0)
+ UnmapOrDie(map_[i], kL2Size * sizeof(T));
+ }
+ }
+
+ IndexT Alloc(Cache *c) {
+ if (c->pos == 0)
+ Refill(c);
+ return c->cache[--c->pos];
+ }
+
+ void Free(Cache *c, IndexT idx) {
+ DCHECK_NE(idx, 0);
+ if (c->pos == Cache::kSize)
+ Drain(c);
+ c->cache[c->pos++] = idx;
+ }
+
+ T *Map(IndexT idx) {
+ DCHECK_NE(idx, 0);
+ DCHECK_LE(idx, kL1Size * kL2Size);
+ return &map_[idx / kL2Size][idx % kL2Size];
+ }
+
+ void FlushCache(Cache *c) {
+ SpinMutexLock lock(&mtx_);
+ while (c->pos) {
+ IndexT idx = c->cache[--c->pos];
+ *(IndexT*)Map(idx) = freelist_;
+ freelist_ = idx;
+ }
+ }
+
+ void InitCache(Cache *c) {
+ c->pos = 0;
+ internal_memset(c->cache, 0, sizeof(c->cache));
+ }
+
+ private:
+ T *map_[kL1Size];
+ SpinMutex mtx_;
+ IndexT freelist_;
+ uptr fillpos_;
+
+ void Refill(Cache *c) {
+ SpinMutexLock lock(&mtx_);
+ if (freelist_ == 0) {
+ if (fillpos_ == kL1Size) {
+ Printf("ThreadSanitizer: DenseSlabAllocator overflow. Dying.\n");
+ Die();
+ }
+ T *batch = (T*)MmapOrDie(kL2Size * sizeof(T), "DenseSlabAllocator");
+ // Reserve 0 as invalid index.
+ IndexT start = fillpos_ == 0 ? 1 : 0;
+ for (IndexT i = start; i < kL2Size; i++) {
+ new(batch + i) T();
+ *(IndexT*)(batch + i) = i + 1 + fillpos_ * kL2Size;
+ }
+ *(IndexT*)(batch + kL2Size - 1) = 0;
+ freelist_ = fillpos_ * kL2Size + start;
+ map_[fillpos_++] = batch;
+ }
+ for (uptr i = 0; i < Cache::kSize / 2 && freelist_ != 0; i++) {
+ IndexT idx = freelist_;
+ c->cache[c->pos++] = idx;
+ freelist_ = *(IndexT*)Map(idx);
+ }
+ }
+
+ void Drain(Cache *c) {
+ SpinMutexLock lock(&mtx_);
+ for (uptr i = 0; i < Cache::kSize / 2; i++) {
+ IndexT idx = c->cache[--c->pos];
+ *(IndexT*)Map(idx) = freelist_;
+ freelist_ = idx;
+ }
+ }
+};
+
+} // namespace __tsan
+
+#endif // TSAN_DENSE_ALLOC_H
diff --git a/lib/tsan/rtl/tsan_fd.cc b/lib/tsan/rtl/tsan_fd.cc
index 86db119fc918..d18502f00540 100644
--- a/lib/tsan/rtl/tsan_fd.cc
+++ b/lib/tsan/rtl/tsan_fd.cc
@@ -44,11 +44,12 @@ static FdContext fdctx;
static bool bogusfd(int fd) {
// Apparently a bogus fd value.
- return fd < 0 || fd >= (1 << 30);
+ return fd < 0 || fd >= kTableSize;
}
-static FdSync *allocsync() {
- FdSync *s = (FdSync*)internal_alloc(MBlockFD, sizeof(FdSync));
+static FdSync *allocsync(ThreadState *thr, uptr pc) {
+ FdSync *s = (FdSync*)user_alloc(thr, pc, sizeof(FdSync), kDefaultAlignment,
+ false);
atomic_store(&s->rc, 1, memory_order_relaxed);
return s;
}
@@ -65,10 +66,7 @@ static void unref(ThreadState *thr, uptr pc, FdSync *s) {
CHECK_NE(s, &fdctx.globsync);
CHECK_NE(s, &fdctx.filesync);
CHECK_NE(s, &fdctx.socksync);
- SyncVar *v = CTX()->synctab.GetAndRemove(thr, pc, (uptr)s);
- if (v)
- DestroyAndFree(v);
- internal_free(s);
+ user_free(thr, pc, s, false);
}
}
}
@@ -81,13 +79,13 @@ static FdDesc *fddesc(ThreadState *thr, uptr pc, int fd) {
if (l1 == 0) {
uptr size = kTableSizeL2 * sizeof(FdDesc);
// We need this to reside in user memory to properly catch races on it.
- void *p = user_alloc(thr, pc, size);
+ void *p = user_alloc(thr, pc, size, kDefaultAlignment, false);
internal_memset(p, 0, size);
MemoryResetRange(thr, (uptr)&fddesc, (uptr)p, size);
if (atomic_compare_exchange_strong(pl1, &l1, (uptr)p, memory_order_acq_rel))
l1 = (uptr)p;
else
- user_free(thr, pc, p);
+ user_free(thr, pc, p, false);
}
return &((FdDesc*)l1)[fd % kTableSizeL2]; // NOLINT
}
@@ -219,7 +217,7 @@ void FdDup(ThreadState *thr, uptr pc, int oldfd, int newfd) {
void FdPipeCreate(ThreadState *thr, uptr pc, int rfd, int wfd) {
DPrintf("#%d: FdCreatePipe(%d, %d)\n", thr->tid, rfd, wfd);
- FdSync *s = allocsync();
+ FdSync *s = allocsync(thr, pc);
init(thr, pc, rfd, ref(s));
init(thr, pc, wfd, ref(s));
unref(thr, pc, s);
@@ -229,7 +227,7 @@ void FdEventCreate(ThreadState *thr, uptr pc, int fd) {
DPrintf("#%d: FdEventCreate(%d)\n", thr->tid, fd);
if (bogusfd(fd))
return;
- init(thr, pc, fd, allocsync());
+ init(thr, pc, fd, allocsync(thr, pc));
}
void FdSignalCreate(ThreadState *thr, uptr pc, int fd) {
@@ -250,7 +248,7 @@ void FdPollCreate(ThreadState *thr, uptr pc, int fd) {
DPrintf("#%d: FdPollCreate(%d)\n", thr->tid, fd);
if (bogusfd(fd))
return;
- init(thr, pc, fd, allocsync());
+ init(thr, pc, fd, allocsync(thr, pc));
}
void FdSocketCreate(ThreadState *thr, uptr pc, int fd) {
@@ -285,13 +283,13 @@ void FdSocketConnect(ThreadState *thr, uptr pc, int fd) {
init(thr, pc, fd, &fdctx.socksync);
}
-uptr File2addr(char *path) {
+uptr File2addr(const char *path) {
(void)path;
static u64 addr;
return (uptr)&addr;
}
-uptr Dir2addr(char *path) {
+uptr Dir2addr(const char *path) {
(void)path;
static u64 addr;
return (uptr)&addr;
diff --git a/lib/tsan/rtl/tsan_fd.h b/lib/tsan/rtl/tsan_fd.h
index 979198e2e74d..75c616dae0fd 100644
--- a/lib/tsan/rtl/tsan_fd.h
+++ b/lib/tsan/rtl/tsan_fd.h
@@ -57,8 +57,8 @@ void FdSocketConnect(ThreadState *thr, uptr pc, int fd);
bool FdLocation(uptr addr, int *fd, int *tid, u32 *stack);
void FdOnFork(ThreadState *thr, uptr pc);
-uptr File2addr(char *path);
-uptr Dir2addr(char *path);
+uptr File2addr(const char *path);
+uptr Dir2addr(const char *path);
} // namespace __tsan
diff --git a/lib/tsan/rtl/tsan_flags.cc b/lib/tsan/rtl/tsan_flags.cc
index c6f24bf49abd..5dc331f59469 100644
--- a/lib/tsan/rtl/tsan_flags.cc
+++ b/lib/tsan/rtl/tsan_flags.cc
@@ -20,46 +20,46 @@
namespace __tsan {
Flags *flags() {
- return &CTX()->flags;
+ return &ctx->flags;
}
// Can be overriden in frontend.
#ifdef TSAN_EXTERNAL_HOOKS
-void OverrideFlags(Flags *f);
extern "C" const char* __tsan_default_options();
#else
-void WEAK OverrideFlags(Flags *f) {
- (void)f;
-}
-extern "C" const char *WEAK __tsan_default_options() {
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+const char *WEAK __tsan_default_options() {
return "";
}
#endif
static void ParseFlags(Flags *f, const char *env) {
- ParseFlag(env, &f->enable_annotations, "enable_annotations");
- ParseFlag(env, &f->suppress_equal_stacks, "suppress_equal_stacks");
- ParseFlag(env, &f->suppress_equal_addresses, "suppress_equal_addresses");
- ParseFlag(env, &f->suppress_java, "suppress_java");
- ParseFlag(env, &f->report_bugs, "report_bugs");
- ParseFlag(env, &f->report_thread_leaks, "report_thread_leaks");
- ParseFlag(env, &f->report_destroy_locked, "report_destroy_locked");
- ParseFlag(env, &f->report_signal_unsafe, "report_signal_unsafe");
- ParseFlag(env, &f->report_atomic_races, "report_atomic_races");
- ParseFlag(env, &f->force_seq_cst_atomics, "force_seq_cst_atomics");
- ParseFlag(env, &f->suppressions, "suppressions");
- ParseFlag(env, &f->print_suppressions, "print_suppressions");
- ParseFlag(env, &f->print_benign, "print_benign");
- ParseFlag(env, &f->exitcode, "exitcode");
- ParseFlag(env, &f->halt_on_error, "halt_on_error");
- ParseFlag(env, &f->atexit_sleep_ms, "atexit_sleep_ms");
- ParseFlag(env, &f->profile_memory, "profile_memory");
- ParseFlag(env, &f->flush_memory_ms, "flush_memory_ms");
- ParseFlag(env, &f->flush_symbolizer_ms, "flush_symbolizer_ms");
- ParseFlag(env, &f->memory_limit_mb, "memory_limit_mb");
- ParseFlag(env, &f->stop_on_start, "stop_on_start");
- ParseFlag(env, &f->history_size, "history_size");
- ParseFlag(env, &f->io_sync, "io_sync");
+ ParseFlag(env, &f->enable_annotations, "enable_annotations", "");
+ ParseFlag(env, &f->suppress_equal_stacks, "suppress_equal_stacks", "");
+ ParseFlag(env, &f->suppress_equal_addresses, "suppress_equal_addresses", "");
+ ParseFlag(env, &f->report_bugs, "report_bugs", "");
+ ParseFlag(env, &f->report_thread_leaks, "report_thread_leaks", "");
+ ParseFlag(env, &f->report_destroy_locked, "report_destroy_locked", "");
+ ParseFlag(env, &f->report_mutex_bugs, "report_mutex_bugs", "");
+ ParseFlag(env, &f->report_signal_unsafe, "report_signal_unsafe", "");
+ ParseFlag(env, &f->report_atomic_races, "report_atomic_races", "");
+ ParseFlag(env, &f->force_seq_cst_atomics, "force_seq_cst_atomics", "");
+ ParseFlag(env, &f->print_benign, "print_benign", "");
+ ParseFlag(env, &f->exitcode, "exitcode", "");
+ ParseFlag(env, &f->halt_on_error, "halt_on_error", "");
+ ParseFlag(env, &f->atexit_sleep_ms, "atexit_sleep_ms", "");
+ ParseFlag(env, &f->profile_memory, "profile_memory", "");
+ ParseFlag(env, &f->flush_memory_ms, "flush_memory_ms", "");
+ ParseFlag(env, &f->flush_symbolizer_ms, "flush_symbolizer_ms", "");
+ ParseFlag(env, &f->memory_limit_mb, "memory_limit_mb", "");
+ ParseFlag(env, &f->stop_on_start, "stop_on_start", "");
+ ParseFlag(env, &f->running_on_valgrind, "running_on_valgrind", "");
+ ParseFlag(env, &f->history_size, "history_size", "");
+ ParseFlag(env, &f->io_sync, "io_sync", "");
+ ParseFlag(env, &f->die_after_fork, "die_after_fork", "");
+
+ // DDFlags
+ ParseFlag(env, &f->second_deadlock_stack, "second_deadlock_stack", "");
}
void InitializeFlags(Flags *f, const char *env) {
@@ -69,15 +69,13 @@ void InitializeFlags(Flags *f, const char *env) {
f->enable_annotations = true;
f->suppress_equal_stacks = true;
f->suppress_equal_addresses = true;
- f->suppress_java = false;
f->report_bugs = true;
f->report_thread_leaks = true;
f->report_destroy_locked = true;
+ f->report_mutex_bugs = true;
f->report_signal_unsafe = true;
f->report_atomic_races = true;
f->force_seq_cst_atomics = false;
- f->suppressions = "";
- f->print_suppressions = false;
f->print_benign = false;
f->exitcode = 66;
f->halt_on_error = false;
@@ -90,19 +88,25 @@ void InitializeFlags(Flags *f, const char *env) {
f->running_on_valgrind = false;
f->history_size = kGoMode ? 1 : 2; // There are a lot of goroutines in Go.
f->io_sync = 1;
+ f->die_after_fork = true;
+
+ // DDFlags
+ f->second_deadlock_stack = false;
CommonFlags *cf = common_flags();
- SetCommonFlagDefaults();
- *static_cast<CommonFlags*>(f) = *cf;
+ SetCommonFlagsDefaults(cf);
+ // Override some common flags defaults.
+ cf->allow_addr2line = true;
+ cf->detect_deadlocks = true;
+ cf->print_suppressions = false;
+ cf->stack_trace_format = " #%n %f %S %M";
// Let a frontend override.
- OverrideFlags(f);
ParseFlags(f, __tsan_default_options());
- ParseCommonFlagsFromString(__tsan_default_options());
+ ParseCommonFlagsFromString(cf, __tsan_default_options());
// Override from command line.
ParseFlags(f, env);
- ParseCommonFlagsFromString(env);
- *static_cast<CommonFlags*>(f) = *cf;
+ ParseCommonFlagsFromString(cf, env);
// Sanity check.
if (!f->report_bugs) {
@@ -111,6 +115,8 @@ void InitializeFlags(Flags *f, const char *env) {
f->report_signal_unsafe = false;
}
+ if (cf->help) PrintFlagDescriptions();
+
if (f->history_size < 0 || f->history_size > 7) {
Printf("ThreadSanitizer: incorrect value for history_size"
" (must be [0..7])\n");
diff --git a/lib/tsan/rtl/tsan_flags.h b/lib/tsan/rtl/tsan_flags.h
index 3916df3cc9e1..621ca139236f 100644
--- a/lib/tsan/rtl/tsan_flags.h
+++ b/lib/tsan/rtl/tsan_flags.h
@@ -14,34 +14,28 @@
#ifndef TSAN_FLAGS_H
#define TSAN_FLAGS_H
-// ----------- ATTENTION -------------
-// ThreadSanitizer user may provide its implementation of weak
-// symbol __tsan::OverrideFlags(__tsan::Flags). Therefore, this
-// header may be included in the user code, and shouldn't include
-// other headers from TSan or common sanitizer runtime.
-
#include "sanitizer_common/sanitizer_flags.h"
+#include "sanitizer_common/sanitizer_deadlock_detector_interface.h"
namespace __tsan {
-struct Flags : CommonFlags {
+struct Flags : DDFlags {
// Enable dynamic annotations, otherwise they are no-ops.
bool enable_annotations;
- // Supress a race report if we've already output another race report
+ // Suppress a race report if we've already output another race report
// with the same stack.
bool suppress_equal_stacks;
- // Supress a race report if we've already output another race report
+ // Suppress a race report if we've already output another race report
// on the same address.
bool suppress_equal_addresses;
- // Suppress weird race reports that can be seen if JVM is embed
- // into the process.
- bool suppress_java;
// Turns off bug reporting entirely (useful for benchmarking).
bool report_bugs;
// Report thread leaks at exit?
bool report_thread_leaks;
// Report destruction of a locked mutex?
bool report_destroy_locked;
+ // Report incorrect usages of mutexes and mutex annotations?
+ bool report_mutex_bugs;
// Report violations of async signal-safety
// (e.g. malloc() call from a signal handler).
bool report_signal_unsafe;
@@ -50,10 +44,6 @@ struct Flags : CommonFlags {
// If set, all atomics are effectively sequentially consistent (seq_cst),
// regardless of what user actually specified.
bool force_seq_cst_atomics;
- // Suppressions filename.
- const char *suppressions;
- // Print matched suppressions at exit.
- bool print_suppressions;
// Print matched "benign" races at exit.
bool print_benign;
// Override exit status if something was reported.
@@ -87,6 +77,8 @@ struct Flags : CommonFlags {
// 1 - reasonable level of synchronization (write->read)
// 2 - global synchronization of all IO operations
int io_sync;
+ // Die after multi-threaded fork if the child creates new threads.
+ bool die_after_fork;
};
Flags *flags();
diff --git a/lib/tsan/rtl/tsan_ignoreset.cc b/lib/tsan/rtl/tsan_ignoreset.cc
new file mode 100644
index 000000000000..cdb90d229980
--- /dev/null
+++ b/lib/tsan/rtl/tsan_ignoreset.cc
@@ -0,0 +1,47 @@
+//===-- tsan_ignoreset.cc -------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+#include "tsan_ignoreset.h"
+
+namespace __tsan {
+
+const uptr IgnoreSet::kMaxSize;
+
+IgnoreSet::IgnoreSet()
+ : size_() {
+}
+
+void IgnoreSet::Add(u32 stack_id) {
+ if (size_ == kMaxSize)
+ return;
+ for (uptr i = 0; i < size_; i++) {
+ if (stacks_[i] == stack_id)
+ return;
+ }
+ stacks_[size_++] = stack_id;
+}
+
+void IgnoreSet::Reset() {
+ size_ = 0;
+}
+
+uptr IgnoreSet::Size() const {
+ return size_;
+}
+
+u32 IgnoreSet::At(uptr i) const {
+ CHECK_LT(i, size_);
+ CHECK_LE(size_, kMaxSize);
+ return stacks_[i];
+}
+
+} // namespace __tsan
diff --git a/lib/tsan/rtl/tsan_ignoreset.h b/lib/tsan/rtl/tsan_ignoreset.h
new file mode 100644
index 000000000000..e747d819c758
--- /dev/null
+++ b/lib/tsan/rtl/tsan_ignoreset.h
@@ -0,0 +1,38 @@
+//===-- tsan_ignoreset.h ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of ThreadSanitizer (TSan), a race detector.
+//
+// IgnoreSet holds a set of stack traces where ignores were enabled.
+//===----------------------------------------------------------------------===//
+#ifndef TSAN_IGNORESET_H
+#define TSAN_IGNORESET_H
+
+#include "tsan_defs.h"
+
+namespace __tsan {
+
+class IgnoreSet {
+ public:
+ static const uptr kMaxSize = 16;
+
+ IgnoreSet();
+ void Add(u32 stack_id);
+ void Reset();
+ uptr Size() const;
+ u32 At(uptr i) const;
+
+ private:
+ uptr size_;
+ u32 stacks_[kMaxSize];
+};
+
+} // namespace __tsan
+
+#endif // TSAN_IGNORESET_H
diff --git a/lib/tsan/rtl/tsan_interceptors.cc b/lib/tsan/rtl/tsan_interceptors.cc
index ef38f7987cde..5bede0ec7d0c 100644
--- a/lib/tsan/rtl/tsan_interceptors.cc
+++ b/lib/tsan/rtl/tsan_interceptors.cc
@@ -29,7 +29,17 @@
using namespace __tsan; // NOLINT
-const int kSigCount = 64;
+#if SANITIZER_FREEBSD
+#define __errno_location __error
+#define __libc_malloc __malloc
+#define __libc_realloc __realloc
+#define __libc_calloc __calloc
+#define __libc_free __free
+#define stdout __stdoutp
+#define stderr __stderrp
+#endif
+
+const int kSigCount = 65;
struct my_siginfo_t {
// The size is determined by looking at sizeof of real siginfo_t on linux.
@@ -47,12 +57,13 @@ DECLARE_REAL(int, pthread_attr_getdetachstate, void *, void *)
extern "C" int pthread_attr_setstacksize(void *attr, uptr stacksize);
extern "C" int pthread_key_create(unsigned *key, void (*destructor)(void* v));
extern "C" int pthread_setspecific(unsigned key, const void *v);
-extern "C" int pthread_mutexattr_gettype(void *a, int *type);
+DECLARE_REAL(int, pthread_mutexattr_gettype, void *, void *)
extern "C" int pthread_yield();
extern "C" int pthread_sigmask(int how, const __sanitizer_sigset_t *set,
__sanitizer_sigset_t *oldset);
// REAL(sigfillset) defined in common interceptors.
DECLARE_REAL(int, sigfillset, __sanitizer_sigset_t *set)
+DECLARE_REAL(int, fflush, __sanitizer_FILE *fp)
extern "C" void *pthread_self();
extern "C" void _exit(int status);
extern "C" int *__errno_location();
@@ -61,7 +72,10 @@ extern "C" void *__libc_malloc(uptr size);
extern "C" void *__libc_calloc(uptr size, uptr n);
extern "C" void *__libc_realloc(void *ptr, uptr size);
extern "C" void __libc_free(void *ptr);
+#if !SANITIZER_FREEBSD
extern "C" int mallopt(int param, int value);
+#endif
+extern __sanitizer_FILE *stdout, *stderr;
const int PTHREAD_MUTEX_RECURSIVE = 1;
const int PTHREAD_MUTEX_RECURSIVE_NP = 1;
const int EINVAL = 22;
@@ -73,6 +87,7 @@ const int SIGABRT = 6;
const int SIGFPE = 8;
const int SIGSEGV = 11;
const int SIGPIPE = 13;
+const int SIGTERM = 15;
const int SIGBUS = 7;
const int SIGSYS = 31;
void *const MAP_FAILED = (void*)-1;
@@ -95,9 +110,14 @@ struct sigaction_t {
sighandler_t sa_handler;
void (*sa_sigaction)(int sig, my_siginfo_t *siginfo, void *uctx);
};
+#if SANITIZER_FREEBSD
+ int sa_flags;
+ __sanitizer_sigset_t sa_mask;
+#else
__sanitizer_sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)();
+#endif
};
const sighandler_t SIG_DFL = (sighandler_t)0;
@@ -121,9 +141,9 @@ struct SignalDesc {
};
struct SignalContext {
- int in_blocking_func;
int int_signal_send;
- int pending_signal_count;
+ atomic_uintptr_t in_blocking_func;
+ atomic_uintptr_t have_pending_signals;
SignalDesc pending_signals[kSigCount];
};
@@ -135,7 +155,7 @@ static LibIgnore *libignore() {
}
void InitializeLibIgnore() {
- libignore()->Init(*GetSuppressionContext());
+ libignore()->Init(*SuppressionContext::Get());
libignore()->OnLibraryLoaded(0);
}
@@ -143,8 +163,7 @@ void InitializeLibIgnore() {
static SignalContext *SigCtx(ThreadState *thr) {
SignalContext *ctx = (SignalContext*)thr->signal_ctx;
- if (ctx == 0 && thr->is_alive) {
- ScopedInRtl in_rtl;
+ if (ctx == 0 && !thr->is_dead) {
ctx = (SignalContext*)MmapOrDie(sizeof(*ctx), "SignalContext");
MemoryResetRange(thr, (uptr)&SigCtx, (uptr)ctx, sizeof(*ctx));
thr->signal_ctx = ctx;
@@ -160,78 +179,92 @@ class ScopedInterceptor {
~ScopedInterceptor();
private:
ThreadState *const thr_;
- const int in_rtl_;
+ const uptr pc_;
bool in_ignored_lib_;
};
ScopedInterceptor::ScopedInterceptor(ThreadState *thr, const char *fname,
uptr pc)
: thr_(thr)
- , in_rtl_(thr->in_rtl)
+ , pc_(pc)
, in_ignored_lib_(false) {
- if (thr_->in_rtl == 0) {
+ if (!thr_->ignore_interceptors) {
Initialize(thr);
FuncEntry(thr, pc);
- thr_->in_rtl++;
- DPrintf("#%d: intercept %s()\n", thr_->tid, fname);
- } else {
- thr_->in_rtl++;
}
+ DPrintf("#%d: intercept %s()\n", thr_->tid, fname);
if (!thr_->in_ignored_lib && libignore()->IsIgnored(pc)) {
in_ignored_lib_ = true;
thr_->in_ignored_lib = true;
- ThreadIgnoreBegin(thr_);
+ ThreadIgnoreBegin(thr_, pc_);
}
}
ScopedInterceptor::~ScopedInterceptor() {
if (in_ignored_lib_) {
thr_->in_ignored_lib = false;
- ThreadIgnoreEnd(thr_);
+ ThreadIgnoreEnd(thr_, pc_);
}
- thr_->in_rtl--;
- if (thr_->in_rtl == 0) {
- FuncExit(thr_);
+ if (!thr_->ignore_interceptors) {
ProcessPendingSignals(thr_);
+ FuncExit(thr_);
+ CheckNoLocks(thr_);
}
- CHECK_EQ(in_rtl_, thr_->in_rtl);
}
#define SCOPED_INTERCEPTOR_RAW(func, ...) \
ThreadState *thr = cur_thread(); \
- StatInc(thr, StatInterceptor); \
- StatInc(thr, StatInt_##func); \
const uptr caller_pc = GET_CALLER_PC(); \
ScopedInterceptor si(thr, #func, caller_pc); \
- const uptr pc = __sanitizer::StackTrace::GetCurrentPc(); \
+ const uptr pc = StackTrace::GetCurrentPc(); \
(void)pc; \
/**/
#define SCOPED_TSAN_INTERCEPTOR(func, ...) \
SCOPED_INTERCEPTOR_RAW(func, __VA_ARGS__); \
if (REAL(func) == 0) { \
- Printf("FATAL: ThreadSanitizer: failed to intercept %s\n", #func); \
+ Report("FATAL: ThreadSanitizer: failed to intercept %s\n", #func); \
Die(); \
- } \
- if (thr->in_rtl > 1 || thr->in_ignored_lib) \
+ } \
+ if (thr->ignore_interceptors || thr->in_ignored_lib) \
return REAL(func)(__VA_ARGS__); \
/**/
#define TSAN_INTERCEPTOR(ret, func, ...) INTERCEPTOR(ret, func, __VA_ARGS__)
#define TSAN_INTERCEPT(func) INTERCEPT_FUNCTION(func)
+#if SANITIZER_FREEBSD
+# define TSAN_INTERCEPT_VER(func, ver) INTERCEPT_FUNCTION(func)
+#else
+# define TSAN_INTERCEPT_VER(func, ver) INTERCEPT_FUNCTION_VER(func, ver)
+#endif
#define BLOCK_REAL(name) (BlockingCall(thr), REAL(name))
struct BlockingCall {
explicit BlockingCall(ThreadState *thr)
- : ctx(SigCtx(thr)) {
- ctx->in_blocking_func++;
+ : thr(thr)
+ , ctx(SigCtx(thr)) {
+ for (;;) {
+ atomic_store(&ctx->in_blocking_func, 1, memory_order_relaxed);
+ if (atomic_load(&ctx->have_pending_signals, memory_order_relaxed) == 0)
+ break;
+ atomic_store(&ctx->in_blocking_func, 0, memory_order_relaxed);
+ ProcessPendingSignals(thr);
+ }
+ // When we are in a "blocking call", we process signals asynchronously
+ // (right when they arrive). In this context we do not expect to be
+ // executing any user/runtime code. The known interceptor sequence when
+ // this is not true is: pthread_join -> munmap(stack). It's fine
+ // to ignore munmap in this case -- we handle stack shadow separately.
+ thr->ignore_interceptors++;
}
~BlockingCall() {
- ctx->in_blocking_func--;
+ thr->ignore_interceptors--;
+ atomic_store(&ctx->in_blocking_func, 0, memory_order_relaxed);
}
+ ThreadState *thr;
SignalContext *ctx;
};
@@ -256,116 +289,78 @@ TSAN_INTERCEPTOR(int, nanosleep, void *req, void *rem) {
return res;
}
-TSAN_INTERCEPTOR(void*, dlopen, const char *filename, int flag) {
- SCOPED_INTERCEPTOR_RAW(dlopen, filename, flag);
- // dlopen will execute global constructors, so it must be not in rtl.
- CHECK_EQ(thr->in_rtl, 1);
- thr->in_rtl = 0;
- void *res = REAL(dlopen)(filename, flag);
- thr->in_rtl = 1;
- libignore()->OnLibraryLoaded(filename);
- return res;
-}
+// The sole reason tsan wraps atexit callbacks is to establish synchronization
+// between callback setup and callback execution.
+struct AtExitCtx {
+ void (*f)();
+ void *arg;
+};
-TSAN_INTERCEPTOR(int, dlclose, void *handle) {
- SCOPED_INTERCEPTOR_RAW(dlclose, handle);
- // dlclose will execute global destructors, so it must be not in rtl.
- CHECK_EQ(thr->in_rtl, 1);
- thr->in_rtl = 0;
- int res = REAL(dlclose)(handle);
- thr->in_rtl = 1;
- libignore()->OnLibraryUnloaded();
- return res;
+static void at_exit_wrapper(void *arg) {
+ ThreadState *thr = cur_thread();
+ uptr pc = 0;
+ Acquire(thr, pc, (uptr)arg);
+ AtExitCtx *ctx = (AtExitCtx*)arg;
+ ((void(*)(void *arg))ctx->f)(ctx->arg);
+ __libc_free(ctx);
}
-class AtExitContext {
- public:
- AtExitContext()
- : mtx_(MutexTypeAtExit, StatMtxAtExit)
- , pos_() {
- }
-
- typedef void(*atexit_t)();
-
- int atexit(ThreadState *thr, uptr pc, bool is_on_exit,
- atexit_t f, void *arg) {
- Lock l(&mtx_);
- if (pos_ == kMaxAtExit)
- return 1;
- Release(thr, pc, (uptr)this);
- stack_[pos_] = f;
- args_[pos_] = arg;
- is_on_exits_[pos_] = is_on_exit;
- pos_++;
- return 0;
- }
-
- void exit(ThreadState *thr, uptr pc) {
- CHECK_EQ(thr->in_rtl, 0);
- for (;;) {
- atexit_t f = 0;
- void *arg = 0;
- bool is_on_exit = false;
- {
- Lock l(&mtx_);
- if (pos_) {
- pos_--;
- f = stack_[pos_];
- arg = args_[pos_];
- is_on_exit = is_on_exits_[pos_];
- ScopedInRtl in_rtl;
- Acquire(thr, pc, (uptr)this);
- }
- }
- if (f == 0)
- break;
- DPrintf("#%d: executing atexit func %p\n", thr->tid, f);
- CHECK_EQ(thr->in_rtl, 0);
- if (is_on_exit)
- ((void(*)(int status, void *arg))f)(0, arg);
- else
- ((void(*)(void *arg, void *dso))f)(arg, 0);
- }
- }
-
- private:
- static const int kMaxAtExit = 128;
- Mutex mtx_;
- atexit_t stack_[kMaxAtExit];
- void *args_[kMaxAtExit];
- bool is_on_exits_[kMaxAtExit];
- int pos_;
-};
-
-static AtExitContext *atexit_ctx;
+static int setup_at_exit_wrapper(ThreadState *thr, uptr pc, void(*f)(),
+ void *arg, void *dso);
TSAN_INTERCEPTOR(int, atexit, void (*f)()) {
if (cur_thread()->in_symbolizer)
return 0;
- SCOPED_TSAN_INTERCEPTOR(atexit, f);
- return atexit_ctx->atexit(thr, pc, false, (void(*)())f, 0);
+ // We want to setup the atexit callback even if we are in ignored lib
+ // or after fork.
+ SCOPED_INTERCEPTOR_RAW(atexit, f);
+ return setup_at_exit_wrapper(thr, pc, (void(*)())f, 0, 0);
}
-TSAN_INTERCEPTOR(int, on_exit, void(*f)(int, void*), void *arg) {
+TSAN_INTERCEPTOR(int, __cxa_atexit, void (*f)(void *a), void *arg, void *dso) {
if (cur_thread()->in_symbolizer)
return 0;
- SCOPED_TSAN_INTERCEPTOR(on_exit, f, arg);
- return atexit_ctx->atexit(thr, pc, true, (void(*)())f, arg);
+ SCOPED_TSAN_INTERCEPTOR(__cxa_atexit, f, arg, dso);
+ return setup_at_exit_wrapper(thr, pc, (void(*)())f, arg, dso);
}
-TSAN_INTERCEPTOR(int, __cxa_atexit, void (*f)(void *a), void *arg, void *dso) {
+static int setup_at_exit_wrapper(ThreadState *thr, uptr pc, void(*f)(),
+ void *arg, void *dso) {
+ AtExitCtx *ctx = (AtExitCtx*)__libc_malloc(sizeof(AtExitCtx));
+ ctx->f = f;
+ ctx->arg = arg;
+ Release(thr, pc, (uptr)ctx);
+ // Memory allocation in __cxa_atexit will race with free during exit,
+ // because we do not see synchronization around atexit callback list.
+ ThreadIgnoreBegin(thr, pc);
+ int res = REAL(__cxa_atexit)(at_exit_wrapper, ctx, dso);
+ ThreadIgnoreEnd(thr, pc);
+ return res;
+}
+
+static void on_exit_wrapper(int status, void *arg) {
+ ThreadState *thr = cur_thread();
+ uptr pc = 0;
+ Acquire(thr, pc, (uptr)arg);
+ AtExitCtx *ctx = (AtExitCtx*)arg;
+ ((void(*)(int status, void *arg))ctx->f)(status, ctx->arg);
+ __libc_free(ctx);
+}
+
+TSAN_INTERCEPTOR(int, on_exit, void(*f)(int, void*), void *arg) {
if (cur_thread()->in_symbolizer)
return 0;
- SCOPED_TSAN_INTERCEPTOR(__cxa_atexit, f, arg, dso);
- if (dso) {
- // Memory allocation in __cxa_atexit will race with free during exit,
- // because we do not see synchronization around atexit callback list.
- ThreadIgnoreBegin(thr);
- int res = REAL(__cxa_atexit)(f, arg, dso);
- ThreadIgnoreEnd(thr);
- return res;
- }
- return atexit_ctx->atexit(thr, pc, false, (void(*)())f, arg);
+ SCOPED_TSAN_INTERCEPTOR(on_exit, f, arg);
+ AtExitCtx *ctx = (AtExitCtx*)__libc_malloc(sizeof(AtExitCtx));
+ ctx->f = (void(*)())f;
+ ctx->arg = arg;
+ Release(thr, pc, (uptr)ctx);
+ // Memory allocation in __cxa_atexit will race with free during exit,
+ // because we do not see synchronization around atexit callback list.
+ ThreadIgnoreBegin(thr, pc);
+ int res = REAL(on_exit)(on_exit_wrapper, ctx);
+ ThreadIgnoreEnd(thr, pc);
+ return res;
}
// Cleanup old bufs.
@@ -391,10 +386,21 @@ static void SetJmp(ThreadState *thr, uptr sp, uptr mangled_sp) {
buf->sp = sp;
buf->mangled_sp = mangled_sp;
buf->shadow_stack_pos = thr->shadow_stack_pos;
+ SignalContext *sctx = SigCtx(thr);
+ buf->int_signal_send = sctx ? sctx->int_signal_send : 0;
+ buf->in_blocking_func = sctx ?
+ atomic_load(&sctx->in_blocking_func, memory_order_relaxed) :
+ false;
+ buf->in_signal_handler = atomic_load(&thr->in_signal_handler,
+ memory_order_relaxed);
}
static void LongJmp(ThreadState *thr, uptr *env) {
+#if SANITIZER_FREEBSD
+ uptr mangled_sp = env[2];
+#else
uptr mangled_sp = env[6];
+#endif // SANITIZER_FREEBSD
// Find the saved buf by mangled_sp.
for (uptr i = 0; i < thr->jmp_bufs.Size(); i++) {
JmpBuf *buf = &thr->jmp_bufs[i];
@@ -403,6 +409,14 @@ static void LongJmp(ThreadState *thr, uptr *env) {
// Unwind the stack.
while (thr->shadow_stack_pos > buf->shadow_stack_pos)
FuncExit(thr);
+ SignalContext *sctx = SigCtx(thr);
+ if (sctx) {
+ sctx->int_signal_send = buf->int_signal_send;
+ atomic_store(&sctx->in_blocking_func, buf->in_blocking_func,
+ memory_order_relaxed);
+ }
+ atomic_store(&thr->in_signal_handler, buf->in_signal_handler,
+ memory_order_relaxed);
JmpBufGarbageCollect(thr, buf->sp - 1); // do not collect buf->sp
return;
}
@@ -413,7 +427,6 @@ static void LongJmp(ThreadState *thr, uptr *env) {
// FIXME: put everything below into a common extern "C" block?
extern "C" void __tsan_setjmp(uptr sp, uptr mangled_sp) {
- ScopedInRtl in_rtl;
SetJmp(cur_thread(), sp, mangled_sp);
}
@@ -540,7 +553,7 @@ TSAN_INTERCEPTOR(void, cfree, void *p) {
TSAN_INTERCEPTOR(uptr, malloc_usable_size, void *p) {
SCOPED_INTERCEPTOR_RAW(malloc_usable_size, p);
- return user_alloc_usable_size(thr, pc, p);
+ return user_alloc_usable_size(p);
}
#define OPERATOR_NEW_BODY(mangled_name) \
@@ -587,21 +600,21 @@ void *operator new[](__sanitizer::uptr size, std::nothrow_t const&) {
user_free(thr, pc, ptr);
SANITIZER_INTERFACE_ATTRIBUTE
-void operator delete(void *ptr);
-void operator delete(void *ptr) {
+void operator delete(void *ptr) throw();
+void operator delete(void *ptr) throw() {
OPERATOR_DELETE_BODY(_ZdlPv);
}
SANITIZER_INTERFACE_ATTRIBUTE
-void operator delete[](void *ptr);
-void operator delete[](void *ptr) {
- OPERATOR_DELETE_BODY(_ZdlPvRKSt9nothrow_t);
+void operator delete[](void *ptr) throw();
+void operator delete[](void *ptr) throw() {
+ OPERATOR_DELETE_BODY(_ZdaPv);
}
SANITIZER_INTERFACE_ATTRIBUTE
void operator delete(void *ptr, std::nothrow_t const&);
void operator delete(void *ptr, std::nothrow_t const&) {
- OPERATOR_DELETE_BODY(_ZdaPv);
+ OPERATOR_DELETE_BODY(_ZdlPvRKSt9nothrow_t);
}
SANITIZER_INTERFACE_ATTRIBUTE
@@ -635,7 +648,8 @@ TSAN_INTERCEPTOR(int, memcmp, const void *s1, const void *s2, uptr n) {
int res = 0;
uptr len = 0;
for (; len < n; len++) {
- if ((res = ((unsigned char*)s1)[len] - ((unsigned char*)s2)[len]))
+ if ((res = ((const unsigned char *)s1)[len] -
+ ((const unsigned char *)s2)[len]))
break;
}
MemoryAccessRange(thr, pc, (uptr)s1, len < n ? len + 1 : n, false);
@@ -643,20 +657,6 @@ TSAN_INTERCEPTOR(int, memcmp, const void *s1, const void *s2, uptr n) {
return res;
}
-TSAN_INTERCEPTOR(void*, memchr, void *s, int c, uptr n) {
- SCOPED_TSAN_INTERCEPTOR(memchr, s, c, n);
- void *res = REAL(memchr)(s, c, n);
- uptr len = res ? (char*)res - (char*)s + 1 : n;
- MemoryAccessRange(thr, pc, (uptr)s, len, false);
- return res;
-}
-
-TSAN_INTERCEPTOR(void*, memrchr, char *s, int c, uptr n) {
- SCOPED_TSAN_INTERCEPTOR(memrchr, s, c, n);
- MemoryAccessRange(thr, pc, (uptr)s, n, false);
- return REAL(memrchr)(s, c, n);
-}
-
TSAN_INTERCEPTOR(void*, memmove, void *dst, void *src, uptr n) {
SCOPED_TSAN_INTERCEPTOR(memmove, dst, src, n);
MemoryAccessRange(thr, pc, (uptr)dst, n, true);
@@ -746,6 +746,7 @@ TSAN_INTERCEPTOR(void*, mmap, void *addr, long_t sz, int prot,
return res;
}
+#if !SANITIZER_FREEBSD
TSAN_INTERCEPTOR(void*, mmap64, void *addr, long_t sz, int prot,
int flags, int fd, u64 off) {
SCOPED_TSAN_INTERCEPTOR(mmap64, addr, sz, prot, flags, fd, off);
@@ -759,6 +760,10 @@ TSAN_INTERCEPTOR(void*, mmap64, void *addr, long_t sz, int prot,
}
return res;
}
+#define TSAN_MAYBE_INTERCEPT_MMAP64 TSAN_INTERCEPT(mmap64)
+#else
+#define TSAN_MAYBE_INTERCEPT_MMAP64
+#endif
TSAN_INTERCEPTOR(int, munmap, void *addr, long_t sz) {
SCOPED_TSAN_INTERCEPTOR(munmap, addr, sz);
@@ -767,21 +772,36 @@ TSAN_INTERCEPTOR(int, munmap, void *addr, long_t sz) {
return res;
}
+#if !SANITIZER_FREEBSD
TSAN_INTERCEPTOR(void*, memalign, uptr align, uptr sz) {
SCOPED_INTERCEPTOR_RAW(memalign, align, sz);
return user_alloc(thr, pc, sz, align);
}
+#define TSAN_MAYBE_INTERCEPT_MEMALIGN TSAN_INTERCEPT(memalign)
+#else
+#define TSAN_MAYBE_INTERCEPT_MEMALIGN
+#endif
+
+TSAN_INTERCEPTOR(void*, aligned_alloc, uptr align, uptr sz) {
+ SCOPED_INTERCEPTOR_RAW(memalign, align, sz);
+ return user_alloc(thr, pc, sz, align);
+}
TSAN_INTERCEPTOR(void*, valloc, uptr sz) {
SCOPED_INTERCEPTOR_RAW(valloc, sz);
return user_alloc(thr, pc, sz, GetPageSizeCached());
}
+#if !SANITIZER_FREEBSD
TSAN_INTERCEPTOR(void*, pvalloc, uptr sz) {
SCOPED_INTERCEPTOR_RAW(pvalloc, sz);
sz = RoundUp(sz, GetPageSizeCached());
return user_alloc(thr, pc, sz, GetPageSizeCached());
}
+#define TSAN_MAYBE_INTERCEPT_PVALLOC TSAN_INTERCEPT(pvalloc)
+#else
+#define TSAN_MAYBE_INTERCEPT_PVALLOC
+#endif
TSAN_INTERCEPTOR(int, posix_memalign, void **memptr, uptr align, uptr sz) {
SCOPED_INTERCEPTOR_RAW(posix_memalign, memptr, align, sz);
@@ -827,7 +847,6 @@ static void thread_finalize(void *v) {
return;
}
{
- ScopedInRtl in_rtl;
ThreadState *thr = cur_thread();
ThreadFinish(thr);
SignalContext *sctx = thr->signal_ctx;
@@ -852,17 +871,19 @@ extern "C" void *__tsan_thread_start_func(void *arg) {
int tid = 0;
{
ThreadState *thr = cur_thread();
- ScopedInRtl in_rtl;
+ // Thread-local state is not initialized yet.
+ ScopedIgnoreInterceptors ignore;
+ ThreadIgnoreBegin(thr, 0);
if (pthread_setspecific(g_thread_finalize_key,
(void *)kPthreadDestructorIterations)) {
Printf("ThreadSanitizer: failed to set thread key\n");
Die();
}
+ ThreadIgnoreEnd(thr, 0);
while ((tid = atomic_load(&p->tid, memory_order_acquire)) == 0)
pthread_yield();
atomic_store(&p->tid, 0, memory_order_release);
ThreadStart(thr, tid, GetTid());
- CHECK_EQ(thr->in_rtl, 1);
}
void *res = callback(param);
// Prevent the callback from being tail called,
@@ -875,6 +896,17 @@ extern "C" void *__tsan_thread_start_func(void *arg) {
TSAN_INTERCEPTOR(int, pthread_create,
void *th, void *attr, void *(*callback)(void*), void * param) {
SCOPED_INTERCEPTOR_RAW(pthread_create, th, attr, callback, param);
+ if (ctx->after_multithreaded_fork) {
+ if (flags()->die_after_fork) {
+ Report("ThreadSanitizer: starting new threads after multi-threaded "
+ "fork is not supported. Dying (set die_after_fork=0 to override)\n");
+ Die();
+ } else {
+ VPrintf(1, "ThreadSanitizer: starting new threads after multi-threaded "
+ "fork is not supported (pid %d). Continuing because of "
+ "die_after_fork=0, but you are on your own\n", internal_getpid());
+ }
+ }
__sanitizer_pthread_attr_t myattr;
if (attr == 0) {
pthread_attr_init(&myattr);
@@ -882,13 +914,20 @@ TSAN_INTERCEPTOR(int, pthread_create,
}
int detached = 0;
REAL(pthread_attr_getdetachstate)(attr, &detached);
- AdjustStackSizeLinux(attr);
+ AdjustStackSize(attr);
ThreadParam p;
p.callback = callback;
p.param = param;
atomic_store(&p.tid, 0, memory_order_relaxed);
- int res = REAL(pthread_create)(th, attr, __tsan_thread_start_func, &p);
+ int res = -1;
+ {
+ // Otherwise we see false positives in pthread stack manipulation.
+ ScopedIgnoreInterceptors ignore;
+ ThreadIgnoreBegin(thr, pc);
+ res = REAL(pthread_create)(th, attr, __tsan_thread_start_func, &p);
+ ThreadIgnoreEnd(thr, pc);
+ }
if (res == 0) {
int tid = ThreadCreate(thr, pc, *(uptr*)th, detached);
CHECK_NE(tid, 0);
@@ -904,7 +943,9 @@ TSAN_INTERCEPTOR(int, pthread_create,
TSAN_INTERCEPTOR(int, pthread_join, void *th, void **ret) {
SCOPED_INTERCEPTOR_RAW(pthread_join, th, ret);
int tid = ThreadTid(thr, pc, (uptr)th);
+ ThreadIgnoreBegin(thr, pc);
int res = BLOCK_REAL(pthread_join)(th, ret);
+ ThreadIgnoreEnd(thr, pc);
if (res == 0) {
ThreadJoin(thr, pc, tid);
}
@@ -921,6 +962,122 @@ TSAN_INTERCEPTOR(int, pthread_detach, void *th) {
return res;
}
+// Problem:
+// NPTL implementation of pthread_cond has 2 versions (2.2.5 and 2.3.2).
+// pthread_cond_t has different size in the different versions.
+// If call new REAL functions for old pthread_cond_t, they will corrupt memory
+// after pthread_cond_t (old cond is smaller).
+// If we call old REAL functions for new pthread_cond_t, we will lose some
+// functionality (e.g. old functions do not support waiting against
+// CLOCK_REALTIME).
+// Proper handling would require to have 2 versions of interceptors as well.
+// But this is messy, in particular requires linker scripts when sanitizer
+// runtime is linked into a shared library.
+// Instead we assume we don't have dynamic libraries built against old
+// pthread (2.2.5 is dated by 2002). And provide legacy_pthread_cond flag
+// that allows to work with old libraries (but this mode does not support
+// some features, e.g. pthread_condattr_getpshared).
+static void *init_cond(void *c, bool force = false) {
+ // sizeof(pthread_cond_t) >= sizeof(uptr) in both versions.
+ // So we allocate additional memory on the side large enough to hold
+ // any pthread_cond_t object. Always call new REAL functions, but pass
+ // the aux object to them.
+ // Note: the code assumes that PTHREAD_COND_INITIALIZER initializes
+ // first word of pthread_cond_t to zero.
+ // It's all relevant only for linux.
+ if (!common_flags()->legacy_pthread_cond)
+ return c;
+ atomic_uintptr_t *p = (atomic_uintptr_t*)c;
+ uptr cond = atomic_load(p, memory_order_acquire);
+ if (!force && cond != 0)
+ return (void*)cond;
+ void *newcond = WRAP(malloc)(pthread_cond_t_sz);
+ internal_memset(newcond, 0, pthread_cond_t_sz);
+ if (atomic_compare_exchange_strong(p, &cond, (uptr)newcond,
+ memory_order_acq_rel))
+ return newcond;
+ WRAP(free)(newcond);
+ return (void*)cond;
+}
+
+struct CondMutexUnlockCtx {
+ ThreadState *thr;
+ uptr pc;
+ void *m;
+};
+
+static void cond_mutex_unlock(CondMutexUnlockCtx *arg) {
+ MutexLock(arg->thr, arg->pc, (uptr)arg->m);
+}
+
+INTERCEPTOR(int, pthread_cond_init, void *c, void *a) {
+ void *cond = init_cond(c, true);
+ SCOPED_TSAN_INTERCEPTOR(pthread_cond_init, cond, a);
+ MemoryAccessRange(thr, pc, (uptr)c, sizeof(uptr), true);
+ return REAL(pthread_cond_init)(cond, a);
+}
+
+INTERCEPTOR(int, pthread_cond_wait, void *c, void *m) {
+ void *cond = init_cond(c);
+ SCOPED_TSAN_INTERCEPTOR(pthread_cond_wait, cond, m);
+ MutexUnlock(thr, pc, (uptr)m);
+ MemoryAccessRange(thr, pc, (uptr)c, sizeof(uptr), false);
+ CondMutexUnlockCtx arg = {thr, pc, m};
+ // This ensures that we handle mutex lock even in case of pthread_cancel.
+ // See test/tsan/cond_cancel.cc.
+ int res = call_pthread_cancel_with_cleanup(
+ (int(*)(void *c, void *m, void *abstime))REAL(pthread_cond_wait),
+ cond, m, 0, (void(*)(void *arg))cond_mutex_unlock, &arg);
+ if (res == errno_EOWNERDEAD)
+ MutexRepair(thr, pc, (uptr)m);
+ MutexLock(thr, pc, (uptr)m);
+ return res;
+}
+
+INTERCEPTOR(int, pthread_cond_timedwait, void *c, void *m, void *abstime) {
+ void *cond = init_cond(c);
+ SCOPED_TSAN_INTERCEPTOR(pthread_cond_timedwait, cond, m, abstime);
+ MutexUnlock(thr, pc, (uptr)m);
+ MemoryAccessRange(thr, pc, (uptr)c, sizeof(uptr), false);
+ CondMutexUnlockCtx arg = {thr, pc, m};
+ // This ensures that we handle mutex lock even in case of pthread_cancel.
+ // See test/tsan/cond_cancel.cc.
+ int res = call_pthread_cancel_with_cleanup(
+ REAL(pthread_cond_timedwait), cond, m, abstime,
+ (void(*)(void *arg))cond_mutex_unlock, &arg);
+ if (res == errno_EOWNERDEAD)
+ MutexRepair(thr, pc, (uptr)m);
+ MutexLock(thr, pc, (uptr)m);
+ return res;
+}
+
+INTERCEPTOR(int, pthread_cond_signal, void *c) {
+ void *cond = init_cond(c);
+ SCOPED_TSAN_INTERCEPTOR(pthread_cond_signal, cond);
+ MemoryAccessRange(thr, pc, (uptr)c, sizeof(uptr), false);
+ return REAL(pthread_cond_signal)(cond);
+}
+
+INTERCEPTOR(int, pthread_cond_broadcast, void *c) {
+ void *cond = init_cond(c);
+ SCOPED_TSAN_INTERCEPTOR(pthread_cond_broadcast, cond);
+ MemoryAccessRange(thr, pc, (uptr)c, sizeof(uptr), false);
+ return REAL(pthread_cond_broadcast)(cond);
+}
+
+INTERCEPTOR(int, pthread_cond_destroy, void *c) {
+ void *cond = init_cond(c);
+ SCOPED_TSAN_INTERCEPTOR(pthread_cond_destroy, cond);
+ MemoryAccessRange(thr, pc, (uptr)c, sizeof(uptr), true);
+ int res = REAL(pthread_cond_destroy)(cond);
+ if (common_flags()->legacy_pthread_cond) {
+ // Free our aux cond and zero the pointer to not leave dangling pointers.
+ WRAP(free)(cond);
+ atomic_store((atomic_uintptr_t*)c, 0, memory_order_relaxed);
+ }
+ return res;
+}
+
TSAN_INTERCEPTOR(int, pthread_mutex_init, void *m, void *a) {
SCOPED_TSAN_INTERCEPTOR(pthread_mutex_init, m, a);
int res = REAL(pthread_mutex_init)(m, a);
@@ -928,7 +1085,7 @@ TSAN_INTERCEPTOR(int, pthread_mutex_init, void *m, void *a) {
bool recursive = false;
if (a) {
int type = 0;
- if (pthread_mutexattr_gettype(a, &type) == 0)
+ if (REAL(pthread_mutexattr_gettype)(a, &type) == 0)
recursive = (type == PTHREAD_MUTEX_RECURSIVE
|| type == PTHREAD_MUTEX_RECURSIVE_NP);
}
@@ -952,7 +1109,7 @@ TSAN_INTERCEPTOR(int, pthread_mutex_trylock, void *m) {
if (res == EOWNERDEAD)
MutexRepair(thr, pc, (uptr)m);
if (res == 0 || res == EOWNERDEAD)
- MutexLock(thr, pc, (uptr)m);
+ MutexLock(thr, pc, (uptr)m, /*rec=*/1, /*try_lock=*/true);
return res;
}
@@ -996,7 +1153,7 @@ TSAN_INTERCEPTOR(int, pthread_spin_trylock, void *m) {
SCOPED_TSAN_INTERCEPTOR(pthread_spin_trylock, m);
int res = REAL(pthread_spin_trylock)(m);
if (res == 0) {
- MutexLock(thr, pc, (uptr)m);
+ MutexLock(thr, pc, (uptr)m, /*rec=*/1, /*try_lock=*/true);
}
return res;
}
@@ -1039,7 +1196,7 @@ TSAN_INTERCEPTOR(int, pthread_rwlock_tryrdlock, void *m) {
SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_tryrdlock, m);
int res = REAL(pthread_rwlock_tryrdlock)(m);
if (res == 0) {
- MutexReadLock(thr, pc, (uptr)m);
+ MutexReadLock(thr, pc, (uptr)m, /*try_lock=*/true);
}
return res;
}
@@ -1066,7 +1223,7 @@ TSAN_INTERCEPTOR(int, pthread_rwlock_trywrlock, void *m) {
SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_trywrlock, m);
int res = REAL(pthread_rwlock_trywrlock)(m);
if (res == 0) {
- MutexLock(thr, pc, (uptr)m);
+ MutexLock(thr, pc, (uptr)m, /*rec=*/1, /*try_lock=*/true);
}
return res;
}
@@ -1087,23 +1244,6 @@ TSAN_INTERCEPTOR(int, pthread_rwlock_unlock, void *m) {
return res;
}
-TSAN_INTERCEPTOR(int, pthread_cond_destroy, void *c) {
- SCOPED_TSAN_INTERCEPTOR(pthread_cond_destroy, c);
- MemoryWrite(thr, pc, (uptr)c, kSizeLog1);
- int res = REAL(pthread_cond_destroy)(c);
- return res;
-}
-
-TSAN_INTERCEPTOR(int, pthread_cond_timedwait, void *c, void *m,
- void *abstime) {
- SCOPED_TSAN_INTERCEPTOR(pthread_cond_timedwait, c, m, abstime);
- MutexUnlock(thr, pc, (uptr)m);
- MemoryRead(thr, pc, (uptr)c, kSizeLog1);
- int res = REAL(pthread_cond_timedwait)(c, m, abstime);
- MutexLock(thr, pc, (uptr)m);
- return res;
-}
-
TSAN_INTERCEPTOR(int, pthread_barrier_init, void *b, void *a, unsigned count) {
SCOPED_TSAN_INTERCEPTOR(pthread_barrier_init, b, a, count);
MemoryWrite(thr, pc, (uptr)b, kSizeLog1);
@@ -1132,19 +1272,13 @@ TSAN_INTERCEPTOR(int, pthread_barrier_wait, void *b) {
TSAN_INTERCEPTOR(int, pthread_once, void *o, void (*f)()) {
SCOPED_INTERCEPTOR_RAW(pthread_once, o, f);
- // Using SCOPED_INTERCEPTOR_RAW, because if we are called from an ignored lib,
- // the user callback must be executed with thr->in_rtl == 0.
if (o == 0 || f == 0)
return EINVAL;
atomic_uint32_t *a = static_cast<atomic_uint32_t*>(o);
u32 v = atomic_load(a, memory_order_acquire);
if (v == 0 && atomic_compare_exchange_strong(a, &v, 1,
memory_order_relaxed)) {
- const int old_in_rtl = thr->in_rtl;
- thr->in_rtl = 0;
(*f)();
- CHECK_EQ(thr->in_rtl, 0);
- thr->in_rtl = old_in_rtl;
if (!thr->in_ignored_lib)
Release(thr, pc, (uptr)o);
atomic_store(a, 2, memory_order_release);
@@ -1214,73 +1348,135 @@ TSAN_INTERCEPTOR(int, sem_getvalue, void *s, int *sval) {
return res;
}
+#if !SANITIZER_FREEBSD
TSAN_INTERCEPTOR(int, __xstat, int version, const char *path, void *buf) {
SCOPED_TSAN_INTERCEPTOR(__xstat, version, path, buf);
return REAL(__xstat)(version, path, buf);
}
+#define TSAN_MAYBE_INTERCEPT___XSTAT TSAN_INTERCEPT(__xstat)
+#else
+#define TSAN_MAYBE_INTERCEPT___XSTAT
+#endif
TSAN_INTERCEPTOR(int, stat, const char *path, void *buf) {
+#if SANITIZER_FREEBSD
+ SCOPED_TSAN_INTERCEPTOR(stat, path, buf);
+ return REAL(stat)(path, buf);
+#else
SCOPED_TSAN_INTERCEPTOR(__xstat, 0, path, buf);
return REAL(__xstat)(0, path, buf);
+#endif
}
+#if !SANITIZER_FREEBSD
TSAN_INTERCEPTOR(int, __xstat64, int version, const char *path, void *buf) {
SCOPED_TSAN_INTERCEPTOR(__xstat64, version, path, buf);
return REAL(__xstat64)(version, path, buf);
}
+#define TSAN_MAYBE_INTERCEPT___XSTAT64 TSAN_INTERCEPT(__xstat64)
+#else
+#define TSAN_MAYBE_INTERCEPT___XSTAT64
+#endif
+#if !SANITIZER_FREEBSD
TSAN_INTERCEPTOR(int, stat64, const char *path, void *buf) {
SCOPED_TSAN_INTERCEPTOR(__xstat64, 0, path, buf);
return REAL(__xstat64)(0, path, buf);
}
+#define TSAN_MAYBE_INTERCEPT_STAT64 TSAN_INTERCEPT(stat64)
+#else
+#define TSAN_MAYBE_INTERCEPT_STAT64
+#endif
+#if !SANITIZER_FREEBSD
TSAN_INTERCEPTOR(int, __lxstat, int version, const char *path, void *buf) {
SCOPED_TSAN_INTERCEPTOR(__lxstat, version, path, buf);
return REAL(__lxstat)(version, path, buf);
}
+#define TSAN_MAYBE_INTERCEPT___LXSTAT TSAN_INTERCEPT(__lxstat)
+#else
+#define TSAN_MAYBE_INTERCEPT___LXSTAT
+#endif
TSAN_INTERCEPTOR(int, lstat, const char *path, void *buf) {
+#if SANITIZER_FREEBSD
+ SCOPED_TSAN_INTERCEPTOR(lstat, path, buf);
+ return REAL(lstat)(path, buf);
+#else
SCOPED_TSAN_INTERCEPTOR(__lxstat, 0, path, buf);
return REAL(__lxstat)(0, path, buf);
+#endif
}
+#if !SANITIZER_FREEBSD
TSAN_INTERCEPTOR(int, __lxstat64, int version, const char *path, void *buf) {
SCOPED_TSAN_INTERCEPTOR(__lxstat64, version, path, buf);
return REAL(__lxstat64)(version, path, buf);
}
+#define TSAN_MAYBE_INTERCEPT___LXSTAT64 TSAN_INTERCEPT(__lxstat64)
+#else
+#define TSAN_MAYBE_INTERCEPT___LXSTAT64
+#endif
+#if !SANITIZER_FREEBSD
TSAN_INTERCEPTOR(int, lstat64, const char *path, void *buf) {
SCOPED_TSAN_INTERCEPTOR(__lxstat64, 0, path, buf);
return REAL(__lxstat64)(0, path, buf);
}
+#define TSAN_MAYBE_INTERCEPT_LSTAT64 TSAN_INTERCEPT(lstat64)
+#else
+#define TSAN_MAYBE_INTERCEPT_LSTAT64
+#endif
+#if !SANITIZER_FREEBSD
TSAN_INTERCEPTOR(int, __fxstat, int version, int fd, void *buf) {
SCOPED_TSAN_INTERCEPTOR(__fxstat, version, fd, buf);
if (fd > 0)
FdAccess(thr, pc, fd);
return REAL(__fxstat)(version, fd, buf);
}
+#define TSAN_MAYBE_INTERCEPT___FXSTAT TSAN_INTERCEPT(__fxstat)
+#else
+#define TSAN_MAYBE_INTERCEPT___FXSTAT
+#endif
TSAN_INTERCEPTOR(int, fstat, int fd, void *buf) {
+#if SANITIZER_FREEBSD
+ SCOPED_TSAN_INTERCEPTOR(fstat, fd, buf);
+ if (fd > 0)
+ FdAccess(thr, pc, fd);
+ return REAL(fstat)(fd, buf);
+#else
SCOPED_TSAN_INTERCEPTOR(__fxstat, 0, fd, buf);
if (fd > 0)
FdAccess(thr, pc, fd);
return REAL(__fxstat)(0, fd, buf);
+#endif
}
+#if !SANITIZER_FREEBSD
TSAN_INTERCEPTOR(int, __fxstat64, int version, int fd, void *buf) {
SCOPED_TSAN_INTERCEPTOR(__fxstat64, version, fd, buf);
if (fd > 0)
FdAccess(thr, pc, fd);
return REAL(__fxstat64)(version, fd, buf);
}
+#define TSAN_MAYBE_INTERCEPT___FXSTAT64 TSAN_INTERCEPT(__fxstat64)
+#else
+#define TSAN_MAYBE_INTERCEPT___FXSTAT64
+#endif
+#if !SANITIZER_FREEBSD
TSAN_INTERCEPTOR(int, fstat64, int fd, void *buf) {
SCOPED_TSAN_INTERCEPTOR(__fxstat64, 0, fd, buf);
if (fd > 0)
FdAccess(thr, pc, fd);
return REAL(__fxstat64)(0, fd, buf);
}
+#define TSAN_MAYBE_INTERCEPT_FSTAT64 TSAN_INTERCEPT(fstat64)
+#else
+#define TSAN_MAYBE_INTERCEPT_FSTAT64
+#endif
TSAN_INTERCEPTOR(int, open, const char *name, int flags, int mode) {
SCOPED_TSAN_INTERCEPTOR(open, name, flags, mode);
@@ -1290,6 +1486,7 @@ TSAN_INTERCEPTOR(int, open, const char *name, int flags, int mode) {
return fd;
}
+#if !SANITIZER_FREEBSD
TSAN_INTERCEPTOR(int, open64, const char *name, int flags, int mode) {
SCOPED_TSAN_INTERCEPTOR(open64, name, flags, mode);
int fd = REAL(open64)(name, flags, mode);
@@ -1297,6 +1494,10 @@ TSAN_INTERCEPTOR(int, open64, const char *name, int flags, int mode) {
FdFileCreate(thr, pc, fd);
return fd;
}
+#define TSAN_MAYBE_INTERCEPT_OPEN64 TSAN_INTERCEPT(open64)
+#else
+#define TSAN_MAYBE_INTERCEPT_OPEN64
+#endif
TSAN_INTERCEPTOR(int, creat, const char *name, int mode) {
SCOPED_TSAN_INTERCEPTOR(creat, name, mode);
@@ -1306,6 +1507,7 @@ TSAN_INTERCEPTOR(int, creat, const char *name, int mode) {
return fd;
}
+#if !SANITIZER_FREEBSD
TSAN_INTERCEPTOR(int, creat64, const char *name, int mode) {
SCOPED_TSAN_INTERCEPTOR(creat64, name, mode);
int fd = REAL(creat64)(name, mode);
@@ -1313,6 +1515,10 @@ TSAN_INTERCEPTOR(int, creat64, const char *name, int mode) {
FdFileCreate(thr, pc, fd);
return fd;
}
+#define TSAN_MAYBE_INTERCEPT_CREAT64 TSAN_INTERCEPT(creat64)
+#else
+#define TSAN_MAYBE_INTERCEPT_CREAT64
+#endif
TSAN_INTERCEPTOR(int, dup, int oldfd) {
SCOPED_TSAN_INTERCEPTOR(dup, oldfd);
@@ -1338,6 +1544,7 @@ TSAN_INTERCEPTOR(int, dup3, int oldfd, int newfd, int flags) {
return newfd2;
}
+#if !SANITIZER_FREEBSD
TSAN_INTERCEPTOR(int, eventfd, unsigned initval, int flags) {
SCOPED_TSAN_INTERCEPTOR(eventfd, initval, flags);
int fd = REAL(eventfd)(initval, flags);
@@ -1345,7 +1552,12 @@ TSAN_INTERCEPTOR(int, eventfd, unsigned initval, int flags) {
FdEventCreate(thr, pc, fd);
return fd;
}
+#define TSAN_MAYBE_INTERCEPT_EVENTFD TSAN_INTERCEPT(eventfd)
+#else
+#define TSAN_MAYBE_INTERCEPT_EVENTFD
+#endif
+#if !SANITIZER_FREEBSD
TSAN_INTERCEPTOR(int, signalfd, int fd, void *mask, int flags) {
SCOPED_TSAN_INTERCEPTOR(signalfd, fd, mask, flags);
if (fd >= 0)
@@ -1355,7 +1567,12 @@ TSAN_INTERCEPTOR(int, signalfd, int fd, void *mask, int flags) {
FdSignalCreate(thr, pc, fd);
return fd;
}
+#define TSAN_MAYBE_INTERCEPT_SIGNALFD TSAN_INTERCEPT(signalfd)
+#else
+#define TSAN_MAYBE_INTERCEPT_SIGNALFD
+#endif
+#if !SANITIZER_FREEBSD
TSAN_INTERCEPTOR(int, inotify_init, int fake) {
SCOPED_TSAN_INTERCEPTOR(inotify_init, fake);
int fd = REAL(inotify_init)(fake);
@@ -1363,7 +1580,12 @@ TSAN_INTERCEPTOR(int, inotify_init, int fake) {
FdInotifyCreate(thr, pc, fd);
return fd;
}
+#define TSAN_MAYBE_INTERCEPT_INOTIFY_INIT TSAN_INTERCEPT(inotify_init)
+#else
+#define TSAN_MAYBE_INTERCEPT_INOTIFY_INIT
+#endif
+#if !SANITIZER_FREEBSD
TSAN_INTERCEPTOR(int, inotify_init1, int flags) {
SCOPED_TSAN_INTERCEPTOR(inotify_init1, flags);
int fd = REAL(inotify_init1)(flags);
@@ -1371,6 +1593,10 @@ TSAN_INTERCEPTOR(int, inotify_init1, int flags) {
FdInotifyCreate(thr, pc, fd);
return fd;
}
+#define TSAN_MAYBE_INTERCEPT_INOTIFY_INIT1 TSAN_INTERCEPT(inotify_init1)
+#else
+#define TSAN_MAYBE_INTERCEPT_INOTIFY_INIT1
+#endif
TSAN_INTERCEPTOR(int, socket, int domain, int type, int protocol) {
SCOPED_TSAN_INTERCEPTOR(socket, domain, type, protocol);
@@ -1413,6 +1639,7 @@ TSAN_INTERCEPTOR(int, listen, int fd, int backlog) {
return res;
}
+#if !SANITIZER_FREEBSD
TSAN_INTERCEPTOR(int, epoll_create, int size) {
SCOPED_TSAN_INTERCEPTOR(epoll_create, size);
int fd = REAL(epoll_create)(size);
@@ -1420,7 +1647,12 @@ TSAN_INTERCEPTOR(int, epoll_create, int size) {
FdPollCreate(thr, pc, fd);
return fd;
}
+#define TSAN_MAYBE_INTERCEPT_EPOLL_CREATE TSAN_INTERCEPT(epoll_create)
+#else
+#define TSAN_MAYBE_INTERCEPT_EPOLL_CREATE
+#endif
+#if !SANITIZER_FREEBSD
TSAN_INTERCEPTOR(int, epoll_create1, int flags) {
SCOPED_TSAN_INTERCEPTOR(epoll_create1, flags);
int fd = REAL(epoll_create1)(flags);
@@ -1428,6 +1660,10 @@ TSAN_INTERCEPTOR(int, epoll_create1, int flags) {
FdPollCreate(thr, pc, fd);
return fd;
}
+#define TSAN_MAYBE_INTERCEPT_EPOLL_CREATE1 TSAN_INTERCEPT(epoll_create1)
+#else
+#define TSAN_MAYBE_INTERCEPT_EPOLL_CREATE1
+#endif
TSAN_INTERCEPTOR(int, close, int fd) {
SCOPED_TSAN_INTERCEPTOR(close, fd);
@@ -1436,14 +1672,20 @@ TSAN_INTERCEPTOR(int, close, int fd) {
return REAL(close)(fd);
}
+#if !SANITIZER_FREEBSD
TSAN_INTERCEPTOR(int, __close, int fd) {
SCOPED_TSAN_INTERCEPTOR(__close, fd);
if (fd >= 0)
FdClose(thr, pc, fd);
return REAL(__close)(fd);
}
+#define TSAN_MAYBE_INTERCEPT___CLOSE TSAN_INTERCEPT(__close)
+#else
+#define TSAN_MAYBE_INTERCEPT___CLOSE
+#endif
// glibc guts
+#if !SANITIZER_FREEBSD
TSAN_INTERCEPTOR(void, __res_iclose, void *state, bool free_addr) {
SCOPED_TSAN_INTERCEPTOR(__res_iclose, state, free_addr);
int fds[64];
@@ -1454,6 +1696,10 @@ TSAN_INTERCEPTOR(void, __res_iclose, void *state, bool free_addr) {
}
REAL(__res_iclose)(state, free_addr);
}
+#define TSAN_MAYBE_INTERCEPT___RES_ICLOSE TSAN_INTERCEPT(__res_iclose)
+#else
+#define TSAN_MAYBE_INTERCEPT___RES_ICLOSE
+#endif
TSAN_INTERCEPTOR(int, pipe, int *pipefd) {
SCOPED_TSAN_INTERCEPTOR(pipe, pipefd);
@@ -1509,10 +1755,9 @@ TSAN_INTERCEPTOR(int, unlink, char *path) {
return res;
}
-TSAN_INTERCEPTOR(void*, fopen, char *path, char *mode) {
- SCOPED_TSAN_INTERCEPTOR(fopen, path, mode);
- void *res = REAL(fopen)(path, mode);
- Acquire(thr, pc, File2addr(path));
+TSAN_INTERCEPTOR(void*, tmpfile, int fake) {
+ SCOPED_TSAN_INTERCEPTOR(tmpfile, fake);
+ void *res = REAL(tmpfile)(fake);
if (res) {
int fd = fileno_unlocked(res);
if (fd >= 0)
@@ -1521,15 +1766,10 @@ TSAN_INTERCEPTOR(void*, fopen, char *path, char *mode) {
return res;
}
-TSAN_INTERCEPTOR(void*, freopen, char *path, char *mode, void *stream) {
- SCOPED_TSAN_INTERCEPTOR(freopen, path, mode, stream);
- if (stream) {
- int fd = fileno_unlocked(stream);
- if (fd >= 0)
- FdClose(thr, pc, fd);
- }
- void *res = REAL(freopen)(path, mode, stream);
- Acquire(thr, pc, File2addr(path));
+#if !SANITIZER_FREEBSD
+TSAN_INTERCEPTOR(void*, tmpfile64, int fake) {
+ SCOPED_TSAN_INTERCEPTOR(tmpfile64, fake);
+ void *res = REAL(tmpfile64)(fake);
if (res) {
int fd = fileno_unlocked(res);
if (fd >= 0)
@@ -1537,19 +1777,10 @@ TSAN_INTERCEPTOR(void*, freopen, char *path, char *mode, void *stream) {
}
return res;
}
-
-TSAN_INTERCEPTOR(int, fclose, void *stream) {
- // libc file streams can call user-supplied functions, see fopencookie.
- {
- SCOPED_TSAN_INTERCEPTOR(fclose, stream);
- if (stream) {
- int fd = fileno_unlocked(stream);
- if (fd >= 0)
- FdClose(thr, pc, fd);
- }
- }
- return REAL(fclose)(stream);
-}
+#define TSAN_MAYBE_INTERCEPT_TMPFILE64 TSAN_INTERCEPT(tmpfile64)
+#else
+#define TSAN_MAYBE_INTERCEPT_TMPFILE64
+#endif
TSAN_INTERCEPTOR(uptr, fread, void *ptr, uptr size, uptr nmemb, void *f) {
// libc file streams can call user-supplied functions, see fopencookie.
@@ -1569,17 +1800,16 @@ TSAN_INTERCEPTOR(uptr, fwrite, const void *p, uptr size, uptr nmemb, void *f) {
return REAL(fwrite)(p, size, nmemb, f);
}
-TSAN_INTERCEPTOR(int, fflush, void *stream) {
- // libc file streams can call user-supplied functions, see fopencookie.
- {
- SCOPED_TSAN_INTERCEPTOR(fflush, stream);
- }
- return REAL(fflush)(stream);
+static void FlushStreams() {
+ // Flushing all the streams here may freeze the process if a child thread is
+ // performing file stream operations at the same time.
+ REAL(fflush)(stdout);
+ REAL(fflush)(stderr);
}
TSAN_INTERCEPTOR(void, abort, int fake) {
SCOPED_TSAN_INTERCEPTOR(abort, fake);
- REAL(fflush)(0);
+ FlushStreams();
REAL(abort)(fake);
}
@@ -1604,6 +1834,7 @@ TSAN_INTERCEPTOR(void*, opendir, char *path) {
return res;
}
+#if !SANITIZER_FREEBSD
TSAN_INTERCEPTOR(int, epoll_ctl, int epfd, int op, int fd, void *ev) {
SCOPED_TSAN_INTERCEPTOR(epoll_ctl, epfd, op, fd, ev);
if (epfd >= 0)
@@ -1615,7 +1846,12 @@ TSAN_INTERCEPTOR(int, epoll_ctl, int epfd, int op, int fd, void *ev) {
int res = REAL(epoll_ctl)(epfd, op, fd, ev);
return res;
}
+#define TSAN_MAYBE_INTERCEPT_EPOLL_CTL TSAN_INTERCEPT(epoll_ctl)
+#else
+#define TSAN_MAYBE_INTERCEPT_EPOLL_CTL
+#endif
+#if !SANITIZER_FREEBSD
TSAN_INTERCEPTOR(int, epoll_wait, int epfd, void *ev, int cnt, int timeout) {
SCOPED_TSAN_INTERCEPTOR(epoll_wait, epfd, ev, cnt, timeout);
if (epfd >= 0)
@@ -1625,31 +1861,119 @@ TSAN_INTERCEPTOR(int, epoll_wait, int epfd, void *ev, int cnt, int timeout) {
FdAcquire(thr, pc, epfd);
return res;
}
+#define TSAN_MAYBE_INTERCEPT_EPOLL_WAIT TSAN_INTERCEPT(epoll_wait)
+#else
+#define TSAN_MAYBE_INTERCEPT_EPOLL_WAIT
+#endif
+
+namespace __tsan {
+
+static void CallUserSignalHandler(ThreadState *thr, bool sync, bool acquire,
+ bool sigact, int sig, my_siginfo_t *info, void *uctx) {
+ if (acquire)
+ Acquire(thr, 0, (uptr)&sigactions[sig]);
+ // Ensure that the handler does not spoil errno.
+ const int saved_errno = errno;
+ errno = 99;
+ // Need to remember pc before the call, because the handler can reset it.
+ uptr pc = sigact ?
+ (uptr)sigactions[sig].sa_sigaction :
+ (uptr)sigactions[sig].sa_handler;
+ pc += 1; // return address is expected, OutputReport() will undo this
+ if (sigact)
+ sigactions[sig].sa_sigaction(sig, info, uctx);
+ else
+ sigactions[sig].sa_handler(sig);
+ // We do not detect errno spoiling for SIGTERM,
+ // because some SIGTERM handlers do spoil errno but reraise SIGTERM,
+ // tsan reports false positive in such case.
+ // It's difficult to properly detect this situation (reraise),
+ // because in async signal processing case (when handler is called directly
+ // from rtl_generic_sighandler) we have not yet received the reraised
+ // signal; and it looks too fragile to intercept all ways to reraise a signal.
+ if (flags()->report_bugs && !sync && sig != SIGTERM && errno != 99) {
+ VarSizeStackTrace stack;
+ ObtainCurrentStack(thr, pc, &stack);
+ ThreadRegistryLock l(ctx->thread_registry);
+ ScopedReport rep(ReportTypeErrnoInSignal);
+ if (!IsFiredSuppression(ctx, rep, stack)) {
+ rep.AddStack(stack, true);
+ OutputReport(thr, rep);
+ }
+ }
+ errno = saved_errno;
+}
+
+void ProcessPendingSignals(ThreadState *thr) {
+ SignalContext *sctx = SigCtx(thr);
+ if (sctx == 0 ||
+ atomic_load(&sctx->have_pending_signals, memory_order_relaxed) == 0)
+ return;
+ atomic_store(&sctx->have_pending_signals, 0, memory_order_relaxed);
+ atomic_fetch_add(&thr->in_signal_handler, 1, memory_order_relaxed);
+ // These are too big for stack.
+ static THREADLOCAL __sanitizer_sigset_t emptyset, oldset;
+ REAL(sigfillset)(&emptyset);
+ pthread_sigmask(SIG_SETMASK, &emptyset, &oldset);
+ for (int sig = 0; sig < kSigCount; sig++) {
+ SignalDesc *signal = &sctx->pending_signals[sig];
+ if (signal->armed) {
+ signal->armed = false;
+ if (sigactions[sig].sa_handler != SIG_DFL
+ && sigactions[sig].sa_handler != SIG_IGN) {
+ CallUserSignalHandler(thr, false, true, signal->sigaction,
+ sig, &signal->siginfo, &signal->ctx);
+ }
+ }
+ }
+ pthread_sigmask(SIG_SETMASK, &oldset, 0);
+ atomic_fetch_add(&thr->in_signal_handler, -1, memory_order_relaxed);
+}
+
+} // namespace __tsan
+
+static bool is_sync_signal(SignalContext *sctx, int sig) {
+ return sig == SIGSEGV || sig == SIGBUS || sig == SIGILL ||
+ sig == SIGABRT || sig == SIGFPE || sig == SIGPIPE || sig == SIGSYS ||
+ // If we are sending signal to ourselves, we must process it now.
+ (sctx && sig == sctx->int_signal_send);
+}
void ALWAYS_INLINE rtl_generic_sighandler(bool sigact, int sig,
my_siginfo_t *info, void *ctx) {
ThreadState *thr = cur_thread();
SignalContext *sctx = SigCtx(thr);
+ if (sig < 0 || sig >= kSigCount) {
+ VPrintf(1, "ThreadSanitizer: ignoring signal %d\n", sig);
+ return;
+ }
// Don't mess with synchronous signals.
- if (sig == SIGSEGV || sig == SIGBUS || sig == SIGILL ||
- sig == SIGABRT || sig == SIGFPE || sig == SIGPIPE || sig == SIGSYS ||
- // If we are sending signal to ourselves, we must process it now.
- (sctx && sig == sctx->int_signal_send) ||
+ const bool sync = is_sync_signal(sctx, sig);
+ if (sync ||
// If we are in blocking function, we can safely process it now
// (but check if we are in a recursive interceptor,
// i.e. pthread_join()->munmap()).
- (sctx && sctx->in_blocking_func == 1 && thr->in_rtl == 1)) {
- int in_rtl = thr->in_rtl;
- thr->in_rtl = 0;
- CHECK_EQ(thr->in_signal_handler, false);
- thr->in_signal_handler = true;
- if (sigact)
- sigactions[sig].sa_sigaction(sig, info, ctx);
- else
- sigactions[sig].sa_handler(sig);
- CHECK_EQ(thr->in_signal_handler, true);
- thr->in_signal_handler = false;
- thr->in_rtl = in_rtl;
+ (sctx && atomic_load(&sctx->in_blocking_func, memory_order_relaxed))) {
+ atomic_fetch_add(&thr->in_signal_handler, 1, memory_order_relaxed);
+ if (sctx && atomic_load(&sctx->in_blocking_func, memory_order_relaxed)) {
+ // We ignore interceptors in blocking functions,
+ // temporary enbled them again while we are calling user function.
+ int const i = thr->ignore_interceptors;
+ thr->ignore_interceptors = 0;
+ atomic_store(&sctx->in_blocking_func, 0, memory_order_relaxed);
+ CallUserSignalHandler(thr, sync, true, sigact, sig, info, ctx);
+ thr->ignore_interceptors = i;
+ atomic_store(&sctx->in_blocking_func, 1, memory_order_relaxed);
+ } else {
+ // Be very conservative with when we do acquire in this case.
+ // It's unsafe to do acquire in async handlers, because ThreadState
+ // can be in inconsistent state.
+ // SIGSYS looks relatively safe -- it's synchronous and can actually
+ // need some global state.
+ bool acq = (sig == SIGSYS);
+ CallUserSignalHandler(thr, sync, acq, sigact, sig, info, ctx);
+ }
+ atomic_fetch_add(&thr->in_signal_handler, -1, memory_order_relaxed);
return;
}
@@ -1663,7 +1987,7 @@ void ALWAYS_INLINE rtl_generic_sighandler(bool sigact, int sig,
internal_memcpy(&signal->siginfo, info, sizeof(*info));
if (ctx)
internal_memcpy(&signal->ctx, ctx, sizeof(signal->ctx));
- sctx->pending_signal_count++;
+ atomic_store(&sctx->have_pending_signals, 1, memory_order_relaxed);
}
}
@@ -1691,6 +2015,7 @@ TSAN_INTERCEPTOR(int, sigaction, int sig, sigaction_t *act, sigaction_t *old) {
else
newact.sa_handler = rtl_sighandler;
}
+ ReleaseStore(thr, pc, (uptr)&sigactions[sig]);
int res = REAL(sigaction)(sig, &newact, 0);
return res;
}
@@ -1768,61 +2093,52 @@ TSAN_INTERCEPTOR(int, getaddrinfo, void *node, void *service,
// We miss atomic synchronization in getaddrinfo,
// and can report false race between malloc and free
// inside of getaddrinfo. So ignore memory accesses.
- ThreadIgnoreBegin(thr);
- // getaddrinfo calls fopen, which can be intercepted by user.
- thr->in_rtl--;
- CHECK_EQ(thr->in_rtl, 0);
+ ThreadIgnoreBegin(thr, pc);
int res = REAL(getaddrinfo)(node, service, hints, rv);
- thr->in_rtl++;
- ThreadIgnoreEnd(thr);
+ ThreadIgnoreEnd(thr, pc);
return res;
}
-// Linux kernel has a bug that leads to kernel deadlock if a process
-// maps TBs of memory and then calls mlock().
-static void MlockIsUnsupported() {
- static atomic_uint8_t printed;
- if (atomic_exchange(&printed, 1, memory_order_relaxed))
- return;
- if (flags()->verbosity > 0)
- Printf("INFO: ThreadSanitizer ignores mlock/mlockall/munlock/munlockall\n");
-}
-
-TSAN_INTERCEPTOR(int, mlock, const void *addr, uptr len) {
- MlockIsUnsupported();
- return 0;
-}
-
-TSAN_INTERCEPTOR(int, munlock, const void *addr, uptr len) {
- MlockIsUnsupported();
- return 0;
-}
-
-TSAN_INTERCEPTOR(int, mlockall, int flags) {
- MlockIsUnsupported();
- return 0;
-}
-
-TSAN_INTERCEPTOR(int, munlockall, void) {
- MlockIsUnsupported();
- return 0;
-}
-
TSAN_INTERCEPTOR(int, fork, int fake) {
+ if (cur_thread()->in_symbolizer)
+ return REAL(fork)(fake);
SCOPED_INTERCEPTOR_RAW(fork, fake);
+ ForkBefore(thr, pc);
int pid = REAL(fork)(fake);
if (pid == 0) {
// child
+ ForkChildAfter(thr, pc);
FdOnFork(thr, pc);
} else if (pid > 0) {
// parent
+ ForkParentAfter(thr, pc);
+ } else {
+ // error
+ ForkParentAfter(thr, pc);
}
return pid;
}
+TSAN_INTERCEPTOR(int, vfork, int fake) {
+ // Some programs (e.g. openjdk) call close for all file descriptors
+ // in the child process. Under tsan it leads to false positives, because
+ // address space is shared, so the parent process also thinks that
+ // the descriptors are closed (while they are actually not).
+ // This leads to false positives due to missed synchronization.
+ // Strictly saying this is undefined behavior, because vfork child is not
+ // allowed to call any functions other than exec/exit. But this is what
+ // openjdk does, so we want to handle it.
+ // We could disable interceptors in the child process. But it's not possible
+ // to simply intercept and wrap vfork, because vfork child is not allowed
+ // to return from the function that calls vfork, and that's exactly what
+ // we would do. So this would require some assembly trickery as well.
+ // Instead we simply turn vfork into fork.
+ return WRAP(fork)(fake);
+}
+
static int OnExit(ThreadState *thr) {
int status = Finalize(thr);
- REAL(fflush)(0);
+ FlushStreams();
return status;
}
@@ -1832,20 +2148,31 @@ struct TsanInterceptorContext {
const uptr pc;
};
+static void HandleRecvmsg(ThreadState *thr, uptr pc,
+ __sanitizer_msghdr *msg) {
+ int fds[64];
+ int cnt = ExtractRecvmsgFDs(msg, fds, ARRAY_SIZE(fds));
+ for (int i = 0; i < cnt; i++)
+ FdEventCreate(thr, pc, fds[i]);
+}
+
#include "sanitizer_common/sanitizer_platform_interceptors.h"
-// Causes interceptor recursion (getpwuid_r() calls fopen())
-#undef SANITIZER_INTERCEPT_GETPWNAM_AND_FRIENDS
-#undef SANITIZER_INTERCEPT_GETPWNAM_R_AND_FRIENDS
// Causes interceptor recursion (getaddrinfo() and fopen())
#undef SANITIZER_INTERCEPT_GETADDRINFO
-#undef SANITIZER_INTERCEPT_GETNAMEINFO
-// Causes interceptor recursion (glob64() calls lstat64())
-#undef SANITIZER_INTERCEPT_GLOB
+// There interceptors do not seem to be strictly necessary for tsan.
+// But we see cases where the interceptors consume 70% of execution time.
+// Memory blocks passed to fgetgrent_r are "written to" by tsan several times.
+// First, there is some recursion (getgrnam_r calls fgetgrent_r), and each
+// function "writes to" the buffer. Then, the same memory is "written to"
+// twice, first as buf and then as pwbufp (both of them refer to the same
+// addresses).
+#undef SANITIZER_INTERCEPT_GETPWENT
+#undef SANITIZER_INTERCEPT_GETPWENT_R
+#undef SANITIZER_INTERCEPT_FGETPWENT
+#undef SANITIZER_INTERCEPT_GETPWNAM_AND_FRIENDS
+#undef SANITIZER_INTERCEPT_GETPWNAM_R_AND_FRIENDS
#define COMMON_INTERCEPT_FUNCTION(name) INTERCEPT_FUNCTION(name)
-#define COMMON_INTERCEPTOR_UNPOISON_PARAM(ctx, count) \
- do { \
- } while (false)
#define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \
MemoryAccessRange(((TsanInterceptorContext *)ctx)->thr, \
@@ -1863,6 +2190,31 @@ struct TsanInterceptorContext {
ctx = (void *)&_ctx; \
(void) ctx;
+#define COMMON_INTERCEPTOR_ENTER_NOIGNORE(ctx, func, ...) \
+ SCOPED_INTERCEPTOR_RAW(func, __VA_ARGS__); \
+ TsanInterceptorContext _ctx = {thr, caller_pc, pc}; \
+ ctx = (void *)&_ctx; \
+ (void) ctx;
+
+#define COMMON_INTERCEPTOR_FILE_OPEN(ctx, file, path) \
+ Acquire(thr, pc, File2addr(path)); \
+ if (file) { \
+ int fd = fileno_unlocked(file); \
+ if (fd >= 0) FdFileCreate(thr, pc, fd); \
+ }
+
+#define COMMON_INTERCEPTOR_FILE_CLOSE(ctx, file) \
+ if (file) { \
+ int fd = fileno_unlocked(file); \
+ if (fd >= 0) FdClose(thr, pc, fd); \
+ }
+
+#define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, res) \
+ libignore()->OnLibraryLoaded(filename)
+
+#define COMMON_INTERCEPTOR_LIBRARY_UNLOADED() \
+ libignore()->OnLibraryUnloaded()
+
#define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd) \
FdAcquire(((TsanInterceptorContext *) ctx)->thr, pc, fd)
@@ -1879,7 +2231,7 @@ struct TsanInterceptorContext {
ThreadSetName(((TsanInterceptorContext *) ctx)->thr, name)
#define COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name) \
- CTX()->thread_registry->SetThreadNameByUserId(thread, name)
+ __tsan::ctx->thread_registry->SetThreadNameByUserId(thread, name)
#define COMMON_INTERCEPTOR_BLOCK_REAL(name) BLOCK_REAL(name)
@@ -1898,10 +2250,16 @@ struct TsanInterceptorContext {
MutexRepair(((TsanInterceptorContext *)ctx)->thr, \
((TsanInterceptorContext *)ctx)->pc, (uptr)m)
+#define COMMON_INTERCEPTOR_HANDLE_RECVMSG(ctx, msg) \
+ HandleRecvmsg(((TsanInterceptorContext *)ctx)->thr, \
+ ((TsanInterceptorContext *)ctx)->pc, msg)
+
#include "sanitizer_common/sanitizer_common_interceptors.inc"
#define TSAN_SYSCALL() \
ThreadState *thr = cur_thread(); \
+ if (thr->ignore_interceptors) \
+ return; \
ScopedSyscall scoped_syscall(thr) \
/**/
@@ -1910,15 +2268,11 @@ struct ScopedSyscall {
explicit ScopedSyscall(ThreadState *thr)
: thr(thr) {
- if (thr->in_rtl == 0)
- Initialize(thr);
- thr->in_rtl++;
+ Initialize(thr);
}
~ScopedSyscall() {
- thr->in_rtl--;
- if (thr->in_rtl == 0)
- ProcessPendingSignals(thr);
+ ProcessPendingSignals(thr);
}
};
@@ -1927,131 +2281,131 @@ static void syscall_access_range(uptr pc, uptr p, uptr s, bool write) {
MemoryAccessRange(thr, pc, p, s, write);
}
+static void syscall_acquire(uptr pc, uptr addr) {
+ TSAN_SYSCALL();
+ Acquire(thr, pc, addr);
+ DPrintf("syscall_acquire(%p)\n", addr);
+}
+
+static void syscall_release(uptr pc, uptr addr) {
+ TSAN_SYSCALL();
+ DPrintf("syscall_release(%p)\n", addr);
+ Release(thr, pc, addr);
+}
+
static void syscall_fd_close(uptr pc, int fd) {
TSAN_SYSCALL();
- if (fd >= 0)
- FdClose(thr, pc, fd);
+ FdClose(thr, pc, fd);
+}
+
+static USED void syscall_fd_acquire(uptr pc, int fd) {
+ TSAN_SYSCALL();
+ FdAcquire(thr, pc, fd);
+ DPrintf("syscall_fd_acquire(%p)\n", fd);
+}
+
+static USED void syscall_fd_release(uptr pc, int fd) {
+ TSAN_SYSCALL();
+ DPrintf("syscall_fd_release(%p)\n", fd);
+ FdRelease(thr, pc, fd);
}
static void syscall_pre_fork(uptr pc) {
TSAN_SYSCALL();
+ ForkBefore(thr, pc);
}
-static void syscall_post_fork(uptr pc, int res) {
+static void syscall_post_fork(uptr pc, int pid) {
TSAN_SYSCALL();
- if (res == 0) {
+ if (pid == 0) {
// child
+ ForkChildAfter(thr, pc);
FdOnFork(thr, pc);
- } else if (res > 0) {
+ } else if (pid > 0) {
// parent
+ ForkParentAfter(thr, pc);
+ } else {
+ // error
+ ForkParentAfter(thr, pc);
}
}
#define COMMON_SYSCALL_PRE_READ_RANGE(p, s) \
syscall_access_range(GET_CALLER_PC(), (uptr)(p), (uptr)(s), false)
+
#define COMMON_SYSCALL_PRE_WRITE_RANGE(p, s) \
syscall_access_range(GET_CALLER_PC(), (uptr)(p), (uptr)(s), true)
+
#define COMMON_SYSCALL_POST_READ_RANGE(p, s) \
do { \
(void)(p); \
(void)(s); \
} while (false)
+
#define COMMON_SYSCALL_POST_WRITE_RANGE(p, s) \
do { \
(void)(p); \
(void)(s); \
} while (false)
+
+#define COMMON_SYSCALL_ACQUIRE(addr) \
+ syscall_acquire(GET_CALLER_PC(), (uptr)(addr))
+
+#define COMMON_SYSCALL_RELEASE(addr) \
+ syscall_release(GET_CALLER_PC(), (uptr)(addr))
+
#define COMMON_SYSCALL_FD_CLOSE(fd) syscall_fd_close(GET_CALLER_PC(), fd)
+
+#define COMMON_SYSCALL_FD_ACQUIRE(fd) syscall_fd_acquire(GET_CALLER_PC(), fd)
+
+#define COMMON_SYSCALL_FD_RELEASE(fd) syscall_fd_release(GET_CALLER_PC(), fd)
+
#define COMMON_SYSCALL_PRE_FORK() \
syscall_pre_fork(GET_CALLER_PC())
+
#define COMMON_SYSCALL_POST_FORK(res) \
syscall_post_fork(GET_CALLER_PC(), res)
+
#include "sanitizer_common/sanitizer_common_syscalls.inc"
namespace __tsan {
static void finalize(void *arg) {
ThreadState *thr = cur_thread();
- uptr pc = 0;
- atexit_ctx->exit(thr, pc);
int status = Finalize(thr);
- REAL(fflush)(0);
+ // Make sure the output is not lost.
+ FlushStreams();
if (status)
REAL(_exit)(status);
}
-void ProcessPendingSignals(ThreadState *thr) {
- CHECK_EQ(thr->in_rtl, 0);
- SignalContext *sctx = SigCtx(thr);
- if (sctx == 0 || sctx->pending_signal_count == 0 || thr->in_signal_handler)
- return;
- Context *ctx = CTX();
- thr->in_signal_handler = true;
- sctx->pending_signal_count = 0;
- // These are too big for stack.
- static THREADLOCAL __sanitizer_sigset_t emptyset, oldset;
- REAL(sigfillset)(&emptyset);
- pthread_sigmask(SIG_SETMASK, &emptyset, &oldset);
- for (int sig = 0; sig < kSigCount; sig++) {
- SignalDesc *signal = &sctx->pending_signals[sig];
- if (signal->armed) {
- signal->armed = false;
- if (sigactions[sig].sa_handler != SIG_DFL
- && sigactions[sig].sa_handler != SIG_IGN) {
- // Insure that the handler does not spoil errno.
- const int saved_errno = errno;
- errno = 0;
- if (signal->sigaction)
- sigactions[sig].sa_sigaction(sig, &signal->siginfo, &signal->ctx);
- else
- sigactions[sig].sa_handler(sig);
- if (flags()->report_bugs && errno != 0) {
- ScopedInRtl in_rtl;
- __tsan::StackTrace stack;
- uptr pc = signal->sigaction ?
- (uptr)sigactions[sig].sa_sigaction :
- (uptr)sigactions[sig].sa_handler;
- pc += 1; // return address is expected, OutputReport() will undo this
- stack.Init(&pc, 1);
- ThreadRegistryLock l(ctx->thread_registry);
- ScopedReport rep(ReportTypeErrnoInSignal);
- if (!IsFiredSuppression(ctx, rep, stack)) {
- rep.AddStack(&stack);
- OutputReport(ctx, rep, rep.GetReport()->stacks[0]);
- }
- }
- errno = saved_errno;
- }
- }
- }
- pthread_sigmask(SIG_SETMASK, &oldset, 0);
- CHECK_EQ(thr->in_signal_handler, true);
- thr->in_signal_handler = false;
-}
-
static void unreachable() {
- Printf("FATAL: ThreadSanitizer: unreachable called\n");
+ Report("FATAL: ThreadSanitizer: unreachable called\n");
Die();
}
void InitializeInterceptors() {
- CHECK_GT(cur_thread()->in_rtl, 0);
-
// We need to setup it early, because functions like dlsym() can call it.
REAL(memset) = internal_memset;
REAL(memcpy) = internal_memcpy;
REAL(memcmp) = internal_memcmp;
// Instruct libc malloc to consume less memory.
+#if !SANITIZER_FREEBSD
mallopt(1, 0); // M_MXFAST
mallopt(-3, 32*1024); // M_MMAP_THRESHOLD
+#endif
- SANITIZER_COMMON_INTERCEPTORS_INIT;
+ InitializeCommonInterceptors();
+
+ // We can not use TSAN_INTERCEPT to get setjmp addr,
+ // because it does &setjmp and setjmp is not present in some versions of libc.
+ using __interception::GetRealFunctionAddress;
+ GetRealFunctionAddress("setjmp", (uptr*)&REAL(setjmp), 0, 0);
+ GetRealFunctionAddress("_setjmp", (uptr*)&REAL(_setjmp), 0, 0);
+ GetRealFunctionAddress("sigsetjmp", (uptr*)&REAL(sigsetjmp), 0, 0);
+ GetRealFunctionAddress("__sigsetjmp", (uptr*)&REAL(__sigsetjmp), 0, 0);
- TSAN_INTERCEPT(setjmp);
- TSAN_INTERCEPT(_setjmp);
- TSAN_INTERCEPT(sigsetjmp);
- TSAN_INTERCEPT(__sigsetjmp);
TSAN_INTERCEPT(longjmp);
TSAN_INTERCEPT(siglongjmp);
@@ -2062,18 +2416,16 @@ void InitializeInterceptors() {
TSAN_INTERCEPT(free);
TSAN_INTERCEPT(cfree);
TSAN_INTERCEPT(mmap);
- TSAN_INTERCEPT(mmap64);
+ TSAN_MAYBE_INTERCEPT_MMAP64;
TSAN_INTERCEPT(munmap);
- TSAN_INTERCEPT(memalign);
+ TSAN_MAYBE_INTERCEPT_MEMALIGN;
TSAN_INTERCEPT(valloc);
- TSAN_INTERCEPT(pvalloc);
+ TSAN_MAYBE_INTERCEPT_PVALLOC;
TSAN_INTERCEPT(posix_memalign);
TSAN_INTERCEPT(strlen);
TSAN_INTERCEPT(memset);
TSAN_INTERCEPT(memcpy);
- TSAN_INTERCEPT(memchr);
- TSAN_INTERCEPT(memrchr);
TSAN_INTERCEPT(memmove);
TSAN_INTERCEPT(memcmp);
TSAN_INTERCEPT(strchr);
@@ -2088,6 +2440,13 @@ void InitializeInterceptors() {
TSAN_INTERCEPT(pthread_join);
TSAN_INTERCEPT(pthread_detach);
+ TSAN_INTERCEPT_VER(pthread_cond_init, "GLIBC_2.3.2");
+ TSAN_INTERCEPT_VER(pthread_cond_signal, "GLIBC_2.3.2");
+ TSAN_INTERCEPT_VER(pthread_cond_broadcast, "GLIBC_2.3.2");
+ TSAN_INTERCEPT_VER(pthread_cond_wait, "GLIBC_2.3.2");
+ TSAN_INTERCEPT_VER(pthread_cond_timedwait, "GLIBC_2.3.2");
+ TSAN_INTERCEPT_VER(pthread_cond_destroy, "GLIBC_2.3.2");
+
TSAN_INTERCEPT(pthread_mutex_init);
TSAN_INTERCEPT(pthread_mutex_destroy);
TSAN_INTERCEPT(pthread_mutex_trylock);
@@ -2109,9 +2468,6 @@ void InitializeInterceptors() {
TSAN_INTERCEPT(pthread_rwlock_timedwrlock);
TSAN_INTERCEPT(pthread_rwlock_unlock);
- INTERCEPT_FUNCTION_VER(pthread_cond_destroy, "GLIBC_2.3.2");
- INTERCEPT_FUNCTION_VER(pthread_cond_timedwait, "GLIBC_2.3.2");
-
TSAN_INTERCEPT(pthread_barrier_init);
TSAN_INTERCEPT(pthread_barrier_destroy);
TSAN_INTERCEPT(pthread_barrier_wait);
@@ -2127,38 +2483,38 @@ void InitializeInterceptors() {
TSAN_INTERCEPT(sem_getvalue);
TSAN_INTERCEPT(stat);
- TSAN_INTERCEPT(__xstat);
- TSAN_INTERCEPT(stat64);
- TSAN_INTERCEPT(__xstat64);
+ TSAN_MAYBE_INTERCEPT___XSTAT;
+ TSAN_MAYBE_INTERCEPT_STAT64;
+ TSAN_MAYBE_INTERCEPT___XSTAT64;
TSAN_INTERCEPT(lstat);
- TSAN_INTERCEPT(__lxstat);
- TSAN_INTERCEPT(lstat64);
- TSAN_INTERCEPT(__lxstat64);
+ TSAN_MAYBE_INTERCEPT___LXSTAT;
+ TSAN_MAYBE_INTERCEPT_LSTAT64;
+ TSAN_MAYBE_INTERCEPT___LXSTAT64;
TSAN_INTERCEPT(fstat);
- TSAN_INTERCEPT(__fxstat);
- TSAN_INTERCEPT(fstat64);
- TSAN_INTERCEPT(__fxstat64);
+ TSAN_MAYBE_INTERCEPT___FXSTAT;
+ TSAN_MAYBE_INTERCEPT_FSTAT64;
+ TSAN_MAYBE_INTERCEPT___FXSTAT64;
TSAN_INTERCEPT(open);
- TSAN_INTERCEPT(open64);
+ TSAN_MAYBE_INTERCEPT_OPEN64;
TSAN_INTERCEPT(creat);
- TSAN_INTERCEPT(creat64);
+ TSAN_MAYBE_INTERCEPT_CREAT64;
TSAN_INTERCEPT(dup);
TSAN_INTERCEPT(dup2);
TSAN_INTERCEPT(dup3);
- TSAN_INTERCEPT(eventfd);
- TSAN_INTERCEPT(signalfd);
- TSAN_INTERCEPT(inotify_init);
- TSAN_INTERCEPT(inotify_init1);
+ TSAN_MAYBE_INTERCEPT_EVENTFD;
+ TSAN_MAYBE_INTERCEPT_SIGNALFD;
+ TSAN_MAYBE_INTERCEPT_INOTIFY_INIT;
+ TSAN_MAYBE_INTERCEPT_INOTIFY_INIT1;
TSAN_INTERCEPT(socket);
TSAN_INTERCEPT(socketpair);
TSAN_INTERCEPT(connect);
TSAN_INTERCEPT(bind);
TSAN_INTERCEPT(listen);
- TSAN_INTERCEPT(epoll_create);
- TSAN_INTERCEPT(epoll_create1);
+ TSAN_MAYBE_INTERCEPT_EPOLL_CREATE;
+ TSAN_MAYBE_INTERCEPT_EPOLL_CREATE1;
TSAN_INTERCEPT(close);
- TSAN_INTERCEPT(__close);
- TSAN_INTERCEPT(__res_iclose);
+ TSAN_MAYBE_INTERCEPT___CLOSE;
+ TSAN_MAYBE_INTERCEPT___RES_ICLOSE;
TSAN_INTERCEPT(pipe);
TSAN_INTERCEPT(pipe2);
@@ -2167,19 +2523,17 @@ void InitializeInterceptors() {
TSAN_INTERCEPT(recv);
TSAN_INTERCEPT(unlink);
- TSAN_INTERCEPT(fopen);
- TSAN_INTERCEPT(freopen);
- TSAN_INTERCEPT(fclose);
+ TSAN_INTERCEPT(tmpfile);
+ TSAN_MAYBE_INTERCEPT_TMPFILE64;
TSAN_INTERCEPT(fread);
TSAN_INTERCEPT(fwrite);
- TSAN_INTERCEPT(fflush);
TSAN_INTERCEPT(abort);
TSAN_INTERCEPT(puts);
TSAN_INTERCEPT(rmdir);
TSAN_INTERCEPT(opendir);
- TSAN_INTERCEPT(epoll_ctl);
- TSAN_INTERCEPT(epoll_wait);
+ TSAN_MAYBE_INTERCEPT_EPOLL_CTL;
+ TSAN_MAYBE_INTERCEPT_EPOLL_WAIT;
TSAN_INTERCEPT(sigaction);
TSAN_INTERCEPT(signal);
@@ -2193,14 +2547,8 @@ void InitializeInterceptors() {
TSAN_INTERCEPT(gettimeofday);
TSAN_INTERCEPT(getaddrinfo);
- TSAN_INTERCEPT(mlock);
- TSAN_INTERCEPT(munlock);
- TSAN_INTERCEPT(mlockall);
- TSAN_INTERCEPT(munlockall);
-
TSAN_INTERCEPT(fork);
- TSAN_INTERCEPT(dlopen);
- TSAN_INTERCEPT(dlclose);
+ TSAN_INTERCEPT(vfork);
TSAN_INTERCEPT(on_exit);
TSAN_INTERCEPT(__cxa_atexit);
TSAN_INTERCEPT(_exit);
@@ -2208,9 +2556,6 @@ void InitializeInterceptors() {
// Need to setup it, because interceptors check that the function is resolved.
// But atexit is emitted directly into the module, so can't be resolved.
REAL(atexit) = (int(*)(void(*)()))unreachable;
- atexit_ctx = new(internal_alloc(MBlockAtExit, sizeof(AtExitContext)))
- AtExitContext();
-
if (REAL(__cxa_atexit)(&finalize, 0, 0)) {
Printf("ThreadSanitizer: failed to setup atexit callback\n");
Die();
@@ -2224,16 +2569,19 @@ void InitializeInterceptors() {
FdInit();
}
-void internal_start_thread(void(*func)(void *arg), void *arg) {
- // Start the thread with signals blocked, otherwise it can steal users
- // signals.
- __sanitizer_kernel_sigset_t set, old;
+void *internal_start_thread(void(*func)(void *arg), void *arg) {
+ // Start the thread with signals blocked, otherwise it can steal user signals.
+ __sanitizer_sigset_t set, old;
internal_sigfillset(&set);
internal_sigprocmask(SIG_SETMASK, &set, &old);
void *th;
REAL(pthread_create)(&th, 0, (void*(*)(void *arg))func, arg);
- REAL(pthread_detach)(th);
internal_sigprocmask(SIG_SETMASK, &old, 0);
+ return th;
+}
+
+void internal_join_thread(void *th) {
+ REAL(pthread_join)(th, 0);
}
} // namespace __tsan
diff --git a/lib/tsan/rtl/tsan_interface_ann.cc b/lib/tsan/rtl/tsan_interface_ann.cc
index cacbc0281d0f..fd3c846678f5 100644
--- a/lib/tsan/rtl/tsan_interface_ann.cc
+++ b/lib/tsan/rtl/tsan_interface_ann.cc
@@ -33,33 +33,28 @@ class ScopedAnnotation {
public:
ScopedAnnotation(ThreadState *thr, const char *aname, const char *f, int l,
uptr pc)
- : thr_(thr)
- , in_rtl_(thr->in_rtl) {
- CHECK_EQ(thr_->in_rtl, 0);
+ : thr_(thr) {
FuncEntry(thr_, pc);
- thr_->in_rtl++;
DPrintf("#%d: annotation %s() %s:%d\n", thr_->tid, aname, f, l);
}
~ScopedAnnotation() {
- thr_->in_rtl--;
- CHECK_EQ(in_rtl_, thr_->in_rtl);
FuncExit(thr_);
+ CheckNoLocks(thr_);
}
private:
ThreadState *const thr_;
- const int in_rtl_;
};
#define SCOPED_ANNOTATION(typ) \
if (!flags()->enable_annotations) \
return; \
ThreadState *thr = cur_thread(); \
- const uptr pc = (uptr)__builtin_return_address(0); \
+ const uptr caller_pc = (uptr)__builtin_return_address(0); \
StatInc(thr, StatAnnotation); \
StatInc(thr, Stat##typ); \
- ScopedAnnotation sa(thr, __FUNCTION__, f, l, \
- (uptr)__builtin_return_address(0)); \
+ ScopedAnnotation sa(thr, __func__, f, l, caller_pc); \
+ const uptr pc = StackTrace::GetCurrentPc(); \
(void)pc; \
/**/
@@ -131,8 +126,6 @@ static ExpectRace *FindRace(ExpectRace *list, uptr addr, uptr size) {
static bool CheckContains(ExpectRace *list, uptr addr, uptr size) {
ExpectRace *race = FindRace(list, addr, size);
- if (race == 0 && AlternativeAddress(addr))
- race = FindRace(list, AlternativeAddress(addr), size);
if (race == 0)
return false;
DPrintf("Hit expected/benign race: %s addr=%zx:%d %s:%d\n",
@@ -311,7 +304,7 @@ void INTERFACE_ATTRIBUTE AnnotateFlushExpectedRaces(char *f, int l) {
while (dyn_ann_ctx->expect.next != &dyn_ann_ctx->expect) {
ExpectRace *race = dyn_ann_ctx->expect.next;
if (race->hitcount == 0) {
- CTX()->nmissed_expected++;
+ ctx->nmissed_expected++;
ReportMissedExpectedRace(race);
}
race->prev->next = race->next;
@@ -383,32 +376,32 @@ void INTERFACE_ATTRIBUTE AnnotateBenignRace(
void INTERFACE_ATTRIBUTE AnnotateIgnoreReadsBegin(char *f, int l) {
SCOPED_ANNOTATION(AnnotateIgnoreReadsBegin);
- ThreadIgnoreBegin(thr);
+ ThreadIgnoreBegin(thr, pc);
}
void INTERFACE_ATTRIBUTE AnnotateIgnoreReadsEnd(char *f, int l) {
SCOPED_ANNOTATION(AnnotateIgnoreReadsEnd);
- ThreadIgnoreEnd(thr);
+ ThreadIgnoreEnd(thr, pc);
}
void INTERFACE_ATTRIBUTE AnnotateIgnoreWritesBegin(char *f, int l) {
SCOPED_ANNOTATION(AnnotateIgnoreWritesBegin);
- ThreadIgnoreBegin(thr);
+ ThreadIgnoreBegin(thr, pc);
}
void INTERFACE_ATTRIBUTE AnnotateIgnoreWritesEnd(char *f, int l) {
SCOPED_ANNOTATION(AnnotateIgnoreWritesEnd);
- ThreadIgnoreEnd(thr);
+ ThreadIgnoreEnd(thr, pc);
}
void INTERFACE_ATTRIBUTE AnnotateIgnoreSyncBegin(char *f, int l) {
SCOPED_ANNOTATION(AnnotateIgnoreSyncBegin);
- ThreadIgnoreSyncBegin(thr);
+ ThreadIgnoreSyncBegin(thr, pc);
}
void INTERFACE_ATTRIBUTE AnnotateIgnoreSyncEnd(char *f, int l) {
SCOPED_ANNOTATION(AnnotateIgnoreSyncEnd);
- ThreadIgnoreSyncEnd(thr);
+ ThreadIgnoreSyncEnd(thr, pc);
}
void INTERFACE_ATTRIBUTE AnnotatePublishMemoryRange(
@@ -441,7 +434,7 @@ void INTERFACE_ATTRIBUTE WTFAnnotateHappensAfter(char *f, int l, uptr addr) {
void INTERFACE_ATTRIBUTE WTFAnnotateBenignRaceSized(
char *f, int l, uptr mem, uptr sz, char *desc) {
SCOPED_ANNOTATION(AnnotateBenignRaceSized);
- BenignRaceImpl(f, l, mem, 1, desc);
+ BenignRaceImpl(f, l, mem, sz, desc);
}
int INTERFACE_ATTRIBUTE RunningOnValgrind() {
@@ -461,4 +454,6 @@ const char INTERFACE_ATTRIBUTE* ThreadSanitizerQuery(const char *query) {
void INTERFACE_ATTRIBUTE
AnnotateMemoryIsInitialized(char *f, int l, uptr mem, uptr sz) {}
+void INTERFACE_ATTRIBUTE
+AnnotateMemoryIsUninitialized(char *f, int l, uptr mem, uptr sz) {}
} // extern "C"
diff --git a/lib/tsan/rtl/tsan_interface_atomic.cc b/lib/tsan/rtl/tsan_interface_atomic.cc
index d9f8cdf5b106..9b699511674a 100644
--- a/lib/tsan/rtl/tsan_interface_atomic.cc
+++ b/lib/tsan/rtl/tsan_interface_atomic.cc
@@ -12,7 +12,7 @@
//===----------------------------------------------------------------------===//
// ThreadSanitizer atomic operations are based on C++11/C1x standards.
-// For background see C++11 standard. A slightly older, publically
+// For background see C++11 standard. A slightly older, publicly
// available draft of the standard (not entirely up-to-date, but close enough
// for casual browsing) is available here:
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3242.pdf
@@ -21,72 +21,40 @@
#include "sanitizer_common/sanitizer_placement_new.h"
#include "sanitizer_common/sanitizer_stacktrace.h"
-#include "tsan_interface_atomic.h"
+#include "sanitizer_common/sanitizer_mutex.h"
#include "tsan_flags.h"
#include "tsan_rtl.h"
using namespace __tsan; // NOLINT
-#define SCOPED_ATOMIC(func, ...) \
- const uptr callpc = (uptr)__builtin_return_address(0); \
- uptr pc = __sanitizer::StackTrace::GetCurrentPc(); \
- mo = ConvertOrder(mo); \
- mo = flags()->force_seq_cst_atomics ? (morder)mo_seq_cst : mo; \
- ThreadState *const thr = cur_thread(); \
- AtomicStatInc(thr, sizeof(*a), mo, StatAtomic##func); \
- ScopedAtomic sa(thr, callpc, a, mo, __FUNCTION__); \
- return Atomic##func(thr, pc, __VA_ARGS__); \
-/**/
-
-// Some shortcuts.
-typedef __tsan_memory_order morder;
-typedef __tsan_atomic8 a8;
-typedef __tsan_atomic16 a16;
-typedef __tsan_atomic32 a32;
-typedef __tsan_atomic64 a64;
-typedef __tsan_atomic128 a128;
-const morder mo_relaxed = __tsan_memory_order_relaxed;
-const morder mo_consume = __tsan_memory_order_consume;
-const morder mo_acquire = __tsan_memory_order_acquire;
-const morder mo_release = __tsan_memory_order_release;
-const morder mo_acq_rel = __tsan_memory_order_acq_rel;
-const morder mo_seq_cst = __tsan_memory_order_seq_cst;
+// These should match declarations from public tsan_interface_atomic.h header.
+typedef unsigned char a8;
+typedef unsigned short a16; // NOLINT
+typedef unsigned int a32;
+typedef unsigned long long a64; // NOLINT
+#if !defined(SANITIZER_GO) && (defined(__SIZEOF_INT128__) \
+ || (__clang_major__ * 100 + __clang_minor__ >= 302))
+__extension__ typedef __int128 a128;
+# define __TSAN_HAS_INT128 1
+#else
+# define __TSAN_HAS_INT128 0
+#endif
-class ScopedAtomic {
- public:
- ScopedAtomic(ThreadState *thr, uptr pc, const volatile void *a,
- morder mo, const char *func)
- : thr_(thr) {
- CHECK_EQ(thr_->in_rtl, 0);
- ProcessPendingSignals(thr);
- FuncEntry(thr_, pc);
- DPrintf("#%d: %s(%p, %d)\n", thr_->tid, func, a, mo);
- thr_->in_rtl++;
- }
- ~ScopedAtomic() {
- thr_->in_rtl--;
- CHECK_EQ(thr_->in_rtl, 0);
- FuncExit(thr_);
- }
- private:
- ThreadState *thr_;
-};
+#ifndef SANITIZER_GO
+// Protects emulation of 128-bit atomic operations.
+static StaticSpinMutex mutex128;
+#endif
-static void AtomicStatInc(ThreadState *thr, uptr size, morder mo, StatType t) {
- StatInc(thr, StatAtomic);
- StatInc(thr, t);
- StatInc(thr, size == 1 ? StatAtomic1
- : size == 2 ? StatAtomic2
- : size == 4 ? StatAtomic4
- : size == 8 ? StatAtomic8
- : StatAtomic16);
- StatInc(thr, mo == mo_relaxed ? StatAtomicRelaxed
- : mo == mo_consume ? StatAtomicConsume
- : mo == mo_acquire ? StatAtomicAcquire
- : mo == mo_release ? StatAtomicRelease
- : mo == mo_acq_rel ? StatAtomicAcq_Rel
- : StatAtomicSeq_Cst);
-}
+// Part of ABI, do not change.
+// http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/atomic?view=markup
+typedef enum {
+ mo_relaxed,
+ mo_consume,
+ mo_acquire,
+ mo_release,
+ mo_acq_rel,
+ mo_seq_cst
+} morder;
static bool IsLoadOrder(morder mo) {
return mo == mo_relaxed || mo == mo_consume
@@ -110,27 +78,6 @@ static bool IsAcqRelOrder(morder mo) {
return mo == mo_acq_rel || mo == mo_seq_cst;
}
-static morder ConvertOrder(morder mo) {
- if (mo > (morder)100500) {
- mo = morder(mo - 100500);
- if (mo == morder(1 << 0))
- mo = mo_relaxed;
- else if (mo == morder(1 << 1))
- mo = mo_consume;
- else if (mo == morder(1 << 2))
- mo = mo_acquire;
- else if (mo == morder(1 << 3))
- mo = mo_release;
- else if (mo == morder(1 << 4))
- mo = mo_acq_rel;
- else if (mo == morder(1 << 5))
- mo = mo_seq_cst;
- }
- CHECK_GE(mo, mo_relaxed);
- CHECK_LE(mo, mo_seq_cst);
- return mo;
-}
-
template<typename T> T func_xchg(volatile T *v, T op) {
T res = __sync_lock_test_and_set(v, op);
// __sync_lock_test_and_set does not contain full barrier.
@@ -178,50 +125,58 @@ template<typename T> T func_cas(volatile T *v, T cmp, T xch) {
// Atomic ops are executed under tsan internal mutex,
// here we assume that the atomic variables are not accessed
// from non-instrumented code.
-#ifndef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_16
+#if !defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16) && !defined(SANITIZER_GO)
a128 func_xchg(volatile a128 *v, a128 op) {
+ SpinMutexLock lock(&mutex128);
a128 cmp = *v;
*v = op;
return cmp;
}
a128 func_add(volatile a128 *v, a128 op) {
+ SpinMutexLock lock(&mutex128);
a128 cmp = *v;
*v = cmp + op;
return cmp;
}
a128 func_sub(volatile a128 *v, a128 op) {
+ SpinMutexLock lock(&mutex128);
a128 cmp = *v;
*v = cmp - op;
return cmp;
}
a128 func_and(volatile a128 *v, a128 op) {
+ SpinMutexLock lock(&mutex128);
a128 cmp = *v;
*v = cmp & op;
return cmp;
}
a128 func_or(volatile a128 *v, a128 op) {
+ SpinMutexLock lock(&mutex128);
a128 cmp = *v;
*v = cmp | op;
return cmp;
}
a128 func_xor(volatile a128 *v, a128 op) {
+ SpinMutexLock lock(&mutex128);
a128 cmp = *v;
*v = cmp ^ op;
return cmp;
}
a128 func_nand(volatile a128 *v, a128 op) {
+ SpinMutexLock lock(&mutex128);
a128 cmp = *v;
*v = ~(cmp & op);
return cmp;
}
a128 func_cas(volatile a128 *v, a128 cmp, a128 xch) {
+ SpinMutexLock lock(&mutex128);
a128 cur = *v;
if (cur == cmp)
*v = xch;
@@ -243,26 +198,80 @@ static int SizeLog() {
// this leads to false negatives only in very obscure cases.
}
+#ifndef SANITIZER_GO
+static atomic_uint8_t *to_atomic(const volatile a8 *a) {
+ return reinterpret_cast<atomic_uint8_t *>(const_cast<a8 *>(a));
+}
+
+static atomic_uint16_t *to_atomic(const volatile a16 *a) {
+ return reinterpret_cast<atomic_uint16_t *>(const_cast<a16 *>(a));
+}
+#endif
+
+static atomic_uint32_t *to_atomic(const volatile a32 *a) {
+ return reinterpret_cast<atomic_uint32_t *>(const_cast<a32 *>(a));
+}
+
+static atomic_uint64_t *to_atomic(const volatile a64 *a) {
+ return reinterpret_cast<atomic_uint64_t *>(const_cast<a64 *>(a));
+}
+
+static memory_order to_mo(morder mo) {
+ switch (mo) {
+ case mo_relaxed: return memory_order_relaxed;
+ case mo_consume: return memory_order_consume;
+ case mo_acquire: return memory_order_acquire;
+ case mo_release: return memory_order_release;
+ case mo_acq_rel: return memory_order_acq_rel;
+ case mo_seq_cst: return memory_order_seq_cst;
+ }
+ CHECK(0);
+ return memory_order_seq_cst;
+}
+
+template<typename T>
+static T NoTsanAtomicLoad(const volatile T *a, morder mo) {
+ return atomic_load(to_atomic(a), to_mo(mo));
+}
+
+#if __TSAN_HAS_INT128 && !defined(SANITIZER_GO)
+static a128 NoTsanAtomicLoad(const volatile a128 *a, morder mo) {
+ SpinMutexLock lock(&mutex128);
+ return *a;
+}
+#endif
+
template<typename T>
static T AtomicLoad(ThreadState *thr, uptr pc, const volatile T *a,
morder mo) {
CHECK(IsLoadOrder(mo));
// This fast-path is critical for performance.
// Assume the access is atomic.
- if (!IsAcquireOrder(mo) && sizeof(T) <= sizeof(a)) {
+ if (!IsAcquireOrder(mo)) {
MemoryReadAtomic(thr, pc, (uptr)a, SizeLog<T>());
- return *a; // as if atomic
+ return NoTsanAtomicLoad(a, mo);
}
- SyncVar *s = CTX()->synctab.GetOrCreateAndLock(thr, pc, (uptr)a, false);
+ SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, (uptr)a, false);
AcquireImpl(thr, pc, &s->clock);
- T v = *a;
+ T v = NoTsanAtomicLoad(a, mo);
s->mtx.ReadUnlock();
- __sync_synchronize();
MemoryReadAtomic(thr, pc, (uptr)a, SizeLog<T>());
return v;
}
template<typename T>
+static void NoTsanAtomicStore(volatile T *a, T v, morder mo) {
+ atomic_store(to_atomic(a), v, to_mo(mo));
+}
+
+#if __TSAN_HAS_INT128 && !defined(SANITIZER_GO)
+static void NoTsanAtomicStore(volatile a128 *a, a128 v, morder mo) {
+ SpinMutexLock lock(&mutex128);
+ *a = v;
+}
+#endif
+
+template<typename T>
static void AtomicStore(ThreadState *thr, uptr pc, volatile T *a, T v,
morder mo) {
CHECK(IsStoreOrder(mo));
@@ -271,21 +280,18 @@ static void AtomicStore(ThreadState *thr, uptr pc, volatile T *a, T v,
// Assume the access is atomic.
// Strictly saying even relaxed store cuts off release sequence,
// so must reset the clock.
- if (!IsReleaseOrder(mo) && sizeof(T) <= sizeof(a)) {
- *a = v; // as if atomic
+ if (!IsReleaseOrder(mo)) {
+ NoTsanAtomicStore(a, v, mo);
return;
}
__sync_synchronize();
- SyncVar *s = CTX()->synctab.GetOrCreateAndLock(thr, pc, (uptr)a, true);
+ SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, (uptr)a, true);
thr->fast_state.IncrementEpoch();
// Can't increment epoch w/o writing to the trace as well.
TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0);
ReleaseImpl(thr, pc, &s->clock);
- *a = v;
+ NoTsanAtomicStore(a, v, mo);
s->mtx.Unlock();
- // Trainling memory barrier to provide sequential consistency
- // for Dekker-like store-load synchronization.
- __sync_synchronize();
}
template<typename T, T (*F)(volatile T *v, T op)>
@@ -293,7 +299,7 @@ static T AtomicRMW(ThreadState *thr, uptr pc, volatile T *a, T v, morder mo) {
MemoryWriteAtomic(thr, pc, (uptr)a, SizeLog<T>());
SyncVar *s = 0;
if (mo != mo_relaxed) {
- s = CTX()->synctab.GetOrCreateAndLock(thr, pc, (uptr)a, true);
+ s = ctx->metamap.GetOrCreateAndLock(thr, pc, (uptr)a, true);
thr->fast_state.IncrementEpoch();
// Can't increment epoch w/o writing to the trace as well.
TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0);
@@ -311,6 +317,41 @@ static T AtomicRMW(ThreadState *thr, uptr pc, volatile T *a, T v, morder mo) {
}
template<typename T>
+static T NoTsanAtomicExchange(volatile T *a, T v, morder mo) {
+ return func_xchg(a, v);
+}
+
+template<typename T>
+static T NoTsanAtomicFetchAdd(volatile T *a, T v, morder mo) {
+ return func_add(a, v);
+}
+
+template<typename T>
+static T NoTsanAtomicFetchSub(volatile T *a, T v, morder mo) {
+ return func_sub(a, v);
+}
+
+template<typename T>
+static T NoTsanAtomicFetchAnd(volatile T *a, T v, morder mo) {
+ return func_and(a, v);
+}
+
+template<typename T>
+static T NoTsanAtomicFetchOr(volatile T *a, T v, morder mo) {
+ return func_or(a, v);
+}
+
+template<typename T>
+static T NoTsanAtomicFetchXor(volatile T *a, T v, morder mo) {
+ return func_xor(a, v);
+}
+
+template<typename T>
+static T NoTsanAtomicFetchNand(volatile T *a, T v, morder mo) {
+ return func_nand(a, v);
+}
+
+template<typename T>
static T AtomicExchange(ThreadState *thr, uptr pc, volatile T *a, T v,
morder mo) {
return AtomicRMW<T, func_xchg>(thr, pc, a, v, mo);
@@ -353,13 +394,37 @@ static T AtomicFetchNand(ThreadState *thr, uptr pc, volatile T *a, T v,
}
template<typename T>
+static bool NoTsanAtomicCAS(volatile T *a, T *c, T v, morder mo, morder fmo) {
+ return atomic_compare_exchange_strong(to_atomic(a), c, v, to_mo(mo));
+}
+
+#if __TSAN_HAS_INT128
+static bool NoTsanAtomicCAS(volatile a128 *a, a128 *c, a128 v,
+ morder mo, morder fmo) {
+ a128 old = *c;
+ a128 cur = func_cas(a, old, v);
+ if (cur == old)
+ return true;
+ *c = cur;
+ return false;
+}
+#endif
+
+template<typename T>
+static T NoTsanAtomicCAS(volatile T *a, T c, T v, morder mo, morder fmo) {
+ NoTsanAtomicCAS(a, &c, v, mo, fmo);
+ return c;
+}
+
+template<typename T>
static bool AtomicCAS(ThreadState *thr, uptr pc,
volatile T *a, T *c, T v, morder mo, morder fmo) {
(void)fmo; // Unused because llvm does not pass it yet.
MemoryWriteAtomic(thr, pc, (uptr)a, SizeLog<T>());
SyncVar *s = 0;
+ bool write_lock = mo != mo_acquire && mo != mo_consume;
if (mo != mo_relaxed) {
- s = CTX()->synctab.GetOrCreateAndLock(thr, pc, (uptr)a, true);
+ s = ctx->metamap.GetOrCreateAndLock(thr, pc, (uptr)a, write_lock);
thr->fast_state.IncrementEpoch();
// Can't increment epoch w/o writing to the trace as well.
TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0);
@@ -372,8 +437,12 @@ static bool AtomicCAS(ThreadState *thr, uptr pc,
}
T cc = *c;
T pr = func_cas(a, cc, v);
- if (s)
- s->mtx.Unlock();
+ if (s) {
+ if (write_lock)
+ s->mtx.Unlock();
+ else
+ s->mtx.ReadUnlock();
+ }
if (pr == cc)
return true;
*c = pr;
@@ -387,293 +456,498 @@ static T AtomicCAS(ThreadState *thr, uptr pc,
return c;
}
+#ifndef SANITIZER_GO
+static void NoTsanAtomicFence(morder mo) {
+ __sync_synchronize();
+}
+
static void AtomicFence(ThreadState *thr, uptr pc, morder mo) {
// FIXME(dvyukov): not implemented.
__sync_synchronize();
}
+#endif
+
+// Interface functions follow.
+#ifndef SANITIZER_GO
+
+// C/C++
+
+#define SCOPED_ATOMIC(func, ...) \
+ const uptr callpc = (uptr)__builtin_return_address(0); \
+ uptr pc = StackTrace::GetCurrentPc(); \
+ mo = flags()->force_seq_cst_atomics ? (morder)mo_seq_cst : mo; \
+ ThreadState *const thr = cur_thread(); \
+ if (thr->ignore_interceptors) \
+ return NoTsanAtomic##func(__VA_ARGS__); \
+ AtomicStatInc(thr, sizeof(*a), mo, StatAtomic##func); \
+ ScopedAtomic sa(thr, callpc, a, mo, __func__); \
+ return Atomic##func(thr, pc, __VA_ARGS__); \
+/**/
+
+class ScopedAtomic {
+ public:
+ ScopedAtomic(ThreadState *thr, uptr pc, const volatile void *a,
+ morder mo, const char *func)
+ : thr_(thr) {
+ FuncEntry(thr_, pc);
+ DPrintf("#%d: %s(%p, %d)\n", thr_->tid, func, a, mo);
+ }
+ ~ScopedAtomic() {
+ ProcessPendingSignals(thr_);
+ FuncExit(thr_);
+ }
+ private:
+ ThreadState *thr_;
+};
+
+static void AtomicStatInc(ThreadState *thr, uptr size, morder mo, StatType t) {
+ StatInc(thr, StatAtomic);
+ StatInc(thr, t);
+ StatInc(thr, size == 1 ? StatAtomic1
+ : size == 2 ? StatAtomic2
+ : size == 4 ? StatAtomic4
+ : size == 8 ? StatAtomic8
+ : StatAtomic16);
+ StatInc(thr, mo == mo_relaxed ? StatAtomicRelaxed
+ : mo == mo_consume ? StatAtomicConsume
+ : mo == mo_acquire ? StatAtomicAcquire
+ : mo == mo_release ? StatAtomicRelease
+ : mo == mo_acq_rel ? StatAtomicAcq_Rel
+ : StatAtomicSeq_Cst);
+}
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE
a8 __tsan_atomic8_load(const volatile a8 *a, morder mo) {
SCOPED_ATOMIC(Load, a, mo);
}
+SANITIZER_INTERFACE_ATTRIBUTE
a16 __tsan_atomic16_load(const volatile a16 *a, morder mo) {
SCOPED_ATOMIC(Load, a, mo);
}
+SANITIZER_INTERFACE_ATTRIBUTE
a32 __tsan_atomic32_load(const volatile a32 *a, morder mo) {
SCOPED_ATOMIC(Load, a, mo);
}
+SANITIZER_INTERFACE_ATTRIBUTE
a64 __tsan_atomic64_load(const volatile a64 *a, morder mo) {
SCOPED_ATOMIC(Load, a, mo);
}
#if __TSAN_HAS_INT128
+SANITIZER_INTERFACE_ATTRIBUTE
a128 __tsan_atomic128_load(const volatile a128 *a, morder mo) {
SCOPED_ATOMIC(Load, a, mo);
}
#endif
+SANITIZER_INTERFACE_ATTRIBUTE
void __tsan_atomic8_store(volatile a8 *a, a8 v, morder mo) {
SCOPED_ATOMIC(Store, a, v, mo);
}
+SANITIZER_INTERFACE_ATTRIBUTE
void __tsan_atomic16_store(volatile a16 *a, a16 v, morder mo) {
SCOPED_ATOMIC(Store, a, v, mo);
}
+SANITIZER_INTERFACE_ATTRIBUTE
void __tsan_atomic32_store(volatile a32 *a, a32 v, morder mo) {
SCOPED_ATOMIC(Store, a, v, mo);
}
+SANITIZER_INTERFACE_ATTRIBUTE
void __tsan_atomic64_store(volatile a64 *a, a64 v, morder mo) {
SCOPED_ATOMIC(Store, a, v, mo);
}
#if __TSAN_HAS_INT128
+SANITIZER_INTERFACE_ATTRIBUTE
void __tsan_atomic128_store(volatile a128 *a, a128 v, morder mo) {
SCOPED_ATOMIC(Store, a, v, mo);
}
#endif
+SANITIZER_INTERFACE_ATTRIBUTE
a8 __tsan_atomic8_exchange(volatile a8 *a, a8 v, morder mo) {
SCOPED_ATOMIC(Exchange, a, v, mo);
}
+SANITIZER_INTERFACE_ATTRIBUTE
a16 __tsan_atomic16_exchange(volatile a16 *a, a16 v, morder mo) {
SCOPED_ATOMIC(Exchange, a, v, mo);
}
+SANITIZER_INTERFACE_ATTRIBUTE
a32 __tsan_atomic32_exchange(volatile a32 *a, a32 v, morder mo) {
SCOPED_ATOMIC(Exchange, a, v, mo);
}
+SANITIZER_INTERFACE_ATTRIBUTE
a64 __tsan_atomic64_exchange(volatile a64 *a, a64 v, morder mo) {
SCOPED_ATOMIC(Exchange, a, v, mo);
}
#if __TSAN_HAS_INT128
+SANITIZER_INTERFACE_ATTRIBUTE
a128 __tsan_atomic128_exchange(volatile a128 *a, a128 v, morder mo) {
SCOPED_ATOMIC(Exchange, a, v, mo);
}
#endif
+SANITIZER_INTERFACE_ATTRIBUTE
a8 __tsan_atomic8_fetch_add(volatile a8 *a, a8 v, morder mo) {
SCOPED_ATOMIC(FetchAdd, a, v, mo);
}
+SANITIZER_INTERFACE_ATTRIBUTE
a16 __tsan_atomic16_fetch_add(volatile a16 *a, a16 v, morder mo) {
SCOPED_ATOMIC(FetchAdd, a, v, mo);
}
+SANITIZER_INTERFACE_ATTRIBUTE
a32 __tsan_atomic32_fetch_add(volatile a32 *a, a32 v, morder mo) {
SCOPED_ATOMIC(FetchAdd, a, v, mo);
}
+SANITIZER_INTERFACE_ATTRIBUTE
a64 __tsan_atomic64_fetch_add(volatile a64 *a, a64 v, morder mo) {
SCOPED_ATOMIC(FetchAdd, a, v, mo);
}
#if __TSAN_HAS_INT128
+SANITIZER_INTERFACE_ATTRIBUTE
a128 __tsan_atomic128_fetch_add(volatile a128 *a, a128 v, morder mo) {
SCOPED_ATOMIC(FetchAdd, a, v, mo);
}
#endif
+SANITIZER_INTERFACE_ATTRIBUTE
a8 __tsan_atomic8_fetch_sub(volatile a8 *a, a8 v, morder mo) {
SCOPED_ATOMIC(FetchSub, a, v, mo);
}
+SANITIZER_INTERFACE_ATTRIBUTE
a16 __tsan_atomic16_fetch_sub(volatile a16 *a, a16 v, morder mo) {
SCOPED_ATOMIC(FetchSub, a, v, mo);
}
+SANITIZER_INTERFACE_ATTRIBUTE
a32 __tsan_atomic32_fetch_sub(volatile a32 *a, a32 v, morder mo) {
SCOPED_ATOMIC(FetchSub, a, v, mo);
}
+SANITIZER_INTERFACE_ATTRIBUTE
a64 __tsan_atomic64_fetch_sub(volatile a64 *a, a64 v, morder mo) {
SCOPED_ATOMIC(FetchSub, a, v, mo);
}
#if __TSAN_HAS_INT128
+SANITIZER_INTERFACE_ATTRIBUTE
a128 __tsan_atomic128_fetch_sub(volatile a128 *a, a128 v, morder mo) {
SCOPED_ATOMIC(FetchSub, a, v, mo);
}
#endif
+SANITIZER_INTERFACE_ATTRIBUTE
a8 __tsan_atomic8_fetch_and(volatile a8 *a, a8 v, morder mo) {
SCOPED_ATOMIC(FetchAnd, a, v, mo);
}
+SANITIZER_INTERFACE_ATTRIBUTE
a16 __tsan_atomic16_fetch_and(volatile a16 *a, a16 v, morder mo) {
SCOPED_ATOMIC(FetchAnd, a, v, mo);
}
+SANITIZER_INTERFACE_ATTRIBUTE
a32 __tsan_atomic32_fetch_and(volatile a32 *a, a32 v, morder mo) {
SCOPED_ATOMIC(FetchAnd, a, v, mo);
}
+SANITIZER_INTERFACE_ATTRIBUTE
a64 __tsan_atomic64_fetch_and(volatile a64 *a, a64 v, morder mo) {
SCOPED_ATOMIC(FetchAnd, a, v, mo);
}
#if __TSAN_HAS_INT128
+SANITIZER_INTERFACE_ATTRIBUTE
a128 __tsan_atomic128_fetch_and(volatile a128 *a, a128 v, morder mo) {
SCOPED_ATOMIC(FetchAnd, a, v, mo);
}
#endif
+SANITIZER_INTERFACE_ATTRIBUTE
a8 __tsan_atomic8_fetch_or(volatile a8 *a, a8 v, morder mo) {
SCOPED_ATOMIC(FetchOr, a, v, mo);
}
+SANITIZER_INTERFACE_ATTRIBUTE
a16 __tsan_atomic16_fetch_or(volatile a16 *a, a16 v, morder mo) {
SCOPED_ATOMIC(FetchOr, a, v, mo);
}
+SANITIZER_INTERFACE_ATTRIBUTE
a32 __tsan_atomic32_fetch_or(volatile a32 *a, a32 v, morder mo) {
SCOPED_ATOMIC(FetchOr, a, v, mo);
}
+SANITIZER_INTERFACE_ATTRIBUTE
a64 __tsan_atomic64_fetch_or(volatile a64 *a, a64 v, morder mo) {
SCOPED_ATOMIC(FetchOr, a, v, mo);
}
#if __TSAN_HAS_INT128
+SANITIZER_INTERFACE_ATTRIBUTE
a128 __tsan_atomic128_fetch_or(volatile a128 *a, a128 v, morder mo) {
SCOPED_ATOMIC(FetchOr, a, v, mo);
}
#endif
+SANITIZER_INTERFACE_ATTRIBUTE
a8 __tsan_atomic8_fetch_xor(volatile a8 *a, a8 v, morder mo) {
SCOPED_ATOMIC(FetchXor, a, v, mo);
}
+SANITIZER_INTERFACE_ATTRIBUTE
a16 __tsan_atomic16_fetch_xor(volatile a16 *a, a16 v, morder mo) {
SCOPED_ATOMIC(FetchXor, a, v, mo);
}
+SANITIZER_INTERFACE_ATTRIBUTE
a32 __tsan_atomic32_fetch_xor(volatile a32 *a, a32 v, morder mo) {
SCOPED_ATOMIC(FetchXor, a, v, mo);
}
+SANITIZER_INTERFACE_ATTRIBUTE
a64 __tsan_atomic64_fetch_xor(volatile a64 *a, a64 v, morder mo) {
SCOPED_ATOMIC(FetchXor, a, v, mo);
}
#if __TSAN_HAS_INT128
+SANITIZER_INTERFACE_ATTRIBUTE
a128 __tsan_atomic128_fetch_xor(volatile a128 *a, a128 v, morder mo) {
SCOPED_ATOMIC(FetchXor, a, v, mo);
}
#endif
+SANITIZER_INTERFACE_ATTRIBUTE
a8 __tsan_atomic8_fetch_nand(volatile a8 *a, a8 v, morder mo) {
SCOPED_ATOMIC(FetchNand, a, v, mo);
}
+SANITIZER_INTERFACE_ATTRIBUTE
a16 __tsan_atomic16_fetch_nand(volatile a16 *a, a16 v, morder mo) {
SCOPED_ATOMIC(FetchNand, a, v, mo);
}
+SANITIZER_INTERFACE_ATTRIBUTE
a32 __tsan_atomic32_fetch_nand(volatile a32 *a, a32 v, morder mo) {
SCOPED_ATOMIC(FetchNand, a, v, mo);
}
+SANITIZER_INTERFACE_ATTRIBUTE
a64 __tsan_atomic64_fetch_nand(volatile a64 *a, a64 v, morder mo) {
SCOPED_ATOMIC(FetchNand, a, v, mo);
}
#if __TSAN_HAS_INT128
+SANITIZER_INTERFACE_ATTRIBUTE
a128 __tsan_atomic128_fetch_nand(volatile a128 *a, a128 v, morder mo) {
SCOPED_ATOMIC(FetchNand, a, v, mo);
}
#endif
+SANITIZER_INTERFACE_ATTRIBUTE
int __tsan_atomic8_compare_exchange_strong(volatile a8 *a, a8 *c, a8 v,
morder mo, morder fmo) {
SCOPED_ATOMIC(CAS, a, c, v, mo, fmo);
}
+SANITIZER_INTERFACE_ATTRIBUTE
int __tsan_atomic16_compare_exchange_strong(volatile a16 *a, a16 *c, a16 v,
morder mo, morder fmo) {
SCOPED_ATOMIC(CAS, a, c, v, mo, fmo);
}
+SANITIZER_INTERFACE_ATTRIBUTE
int __tsan_atomic32_compare_exchange_strong(volatile a32 *a, a32 *c, a32 v,
morder mo, morder fmo) {
SCOPED_ATOMIC(CAS, a, c, v, mo, fmo);
}
+SANITIZER_INTERFACE_ATTRIBUTE
int __tsan_atomic64_compare_exchange_strong(volatile a64 *a, a64 *c, a64 v,
morder mo, morder fmo) {
SCOPED_ATOMIC(CAS, a, c, v, mo, fmo);
}
#if __TSAN_HAS_INT128
+SANITIZER_INTERFACE_ATTRIBUTE
int __tsan_atomic128_compare_exchange_strong(volatile a128 *a, a128 *c, a128 v,
morder mo, morder fmo) {
SCOPED_ATOMIC(CAS, a, c, v, mo, fmo);
}
#endif
+SANITIZER_INTERFACE_ATTRIBUTE
int __tsan_atomic8_compare_exchange_weak(volatile a8 *a, a8 *c, a8 v,
morder mo, morder fmo) {
SCOPED_ATOMIC(CAS, a, c, v, mo, fmo);
}
+SANITIZER_INTERFACE_ATTRIBUTE
int __tsan_atomic16_compare_exchange_weak(volatile a16 *a, a16 *c, a16 v,
morder mo, morder fmo) {
SCOPED_ATOMIC(CAS, a, c, v, mo, fmo);
}
+SANITIZER_INTERFACE_ATTRIBUTE
int __tsan_atomic32_compare_exchange_weak(volatile a32 *a, a32 *c, a32 v,
morder mo, morder fmo) {
SCOPED_ATOMIC(CAS, a, c, v, mo, fmo);
}
+SANITIZER_INTERFACE_ATTRIBUTE
int __tsan_atomic64_compare_exchange_weak(volatile a64 *a, a64 *c, a64 v,
morder mo, morder fmo) {
SCOPED_ATOMIC(CAS, a, c, v, mo, fmo);
}
#if __TSAN_HAS_INT128
+SANITIZER_INTERFACE_ATTRIBUTE
int __tsan_atomic128_compare_exchange_weak(volatile a128 *a, a128 *c, a128 v,
morder mo, morder fmo) {
SCOPED_ATOMIC(CAS, a, c, v, mo, fmo);
}
#endif
+SANITIZER_INTERFACE_ATTRIBUTE
a8 __tsan_atomic8_compare_exchange_val(volatile a8 *a, a8 c, a8 v,
morder mo, morder fmo) {
SCOPED_ATOMIC(CAS, a, c, v, mo, fmo);
}
+
+SANITIZER_INTERFACE_ATTRIBUTE
a16 __tsan_atomic16_compare_exchange_val(volatile a16 *a, a16 c, a16 v,
morder mo, morder fmo) {
SCOPED_ATOMIC(CAS, a, c, v, mo, fmo);
}
+SANITIZER_INTERFACE_ATTRIBUTE
a32 __tsan_atomic32_compare_exchange_val(volatile a32 *a, a32 c, a32 v,
morder mo, morder fmo) {
SCOPED_ATOMIC(CAS, a, c, v, mo, fmo);
}
+SANITIZER_INTERFACE_ATTRIBUTE
a64 __tsan_atomic64_compare_exchange_val(volatile a64 *a, a64 c, a64 v,
morder mo, morder fmo) {
SCOPED_ATOMIC(CAS, a, c, v, mo, fmo);
}
#if __TSAN_HAS_INT128
+SANITIZER_INTERFACE_ATTRIBUTE
a128 __tsan_atomic128_compare_exchange_val(volatile a128 *a, a128 c, a128 v,
morder mo, morder fmo) {
SCOPED_ATOMIC(CAS, a, c, v, mo, fmo);
}
#endif
+SANITIZER_INTERFACE_ATTRIBUTE
void __tsan_atomic_thread_fence(morder mo) {
char* a = 0;
SCOPED_ATOMIC(Fence, mo);
}
+SANITIZER_INTERFACE_ATTRIBUTE
void __tsan_atomic_signal_fence(morder mo) {
}
+} // extern "C"
+
+#else // #ifndef SANITIZER_GO
+
+// Go
+
+#define ATOMIC(func, ...) \
+ if (thr->ignore_sync) { \
+ NoTsanAtomic##func(__VA_ARGS__); \
+ } else { \
+ FuncEntry(thr, cpc); \
+ Atomic##func(thr, pc, __VA_ARGS__); \
+ FuncExit(thr); \
+ } \
+/**/
+
+#define ATOMIC_RET(func, ret, ...) \
+ if (thr->ignore_sync) { \
+ (ret) = NoTsanAtomic##func(__VA_ARGS__); \
+ } else { \
+ FuncEntry(thr, cpc); \
+ (ret) = Atomic##func(thr, pc, __VA_ARGS__); \
+ FuncExit(thr); \
+ } \
+/**/
+
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_go_atomic32_load(ThreadState *thr, uptr cpc, uptr pc, u8 *a) {
+ ATOMIC_RET(Load, *(a32*)(a+8), *(a32**)a, mo_acquire);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_go_atomic64_load(ThreadState *thr, uptr cpc, uptr pc, u8 *a) {
+ ATOMIC_RET(Load, *(a64*)(a+8), *(a64**)a, mo_acquire);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_go_atomic32_store(ThreadState *thr, uptr cpc, uptr pc, u8 *a) {
+ ATOMIC(Store, *(a32**)a, *(a32*)(a+8), mo_release);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_go_atomic64_store(ThreadState *thr, uptr cpc, uptr pc, u8 *a) {
+ ATOMIC(Store, *(a64**)a, *(a64*)(a+8), mo_release);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_go_atomic32_fetch_add(ThreadState *thr, uptr cpc, uptr pc, u8 *a) {
+ ATOMIC_RET(FetchAdd, *(a32*)(a+16), *(a32**)a, *(a32*)(a+8), mo_acq_rel);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_go_atomic64_fetch_add(ThreadState *thr, uptr cpc, uptr pc, u8 *a) {
+ ATOMIC_RET(FetchAdd, *(a64*)(a+16), *(a64**)a, *(a64*)(a+8), mo_acq_rel);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_go_atomic32_exchange(ThreadState *thr, uptr cpc, uptr pc, u8 *a) {
+ ATOMIC_RET(Exchange, *(a32*)(a+16), *(a32**)a, *(a32*)(a+8), mo_acq_rel);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_go_atomic64_exchange(ThreadState *thr, uptr cpc, uptr pc, u8 *a) {
+ ATOMIC_RET(Exchange, *(a64*)(a+16), *(a64**)a, *(a64*)(a+8), mo_acq_rel);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_go_atomic32_compare_exchange(
+ ThreadState *thr, uptr cpc, uptr pc, u8 *a) {
+ a32 cur = 0;
+ a32 cmp = *(a32*)(a+8);
+ ATOMIC_RET(CAS, cur, *(a32**)a, cmp, *(a32*)(a+12), mo_acq_rel, mo_acquire);
+ *(bool*)(a+16) = (cur == cmp);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_go_atomic64_compare_exchange(
+ ThreadState *thr, uptr cpc, uptr pc, u8 *a) {
+ a64 cur = 0;
+ a64 cmp = *(a64*)(a+8);
+ ATOMIC_RET(CAS, cur, *(a64**)a, cmp, *(a64*)(a+16), mo_acq_rel, mo_acquire);
+ *(bool*)(a+24) = (cur == cmp);
+}
+} // extern "C"
+#endif // #ifndef SANITIZER_GO
diff --git a/lib/tsan/rtl/tsan_interface_atomic.h b/lib/tsan/rtl/tsan_interface_atomic.h
deleted file mode 100644
index 5352d56679f7..000000000000
--- a/lib/tsan/rtl/tsan_interface_atomic.h
+++ /dev/null
@@ -1,205 +0,0 @@
-//===-- tsan_interface_atomic.h ---------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file is a part of ThreadSanitizer (TSan), a race detector.
-//
-//===----------------------------------------------------------------------===//
-#ifndef TSAN_INTERFACE_ATOMIC_H
-#define TSAN_INTERFACE_ATOMIC_H
-
-#ifndef INTERFACE_ATTRIBUTE
-# define INTERFACE_ATTRIBUTE __attribute__((visibility("default")))
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef char __tsan_atomic8;
-typedef short __tsan_atomic16; // NOLINT
-typedef int __tsan_atomic32;
-typedef long __tsan_atomic64; // NOLINT
-
-#if defined(__SIZEOF_INT128__) \
- || (__clang_major__ * 100 + __clang_minor__ >= 302)
-__extension__ typedef __int128 __tsan_atomic128;
-#define __TSAN_HAS_INT128 1
-#else
-typedef char __tsan_atomic128;
-#define __TSAN_HAS_INT128 0
-#endif
-
-// Part of ABI, do not change.
-// http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/atomic?view=markup
-typedef enum {
- __tsan_memory_order_relaxed,
- __tsan_memory_order_consume,
- __tsan_memory_order_acquire,
- __tsan_memory_order_release,
- __tsan_memory_order_acq_rel,
- __tsan_memory_order_seq_cst
-} __tsan_memory_order;
-
-__tsan_atomic8 __tsan_atomic8_load(const volatile __tsan_atomic8 *a,
- __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
-__tsan_atomic16 __tsan_atomic16_load(const volatile __tsan_atomic16 *a,
- __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
-__tsan_atomic32 __tsan_atomic32_load(const volatile __tsan_atomic32 *a,
- __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
-__tsan_atomic64 __tsan_atomic64_load(const volatile __tsan_atomic64 *a,
- __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
-__tsan_atomic128 __tsan_atomic128_load(const volatile __tsan_atomic128 *a,
- __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
-
-void __tsan_atomic8_store(volatile __tsan_atomic8 *a, __tsan_atomic8 v,
- __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
-void __tsan_atomic16_store(volatile __tsan_atomic16 *a, __tsan_atomic16 v,
- __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
-void __tsan_atomic32_store(volatile __tsan_atomic32 *a, __tsan_atomic32 v,
- __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
-void __tsan_atomic64_store(volatile __tsan_atomic64 *a, __tsan_atomic64 v,
- __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
-void __tsan_atomic128_store(volatile __tsan_atomic128 *a, __tsan_atomic128 v,
- __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
-
-__tsan_atomic8 __tsan_atomic8_exchange(volatile __tsan_atomic8 *a,
- __tsan_atomic8 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
-__tsan_atomic16 __tsan_atomic16_exchange(volatile __tsan_atomic16 *a,
- __tsan_atomic16 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
-__tsan_atomic32 __tsan_atomic32_exchange(volatile __tsan_atomic32 *a,
- __tsan_atomic32 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
-__tsan_atomic64 __tsan_atomic64_exchange(volatile __tsan_atomic64 *a,
- __tsan_atomic64 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
-__tsan_atomic128 __tsan_atomic128_exchange(volatile __tsan_atomic128 *a,
- __tsan_atomic128 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
-
-__tsan_atomic8 __tsan_atomic8_fetch_add(volatile __tsan_atomic8 *a,
- __tsan_atomic8 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
-__tsan_atomic16 __tsan_atomic16_fetch_add(volatile __tsan_atomic16 *a,
- __tsan_atomic16 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
-__tsan_atomic32 __tsan_atomic32_fetch_add(volatile __tsan_atomic32 *a,
- __tsan_atomic32 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
-__tsan_atomic64 __tsan_atomic64_fetch_add(volatile __tsan_atomic64 *a,
- __tsan_atomic64 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
-__tsan_atomic128 __tsan_atomic128_fetch_add(volatile __tsan_atomic128 *a,
- __tsan_atomic128 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
-
-__tsan_atomic8 __tsan_atomic8_fetch_sub(volatile __tsan_atomic8 *a,
- __tsan_atomic8 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
-__tsan_atomic16 __tsan_atomic16_fetch_sub(volatile __tsan_atomic16 *a,
- __tsan_atomic16 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
-__tsan_atomic32 __tsan_atomic32_fetch_sub(volatile __tsan_atomic32 *a,
- __tsan_atomic32 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
-__tsan_atomic64 __tsan_atomic64_fetch_sub(volatile __tsan_atomic64 *a,
- __tsan_atomic64 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
-__tsan_atomic128 __tsan_atomic128_fetch_sub(volatile __tsan_atomic128 *a,
- __tsan_atomic128 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
-
-__tsan_atomic8 __tsan_atomic8_fetch_and(volatile __tsan_atomic8 *a,
- __tsan_atomic8 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
-__tsan_atomic16 __tsan_atomic16_fetch_and(volatile __tsan_atomic16 *a,
- __tsan_atomic16 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
-__tsan_atomic32 __tsan_atomic32_fetch_and(volatile __tsan_atomic32 *a,
- __tsan_atomic32 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
-__tsan_atomic64 __tsan_atomic64_fetch_and(volatile __tsan_atomic64 *a,
- __tsan_atomic64 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
-__tsan_atomic128 __tsan_atomic128_fetch_and(volatile __tsan_atomic128 *a,
- __tsan_atomic128 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
-
-__tsan_atomic8 __tsan_atomic8_fetch_or(volatile __tsan_atomic8 *a,
- __tsan_atomic8 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
-__tsan_atomic16 __tsan_atomic16_fetch_or(volatile __tsan_atomic16 *a,
- __tsan_atomic16 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
-__tsan_atomic32 __tsan_atomic32_fetch_or(volatile __tsan_atomic32 *a,
- __tsan_atomic32 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
-__tsan_atomic64 __tsan_atomic64_fetch_or(volatile __tsan_atomic64 *a,
- __tsan_atomic64 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
-__tsan_atomic128 __tsan_atomic128_fetch_or(volatile __tsan_atomic128 *a,
- __tsan_atomic128 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
-
-__tsan_atomic8 __tsan_atomic8_fetch_xor(volatile __tsan_atomic8 *a,
- __tsan_atomic8 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
-__tsan_atomic16 __tsan_atomic16_fetch_xor(volatile __tsan_atomic16 *a,
- __tsan_atomic16 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
-__tsan_atomic32 __tsan_atomic32_fetch_xor(volatile __tsan_atomic32 *a,
- __tsan_atomic32 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
-__tsan_atomic64 __tsan_atomic64_fetch_xor(volatile __tsan_atomic64 *a,
- __tsan_atomic64 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
-__tsan_atomic128 __tsan_atomic128_fetch_xor(volatile __tsan_atomic128 *a,
- __tsan_atomic128 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
-
-__tsan_atomic8 __tsan_atomic8_fetch_nand(volatile __tsan_atomic8 *a,
- __tsan_atomic8 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
-__tsan_atomic16 __tsan_atomic16_fetch_nand(volatile __tsan_atomic16 *a,
- __tsan_atomic16 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
-__tsan_atomic32 __tsan_atomic32_fetch_nand(volatile __tsan_atomic32 *a,
- __tsan_atomic32 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
-__tsan_atomic64 __tsan_atomic64_fetch_nand(volatile __tsan_atomic64 *a,
- __tsan_atomic64 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
-__tsan_atomic128 __tsan_atomic128_fetch_nand(volatile __tsan_atomic128 *a,
- __tsan_atomic128 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
-
-int __tsan_atomic8_compare_exchange_weak(volatile __tsan_atomic8 *a,
- __tsan_atomic8 *c, __tsan_atomic8 v, __tsan_memory_order mo,
- __tsan_memory_order fail_mo) INTERFACE_ATTRIBUTE;
-int __tsan_atomic16_compare_exchange_weak(volatile __tsan_atomic16 *a,
- __tsan_atomic16 *c, __tsan_atomic16 v, __tsan_memory_order mo,
- __tsan_memory_order fail_mo) INTERFACE_ATTRIBUTE;
-int __tsan_atomic32_compare_exchange_weak(volatile __tsan_atomic32 *a,
- __tsan_atomic32 *c, __tsan_atomic32 v, __tsan_memory_order mo,
- __tsan_memory_order fail_mo) INTERFACE_ATTRIBUTE;
-int __tsan_atomic64_compare_exchange_weak(volatile __tsan_atomic64 *a,
- __tsan_atomic64 *c, __tsan_atomic64 v, __tsan_memory_order mo,
- __tsan_memory_order fail_mo) INTERFACE_ATTRIBUTE;
-int __tsan_atomic128_compare_exchange_weak(volatile __tsan_atomic128 *a,
- __tsan_atomic128 *c, __tsan_atomic128 v, __tsan_memory_order mo,
- __tsan_memory_order fail_mo) INTERFACE_ATTRIBUTE;
-
-int __tsan_atomic8_compare_exchange_strong(volatile __tsan_atomic8 *a,
- __tsan_atomic8 *c, __tsan_atomic8 v, __tsan_memory_order mo,
- __tsan_memory_order fail_mo) INTERFACE_ATTRIBUTE;
-int __tsan_atomic16_compare_exchange_strong(volatile __tsan_atomic16 *a,
- __tsan_atomic16 *c, __tsan_atomic16 v, __tsan_memory_order mo,
- __tsan_memory_order fail_mo) INTERFACE_ATTRIBUTE;
-int __tsan_atomic32_compare_exchange_strong(volatile __tsan_atomic32 *a,
- __tsan_atomic32 *c, __tsan_atomic32 v, __tsan_memory_order mo,
- __tsan_memory_order fail_mo) INTERFACE_ATTRIBUTE;
-int __tsan_atomic64_compare_exchange_strong(volatile __tsan_atomic64 *a,
- __tsan_atomic64 *c, __tsan_atomic64 v, __tsan_memory_order mo,
- __tsan_memory_order fail_mo) INTERFACE_ATTRIBUTE;
-int __tsan_atomic128_compare_exchange_strong(volatile __tsan_atomic128 *a,
- __tsan_atomic128 *c, __tsan_atomic128 v, __tsan_memory_order mo,
- __tsan_memory_order fail_mo) INTERFACE_ATTRIBUTE;
-
-__tsan_atomic8 __tsan_atomic8_compare_exchange_val(
- volatile __tsan_atomic8 *a, __tsan_atomic8 c, __tsan_atomic8 v,
- __tsan_memory_order mo, __tsan_memory_order fail_mo) INTERFACE_ATTRIBUTE;
-__tsan_atomic16 __tsan_atomic16_compare_exchange_val(
- volatile __tsan_atomic16 *a, __tsan_atomic16 c, __tsan_atomic16 v,
- __tsan_memory_order mo, __tsan_memory_order fail_mo) INTERFACE_ATTRIBUTE;
-__tsan_atomic32 __tsan_atomic32_compare_exchange_val(
- volatile __tsan_atomic32 *a, __tsan_atomic32 c, __tsan_atomic32 v,
- __tsan_memory_order mo, __tsan_memory_order fail_mo) INTERFACE_ATTRIBUTE;
-__tsan_atomic64 __tsan_atomic64_compare_exchange_val(
- volatile __tsan_atomic64 *a, __tsan_atomic64 c, __tsan_atomic64 v,
- __tsan_memory_order mo, __tsan_memory_order fail_mo) INTERFACE_ATTRIBUTE;
-__tsan_atomic128 __tsan_atomic128_compare_exchange_val(
- volatile __tsan_atomic128 *a, __tsan_atomic128 c, __tsan_atomic128 v,
- __tsan_memory_order mo, __tsan_memory_order fail_mo) INTERFACE_ATTRIBUTE;
-
-void __tsan_atomic_thread_fence(__tsan_memory_order mo) INTERFACE_ATTRIBUTE;
-void __tsan_atomic_signal_fence(__tsan_memory_order mo) INTERFACE_ATTRIBUTE;
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
-#undef INTERFACE_ATTRIBUTE
-
-#endif // #ifndef TSAN_INTERFACE_ATOMIC_H
diff --git a/lib/tsan/rtl/tsan_interface_java.cc b/lib/tsan/rtl/tsan_interface_java.cc
index 53f14cf07b59..8615349f657f 100644
--- a/lib/tsan/rtl/tsan_interface_java.cc
+++ b/lib/tsan/rtl/tsan_interface_java.cc
@@ -22,54 +22,17 @@
using namespace __tsan; // NOLINT
-namespace __tsan {
-
-const uptr kHeapShadow = 0x300000000000ull;
-const uptr kHeapAlignment = 8;
+const jptr kHeapAlignment = 8;
-struct BlockDesc {
- bool begin;
- Mutex mtx;
- SyncVar *head;
-
- BlockDesc()
- : mtx(MutexTypeJavaMBlock, StatMtxJavaMBlock)
- , head() {
- CHECK_EQ(begin, false);
- begin = true;
- }
-
- ~BlockDesc() {
- CHECK_EQ(begin, true);
- begin = false;
- ThreadState *thr = cur_thread();
- SyncVar *s = head;
- while (s) {
- SyncVar *s1 = s->next;
- StatInc(thr, StatSyncDestroyed);
- s->mtx.Lock();
- s->mtx.Unlock();
- thr->mset.Remove(s->GetId());
- DestroyAndFree(s);
- s = s1;
- }
- }
-};
+namespace __tsan {
struct JavaContext {
const uptr heap_begin;
const uptr heap_size;
- BlockDesc *heap_shadow;
JavaContext(jptr heap_begin, jptr heap_size)
: heap_begin(heap_begin)
, heap_size(heap_size) {
- uptr size = heap_size / kHeapAlignment * sizeof(BlockDesc);
- heap_shadow = (BlockDesc*)MmapFixedNoReserve(kHeapShadow, size);
- if ((uptr)heap_shadow != kHeapShadow) {
- Printf("ThreadSanitizer: failed to mmap Java heap shadow\n");
- Die();
- }
}
};
@@ -79,13 +42,9 @@ class ScopedJavaFunc {
: thr_(thr) {
Initialize(thr_);
FuncEntry(thr, pc);
- CHECK_EQ(thr_->in_rtl, 0);
- thr_->in_rtl++;
}
~ScopedJavaFunc() {
- thr_->in_rtl--;
- CHECK_EQ(thr_->in_rtl, 0);
FuncExit(thr_);
// FIXME(dvyukov): process pending signals.
}
@@ -97,69 +56,12 @@ class ScopedJavaFunc {
static u64 jctx_buf[sizeof(JavaContext) / sizeof(u64) + 1];
static JavaContext *jctx;
-static BlockDesc *getblock(uptr addr) {
- uptr i = (addr - jctx->heap_begin) / kHeapAlignment;
- return &jctx->heap_shadow[i];
-}
-
-static uptr USED getmem(BlockDesc *b) {
- uptr i = b - jctx->heap_shadow;
- uptr p = jctx->heap_begin + i * kHeapAlignment;
- CHECK_GE(p, jctx->heap_begin);
- CHECK_LT(p, jctx->heap_begin + jctx->heap_size);
- return p;
-}
-
-static BlockDesc *getblockbegin(uptr addr) {
- for (BlockDesc *b = getblock(addr);; b--) {
- CHECK_GE(b, jctx->heap_shadow);
- if (b->begin)
- return b;
- }
- return 0;
-}
-
-SyncVar* GetJavaSync(ThreadState *thr, uptr pc, uptr addr,
- bool write_lock, bool create) {
- if (jctx == 0 || addr < jctx->heap_begin
- || addr >= jctx->heap_begin + jctx->heap_size)
- return 0;
- BlockDesc *b = getblockbegin(addr);
- DPrintf("#%d: GetJavaSync %p->%p\n", thr->tid, addr, b);
- Lock l(&b->mtx);
- SyncVar *s = b->head;
- for (; s; s = s->next) {
- if (s->addr == addr) {
- DPrintf("#%d: found existing sync for %p\n", thr->tid, addr);
- break;
- }
- }
- if (s == 0 && create) {
- DPrintf("#%d: creating new sync for %p\n", thr->tid, addr);
- s = CTX()->synctab.Create(thr, pc, addr);
- s->next = b->head;
- b->head = s;
- }
- if (s) {
- if (write_lock)
- s->mtx.Lock();
- else
- s->mtx.ReadLock();
- }
- return s;
-}
-
-SyncVar* GetAndRemoveJavaSync(ThreadState *thr, uptr pc, uptr addr) {
- // We do not destroy Java mutexes other than in __tsan_java_free().
- return 0;
-}
-
} // namespace __tsan
#define SCOPED_JAVA_FUNC(func) \
ThreadState *thr = cur_thread(); \
const uptr caller_pc = GET_CALLER_PC(); \
- const uptr pc = __sanitizer::StackTrace::GetCurrentPc(); \
+ const uptr pc = StackTrace::GetCurrentPc(); \
(void)pc; \
ScopedJavaFunc scoped(thr, caller_pc); \
/**/
@@ -196,8 +98,7 @@ void __tsan_java_alloc(jptr ptr, jptr size) {
CHECK_GE(ptr, jctx->heap_begin);
CHECK_LE(ptr + size, jctx->heap_begin + jctx->heap_size);
- BlockDesc *b = getblock(ptr);
- new(b) BlockDesc();
+ OnUserAlloc(thr, pc, ptr, size, false);
}
void __tsan_java_free(jptr ptr, jptr size) {
@@ -210,12 +111,7 @@ void __tsan_java_free(jptr ptr, jptr size) {
CHECK_GE(ptr, jctx->heap_begin);
CHECK_LE(ptr + size, jctx->heap_begin + jctx->heap_size);
- BlockDesc *beg = getblock(ptr);
- BlockDesc *end = getblock(ptr + size);
- for (BlockDesc *b = beg; b != end; b++) {
- if (b->begin)
- b->~BlockDesc();
- }
+ ctx->metamap.FreeRange(thr, pc, ptr, size);
}
void __tsan_java_move(jptr src, jptr dst, jptr size) {
@@ -230,42 +126,36 @@ void __tsan_java_move(jptr src, jptr dst, jptr size) {
CHECK_LE(src + size, jctx->heap_begin + jctx->heap_size);
CHECK_GE(dst, jctx->heap_begin);
CHECK_LE(dst + size, jctx->heap_begin + jctx->heap_size);
- CHECK(dst >= src + size || src >= dst + size);
+ CHECK_NE(dst, src);
+ CHECK_NE(size, 0);
// Assuming it's not running concurrently with threads that do
// memory accesses and mutex operations (stop-the-world phase).
- { // NOLINT
- BlockDesc *s = getblock(src);
- BlockDesc *d = getblock(dst);
- BlockDesc *send = getblock(src + size);
- for (; s != send; s++, d++) {
- CHECK_EQ(d->begin, false);
- if (s->begin) {
- DPrintf("#%d: moving block %p->%p\n", thr->tid, getmem(s), getmem(d));
- new(d) BlockDesc;
- d->head = s->head;
- for (SyncVar *sync = d->head; sync; sync = sync->next) {
- uptr newaddr = sync->addr - src + dst;
- DPrintf("#%d: moving sync %p->%p\n", thr->tid, sync->addr, newaddr);
- sync->addr = newaddr;
- }
- s->head = 0;
- s->~BlockDesc();
- }
- }
+ ctx->metamap.MoveMemory(src, dst, size);
+
+ // Move shadow.
+ u64 *s = (u64*)MemToShadow(src);
+ u64 *d = (u64*)MemToShadow(dst);
+ u64 *send = (u64*)MemToShadow(src + size);
+ uptr inc = 1;
+ if (dst > src) {
+ s = (u64*)MemToShadow(src + size) - 1;
+ d = (u64*)MemToShadow(dst + size) - 1;
+ send = (u64*)MemToShadow(src) - 1;
+ inc = -1;
}
-
- { // NOLINT
- u64 *s = (u64*)MemToShadow(src);
- u64 *d = (u64*)MemToShadow(dst);
- u64 *send = (u64*)MemToShadow(src + size);
- for (; s != send; s++, d++) {
- *d = *s;
- *s = 0;
- }
+ for (; s != send; s += inc, d += inc) {
+ *d = *s;
+ *s = 0;
}
}
+void __tsan_java_finalize() {
+ SCOPED_JAVA_FUNC(__tsan_java_finalize);
+ DPrintf("#%d: java_mutex_finalize()\n", thr->tid);
+ AcquireGlobal(thr, 0);
+}
+
void __tsan_java_mutex_lock(jptr addr) {
SCOPED_JAVA_FUNC(__tsan_java_mutex_lock);
DPrintf("#%d: java_mutex_lock(%p)\n", thr->tid, addr);
diff --git a/lib/tsan/rtl/tsan_interface_java.h b/lib/tsan/rtl/tsan_interface_java.h
index 9ac78e074bbe..1f793df712de 100644
--- a/lib/tsan/rtl/tsan_interface_java.h
+++ b/lib/tsan/rtl/tsan_interface_java.h
@@ -50,8 +50,13 @@ void __tsan_java_alloc(jptr ptr, jptr size) INTERFACE_ATTRIBUTE;
void __tsan_java_free(jptr ptr, jptr size) INTERFACE_ATTRIBUTE;
// Callback for memory move by GC.
// Can be aggregated for several objects (preferably).
-// The ranges must not overlap.
+// The ranges can overlap.
void __tsan_java_move(jptr src, jptr dst, jptr size) INTERFACE_ATTRIBUTE;
+// This function must be called on the finalizer thread
+// before executing a batch of finalizers.
+// It ensures necessary synchronization between
+// java object creation and finalization.
+void __tsan_java_finalize() INTERFACE_ATTRIBUTE;
// Mutex lock.
// Addr is any unique address associated with the mutex.
diff --git a/lib/tsan/rtl/tsan_md5.cc b/lib/tsan/rtl/tsan_md5.cc
index 66e824043153..51279c10d17a 100644
--- a/lib/tsan/rtl/tsan_md5.cc
+++ b/lib/tsan/rtl/tsan_md5.cc
@@ -25,7 +25,7 @@ namespace __tsan {
(a) += (b);
#define SET(n) \
- (*(MD5_u32plus *)&ptr[(n) * 4])
+ (*(const MD5_u32plus *)&ptr[(n) * 4])
#define GET(n) \
SET(n)
@@ -39,13 +39,11 @@ typedef struct {
MD5_u32plus block[16];
} MD5_CTX;
-static void *body(MD5_CTX *ctx, void *data, ulong_t size) {
- unsigned char *ptr;
+static const void *body(MD5_CTX *ctx, const void *data, ulong_t size) {
+ const unsigned char *ptr = (const unsigned char *)data;
MD5_u32plus a, b, c, d;
MD5_u32plus saved_a, saved_b, saved_c, saved_d;
- ptr = (unsigned char*)data;
-
a = ctx->a;
b = ctx->b;
c = ctx->c;
@@ -151,7 +149,7 @@ void MD5_Init(MD5_CTX *ctx) {
ctx->hi = 0;
}
-void MD5_Update(MD5_CTX *ctx, void *data, ulong_t size) {
+void MD5_Update(MD5_CTX *ctx, const void *data, ulong_t size) {
MD5_u32plus saved_lo;
ulong_t used, free;
@@ -171,7 +169,7 @@ void MD5_Update(MD5_CTX *ctx, void *data, ulong_t size) {
}
internal_memcpy(&ctx->buffer[used], data, free);
- data = (unsigned char *)data + free;
+ data = (const unsigned char *)data + free;
size -= free;
body(ctx, ctx->buffer, 64);
}
@@ -238,7 +236,7 @@ MD5Hash md5_hash(const void *data, uptr size) {
MD5Hash res;
MD5_CTX ctx;
MD5_Init(&ctx);
- MD5_Update(&ctx, (void*)data, size);
+ MD5_Update(&ctx, data, size);
MD5_Final((unsigned char*)&res.hash[0], &ctx);
return res;
}
diff --git a/lib/tsan/rtl/tsan_mman.cc b/lib/tsan/rtl/tsan_mman.cc
index 8547f714be13..285bdb34d91d 100644
--- a/lib/tsan/rtl/tsan_mman.cc
+++ b/lib/tsan/rtl/tsan_mman.cc
@@ -10,6 +10,7 @@
// This file is a part of ThreadSanitizer (TSan), a race detector.
//
//===----------------------------------------------------------------------===//
+#include "sanitizer_common/sanitizer_allocator_interface.h"
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_placement_new.h"
#include "tsan_mman.h"
@@ -18,43 +19,17 @@
#include "tsan_flags.h"
// May be overriden by front-end.
-extern "C" void WEAK __tsan_malloc_hook(void *ptr, uptr size) {
+extern "C" void WEAK __sanitizer_malloc_hook(void *ptr, uptr size) {
(void)ptr;
(void)size;
}
-extern "C" void WEAK __tsan_free_hook(void *ptr) {
+extern "C" void WEAK __sanitizer_free_hook(void *ptr) {
(void)ptr;
}
namespace __tsan {
-COMPILER_CHECK(sizeof(MBlock) == 16);
-
-void MBlock::Lock() {
- atomic_uintptr_t *a = reinterpret_cast<atomic_uintptr_t*>(this);
- uptr v = atomic_load(a, memory_order_relaxed);
- for (int iter = 0;; iter++) {
- if (v & 1) {
- if (iter < 10)
- proc_yield(20);
- else
- internal_sched_yield();
- v = atomic_load(a, memory_order_relaxed);
- continue;
- }
- if (atomic_compare_exchange_weak(a, &v, v | 1, memory_order_acquire))
- break;
- }
-}
-
-void MBlock::Unlock() {
- atomic_uintptr_t *a = reinterpret_cast<atomic_uintptr_t*>(this);
- uptr v = atomic_load(a, memory_order_relaxed);
- DCHECK(v & 1);
- atomic_store(a, v & ~1, memory_order_relaxed);
-}
-
struct MapUnmapCallback {
void OnMap(uptr p, uptr size) const { }
void OnUnmap(uptr p, uptr size) const {
@@ -88,66 +63,58 @@ void AllocatorPrintStats() {
}
static void SignalUnsafeCall(ThreadState *thr, uptr pc) {
- if (!thr->in_signal_handler || !flags()->report_signal_unsafe)
+ if (atomic_load(&thr->in_signal_handler, memory_order_relaxed) == 0 ||
+ !flags()->report_signal_unsafe)
return;
- Context *ctx = CTX();
- StackTrace stack;
- stack.ObtainCurrent(thr, pc);
+ VarSizeStackTrace stack;
+ ObtainCurrentStack(thr, pc, &stack);
ThreadRegistryLock l(ctx->thread_registry);
ScopedReport rep(ReportTypeSignalUnsafe);
if (!IsFiredSuppression(ctx, rep, stack)) {
- rep.AddStack(&stack);
- OutputReport(ctx, rep, rep.GetReport()->stacks[0]);
+ rep.AddStack(stack, true);
+ OutputReport(thr, rep);
}
}
-void *user_alloc(ThreadState *thr, uptr pc, uptr sz, uptr align) {
- CHECK_GT(thr->in_rtl, 0);
+void *user_alloc(ThreadState *thr, uptr pc, uptr sz, uptr align, bool signal) {
if ((sz >= (1ull << 40)) || (align >= (1ull << 40)))
return AllocatorReturnNull();
void *p = allocator()->Allocate(&thr->alloc_cache, sz, align);
if (p == 0)
return 0;
- MBlock *b = new(allocator()->GetMetaData(p)) MBlock;
- b->Init(sz, thr->tid, CurrentStackId(thr, pc));
- if (CTX() && CTX()->initialized) {
- if (thr->ignore_reads_and_writes == 0)
- MemoryRangeImitateWrite(thr, pc, (uptr)p, sz);
- else
- MemoryResetRange(thr, pc, (uptr)p, sz);
- }
- DPrintf("#%d: alloc(%zu) = %p\n", thr->tid, sz, p);
- SignalUnsafeCall(thr, pc);
+ if (ctx && ctx->initialized)
+ OnUserAlloc(thr, pc, (uptr)p, sz, true);
+ if (signal)
+ SignalUnsafeCall(thr, pc);
return p;
}
-void user_free(ThreadState *thr, uptr pc, void *p) {
- CHECK_GT(thr->in_rtl, 0);
- CHECK_NE(p, (void*)0);
- DPrintf("#%d: free(%p)\n", thr->tid, p);
- MBlock *b = (MBlock*)allocator()->GetMetaData(p);
- if (b->ListHead()) {
- MBlock::ScopedLock l(b);
- for (SyncVar *s = b->ListHead(); s;) {
- SyncVar *res = s;
- s = s->next;
- StatInc(thr, StatSyncDestroyed);
- res->mtx.Lock();
- res->mtx.Unlock();
- DestroyAndFree(res);
- }
- b->ListReset();
- }
- if (CTX() && CTX()->initialized && thr->in_rtl == 1) {
- if (thr->ignore_reads_and_writes == 0)
- MemoryRangeFreed(thr, pc, (uptr)p, b->Size());
- }
+void user_free(ThreadState *thr, uptr pc, void *p, bool signal) {
+ if (ctx && ctx->initialized)
+ OnUserFree(thr, pc, (uptr)p, true);
allocator()->Deallocate(&thr->alloc_cache, p);
- SignalUnsafeCall(thr, pc);
+ if (signal)
+ SignalUnsafeCall(thr, pc);
+}
+
+void OnUserAlloc(ThreadState *thr, uptr pc, uptr p, uptr sz, bool write) {
+ DPrintf("#%d: alloc(%zu) = %p\n", thr->tid, sz, p);
+ ctx->metamap.AllocBlock(thr, pc, p, sz);
+ if (write && thr->ignore_reads_and_writes == 0)
+ MemoryRangeImitateWrite(thr, pc, (uptr)p, sz);
+ else
+ MemoryResetRange(thr, pc, (uptr)p, sz);
+}
+
+void OnUserFree(ThreadState *thr, uptr pc, uptr p, bool write) {
+ CHECK_NE(p, (void*)0);
+ uptr sz = ctx->metamap.FreeBlock(thr, pc, p);
+ DPrintf("#%d: free(%p, %zu)\n", thr->tid, p, sz);
+ if (write && thr->ignore_reads_and_writes == 0)
+ MemoryRangeFreed(thr, pc, (uptr)p, sz);
}
void *user_realloc(ThreadState *thr, uptr pc, void *p, uptr sz) {
- CHECK_GT(thr->in_rtl, 0);
void *p2 = 0;
// FIXME: Handle "shrinking" more efficiently,
// it seems that some software actually does this.
@@ -156,9 +123,8 @@ void *user_realloc(ThreadState *thr, uptr pc, void *p, uptr sz) {
if (p2 == 0)
return 0;
if (p) {
- MBlock *b = user_mblock(thr, p);
- CHECK_NE(b, 0);
- internal_memcpy(p2, p, min(b->Size(), sz));
+ uptr oldsz = user_alloc_usable_size(p);
+ internal_memcpy(p2, p, min(oldsz, sz));
}
}
if (p)
@@ -166,43 +132,29 @@ void *user_realloc(ThreadState *thr, uptr pc, void *p, uptr sz) {
return p2;
}
-uptr user_alloc_usable_size(ThreadState *thr, uptr pc, void *p) {
- CHECK_GT(thr->in_rtl, 0);
+uptr user_alloc_usable_size(const void *p) {
if (p == 0)
return 0;
- MBlock *b = (MBlock*)allocator()->GetMetaData(p);
- return b ? b->Size() : 0;
-}
-
-MBlock *user_mblock(ThreadState *thr, void *p) {
- CHECK_NE(p, 0);
- Allocator *a = allocator();
- void *b = a->GetBlockBegin(p);
- if (b == 0)
- return 0;
- return (MBlock*)a->GetMetaData(b);
+ MBlock *b = ctx->metamap.GetBlock((uptr)p);
+ return b ? b->siz : 0;
}
void invoke_malloc_hook(void *ptr, uptr size) {
- Context *ctx = CTX();
ThreadState *thr = cur_thread();
- if (ctx == 0 || !ctx->initialized || thr->in_rtl)
+ if (ctx == 0 || !ctx->initialized || thr->ignore_interceptors)
return;
- __tsan_malloc_hook(ptr, size);
+ __sanitizer_malloc_hook(ptr, size);
}
void invoke_free_hook(void *ptr) {
- Context *ctx = CTX();
ThreadState *thr = cur_thread();
- if (ctx == 0 || !ctx->initialized || thr->in_rtl)
+ if (ctx == 0 || !ctx->initialized || thr->ignore_interceptors)
return;
- __tsan_free_hook(ptr);
+ __sanitizer_free_hook(ptr);
}
void *internal_alloc(MBlockType typ, uptr sz) {
ThreadState *thr = cur_thread();
- CHECK_GT(thr->in_rtl, 0);
- CHECK_LE(sz, InternalSizeClassMap::kMaxSize);
if (thr->nomalloc) {
thr->nomalloc = 0; // CHECK calls internal_malloc().
CHECK(0);
@@ -212,7 +164,6 @@ void *internal_alloc(MBlockType typ, uptr sz) {
void internal_free(void *p) {
ThreadState *thr = cur_thread();
- CHECK_GT(thr->in_rtl, 0);
if (thr->nomalloc) {
thr->nomalloc = 0; // CHECK calls internal_malloc().
CHECK(0);
@@ -225,51 +176,42 @@ void internal_free(void *p) {
using namespace __tsan;
extern "C" {
-uptr __tsan_get_current_allocated_bytes() {
- u64 stats[AllocatorStatCount];
+uptr __sanitizer_get_current_allocated_bytes() {
+ uptr stats[AllocatorStatCount];
allocator()->GetStats(stats);
- u64 m = stats[AllocatorStatMalloced];
- u64 f = stats[AllocatorStatFreed];
- return m >= f ? m - f : 1;
+ return stats[AllocatorStatAllocated];
}
-uptr __tsan_get_heap_size() {
- u64 stats[AllocatorStatCount];
+uptr __sanitizer_get_heap_size() {
+ uptr stats[AllocatorStatCount];
allocator()->GetStats(stats);
- u64 m = stats[AllocatorStatMmapped];
- u64 f = stats[AllocatorStatUnmapped];
- return m >= f ? m - f : 1;
+ return stats[AllocatorStatMapped];
}
-uptr __tsan_get_free_bytes() {
+uptr __sanitizer_get_free_bytes() {
return 1;
}
-uptr __tsan_get_unmapped_bytes() {
+uptr __sanitizer_get_unmapped_bytes() {
return 1;
}
-uptr __tsan_get_estimated_allocated_size(uptr size) {
+uptr __sanitizer_get_estimated_allocated_size(uptr size) {
return size;
}
-bool __tsan_get_ownership(void *p) {
+int __sanitizer_get_ownership(const void *p) {
return allocator()->GetBlockBegin(p) != 0;
}
-uptr __tsan_get_allocated_size(void *p) {
- if (p == 0)
- return 0;
- p = allocator()->GetBlockBegin(p);
- if (p == 0)
- return 0;
- MBlock *b = (MBlock*)allocator()->GetMetaData(p);
- return b->Size();
+uptr __sanitizer_get_allocated_size(const void *p) {
+ return user_alloc_usable_size(p);
}
void __tsan_on_thread_idle() {
ThreadState *thr = cur_thread();
allocator()->SwallowCache(&thr->alloc_cache);
internal_allocator()->SwallowCache(&thr->internal_alloc_cache);
+ ctx->metamap.OnThreadIdle(thr);
}
} // extern "C"
diff --git a/lib/tsan/rtl/tsan_mman.h b/lib/tsan/rtl/tsan_mman.h
index 19d555437f3e..7d41fa864a26 100644
--- a/lib/tsan/rtl/tsan_mman.h
+++ b/lib/tsan/rtl/tsan_mman.h
@@ -26,15 +26,12 @@ void AllocatorPrintStats();
// For user allocations.
void *user_alloc(ThreadState *thr, uptr pc, uptr sz,
- uptr align = kDefaultAlignment);
+ uptr align = kDefaultAlignment, bool signal = true);
// Does not accept NULL.
-void user_free(ThreadState *thr, uptr pc, void *p);
+void user_free(ThreadState *thr, uptr pc, void *p, bool signal = true);
void *user_realloc(ThreadState *thr, uptr pc, void *p, uptr sz);
void *user_alloc_aligned(ThreadState *thr, uptr pc, uptr sz, uptr align);
-uptr user_alloc_usable_size(ThreadState *thr, uptr pc, void *p);
-// Given the pointer p into a valid allocated block,
-// returns the descriptor of the block.
-MBlock *user_mblock(ThreadState *thr, void *p);
+uptr user_alloc_usable_size(const void *p);
// Invoking malloc/free hooks that may be installed by the user.
void invoke_malloc_hook(void *ptr, uptr size);
@@ -62,7 +59,6 @@ enum MBlockType {
MBlockSuppression,
MBlockExpectRace,
MBlockSignal,
- MBlockFD,
MBlockJmpBuf,
// This must be the last.
diff --git a/lib/tsan/rtl/tsan_mutex.cc b/lib/tsan/rtl/tsan_mutex.cc
index a92fd90fd9c1..9ea9bae21b50 100644
--- a/lib/tsan/rtl/tsan_mutex.cc
+++ b/lib/tsan/rtl/tsan_mutex.cc
@@ -25,28 +25,29 @@ namespace __tsan {
// then Report mutex can be locked while under Threads mutex.
// The leaf mutexes can be locked under any other mutexes.
// Recursive locking is not supported.
-#if TSAN_DEBUG && !TSAN_GO
+#if TSAN_DEBUG && !SANITIZER_GO
const MutexType MutexTypeLeaf = (MutexType)-1;
static MutexType CanLockTab[MutexTypeCount][MutexTypeCount] = {
/*0 MutexTypeInvalid*/ {},
/*1 MutexTypeTrace*/ {MutexTypeLeaf},
/*2 MutexTypeThreads*/ {MutexTypeReport},
- /*3 MutexTypeReport*/ {MutexTypeSyncTab, MutexTypeSyncVar,
+ /*3 MutexTypeReport*/ {MutexTypeSyncVar,
MutexTypeMBlock, MutexTypeJavaMBlock},
- /*4 MutexTypeSyncVar*/ {},
- /*5 MutexTypeSyncTab*/ {MutexTypeSyncVar},
+ /*4 MutexTypeSyncVar*/ {MutexTypeDDetector},
+ /*5 MutexTypeSyncTab*/ {}, // unused
/*6 MutexTypeSlab*/ {MutexTypeLeaf},
/*7 MutexTypeAnnotations*/ {},
- /*8 MutexTypeAtExit*/ {MutexTypeSyncTab},
+ /*8 MutexTypeAtExit*/ {MutexTypeSyncVar},
/*9 MutexTypeMBlock*/ {MutexTypeSyncVar},
/*10 MutexTypeJavaMBlock*/ {MutexTypeSyncVar},
+ /*11 MutexTypeDDetector*/ {},
};
static bool CanLockAdj[MutexTypeCount][MutexTypeCount];
#endif
void InitializeMutex() {
-#if TSAN_DEBUG && !TSAN_GO
+#if TSAN_DEBUG && !SANITIZER_GO
// Build the "can lock" adjacency matrix.
// If [i][j]==true, then one can lock mutex j while under mutex i.
const int N = MutexTypeCount;
@@ -123,12 +124,12 @@ void InitializeMutex() {
#endif
}
-DeadlockDetector::DeadlockDetector() {
+InternalDeadlockDetector::InternalDeadlockDetector() {
// Rely on zero initialization because some mutexes can be locked before ctor.
}
-#if TSAN_DEBUG && !TSAN_GO
-void DeadlockDetector::Lock(MutexType t) {
+#if TSAN_DEBUG && !SANITIZER_GO
+void InternalDeadlockDetector::Lock(MutexType t) {
// Printf("LOCK %d @%zu\n", t, seq_ + 1);
CHECK_GT(t, MutexTypeInvalid);
CHECK_LT(t, MutexTypeCount);
@@ -155,13 +156,25 @@ void DeadlockDetector::Lock(MutexType t) {
}
}
-void DeadlockDetector::Unlock(MutexType t) {
+void InternalDeadlockDetector::Unlock(MutexType t) {
// Printf("UNLO %d @%zu #%zu\n", t, seq_, locked_[t]);
CHECK(locked_[t]);
locked_[t] = 0;
}
+
+void InternalDeadlockDetector::CheckNoLocks() {
+ for (int i = 0; i != MutexTypeCount; i++) {
+ CHECK_EQ(locked_[i], 0);
+ }
+}
#endif
+void CheckNoLocks(ThreadState *thr) {
+#if TSAN_DEBUG && !SANITIZER_GO
+ thr->internal_deadlock_detector.CheckNoLocks();
+#endif
+}
+
const uptr kUnlocked = 0;
const uptr kWriteLock = 1;
const uptr kReadLock = 2;
@@ -209,8 +222,8 @@ Mutex::~Mutex() {
}
void Mutex::Lock() {
-#if TSAN_DEBUG && !TSAN_GO
- cur_thread()->deadlock_detector.Lock(type_);
+#if TSAN_DEBUG && !SANITIZER_GO
+ cur_thread()->internal_deadlock_detector.Lock(type_);
#endif
uptr cmp = kUnlocked;
if (atomic_compare_exchange_strong(&state_, &cmp, kWriteLock,
@@ -221,7 +234,7 @@ void Mutex::Lock() {
cmp = kUnlocked;
if (atomic_compare_exchange_weak(&state_, &cmp, kWriteLock,
memory_order_acquire)) {
-#if TSAN_COLLECT_STATS
+#if TSAN_COLLECT_STATS && !SANITIZER_GO
StatInc(cur_thread(), stat_type_, backoff.Contention());
#endif
return;
@@ -234,14 +247,14 @@ void Mutex::Unlock() {
uptr prev = atomic_fetch_sub(&state_, kWriteLock, memory_order_release);
(void)prev;
DCHECK_NE(prev & kWriteLock, 0);
-#if TSAN_DEBUG && !TSAN_GO
- cur_thread()->deadlock_detector.Unlock(type_);
+#if TSAN_DEBUG && !SANITIZER_GO
+ cur_thread()->internal_deadlock_detector.Unlock(type_);
#endif
}
void Mutex::ReadLock() {
-#if TSAN_DEBUG && !TSAN_GO
- cur_thread()->deadlock_detector.Lock(type_);
+#if TSAN_DEBUG && !SANITIZER_GO
+ cur_thread()->internal_deadlock_detector.Lock(type_);
#endif
uptr prev = atomic_fetch_add(&state_, kReadLock, memory_order_acquire);
if ((prev & kWriteLock) == 0)
@@ -249,7 +262,7 @@ void Mutex::ReadLock() {
for (Backoff backoff; backoff.Do();) {
prev = atomic_load(&state_, memory_order_acquire);
if ((prev & kWriteLock) == 0) {
-#if TSAN_COLLECT_STATS
+#if TSAN_COLLECT_STATS && !SANITIZER_GO
StatInc(cur_thread(), stat_type_, backoff.Contention());
#endif
return;
@@ -262,8 +275,8 @@ void Mutex::ReadUnlock() {
(void)prev;
DCHECK_EQ(prev & kWriteLock, 0);
DCHECK_GT(prev & ~kWriteLock, 0);
-#if TSAN_DEBUG && !TSAN_GO
- cur_thread()->deadlock_detector.Unlock(type_);
+#if TSAN_DEBUG && !SANITIZER_GO
+ cur_thread()->internal_deadlock_detector.Unlock(type_);
#endif
}
diff --git a/lib/tsan/rtl/tsan_mutex.h b/lib/tsan/rtl/tsan_mutex.h
index a2b489107a98..7bb1c48fcac8 100644
--- a/lib/tsan/rtl/tsan_mutex.h
+++ b/lib/tsan/rtl/tsan_mutex.h
@@ -31,6 +31,7 @@ enum MutexType {
MutexTypeAtExit,
MutexTypeMBlock,
MutexTypeJavaMBlock,
+ MutexTypeDDetector,
// This must be the last.
MutexTypeCount
@@ -65,11 +66,12 @@ class Mutex {
typedef GenericScopedLock<Mutex> Lock;
typedef GenericScopedReadLock<Mutex> ReadLock;
-class DeadlockDetector {
+class InternalDeadlockDetector {
public:
- DeadlockDetector();
+ InternalDeadlockDetector();
void Lock(MutexType t);
void Unlock(MutexType t);
+ void CheckNoLocks();
private:
u64 seq_;
u64 locked_[MutexTypeCount];
@@ -77,6 +79,10 @@ class DeadlockDetector {
void InitializeMutex();
+// Checks that the current thread does not hold any runtime locks
+// (e.g. when returning from an interceptor).
+void CheckNoLocks(ThreadState *thr);
+
} // namespace __tsan
#endif // TSAN_MUTEX_H
diff --git a/lib/tsan/rtl/tsan_mutexset.h b/lib/tsan/rtl/tsan_mutexset.h
index eebfd4d70a14..68f0ec26fa25 100644
--- a/lib/tsan/rtl/tsan_mutexset.h
+++ b/lib/tsan/rtl/tsan_mutexset.h
@@ -38,19 +38,24 @@ class MutexSet {
uptr Size() const;
Desc Get(uptr i) const;
+ void operator=(const MutexSet &other) {
+ internal_memcpy(this, &other, sizeof(*this));
+ }
+
private:
-#ifndef TSAN_GO
+#ifndef SANITIZER_GO
uptr size_;
Desc descs_[kMaxSize];
#endif
void RemovePos(uptr i);
+ MutexSet(const MutexSet&);
};
// Go does not have mutexes, so do not spend memory and time.
// (Go sync.Mutex is actually a semaphore -- can be unlocked
// in different goroutine).
-#ifdef TSAN_GO
+#ifdef SANITIZER_GO
MutexSet::MutexSet() {}
void MutexSet::Add(u64 id, bool write, u64 epoch) {}
void MutexSet::Del(u64 id, bool write) {}
@@ -62,4 +67,4 @@ MutexSet::Desc MutexSet::Get(uptr i) const { return Desc(); }
} // namespace __tsan
-#endif // TSAN_REPORT_H
+#endif // TSAN_MUTEXSET_H
diff --git a/lib/tsan/rtl/tsan_platform.h b/lib/tsan/rtl/tsan_platform.h
index 32e22ba60434..270a7519dd0a 100644
--- a/lib/tsan/rtl/tsan_platform.h
+++ b/lib/tsan/rtl/tsan_platform.h
@@ -12,161 +12,259 @@
// Platform-specific code.
//===----------------------------------------------------------------------===//
+#ifndef TSAN_PLATFORM_H
+#define TSAN_PLATFORM_H
+
+#if !defined(__LP64__) && !defined(_WIN64)
+# error "Only 64-bit is supported"
+#endif
+
+#include "tsan_defs.h"
+#include "tsan_trace.h"
+
+namespace __tsan {
+
+#if !defined(SANITIZER_GO)
+
/*
-C++ linux memory layout:
-0000 0000 0000 - 03c0 0000 0000: protected
-03c0 0000 0000 - 1000 0000 0000: shadow
-1000 0000 0000 - 6000 0000 0000: protected
-6000 0000 0000 - 6200 0000 0000: traces
-6200 0000 0000 - 7d00 0000 0000: -
-7d00 0000 0000 - 7e00 0000 0000: heap
-7e00 0000 0000 - 7fff ffff ffff: modules and main thread stack
-
-C++ COMPAT linux memory layout:
-0000 0000 0000 - 0400 0000 0000: protected
-0400 0000 0000 - 1000 0000 0000: shadow
-1000 0000 0000 - 2900 0000 0000: protected
-2900 0000 0000 - 2c00 0000 0000: modules
-2c00 0000 0000 - 6000 0000 0000: -
+C/C++ on linux and freebsd
+0000 0000 1000 - 0100 0000 0000: main binary and/or MAP_32BIT mappings
+0100 0000 0000 - 0200 0000 0000: -
+0200 0000 0000 - 1000 0000 0000: shadow
+1000 0000 0000 - 3000 0000 0000: -
+3000 0000 0000 - 4000 0000 0000: metainfo (memory blocks and sync objects)
+4000 0000 0000 - 6000 0000 0000: -
6000 0000 0000 - 6200 0000 0000: traces
6200 0000 0000 - 7d00 0000 0000: -
7d00 0000 0000 - 7e00 0000 0000: heap
-7e00 0000 0000 - 7f00 0000 0000: -
-7f00 0000 0000 - 7fff ffff ffff: main thread stack
+7e00 0000 0000 - 7e80 0000 0000: -
+7e80 0000 0000 - 8000 0000 0000: modules and main thread stack
+*/
-Go linux and darwin memory layout:
-0000 0000 0000 - 0000 1000 0000: executable
-0000 1000 0000 - 00f8 0000 0000: -
-00c0 0000 0000 - 00e0 0000 0000: heap
-00e0 0000 0000 - 1000 0000 0000: -
-1000 0000 0000 - 1380 0000 0000: shadow
-1460 0000 0000 - 6000 0000 0000: -
-6000 0000 0000 - 6200 0000 0000: traces
-6200 0000 0000 - 7fff ffff ffff: -
+const uptr kMetaShadowBeg = 0x300000000000ull;
+const uptr kMetaShadowEnd = 0x400000000000ull;
+const uptr kTraceMemBeg = 0x600000000000ull;
+const uptr kTraceMemEnd = 0x620000000000ull;
+const uptr kShadowBeg = 0x020000000000ull;
+const uptr kShadowEnd = 0x100000000000ull;
+const uptr kHeapMemBeg = 0x7d0000000000ull;
+const uptr kHeapMemEnd = 0x7e0000000000ull;
+const uptr kLoAppMemBeg = 0x000000001000ull;
+const uptr kLoAppMemEnd = 0x010000000000ull;
+const uptr kHiAppMemBeg = 0x7e8000000000ull;
+const uptr kHiAppMemEnd = 0x800000000000ull;
+const uptr kAppMemMsk = 0x7c0000000000ull;
+const uptr kAppMemXor = 0x020000000000ull;
-Go windows memory layout:
-0000 0000 0000 - 0000 1000 0000: executable
-0000 1000 0000 - 00f8 0000 0000: -
+ALWAYS_INLINE
+bool IsAppMem(uptr mem) {
+ return (mem >= kHeapMemBeg && mem < kHeapMemEnd) ||
+ (mem >= kLoAppMemBeg && mem < kLoAppMemEnd) ||
+ (mem >= kHiAppMemBeg && mem < kHiAppMemEnd);
+}
+
+ALWAYS_INLINE
+bool IsShadowMem(uptr mem) {
+ return mem >= kShadowBeg && mem <= kShadowEnd;
+}
+
+ALWAYS_INLINE
+bool IsMetaMem(uptr mem) {
+ return mem >= kMetaShadowBeg && mem <= kMetaShadowEnd;
+}
+
+ALWAYS_INLINE
+uptr MemToShadow(uptr x) {
+ DCHECK(IsAppMem(x));
+ return (((x) & ~(kAppMemMsk | (kShadowCell - 1)))
+ ^ kAppMemXor) * kShadowCnt;
+}
+
+ALWAYS_INLINE
+u32 *MemToMeta(uptr x) {
+ DCHECK(IsAppMem(x));
+ return (u32*)(((((x) & ~(kAppMemMsk | (kMetaShadowCell - 1)))
+ ^ kAppMemXor) / kMetaShadowCell * kMetaShadowSize) | kMetaShadowBeg);
+}
+
+ALWAYS_INLINE
+uptr ShadowToMem(uptr s) {
+ CHECK(IsShadowMem(s));
+ if (s >= MemToShadow(kLoAppMemBeg) && s <= MemToShadow(kLoAppMemEnd - 1))
+ return (s / kShadowCnt) ^ kAppMemXor;
+ else
+ return ((s / kShadowCnt) ^ kAppMemXor) | kAppMemMsk;
+}
+
+static USED uptr UserRegions[] = {
+ kLoAppMemBeg, kLoAppMemEnd,
+ kHiAppMemBeg, kHiAppMemEnd,
+ kHeapMemBeg, kHeapMemEnd,
+};
+
+#elif defined(SANITIZER_GO) && !SANITIZER_WINDOWS
+
+/* Go on linux, darwin and freebsd
+0000 0000 1000 - 0000 1000 0000: executable
+0000 1000 0000 - 00c0 0000 0000: -
00c0 0000 0000 - 00e0 0000 0000: heap
-00e0 0000 0000 - 0100 0000 0000: -
-0100 0000 0000 - 0560 0000 0000: shadow
-0560 0000 0000 - 0760 0000 0000: traces
-0760 0000 0000 - 07ff ffff ffff: -
+00e0 0000 0000 - 2000 0000 0000: -
+2000 0000 0000 - 2380 0000 0000: shadow
+2380 0000 0000 - 3000 0000 0000: -
+3000 0000 0000 - 4000 0000 0000: metainfo (memory blocks and sync objects)
+4000 0000 0000 - 6000 0000 0000: -
+6000 0000 0000 - 6200 0000 0000: traces
+6200 0000 0000 - 8000 0000 0000: -
*/
-#ifndef TSAN_PLATFORM_H
-#define TSAN_PLATFORM_H
+const uptr kMetaShadowBeg = 0x300000000000ull;
+const uptr kMetaShadowEnd = 0x400000000000ull;
+const uptr kTraceMemBeg = 0x600000000000ull;
+const uptr kTraceMemEnd = 0x620000000000ull;
+const uptr kShadowBeg = 0x200000000000ull;
+const uptr kShadowEnd = 0x238000000000ull;
+const uptr kAppMemBeg = 0x000000001000ull;
+const uptr kAppMemEnd = 0x00e000000000ull;
-#include "tsan_defs.h"
-#include "tsan_trace.h"
+ALWAYS_INLINE
+bool IsAppMem(uptr mem) {
+ return mem >= kAppMemBeg && mem < kAppMemEnd;
+}
-#if defined(__LP64__) || defined(_WIN64)
-namespace __tsan {
+ALWAYS_INLINE
+bool IsShadowMem(uptr mem) {
+ return mem >= kShadowBeg && mem <= kShadowEnd;
+}
-#if defined(TSAN_GO)
-static const uptr kLinuxAppMemBeg = 0x000000000000ULL;
-static const uptr kLinuxAppMemEnd = 0x04dfffffffffULL;
-# if SANITIZER_WINDOWS
-static const uptr kLinuxShadowMsk = 0x010000000000ULL;
-# else
-static const uptr kLinuxShadowMsk = 0x200000000000ULL;
-# endif
-// TSAN_COMPAT_SHADOW is intended for COMPAT virtual memory layout,
-// when memory addresses are of the 0x2axxxxxxxxxx form.
-// The option is enabled with 'setarch x86_64 -L'.
-#elif defined(TSAN_COMPAT_SHADOW) && TSAN_COMPAT_SHADOW
-static const uptr kLinuxAppMemBeg = 0x290000000000ULL;
-static const uptr kLinuxAppMemEnd = 0x7fffffffffffULL;
-#else
-static const uptr kLinuxAppMemBeg = 0x7cf000000000ULL;
-static const uptr kLinuxAppMemEnd = 0x7fffffffffffULL;
-#endif
+ALWAYS_INLINE
+bool IsMetaMem(uptr mem) {
+ return mem >= kMetaShadowBeg && mem <= kMetaShadowEnd;
+}
-static const uptr kLinuxAppMemMsk = 0x7c0000000000ULL;
+ALWAYS_INLINE
+uptr MemToShadow(uptr x) {
+ DCHECK(IsAppMem(x));
+ return ((x & ~(kShadowCell - 1)) * kShadowCnt) | kShadowBeg;
+}
-#if SANITIZER_WINDOWS
-const uptr kTraceMemBegin = 0x056000000000ULL;
-#else
-const uptr kTraceMemBegin = 0x600000000000ULL;
-#endif
-const uptr kTraceMemSize = 0x020000000000ULL;
+ALWAYS_INLINE
+u32 *MemToMeta(uptr x) {
+ DCHECK(IsAppMem(x));
+ return (u32*)(((x & ~(kMetaShadowCell - 1)) / \
+ kMetaShadowCell * kMetaShadowSize) | kMetaShadowBeg);
+}
-// This has to be a macro to allow constant initialization of constants below.
-#ifndef TSAN_GO
-#define MemToShadow(addr) \
- (((addr) & ~(kLinuxAppMemMsk | (kShadowCell - 1))) * kShadowCnt)
-#else
-#define MemToShadow(addr) \
- ((((addr) & ~(kShadowCell - 1)) * kShadowCnt) | kLinuxShadowMsk)
-#endif
+ALWAYS_INLINE
+uptr ShadowToMem(uptr s) {
+ CHECK(IsShadowMem(s));
+ return (s & ~kShadowBeg) / kShadowCnt;
+}
+
+static USED uptr UserRegions[] = {
+ kAppMemBeg, kAppMemEnd,
+};
-static const uptr kLinuxShadowBeg = MemToShadow(kLinuxAppMemBeg);
-static const uptr kLinuxShadowEnd =
- MemToShadow(kLinuxAppMemEnd) | 0xff;
+#elif defined(SANITIZER_GO) && SANITIZER_WINDOWS
-static inline bool IsAppMem(uptr mem) {
- return mem >= kLinuxAppMemBeg && mem <= kLinuxAppMemEnd;
+/* Go on windows
+0000 0000 1000 - 0000 1000 0000: executable
+0000 1000 0000 - 00f8 0000 0000: -
+00c0 0000 0000 - 00e0 0000 0000: heap
+00e0 0000 0000 - 0100 0000 0000: -
+0100 0000 0000 - 0380 0000 0000: shadow
+0380 0000 0000 - 0560 0000 0000: -
+0560 0000 0000 - 0760 0000 0000: traces
+0760 0000 0000 - 07d0 0000 0000: metainfo (memory blocks and sync objects)
+07d0 0000 0000 - 8000 0000 0000: -
+*/
+
+const uptr kMetaShadowBeg = 0x076000000000ull;
+const uptr kMetaShadowEnd = 0x07d000000000ull;
+const uptr kTraceMemBeg = 0x056000000000ull;
+const uptr kTraceMemEnd = 0x076000000000ull;
+const uptr kShadowBeg = 0x010000000000ull;
+const uptr kShadowEnd = 0x038000000000ull;
+const uptr kAppMemBeg = 0x000000001000ull;
+const uptr kAppMemEnd = 0x00e000000000ull;
+
+ALWAYS_INLINE
+bool IsAppMem(uptr mem) {
+ return mem >= kAppMemBeg && mem < kAppMemEnd;
}
-static inline bool IsShadowMem(uptr mem) {
- return mem >= kLinuxShadowBeg && mem <= kLinuxShadowEnd;
+ALWAYS_INLINE
+bool IsShadowMem(uptr mem) {
+ return mem >= kShadowBeg && mem <= kShadowEnd;
}
-static inline uptr ShadowToMem(uptr shadow) {
- CHECK(IsShadowMem(shadow));
-#ifdef TSAN_GO
- return (shadow & ~kLinuxShadowMsk) / kShadowCnt;
-#else
- return (shadow / kShadowCnt) | kLinuxAppMemMsk;
-#endif
+ALWAYS_INLINE
+bool IsMetaMem(uptr mem) {
+ return mem >= kMetaShadowBeg && mem <= kMetaShadowEnd;
}
-// For COMPAT mapping returns an alternative address
-// that mapped to the same shadow address.
-// COMPAT mapping is not quite one-to-one.
-static inline uptr AlternativeAddress(uptr addr) {
-#if defined(TSAN_COMPAT_SHADOW) && TSAN_COMPAT_SHADOW
- return (addr & ~kLinuxAppMemMsk) | 0x280000000000ULL;
-#else
- return 0;
-#endif
+ALWAYS_INLINE
+uptr MemToShadow(uptr x) {
+ DCHECK(IsAppMem(x));
+ return ((x & ~(kShadowCell - 1)) * kShadowCnt) | kShadowBeg;
}
-void FlushShadowMemory();
-void WriteMemoryProfile(char *buf, uptr buf_size);
-uptr GetRSS();
+ALWAYS_INLINE
+u32 *MemToMeta(uptr x) {
+ DCHECK(IsAppMem(x));
+ return (u32*)(((x & ~(kMetaShadowCell - 1)) / \
+ kMetaShadowCell * kMetaShadowSize) | kMetaShadowEnd);
+}
+
+ALWAYS_INLINE
+uptr ShadowToMem(uptr s) {
+ CHECK(IsShadowMem(s));
+ // FIXME(dvyukov): this is most likely wrong as the mapping is not bijection.
+ return (x & ~kShadowBeg) / kShadowCnt;
+}
-const char *InitializePlatform();
-void FinalizePlatform();
+static USED uptr UserRegions[] = {
+ kAppMemBeg, kAppMemEnd,
+};
+
+#else
+# error "Unknown platform"
+#endif
// The additional page is to catch shadow stack overflow as paging fault.
-const uptr kTotalTraceSize = (kTraceSize * sizeof(Event) + sizeof(Trace) + 4096
- + 4095) & ~4095;
+// Windows wants 64K alignment for mmaps.
+const uptr kTotalTraceSize = (kTraceSize * sizeof(Event) + sizeof(Trace)
+ + (64 << 10) + (64 << 10) - 1) & ~((64 << 10) - 1);
uptr ALWAYS_INLINE GetThreadTrace(int tid) {
- uptr p = kTraceMemBegin + (uptr)tid * kTotalTraceSize;
- DCHECK_LT(p, kTraceMemBegin + kTraceMemSize);
+ uptr p = kTraceMemBeg + (uptr)tid * kTotalTraceSize;
+ DCHECK_LT(p, kTraceMemEnd);
return p;
}
uptr ALWAYS_INLINE GetThreadTraceHeader(int tid) {
- uptr p = kTraceMemBegin + (uptr)tid * kTotalTraceSize
+ uptr p = kTraceMemBeg + (uptr)tid * kTotalTraceSize
+ kTraceSize * sizeof(Event);
- DCHECK_LT(p, kTraceMemBegin + kTraceMemSize);
+ DCHECK_LT(p, kTraceMemEnd);
return p;
}
-void internal_start_thread(void(*func)(void*), void *arg);
+void InitializePlatform();
+void FlushShadowMemory();
+void WriteMemoryProfile(char *buf, uptr buf_size, uptr nthread, uptr nlive);
+
+void *internal_start_thread(void(*func)(void*), void *arg);
+void internal_join_thread(void *th);
// Says whether the addr relates to a global var.
// Guesses with high probability, may yield both false positives and negatives.
bool IsGlobalVar(uptr addr);
int ExtractResolvFDs(void *state, int *fds, int nfd);
+int ExtractRecvmsgFDs(void *msg, int *fds, int nfd);
-} // namespace __tsan
+int call_pthread_cancel_with_cleanup(int(*fn)(void *c, void *m,
+ void *abstime), void *c, void *m, void *abstime,
+ void(*cleanup)(void *arg), void *arg);
-#else // defined(__LP64__) || defined(_WIN64)
-# error "Only 64-bit is supported"
-#endif
+} // namespace __tsan
#endif // TSAN_PLATFORM_H
diff --git a/lib/tsan/rtl/tsan_platform_linux.cc b/lib/tsan/rtl/tsan_platform_linux.cc
index 906b5dc73be4..4dcfa558529c 100644
--- a/lib/tsan/rtl/tsan_platform_linux.cc
+++ b/lib/tsan/rtl/tsan_platform_linux.cc
@@ -9,17 +9,18 @@
//
// This file is a part of ThreadSanitizer (TSan), a race detector.
//
-// Linux-specific code.
+// Linux- and FreeBSD-specific code.
//===----------------------------------------------------------------------===//
#include "sanitizer_common/sanitizer_platform.h"
-#if SANITIZER_LINUX
+#if SANITIZER_LINUX || SANITIZER_FREEBSD
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_libc.h"
#include "sanitizer_common/sanitizer_procmaps.h"
#include "sanitizer_common/sanitizer_stoptheworld.h"
+#include "sanitizer_common/sanitizer_stackdepot.h"
#include "tsan_platform.h"
#include "tsan_rtl.h"
#include "tsan_flags.h"
@@ -32,8 +33,8 @@
#include <string.h>
#include <stdarg.h>
#include <sys/mman.h>
-#include <sys/prctl.h>
#include <sys/syscall.h>
+#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/resource.h>
@@ -42,9 +43,10 @@
#include <errno.h>
#include <sched.h>
#include <dlfcn.h>
+#if SANITIZER_LINUX
#define __need_res_state
#include <resolv.h>
-#include <malloc.h>
+#endif
#ifdef sa_handler
# undef sa_handler
@@ -54,87 +56,84 @@
# undef sa_sigaction
#endif
-extern "C" struct mallinfo __libc_mallinfo();
+#if SANITIZER_FREEBSD
+extern "C" void *__libc_stack_end;
+void *__libc_stack_end = 0;
+#endif
namespace __tsan {
-const uptr kPageSize = 4096;
+static uptr g_data_start;
+static uptr g_data_end;
-#ifndef TSAN_GO
-ScopedInRtl::ScopedInRtl()
- : thr_(cur_thread()) {
- in_rtl_ = thr_->in_rtl;
- thr_->in_rtl++;
- errno_ = errno;
-}
+const uptr kPageSize = 4096;
-ScopedInRtl::~ScopedInRtl() {
- thr_->in_rtl--;
- errno = errno_;
- CHECK_EQ(in_rtl_, thr_->in_rtl);
-}
+enum {
+ MemTotal = 0,
+ MemShadow = 1,
+ MemMeta = 2,
+ MemFile = 3,
+ MemMmap = 4,
+ MemTrace = 5,
+ MemHeap = 6,
+ MemOther = 7,
+ MemCount = 8,
+};
+
+void FillProfileCallback(uptr p, uptr rss, bool file,
+ uptr *mem, uptr stats_size) {
+ mem[MemTotal] += rss;
+ if (p >= kShadowBeg && p < kShadowEnd)
+ mem[MemShadow] += rss;
+ else if (p >= kMetaShadowBeg && p < kMetaShadowEnd)
+ mem[MemMeta] += rss;
+#ifndef SANITIZER_GO
+ else if (p >= kHeapMemBeg && p < kHeapMemEnd)
+ mem[MemHeap] += rss;
+ else if (p >= kLoAppMemBeg && p < kLoAppMemEnd)
+ mem[file ? MemFile : MemMmap] += rss;
+ else if (p >= kHiAppMemBeg && p < kHiAppMemEnd)
+ mem[file ? MemFile : MemMmap] += rss;
#else
-ScopedInRtl::ScopedInRtl() {
-}
-
-ScopedInRtl::~ScopedInRtl() {
-}
+ else if (p >= kAppMemBeg && p < kAppMemEnd)
+ mem[file ? MemFile : MemMmap] += rss;
#endif
-
-void FillProfileCallback(uptr start, uptr rss, bool file,
- uptr *mem, uptr stats_size) {
- CHECK_EQ(7, stats_size);
- mem[6] += rss; // total
- start >>= 40;
- if (start < 0x10) // shadow
- mem[0] += rss;
- else if (start >= 0x20 && start < 0x30) // compat modules
- mem[file ? 1 : 2] += rss;
- else if (start >= 0x7e) // modules
- mem[file ? 1 : 2] += rss;
- else if (start >= 0x60 && start < 0x62) // traces
- mem[3] += rss;
- else if (start >= 0x7d && start < 0x7e) // heap
- mem[4] += rss;
- else // other
- mem[5] += rss;
-}
-
-void WriteMemoryProfile(char *buf, uptr buf_size) {
- uptr mem[7] = {};
- __sanitizer::GetMemoryProfile(FillProfileCallback, mem, 7);
- char *buf_pos = buf;
- char *buf_end = buf + buf_size;
- buf_pos += internal_snprintf(buf_pos, buf_end - buf_pos,
- "RSS %zd MB: shadow:%zd file:%zd mmap:%zd trace:%zd heap:%zd other:%zd\n",
- mem[6] >> 20, mem[0] >> 20, mem[1] >> 20, mem[2] >> 20,
- mem[3] >> 20, mem[4] >> 20, mem[5] >> 20);
- struct mallinfo mi = __libc_mallinfo();
- buf_pos += internal_snprintf(buf_pos, buf_end - buf_pos,
- "mallinfo: arena=%d mmap=%d fordblks=%d keepcost=%d\n",
- mi.arena >> 20, mi.hblkhd >> 20, mi.fordblks >> 20, mi.keepcost >> 20);
+ else if (p >= kTraceMemBeg && p < kTraceMemEnd)
+ mem[MemTrace] += rss;
+ else
+ mem[MemOther] += rss;
}
-uptr GetRSS() {
- uptr mem[7] = {};
+void WriteMemoryProfile(char *buf, uptr buf_size, uptr nthread, uptr nlive) {
+ uptr mem[MemCount] = {};
__sanitizer::GetMemoryProfile(FillProfileCallback, mem, 7);
- return mem[6];
+ StackDepotStats *stacks = StackDepotGetStats();
+ internal_snprintf(buf, buf_size,
+ "RSS %zd MB: shadow:%zd meta:%zd file:%zd mmap:%zd"
+ " trace:%zd heap:%zd other:%zd stacks=%zd[%zd] nthr=%zd/%zd\n",
+ mem[MemTotal] >> 20, mem[MemShadow] >> 20, mem[MemMeta] >> 20,
+ mem[MemFile] >> 20, mem[MemMmap] >> 20, mem[MemTrace] >> 20,
+ mem[MemHeap] >> 20, mem[MemOther] >> 20,
+ stacks->allocated >> 20, stacks->n_uniq_ids,
+ nlive, nthread);
}
-
+#if SANITIZER_LINUX
void FlushShadowMemoryCallback(
const SuspendedThreadsList &suspended_threads_list,
void *argument) {
- FlushUnneededShadowMemory(kLinuxShadowBeg, kLinuxShadowEnd - kLinuxShadowBeg);
+ FlushUnneededShadowMemory(kShadowBeg, kShadowEnd - kShadowBeg);
}
+#endif
void FlushShadowMemory() {
+#if SANITIZER_LINUX
StopTheWorld(FlushShadowMemoryCallback, 0);
+#endif
}
-#ifndef TSAN_GO
+#ifndef SANITIZER_GO
static void ProtectRange(uptr beg, uptr end) {
- ScopedInRtl in_rtl;
CHECK_LE(beg, end);
if (beg == end)
return;
@@ -144,9 +143,7 @@ static void ProtectRange(uptr beg, uptr end) {
Die();
}
}
-#endif
-#ifndef TSAN_GO
// Mark shadow for .rodata sections with the special kShadowRodata marker.
// Accesses to .rodata can't race, so this saves time, memory and trace space.
static void MapRodata() {
@@ -160,17 +157,19 @@ static void MapRodata() {
#endif
if (tmpdir == 0)
return;
- char filename[256];
- internal_snprintf(filename, sizeof(filename), "%s/tsan.rodata.%d",
+ char name[256];
+ internal_snprintf(name, sizeof(name), "%s/tsan.rodata.%d",
tmpdir, (int)internal_getpid());
- uptr openrv = internal_open(filename, O_RDWR | O_CREAT | O_EXCL, 0600);
+ uptr openrv = internal_open(name, O_RDWR | O_CREAT | O_EXCL, 0600);
if (internal_iserror(openrv))
return;
+ internal_unlink(name); // Unlink it now, so that we can reuse the buffer.
fd_t fd = openrv;
// Fill the file with kShadowRodata.
const uptr kMarkerSize = 512 * 1024 / sizeof(u64);
InternalScopedBuffer<u64> marker(kMarkerSize);
- for (u64 *p = marker.data(); p < marker.data() + kMarkerSize; p++)
+ // volatile to prevent insertion of memset
+ for (volatile u64 *p = marker.data(); p < marker.data() + kMarkerSize; p++)
*p = kShadowRodata;
internal_write(fd, marker.data(), marker.size());
// Map the file into memory.
@@ -178,13 +177,12 @@ static void MapRodata() {
MAP_PRIVATE | MAP_ANONYMOUS, fd, 0);
if (internal_iserror(page)) {
internal_close(fd);
- internal_unlink(filename);
return;
}
// Map the file into shadow of .rodata sections.
MemoryMappingLayout proc_maps(/*cache_enabled*/true);
uptr start, end, offset, prot;
- char name[128];
+ // Reusing the buffer 'name'.
while (proc_maps.Next(&start, &end, &offset, name, ARRAY_SIZE(name), &prot)) {
if (name[0] != 0 && name[0] != '['
&& (prot & MemoryMappingLayout::kProtectionRead)
@@ -201,66 +199,63 @@ static void MapRodata() {
}
}
internal_close(fd);
- internal_unlink(filename);
}
void InitializeShadowMemory() {
- uptr shadow = (uptr)MmapFixedNoReserve(kLinuxShadowBeg,
- kLinuxShadowEnd - kLinuxShadowBeg);
- if (shadow != kLinuxShadowBeg) {
+ // Map memory shadow.
+ uptr shadow = (uptr)MmapFixedNoReserve(kShadowBeg,
+ kShadowEnd - kShadowBeg);
+ if (shadow != kShadowBeg) {
Printf("FATAL: ThreadSanitizer can not mmap the shadow memory\n");
Printf("FATAL: Make sure to compile with -fPIE and "
- "to link with -pie (%p, %p).\n", shadow, kLinuxShadowBeg);
+ "to link with -pie (%p, %p).\n", shadow, kShadowBeg);
Die();
}
- const uptr kClosedLowBeg = 0x200000;
- const uptr kClosedLowEnd = kLinuxShadowBeg - 1;
- const uptr kClosedMidBeg = kLinuxShadowEnd + 1;
- const uptr kClosedMidEnd = min(kLinuxAppMemBeg, kTraceMemBegin);
- ProtectRange(kClosedLowBeg, kClosedLowEnd);
- ProtectRange(kClosedMidBeg, kClosedMidEnd);
- DPrintf("kClosedLow %zx-%zx (%zuGB)\n",
- kClosedLowBeg, kClosedLowEnd, (kClosedLowEnd - kClosedLowBeg) >> 30);
- DPrintf("kLinuxShadow %zx-%zx (%zuGB)\n",
- kLinuxShadowBeg, kLinuxShadowEnd,
- (kLinuxShadowEnd - kLinuxShadowBeg) >> 30);
- DPrintf("kClosedMid %zx-%zx (%zuGB)\n",
- kClosedMidBeg, kClosedMidEnd, (kClosedMidEnd - kClosedMidBeg) >> 30);
- DPrintf("kLinuxAppMem %zx-%zx (%zuGB)\n",
- kLinuxAppMemBeg, kLinuxAppMemEnd,
- (kLinuxAppMemEnd - kLinuxAppMemBeg) >> 30);
- DPrintf("stack %zx\n", (uptr)&shadow);
-
- MapRodata();
-}
+ // This memory range is used for thread stacks and large user mmaps.
+ // Frequently a thread uses only a small part of stack and similarly
+ // a program uses a small part of large mmap. On some programs
+ // we see 20% memory usage reduction without huge pages for this range.
+#ifdef MADV_NOHUGEPAGE
+ madvise((void*)MemToShadow(0x7f0000000000ULL),
+ 0x10000000000ULL * kShadowMultiplier, MADV_NOHUGEPAGE);
#endif
-
-static uptr g_data_start;
-static uptr g_data_end;
-
-#ifndef TSAN_GO
-static void CheckPIE() {
- // Ensure that the binary is indeed compiled with -pie.
- MemoryMappingLayout proc_maps(true);
- uptr start, end;
- if (proc_maps.Next(&start, &end,
- /*offset*/0, /*filename*/0, /*filename_size*/0,
- /*protection*/0)) {
- if ((u64)start < kLinuxAppMemBeg) {
- Printf("FATAL: ThreadSanitizer can not mmap the shadow memory ("
- "something is mapped at 0x%zx < 0x%zx)\n",
- start, kLinuxAppMemBeg);
- Printf("FATAL: Make sure to compile with -fPIE"
- " and to link with -pie.\n");
- Die();
- }
+ DPrintf("memory shadow: %zx-%zx (%zuGB)\n",
+ kShadowBeg, kShadowEnd,
+ (kShadowEnd - kShadowBeg) >> 30);
+
+ // Map meta shadow.
+ uptr meta_size = kMetaShadowEnd - kMetaShadowBeg;
+ uptr meta = (uptr)MmapFixedNoReserve(kMetaShadowBeg, meta_size);
+ if (meta != kMetaShadowBeg) {
+ Printf("FATAL: ThreadSanitizer can not mmap the shadow memory\n");
+ Printf("FATAL: Make sure to compile with -fPIE and "
+ "to link with -pie (%p, %p).\n", meta, kMetaShadowBeg);
+ Die();
}
+ DPrintf("meta shadow: %zx-%zx (%zuGB)\n",
+ meta, meta + meta_size, meta_size >> 30);
+
+ MapRodata();
}
static void InitDataSeg() {
MemoryMappingLayout proc_maps(true);
uptr start, end, offset;
char name[128];
+#if SANITIZER_FREEBSD
+ // On FreeBSD BSS is usually the last block allocated within the
+ // low range and heap is the last block allocated within the range
+ // 0x800000000-0x8ffffffff.
+ while (proc_maps.Next(&start, &end, &offset, name, ARRAY_SIZE(name),
+ /*protection*/ 0)) {
+ DPrintf("%p-%p %p %s\n", start, end, offset, name);
+ if ((start & 0xffff00000000ULL) == 0 && (end & 0xffff00000000ULL) == 0 &&
+ name[0] == '\0') {
+ g_data_start = start;
+ g_data_end = end;
+ }
+ }
+#else
bool prev_is_data = false;
while (proc_maps.Next(&start, &end, &offset, name, ARRAY_SIZE(name),
/*protection*/ 0)) {
@@ -276,34 +271,42 @@ static void InitDataSeg() {
g_data_end = end;
prev_is_data = is_data;
}
+#endif
DPrintf("guessed data_start=%p data_end=%p\n", g_data_start, g_data_end);
CHECK_LT(g_data_start, g_data_end);
CHECK_GE((uptr)&g_data_start, g_data_start);
CHECK_LT((uptr)&g_data_start, g_data_end);
}
-#endif // #ifndef TSAN_GO
-
-static rlim_t getlim(int res) {
- rlimit rlim;
- CHECK_EQ(0, getrlimit(res, &rlim));
- return rlim.rlim_cur;
-}
+static void CheckAndProtect() {
+ // Ensure that the binary is indeed compiled with -pie.
+ MemoryMappingLayout proc_maps(true);
+ uptr p, end;
+ while (proc_maps.Next(&p, &end, 0, 0, 0, 0)) {
+ if (IsAppMem(p))
+ continue;
+ if (p >= kHeapMemEnd &&
+ p < kHeapMemEnd + PrimaryAllocator::AdditionalSize())
+ continue;
+ if (p >= 0xf000000000000000ull) // vdso
+ break;
+ Printf("FATAL: ThreadSanitizer: unexpected memory mapping %p-%p\n", p, end);
+ Die();
+ }
-static void setlim(int res, rlim_t lim) {
- // The following magic is to prevent clang from replacing it with memset.
- volatile rlimit rlim;
- rlim.rlim_cur = lim;
- rlim.rlim_max = lim;
- setrlimit(res, (rlimit*)&rlim);
+ ProtectRange(kLoAppMemEnd, kShadowBeg);
+ ProtectRange(kShadowEnd, kMetaShadowBeg);
+ ProtectRange(kMetaShadowEnd, kTraceMemBeg);
+ // Memory for traces is mapped lazily in MapThreadTrace.
+ // Protect the whole range for now, so that user does not map something here.
+ ProtectRange(kTraceMemBeg, kTraceMemEnd);
+ ProtectRange(kTraceMemEnd, kHeapMemBeg);
+ ProtectRange(kHeapMemEnd + PrimaryAllocator::AdditionalSize(), kHiAppMemBeg);
}
+#endif // #ifndef SANITIZER_GO
-const char *InitializePlatform() {
- void *p = 0;
- if (sizeof(p) == 8) {
- // Disable core dumps, dumping of 16TB usually takes a bit long.
- setlim(RLIMIT_CORE, 0);
- }
+void InitializePlatform() {
+ DisableCoreDumperIfNecessary();
// Go maps shadow memory lazily and works fine with limited address space.
// Unlimited stack is not a problem as well, because the executable
@@ -313,41 +316,44 @@ const char *InitializePlatform() {
// TSan doesn't play well with unlimited stack size (as stack
// overlaps with shadow memory). If we detect unlimited stack size,
// we re-exec the program with limited stack size as a best effort.
- if (getlim(RLIMIT_STACK) == (rlim_t)-1) {
+ if (StackSizeIsUnlimited()) {
const uptr kMaxStackSize = 32 * 1024 * 1024;
- Report("WARNING: Program is run with unlimited stack size, which "
- "wouldn't work with ThreadSanitizer.\n");
- Report("Re-execing with stack size limited to %zd bytes.\n",
- kMaxStackSize);
+ VReport(1, "Program is run with unlimited stack size, which wouldn't "
+ "work with ThreadSanitizer.\n"
+ "Re-execing with stack size limited to %zd bytes.\n",
+ kMaxStackSize);
SetStackSizeLimitInBytes(kMaxStackSize);
reexec = true;
}
- if (getlim(RLIMIT_AS) != (rlim_t)-1) {
+ if (!AddressSpaceIsUnlimited()) {
Report("WARNING: Program is run with limited virtual address space,"
" which wouldn't work with ThreadSanitizer.\n");
Report("Re-execing with unlimited virtual address space.\n");
- setlim(RLIMIT_AS, -1);
+ SetAddressSpaceUnlimited();
reexec = true;
}
if (reexec)
ReExec();
}
-#ifndef TSAN_GO
- CheckPIE();
+#ifndef SANITIZER_GO
+ CheckAndProtect();
InitTlsSize();
InitDataSeg();
#endif
- return GetEnv(kTsanOptionsEnv);
}
bool IsGlobalVar(uptr addr) {
return g_data_start && addr >= g_data_start && addr < g_data_end;
}
-#ifndef TSAN_GO
+#ifndef SANITIZER_GO
+// Extract file descriptors passed to glibc internal __res_iclose function.
+// This is required to properly "close" the fds, because we do not see internal
+// closes within glibc. The code is a pure hack.
int ExtractResolvFDs(void *state, int *fds, int nfd) {
+#if SANITIZER_LINUX
int cnt = 0;
__res_state *statp = (__res_state*)state;
for (int i = 0; i < MAXNS && cnt < nfd; i++) {
@@ -355,10 +361,44 @@ int ExtractResolvFDs(void *state, int *fds, int nfd) {
fds[cnt++] = statp->_u._ext.nssocks[i];
}
return cnt;
-}
+#else
+ return 0;
#endif
+}
+
+// Extract file descriptors passed via UNIX domain sockets.
+// This is requried to properly handle "open" of these fds.
+// see 'man recvmsg' and 'man 3 cmsg'.
+int ExtractRecvmsgFDs(void *msgp, int *fds, int nfd) {
+ int res = 0;
+ msghdr *msg = (msghdr*)msgp;
+ struct cmsghdr *cmsg = CMSG_FIRSTHDR(msg);
+ for (; cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
+ if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS)
+ continue;
+ int n = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(fds[0]);
+ for (int i = 0; i < n; i++) {
+ fds[res++] = ((int*)CMSG_DATA(cmsg))[i];
+ if (res == nfd)
+ return res;
+ }
+ }
+ return res;
+}
+int call_pthread_cancel_with_cleanup(int(*fn)(void *c, void *m,
+ void *abstime), void *c, void *m, void *abstime,
+ void(*cleanup)(void *arg), void *arg) {
+ // pthread_cleanup_push/pop are hardcore macros mess.
+ // We can't intercept nor call them w/o including pthread.h.
+ int res;
+ pthread_cleanup_push(cleanup, arg);
+ res = fn(c, m, abstime);
+ pthread_cleanup_pop(0);
+ return res;
+}
+#endif
} // namespace __tsan
-#endif // SANITIZER_LINUX
+#endif // SANITIZER_LINUX || SANITIZER_FREEBSD
diff --git a/lib/tsan/rtl/tsan_platform_mac.cc b/lib/tsan/rtl/tsan_platform_mac.cc
index 99d4533a4fa2..15b9f9d2cb19 100644
--- a/lib/tsan/rtl/tsan_platform_mac.cc
+++ b/lib/tsan/rtl/tsan_platform_mac.cc
@@ -40,12 +40,6 @@
namespace __tsan {
-ScopedInRtl::ScopedInRtl() {
-}
-
-ScopedInRtl::~ScopedInRtl() {
-}
-
uptr GetShadowMemoryConsumption() {
return 0;
}
@@ -53,42 +47,45 @@ uptr GetShadowMemoryConsumption() {
void FlushShadowMemory() {
}
-#ifndef TSAN_GO
+void WriteMemoryProfile(char *buf, uptr buf_size, uptr nthread, uptr nlive) {
+}
+
+#ifndef SANITIZER_GO
void InitializeShadowMemory() {
- uptr shadow = (uptr)MmapFixedNoReserve(kLinuxShadowBeg,
- kLinuxShadowEnd - kLinuxShadowBeg);
- if (shadow != kLinuxShadowBeg) {
+ uptr shadow = (uptr)MmapFixedNoReserve(kShadowBeg,
+ kShadowEnd - kShadowBeg);
+ if (shadow != kShadowBeg) {
Printf("FATAL: ThreadSanitizer can not mmap the shadow memory\n");
Printf("FATAL: Make sure to compile with -fPIE and "
"to link with -pie.\n");
Die();
}
- DPrintf("kLinuxShadow %zx-%zx (%zuGB)\n",
- kLinuxShadowBeg, kLinuxShadowEnd,
- (kLinuxShadowEnd - kLinuxShadowBeg) >> 30);
- DPrintf("kLinuxAppMem %zx-%zx (%zuGB)\n",
- kLinuxAppMemBeg, kLinuxAppMemEnd,
- (kLinuxAppMemEnd - kLinuxAppMemBeg) >> 30);
+ DPrintf("kShadow %zx-%zx (%zuGB)\n",
+ kShadowBeg, kShadowEnd,
+ (kShadowEnd - kShadowBeg) >> 30);
+ DPrintf("kAppMem %zx-%zx (%zuGB)\n",
+ kAppMemBeg, kAppMemEnd,
+ (kAppMemEnd - kAppMemBeg) >> 30);
}
#endif
-const char *InitializePlatform() {
- void *p = 0;
- if (sizeof(p) == 8) {
- // Disable core dumps, dumping of 16TB usually takes a bit long.
- // The following magic is to prevent clang from replacing it with memset.
- volatile rlimit lim;
- lim.rlim_cur = 0;
- lim.rlim_max = 0;
- setrlimit(RLIMIT_CORE, (rlimit*)&lim);
- }
-
- return GetEnv(kTsanOptionsEnv);
+void InitializePlatform() {
+ DisableCoreDumperIfNecessary();
}
-void FinalizePlatform() {
- fflush(0);
+#ifndef SANITIZER_GO
+int call_pthread_cancel_with_cleanup(int(*fn)(void *c, void *m,
+ void *abstime), void *c, void *m, void *abstime,
+ void(*cleanup)(void *arg), void *arg) {
+ // pthread_cleanup_push/pop are hardcore macros mess.
+ // We can't intercept nor call them w/o including pthread.h.
+ int res;
+ pthread_cleanup_push(cleanup, arg);
+ res = fn(c, m, abstime);
+ pthread_cleanup_pop(0);
+ return res;
}
+#endif
} // namespace __tsan
diff --git a/lib/tsan/rtl/tsan_platform_windows.cc b/lib/tsan/rtl/tsan_platform_windows.cc
index 711db72ce684..cfbe77da2c07 100644
--- a/lib/tsan/rtl/tsan_platform_windows.cc
+++ b/lib/tsan/rtl/tsan_platform_windows.cc
@@ -21,12 +21,6 @@
namespace __tsan {
-ScopedInRtl::ScopedInRtl() {
-}
-
-ScopedInRtl::~ScopedInRtl() {
-}
-
uptr GetShadowMemoryConsumption() {
return 0;
}
@@ -34,12 +28,10 @@ uptr GetShadowMemoryConsumption() {
void FlushShadowMemory() {
}
-const char *InitializePlatform() {
- return GetEnv(kTsanOptionsEnv);
+void WriteMemoryProfile(char *buf, uptr buf_size, uptr nthread, uptr nlive) {
}
-void FinalizePlatform() {
- fflush(0);
+void InitializePlatform() {
}
} // namespace __tsan
diff --git a/lib/tsan/rtl/tsan_report.cc b/lib/tsan/rtl/tsan_report.cc
index 66307ae09dcd..c22f12a1bfa5 100644
--- a/lib/tsan/rtl/tsan_report.cc
+++ b/lib/tsan/rtl/tsan_report.cc
@@ -13,13 +13,31 @@
#include "tsan_report.h"
#include "tsan_platform.h"
#include "tsan_rtl.h"
+#include "sanitizer_common/sanitizer_placement_new.h"
#include "sanitizer_common/sanitizer_report_decorator.h"
+#include "sanitizer_common/sanitizer_stacktrace_printer.h"
namespace __tsan {
-class Decorator: private __sanitizer::AnsiColorDecorator {
+ReportStack::ReportStack() : frames(nullptr), suppressable(false) {}
+
+ReportStack *ReportStack::New() {
+ void *mem = internal_alloc(MBlockReportStack, sizeof(ReportStack));
+ return new(mem) ReportStack();
+}
+
+ReportLocation::ReportLocation(ReportLocationType type)
+ : type(type), global(), heap_chunk_start(0), heap_chunk_size(0), tid(0),
+ fd(0), suppressable(false), stack(nullptr) {}
+
+ReportLocation *ReportLocation::New(ReportLocationType type) {
+ void *mem = internal_alloc(MBlockReportStack, sizeof(ReportLocation));
+ return new(mem) ReportLocation(type);
+}
+
+class Decorator: public __sanitizer::SanitizerCommonDecorator {
public:
- Decorator() : __sanitizer::AnsiColorDecorator(PrintsToTtyCached()) { }
+ Decorator() : SanitizerCommonDecorator() { }
const char *Warning() { return Red(); }
const char *EndWarning() { return Default(); }
const char *Access() { return Blue(); }
@@ -40,6 +58,7 @@ ReportDesc::ReportDesc()
, locs(MBlockReportLoc)
, mutexes(MBlockReportMutex)
, threads(MBlockReportThread)
+ , unique_tids(MBlockReportThread)
, sleep()
, count() {
}
@@ -52,7 +71,7 @@ ReportDesc::~ReportDesc() {
// FIXME(dvyukov): it must be leaking a lot of memory.
}
-#ifndef TSAN_GO
+#ifndef SANITIZER_GO
const int kThreadBufSize = 32;
const char *thread_name(char *buf, int tid) {
@@ -69,30 +88,40 @@ static const char *ReportTypeString(ReportType typ) {
return "data race on vptr (ctor/dtor vs virtual call)";
if (typ == ReportTypeUseAfterFree)
return "heap-use-after-free";
+ if (typ == ReportTypeVptrUseAfterFree)
+ return "heap-use-after-free (virtual call vs free)";
if (typ == ReportTypeThreadLeak)
return "thread leak";
if (typ == ReportTypeMutexDestroyLocked)
return "destroy of a locked mutex";
+ if (typ == ReportTypeMutexDoubleLock)
+ return "double lock of a mutex";
+ if (typ == ReportTypeMutexBadUnlock)
+ return "unlock of an unlocked mutex (or by a wrong thread)";
+ if (typ == ReportTypeMutexBadReadLock)
+ return "read lock of a write locked mutex";
+ if (typ == ReportTypeMutexBadReadUnlock)
+ return "read unlock of a write locked mutex";
if (typ == ReportTypeSignalUnsafe)
return "signal-unsafe call inside of a signal";
if (typ == ReportTypeErrnoInSignal)
return "signal handler spoils errno";
+ if (typ == ReportTypeDeadlock)
+ return "lock-order-inversion (potential deadlock)";
return "";
}
void PrintStack(const ReportStack *ent) {
- if (ent == 0) {
+ if (ent == 0 || ent->frames == 0) {
Printf(" [failed to restore the stack]\n\n");
return;
}
- for (int i = 0; ent; ent = ent->next, i++) {
- Printf(" #%d %s %s:%d", i, ent->func, ent->file, ent->line);
- if (ent->col)
- Printf(":%d", ent->col);
- if (ent->module && ent->offset)
- Printf(" (%s+%p)\n", ent->module, (void*)ent->offset);
- else
- Printf(" (%p)\n", (void*)ent->pc);
+ SymbolizedStack *frame = ent->frames;
+ for (int i = 0; frame && frame->info.address; frame = frame->next, i++) {
+ InternalScopedString res(2 * GetPageSizeCached());
+ RenderFrame(&res, common_flags()->stack_trace_format, i, frame->info,
+ common_flags()->strip_path_prefix, "__interceptor_");
+ Printf("%s\n", res.data());
}
Printf("\n");
}
@@ -134,12 +163,15 @@ static void PrintLocation(const ReportLocation *loc) {
bool print_stack = false;
Printf("%s", d.Location());
if (loc->type == ReportLocationGlobal) {
+ const DataInfo &global = loc->global;
Printf(" Location is global '%s' of size %zu at %p (%s+%p)\n\n",
- loc->name, loc->size, loc->addr, loc->module, loc->offset);
+ global.name, global.size, global.start,
+ StripModuleName(global.module), global.module_offset);
} else if (loc->type == ReportLocationHeap) {
char thrbuf[kThreadBufSize];
Printf(" Location is heap block of size %zu at %p allocated by %s:\n",
- loc->size, loc->addr, thread_name(thrbuf, loc->tid));
+ loc->heap_chunk_size, loc->heap_chunk_start,
+ thread_name(thrbuf, loc->tid));
print_stack = true;
} else if (loc->type == ReportLocationStack) {
Printf(" Location is stack of %s.\n\n", thread_name(thrbuf, loc->tid));
@@ -155,6 +187,17 @@ static void PrintLocation(const ReportLocation *loc) {
PrintStack(loc->stack);
}
+static void PrintMutexShort(const ReportMutex *rm, const char *after) {
+ Decorator d;
+ Printf("%sM%zd%s%s", d.Mutex(), rm->id, d.EndMutex(), after);
+}
+
+static void PrintMutexShortWithAddress(const ReportMutex *rm,
+ const char *after) {
+ Decorator d;
+ Printf("%sM%zd (%p)%s%s", d.Mutex(), rm->id, rm->addr, d.EndMutex(), after);
+}
+
static void PrintMutex(const ReportMutex *rm) {
Decorator d;
if (rm->destroyed) {
@@ -163,7 +206,7 @@ static void PrintMutex(const ReportMutex *rm) {
Printf("%s", d.EndMutex());
} else {
Printf("%s", d.Mutex());
- Printf(" Mutex M%llu created at:\n", rm->id);
+ Printf(" Mutex M%llu (%p) created at:\n", rm->id, rm->addr);
Printf("%s", d.EndMutex());
PrintStack(rm->stack);
}
@@ -208,10 +251,20 @@ static ReportStack *ChooseSummaryStack(const ReportDesc *rep) {
return 0;
}
-ReportStack *SkipTsanInternalFrames(ReportStack *ent) {
- while (FrameIsInternal(ent) && ent->next)
- ent = ent->next;
- return ent;
+static bool FrameIsInternal(const SymbolizedStack *frame) {
+ if (frame == 0)
+ return false;
+ const char *file = frame->info.file;
+ return file != 0 &&
+ (internal_strstr(file, "tsan_interceptors.cc") ||
+ internal_strstr(file, "sanitizer_common_interceptors.inc") ||
+ internal_strstr(file, "tsan_interface_"));
+}
+
+static SymbolizedStack *SkipTsanInternalFrames(SymbolizedStack *frames) {
+ while (FrameIsInternal(frames) && frames->next)
+ frames = frames->next;
+ return frames;
}
void PrintReport(const ReportDesc *rep) {
@@ -223,10 +276,42 @@ void PrintReport(const ReportDesc *rep) {
(int)internal_getpid());
Printf("%s", d.EndWarning());
- for (uptr i = 0; i < rep->stacks.Size(); i++) {
- if (i)
- Printf(" and:\n");
- PrintStack(rep->stacks[i]);
+ if (rep->typ == ReportTypeDeadlock) {
+ char thrbuf[kThreadBufSize];
+ Printf(" Cycle in lock order graph: ");
+ for (uptr i = 0; i < rep->mutexes.Size(); i++)
+ PrintMutexShortWithAddress(rep->mutexes[i], " => ");
+ PrintMutexShort(rep->mutexes[0], "\n\n");
+ CHECK_GT(rep->mutexes.Size(), 0U);
+ CHECK_EQ(rep->mutexes.Size() * (flags()->second_deadlock_stack ? 2 : 1),
+ rep->stacks.Size());
+ for (uptr i = 0; i < rep->mutexes.Size(); i++) {
+ Printf(" Mutex ");
+ PrintMutexShort(rep->mutexes[(i + 1) % rep->mutexes.Size()],
+ " acquired here while holding mutex ");
+ PrintMutexShort(rep->mutexes[i], " in ");
+ Printf("%s", d.ThreadDescription());
+ Printf("%s:\n", thread_name(thrbuf, rep->unique_tids[i]));
+ Printf("%s", d.EndThreadDescription());
+ if (flags()->second_deadlock_stack) {
+ PrintStack(rep->stacks[2*i]);
+ Printf(" Mutex ");
+ PrintMutexShort(rep->mutexes[i],
+ " previously acquired by the same thread here:\n");
+ PrintStack(rep->stacks[2*i+1]);
+ } else {
+ PrintStack(rep->stacks[i]);
+ if (i == 0)
+ Printf(" Hint: use TSAN_OPTIONS=second_deadlock_stack=1 "
+ "to get more informative warning message\n\n");
+ }
+ }
+ } else {
+ for (uptr i = 0; i < rep->stacks.Size(); i++) {
+ if (i)
+ Printf(" and:\n");
+ PrintStack(rep->stacks[i]);
+ }
}
for (uptr i = 0; i < rep->mops.Size(); i++)
@@ -238,8 +323,10 @@ void PrintReport(const ReportDesc *rep) {
for (uptr i = 0; i < rep->locs.Size(); i++)
PrintLocation(rep->locs[i]);
- for (uptr i = 0; i < rep->mutexes.Size(); i++)
- PrintMutex(rep->mutexes[i]);
+ if (rep->typ != ReportTypeDeadlock) {
+ for (uptr i = 0; i < rep->mutexes.Size(); i++)
+ PrintMutex(rep->mutexes[i]);
+ }
for (uptr i = 0; i < rep->threads.Size(); i++)
PrintThread(rep->threads[i]);
@@ -247,24 +334,30 @@ void PrintReport(const ReportDesc *rep) {
if (rep->typ == ReportTypeThreadLeak && rep->count > 1)
Printf(" And %d more similar thread leaks.\n\n", rep->count - 1);
- if (ReportStack *ent = SkipTsanInternalFrames(ChooseSummaryStack(rep)))
- ReportErrorSummary(rep_typ_str, ent->file, ent->line, ent->func);
+ if (ReportStack *stack = ChooseSummaryStack(rep)) {
+ if (SymbolizedStack *frame = SkipTsanInternalFrames(stack->frames)) {
+ const AddressInfo &info = frame->info;
+ ReportErrorSummary(rep_typ_str, info.file, info.line, info.function);
+ }
+ }
Printf("==================\n");
}
-#else // #ifndef TSAN_GO
+#else // #ifndef SANITIZER_GO
const int kMainThreadId = 1;
void PrintStack(const ReportStack *ent) {
- if (ent == 0) {
+ if (ent == 0 || ent->frames == 0) {
Printf(" [failed to restore the stack]\n");
return;
}
- for (int i = 0; ent; ent = ent->next, i++) {
- Printf(" %s()\n %s:%d +0x%zx\n",
- ent->func, ent->file, ent->line, (void*)ent->offset);
+ SymbolizedStack *frame = ent->frames;
+ for (int i = 0; frame; frame = frame->next, i++) {
+ const AddressInfo &info = frame->info;
+ Printf(" %s()\n %s:%d +0x%zx\n", info.function, info.file, info.line,
+ (void *)info.module_offset);
}
}
@@ -291,11 +384,26 @@ static void PrintThread(const ReportThread *rt) {
void PrintReport(const ReportDesc *rep) {
Printf("==================\n");
- Printf("WARNING: DATA RACE");
- for (uptr i = 0; i < rep->mops.Size(); i++)
- PrintMop(rep->mops[i], i == 0);
- for (uptr i = 0; i < rep->threads.Size(); i++)
- PrintThread(rep->threads[i]);
+ if (rep->typ == ReportTypeRace) {
+ Printf("WARNING: DATA RACE");
+ for (uptr i = 0; i < rep->mops.Size(); i++)
+ PrintMop(rep->mops[i], i == 0);
+ for (uptr i = 0; i < rep->threads.Size(); i++)
+ PrintThread(rep->threads[i]);
+ } else if (rep->typ == ReportTypeDeadlock) {
+ Printf("WARNING: DEADLOCK\n");
+ for (uptr i = 0; i < rep->mutexes.Size(); i++) {
+ Printf("Goroutine %d lock mutex %d while holding mutex %d:\n",
+ 999, rep->mutexes[i]->id,
+ rep->mutexes[(i+1) % rep->mutexes.Size()]->id);
+ PrintStack(rep->stacks[2*i]);
+ Printf("\n");
+ Printf("Mutex %d was previously locked here:\n",
+ rep->mutexes[(i+1) % rep->mutexes.Size()]->id);
+ PrintStack(rep->stacks[2*i + 1]);
+ Printf("\n");
+ }
+ }
Printf("==================\n");
}
diff --git a/lib/tsan/rtl/tsan_report.h b/lib/tsan/rtl/tsan_report.h
index b2ce0dd66a27..3e344a048e43 100644
--- a/lib/tsan/rtl/tsan_report.h
+++ b/lib/tsan/rtl/tsan_report.h
@@ -13,6 +13,7 @@
#ifndef TSAN_REPORT_H
#define TSAN_REPORT_H
+#include "sanitizer_common/sanitizer_symbolizer.h"
#include "tsan_defs.h"
#include "tsan_vector.h"
@@ -22,21 +23,25 @@ enum ReportType {
ReportTypeRace,
ReportTypeVptrRace,
ReportTypeUseAfterFree,
+ ReportTypeVptrUseAfterFree,
ReportTypeThreadLeak,
ReportTypeMutexDestroyLocked,
+ ReportTypeMutexDoubleLock,
+ ReportTypeMutexBadUnlock,
+ ReportTypeMutexBadReadLock,
+ ReportTypeMutexBadReadUnlock,
ReportTypeSignalUnsafe,
- ReportTypeErrnoInSignal
+ ReportTypeErrnoInSignal,
+ ReportTypeDeadlock
};
struct ReportStack {
- ReportStack *next;
- char *module;
- uptr offset;
- uptr pc;
- char *func;
- char *file;
- int line;
- int col;
+ SymbolizedStack *frames;
+ bool suppressable;
+ static ReportStack *New();
+
+ private:
+ ReportStack();
};
struct ReportMopMutex {
@@ -66,16 +71,17 @@ enum ReportLocationType {
struct ReportLocation {
ReportLocationType type;
- uptr addr;
- uptr size;
- char *module;
- uptr offset;
+ DataInfo global;
+ uptr heap_chunk_start;
+ uptr heap_chunk_size;
int tid;
int fd;
- char *name;
- char *file;
- int line;
+ bool suppressable;
ReportStack *stack;
+
+ static ReportLocation *New(ReportLocationType type);
+ private:
+ explicit ReportLocation(ReportLocationType type);
};
struct ReportThread {
@@ -89,6 +95,7 @@ struct ReportThread {
struct ReportMutex {
u64 id;
+ uptr addr;
bool destroyed;
ReportStack *stack;
};
@@ -101,6 +108,7 @@ class ReportDesc {
Vector<ReportLocation*> locs;
Vector<ReportMutex*> mutexes;
Vector<ReportThread*> threads;
+ Vector<int> unique_tids;
ReportStack *sleep;
int count;
diff --git a/lib/tsan/rtl/tsan_rtl.cc b/lib/tsan/rtl/tsan_rtl.cc
index 1f66d29a741c..7cb7008e2980 100644
--- a/lib/tsan/rtl/tsan_rtl.cc
+++ b/lib/tsan/rtl/tsan_rtl.cc
@@ -25,6 +25,16 @@
#include "tsan_suppressions.h"
#include "tsan_symbolize.h"
+#ifdef __SSE3__
+// <emmintrin.h> transitively includes <stdlib.h>,
+// and it's prohibited to include std headers into tsan runtime.
+// So we do this dirty trick.
+#define _MM_MALLOC_H_INCLUDED
+#define __MM_MALLOC_H
+#include <emmintrin.h>
+typedef __m128i m128;
+#endif
+
volatile int __tsan_resumed = 0;
extern "C" void __tsan_resume() {
@@ -33,25 +43,25 @@ extern "C" void __tsan_resume() {
namespace __tsan {
-#ifndef TSAN_GO
+#ifndef SANITIZER_GO
THREADLOCAL char cur_thread_placeholder[sizeof(ThreadState)] ALIGNED(64);
#endif
static char ctx_placeholder[sizeof(Context)] ALIGNED(64);
+Context *ctx;
// Can be overriden by a front-end.
#ifdef TSAN_EXTERNAL_HOOKS
bool OnFinalize(bool failed);
+void OnInitialize();
#else
+SANITIZER_INTERFACE_ATTRIBUTE
bool WEAK OnFinalize(bool failed) {
return failed;
}
+SANITIZER_INTERFACE_ATTRIBUTE
+void WEAK OnInitialize() {}
#endif
-static Context *ctx;
-Context *CTX() {
- return ctx;
-}
-
static char thread_registry_placeholder[sizeof(ThreadRegistry)];
static ThreadContextBase *CreateThreadContext(u32 tid) {
@@ -63,7 +73,7 @@ static ThreadContextBase *CreateThreadContext(u32 tid) {
return new(mem) ThreadContext(tid);
}
-#ifndef TSAN_GO
+#ifndef SANITIZER_GO
static const u32 kThreadQuarantineSize = 16;
#else
static const u32 kThreadQuarantineSize = 64;
@@ -75,7 +85,7 @@ Context::Context()
, nreported()
, nmissed_expected()
, thread_registry(new(thread_registry_placeholder) ThreadRegistry(
- CreateThreadContext, kMaxTid, kThreadQuarantineSize))
+ CreateThreadContext, kMaxTid, kThreadQuarantineSize, kMaxTidReuse))
, racy_stacks(MBlockRacyStacks)
, racy_addresses(MBlockRacyAddresses)
, fired_suppressions(8) {
@@ -83,14 +93,16 @@ Context::Context()
// The objects are allocated in TLS, so one may rely on zero-initialization.
ThreadState::ThreadState(Context *ctx, int tid, int unique_id, u64 epoch,
+ unsigned reuse_count,
uptr stk_addr, uptr stk_size,
uptr tls_addr, uptr tls_size)
: fast_state(tid, epoch)
// Do not touch these, rely on zero initialization,
// they may be accessed before the ctor.
// , ignore_reads_and_writes()
- // , in_rtl()
-#ifndef TSAN_GO
+ // , ignore_interceptors()
+ , clock(tid, reuse_count)
+#ifndef SANITIZER_GO
, jmp_bufs(MBlockJmpBuf)
#endif
, tid(tid)
@@ -98,7 +110,11 @@ ThreadState::ThreadState(Context *ctx, int tid, int unique_id, u64 epoch,
, stk_addr(stk_addr)
, stk_size(stk_size)
, tls_addr(tls_addr)
- , tls_size(tls_size) {
+ , tls_size(tls_size)
+#ifndef SANITIZER_GO
+ , last_sleep_clock(tid)
+#endif
+{
}
static void MemoryProfiler(Context *ctx, fd_t fd, int i) {
@@ -106,62 +122,67 @@ static void MemoryProfiler(Context *ctx, fd_t fd, int i) {
uptr n_running_threads;
ctx->thread_registry->GetNumberOfThreads(&n_threads, &n_running_threads);
InternalScopedBuffer<char> buf(4096);
- internal_snprintf(buf.data(), buf.size(), "%d: nthr=%d nlive=%d\n",
- i, n_threads, n_running_threads);
- internal_write(fd, buf.data(), internal_strlen(buf.data()));
- WriteMemoryProfile(buf.data(), buf.size());
+ WriteMemoryProfile(buf.data(), buf.size(), n_threads, n_running_threads);
internal_write(fd, buf.data(), internal_strlen(buf.data()));
}
static void BackgroundThread(void *arg) {
- ScopedInRtl in_rtl;
- Context *ctx = CTX();
+#ifndef SANITIZER_GO
+ // This is a non-initialized non-user thread, nothing to see here.
+ // We don't use ScopedIgnoreInterceptors, because we want ignores to be
+ // enabled even when the thread function exits (e.g. during pthread thread
+ // shutdown code).
+ cur_thread()->ignore_interceptors++;
+#endif
const u64 kMs2Ns = 1000 * 1000;
fd_t mprof_fd = kInvalidFd;
if (flags()->profile_memory && flags()->profile_memory[0]) {
- InternalScopedBuffer<char> filename(4096);
- internal_snprintf(filename.data(), filename.size(), "%s.%d",
- flags()->profile_memory, (int)internal_getpid());
- uptr openrv = OpenFile(filename.data(), true);
- if (internal_iserror(openrv)) {
- Printf("ThreadSanitizer: failed to open memory profile file '%s'\n",
- &filename[0]);
+ if (internal_strcmp(flags()->profile_memory, "stdout") == 0) {
+ mprof_fd = 1;
+ } else if (internal_strcmp(flags()->profile_memory, "stderr") == 0) {
+ mprof_fd = 2;
} else {
- mprof_fd = openrv;
+ InternalScopedString filename(kMaxPathLength);
+ filename.append("%s.%d", flags()->profile_memory, (int)internal_getpid());
+ uptr openrv = OpenFile(filename.data(), true);
+ if (internal_iserror(openrv)) {
+ Printf("ThreadSanitizer: failed to open memory profile file '%s'\n",
+ &filename[0]);
+ } else {
+ mprof_fd = openrv;
+ }
}
}
u64 last_flush = NanoTime();
uptr last_rss = 0;
- for (int i = 0; ; i++) {
- SleepForSeconds(1);
+ for (int i = 0;
+ atomic_load(&ctx->stop_background_thread, memory_order_relaxed) == 0;
+ i++) {
+ SleepForMillis(100);
u64 now = NanoTime();
// Flush memory if requested.
if (flags()->flush_memory_ms > 0) {
if (last_flush + flags()->flush_memory_ms * kMs2Ns < now) {
- if (flags()->verbosity > 0)
- Printf("ThreadSanitizer: periodic memory flush\n");
+ VPrintf(1, "ThreadSanitizer: periodic memory flush\n");
FlushShadowMemory();
last_flush = NanoTime();
}
}
+ // GetRSS can be expensive on huge programs, so don't do it every 100ms.
if (flags()->memory_limit_mb > 0) {
uptr rss = GetRSS();
uptr limit = uptr(flags()->memory_limit_mb) << 20;
- if (flags()->verbosity > 0) {
- Printf("ThreadSanitizer: memory flush check"
- " RSS=%llu LAST=%llu LIMIT=%llu\n",
- (u64)rss>>20, (u64)last_rss>>20, (u64)limit>>20);
- }
+ VPrintf(1, "ThreadSanitizer: memory flush check"
+ " RSS=%llu LAST=%llu LIMIT=%llu\n",
+ (u64)rss >> 20, (u64)last_rss >> 20, (u64)limit >> 20);
if (2 * rss > limit + last_rss) {
- if (flags()->verbosity > 0)
- Printf("ThreadSanitizer: flushing memory due to RSS\n");
+ VPrintf(1, "ThreadSanitizer: flushing memory due to RSS\n");
FlushShadowMemory();
rss = GetRSS();
- if (flags()->verbosity > 0)
- Printf("ThreadSanitizer: memory flushed RSS=%llu\n", (u64)rss>>20);
+ VPrintf(1, "ThreadSanitizer: memory flushed RSS=%llu\n", (u64)rss>>20);
}
last_rss = rss;
}
@@ -170,7 +191,7 @@ static void BackgroundThread(void *arg) {
if (mprof_fd != kInvalidFd)
MemoryProfiler(ctx, mprof_fd, i);
-#ifndef TSAN_GO
+#ifndef SANITIZER_GO
// Flush symbolizer cache if requested.
if (flags()->flush_symbolizer_ms > 0) {
u64 last = atomic_load(&ctx->last_symbolize_time_ns,
@@ -186,6 +207,18 @@ static void BackgroundThread(void *arg) {
}
}
+static void StartBackgroundThread() {
+ ctx->background_thread = internal_start_thread(&BackgroundThread, 0);
+}
+
+#ifndef SANITIZER_GO
+static void StopBackgroundThread() {
+ atomic_store(&ctx->stop_background_thread, 1, memory_order_relaxed);
+ internal_join_thread(ctx->background_thread);
+ ctx->background_thread = 0;
+}
+#endif
+
void DontNeedShadowFor(uptr addr, uptr size) {
uptr shadow_beg = MemToShadow(addr);
uptr shadow_end = MemToShadow(addr + size);
@@ -193,13 +226,43 @@ void DontNeedShadowFor(uptr addr, uptr size) {
}
void MapShadow(uptr addr, uptr size) {
+ // Global data is not 64K aligned, but there are no adjacent mappings,
+ // so we can get away with unaligned mapping.
+ // CHECK_EQ(addr, addr & ~((64 << 10) - 1)); // windows wants 64K alignment
MmapFixedNoReserve(MemToShadow(addr), size * kShadowMultiplier);
+
+ // Meta shadow is 2:1, so tread carefully.
+ static bool data_mapped = false;
+ static uptr mapped_meta_end = 0;
+ uptr meta_begin = (uptr)MemToMeta(addr);
+ uptr meta_end = (uptr)MemToMeta(addr + size);
+ meta_begin = RoundDownTo(meta_begin, 64 << 10);
+ meta_end = RoundUpTo(meta_end, 64 << 10);
+ if (!data_mapped) {
+ // First call maps data+bss.
+ data_mapped = true;
+ MmapFixedNoReserve(meta_begin, meta_end - meta_begin);
+ } else {
+ // Mapping continous heap.
+ // Windows wants 64K alignment.
+ meta_begin = RoundDownTo(meta_begin, 64 << 10);
+ meta_end = RoundUpTo(meta_end, 64 << 10);
+ if (meta_end <= mapped_meta_end)
+ return;
+ if (meta_begin < mapped_meta_end)
+ meta_begin = mapped_meta_end;
+ MmapFixedNoReserve(meta_begin, meta_end - meta_begin);
+ mapped_meta_end = meta_end;
+ }
+ VPrintf(2, "mapped meta shadow for (%p-%p) at (%p-%p)\n",
+ addr, addr+size, meta_begin, meta_end);
}
void MapThreadTrace(uptr addr, uptr size) {
DPrintf("#0: Mapping trace at %p-%p(0x%zx)\n", addr, addr + size, size);
- CHECK_GE(addr, kTraceMemBegin);
- CHECK_LE(addr + size, kTraceMemBegin + kTraceMemSize);
+ CHECK_GE(addr, kTraceMemBeg);
+ CHECK_LE(addr + size, kTraceMemEnd);
+ CHECK_EQ(addr, addr & ~((64 << 10) - 1)); // windows wants 64K alignment
uptr addr1 = (uptr)MmapFixedNoReserve(addr, size);
if (addr1 != addr) {
Printf("FATAL: ThreadSanitizer can not mmap thread trace (%p/%p->%p)\n",
@@ -208,57 +271,75 @@ void MapThreadTrace(uptr addr, uptr size) {
}
}
+static void CheckShadowMapping() {
+ for (uptr i = 0; i < ARRAY_SIZE(UserRegions); i += 2) {
+ const uptr beg = UserRegions[i];
+ const uptr end = UserRegions[i + 1];
+ VPrintf(3, "checking shadow region %p-%p\n", beg, end);
+ for (uptr p0 = beg; p0 <= end; p0 += (end - beg) / 4) {
+ for (int x = -1; x <= 1; x++) {
+ const uptr p = p0 + x;
+ if (p < beg || p >= end)
+ continue;
+ const uptr s = MemToShadow(p);
+ VPrintf(3, " checking pointer %p -> %p\n", p, s);
+ CHECK(IsAppMem(p));
+ CHECK(IsShadowMem(s));
+ CHECK_EQ(p & ~(kShadowCell - 1), ShadowToMem(s));
+ const uptr m = (uptr)MemToMeta(p);
+ CHECK(IsMetaMem(m));
+ }
+ }
+ }
+}
+
void Initialize(ThreadState *thr) {
// Thread safe because done before all threads exist.
static bool is_initialized = false;
if (is_initialized)
return;
is_initialized = true;
+ // We are not ready to handle interceptors yet.
+ ScopedIgnoreInterceptors ignore;
SanitizerToolName = "ThreadSanitizer";
// Install tool-specific callbacks in sanitizer_common.
SetCheckFailedCallback(TsanCheckFailed);
- ScopedInRtl in_rtl;
-#ifndef TSAN_GO
+ ctx = new(ctx_placeholder) Context;
+ const char *options = GetEnv(kTsanOptionsEnv);
+ InitializeFlags(&ctx->flags, options);
+#ifndef SANITIZER_GO
InitializeAllocator();
#endif
InitializeInterceptors();
- const char *env = InitializePlatform();
+ CheckShadowMapping();
+ InitializePlatform();
InitializeMutex();
InitializeDynamicAnnotations();
- ctx = new(ctx_placeholder) Context;
-#ifndef TSAN_GO
+#ifndef SANITIZER_GO
InitializeShadowMemory();
#endif
- InitializeFlags(&ctx->flags, env);
// Setup correct file descriptor for error reports.
- __sanitizer_set_report_path(flags()->log_path);
+ __sanitizer_set_report_path(common_flags()->log_path);
InitializeSuppressions();
-#ifndef TSAN_GO
+#ifndef SANITIZER_GO
InitializeLibIgnore();
- // Initialize external symbolizer before internal threads are started.
- const char *external_symbolizer = flags()->external_symbolizer_path;
- bool external_symbolizer_started =
- Symbolizer::Init(external_symbolizer)->IsExternalAvailable();
- if (external_symbolizer != 0 && external_symbolizer[0] != '\0' &&
- !external_symbolizer_started) {
- Printf("Failed to start external symbolizer: '%s'\n",
- external_symbolizer);
- Die();
- }
- Symbolizer::Get()->AddHooks(EnterSymbolizer, ExitSymbolizer);
+ Symbolizer::GetOrInit()->AddHooks(EnterSymbolizer, ExitSymbolizer);
+#endif
+ StartBackgroundThread();
+#ifndef SANITIZER_GO
+ SetSandboxingCallback(StopBackgroundThread);
#endif
- internal_start_thread(&BackgroundThread, 0);
+ if (common_flags()->detect_deadlocks)
+ ctx->dd = DDetector::Create(flags());
- if (ctx->flags.verbosity)
- Printf("***** Running under ThreadSanitizer v2 (pid %d) *****\n",
- (int)internal_getpid());
+ VPrintf(1, "***** Running under ThreadSanitizer v2 (pid %d) *****\n",
+ (int)internal_getpid());
// Initialize thread 0.
int tid = ThreadCreate(thr, 0, 0, true);
CHECK_EQ(tid, 0);
ThreadStart(thr, tid, internal_getpid());
- CHECK_EQ(thr->in_rtl, 1);
ctx->initialized = true;
if (flags()->stop_on_start) {
@@ -267,11 +348,11 @@ void Initialize(ThreadState *thr) {
(int)internal_getpid());
while (__tsan_resumed == 0) {}
}
+
+ OnInitialize();
}
int Finalize(ThreadState *thr) {
- ScopedInRtl in_rtl;
- Context *ctx = __tsan::ctx;
bool failed = false;
if (flags()->atexit_sleep_ms > 0 && ThreadCount(thr) > 1)
@@ -283,8 +364,8 @@ int Finalize(ThreadState *thr) {
CommonSanitizerReportMutex.Unlock();
ctx->report_mtx.Unlock();
-#ifndef TSAN_GO
- if (ctx->flags.verbosity)
+#ifndef SANITIZER_GO
+ if (common_flags()->verbosity)
AllocatorPrintStats();
#endif
@@ -292,7 +373,7 @@ int Finalize(ThreadState *thr) {
if (ctx->nreported) {
failed = true;
-#ifndef TSAN_GO
+#ifndef SANITIZER_GO
Printf("ThreadSanitizer: reported %d warnings\n", ctx->nreported);
#else
Printf("Found %d data race(s)\n", ctx->nreported);
@@ -305,9 +386,9 @@ int Finalize(ThreadState *thr) {
ctx->nmissed_expected);
}
- if (flags()->print_suppressions)
+ if (common_flags()->print_suppressions)
PrintMatchedSuppressions();
-#ifndef TSAN_GO
+#ifndef SANITIZER_GO
if (flags()->print_benign)
PrintMatchedBenignRaces();
#endif
@@ -319,31 +400,82 @@ int Finalize(ThreadState *thr) {
return failed ? flags()->exitcode : 0;
}
-#ifndef TSAN_GO
+#ifndef SANITIZER_GO
+void ForkBefore(ThreadState *thr, uptr pc) {
+ ctx->thread_registry->Lock();
+ ctx->report_mtx.Lock();
+}
+
+void ForkParentAfter(ThreadState *thr, uptr pc) {
+ ctx->report_mtx.Unlock();
+ ctx->thread_registry->Unlock();
+}
+
+void ForkChildAfter(ThreadState *thr, uptr pc) {
+ ctx->report_mtx.Unlock();
+ ctx->thread_registry->Unlock();
+
+ uptr nthread = 0;
+ ctx->thread_registry->GetNumberOfThreads(0, 0, &nthread /* alive threads */);
+ VPrintf(1, "ThreadSanitizer: forked new process with pid %d,"
+ " parent had %d threads\n", (int)internal_getpid(), (int)nthread);
+ if (nthread == 1) {
+ internal_start_thread(&BackgroundThread, 0);
+ } else {
+ // We've just forked a multi-threaded process. We cannot reasonably function
+ // after that (some mutexes may be locked before fork). So just enable
+ // ignores for everything in the hope that we will exec soon.
+ ctx->after_multithreaded_fork = true;
+ thr->ignore_interceptors++;
+ ThreadIgnoreBegin(thr, pc);
+ ThreadIgnoreSyncBegin(thr, pc);
+ }
+}
+#endif
+
+#ifdef SANITIZER_GO
+NOINLINE
+void GrowShadowStack(ThreadState *thr) {
+ const int sz = thr->shadow_stack_end - thr->shadow_stack;
+ const int newsz = 2 * sz;
+ uptr *newstack = (uptr*)internal_alloc(MBlockShadowStack,
+ newsz * sizeof(uptr));
+ internal_memcpy(newstack, thr->shadow_stack, sz * sizeof(uptr));
+ internal_free(thr->shadow_stack);
+ thr->shadow_stack = newstack;
+ thr->shadow_stack_pos = newstack + sz;
+ thr->shadow_stack_end = newstack + newsz;
+}
+#endif
+
u32 CurrentStackId(ThreadState *thr, uptr pc) {
if (thr->shadow_stack_pos == 0) // May happen during bootstrap.
return 0;
- if (pc) {
+ if (pc != 0) {
+#ifndef SANITIZER_GO
+ DCHECK_LT(thr->shadow_stack_pos, thr->shadow_stack_end);
+#else
+ if (thr->shadow_stack_pos == thr->shadow_stack_end)
+ GrowShadowStack(thr);
+#endif
thr->shadow_stack_pos[0] = pc;
thr->shadow_stack_pos++;
}
- u32 id = StackDepotPut(thr->shadow_stack,
- thr->shadow_stack_pos - thr->shadow_stack);
- if (pc)
+ u32 id = StackDepotPut(
+ StackTrace(thr->shadow_stack, thr->shadow_stack_pos - thr->shadow_stack));
+ if (pc != 0)
thr->shadow_stack_pos--;
return id;
}
-#endif
void TraceSwitch(ThreadState *thr) {
thr->nomalloc++;
- ScopedInRtl in_rtl;
Trace *thr_trace = ThreadTrace(thr->tid);
Lock l(&thr_trace->mtx);
unsigned trace = (thr->fast_state.epoch() / kTracePartSize) % TraceParts();
TraceHeader *hdr = &thr_trace->headers[trace];
hdr->epoch0 = thr->fast_state.epoch();
- hdr->stack0.ObtainCurrent(thr, 0);
+ ObtainCurrentStack(thr, 0, &hdr->stack0);
hdr->mset0 = thr->mset;
thr->nomalloc--;
}
@@ -366,7 +498,7 @@ uptr TraceParts() {
return TraceSize() / kTracePartSize;
}
-#ifndef TSAN_GO
+#ifndef SANITIZER_GO
extern "C" void __tsan_trace_switch() {
TraceSwitch(cur_thread());
}
@@ -393,28 +525,25 @@ void StoreIfNotYetStored(u64 *sp, u64 *s) {
*s = 0;
}
-static inline void HandleRace(ThreadState *thr, u64 *shadow_mem,
+ALWAYS_INLINE
+void HandleRace(ThreadState *thr, u64 *shadow_mem,
Shadow cur, Shadow old) {
thr->racy_state[0] = cur.raw();
thr->racy_state[1] = old.raw();
thr->racy_shadow_addr = shadow_mem;
-#ifndef TSAN_GO
+#ifndef SANITIZER_GO
HACKY_CALL(__tsan_report_race);
#else
ReportRace(thr);
#endif
}
-static inline bool OldIsInSameSynchEpoch(Shadow old, ThreadState *thr) {
- return old.epoch() >= thr->fast_synch_epoch;
-}
-
static inline bool HappensBefore(Shadow old, ThreadState *thr) {
return thr->clock.get(old.TidWithIgnore()) >= old.epoch();
}
-ALWAYS_INLINE USED
-void MemoryAccessImpl(ThreadState *thr, uptr addr,
+ALWAYS_INLINE
+void MemoryAccessImpl1(ThreadState *thr, uptr addr,
int kAccessSizeLog, bool kAccessIsWrite, bool kIsAtomic,
u64 *shadow_mem, Shadow cur) {
StatInc(thr, StatMop);
@@ -492,13 +621,13 @@ void UnalignedMemoryAccess(ThreadState *thr, uptr pc, uptr addr,
while (size) {
int size1 = 1;
int kAccessSizeLog = kSizeLog1;
- if (size >= 8 && (addr & ~7) == ((addr + 8) & ~7)) {
+ if (size >= 8 && (addr & ~7) == ((addr + 7) & ~7)) {
size1 = 8;
kAccessSizeLog = kSizeLog8;
- } else if (size >= 4 && (addr & ~7) == ((addr + 4) & ~7)) {
+ } else if (size >= 4 && (addr & ~7) == ((addr + 3) & ~7)) {
size1 = 4;
kAccessSizeLog = kSizeLog4;
- } else if (size >= 2 && (addr & ~7) == ((addr + 2) & ~7)) {
+ } else if (size >= 2 && (addr & ~7) == ((addr + 1) & ~7)) {
size1 = 2;
kAccessSizeLog = kSizeLog2;
}
@@ -508,6 +637,92 @@ void UnalignedMemoryAccess(ThreadState *thr, uptr pc, uptr addr,
}
}
+ALWAYS_INLINE
+bool ContainsSameAccessSlow(u64 *s, u64 a, u64 sync_epoch, bool is_write) {
+ Shadow cur(a);
+ for (uptr i = 0; i < kShadowCnt; i++) {
+ Shadow old(LoadShadow(&s[i]));
+ if (Shadow::Addr0AndSizeAreEqual(cur, old) &&
+ old.TidWithIgnore() == cur.TidWithIgnore() &&
+ old.epoch() > sync_epoch &&
+ old.IsAtomic() == cur.IsAtomic() &&
+ old.IsRead() <= cur.IsRead())
+ return true;
+ }
+ return false;
+}
+
+#if defined(__SSE3__) && TSAN_SHADOW_COUNT == 4
+#define SHUF(v0, v1, i0, i1, i2, i3) _mm_castps_si128(_mm_shuffle_ps( \
+ _mm_castsi128_ps(v0), _mm_castsi128_ps(v1), \
+ (i0)*1 + (i1)*4 + (i2)*16 + (i3)*64))
+ALWAYS_INLINE
+bool ContainsSameAccessFast(u64 *s, u64 a, u64 sync_epoch, bool is_write) {
+ // This is an optimized version of ContainsSameAccessSlow.
+ // load current access into access[0:63]
+ const m128 access = _mm_cvtsi64_si128(a);
+ // duplicate high part of access in addr0:
+ // addr0[0:31] = access[32:63]
+ // addr0[32:63] = access[32:63]
+ // addr0[64:95] = access[32:63]
+ // addr0[96:127] = access[32:63]
+ const m128 addr0 = SHUF(access, access, 1, 1, 1, 1);
+ // load 4 shadow slots
+ const m128 shadow0 = _mm_load_si128((__m128i*)s);
+ const m128 shadow1 = _mm_load_si128((__m128i*)s + 1);
+ // load high parts of 4 shadow slots into addr_vect:
+ // addr_vect[0:31] = shadow0[32:63]
+ // addr_vect[32:63] = shadow0[96:127]
+ // addr_vect[64:95] = shadow1[32:63]
+ // addr_vect[96:127] = shadow1[96:127]
+ m128 addr_vect = SHUF(shadow0, shadow1, 1, 3, 1, 3);
+ if (!is_write) {
+ // set IsRead bit in addr_vect
+ const m128 rw_mask1 = _mm_cvtsi64_si128(1<<15);
+ const m128 rw_mask = SHUF(rw_mask1, rw_mask1, 0, 0, 0, 0);
+ addr_vect = _mm_or_si128(addr_vect, rw_mask);
+ }
+ // addr0 == addr_vect?
+ const m128 addr_res = _mm_cmpeq_epi32(addr0, addr_vect);
+ // epoch1[0:63] = sync_epoch
+ const m128 epoch1 = _mm_cvtsi64_si128(sync_epoch);
+ // epoch[0:31] = sync_epoch[0:31]
+ // epoch[32:63] = sync_epoch[0:31]
+ // epoch[64:95] = sync_epoch[0:31]
+ // epoch[96:127] = sync_epoch[0:31]
+ const m128 epoch = SHUF(epoch1, epoch1, 0, 0, 0, 0);
+ // load low parts of shadow cell epochs into epoch_vect:
+ // epoch_vect[0:31] = shadow0[0:31]
+ // epoch_vect[32:63] = shadow0[64:95]
+ // epoch_vect[64:95] = shadow1[0:31]
+ // epoch_vect[96:127] = shadow1[64:95]
+ const m128 epoch_vect = SHUF(shadow0, shadow1, 0, 2, 0, 2);
+ // epoch_vect >= sync_epoch?
+ const m128 epoch_res = _mm_cmpgt_epi32(epoch_vect, epoch);
+ // addr_res & epoch_res
+ const m128 res = _mm_and_si128(addr_res, epoch_res);
+ // mask[0] = res[7]
+ // mask[1] = res[15]
+ // ...
+ // mask[15] = res[127]
+ const int mask = _mm_movemask_epi8(res);
+ return mask != 0;
+}
+#endif
+
+ALWAYS_INLINE
+bool ContainsSameAccess(u64 *s, u64 a, u64 sync_epoch, bool is_write) {
+#if defined(__SSE3__) && TSAN_SHADOW_COUNT == 4
+ bool res = ContainsSameAccessFast(s, a, sync_epoch, is_write);
+ // NOTE: this check can fail if the shadow is concurrently mutated
+ // by other threads.
+ DCHECK_EQ(res, ContainsSameAccessSlow(s, a, sync_epoch, is_write));
+ return res;
+#else
+ return ContainsSameAccessSlow(s, a, sync_epoch, is_write);
+#endif
+}
+
ALWAYS_INLINE USED
void MemoryAccess(ThreadState *thr, uptr pc, uptr addr,
int kAccessSizeLog, bool kAccessIsWrite, bool kIsAtomic) {
@@ -529,7 +744,7 @@ void MemoryAccess(ThreadState *thr, uptr pc, uptr addr,
}
#endif
- if (*shadow_mem == kShadowRodata) {
+ if (kCppMode && *shadow_mem == kShadowRodata) {
// Access to .rodata section, no races here.
// Measurements show that it can be 10-20% of all memory accesses.
StatInc(thr, StatMop);
@@ -540,20 +755,54 @@ void MemoryAccess(ThreadState *thr, uptr pc, uptr addr,
}
FastState fast_state = thr->fast_state;
- if (fast_state.GetIgnoreBit())
+ if (fast_state.GetIgnoreBit()) {
+ StatInc(thr, StatMop);
+ StatInc(thr, kAccessIsWrite ? StatMopWrite : StatMopRead);
+ StatInc(thr, (StatType)(StatMop1 + kAccessSizeLog));
+ StatInc(thr, StatMopIgnored);
return;
- fast_state.IncrementEpoch();
- thr->fast_state = fast_state;
+ }
+
Shadow cur(fast_state);
cur.SetAddr0AndSizeLog(addr & 7, kAccessSizeLog);
cur.SetWrite(kAccessIsWrite);
cur.SetAtomic(kIsAtomic);
- // We must not store to the trace if we do not store to the shadow.
- // That is, this call must be moved somewhere below.
- TraceAddEvent(thr, fast_state, EventTypeMop, pc);
+ if (LIKELY(ContainsSameAccess(shadow_mem, cur.raw(),
+ thr->fast_synch_epoch, kAccessIsWrite))) {
+ StatInc(thr, StatMop);
+ StatInc(thr, kAccessIsWrite ? StatMopWrite : StatMopRead);
+ StatInc(thr, (StatType)(StatMop1 + kAccessSizeLog));
+ StatInc(thr, StatMopSame);
+ return;
+ }
- MemoryAccessImpl(thr, addr, kAccessSizeLog, kAccessIsWrite, kIsAtomic,
+ if (kCollectHistory) {
+ fast_state.IncrementEpoch();
+ thr->fast_state = fast_state;
+ TraceAddEvent(thr, fast_state, EventTypeMop, pc);
+ cur.IncrementEpoch();
+ }
+
+ MemoryAccessImpl1(thr, addr, kAccessSizeLog, kAccessIsWrite, kIsAtomic,
+ shadow_mem, cur);
+}
+
+// Called by MemoryAccessRange in tsan_rtl_thread.cc
+ALWAYS_INLINE USED
+void MemoryAccessImpl(ThreadState *thr, uptr addr,
+ int kAccessSizeLog, bool kAccessIsWrite, bool kIsAtomic,
+ u64 *shadow_mem, Shadow cur) {
+ if (LIKELY(ContainsSameAccess(shadow_mem, cur.raw(),
+ thr->fast_synch_epoch, kAccessIsWrite))) {
+ StatInc(thr, StatMop);
+ StatInc(thr, kAccessIsWrite ? StatMopWrite : StatMopRead);
+ StatInc(thr, (StatType)(StatMop1 + kAccessSizeLog));
+ StatInc(thr, StatMopSame);
+ return;
+ }
+
+ MemoryAccessImpl1(thr, addr, kAccessSizeLog, kAccessIsWrite, kIsAtomic,
shadow_mem, cur);
}
@@ -582,7 +831,7 @@ static void MemoryRangeSet(ThreadState *thr, uptr pc, uptr addr, uptr size,
size = (size + (kShadowCell - 1)) & ~(kShadowCell - 1);
// UnmapOrDie/MmapFixedNoReserve does not work on Windows,
// so we do it only for C/C++.
- if (kGoMode || size < 64*1024) {
+ if (kGoMode || size < common_flags()->clear_shadow_mmap_threshold) {
u64 *p = (u64*)MemToShadow(addr);
CHECK(IsShadowMem((uptr)p));
CHECK(IsShadowMem((uptr)(p + size * kShadowCnt / kShadowCell - 1)));
@@ -632,8 +881,10 @@ void MemoryRangeFreed(ThreadState *thr, uptr pc, uptr addr, uptr size) {
thr->is_freeing = true;
MemoryAccessRange(thr, pc, addr, size, true);
thr->is_freeing = false;
- thr->fast_state.IncrementEpoch();
- TraceAddEvent(thr, thr->fast_state, EventTypeMop, pc);
+ if (kCollectHistory) {
+ thr->fast_state.IncrementEpoch();
+ TraceAddEvent(thr, thr->fast_state, EventTypeMop, pc);
+ }
Shadow s(thr->fast_state);
s.ClearIgnoreBit();
s.MarkAsFreed();
@@ -643,8 +894,10 @@ void MemoryRangeFreed(ThreadState *thr, uptr pc, uptr addr, uptr size) {
}
void MemoryRangeImitateWrite(ThreadState *thr, uptr pc, uptr addr, uptr size) {
- thr->fast_state.IncrementEpoch();
- TraceAddEvent(thr, thr->fast_state, EventTypeMop, pc);
+ if (kCollectHistory) {
+ thr->fast_state.IncrementEpoch();
+ TraceAddEvent(thr, thr->fast_state, EventTypeMop, pc);
+ }
Shadow s(thr->fast_state);
s.ClearIgnoreBit();
s.SetWrite(true);
@@ -654,29 +907,21 @@ void MemoryRangeImitateWrite(ThreadState *thr, uptr pc, uptr addr, uptr size) {
ALWAYS_INLINE USED
void FuncEntry(ThreadState *thr, uptr pc) {
- DCHECK_EQ(thr->in_rtl, 0);
StatInc(thr, StatFuncEnter);
DPrintf2("#%d: FuncEntry %p\n", (int)thr->fast_state.tid(), (void*)pc);
- thr->fast_state.IncrementEpoch();
- TraceAddEvent(thr, thr->fast_state, EventTypeFuncEnter, pc);
+ if (kCollectHistory) {
+ thr->fast_state.IncrementEpoch();
+ TraceAddEvent(thr, thr->fast_state, EventTypeFuncEnter, pc);
+ }
// Shadow stack maintenance can be replaced with
// stack unwinding during trace switch (which presumably must be faster).
DCHECK_GE(thr->shadow_stack_pos, thr->shadow_stack);
-#ifndef TSAN_GO
+#ifndef SANITIZER_GO
DCHECK_LT(thr->shadow_stack_pos, thr->shadow_stack_end);
#else
- if (thr->shadow_stack_pos == thr->shadow_stack_end) {
- const int sz = thr->shadow_stack_end - thr->shadow_stack;
- const int newsz = 2 * sz;
- uptr *newstack = (uptr*)internal_alloc(MBlockShadowStack,
- newsz * sizeof(uptr));
- internal_memcpy(newstack, thr->shadow_stack, sz * sizeof(uptr));
- internal_free(thr->shadow_stack);
- thr->shadow_stack = newstack;
- thr->shadow_stack_pos = newstack + sz;
- thr->shadow_stack_end = newstack + newsz;
- }
+ if (thr->shadow_stack_pos == thr->shadow_stack_end)
+ GrowShadowStack(thr);
#endif
thr->shadow_stack_pos[0] = pc;
thr->shadow_stack_pos++;
@@ -684,44 +929,61 @@ void FuncEntry(ThreadState *thr, uptr pc) {
ALWAYS_INLINE USED
void FuncExit(ThreadState *thr) {
- DCHECK_EQ(thr->in_rtl, 0);
StatInc(thr, StatFuncExit);
DPrintf2("#%d: FuncExit\n", (int)thr->fast_state.tid());
- thr->fast_state.IncrementEpoch();
- TraceAddEvent(thr, thr->fast_state, EventTypeFuncExit, 0);
+ if (kCollectHistory) {
+ thr->fast_state.IncrementEpoch();
+ TraceAddEvent(thr, thr->fast_state, EventTypeFuncExit, 0);
+ }
DCHECK_GT(thr->shadow_stack_pos, thr->shadow_stack);
-#ifndef TSAN_GO
+#ifndef SANITIZER_GO
DCHECK_LT(thr->shadow_stack_pos, thr->shadow_stack_end);
#endif
thr->shadow_stack_pos--;
}
-void ThreadIgnoreBegin(ThreadState *thr) {
+void ThreadIgnoreBegin(ThreadState *thr, uptr pc) {
DPrintf("#%d: ThreadIgnoreBegin\n", thr->tid);
thr->ignore_reads_and_writes++;
CHECK_GT(thr->ignore_reads_and_writes, 0);
thr->fast_state.SetIgnoreBit();
+#ifndef SANITIZER_GO
+ if (!ctx->after_multithreaded_fork)
+ thr->mop_ignore_set.Add(CurrentStackId(thr, pc));
+#endif
}
-void ThreadIgnoreEnd(ThreadState *thr) {
+void ThreadIgnoreEnd(ThreadState *thr, uptr pc) {
DPrintf("#%d: ThreadIgnoreEnd\n", thr->tid);
thr->ignore_reads_and_writes--;
CHECK_GE(thr->ignore_reads_and_writes, 0);
- if (thr->ignore_reads_and_writes == 0)
+ if (thr->ignore_reads_and_writes == 0) {
thr->fast_state.ClearIgnoreBit();
+#ifndef SANITIZER_GO
+ thr->mop_ignore_set.Reset();
+#endif
+ }
}
-void ThreadIgnoreSyncBegin(ThreadState *thr) {
+void ThreadIgnoreSyncBegin(ThreadState *thr, uptr pc) {
DPrintf("#%d: ThreadIgnoreSyncBegin\n", thr->tid);
thr->ignore_sync++;
CHECK_GT(thr->ignore_sync, 0);
+#ifndef SANITIZER_GO
+ if (!ctx->after_multithreaded_fork)
+ thr->sync_ignore_set.Add(CurrentStackId(thr, pc));
+#endif
}
-void ThreadIgnoreSyncEnd(ThreadState *thr) {
+void ThreadIgnoreSyncEnd(ThreadState *thr, uptr pc) {
DPrintf("#%d: ThreadIgnoreSyncEnd\n", thr->tid);
thr->ignore_sync--;
CHECK_GE(thr->ignore_sync, 0);
+#ifndef SANITIZER_GO
+ if (thr->ignore_sync == 0)
+ thr->sync_ignore_set.Reset();
+#endif
}
bool MD5Hash::operator==(const MD5Hash &other) const {
@@ -752,7 +1014,7 @@ void build_consistency_shadow8() {}
} // namespace __tsan
-#ifndef TSAN_GO
+#ifndef SANITIZER_GO
// Must be included in this file to make sure everything is inlined.
#include "tsan_interface_inl.h"
#endif
diff --git a/lib/tsan/rtl/tsan_rtl.h b/lib/tsan/rtl/tsan_rtl.h
index 4ee667543a6e..8d886875159b 100644
--- a/lib/tsan/rtl/tsan_rtl.h
+++ b/lib/tsan/rtl/tsan_rtl.h
@@ -28,7 +28,9 @@
#include "sanitizer_common/sanitizer_allocator.h"
#include "sanitizer_common/sanitizer_allocator_internal.h"
+#include "sanitizer_common/sanitizer_asm.h"
#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_deadlock_detector_interface.h"
#include "sanitizer_common/sanitizer_libignore.h"
#include "sanitizer_common/sanitizer_suppressions.h"
#include "sanitizer_common/sanitizer_thread_registry.h"
@@ -41,6 +43,8 @@
#include "tsan_report.h"
#include "tsan_platform.h"
#include "tsan_mutexset.h"
+#include "tsan_ignoreset.h"
+#include "tsan_stack_trace.h"
#if SANITIZER_WORDSIZE != 64
# error "ThreadSanitizer is supported only on 64-bit platforms"
@@ -48,87 +52,9 @@
namespace __tsan {
-// Descriptor of user's memory block.
-struct MBlock {
- /*
- u64 mtx : 1; // must be first
- u64 lst : 44;
- u64 stk : 31; // on word boundary
- u64 tid : kTidBits;
- u64 siz : 128 - 1 - 31 - 44 - kTidBits; // 39
- */
- u64 raw[2];
-
- void Init(uptr siz, u32 tid, u32 stk) {
- raw[0] = raw[1] = 0;
- raw[1] |= (u64)siz << ((1 + 44 + 31 + kTidBits) % 64);
- raw[1] |= (u64)tid << ((1 + 44 + 31) % 64);
- raw[0] |= (u64)stk << (1 + 44);
- raw[1] |= (u64)stk >> (64 - 44 - 1);
- DCHECK_EQ(Size(), siz);
- DCHECK_EQ(Tid(), tid);
- DCHECK_EQ(StackId(), stk);
- }
-
- u32 Tid() const {
- return GetLsb(raw[1] >> ((1 + 44 + 31) % 64), kTidBits);
- }
-
- uptr Size() const {
- return raw[1] >> ((1 + 31 + 44 + kTidBits) % 64);
- }
-
- u32 StackId() const {
- return (raw[0] >> (1 + 44)) | GetLsb(raw[1] << (64 - 44 - 1), 31);
- }
-
- SyncVar *ListHead() const {
- return (SyncVar*)(GetLsb(raw[0] >> 1, 44) << 3);
- }
-
- void ListPush(SyncVar *v) {
- SyncVar *lst = ListHead();
- v->next = lst;
- u64 x = (u64)v ^ (u64)lst;
- x = (x >> 3) << 1;
- raw[0] ^= x;
- DCHECK_EQ(ListHead(), v);
- }
-
- SyncVar *ListPop() {
- SyncVar *lst = ListHead();
- SyncVar *nxt = lst->next;
- lst->next = 0;
- u64 x = (u64)lst ^ (u64)nxt;
- x = (x >> 3) << 1;
- raw[0] ^= x;
- DCHECK_EQ(ListHead(), nxt);
- return lst;
- }
-
- void ListReset() {
- SyncVar *lst = ListHead();
- u64 x = (u64)lst;
- x = (x >> 3) << 1;
- raw[0] ^= x;
- DCHECK_EQ(ListHead(), 0);
- }
-
- void Lock();
- void Unlock();
- typedef GenericScopedLock<MBlock> ScopedLock;
-};
-
-#ifndef TSAN_GO
-#if defined(TSAN_COMPAT_SHADOW) && TSAN_COMPAT_SHADOW
-const uptr kAllocatorSpace = 0x7d0000000000ULL;
-#else
-const uptr kAllocatorSpace = 0x7d0000000000ULL;
-#endif
-const uptr kAllocatorSize = 0x10000000000ULL; // 1T.
-
+#ifndef SANITIZER_GO
struct MapUnmapCallback;
-typedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize, sizeof(MBlock),
+typedef SizeClassAllocator64<kHeapMemBeg, kHeapMemEnd - kHeapMemBeg, 0,
DefaultSizeClassMap, MapUnmapCallback> PrimaryAllocator;
typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache;
typedef LargeMmapAllocator<MapUnmapCallback> SecondaryAllocator;
@@ -145,14 +71,14 @@ const u64 kShadowRodata = (u64)-1; // .rodata shadow marker
// FastState (from most significant bit):
// ignore : 1
// tid : kTidBits
-// epoch : kClkBits
// unused : -
// history_size : 3
+// epoch : kClkBits
class FastState {
public:
FastState(u64 tid, u64 epoch) {
x_ = tid << kTidShift;
- x_ |= epoch << kClkShift;
+ x_ |= epoch;
DCHECK_EQ(tid, this->tid());
DCHECK_EQ(epoch, this->epoch());
DCHECK_EQ(GetIgnoreBit(), false);
@@ -177,13 +103,13 @@ class FastState {
}
u64 epoch() const {
- u64 res = (x_ << (kTidBits + 1)) >> (64 - kClkBits);
+ u64 res = x_ & ((1ull << kClkBits) - 1);
return res;
}
void IncrementEpoch() {
u64 old_epoch = epoch();
- x_ += 1 << kClkShift;
+ x_ += 1;
DCHECK_EQ(old_epoch + 1, epoch());
(void)old_epoch;
}
@@ -195,17 +121,19 @@ class FastState {
void SetHistorySize(int hs) {
CHECK_GE(hs, 0);
CHECK_LE(hs, 7);
- x_ = (x_ & ~7) | hs;
+ x_ = (x_ & ~(kHistoryMask << kHistoryShift)) | (u64(hs) << kHistoryShift);
}
+ ALWAYS_INLINE
int GetHistorySize() const {
- return (int)(x_ & 7);
+ return (int)((x_ >> kHistoryShift) & kHistoryMask);
}
void ClearHistorySize() {
- x_ &= ~7;
+ SetHistorySize(0);
}
+ ALWAYS_INLINE
u64 GetTracePos() const {
const int hs = GetHistorySize();
// When hs == 0, the trace consists of 2 parts.
@@ -216,20 +144,21 @@ class FastState {
private:
friend class Shadow;
static const int kTidShift = 64 - kTidBits - 1;
- static const int kClkShift = kTidShift - kClkBits;
static const u64 kIgnoreBit = 1ull << 63;
static const u64 kFreedBit = 1ull << 63;
+ static const u64 kHistoryShift = kClkBits;
+ static const u64 kHistoryMask = 7;
u64 x_;
};
// Shadow (from most significant bit):
// freed : 1
// tid : kTidBits
-// epoch : kClkBits
// is_atomic : 1
// is_read : 1
// size_log : 2
// addr0 : 3
+// epoch : kClkBits
class Shadow : public FastState {
public:
explicit Shadow(u64 x)
@@ -242,10 +171,10 @@ class Shadow : public FastState {
}
void SetAddr0AndSizeLog(u64 addr0, unsigned kAccessSizeLog) {
- DCHECK_EQ(x_ & 31, 0);
+ DCHECK_EQ((x_ >> kClkBits) & 31, 0);
DCHECK_LE(addr0, 7);
DCHECK_LE(kAccessSizeLog, 3);
- x_ |= (kAccessSizeLog << 3) | addr0;
+ x_ |= ((kAccessSizeLog << 3) | addr0) << kClkBits;
DCHECK_EQ(kAccessSizeLog, size_log());
DCHECK_EQ(addr0, this->addr0());
}
@@ -278,47 +207,34 @@ class Shadow : public FastState {
return shifted_xor == 0;
}
- static inline bool Addr0AndSizeAreEqual(const Shadow s1, const Shadow s2) {
- u64 masked_xor = (s1.x_ ^ s2.x_) & 31;
+ static ALWAYS_INLINE
+ bool Addr0AndSizeAreEqual(const Shadow s1, const Shadow s2) {
+ u64 masked_xor = ((s1.x_ ^ s2.x_) >> kClkBits) & 31;
return masked_xor == 0;
}
- static inline bool TwoRangesIntersect(Shadow s1, Shadow s2,
+ static ALWAYS_INLINE bool TwoRangesIntersect(Shadow s1, Shadow s2,
unsigned kS2AccessSize) {
bool res = false;
u64 diff = s1.addr0() - s2.addr0();
if ((s64)diff < 0) { // s1.addr0 < s2.addr0 // NOLINT
// if (s1.addr0() + size1) > s2.addr0()) return true;
- if (s1.size() > -diff) res = true;
+ if (s1.size() > -diff)
+ res = true;
} else {
// if (s2.addr0() + kS2AccessSize > s1.addr0()) return true;
- if (kS2AccessSize > diff) res = true;
+ if (kS2AccessSize > diff)
+ res = true;
}
- DCHECK_EQ(res, TwoRangesIntersectSLOW(s1, s2));
- DCHECK_EQ(res, TwoRangesIntersectSLOW(s2, s1));
+ DCHECK_EQ(res, TwoRangesIntersectSlow(s1, s2));
+ DCHECK_EQ(res, TwoRangesIntersectSlow(s2, s1));
return res;
}
- // The idea behind the offset is as follows.
- // Consider that we have 8 bool's contained within a single 8-byte block
- // (mapped to a single shadow "cell"). Now consider that we write to the bools
- // from a single thread (which we consider the common case).
- // W/o offsetting each access will have to scan 4 shadow values at average
- // to find the corresponding shadow value for the bool.
- // With offsetting we start scanning shadow with the offset so that
- // each access hits necessary shadow straight off (at least in an expected
- // optimistic case).
- // This logic works seamlessly for any layout of user data. For example,
- // if user data is {int, short, char, char}, then accesses to the int are
- // offsetted to 0, short - 4, 1st char - 6, 2nd char - 7. Hopefully, accesses
- // from a single thread won't need to scan all 8 shadow values.
- unsigned ComputeSearchOffset() {
- return x_ & 7;
- }
- u64 addr0() const { return x_ & 7; }
- u64 size() const { return 1ull << size_log(); }
- bool IsWrite() const { return !IsRead(); }
- bool IsRead() const { return x_ & kReadBit; }
+ u64 ALWAYS_INLINE addr0() const { return (x_ >> kClkBits) & 7; }
+ u64 ALWAYS_INLINE size() const { return 1ull << size_log(); }
+ bool ALWAYS_INLINE IsWrite() const { return !IsRead(); }
+ bool ALWAYS_INLINE IsRead() const { return x_ & kReadBit; }
// The idea behind the freed bit is as follows.
// When the memory is freed (or otherwise unaccessible) we write to the shadow
@@ -343,15 +259,14 @@ class Shadow : public FastState {
return res;
}
- bool IsBothReadsOrAtomic(bool kIsWrite, bool kIsAtomic) const {
- // analyzes 5-th bit (is_read) and 6-th bit (is_atomic)
- bool v = x_ & u64(((kIsWrite ^ 1) << kReadShift)
- | (kIsAtomic << kAtomicShift));
+ bool ALWAYS_INLINE IsBothReadsOrAtomic(bool kIsWrite, bool kIsAtomic) const {
+ bool v = x_ & ((u64(kIsWrite ^ 1) << kReadShift)
+ | (u64(kIsAtomic) << kAtomicShift));
DCHECK_EQ(v, (!IsWrite() && !kIsWrite) || (IsAtomic() && kIsAtomic));
return v;
}
- bool IsRWNotWeaker(bool kIsWrite, bool kIsAtomic) const {
+ bool ALWAYS_INLINE IsRWNotWeaker(bool kIsWrite, bool kIsAtomic) const {
bool v = ((x_ >> kReadShift) & 3)
<= u64((kIsWrite ^ 1) | (kIsAtomic << 1));
DCHECK_EQ(v, (IsAtomic() < kIsAtomic) ||
@@ -359,7 +274,7 @@ class Shadow : public FastState {
return v;
}
- bool IsRWWeakerOrEqual(bool kIsWrite, bool kIsAtomic) const {
+ bool ALWAYS_INLINE IsRWWeakerOrEqual(bool kIsWrite, bool kIsAtomic) const {
bool v = ((x_ >> kReadShift) & 3)
>= u64((kIsWrite ^ 1) | (kIsAtomic << 1));
DCHECK_EQ(v, (IsAtomic() > kIsAtomic) ||
@@ -368,14 +283,14 @@ class Shadow : public FastState {
}
private:
- static const u64 kReadShift = 5;
+ static const u64 kReadShift = 5 + kClkBits;
static const u64 kReadBit = 1ull << kReadShift;
- static const u64 kAtomicShift = 6;
+ static const u64 kAtomicShift = 6 + kClkBits;
static const u64 kAtomicBit = 1ull << kAtomicShift;
- u64 size_log() const { return (x_ >> 3) & 3; }
+ u64 size_log() const { return (x_ >> (3 + kClkBits)) & 3; }
- static bool TwoRangesIntersectSLOW(const Shadow s1, const Shadow s2) {
+ static bool TwoRangesIntersectSlow(const Shadow s1, const Shadow s2) {
if (s1.addr0() == s2.addr0()) return true;
if (s1.addr0() < s2.addr0() && s1.addr0() + s1.size() > s2.addr0())
return true;
@@ -390,6 +305,9 @@ struct SignalContext;
struct JmpBuf {
uptr sp;
uptr mangled_sp;
+ int int_signal_send;
+ bool in_blocking_func;
+ uptr in_signal_handler;
uptr *shadow_stack_pos;
};
@@ -413,6 +331,11 @@ struct ThreadState {
// for better performance.
int ignore_reads_and_writes;
int ignore_sync;
+ // Go does not support ignores.
+#ifndef SANITIZER_GO
+ IgnoreSet mop_ignore_set;
+ IgnoreSet sync_ignore_set;
+#endif
// C/C++ uses fixed size shadow stack embed into Trace.
// Go uses malloc-allocated shadow stack with dynamic size.
uptr *shadow_stack;
@@ -422,31 +345,38 @@ struct ThreadState {
u64 racy_state[2];
MutexSet mset;
ThreadClock clock;
-#ifndef TSAN_GO
+#ifndef SANITIZER_GO
AllocatorCache alloc_cache;
InternalAllocatorCache internal_alloc_cache;
Vector<JmpBuf> jmp_bufs;
+ int ignore_interceptors;
#endif
u64 stat[StatCnt];
const int tid;
const int unique_id;
- int in_rtl;
bool in_symbolizer;
bool in_ignored_lib;
- bool is_alive;
+ bool is_dead;
bool is_freeing;
bool is_vptr_access;
const uptr stk_addr;
const uptr stk_size;
const uptr tls_addr;
const uptr tls_size;
+ ThreadContext *tctx;
- DeadlockDetector deadlock_detector;
+ InternalDeadlockDetector internal_deadlock_detector;
+ DDPhysicalThread *dd_pt;
+ DDLogicalThread *dd_lt;
- bool in_signal_handler;
+ atomic_uintptr_t in_signal_handler;
SignalContext *signal_ctx;
-#ifndef TSAN_GO
+ DenseSlabAllocCache block_cache;
+ DenseSlabAllocCache sync_cache;
+ DenseSlabAllocCache clock_cache;
+
+#ifndef SANITIZER_GO
u32 last_sleep_stack_id;
ThreadClock last_sleep_clock;
#endif
@@ -456,13 +386,13 @@ struct ThreadState {
int nomalloc;
explicit ThreadState(Context *ctx, int tid, int unique_id, u64 epoch,
+ unsigned reuse_count,
uptr stk_addr, uptr stk_size,
uptr tls_addr, uptr tls_size);
};
-Context *CTX();
-
-#ifndef TSAN_GO
+#ifndef SANITIZER_GO
+__attribute__((tls_model("initial-exec")))
extern THREADLOCAL char cur_thread_placeholder[];
INLINE ThreadState *cur_thread() {
return reinterpret_cast<ThreadState *>(&cur_thread_placeholder);
@@ -474,11 +404,7 @@ class ThreadContext : public ThreadContextBase {
explicit ThreadContext(int tid);
~ThreadContext();
ThreadState *thr;
-#ifdef TSAN_GO
- StackTrace creation_stack;
-#else
u32 creation_stack_id;
-#endif
SyncClock sync;
// Epoch at which the thread had started.
// If we see an event from the thread stamped by an older epoch,
@@ -493,6 +419,7 @@ class ThreadContext : public ThreadContextBase {
void OnStarted(void *arg);
void OnCreated(void *arg);
void OnReset();
+ void OnDetached(void *arg);
};
struct RacyStacks {
@@ -521,20 +448,27 @@ struct Context {
Context();
bool initialized;
+ bool after_multithreaded_fork;
- SyncTab synctab;
+ MetaMap metamap;
Mutex report_mtx;
int nreported;
int nmissed_expected;
atomic_uint64_t last_symbolize_time_ns;
+ void *background_thread;
+ atomic_uint32_t stop_background_thread;
+
ThreadRegistry *thread_registry;
Vector<RacyStacks> racy_stacks;
Vector<RacyAddress> racy_addresses;
// Number of fired suppressions may be large enough.
InternalMmapVector<FiredSuppression> fired_suppressions;
+ DDetector *dd;
+
+ ClockAlloc clock_alloc;
Flags flags;
@@ -543,14 +477,20 @@ struct Context {
u64 int_alloc_siz[MBlockTypeCount];
};
-class ScopedInRtl {
- public:
- ScopedInRtl();
- ~ScopedInRtl();
- private:
- ThreadState*thr_;
- int in_rtl_;
- int errno_;
+extern Context *ctx; // The one and the only global runtime context.
+
+struct ScopedIgnoreInterceptors {
+ ScopedIgnoreInterceptors() {
+#ifndef SANITIZER_GO
+ cur_thread()->ignore_interceptors++;
+#endif
+ }
+
+ ~ScopedIgnoreInterceptors() {
+#ifndef SANITIZER_GO
+ cur_thread()->ignore_interceptors--;
+#endif
+ }
};
class ScopedReport {
@@ -558,11 +498,14 @@ class ScopedReport {
explicit ScopedReport(ReportType typ);
~ScopedReport();
- void AddStack(const StackTrace *stack);
- void AddMemoryAccess(uptr addr, Shadow s, const StackTrace *stack,
+ void AddMemoryAccess(uptr addr, Shadow s, StackTrace stack,
const MutexSet *mset);
- void AddThread(const ThreadContext *tctx);
+ void AddStack(StackTrace stack, bool suppressable = false);
+ void AddThread(const ThreadContext *tctx, bool suppressable = false);
+ void AddThread(int unique_tid, bool suppressable = false);
+ void AddUniqueTid(int unique_tid);
void AddMutex(const SyncVar *s);
+ u64 AddMutex(u64 id);
void AddLocation(uptr addr, uptr size);
void AddSleep(u32 stack_id);
void SetCount(int count);
@@ -570,16 +513,31 @@ class ScopedReport {
const ReportDesc *GetReport() const;
private:
- Context *ctx_;
ReportDesc *rep_;
+ // Symbolizer makes lots of intercepted calls. If we try to process them,
+ // at best it will cause deadlocks on internal mutexes.
+ ScopedIgnoreInterceptors ignore_interceptors_;
- void AddMutex(u64 id);
+ void AddDeadMutex(u64 id);
ScopedReport(const ScopedReport&);
void operator = (const ScopedReport&);
};
-void RestoreStack(int tid, const u64 epoch, StackTrace *stk, MutexSet *mset);
+void RestoreStack(int tid, const u64 epoch, VarSizeStackTrace *stk,
+ MutexSet *mset);
+
+template<typename StackTraceTy>
+void ObtainCurrentStack(ThreadState *thr, uptr toppc, StackTraceTy *stack) {
+ uptr size = thr->shadow_stack_pos - thr->shadow_stack;
+ uptr start = 0;
+ if (size + !!toppc > kStackTraceMax) {
+ start = size + !!toppc - kStackTraceMax;
+ size = kStackTraceMax - !!toppc;
+ }
+ stack->Init(&thr->shadow_stack[start], size, toppc);
+}
+
void StatAggregate(u64 *dst, u64 *src);
void StatOutput(u64 *stat);
@@ -600,19 +558,16 @@ void InitializeInterceptors();
void InitializeLibIgnore();
void InitializeDynamicAnnotations();
+void ForkBefore(ThreadState *thr, uptr pc);
+void ForkParentAfter(ThreadState *thr, uptr pc);
+void ForkChildAfter(ThreadState *thr, uptr pc);
+
void ReportRace(ThreadState *thr);
-bool OutputReport(Context *ctx,
- const ScopedReport &srep,
- const ReportStack *suppress_stack1 = 0,
- const ReportStack *suppress_stack2 = 0,
- const ReportLocation *suppress_loc = 0);
-bool IsFiredSuppression(Context *ctx,
- const ScopedReport &srep,
- const StackTrace &trace);
+bool OutputReport(ThreadState *thr, const ScopedReport &srep);
+bool IsFiredSuppression(Context *ctx, const ScopedReport &srep,
+ StackTrace trace);
bool IsExpectedReport(uptr addr, uptr size);
void PrintMatchedBenignRaces();
-bool FrameIsInternal(const ReportStack *frame);
-ReportStack *SkipTsanInternalFrames(ReportStack *ent);
#if defined(TSAN_DEBUG_OUTPUT) && TSAN_DEBUG_OUTPUT >= 1
# define DPrintf Printf
@@ -627,15 +582,15 @@ ReportStack *SkipTsanInternalFrames(ReportStack *ent);
#endif
u32 CurrentStackId(ThreadState *thr, uptr pc);
+ReportStack *SymbolizeStackId(u32 stack_id);
void PrintCurrentStack(ThreadState *thr, uptr pc);
-void PrintCurrentStackSlow(); // uses libunwind
+void PrintCurrentStackSlow(uptr pc); // uses libunwind
void Initialize(ThreadState *thr);
int Finalize(ThreadState *thr);
-SyncVar* GetJavaSync(ThreadState *thr, uptr pc, uptr addr,
- bool write_lock, bool create);
-SyncVar* GetAndRemoveJavaSync(ThreadState *thr, uptr pc, uptr addr);
+void OnUserAlloc(ThreadState *thr, uptr pc, uptr p, uptr sz, bool write);
+void OnUserFree(ThreadState *thr, uptr pc, uptr p, bool write);
void MemoryAccess(ThreadState *thr, uptr pc, uptr addr,
int kAccessSizeLog, bool kAccessIsWrite, bool kIsAtomic);
@@ -678,10 +633,10 @@ void MemoryResetRange(ThreadState *thr, uptr pc, uptr addr, uptr size);
void MemoryRangeFreed(ThreadState *thr, uptr pc, uptr addr, uptr size);
void MemoryRangeImitateWrite(ThreadState *thr, uptr pc, uptr addr, uptr size);
-void ThreadIgnoreBegin(ThreadState *thr);
-void ThreadIgnoreEnd(ThreadState *thr);
-void ThreadIgnoreSyncBegin(ThreadState *thr);
-void ThreadIgnoreSyncEnd(ThreadState *thr);
+void ThreadIgnoreBegin(ThreadState *thr, uptr pc);
+void ThreadIgnoreEnd(ThreadState *thr, uptr pc);
+void ThreadIgnoreSyncBegin(ThreadState *thr, uptr pc);
+void ThreadIgnoreSyncEnd(ThreadState *thr, uptr pc);
void FuncEntry(ThreadState *thr, uptr pc);
void FuncExit(ThreadState *thr);
@@ -700,14 +655,21 @@ void ProcessPendingSignals(ThreadState *thr);
void MutexCreate(ThreadState *thr, uptr pc, uptr addr,
bool rw, bool recursive, bool linker_init);
void MutexDestroy(ThreadState *thr, uptr pc, uptr addr);
-void MutexLock(ThreadState *thr, uptr pc, uptr addr, int rec = 1);
+void MutexLock(ThreadState *thr, uptr pc, uptr addr, int rec = 1,
+ bool try_lock = false);
int MutexUnlock(ThreadState *thr, uptr pc, uptr addr, bool all = false);
-void MutexReadLock(ThreadState *thr, uptr pc, uptr addr);
+void MutexReadLock(ThreadState *thr, uptr pc, uptr addr, bool try_lock = false);
void MutexReadUnlock(ThreadState *thr, uptr pc, uptr addr);
void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr);
void MutexRepair(ThreadState *thr, uptr pc, uptr addr); // call on EOWNERDEAD
void Acquire(ThreadState *thr, uptr pc, uptr addr);
+// AcquireGlobal synchronizes the current thread with all other threads.
+// In terms of happens-before relation, it draws a HB edge from all threads
+// (where they happen to execute right now) to the current thread. We use it to
+// handle Go finalizers. Namely, finalizer goroutine executes AcquireGlobal
+// right before executing finalizers. This provides a coarse, but simple
+// approximation of the actual required synchronization.
void AcquireGlobal(ThreadState *thr, uptr pc);
void Release(ThreadState *thr, uptr pc, uptr addr);
void ReleaseStore(ThreadState *thr, uptr pc, uptr addr);
@@ -728,11 +690,11 @@ void AcquireReleaseImpl(ThreadState *thr, uptr pc, SyncClock *c);
// so we create a reserve stack frame for it (1024b must be enough).
#define HACKY_CALL(f) \
__asm__ __volatile__("sub $1024, %%rsp;" \
- ".cfi_adjust_cfa_offset 1024;" \
+ CFI_INL_ADJUST_CFA_OFFSET(1024) \
".hidden " #f "_thunk;" \
"call " #f "_thunk;" \
"add $1024, %%rsp;" \
- ".cfi_adjust_cfa_offset -1024;" \
+ CFI_INL_ADJUST_CFA_OFFSET(-1024) \
::: "memory", "cc");
#else
#define HACKY_CALL(f) f()
@@ -747,13 +709,15 @@ Trace *ThreadTrace(int tid);
extern "C" void __tsan_trace_switch();
void ALWAYS_INLINE TraceAddEvent(ThreadState *thr, FastState fs,
EventType typ, u64 addr) {
+ if (!kCollectHistory)
+ return;
DCHECK_GE((int)typ, 0);
DCHECK_LE((int)typ, 7);
DCHECK_EQ(GetLsb(addr, 61), addr);
StatInc(thr, StatEvents);
u64 pos = fs.GetTracePos();
if (UNLIKELY((pos % kTracePartSize) == 0)) {
-#ifndef TSAN_GO
+#ifndef SANITIZER_GO
HACKY_CALL(__tsan_trace_switch);
#else
TraceSwitch(thr);
diff --git a/lib/tsan/rtl/tsan_rtl_amd64.S b/lib/tsan/rtl/tsan_rtl_amd64.S
index 11c75c72dbe5..8db62f9013a3 100644
--- a/lib/tsan/rtl/tsan_rtl_amd64.S
+++ b/lib/tsan/rtl/tsan_rtl_amd64.S
@@ -1,43 +1,44 @@
+#include "sanitizer_common/sanitizer_asm.h"
.section .text
.hidden __tsan_trace_switch
.globl __tsan_trace_switch_thunk
__tsan_trace_switch_thunk:
- .cfi_startproc
+ CFI_STARTPROC
# Save scratch registers.
push %rax
- .cfi_adjust_cfa_offset 8
- .cfi_rel_offset %rax, 0
+ CFI_ADJUST_CFA_OFFSET(8)
+ CFI_REL_OFFSET(%rax, 0)
push %rcx
- .cfi_adjust_cfa_offset 8
- .cfi_rel_offset %rcx, 0
+ CFI_ADJUST_CFA_OFFSET(8)
+ CFI_REL_OFFSET(%rcx, 0)
push %rdx
- .cfi_adjust_cfa_offset 8
- .cfi_rel_offset %rdx, 0
+ CFI_ADJUST_CFA_OFFSET(8)
+ CFI_REL_OFFSET(%rdx, 0)
push %rsi
- .cfi_adjust_cfa_offset 8
- .cfi_rel_offset %rsi, 0
+ CFI_ADJUST_CFA_OFFSET(8)
+ CFI_REL_OFFSET(%rsi, 0)
push %rdi
- .cfi_adjust_cfa_offset 8
- .cfi_rel_offset %rdi, 0
+ CFI_ADJUST_CFA_OFFSET(8)
+ CFI_REL_OFFSET(%rdi, 0)
push %r8
- .cfi_adjust_cfa_offset 8
- .cfi_rel_offset %r8, 0
+ CFI_ADJUST_CFA_OFFSET(8)
+ CFI_REL_OFFSET(%r8, 0)
push %r9
- .cfi_adjust_cfa_offset 8
- .cfi_rel_offset %r9, 0
+ CFI_ADJUST_CFA_OFFSET(8)
+ CFI_REL_OFFSET(%r9, 0)
push %r10
- .cfi_adjust_cfa_offset 8
- .cfi_rel_offset %r10, 0
+ CFI_ADJUST_CFA_OFFSET(8)
+ CFI_REL_OFFSET(%r10, 0)
push %r11
- .cfi_adjust_cfa_offset 8
- .cfi_rel_offset %r11, 0
+ CFI_ADJUST_CFA_OFFSET(8)
+ CFI_REL_OFFSET(%r11, 0)
# Align stack frame.
push %rbx # non-scratch
- .cfi_adjust_cfa_offset 8
- .cfi_rel_offset %rbx, 0
+ CFI_ADJUST_CFA_OFFSET(8)
+ CFI_REL_OFFSET(%rbx, 0)
mov %rsp, %rbx # save current rsp
- .cfi_def_cfa_register %rbx
+ CFI_DEF_CFA_REGISTER(%rbx)
shr $4, %rsp # clear 4 lsb, align to 16
shl $4, %rsp
@@ -45,79 +46,79 @@ __tsan_trace_switch_thunk:
# Unalign stack frame back.
mov %rbx, %rsp # restore the original rsp
- .cfi_def_cfa_register %rsp
+ CFI_DEF_CFA_REGISTER(%rsp)
pop %rbx
- .cfi_adjust_cfa_offset -8
+ CFI_ADJUST_CFA_OFFSET(-8)
# Restore scratch registers.
pop %r11
- .cfi_adjust_cfa_offset -8
+ CFI_ADJUST_CFA_OFFSET(-8)
pop %r10
- .cfi_adjust_cfa_offset -8
+ CFI_ADJUST_CFA_OFFSET(-8)
pop %r9
- .cfi_adjust_cfa_offset -8
+ CFI_ADJUST_CFA_OFFSET(-8)
pop %r8
- .cfi_adjust_cfa_offset -8
+ CFI_ADJUST_CFA_OFFSET(-8)
pop %rdi
- .cfi_adjust_cfa_offset -8
+ CFI_ADJUST_CFA_OFFSET(-8)
pop %rsi
- .cfi_adjust_cfa_offset -8
+ CFI_ADJUST_CFA_OFFSET(-8)
pop %rdx
- .cfi_adjust_cfa_offset -8
+ CFI_ADJUST_CFA_OFFSET(-8)
pop %rcx
- .cfi_adjust_cfa_offset -8
+ CFI_ADJUST_CFA_OFFSET(-8)
pop %rax
- .cfi_adjust_cfa_offset -8
- .cfi_restore %rax
- .cfi_restore %rbx
- .cfi_restore %rcx
- .cfi_restore %rdx
- .cfi_restore %rsi
- .cfi_restore %rdi
- .cfi_restore %r8
- .cfi_restore %r9
- .cfi_restore %r10
- .cfi_restore %r11
+ CFI_ADJUST_CFA_OFFSET(-8)
+ CFI_RESTORE(%rax)
+ CFI_RESTORE(%rbx)
+ CFI_RESTORE(%rcx)
+ CFI_RESTORE(%rdx)
+ CFI_RESTORE(%rsi)
+ CFI_RESTORE(%rdi)
+ CFI_RESTORE(%r8)
+ CFI_RESTORE(%r9)
+ CFI_RESTORE(%r10)
+ CFI_RESTORE(%r11)
ret
- .cfi_endproc
+ CFI_ENDPROC
.hidden __tsan_report_race
.globl __tsan_report_race_thunk
__tsan_report_race_thunk:
- .cfi_startproc
+ CFI_STARTPROC
# Save scratch registers.
push %rax
- .cfi_adjust_cfa_offset 8
- .cfi_rel_offset %rax, 0
+ CFI_ADJUST_CFA_OFFSET(8)
+ CFI_REL_OFFSET(%rax, 0)
push %rcx
- .cfi_adjust_cfa_offset 8
- .cfi_rel_offset %rcx, 0
+ CFI_ADJUST_CFA_OFFSET(8)
+ CFI_REL_OFFSET(%rcx, 0)
push %rdx
- .cfi_adjust_cfa_offset 8
- .cfi_rel_offset %rdx, 0
+ CFI_ADJUST_CFA_OFFSET(8)
+ CFI_REL_OFFSET(%rdx, 0)
push %rsi
- .cfi_adjust_cfa_offset 8
- .cfi_rel_offset %rsi, 0
+ CFI_ADJUST_CFA_OFFSET(8)
+ CFI_REL_OFFSET(%rsi, 0)
push %rdi
- .cfi_adjust_cfa_offset 8
- .cfi_rel_offset %rdi, 0
+ CFI_ADJUST_CFA_OFFSET(8)
+ CFI_REL_OFFSET(%rdi, 0)
push %r8
- .cfi_adjust_cfa_offset 8
- .cfi_rel_offset %r8, 0
+ CFI_ADJUST_CFA_OFFSET(8)
+ CFI_REL_OFFSET(%r8, 0)
push %r9
- .cfi_adjust_cfa_offset 8
- .cfi_rel_offset %r9, 0
+ CFI_ADJUST_CFA_OFFSET(8)
+ CFI_REL_OFFSET(%r9, 0)
push %r10
- .cfi_adjust_cfa_offset 8
- .cfi_rel_offset %r10, 0
+ CFI_ADJUST_CFA_OFFSET(8)
+ CFI_REL_OFFSET(%r10, 0)
push %r11
- .cfi_adjust_cfa_offset 8
- .cfi_rel_offset %r11, 0
+ CFI_ADJUST_CFA_OFFSET(8)
+ CFI_REL_OFFSET(%r11, 0)
# Align stack frame.
push %rbx # non-scratch
- .cfi_adjust_cfa_offset 8
- .cfi_rel_offset %rbx, 0
+ CFI_ADJUST_CFA_OFFSET(8)
+ CFI_REL_OFFSET(%rbx, 0)
mov %rsp, %rbx # save current rsp
- .cfi_def_cfa_register %rbx
+ CFI_DEF_CFA_REGISTER(%rbx)
shr $4, %rsp # clear 4 lsb, align to 16
shl $4, %rsp
@@ -125,179 +126,199 @@ __tsan_report_race_thunk:
# Unalign stack frame back.
mov %rbx, %rsp # restore the original rsp
- .cfi_def_cfa_register %rsp
+ CFI_DEF_CFA_REGISTER(%rsp)
pop %rbx
- .cfi_adjust_cfa_offset -8
+ CFI_ADJUST_CFA_OFFSET(-8)
# Restore scratch registers.
pop %r11
- .cfi_adjust_cfa_offset -8
+ CFI_ADJUST_CFA_OFFSET(-8)
pop %r10
- .cfi_adjust_cfa_offset -8
+ CFI_ADJUST_CFA_OFFSET(-8)
pop %r9
- .cfi_adjust_cfa_offset -8
+ CFI_ADJUST_CFA_OFFSET(-8)
pop %r8
- .cfi_adjust_cfa_offset -8
+ CFI_ADJUST_CFA_OFFSET(-8)
pop %rdi
- .cfi_adjust_cfa_offset -8
+ CFI_ADJUST_CFA_OFFSET(-8)
pop %rsi
- .cfi_adjust_cfa_offset -8
+ CFI_ADJUST_CFA_OFFSET(-8)
pop %rdx
- .cfi_adjust_cfa_offset -8
+ CFI_ADJUST_CFA_OFFSET(-8)
pop %rcx
- .cfi_adjust_cfa_offset -8
+ CFI_ADJUST_CFA_OFFSET(-8)
pop %rax
- .cfi_adjust_cfa_offset -8
- .cfi_restore %rax
- .cfi_restore %rbx
- .cfi_restore %rcx
- .cfi_restore %rdx
- .cfi_restore %rsi
- .cfi_restore %rdi
- .cfi_restore %r8
- .cfi_restore %r9
- .cfi_restore %r10
- .cfi_restore %r11
+ CFI_ADJUST_CFA_OFFSET(-8)
+ CFI_RESTORE(%rax)
+ CFI_RESTORE(%rbx)
+ CFI_RESTORE(%rcx)
+ CFI_RESTORE(%rdx)
+ CFI_RESTORE(%rsi)
+ CFI_RESTORE(%rdi)
+ CFI_RESTORE(%r8)
+ CFI_RESTORE(%r9)
+ CFI_RESTORE(%r10)
+ CFI_RESTORE(%r11)
ret
- .cfi_endproc
+ CFI_ENDPROC
.hidden __tsan_setjmp
.comm _ZN14__interception11real_setjmpE,8,8
.globl setjmp
.type setjmp, @function
setjmp:
- .cfi_startproc
+ CFI_STARTPROC
// save env parameter
push %rdi
- .cfi_adjust_cfa_offset 8
- .cfi_rel_offset %rdi, 0
+ CFI_ADJUST_CFA_OFFSET(8)
+ CFI_REL_OFFSET(%rdi, 0)
// obtain %rsp
+#if defined(__FreeBSD__)
+ lea 8(%rsp), %rdi
+ mov %rdi, %rsi
+#else
lea 16(%rsp), %rdi
mov %rdi, %rsi
xor %fs:0x30, %rsi // magic mangling of rsp (see libc setjmp)
rol $0x11, %rsi
+#endif
// call tsan interceptor
call __tsan_setjmp
// restore env parameter
pop %rdi
- .cfi_adjust_cfa_offset -8
- .cfi_restore %rdi
+ CFI_ADJUST_CFA_OFFSET(-8)
+ CFI_RESTORE(%rdi)
// tail jump to libc setjmp
movl $0, %eax
movq _ZN14__interception11real_setjmpE@GOTPCREL(%rip), %rdx
jmp *(%rdx)
- .cfi_endproc
+ CFI_ENDPROC
.size setjmp, .-setjmp
.comm _ZN14__interception12real__setjmpE,8,8
.globl _setjmp
.type _setjmp, @function
_setjmp:
- .cfi_startproc
+ CFI_STARTPROC
// save env parameter
push %rdi
- .cfi_adjust_cfa_offset 8
- .cfi_rel_offset %rdi, 0
+ CFI_ADJUST_CFA_OFFSET(8)
+ CFI_REL_OFFSET(%rdi, 0)
// obtain %rsp
+#if defined(__FreeBSD__)
+ lea 8(%rsp), %rdi
+ mov %rdi, %rsi
+#else
lea 16(%rsp), %rdi
mov %rdi, %rsi
xor %fs:0x30, %rsi // magic mangling of rsp (see libc setjmp)
rol $0x11, %rsi
+#endif
// call tsan interceptor
call __tsan_setjmp
// restore env parameter
pop %rdi
- .cfi_adjust_cfa_offset -8
- .cfi_restore %rdi
+ CFI_ADJUST_CFA_OFFSET(-8)
+ CFI_RESTORE(%rdi)
// tail jump to libc setjmp
movl $0, %eax
movq _ZN14__interception12real__setjmpE@GOTPCREL(%rip), %rdx
jmp *(%rdx)
- .cfi_endproc
+ CFI_ENDPROC
.size _setjmp, .-_setjmp
.comm _ZN14__interception14real_sigsetjmpE,8,8
.globl sigsetjmp
.type sigsetjmp, @function
sigsetjmp:
- .cfi_startproc
+ CFI_STARTPROC
// save env parameter
push %rdi
- .cfi_adjust_cfa_offset 8
- .cfi_rel_offset %rdi, 0
+ CFI_ADJUST_CFA_OFFSET(8)
+ CFI_REL_OFFSET(%rdi, 0)
// save savesigs parameter
push %rsi
- .cfi_adjust_cfa_offset 8
- .cfi_rel_offset %rsi, 0
+ CFI_ADJUST_CFA_OFFSET(8)
+ CFI_REL_OFFSET(%rsi, 0)
// align stack frame
sub $8, %rsp
- .cfi_adjust_cfa_offset 8
+ CFI_ADJUST_CFA_OFFSET(8)
// obtain %rsp
+#if defined(__FreeBSD__)
+ lea 24(%rsp), %rdi
+ mov %rdi, %rsi
+#else
lea 32(%rsp), %rdi
mov %rdi, %rsi
xor %fs:0x30, %rsi // magic mangling of rsp (see libc setjmp)
rol $0x11, %rsi
+#endif
// call tsan interceptor
call __tsan_setjmp
// unalign stack frame
add $8, %rsp
- .cfi_adjust_cfa_offset -8
+ CFI_ADJUST_CFA_OFFSET(-8)
// restore savesigs parameter
pop %rsi
- .cfi_adjust_cfa_offset -8
- .cfi_restore %rsi
+ CFI_ADJUST_CFA_OFFSET(-8)
+ CFI_RESTORE(%rsi)
// restore env parameter
pop %rdi
- .cfi_adjust_cfa_offset -8
- .cfi_restore %rdi
+ CFI_ADJUST_CFA_OFFSET(-8)
+ CFI_RESTORE(%rdi)
// tail jump to libc sigsetjmp
movl $0, %eax
movq _ZN14__interception14real_sigsetjmpE@GOTPCREL(%rip), %rdx
jmp *(%rdx)
- .cfi_endproc
+ CFI_ENDPROC
.size sigsetjmp, .-sigsetjmp
.comm _ZN14__interception16real___sigsetjmpE,8,8
.globl __sigsetjmp
.type __sigsetjmp, @function
__sigsetjmp:
- .cfi_startproc
+ CFI_STARTPROC
// save env parameter
push %rdi
- .cfi_adjust_cfa_offset 8
- .cfi_rel_offset %rdi, 0
+ CFI_ADJUST_CFA_OFFSET(8)
+ CFI_REL_OFFSET(%rdi, 0)
// save savesigs parameter
push %rsi
- .cfi_adjust_cfa_offset 8
- .cfi_rel_offset %rsi, 0
+ CFI_ADJUST_CFA_OFFSET(8)
+ CFI_REL_OFFSET(%rsi, 0)
// align stack frame
sub $8, %rsp
- .cfi_adjust_cfa_offset 8
+ CFI_ADJUST_CFA_OFFSET(8)
// obtain %rsp
+#if defined(__FreeBSD__)
+ lea 24(%rsp), %rdi
+ mov %rdi, %rsi
+#else
lea 32(%rsp), %rdi
mov %rdi, %rsi
xor %fs:0x30, %rsi // magic mangling of rsp (see libc setjmp)
rol $0x11, %rsi
+#endif
// call tsan interceptor
call __tsan_setjmp
// unalign stack frame
add $8, %rsp
- .cfi_adjust_cfa_offset -8
+ CFI_ADJUST_CFA_OFFSET(-8)
// restore savesigs parameter
pop %rsi
- .cfi_adjust_cfa_offset -8
- .cfi_restore %rsi
+ CFI_ADJUST_CFA_OFFSET(-8)
+ CFI_RESTORE(%rsi)
// restore env parameter
pop %rdi
- .cfi_adjust_cfa_offset -8
- .cfi_restore %rdi
+ CFI_ADJUST_CFA_OFFSET(-8)
+ CFI_RESTORE(%rdi)
// tail jump to libc sigsetjmp
movl $0, %eax
movq _ZN14__interception16real___sigsetjmpE@GOTPCREL(%rip), %rdx
jmp *(%rdx)
- .cfi_endproc
+ CFI_ENDPROC
.size __sigsetjmp, .-__sigsetjmp
-#ifdef __linux__
+#if defined(__FreeBSD__) || defined(__linux__)
/* We do not need executable stack. */
.section .note.GNU-stack,"",@progbits
#endif
diff --git a/lib/tsan/rtl/tsan_rtl_mutex.cc b/lib/tsan/rtl/tsan_rtl_mutex.cc
index 409391678f01..ddf2b69bdbbc 100644
--- a/lib/tsan/rtl/tsan_rtl_mutex.cc
+++ b/lib/tsan/rtl/tsan_rtl_mutex.cc
@@ -11,6 +11,9 @@
//
//===----------------------------------------------------------------------===//
+#include <sanitizer_common/sanitizer_deadlock_detector_interface.h>
+#include <sanitizer_common/sanitizer_stackdepot.h>
+
#include "tsan_rtl.h"
#include "tsan_flags.h"
#include "tsan_sync.h"
@@ -20,10 +23,51 @@
namespace __tsan {
+void ReportDeadlock(ThreadState *thr, uptr pc, DDReport *r);
+
+struct Callback : DDCallback {
+ ThreadState *thr;
+ uptr pc;
+
+ Callback(ThreadState *thr, uptr pc)
+ : thr(thr)
+ , pc(pc) {
+ DDCallback::pt = thr->dd_pt;
+ DDCallback::lt = thr->dd_lt;
+ }
+
+ virtual u32 Unwind() {
+ return CurrentStackId(thr, pc);
+ }
+ virtual int UniqueTid() {
+ return thr->unique_id;
+ }
+};
+
+void DDMutexInit(ThreadState *thr, uptr pc, SyncVar *s) {
+ Callback cb(thr, pc);
+ ctx->dd->MutexInit(&cb, &s->dd);
+ s->dd.ctx = s->GetId();
+}
+
+static void ReportMutexMisuse(ThreadState *thr, uptr pc, ReportType typ,
+ uptr addr, u64 mid) {
+ // In Go, these misuses are either impossible, or detected by std lib,
+ // or false positives (e.g. unlock in a different thread).
+ if (kGoMode)
+ return;
+ ThreadRegistryLock l(ctx->thread_registry);
+ ScopedReport rep(typ);
+ rep.AddMutex(mid);
+ VarSizeStackTrace trace;
+ ObtainCurrentStack(thr, pc, &trace);
+ rep.AddStack(trace, true);
+ rep.AddLocation(addr, 1);
+ OutputReport(thr, rep);
+}
+
void MutexCreate(ThreadState *thr, uptr pc, uptr addr,
bool rw, bool recursive, bool linker_init) {
- Context *ctx = CTX();
- CHECK_GT(thr->in_rtl, 0);
DPrintf("#%d: MutexCreate %zx\n", thr->tid, addr);
StatInc(thr, StatMutexCreate);
if (!linker_init && IsAppMem(addr)) {
@@ -32,71 +76,92 @@ void MutexCreate(ThreadState *thr, uptr pc, uptr addr,
MemoryWrite(thr, pc, addr, kSizeLog1);
thr->is_freeing = false;
}
- SyncVar *s = ctx->synctab.GetOrCreateAndLock(thr, pc, addr, true);
+ SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true);
s->is_rw = rw;
s->is_recursive = recursive;
s->is_linker_init = linker_init;
+ if (kCppMode && s->creation_stack_id == 0)
+ s->creation_stack_id = CurrentStackId(thr, pc);
s->mtx.Unlock();
}
void MutexDestroy(ThreadState *thr, uptr pc, uptr addr) {
- Context *ctx = CTX();
- CHECK_GT(thr->in_rtl, 0);
DPrintf("#%d: MutexDestroy %zx\n", thr->tid, addr);
StatInc(thr, StatMutexDestroy);
-#ifndef TSAN_GO
+#ifndef SANITIZER_GO
// Global mutexes not marked as LINKER_INITIALIZED
// cause tons of not interesting reports, so just ignore it.
if (IsGlobalVar(addr))
return;
#endif
- SyncVar *s = ctx->synctab.GetAndRemove(thr, pc, addr);
- if (s == 0)
- return;
if (IsAppMem(addr)) {
CHECK(!thr->is_freeing);
thr->is_freeing = true;
MemoryWrite(thr, pc, addr, kSizeLog1);
thr->is_freeing = false;
}
+ SyncVar *s = ctx->metamap.GetIfExistsAndLock(addr);
+ if (s == 0)
+ return;
+ if (common_flags()->detect_deadlocks) {
+ Callback cb(thr, pc);
+ ctx->dd->MutexDestroy(&cb, &s->dd);
+ ctx->dd->MutexInit(&cb, &s->dd);
+ }
+ bool unlock_locked = false;
if (flags()->report_destroy_locked
&& s->owner_tid != SyncVar::kInvalidTid
&& !s->is_broken) {
s->is_broken = true;
+ unlock_locked = true;
+ }
+ u64 mid = s->GetId();
+ u32 last_lock = s->last_lock;
+ if (!unlock_locked)
+ s->Reset(thr); // must not reset it before the report is printed
+ s->mtx.Unlock();
+ if (unlock_locked) {
ThreadRegistryLock l(ctx->thread_registry);
ScopedReport rep(ReportTypeMutexDestroyLocked);
- rep.AddMutex(s);
- StackTrace trace;
- trace.ObtainCurrent(thr, pc);
- rep.AddStack(&trace);
- FastState last(s->last_lock);
+ rep.AddMutex(mid);
+ VarSizeStackTrace trace;
+ ObtainCurrentStack(thr, pc, &trace);
+ rep.AddStack(trace);
+ FastState last(last_lock);
RestoreStack(last.tid(), last.epoch(), &trace, 0);
- rep.AddStack(&trace);
- rep.AddLocation(s->addr, 1);
- OutputReport(ctx, rep);
+ rep.AddStack(trace, true);
+ rep.AddLocation(addr, 1);
+ OutputReport(thr, rep);
+ }
+ if (unlock_locked) {
+ SyncVar *s = ctx->metamap.GetIfExistsAndLock(addr);
+ if (s != 0) {
+ s->Reset(thr);
+ s->mtx.Unlock();
+ }
}
- thr->mset.Remove(s->GetId());
- DestroyAndFree(s);
+ thr->mset.Remove(mid);
+ // s will be destroyed and freed in MetaMap::FreeBlock.
}
-void MutexLock(ThreadState *thr, uptr pc, uptr addr, int rec) {
- CHECK_GT(thr->in_rtl, 0);
+void MutexLock(ThreadState *thr, uptr pc, uptr addr, int rec, bool try_lock) {
DPrintf("#%d: MutexLock %zx rec=%d\n", thr->tid, addr, rec);
CHECK_GT(rec, 0);
if (IsAppMem(addr))
MemoryReadAtomic(thr, pc, addr, kSizeLog1);
- SyncVar *s = CTX()->synctab.GetOrCreateAndLock(thr, pc, addr, true);
+ SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true);
thr->fast_state.IncrementEpoch();
TraceAddEvent(thr, thr->fast_state, EventTypeLock, s->GetId());
+ bool report_double_lock = false;
if (s->owner_tid == SyncVar::kInvalidTid) {
CHECK_EQ(s->recursion, 0);
s->owner_tid = thr->tid;
s->last_lock = thr->fast_state.raw();
} else if (s->owner_tid == thr->tid) {
CHECK_GT(s->recursion, 0);
- } else {
- Printf("ThreadSanitizer WARNING: double lock of mutex %p\n", addr);
- PrintCurrentStack(thr, pc);
+ } else if (flags()->report_mutex_bugs && !s->is_broken) {
+ s->is_broken = true;
+ report_double_lock = true;
}
if (s->recursion == 0) {
StatInc(thr, StatMutexLock);
@@ -107,30 +172,36 @@ void MutexLock(ThreadState *thr, uptr pc, uptr addr, int rec) {
}
s->recursion += rec;
thr->mset.Add(s->GetId(), true, thr->fast_state.epoch());
+ if (common_flags()->detect_deadlocks && (s->recursion - rec) == 0) {
+ Callback cb(thr, pc);
+ if (!try_lock)
+ ctx->dd->MutexBeforeLock(&cb, &s->dd, true);
+ ctx->dd->MutexAfterLock(&cb, &s->dd, true, try_lock);
+ }
+ u64 mid = s->GetId();
s->mtx.Unlock();
+ // Can't touch s after this point.
+ if (report_double_lock)
+ ReportMutexMisuse(thr, pc, ReportTypeMutexDoubleLock, addr, mid);
+ if (common_flags()->detect_deadlocks) {
+ Callback cb(thr, pc);
+ ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb));
+ }
}
int MutexUnlock(ThreadState *thr, uptr pc, uptr addr, bool all) {
- CHECK_GT(thr->in_rtl, 0);
DPrintf("#%d: MutexUnlock %zx all=%d\n", thr->tid, addr, all);
if (IsAppMem(addr))
MemoryReadAtomic(thr, pc, addr, kSizeLog1);
- SyncVar *s = CTX()->synctab.GetOrCreateAndLock(thr, pc, addr, true);
+ SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true);
thr->fast_state.IncrementEpoch();
TraceAddEvent(thr, thr->fast_state, EventTypeUnlock, s->GetId());
int rec = 0;
- if (s->recursion == 0) {
- if (!s->is_broken) {
+ bool report_bad_unlock = false;
+ if (kCppMode && (s->recursion == 0 || s->owner_tid != thr->tid)) {
+ if (flags()->report_mutex_bugs && !s->is_broken) {
s->is_broken = true;
- Printf("ThreadSanitizer WARNING: unlock of unlocked mutex %p\n", addr);
- PrintCurrentStack(thr, pc);
- }
- } else if (s->owner_tid != thr->tid) {
- if (!s->is_broken) {
- s->is_broken = true;
- Printf("ThreadSanitizer WARNING: mutex %p is unlocked by wrong thread\n",
- addr);
- PrintCurrentStack(thr, pc);
+ report_bad_unlock = true;
}
} else {
rec = all ? s->recursion : 1;
@@ -144,56 +215,97 @@ int MutexUnlock(ThreadState *thr, uptr pc, uptr addr, bool all) {
}
}
thr->mset.Del(s->GetId(), true);
+ if (common_flags()->detect_deadlocks && s->recursion == 0 &&
+ !report_bad_unlock) {
+ Callback cb(thr, pc);
+ ctx->dd->MutexBeforeUnlock(&cb, &s->dd, true);
+ }
+ u64 mid = s->GetId();
s->mtx.Unlock();
+ // Can't touch s after this point.
+ if (report_bad_unlock)
+ ReportMutexMisuse(thr, pc, ReportTypeMutexBadUnlock, addr, mid);
+ if (common_flags()->detect_deadlocks && !report_bad_unlock) {
+ Callback cb(thr, pc);
+ ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb));
+ }
return rec;
}
-void MutexReadLock(ThreadState *thr, uptr pc, uptr addr) {
- CHECK_GT(thr->in_rtl, 0);
+void MutexReadLock(ThreadState *thr, uptr pc, uptr addr, bool trylock) {
DPrintf("#%d: MutexReadLock %zx\n", thr->tid, addr);
StatInc(thr, StatMutexReadLock);
if (IsAppMem(addr))
MemoryReadAtomic(thr, pc, addr, kSizeLog1);
- SyncVar *s = CTX()->synctab.GetOrCreateAndLock(thr, pc, addr, false);
+ SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, false);
thr->fast_state.IncrementEpoch();
TraceAddEvent(thr, thr->fast_state, EventTypeRLock, s->GetId());
+ bool report_bad_lock = false;
if (s->owner_tid != SyncVar::kInvalidTid) {
- Printf("ThreadSanitizer WARNING: read lock of a write locked mutex %p\n",
- addr);
- PrintCurrentStack(thr, pc);
+ if (flags()->report_mutex_bugs && !s->is_broken) {
+ s->is_broken = true;
+ report_bad_lock = true;
+ }
}
AcquireImpl(thr, pc, &s->clock);
s->last_lock = thr->fast_state.raw();
thr->mset.Add(s->GetId(), false, thr->fast_state.epoch());
+ if (common_flags()->detect_deadlocks && s->recursion == 0) {
+ Callback cb(thr, pc);
+ if (!trylock)
+ ctx->dd->MutexBeforeLock(&cb, &s->dd, false);
+ ctx->dd->MutexAfterLock(&cb, &s->dd, false, trylock);
+ }
+ u64 mid = s->GetId();
s->mtx.ReadUnlock();
+ // Can't touch s after this point.
+ if (report_bad_lock)
+ ReportMutexMisuse(thr, pc, ReportTypeMutexBadReadLock, addr, mid);
+ if (common_flags()->detect_deadlocks) {
+ Callback cb(thr, pc);
+ ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb));
+ }
}
void MutexReadUnlock(ThreadState *thr, uptr pc, uptr addr) {
- CHECK_GT(thr->in_rtl, 0);
DPrintf("#%d: MutexReadUnlock %zx\n", thr->tid, addr);
StatInc(thr, StatMutexReadUnlock);
if (IsAppMem(addr))
MemoryReadAtomic(thr, pc, addr, kSizeLog1);
- SyncVar *s = CTX()->synctab.GetOrCreateAndLock(thr, pc, addr, true);
+ SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true);
thr->fast_state.IncrementEpoch();
TraceAddEvent(thr, thr->fast_state, EventTypeRUnlock, s->GetId());
+ bool report_bad_unlock = false;
if (s->owner_tid != SyncVar::kInvalidTid) {
- Printf("ThreadSanitizer WARNING: read unlock of a write locked mutex %p\n",
- addr);
- PrintCurrentStack(thr, pc);
+ if (flags()->report_mutex_bugs && !s->is_broken) {
+ s->is_broken = true;
+ report_bad_unlock = true;
+ }
}
ReleaseImpl(thr, pc, &s->read_clock);
+ if (common_flags()->detect_deadlocks && s->recursion == 0) {
+ Callback cb(thr, pc);
+ ctx->dd->MutexBeforeUnlock(&cb, &s->dd, false);
+ }
+ u64 mid = s->GetId();
s->mtx.Unlock();
- thr->mset.Del(s->GetId(), false);
+ // Can't touch s after this point.
+ thr->mset.Del(mid, false);
+ if (report_bad_unlock)
+ ReportMutexMisuse(thr, pc, ReportTypeMutexBadReadUnlock, addr, mid);
+ if (common_flags()->detect_deadlocks) {
+ Callback cb(thr, pc);
+ ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb));
+ }
}
void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr) {
- CHECK_GT(thr->in_rtl, 0);
DPrintf("#%d: MutexReadOrWriteUnlock %zx\n", thr->tid, addr);
if (IsAppMem(addr))
MemoryReadAtomic(thr, pc, addr, kSizeLog1);
- SyncVar *s = CTX()->synctab.GetOrCreateAndLock(thr, pc, addr, true);
+ SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true);
bool write = true;
+ bool report_bad_unlock = false;
if (s->owner_tid == SyncVar::kInvalidTid) {
// Seems to be read unlock.
write = false;
@@ -216,30 +328,37 @@ void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr) {
}
} else if (!s->is_broken) {
s->is_broken = true;
- Printf("ThreadSanitizer WARNING: mutex %p is unlock by wrong thread\n",
- addr);
- PrintCurrentStack(thr, pc);
+ report_bad_unlock = true;
}
thr->mset.Del(s->GetId(), write);
+ if (common_flags()->detect_deadlocks && s->recursion == 0) {
+ Callback cb(thr, pc);
+ ctx->dd->MutexBeforeUnlock(&cb, &s->dd, write);
+ }
+ u64 mid = s->GetId();
s->mtx.Unlock();
+ // Can't touch s after this point.
+ if (report_bad_unlock)
+ ReportMutexMisuse(thr, pc, ReportTypeMutexBadUnlock, addr, mid);
+ if (common_flags()->detect_deadlocks) {
+ Callback cb(thr, pc);
+ ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb));
+ }
}
void MutexRepair(ThreadState *thr, uptr pc, uptr addr) {
- Context *ctx = CTX();
- CHECK_GT(thr->in_rtl, 0);
DPrintf("#%d: MutexRepair %zx\n", thr->tid, addr);
- SyncVar *s = ctx->synctab.GetOrCreateAndLock(thr, pc, addr, true);
+ SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true);
s->owner_tid = SyncVar::kInvalidTid;
s->recursion = 0;
s->mtx.Unlock();
}
void Acquire(ThreadState *thr, uptr pc, uptr addr) {
- CHECK_GT(thr->in_rtl, 0);
DPrintf("#%d: Acquire %zx\n", thr->tid, addr);
if (thr->ignore_sync)
return;
- SyncVar *s = CTX()->synctab.GetOrCreateAndLock(thr, pc, addr, false);
+ SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, false);
AcquireImpl(thr, pc, &s->clock);
s->mtx.ReadUnlock();
}
@@ -257,17 +376,16 @@ void AcquireGlobal(ThreadState *thr, uptr pc) {
DPrintf("#%d: AcquireGlobal\n", thr->tid);
if (thr->ignore_sync)
return;
- ThreadRegistryLock l(CTX()->thread_registry);
- CTX()->thread_registry->RunCallbackForEachThreadLocked(
+ ThreadRegistryLock l(ctx->thread_registry);
+ ctx->thread_registry->RunCallbackForEachThreadLocked(
UpdateClockCallback, thr);
}
void Release(ThreadState *thr, uptr pc, uptr addr) {
- CHECK_GT(thr->in_rtl, 0);
DPrintf("#%d: Release %zx\n", thr->tid, addr);
if (thr->ignore_sync)
return;
- SyncVar *s = CTX()->synctab.GetOrCreateAndLock(thr, pc, addr, true);
+ SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true);
thr->fast_state.IncrementEpoch();
// Can't increment epoch w/o writing to the trace as well.
TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0);
@@ -276,11 +394,10 @@ void Release(ThreadState *thr, uptr pc, uptr addr) {
}
void ReleaseStore(ThreadState *thr, uptr pc, uptr addr) {
- CHECK_GT(thr->in_rtl, 0);
DPrintf("#%d: ReleaseStore %zx\n", thr->tid, addr);
if (thr->ignore_sync)
return;
- SyncVar *s = CTX()->synctab.GetOrCreateAndLock(thr, pc, addr, true);
+ SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true);
thr->fast_state.IncrementEpoch();
// Can't increment epoch w/o writing to the trace as well.
TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0);
@@ -288,7 +405,7 @@ void ReleaseStore(ThreadState *thr, uptr pc, uptr addr) {
s->mtx.Unlock();
}
-#ifndef TSAN_GO
+#ifndef SANITIZER_GO
static void UpdateSleepClockCallback(ThreadContextBase *tctx_base, void *arg) {
ThreadState *thr = reinterpret_cast<ThreadState*>(arg);
ThreadContext *tctx = static_cast<ThreadContext*>(tctx_base);
@@ -303,8 +420,8 @@ void AfterSleep(ThreadState *thr, uptr pc) {
if (thr->ignore_sync)
return;
thr->last_sleep_stack_id = CurrentStackId(thr, pc);
- ThreadRegistryLock l(CTX()->thread_registry);
- CTX()->thread_registry->RunCallbackForEachThreadLocked(
+ ThreadRegistryLock l(ctx->thread_registry);
+ ctx->thread_registry->RunCallbackForEachThreadLocked(
UpdateSleepClockCallback, thr);
}
#endif
@@ -312,37 +429,63 @@ void AfterSleep(ThreadState *thr, uptr pc) {
void AcquireImpl(ThreadState *thr, uptr pc, SyncClock *c) {
if (thr->ignore_sync)
return;
- thr->clock.set(thr->tid, thr->fast_state.epoch());
- thr->clock.acquire(c);
+ thr->clock.set(thr->fast_state.epoch());
+ thr->clock.acquire(&thr->clock_cache, c);
StatInc(thr, StatSyncAcquire);
}
void ReleaseImpl(ThreadState *thr, uptr pc, SyncClock *c) {
if (thr->ignore_sync)
return;
- thr->clock.set(thr->tid, thr->fast_state.epoch());
+ thr->clock.set(thr->fast_state.epoch());
thr->fast_synch_epoch = thr->fast_state.epoch();
- thr->clock.release(c);
+ thr->clock.release(&thr->clock_cache, c);
StatInc(thr, StatSyncRelease);
}
void ReleaseStoreImpl(ThreadState *thr, uptr pc, SyncClock *c) {
if (thr->ignore_sync)
return;
- thr->clock.set(thr->tid, thr->fast_state.epoch());
+ thr->clock.set(thr->fast_state.epoch());
thr->fast_synch_epoch = thr->fast_state.epoch();
- thr->clock.ReleaseStore(c);
+ thr->clock.ReleaseStore(&thr->clock_cache, c);
StatInc(thr, StatSyncRelease);
}
void AcquireReleaseImpl(ThreadState *thr, uptr pc, SyncClock *c) {
if (thr->ignore_sync)
return;
- thr->clock.set(thr->tid, thr->fast_state.epoch());
+ thr->clock.set(thr->fast_state.epoch());
thr->fast_synch_epoch = thr->fast_state.epoch();
- thr->clock.acq_rel(c);
+ thr->clock.acq_rel(&thr->clock_cache, c);
StatInc(thr, StatSyncAcquire);
StatInc(thr, StatSyncRelease);
}
+void ReportDeadlock(ThreadState *thr, uptr pc, DDReport *r) {
+ if (r == 0)
+ return;
+ ThreadRegistryLock l(ctx->thread_registry);
+ ScopedReport rep(ReportTypeDeadlock);
+ for (int i = 0; i < r->n; i++) {
+ rep.AddMutex(r->loop[i].mtx_ctx0);
+ rep.AddUniqueTid((int)r->loop[i].thr_ctx);
+ rep.AddThread((int)r->loop[i].thr_ctx);
+ }
+ uptr dummy_pc = 0x42;
+ for (int i = 0; i < r->n; i++) {
+ for (int j = 0; j < (flags()->second_deadlock_stack ? 2 : 1); j++) {
+ u32 stk = r->loop[i].stk[j];
+ if (stk) {
+ rep.AddStack(StackDepotGet(stk), true);
+ } else {
+ // Sometimes we fail to extract the stack trace (FIXME: investigate),
+ // but we should still produce some stack trace in the report.
+ rep.AddStack(StackTrace(&dummy_pc, 1), true);
+ }
+ }
+ }
+ OutputReport(thr, rep);
+}
+
} // namespace __tsan
diff --git a/lib/tsan/rtl/tsan_rtl_report.cc b/lib/tsan/rtl/tsan_rtl_report.cc
index 4fed43faf25f..0481b23b7be0 100644
--- a/lib/tsan/rtl/tsan_rtl_report.cc
+++ b/lib/tsan/rtl/tsan_rtl_report.cc
@@ -30,15 +30,18 @@ namespace __tsan {
using namespace __sanitizer; // NOLINT
-static ReportStack *SymbolizeStack(const StackTrace& trace);
+static ReportStack *SymbolizeStack(StackTrace trace);
void TsanCheckFailed(const char *file, int line, const char *cond,
u64 v1, u64 v2) {
- ScopedInRtl in_rtl;
+ // There is high probability that interceptors will check-fail as well,
+ // on the other hand there is no sense in processing interceptors
+ // since we are going to die soon.
+ ScopedIgnoreInterceptors ignore;
Printf("FATAL: ThreadSanitizer CHECK failed: "
"%s:%d \"%s\" (0x%zx, 0x%zx)\n",
file, line, cond, (uptr)v1, (uptr)v2);
- PrintCurrentStackSlow();
+ PrintCurrentStackSlow(StackTrace::GetCurrentPc());
Die();
}
@@ -53,108 +56,113 @@ bool WEAK OnReport(const ReportDesc *rep, bool suppressed) {
}
#endif
-static void StackStripMain(ReportStack *stack) {
- ReportStack *last_frame = 0;
- ReportStack *last_frame2 = 0;
- const char *prefix = "__interceptor_";
- uptr prefix_len = internal_strlen(prefix);
- const char *path_prefix = flags()->strip_path_prefix;
- uptr path_prefix_len = internal_strlen(path_prefix);
- char *pos;
- for (ReportStack *ent = stack; ent; ent = ent->next) {
- if (ent->func && 0 == internal_strncmp(ent->func, prefix, prefix_len))
- ent->func += prefix_len;
- if (ent->file && (pos = internal_strstr(ent->file, path_prefix)))
- ent->file = pos + path_prefix_len;
- if (ent->file && ent->file[0] == '.' && ent->file[1] == '/')
- ent->file += 2;
+static void StackStripMain(SymbolizedStack *frames) {
+ SymbolizedStack *last_frame = nullptr;
+ SymbolizedStack *last_frame2 = nullptr;
+ for (SymbolizedStack *cur = frames; cur; cur = cur->next) {
last_frame2 = last_frame;
- last_frame = ent;
+ last_frame = cur;
}
if (last_frame2 == 0)
return;
- const char *last = last_frame->func;
-#ifndef TSAN_GO
- const char *last2 = last_frame2->func;
+#ifndef SANITIZER_GO
+ const char *last = last_frame->info.function;
+ const char *last2 = last_frame2->info.function;
// Strip frame above 'main'
if (last2 && 0 == internal_strcmp(last2, "main")) {
- last_frame2->next = 0;
+ last_frame->ClearAll();
+ last_frame2->next = nullptr;
// Strip our internal thread start routine.
} else if (last && 0 == internal_strcmp(last, "__tsan_thread_start_func")) {
- last_frame2->next = 0;
+ last_frame->ClearAll();
+ last_frame2->next = nullptr;
// Strip global ctors init.
} else if (last && 0 == internal_strcmp(last, "__do_global_ctors_aux")) {
- last_frame2->next = 0;
+ last_frame->ClearAll();
+ last_frame2->next = nullptr;
// If both are 0, then we probably just failed to symbolize.
} else if (last || last2) {
// Ensure that we recovered stack completely. Trimmed stack
// can actually happen if we do not instrument some code,
// so it's only a debug print. However we must try hard to not miss it
// due to our fault.
- DPrintf("Bottom stack frame of stack %zx is missed\n", stack->pc);
+ DPrintf("Bottom stack frame of stack %zx is missed\n", stack->info.address);
}
#else
// The last frame always point into runtime (gosched0, goexit0, runtime.main).
- last_frame2->next = 0;
- (void)last;
+ last_frame->ClearAll();
+ last_frame2->next = nullptr;
#endif
}
-static ReportStack *SymbolizeStack(const StackTrace& trace) {
- if (trace.IsEmpty())
+ReportStack *SymbolizeStackId(u32 stack_id) {
+ if (stack_id == 0)
return 0;
- ReportStack *stack = 0;
- for (uptr si = 0; si < trace.Size(); si++) {
- const uptr pc = trace.Get(si);
-#ifndef TSAN_GO
- // We obtain the return address, that is, address of the next instruction,
- // so offset it by 1 byte.
- const uptr pc1 = __sanitizer::StackTrace::GetPreviousInstructionPc(pc);
+ StackTrace stack = StackDepotGet(stack_id);
+ if (stack.trace == nullptr)
+ return nullptr;
+ return SymbolizeStack(stack);
+}
+
+static ReportStack *SymbolizeStack(StackTrace trace) {
+ if (trace.size == 0)
+ return 0;
+ SymbolizedStack *top = nullptr;
+ for (uptr si = 0; si < trace.size; si++) {
+ const uptr pc = trace.trace[si];
+ uptr pc1 = pc;
+#ifndef SANITIZER_GO
+ // We obtain the return address, but we're interested in the previous
+ // instruction.
+ if ((pc & kExternalPCBit) == 0)
+ pc1 = StackTrace::GetPreviousInstructionPc(pc);
#else
// FIXME(dvyukov): Go sometimes uses address of a function as top pc.
- uptr pc1 = pc;
- if (si != trace.Size() - 1)
+ if (si != trace.size - 1)
pc1 -= 1;
#endif
- ReportStack *ent = SymbolizeCode(pc1);
+ SymbolizedStack *ent = SymbolizeCode(pc1);
CHECK_NE(ent, 0);
- ReportStack *last = ent;
+ SymbolizedStack *last = ent;
while (last->next) {
- last->pc = pc; // restore original pc for report
+ last->info.address = pc; // restore original pc for report
last = last->next;
}
- last->pc = pc; // restore original pc for report
- last->next = stack;
- stack = ent;
+ last->info.address = pc; // restore original pc for report
+ last->next = top;
+ top = ent;
}
- StackStripMain(stack);
+ StackStripMain(top);
+
+ ReportStack *stack = ReportStack::New();
+ stack->frames = top;
return stack;
}
ScopedReport::ScopedReport(ReportType typ) {
- ctx_ = CTX();
- ctx_->thread_registry->CheckLocked();
+ ctx->thread_registry->CheckLocked();
void *mem = internal_alloc(MBlockReport, sizeof(ReportDesc));
rep_ = new(mem) ReportDesc;
rep_->typ = typ;
- ctx_->report_mtx.Lock();
+ ctx->report_mtx.Lock();
CommonSanitizerReportMutex.Lock();
}
ScopedReport::~ScopedReport() {
CommonSanitizerReportMutex.Unlock();
- ctx_->report_mtx.Unlock();
+ ctx->report_mtx.Unlock();
DestroyAndFree(rep_);
}
-void ScopedReport::AddStack(const StackTrace *stack) {
+void ScopedReport::AddStack(StackTrace stack, bool suppressable) {
ReportStack **rs = rep_->stacks.PushBack();
- *rs = SymbolizeStack(*stack);
+ *rs = SymbolizeStack(stack);
+ (*rs)->suppressable = suppressable;
}
-void ScopedReport::AddMemoryAccess(uptr addr, Shadow s,
- const StackTrace *stack, const MutexSet *mset) {
+void ScopedReport::AddMemoryAccess(uptr addr, Shadow s, StackTrace stack,
+ const MutexSet *mset) {
void *mem = internal_alloc(MBlockReportMop, sizeof(ReportMop));
ReportMop *mop = new(mem) ReportMop;
rep_->mops.PushBack(mop);
@@ -163,30 +171,22 @@ void ScopedReport::AddMemoryAccess(uptr addr, Shadow s,
mop->size = s.size();
mop->write = s.IsWrite();
mop->atomic = s.IsAtomic();
- mop->stack = SymbolizeStack(*stack);
+ mop->stack = SymbolizeStack(stack);
+ if (mop->stack)
+ mop->stack->suppressable = true;
for (uptr i = 0; i < mset->Size(); i++) {
MutexSet::Desc d = mset->Get(i);
- u64 uid = 0;
- uptr addr = SyncVar::SplitId(d.id, &uid);
- SyncVar *s = ctx_->synctab.GetIfExistsAndLock(addr, false);
- // Check that the mutex is still alive.
- // Another mutex can be created at the same address,
- // so check uid as well.
- if (s && s->CheckId(uid)) {
- ReportMopMutex mtx = {s->uid, d.write};
- mop->mset.PushBack(mtx);
- AddMutex(s);
- } else {
- ReportMopMutex mtx = {d.id, d.write};
- mop->mset.PushBack(mtx);
- AddMutex(d.id);
- }
- if (s)
- s->mtx.ReadUnlock();
+ u64 mid = this->AddMutex(d.id);
+ ReportMopMutex mtx = {mid, d.write};
+ mop->mset.PushBack(mtx);
}
}
-void ScopedReport::AddThread(const ThreadContext *tctx) {
+void ScopedReport::AddUniqueTid(int unique_tid) {
+ rep_->unique_tids.PushBack(unique_tid);
+}
+
+void ScopedReport::AddThread(const ThreadContext *tctx, bool suppressable) {
for (uptr i = 0; i < rep_->threads.Size(); i++) {
if ((u32)rep_->threads[i]->id == tctx->tid)
return;
@@ -197,25 +197,16 @@ void ScopedReport::AddThread(const ThreadContext *tctx) {
rt->id = tctx->tid;
rt->pid = tctx->os_id;
rt->running = (tctx->status == ThreadStatusRunning);
- rt->name = tctx->name ? internal_strdup(tctx->name) : 0;
+ rt->name = internal_strdup(tctx->name);
rt->parent_tid = tctx->parent_tid;
rt->stack = 0;
-#ifdef TSAN_GO
- rt->stack = SymbolizeStack(tctx->creation_stack);
-#else
- uptr ssz = 0;
- const uptr *stack = StackDepotGet(tctx->creation_stack_id, &ssz);
- if (stack) {
- StackTrace trace;
- trace.Init(stack, ssz);
- rt->stack = SymbolizeStack(trace);
- }
-#endif
+ rt->stack = SymbolizeStackId(tctx->creation_stack_id);
+ if (rt->stack)
+ rt->stack->suppressable = suppressable;
}
-#ifndef TSAN_GO
+#ifndef SANITIZER_GO
static ThreadContext *FindThreadByUidLocked(int unique_id) {
- Context *ctx = CTX();
ctx->thread_registry->CheckLocked();
for (unsigned i = 0; i < kMaxTid; i++) {
ThreadContext *tctx = static_cast<ThreadContext*>(
@@ -228,7 +219,6 @@ static ThreadContext *FindThreadByUidLocked(int unique_id) {
}
static ThreadContext *FindThreadByTidLocked(int tid) {
- Context *ctx = CTX();
ctx->thread_registry->CheckLocked();
return static_cast<ThreadContext*>(
ctx->thread_registry->GetThreadLocked(tid));
@@ -246,7 +236,6 @@ static bool IsInStackOrTls(ThreadContextBase *tctx_base, void *arg) {
}
ThreadContext *IsThreadStackOrTls(uptr addr, bool *is_stack) {
- Context *ctx = CTX();
ctx->thread_registry->CheckLocked();
ThreadContext *tctx = static_cast<ThreadContext*>(
ctx->thread_registry->FindThreadContextLocked(IsInStackOrTls,
@@ -260,6 +249,12 @@ ThreadContext *IsThreadStackOrTls(uptr addr, bool *is_stack) {
}
#endif
+void ScopedReport::AddThread(int unique_tid, bool suppressable) {
+#ifndef SANITIZER_GO
+ AddThread(FindThreadByUidLocked(unique_tid), suppressable);
+#endif
+}
+
void ScopedReport::AddMutex(const SyncVar *s) {
for (uptr i = 0; i < rep_->mutexes.Size(); i++) {
if (rep_->mutexes[i]->id == s->uid)
@@ -269,20 +264,31 @@ void ScopedReport::AddMutex(const SyncVar *s) {
ReportMutex *rm = new(mem) ReportMutex();
rep_->mutexes.PushBack(rm);
rm->id = s->uid;
+ rm->addr = s->addr;
rm->destroyed = false;
- rm->stack = 0;
-#ifndef TSAN_GO
- uptr ssz = 0;
- const uptr *stack = StackDepotGet(s->creation_stack_id, &ssz);
- if (stack) {
- StackTrace trace;
- trace.Init(stack, ssz);
- rm->stack = SymbolizeStack(trace);
- }
-#endif
+ rm->stack = SymbolizeStackId(s->creation_stack_id);
}
-void ScopedReport::AddMutex(u64 id) {
+u64 ScopedReport::AddMutex(u64 id) {
+ u64 uid = 0;
+ u64 mid = id;
+ uptr addr = SyncVar::SplitId(id, &uid);
+ SyncVar *s = ctx->metamap.GetIfExistsAndLock(addr);
+ // Check that the mutex is still alive.
+ // Another mutex can be created at the same address,
+ // so check uid as well.
+ if (s && s->CheckId(uid)) {
+ mid = s->uid;
+ AddMutex(s);
+ } else {
+ AddDeadMutex(id);
+ }
+ if (s)
+ s->mtx.Unlock();
+ return mid;
+}
+
+void ScopedReport::AddDeadMutex(u64 id) {
for (uptr i = 0; i < rep_->mutexes.Size(); i++) {
if (rep_->mutexes[i]->id == id)
return;
@@ -291,6 +297,7 @@ void ScopedReport::AddMutex(u64 id) {
ReportMutex *rm = new(mem) ReportMutex();
rep_->mutexes.PushBack(rm);
rm->id = id;
+ rm->addr = 0;
rm->destroyed = true;
rm->stack = 0;
}
@@ -298,82 +305,59 @@ void ScopedReport::AddMutex(u64 id) {
void ScopedReport::AddLocation(uptr addr, uptr size) {
if (addr == 0)
return;
-#ifndef TSAN_GO
+#ifndef SANITIZER_GO
int fd = -1;
int creat_tid = -1;
u32 creat_stack = 0;
- if (FdLocation(addr, &fd, &creat_tid, &creat_stack)
- || FdLocation(AlternativeAddress(addr), &fd, &creat_tid, &creat_stack)) {
- void *mem = internal_alloc(MBlockReportLoc, sizeof(ReportLocation));
- ReportLocation *loc = new(mem) ReportLocation();
- rep_->locs.PushBack(loc);
- loc->type = ReportLocationFD;
+ if (FdLocation(addr, &fd, &creat_tid, &creat_stack)) {
+ ReportLocation *loc = ReportLocation::New(ReportLocationFD);
loc->fd = fd;
loc->tid = creat_tid;
- uptr ssz = 0;
- const uptr *stack = StackDepotGet(creat_stack, &ssz);
- if (stack) {
- StackTrace trace;
- trace.Init(stack, ssz);
- loc->stack = SymbolizeStack(trace);
- }
+ loc->stack = SymbolizeStackId(creat_stack);
+ rep_->locs.PushBack(loc);
ThreadContext *tctx = FindThreadByUidLocked(creat_tid);
if (tctx)
AddThread(tctx);
return;
}
MBlock *b = 0;
- if (allocator()->PointerIsMine((void*)addr)
- && (b = user_mblock(0, (void*)addr))) {
- ThreadContext *tctx = FindThreadByTidLocked(b->Tid());
- void *mem = internal_alloc(MBlockReportLoc, sizeof(ReportLocation));
- ReportLocation *loc = new(mem) ReportLocation();
+ Allocator *a = allocator();
+ if (a->PointerIsMine((void*)addr)) {
+ void *block_begin = a->GetBlockBegin((void*)addr);
+ if (block_begin)
+ b = ctx->metamap.GetBlock((uptr)block_begin);
+ }
+ if (b != 0) {
+ ThreadContext *tctx = FindThreadByTidLocked(b->tid);
+ ReportLocation *loc = ReportLocation::New(ReportLocationHeap);
+ loc->heap_chunk_start = (uptr)allocator()->GetBlockBegin((void *)addr);
+ loc->heap_chunk_size = b->siz;
+ loc->tid = tctx ? tctx->tid : b->tid;
+ loc->stack = SymbolizeStackId(b->stk);
rep_->locs.PushBack(loc);
- loc->type = ReportLocationHeap;
- loc->addr = (uptr)allocator()->GetBlockBegin((void*)addr);
- loc->size = b->Size();
- loc->tid = tctx ? tctx->tid : b->Tid();
- loc->name = 0;
- loc->file = 0;
- loc->line = 0;
- loc->stack = 0;
- uptr ssz = 0;
- const uptr *stack = StackDepotGet(b->StackId(), &ssz);
- if (stack) {
- StackTrace trace;
- trace.Init(stack, ssz);
- loc->stack = SymbolizeStack(trace);
- }
if (tctx)
AddThread(tctx);
return;
}
bool is_stack = false;
if (ThreadContext *tctx = IsThreadStackOrTls(addr, &is_stack)) {
- void *mem = internal_alloc(MBlockReportLoc, sizeof(ReportLocation));
- ReportLocation *loc = new(mem) ReportLocation();
- rep_->locs.PushBack(loc);
- loc->type = is_stack ? ReportLocationStack : ReportLocationTLS;
+ ReportLocation *loc =
+ ReportLocation::New(is_stack ? ReportLocationStack : ReportLocationTLS);
loc->tid = tctx->tid;
+ rep_->locs.PushBack(loc);
AddThread(tctx);
}
- ReportLocation *loc = SymbolizeData(addr);
- if (loc) {
+ if (ReportLocation *loc = SymbolizeData(addr)) {
+ loc->suppressable = true;
rep_->locs.PushBack(loc);
return;
}
#endif
}
-#ifndef TSAN_GO
+#ifndef SANITIZER_GO
void ScopedReport::AddSleep(u32 stack_id) {
- uptr ssz = 0;
- const uptr *stack = StackDepotGet(stack_id, &ssz);
- if (stack) {
- StackTrace trace;
- trace.Init(stack, ssz);
- rep_->sleep = SymbolizeStack(trace);
- }
+ rep_->sleep = SymbolizeStackId(stack_id);
}
#endif
@@ -385,11 +369,11 @@ const ReportDesc *ScopedReport::GetReport() const {
return rep_;
}
-void RestoreStack(int tid, const u64 epoch, StackTrace *stk, MutexSet *mset) {
+void RestoreStack(int tid, const u64 epoch, VarSizeStackTrace *stk,
+ MutexSet *mset) {
// This function restores stack trace and mutex set for the thread/epoch.
// It does so by getting stack trace and mutex set at the beginning of
// trace part, and then replaying the trace till the given epoch.
- Context *ctx = CTX();
ctx->thread_registry->CheckLocked();
ThreadContext *tctx = static_cast<ThreadContext*>(
ctx->thread_registry->GetThreadLocked(tid));
@@ -411,13 +395,13 @@ void RestoreStack(int tid, const u64 epoch, StackTrace *stk, MutexSet *mset) {
DPrintf("#%d: RestoreStack epoch=%zu ebegin=%zu eend=%zu partidx=%d\n",
tid, (uptr)epoch, (uptr)ebegin, (uptr)eend, partidx);
InternalScopedBuffer<uptr> stack(kShadowStackSize);
- for (uptr i = 0; i < hdr->stack0.Size(); i++) {
- stack[i] = hdr->stack0.Get(i);
+ for (uptr i = 0; i < hdr->stack0.size; i++) {
+ stack[i] = hdr->stack0.trace[i];
DPrintf2(" #%02lu: pc=%zx\n", i, stack[i]);
}
if (mset)
*mset = hdr->mset0;
- uptr pos = hdr->stack0.Size();
+ uptr pos = hdr->stack0.size;
Event *events = (Event*)GetThreadTrace(tid);
for (uptr i = ebegin; i <= eend; i++) {
Event ev = events[i];
@@ -452,14 +436,13 @@ void RestoreStack(int tid, const u64 epoch, StackTrace *stk, MutexSet *mset) {
stk->Init(stack.data(), pos);
}
-static bool HandleRacyStacks(ThreadState *thr, const StackTrace (&traces)[2],
- uptr addr_min, uptr addr_max) {
- Context *ctx = CTX();
+static bool HandleRacyStacks(ThreadState *thr, VarSizeStackTrace traces[2],
+ uptr addr_min, uptr addr_max) {
bool equal_stack = false;
RacyStacks hash;
if (flags()->suppress_equal_stacks) {
- hash.hash[0] = md5_hash(traces[0].Begin(), traces[0].Size() * sizeof(uptr));
- hash.hash[1] = md5_hash(traces[1].Begin(), traces[1].Size() * sizeof(uptr));
+ hash.hash[0] = md5_hash(traces[0].trace, traces[0].size * sizeof(uptr));
+ hash.hash[1] = md5_hash(traces[1].trace, traces[1].size * sizeof(uptr));
for (uptr i = 0; i < ctx->racy_stacks.Size(); i++) {
if (hash == ctx->racy_stacks[i]) {
DPrintf("ThreadSanitizer: suppressing report as doubled (stack)\n");
@@ -492,13 +475,12 @@ static bool HandleRacyStacks(ThreadState *thr, const StackTrace (&traces)[2],
return false;
}
-static void AddRacyStacks(ThreadState *thr, const StackTrace (&traces)[2],
- uptr addr_min, uptr addr_max) {
- Context *ctx = CTX();
+static void AddRacyStacks(ThreadState *thr, VarSizeStackTrace traces[2],
+ uptr addr_min, uptr addr_max) {
if (flags()->suppress_equal_stacks) {
RacyStacks hash;
- hash.hash[0] = md5_hash(traces[0].Begin(), traces[0].Size() * sizeof(uptr));
- hash.hash[1] = md5_hash(traces[1].Begin(), traces[1].Size() * sizeof(uptr));
+ hash.hash[0] = md5_hash(traces[0].trace, traces[0].size * sizeof(uptr));
+ hash.hash[1] = md5_hash(traces[1].trace, traces[1].size * sizeof(uptr));
ctx->racy_stacks.PushBack(hash);
}
if (flags()->suppress_equal_addresses) {
@@ -507,25 +489,31 @@ static void AddRacyStacks(ThreadState *thr, const StackTrace (&traces)[2],
}
}
-bool OutputReport(Context *ctx,
- const ScopedReport &srep,
- const ReportStack *suppress_stack1,
- const ReportStack *suppress_stack2,
- const ReportLocation *suppress_loc) {
+bool OutputReport(ThreadState *thr, const ScopedReport &srep) {
atomic_store(&ctx->last_symbolize_time_ns, NanoTime(), memory_order_relaxed);
const ReportDesc *rep = srep.GetReport();
Suppression *supp = 0;
- uptr suppress_pc = IsSuppressed(rep->typ, suppress_stack1, &supp);
- if (suppress_pc == 0)
- suppress_pc = IsSuppressed(rep->typ, suppress_stack2, &supp);
- if (suppress_pc == 0)
- suppress_pc = IsSuppressed(rep->typ, suppress_loc, &supp);
+ uptr suppress_pc = 0;
+ for (uptr i = 0; suppress_pc == 0 && i < rep->mops.Size(); i++)
+ suppress_pc = IsSuppressed(rep->typ, rep->mops[i]->stack, &supp);
+ for (uptr i = 0; suppress_pc == 0 && i < rep->stacks.Size(); i++)
+ suppress_pc = IsSuppressed(rep->typ, rep->stacks[i], &supp);
+ for (uptr i = 0; suppress_pc == 0 && i < rep->threads.Size(); i++)
+ suppress_pc = IsSuppressed(rep->typ, rep->threads[i]->stack, &supp);
+ for (uptr i = 0; suppress_pc == 0 && i < rep->locs.Size(); i++)
+ suppress_pc = IsSuppressed(rep->typ, rep->locs[i], &supp);
if (suppress_pc != 0) {
FiredSuppression s = {srep.GetReport()->typ, suppress_pc, supp};
ctx->fired_suppressions.push_back(s);
}
- if (OnReport(rep, suppress_pc != 0))
- return false;
+ {
+ bool old_is_freeing = thr->is_freeing;
+ thr->is_freeing = false;
+ bool suppressed = OnReport(rep, suppress_pc != 0);
+ thr->is_freeing = old_is_freeing;
+ if (suppressed)
+ return false;
+ }
PrintReport(rep);
ctx->nreported++;
if (flags()->halt_on_error)
@@ -533,15 +521,14 @@ bool OutputReport(Context *ctx,
return true;
}
-bool IsFiredSuppression(Context *ctx,
- const ScopedReport &srep,
- const StackTrace &trace) {
+bool IsFiredSuppression(Context *ctx, const ScopedReport &srep,
+ StackTrace trace) {
for (uptr k = 0; k < ctx->fired_suppressions.size(); k++) {
if (ctx->fired_suppressions[k].type != srep.GetReport()->typ)
continue;
- for (uptr j = 0; j < trace.Size(); j++) {
+ for (uptr j = 0; j < trace.size; j++) {
FiredSuppression *s = &ctx->fired_suppressions[k];
- if (trace.Get(j) == s->pc) {
+ if (trace.trace[j] == s->pc) {
if (s->supp)
s->supp->hit_count++;
return true;
@@ -567,48 +554,6 @@ static bool IsFiredSuppression(Context *ctx,
return false;
}
-bool FrameIsInternal(const ReportStack *frame) {
- return frame != 0 && frame->file != 0
- && (internal_strstr(frame->file, "tsan_interceptors.cc") ||
- internal_strstr(frame->file, "sanitizer_common_interceptors.inc") ||
- internal_strstr(frame->file, "tsan_interface_"));
-}
-
-// On programs that use Java we see weird reports like:
-// WARNING: ThreadSanitizer: data race (pid=22512)
-// Read of size 8 at 0x7d2b00084318 by thread 100:
-// #0 memcpy tsan_interceptors.cc:406 (foo+0x00000d8dfae3)
-// #1 <null> <null>:0 (0x7f7ad9b40193)
-// Previous write of size 8 at 0x7d2b00084318 by thread 105:
-// #0 strncpy tsan_interceptors.cc:501 (foo+0x00000d8e0919)
-// #1 <null> <null>:0 (0x7f7ad9b42707)
-static bool IsJavaNonsense(const ReportDesc *rep) {
-#ifndef TSAN_GO
- for (uptr i = 0; i < rep->mops.Size(); i++) {
- ReportMop *mop = rep->mops[i];
- ReportStack *frame = mop->stack;
- if (frame == 0
- || (frame->func == 0 && frame->file == 0 && frame->line == 0
- && frame->module == 0)) {
- return true;
- }
- if (FrameIsInternal(frame)) {
- frame = frame->next;
- if (frame == 0
- || (frame->func == 0 && frame->file == 0 && frame->line == 0
- && frame->module == 0)) {
- if (frame) {
- FiredSuppression supp = {rep->typ, frame->pc, 0};
- CTX()->fired_suppressions.push_back(supp);
- }
- return true;
- }
- }
- }
-#endif
- return false;
-}
-
static bool RaceBetweenAtomicAndFree(ThreadState *thr) {
Shadow s0(thr->racy_state[0]);
Shadow s1(thr->racy_state[1]);
@@ -623,10 +568,14 @@ static bool RaceBetweenAtomicAndFree(ThreadState *thr) {
}
void ReportRace(ThreadState *thr) {
+ CheckNoLocks(thr);
+
+ // Symbolizer makes lots of intercepted calls. If we try to process them,
+ // at best it will cause deadlocks on internal mutexes.
+ ScopedIgnoreInterceptors ignore;
+
if (!flags()->report_bugs)
return;
- ScopedInRtl in_rtl;
-
if (!flags()->report_atomic_races && !RaceBetweenAtomicAndFree(thr))
return;
@@ -651,11 +600,12 @@ void ReportRace(ThreadState *thr) {
return;
}
- Context *ctx = CTX();
ThreadRegistryLock l0(ctx->thread_registry);
ReportType typ = ReportTypeRace;
- if (thr->is_vptr_access)
+ if (thr->is_vptr_access && freed)
+ typ = ReportTypeVptrUseAfterFree;
+ else if (thr->is_vptr_access)
typ = ReportTypeVptrRace;
else if (freed)
typ = ReportTypeUseAfterFree;
@@ -663,9 +613,9 @@ void ReportRace(ThreadState *thr) {
if (IsFiredSuppression(ctx, rep, addr))
return;
const uptr kMop = 2;
- StackTrace traces[kMop];
+ VarSizeStackTrace traces[kMop];
const uptr toppc = TraceTopPC(thr);
- traces[0].ObtainCurrent(thr, toppc);
+ ObtainCurrentStack(thr, toppc, &traces[0]);
if (IsFiredSuppression(ctx, rep, traces[0]))
return;
InternalScopedBuffer<MutexSet> mset2(1);
@@ -680,13 +630,10 @@ void ReportRace(ThreadState *thr) {
for (uptr i = 0; i < kMop; i++) {
Shadow s(thr->racy_state[i]);
- rep.AddMemoryAccess(addr, s, &traces[i],
+ rep.AddMemoryAccess(addr, s, traces[i],
i == 0 ? &thr->mset : mset2.data());
}
- if (flags()->suppress_java && IsJavaNonsense(rep.GetReport()))
- return;
-
for (uptr i = 0; i < kMop; i++) {
FastState s(thr->racy_state[i]);
ThreadContext *tctx = static_cast<ThreadContext*>(
@@ -698,7 +645,7 @@ void ReportRace(ThreadState *thr) {
rep.AddLocation(addr_min, addr_max - addr_min);
-#ifndef TSAN_GO
+#ifndef SANITIZER_GO
{ // NOLINT
Shadow s(thr->racy_state[1]);
if (s.epoch() <= thr->last_sleep_clock.get(s.tid()))
@@ -706,37 +653,40 @@ void ReportRace(ThreadState *thr) {
}
#endif
- ReportLocation *suppress_loc = rep.GetReport()->locs.Size() ?
- rep.GetReport()->locs[0] : 0;
- if (!OutputReport(ctx, rep, rep.GetReport()->mops[0]->stack,
- rep.GetReport()->mops[1]->stack,
- suppress_loc))
+ if (!OutputReport(thr, rep))
return;
AddRacyStacks(thr, traces, addr_min, addr_max);
}
void PrintCurrentStack(ThreadState *thr, uptr pc) {
- StackTrace trace;
- trace.ObtainCurrent(thr, pc);
+ VarSizeStackTrace trace;
+ ObtainCurrentStack(thr, pc, &trace);
PrintStack(SymbolizeStack(trace));
}
-void PrintCurrentStackSlow() {
-#ifndef TSAN_GO
- __sanitizer::StackTrace *ptrace = new(internal_alloc(MBlockStackTrace,
- sizeof(__sanitizer::StackTrace))) __sanitizer::StackTrace;
- ptrace->Unwind(kStackTraceMax, __sanitizer::StackTrace::GetCurrentPc(),
- 0, 0, 0, false);
+void PrintCurrentStackSlow(uptr pc) {
+#ifndef SANITIZER_GO
+ BufferedStackTrace *ptrace =
+ new(internal_alloc(MBlockStackTrace, sizeof(BufferedStackTrace)))
+ BufferedStackTrace();
+ ptrace->Unwind(kStackTraceMax, pc, 0, 0, 0, 0, false);
for (uptr i = 0; i < ptrace->size / 2; i++) {
- uptr tmp = ptrace->trace[i];
- ptrace->trace[i] = ptrace->trace[ptrace->size - i - 1];
- ptrace->trace[ptrace->size - i - 1] = tmp;
+ uptr tmp = ptrace->trace_buffer[i];
+ ptrace->trace_buffer[i] = ptrace->trace_buffer[ptrace->size - i - 1];
+ ptrace->trace_buffer[ptrace->size - i - 1] = tmp;
}
- StackTrace trace;
- trace.Init(ptrace->trace, ptrace->size);
- PrintStack(SymbolizeStack(trace));
+ PrintStack(SymbolizeStack(*ptrace));
#endif
}
} // namespace __tsan
+
+using namespace __tsan;
+
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_print_stack_trace() {
+ PrintCurrentStackSlow(StackTrace::GetCurrentPc());
+}
+} // extern "C"
diff --git a/lib/tsan/rtl/tsan_rtl_thread.cc b/lib/tsan/rtl/tsan_rtl_thread.cc
index 4e451b042947..7b7b27c024f6 100644
--- a/lib/tsan/rtl/tsan_rtl_thread.cc
+++ b/lib/tsan/rtl/tsan_rtl_thread.cc
@@ -30,19 +30,19 @@ ThreadContext::ThreadContext(int tid)
, epoch1() {
}
-#ifndef TSAN_GO
+#ifndef SANITIZER_GO
ThreadContext::~ThreadContext() {
}
#endif
void ThreadContext::OnDead() {
- sync.Reset();
+ CHECK_EQ(sync.size(), 0);
}
void ThreadContext::OnJoined(void *arg) {
ThreadState *caller_thr = static_cast<ThreadState *>(arg);
AcquireImpl(caller_thr, 0, &sync);
- sync.Reset();
+ sync.Reset(&caller_thr->clock_cache);
}
struct OnCreatedArgs {
@@ -59,21 +59,22 @@ void ThreadContext::OnCreated(void *arg) {
// Can't increment epoch w/o writing to the trace as well.
TraceAddEvent(args->thr, args->thr->fast_state, EventTypeMop, 0);
ReleaseImpl(args->thr, 0, &sync);
-#ifdef TSAN_GO
- creation_stack.ObtainCurrent(args->thr, args->pc);
-#else
creation_stack_id = CurrentStackId(args->thr, args->pc);
-#endif
if (reuse_count == 0)
StatInc(args->thr, StatThreadMaxTid);
}
void ThreadContext::OnReset() {
- sync.Reset();
+ CHECK_EQ(sync.size(), 0);
FlushUnneededShadowMemory(GetThreadTrace(tid), TraceSize() * sizeof(Event));
//!!! FlushUnneededShadowMemory(GetThreadTraceHeader(tid), sizeof(Trace));
}
+void ThreadContext::OnDetached(void *arg) {
+ ThreadState *thr1 = static_cast<ThreadState*>(arg);
+ sync.Reset(&thr1->clock_cache);
+}
+
struct OnStartedArgs {
ThreadState *thr;
uptr stk_addr;
@@ -89,9 +90,9 @@ void ThreadContext::OnStarted(void *arg) {
// from different threads.
epoch0 = RoundUp(epoch1 + 1, kTracePartSize);
epoch1 = (u64)-1;
- new(thr) ThreadState(CTX(), tid, unique_id,
- epoch0, args->stk_addr, args->stk_size, args->tls_addr, args->tls_size);
-#ifndef TSAN_GO
+ new(thr) ThreadState(ctx, tid, unique_id, epoch0, reuse_count,
+ args->stk_addr, args->stk_size, args->tls_addr, args->tls_size);
+#ifndef SANITIZER_GO
thr->shadow_stack = &ThreadTrace(thr->tid)->shadow_stack[0];
thr->shadow_stack_pos = thr->shadow_stack;
thr->shadow_stack_end = thr->shadow_stack + kShadowStackSize;
@@ -103,9 +104,13 @@ void ThreadContext::OnStarted(void *arg) {
thr->shadow_stack_pos = thr->shadow_stack;
thr->shadow_stack_end = thr->shadow_stack + kInitStackSize;
#endif
-#ifndef TSAN_GO
+#ifndef SANITIZER_GO
AllocatorThreadStart(thr);
#endif
+ if (common_flags()->detect_deadlocks) {
+ thr->dd_pt = ctx->dd->CreatePhysicalThread();
+ thr->dd_lt = ctx->dd->CreateLogicalThread(unique_id);
+ }
thr->fast_synch_epoch = epoch0;
AcquireImpl(thr, 0, &sync);
thr->fast_state.SetHistorySize(flags()->history_size);
@@ -113,12 +118,11 @@ void ThreadContext::OnStarted(void *arg) {
Trace *thr_trace = ThreadTrace(thr->tid);
thr_trace->headers[trace].epoch0 = epoch0;
StatInc(thr, StatSyncAcquire);
- sync.Reset();
+ sync.Reset(&thr->clock_cache);
DPrintf("#%d: ThreadStart epoch=%zu stk_addr=%zx stk_size=%zx "
"tls_addr=%zx tls_size=%zx\n",
tid, (uptr)epoch0, args->stk_addr, args->stk_size,
args->tls_addr, args->tls_size);
- thr->is_alive = true;
}
void ThreadContext::OnFinished() {
@@ -130,15 +134,21 @@ void ThreadContext::OnFinished() {
}
epoch1 = thr->fast_state.epoch();
-#ifndef TSAN_GO
+ if (common_flags()->detect_deadlocks) {
+ ctx->dd->DestroyPhysicalThread(thr->dd_pt);
+ ctx->dd->DestroyLogicalThread(thr->dd_lt);
+ }
+ ctx->clock_alloc.FlushCache(&thr->clock_cache);
+ ctx->metamap.OnThreadIdle(thr);
+#ifndef SANITIZER_GO
AllocatorThreadFinish(thr);
#endif
thr->~ThreadState();
- StatAggregate(CTX()->stat, thr->stat);
+ StatAggregate(ctx->stat, thr->stat);
thr = 0;
}
-#ifndef TSAN_GO
+#ifndef SANITIZER_GO
struct ThreadLeak {
ThreadContext *tctx;
int count;
@@ -160,48 +170,62 @@ static void MaybeReportThreadLeak(ThreadContextBase *tctx_base, void *arg) {
}
#endif
-static void ThreadCheckIgnore(ThreadState *thr) {
- if (thr->ignore_reads_and_writes) {
- Printf("ThreadSanitizer: thread T%d finished with ignores enabled.\n",
- thr->tid);
+#ifndef SANITIZER_GO
+static void ReportIgnoresEnabled(ThreadContext *tctx, IgnoreSet *set) {
+ if (tctx->tid == 0) {
+ Printf("ThreadSanitizer: main thread finished with ignores enabled\n");
+ } else {
+ Printf("ThreadSanitizer: thread T%d %s finished with ignores enabled,"
+ " created at:\n", tctx->tid, tctx->name);
+ PrintStack(SymbolizeStackId(tctx->creation_stack_id));
}
- if (thr->ignore_sync) {
- Printf("ThreadSanitizer: thread T%d finished with sync ignores enabled.\n",
- thr->tid);
+ Printf(" One of the following ignores was not ended"
+ " (in order of probability)\n");
+ for (uptr i = 0; i < set->Size(); i++) {
+ Printf(" Ignore was enabled at:\n");
+ PrintStack(SymbolizeStackId(set->At(i)));
}
+ Die();
}
+static void ThreadCheckIgnore(ThreadState *thr) {
+ if (ctx->after_multithreaded_fork)
+ return;
+ if (thr->ignore_reads_and_writes)
+ ReportIgnoresEnabled(thr->tctx, &thr->mop_ignore_set);
+ if (thr->ignore_sync)
+ ReportIgnoresEnabled(thr->tctx, &thr->sync_ignore_set);
+}
+#else
+static void ThreadCheckIgnore(ThreadState *thr) {}
+#endif
+
void ThreadFinalize(ThreadState *thr) {
- CHECK_GT(thr->in_rtl, 0);
ThreadCheckIgnore(thr);
-#ifndef TSAN_GO
+#ifndef SANITIZER_GO
if (!flags()->report_thread_leaks)
return;
- ThreadRegistryLock l(CTX()->thread_registry);
+ ThreadRegistryLock l(ctx->thread_registry);
Vector<ThreadLeak> leaks(MBlockScopedBuf);
- CTX()->thread_registry->RunCallbackForEachThreadLocked(
+ ctx->thread_registry->RunCallbackForEachThreadLocked(
MaybeReportThreadLeak, &leaks);
for (uptr i = 0; i < leaks.Size(); i++) {
ScopedReport rep(ReportTypeThreadLeak);
- rep.AddThread(leaks[i].tctx);
+ rep.AddThread(leaks[i].tctx, true);
rep.SetCount(leaks[i].count);
- OutputReport(CTX(), rep);
+ OutputReport(thr, rep);
}
#endif
}
int ThreadCount(ThreadState *thr) {
- CHECK_GT(thr->in_rtl, 0);
- Context *ctx = CTX();
uptr result;
ctx->thread_registry->GetNumberOfThreads(0, 0, &result);
return (int)result;
}
int ThreadCreate(ThreadState *thr, uptr pc, uptr uid, bool detached) {
- CHECK_GT(thr->in_rtl, 0);
StatInc(thr, StatThreadCreate);
- Context *ctx = CTX();
OnCreatedArgs args = { thr, pc };
int tid = ctx->thread_registry->CreateThread(uid, detached, thr->tid, &args);
DPrintf("#%d: ThreadCreate tid=%d uid=%zu\n", thr->tid, tid, uid);
@@ -210,7 +234,6 @@ int ThreadCreate(ThreadState *thr, uptr pc, uptr uid, bool detached) {
}
void ThreadStart(ThreadState *thr, int tid, uptr os_id) {
- CHECK_GT(thr->in_rtl, 0);
uptr stk_addr = 0;
uptr stk_size = 0;
uptr tls_addr = 0;
@@ -236,20 +259,31 @@ void ThreadStart(ThreadState *thr, int tid, uptr os_id) {
}
}
+ ThreadRegistry *tr = ctx->thread_registry;
OnStartedArgs args = { thr, stk_addr, stk_size, tls_addr, tls_size };
- CTX()->thread_registry->StartThread(tid, os_id, &args);
+ tr->StartThread(tid, os_id, &args);
+
+ tr->Lock();
+ thr->tctx = (ThreadContext*)tr->GetThreadLocked(tid);
+ tr->Unlock();
+
+#ifndef SANITIZER_GO
+ if (ctx->after_multithreaded_fork) {
+ thr->ignore_interceptors++;
+ ThreadIgnoreBegin(thr, 0);
+ ThreadIgnoreSyncBegin(thr, 0);
+ }
+#endif
}
void ThreadFinish(ThreadState *thr) {
- CHECK_GT(thr->in_rtl, 0);
ThreadCheckIgnore(thr);
StatInc(thr, StatThreadFinish);
if (thr->stk_addr && thr->stk_size)
DontNeedShadowFor(thr->stk_addr, thr->stk_size);
if (thr->tls_addr && thr->tls_size)
DontNeedShadowFor(thr->tls_addr, thr->tls_size);
- thr->is_alive = false;
- Context *ctx = CTX();
+ thr->is_dead = true;
ctx->thread_registry->FinishThread(thr->tid);
}
@@ -263,33 +297,26 @@ static bool FindThreadByUid(ThreadContextBase *tctx, void *arg) {
}
int ThreadTid(ThreadState *thr, uptr pc, uptr uid) {
- CHECK_GT(thr->in_rtl, 0);
- Context *ctx = CTX();
int res = ctx->thread_registry->FindThread(FindThreadByUid, (void*)uid);
DPrintf("#%d: ThreadTid uid=%zu tid=%d\n", thr->tid, uid, res);
return res;
}
void ThreadJoin(ThreadState *thr, uptr pc, int tid) {
- CHECK_GT(thr->in_rtl, 0);
CHECK_GT(tid, 0);
CHECK_LT(tid, kMaxTid);
DPrintf("#%d: ThreadJoin tid=%d\n", thr->tid, tid);
- Context *ctx = CTX();
ctx->thread_registry->JoinThread(tid, thr);
}
void ThreadDetach(ThreadState *thr, uptr pc, int tid) {
- CHECK_GT(thr->in_rtl, 0);
CHECK_GT(tid, 0);
CHECK_LT(tid, kMaxTid);
- Context *ctx = CTX();
- ctx->thread_registry->DetachThread(tid);
+ ctx->thread_registry->DetachThread(tid, thr);
}
void ThreadSetName(ThreadState *thr, const char *name) {
- CHECK_GT(thr->in_rtl, 0);
- CTX()->thread_registry->SetThreadName(thr->tid, name);
+ ctx->thread_registry->SetThreadName(thr->tid, name);
}
void MemoryAccessRange(ThreadState *thr, uptr pc, uptr addr,
diff --git a/lib/tsan/rtl/tsan_stack_trace.cc b/lib/tsan/rtl/tsan_stack_trace.cc
new file mode 100644
index 000000000000..ceca3f8e8738
--- /dev/null
+++ b/lib/tsan/rtl/tsan_stack_trace.cc
@@ -0,0 +1,46 @@
+//===-- tsan_stack_trace.cc -----------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+#include "tsan_stack_trace.h"
+#include "tsan_rtl.h"
+#include "tsan_mman.h"
+
+namespace __tsan {
+
+VarSizeStackTrace::VarSizeStackTrace()
+ : StackTrace(nullptr, 0), trace_buffer(nullptr) {}
+
+VarSizeStackTrace::~VarSizeStackTrace() {
+ ResizeBuffer(0);
+}
+
+void VarSizeStackTrace::ResizeBuffer(uptr new_size) {
+ if (trace_buffer) {
+ internal_free(trace_buffer);
+ }
+ trace_buffer =
+ (new_size > 0)
+ ? (uptr *)internal_alloc(MBlockStackTrace,
+ new_size * sizeof(trace_buffer[0]))
+ : nullptr;
+ trace = trace_buffer;
+ size = new_size;
+}
+
+void VarSizeStackTrace::Init(const uptr *pcs, uptr cnt, uptr extra_top_pc) {
+ ResizeBuffer(cnt + !!extra_top_pc);
+ internal_memcpy(trace_buffer, pcs, cnt * sizeof(trace_buffer[0]));
+ if (extra_top_pc)
+ trace_buffer[cnt] = extra_top_pc;
+}
+
+} // namespace __tsan
diff --git a/lib/tsan/rtl/tsan_stack_trace.h b/lib/tsan/rtl/tsan_stack_trace.h
new file mode 100644
index 000000000000..5bf89bb7584f
--- /dev/null
+++ b/lib/tsan/rtl/tsan_stack_trace.h
@@ -0,0 +1,39 @@
+//===-- tsan_stack_trace.h --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+#ifndef TSAN_STACK_TRACE_H
+#define TSAN_STACK_TRACE_H
+
+#include "sanitizer_common/sanitizer_stacktrace.h"
+#include "tsan_defs.h"
+
+namespace __tsan {
+
+// StackTrace which calls malloc/free to allocate the buffer for
+// addresses in stack traces.
+struct VarSizeStackTrace : public StackTrace {
+ uptr *trace_buffer; // Owned.
+
+ VarSizeStackTrace();
+ ~VarSizeStackTrace();
+ void Init(const uptr *pcs, uptr cnt, uptr extra_top_pc = 0);
+
+ private:
+ void ResizeBuffer(uptr new_size);
+
+ VarSizeStackTrace(const VarSizeStackTrace &);
+ void operator=(const VarSizeStackTrace &);
+};
+
+} // namespace __tsan
+
+#endif // TSAN_STACK_TRACE_H
diff --git a/lib/tsan/rtl/tsan_stat.cc b/lib/tsan/rtl/tsan_stat.cc
index f9dbf121cef4..350a2ba48253 100644
--- a/lib/tsan/rtl/tsan_stat.cc
+++ b/lib/tsan/rtl/tsan_stat.cc
@@ -37,6 +37,7 @@ void StatOutput(u64 *stat) {
name[StatMop4] = " size 4 ";
name[StatMop8] = " size 8 ";
name[StatMopSame] = " Including same ";
+ name[StatMopIgnored] = " Including ignored ";
name[StatMopRange] = " Including range ";
name[StatMopRodata] = " Including .rodata ";
name[StatMopRangeRodata] = " Including .rodata range ";
@@ -74,6 +75,28 @@ void StatOutput(u64 *stat) {
name[StatSyncAcquire] = " acquired ";
name[StatSyncRelease] = " released ";
+ name[StatClockAcquire] = "Clock acquire ";
+ name[StatClockAcquireEmpty] = " empty clock ";
+ name[StatClockAcquireFastRelease] = " fast from release-store ";
+ name[StatClockAcquireLarge] = " contains my tid ";
+ name[StatClockAcquireRepeat] = " repeated (fast) ";
+ name[StatClockAcquireFull] = " full (slow) ";
+ name[StatClockAcquiredSomething] = " acquired something ";
+ name[StatClockRelease] = "Clock release ";
+ name[StatClockReleaseResize] = " resize ";
+ name[StatClockReleaseFast1] = " fast1 ";
+ name[StatClockReleaseFast2] = " fast2 ";
+ name[StatClockReleaseSlow] = " dirty overflow (slow) ";
+ name[StatClockReleaseFull] = " full (slow) ";
+ name[StatClockReleaseAcquired] = " was acquired ";
+ name[StatClockReleaseClearTail] = " clear tail ";
+ name[StatClockStore] = "Clock release store ";
+ name[StatClockStoreResize] = " resize ";
+ name[StatClockStoreFast] = " fast ";
+ name[StatClockStoreFull] = " slow ";
+ name[StatClockStoreTail] = " clear tail ";
+ name[StatClockAcquireRelease] = "Clock acquire-release ";
+
name[StatAtomic] = "Atomic operations ";
name[StatAtomicLoad] = " Including load ";
name[StatAtomicStore] = " store ";
@@ -98,334 +121,6 @@ void StatOutput(u64 *stat) {
name[StatAtomic8] = " size 8 ";
name[StatAtomic16] = " size 16 ";
- name[StatInterceptor] = "Interceptors ";
- name[StatInt_longjmp] = " longjmp ";
- name[StatInt_siglongjmp] = " siglongjmp ";
- name[StatInt_malloc] = " malloc ";
- name[StatInt___libc_memalign] = " __libc_memalign ";
- name[StatInt_calloc] = " calloc ";
- name[StatInt_realloc] = " realloc ";
- name[StatInt_free] = " free ";
- name[StatInt_cfree] = " cfree ";
- name[StatInt_malloc_usable_size] = " malloc_usable_size ";
- name[StatInt_mmap] = " mmap ";
- name[StatInt_mmap64] = " mmap64 ";
- name[StatInt_munmap] = " munmap ";
- name[StatInt_memalign] = " memalign ";
- name[StatInt_valloc] = " valloc ";
- name[StatInt_pvalloc] = " pvalloc ";
- name[StatInt_posix_memalign] = " posix_memalign ";
- name[StatInt__Znwm] = " _Znwm ";
- name[StatInt__ZnwmRKSt9nothrow_t] = " _ZnwmRKSt9nothrow_t ";
- name[StatInt__Znam] = " _Znam ";
- name[StatInt__ZnamRKSt9nothrow_t] = " _ZnamRKSt9nothrow_t ";
- name[StatInt__ZdlPv] = " _ZdlPv ";
- name[StatInt__ZdlPvRKSt9nothrow_t] = " _ZdlPvRKSt9nothrow_t ";
- name[StatInt__ZdaPv] = " _ZdaPv ";
- name[StatInt__ZdaPvRKSt9nothrow_t] = " _ZdaPvRKSt9nothrow_t ";
- name[StatInt_strlen] = " strlen ";
- name[StatInt_memset] = " memset ";
- name[StatInt_memcpy] = " memcpy ";
- name[StatInt_strcmp] = " strcmp ";
- name[StatInt_memchr] = " memchr ";
- name[StatInt_memrchr] = " memrchr ";
- name[StatInt_memmove] = " memmove ";
- name[StatInt_memcmp] = " memcmp ";
- name[StatInt_strchr] = " strchr ";
- name[StatInt_strchrnul] = " strchrnul ";
- name[StatInt_strrchr] = " strrchr ";
- name[StatInt_strncmp] = " strncmp ";
- name[StatInt_strcpy] = " strcpy ";
- name[StatInt_strncpy] = " strncpy ";
- name[StatInt_strstr] = " strstr ";
- name[StatInt_strdup] = " strdup ";
- name[StatInt_strcasecmp] = " strcasecmp ";
- name[StatInt_strncasecmp] = " strncasecmp ";
- name[StatInt_atexit] = " atexit ";
- name[StatInt__exit] = " _exit ";
- name[StatInt___cxa_guard_acquire] = " __cxa_guard_acquire ";
- name[StatInt___cxa_guard_release] = " __cxa_guard_release ";
- name[StatInt___cxa_guard_abort] = " __cxa_guard_abort ";
- name[StatInt_pthread_create] = " pthread_create ";
- name[StatInt_pthread_join] = " pthread_join ";
- name[StatInt_pthread_detach] = " pthread_detach ";
- name[StatInt_pthread_mutex_init] = " pthread_mutex_init ";
- name[StatInt_pthread_mutex_destroy] = " pthread_mutex_destroy ";
- name[StatInt_pthread_mutex_lock] = " pthread_mutex_lock ";
- name[StatInt_pthread_mutex_trylock] = " pthread_mutex_trylock ";
- name[StatInt_pthread_mutex_timedlock] = " pthread_mutex_timedlock ";
- name[StatInt_pthread_mutex_unlock] = " pthread_mutex_unlock ";
- name[StatInt_pthread_spin_init] = " pthread_spin_init ";
- name[StatInt_pthread_spin_destroy] = " pthread_spin_destroy ";
- name[StatInt_pthread_spin_lock] = " pthread_spin_lock ";
- name[StatInt_pthread_spin_trylock] = " pthread_spin_trylock ";
- name[StatInt_pthread_spin_unlock] = " pthread_spin_unlock ";
- name[StatInt_pthread_rwlock_init] = " pthread_rwlock_init ";
- name[StatInt_pthread_rwlock_destroy] = " pthread_rwlock_destroy ";
- name[StatInt_pthread_rwlock_rdlock] = " pthread_rwlock_rdlock ";
- name[StatInt_pthread_rwlock_tryrdlock] = " pthread_rwlock_tryrdlock ";
- name[StatInt_pthread_rwlock_timedrdlock]
- = " pthread_rwlock_timedrdlock ";
- name[StatInt_pthread_rwlock_wrlock] = " pthread_rwlock_wrlock ";
- name[StatInt_pthread_rwlock_trywrlock] = " pthread_rwlock_trywrlock ";
- name[StatInt_pthread_rwlock_timedwrlock]
- = " pthread_rwlock_timedwrlock ";
- name[StatInt_pthread_rwlock_unlock] = " pthread_rwlock_unlock ";
- name[StatInt_pthread_cond_init] = " pthread_cond_init ";
- name[StatInt_pthread_cond_destroy] = " pthread_cond_destroy ";
- name[StatInt_pthread_cond_signal] = " pthread_cond_signal ";
- name[StatInt_pthread_cond_broadcast] = " pthread_cond_broadcast ";
- name[StatInt_pthread_cond_wait] = " pthread_cond_wait ";
- name[StatInt_pthread_cond_timedwait] = " pthread_cond_timedwait ";
- name[StatInt_pthread_barrier_init] = " pthread_barrier_init ";
- name[StatInt_pthread_barrier_destroy] = " pthread_barrier_destroy ";
- name[StatInt_pthread_barrier_wait] = " pthread_barrier_wait ";
- name[StatInt_pthread_once] = " pthread_once ";
- name[StatInt_pthread_getschedparam] = " pthread_getschedparam ";
- name[StatInt_pthread_setname_np] = " pthread_setname_np ";
- name[StatInt_sem_init] = " sem_init ";
- name[StatInt_sem_destroy] = " sem_destroy ";
- name[StatInt_sem_wait] = " sem_wait ";
- name[StatInt_sem_trywait] = " sem_trywait ";
- name[StatInt_sem_timedwait] = " sem_timedwait ";
- name[StatInt_sem_post] = " sem_post ";
- name[StatInt_sem_getvalue] = " sem_getvalue ";
- name[StatInt_stat] = " stat ";
- name[StatInt___xstat] = " __xstat ";
- name[StatInt_stat64] = " stat64 ";
- name[StatInt___xstat64] = " __xstat64 ";
- name[StatInt_lstat] = " lstat ";
- name[StatInt___lxstat] = " __lxstat ";
- name[StatInt_lstat64] = " lstat64 ";
- name[StatInt___lxstat64] = " __lxstat64 ";
- name[StatInt_fstat] = " fstat ";
- name[StatInt___fxstat] = " __fxstat ";
- name[StatInt_fstat64] = " fstat64 ";
- name[StatInt___fxstat64] = " __fxstat64 ";
- name[StatInt_open] = " open ";
- name[StatInt_open64] = " open64 ";
- name[StatInt_creat] = " creat ";
- name[StatInt_creat64] = " creat64 ";
- name[StatInt_dup] = " dup ";
- name[StatInt_dup2] = " dup2 ";
- name[StatInt_dup3] = " dup3 ";
- name[StatInt_eventfd] = " eventfd ";
- name[StatInt_signalfd] = " signalfd ";
- name[StatInt_inotify_init] = " inotify_init ";
- name[StatInt_inotify_init1] = " inotify_init1 ";
- name[StatInt_socket] = " socket ";
- name[StatInt_socketpair] = " socketpair ";
- name[StatInt_connect] = " connect ";
- name[StatInt_bind] = " bind ";
- name[StatInt_listen] = " listen ";
- name[StatInt_accept] = " accept ";
- name[StatInt_accept4] = " accept4 ";
- name[StatInt_epoll_create] = " epoll_create ";
- name[StatInt_epoll_create1] = " epoll_create1 ";
- name[StatInt_close] = " close ";
- name[StatInt___close] = " __close ";
- name[StatInt___res_iclose] = " __res_iclose ";
- name[StatInt_pipe] = " pipe ";
- name[StatInt_pipe2] = " pipe2 ";
- name[StatInt_read] = " read ";
- name[StatInt_prctl] = " prctl ";
- name[StatInt_pread] = " pread ";
- name[StatInt_pread64] = " pread64 ";
- name[StatInt_readv] = " readv ";
- name[StatInt_preadv] = " preadv ";
- name[StatInt_preadv64] = " preadv64 ";
- name[StatInt_write] = " write ";
- name[StatInt_pwrite] = " pwrite ";
- name[StatInt_pwrite64] = " pwrite64 ";
- name[StatInt_writev] = " writev ";
- name[StatInt_pwritev] = " pwritev ";
- name[StatInt_pwritev64] = " pwritev64 ";
- name[StatInt_send] = " send ";
- name[StatInt_sendmsg] = " sendmsg ";
- name[StatInt_recv] = " recv ";
- name[StatInt_recvmsg] = " recvmsg ";
- name[StatInt_unlink] = " unlink ";
- name[StatInt_fopen] = " fopen ";
- name[StatInt_freopen] = " freopen ";
- name[StatInt_fclose] = " fclose ";
- name[StatInt_fread] = " fread ";
- name[StatInt_fwrite] = " fwrite ";
- name[StatInt_fflush] = " fflush ";
- name[StatInt_abort] = " abort ";
- name[StatInt_puts] = " puts ";
- name[StatInt_rmdir] = " rmdir ";
- name[StatInt_opendir] = " opendir ";
- name[StatInt_epoll_ctl] = " epoll_ctl ";
- name[StatInt_epoll_wait] = " epoll_wait ";
- name[StatInt_poll] = " poll ";
- name[StatInt_ppoll] = " ppoll ";
- name[StatInt_sigaction] = " sigaction ";
- name[StatInt_signal] = " signal ";
- name[StatInt_sigsuspend] = " sigsuspend ";
- name[StatInt_raise] = " raise ";
- name[StatInt_kill] = " kill ";
- name[StatInt_pthread_kill] = " pthread_kill ";
- name[StatInt_sleep] = " sleep ";
- name[StatInt_usleep] = " usleep ";
- name[StatInt_nanosleep] = " nanosleep ";
- name[StatInt_gettimeofday] = " gettimeofday ";
- name[StatInt_fork] = " fork ";
- name[StatInt_vscanf] = " vscanf ";
- name[StatInt_vsscanf] = " vsscanf ";
- name[StatInt_vfscanf] = " vfscanf ";
- name[StatInt_scanf] = " scanf ";
- name[StatInt_sscanf] = " sscanf ";
- name[StatInt_fscanf] = " fscanf ";
- name[StatInt___isoc99_vscanf] = " vscanf ";
- name[StatInt___isoc99_vsscanf] = " vsscanf ";
- name[StatInt___isoc99_vfscanf] = " vfscanf ";
- name[StatInt___isoc99_scanf] = " scanf ";
- name[StatInt___isoc99_sscanf] = " sscanf ";
- name[StatInt___isoc99_fscanf] = " fscanf ";
- name[StatInt_on_exit] = " on_exit ";
- name[StatInt___cxa_atexit] = " __cxa_atexit ";
- name[StatInt_localtime] = " localtime ";
- name[StatInt_localtime_r] = " localtime_r ";
- name[StatInt_gmtime] = " gmtime ";
- name[StatInt_gmtime_r] = " gmtime_r ";
- name[StatInt_ctime] = " ctime ";
- name[StatInt_ctime_r] = " ctime_r ";
- name[StatInt_asctime] = " asctime ";
- name[StatInt_asctime_r] = " asctime_r ";
- name[StatInt_strptime] = " strptime ";
- name[StatInt_frexp] = " frexp ";
- name[StatInt_frexpf] = " frexpf ";
- name[StatInt_frexpl] = " frexpl ";
- name[StatInt_getpwnam] = " getpwnam ";
- name[StatInt_getpwuid] = " getpwuid ";
- name[StatInt_getgrnam] = " getgrnam ";
- name[StatInt_getgrgid] = " getgrgid ";
- name[StatInt_getpwnam_r] = " getpwnam_r ";
- name[StatInt_getpwuid_r] = " getpwuid_r ";
- name[StatInt_getgrnam_r] = " getgrnam_r ";
- name[StatInt_getgrgid_r] = " getgrgid_r ";
- name[StatInt_clock_getres] = " clock_getres ";
- name[StatInt_clock_gettime] = " clock_gettime ";
- name[StatInt_clock_settime] = " clock_settime ";
- name[StatInt_getitimer] = " getitimer ";
- name[StatInt_setitimer] = " setitimer ";
- name[StatInt_time] = " time ";
- name[StatInt_glob] = " glob ";
- name[StatInt_glob64] = " glob64 ";
- name[StatInt_wait] = " wait ";
- name[StatInt_waitid] = " waitid ";
- name[StatInt_waitpid] = " waitpid ";
- name[StatInt_wait3] = " wait3 ";
- name[StatInt_wait4] = " wait4 ";
- name[StatInt_inet_ntop] = " inet_ntop ";
- name[StatInt_inet_pton] = " inet_pton ";
- name[StatInt_inet_aton] = " inet_aton ";
- name[StatInt_getaddrinfo] = " getaddrinfo ";
- name[StatInt_getnameinfo] = " getnameinfo ";
- name[StatInt_getsockname] = " getsockname ";
- name[StatInt_gethostent] = " gethostent ";
- name[StatInt_gethostbyname] = " gethostbyname ";
- name[StatInt_gethostbyname2] = " gethostbyname2 ";
- name[StatInt_gethostbyaddr] = " gethostbyaddr ";
- name[StatInt_gethostent_r] = " gethostent_r ";
- name[StatInt_gethostbyname_r] = " gethostbyname_r ";
- name[StatInt_gethostbyname2_r] = " gethostbyname2_r ";
- name[StatInt_gethostbyaddr_r] = " gethostbyaddr_r ";
- name[StatInt_getsockopt] = " getsockopt ";
- name[StatInt_modf] = " modf ";
- name[StatInt_modff] = " modff ";
- name[StatInt_modfl] = " modfl ";
- name[StatInt_getpeername] = " getpeername ";
- name[StatInt_ioctl] = " ioctl ";
- name[StatInt_sysinfo] = " sysinfo ";
- name[StatInt_readdir] = " readdir ";
- name[StatInt_readdir64] = " readdir64 ";
- name[StatInt_readdir_r] = " readdir_r ";
- name[StatInt_readdir64_r] = " readdir64_r ";
- name[StatInt_ptrace] = " ptrace ";
- name[StatInt_setlocale] = " setlocale ";
- name[StatInt_getcwd] = " getcwd ";
- name[StatInt_get_current_dir_name] = " get_current_dir_name ";
- name[StatInt_strtoimax] = " strtoimax ";
- name[StatInt_strtoumax] = " strtoumax ";
- name[StatInt_mbstowcs] = " mbstowcs ";
- name[StatInt_mbsrtowcs] = " mbsrtowcs ";
- name[StatInt_mbsnrtowcs] = " mbsnrtowcs ";
- name[StatInt_wcstombs] = " wcstombs ";
- name[StatInt_wcsrtombs] = " wcsrtombs ";
- name[StatInt_wcsnrtombs] = " wcsnrtombs ";
- name[StatInt_tcgetattr] = " tcgetattr ";
- name[StatInt_realpath] = " realpath ";
- name[StatInt_canonicalize_file_name] = " canonicalize_file_name ";
- name[StatInt_confstr] = " confstr ";
- name[StatInt_sched_getaffinity] = " sched_getaffinity ";
- name[StatInt_strerror] = " strerror ";
- name[StatInt_strerror_r] = " strerror_r ";
- name[StatInt_scandir] = " scandir ";
- name[StatInt_scandir64] = " scandir64 ";
- name[StatInt_getgroups] = " getgroups ";
- name[StatInt_wordexp] = " wordexp ";
- name[StatInt_sigwait] = " sigwait ";
- name[StatInt_sigwaitinfo] = " sigwaitinfo ";
- name[StatInt_sigtimedwait] = " sigtimedwait ";
- name[StatInt_sigemptyset] = " sigemptyset ";
- name[StatInt_sigfillset] = " sigfillset ";
- name[StatInt_sigpending] = " sigpending ";
- name[StatInt_sigprocmask] = " sigprocmask ";
- name[StatInt_backtrace] = " backtrace ";
- name[StatInt_backtrace_symbols] = " backtrace_symbols ";
- name[StatInt_dlopen] = " dlopen ";
- name[StatInt_dlclose] = " dlclose ";
- name[StatInt_getmntent] = " getmntent ";
- name[StatInt_getmntent_r] = " getmntent_r ";
- name[StatInt_statfs] = " statfs ";
- name[StatInt_statfs64] = " statfs64 ";
- name[StatInt_fstatfs] = " fstatfs ";
- name[StatInt_fstatfs64] = " fstatfs64 ";
- name[StatInt_statvfs] = " statvfs ";
- name[StatInt_statvfs64] = " statvfs64 ";
- name[StatInt_fstatvfs] = " fstatvfs ";
- name[StatInt_fstatvfs64] = " fstatvfs64 ";
- name[StatInt_initgroups] = " initgroups ";
- name[StatInt_ether_ntoa] = " ether_ntoa ";
- name[StatInt_ether_aton] = " ether_aton ";
- name[StatInt_ether_ntoa_r] = " ether_ntoa_r ";
- name[StatInt_ether_aton_r] = " ether_aton_r ";
- name[StatInt_ether_ntohost] = " ether_ntohost ";
- name[StatInt_ether_hostton] = " ether_hostton ";
- name[StatInt_ether_line] = " ether_line ";
- name[StatInt_shmctl] = " shmctl ";
- name[StatInt_random_r] = " random_r ";
- name[StatInt_tmpnam] = " tmpnam ";
- name[StatInt_tmpnam_r] = " tmpnam_r ";
- name[StatInt_tempnam] = " tempnam ";
- name[StatInt_sincos] = " sincos ";
- name[StatInt_sincosf] = " sincosf ";
- name[StatInt_sincosl] = " sincosl ";
- name[StatInt_remquo] = " remquo ";
- name[StatInt_remquof] = " remquof ";
- name[StatInt_remquol] = " remquol ";
- name[StatInt_lgamma] = " lgamma ";
- name[StatInt_lgammaf] = " lgammaf ";
- name[StatInt_lgammal] = " lgammal ";
- name[StatInt_lgamma_r] = " lgamma_r ";
- name[StatInt_lgammaf_r] = " lgammaf_r ";
- name[StatInt_lgammal_r] = " lgammal_r ";
- name[StatInt_drand48_r] = " drand48_r ";
- name[StatInt_lrand48_r] = " lrand48_r ";
- name[StatInt_getline] = " getline ";
- name[StatInt_getdelim] = " getdelim ";
-
- name[StatInt_pthread_attr_getdetachstate] = " pthread_addr_getdetachstate "; // NOLINT
- name[StatInt_pthread_attr_getguardsize] = " pthread_addr_getguardsize "; // NOLINT
- name[StatInt_pthread_attr_getschedparam] = " pthread_addr_getschedparam "; // NOLINT
- name[StatInt_pthread_attr_getschedpolicy] = " pthread_addr_getschedpolicy "; // NOLINT
- name[StatInt_pthread_attr_getinheritsched] = " pthread_addr_getinheritsched "; // NOLINT
- name[StatInt_pthread_attr_getscope] = " pthread_addr_getscope "; // NOLINT
- name[StatInt_pthread_attr_getstacksize] = " pthread_addr_getstacksize "; // NOLINT
- name[StatInt_pthread_attr_getstack] = " pthread_addr_getstack "; // NOLINT
- name[StatInt_pthread_attr_getaffinity_np] = " pthread_addr_getaffinity_np "; // NOLINT
-
name[StatAnnotation] = "Dynamic annotations ";
name[StatAnnotateHappensBefore] = " HappensBefore ";
name[StatAnnotateHappensAfter] = " HappensAfter ";
@@ -473,11 +168,12 @@ void StatOutput(u64 *stat) {
name[StatMtxAnnotations] = " Annotations ";
name[StatMtxMBlock] = " MBlock ";
name[StatMtxJavaMBlock] = " JavaMBlock ";
+ name[StatMtxDeadlockDetector] = " DeadlockDetector ";
name[StatMtxFD] = " FD ";
Printf("Statistics:\n");
for (int i = 0; i < StatCnt; i++)
- Printf("%s: %zu\n", name[i], (uptr)stat[i]);
+ Printf("%s: %16zu\n", name[i], (uptr)stat[i]);
}
} // namespace __tsan
diff --git a/lib/tsan/rtl/tsan_stat.h b/lib/tsan/rtl/tsan_stat.h
index a44edfcd65c6..0bd949ed1563 100644
--- a/lib/tsan/rtl/tsan_stat.h
+++ b/lib/tsan/rtl/tsan_stat.h
@@ -26,6 +26,7 @@ enum StatType {
StatMop4,
StatMop8,
StatMopSame,
+ StatMopIgnored,
StatMopRange,
StatMopRodata,
StatMopRangeRodata,
@@ -69,6 +70,32 @@ enum StatType {
StatSyncAcquire,
StatSyncRelease,
+ // Clocks - acquire.
+ StatClockAcquire,
+ StatClockAcquireEmpty,
+ StatClockAcquireFastRelease,
+ StatClockAcquireLarge,
+ StatClockAcquireRepeat,
+ StatClockAcquireFull,
+ StatClockAcquiredSomething,
+ // Clocks - release.
+ StatClockRelease,
+ StatClockReleaseResize,
+ StatClockReleaseFast1,
+ StatClockReleaseFast2,
+ StatClockReleaseSlow,
+ StatClockReleaseFull,
+ StatClockReleaseAcquired,
+ StatClockReleaseClearTail,
+ // Clocks - release store.
+ StatClockStore,
+ StatClockStoreResize,
+ StatClockStoreFast,
+ StatClockStoreFull,
+ StatClockStoreTail,
+ // Clocks - acquire-release.
+ StatClockAcquireRelease,
+
// Atomics.
StatAtomic,
StatAtomicLoad,
@@ -94,333 +121,6 @@ enum StatType {
StatAtomic8,
StatAtomic16,
- // Interceptors.
- StatInterceptor,
- StatInt_longjmp,
- StatInt_siglongjmp,
- StatInt_malloc,
- StatInt___libc_memalign,
- StatInt_calloc,
- StatInt_realloc,
- StatInt_free,
- StatInt_cfree,
- StatInt_malloc_usable_size,
- StatInt_mmap,
- StatInt_mmap64,
- StatInt_munmap,
- StatInt_memalign,
- StatInt_valloc,
- StatInt_pvalloc,
- StatInt_posix_memalign,
- StatInt__Znwm,
- StatInt__ZnwmRKSt9nothrow_t,
- StatInt__Znam,
- StatInt__ZnamRKSt9nothrow_t,
- StatInt__ZdlPv,
- StatInt__ZdlPvRKSt9nothrow_t,
- StatInt__ZdaPv,
- StatInt__ZdaPvRKSt9nothrow_t,
- StatInt_strlen,
- StatInt_memset,
- StatInt_memcpy,
- StatInt_strcmp,
- StatInt_memchr,
- StatInt_memrchr,
- StatInt_memmove,
- StatInt_memcmp,
- StatInt_strchr,
- StatInt_strchrnul,
- StatInt_strrchr,
- StatInt_strncmp,
- StatInt_strcpy,
- StatInt_strncpy,
- StatInt_strcasecmp,
- StatInt_strncasecmp,
- StatInt_strstr,
- StatInt_strdup,
- StatInt_atexit,
- StatInt__exit,
- StatInt___cxa_guard_acquire,
- StatInt___cxa_guard_release,
- StatInt___cxa_guard_abort,
- StatInt_pthread_create,
- StatInt_pthread_join,
- StatInt_pthread_detach,
- StatInt_pthread_mutex_init,
- StatInt_pthread_mutex_destroy,
- StatInt_pthread_mutex_lock,
- StatInt_pthread_mutex_trylock,
- StatInt_pthread_mutex_timedlock,
- StatInt_pthread_mutex_unlock,
- StatInt_pthread_spin_init,
- StatInt_pthread_spin_destroy,
- StatInt_pthread_spin_lock,
- StatInt_pthread_spin_trylock,
- StatInt_pthread_spin_unlock,
- StatInt_pthread_rwlock_init,
- StatInt_pthread_rwlock_destroy,
- StatInt_pthread_rwlock_rdlock,
- StatInt_pthread_rwlock_tryrdlock,
- StatInt_pthread_rwlock_timedrdlock,
- StatInt_pthread_rwlock_wrlock,
- StatInt_pthread_rwlock_trywrlock,
- StatInt_pthread_rwlock_timedwrlock,
- StatInt_pthread_rwlock_unlock,
- StatInt_pthread_cond_init,
- StatInt_pthread_cond_destroy,
- StatInt_pthread_cond_signal,
- StatInt_pthread_cond_broadcast,
- StatInt_pthread_cond_wait,
- StatInt_pthread_cond_timedwait,
- StatInt_pthread_barrier_init,
- StatInt_pthread_barrier_destroy,
- StatInt_pthread_barrier_wait,
- StatInt_pthread_once,
- StatInt_pthread_getschedparam,
- StatInt_pthread_setname_np,
- StatInt_sem_init,
- StatInt_sem_destroy,
- StatInt_sem_wait,
- StatInt_sem_trywait,
- StatInt_sem_timedwait,
- StatInt_sem_post,
- StatInt_sem_getvalue,
- StatInt_stat,
- StatInt___xstat,
- StatInt_stat64,
- StatInt___xstat64,
- StatInt_lstat,
- StatInt___lxstat,
- StatInt_lstat64,
- StatInt___lxstat64,
- StatInt_fstat,
- StatInt___fxstat,
- StatInt_fstat64,
- StatInt___fxstat64,
- StatInt_open,
- StatInt_open64,
- StatInt_creat,
- StatInt_creat64,
- StatInt_dup,
- StatInt_dup2,
- StatInt_dup3,
- StatInt_eventfd,
- StatInt_signalfd,
- StatInt_inotify_init,
- StatInt_inotify_init1,
- StatInt_socket,
- StatInt_socketpair,
- StatInt_connect,
- StatInt_bind,
- StatInt_listen,
- StatInt_accept,
- StatInt_accept4,
- StatInt_epoll_create,
- StatInt_epoll_create1,
- StatInt_close,
- StatInt___close,
- StatInt___res_iclose,
- StatInt_pipe,
- StatInt_pipe2,
- StatInt_read,
- StatInt_prctl,
- StatInt_pread,
- StatInt_pread64,
- StatInt_readv,
- StatInt_preadv,
- StatInt_preadv64,
- StatInt_write,
- StatInt_pwrite,
- StatInt_pwrite64,
- StatInt_writev,
- StatInt_pwritev,
- StatInt_pwritev64,
- StatInt_send,
- StatInt_sendmsg,
- StatInt_recv,
- StatInt_recvmsg,
- StatInt_unlink,
- StatInt_fopen,
- StatInt_freopen,
- StatInt_fclose,
- StatInt_fread,
- StatInt_fwrite,
- StatInt_fflush,
- StatInt_abort,
- StatInt_puts,
- StatInt_rmdir,
- StatInt_opendir,
- StatInt_epoll_ctl,
- StatInt_epoll_wait,
- StatInt_poll,
- StatInt_ppoll,
- StatInt_sigaction,
- StatInt_signal,
- StatInt_sigsuspend,
- StatInt_raise,
- StatInt_kill,
- StatInt_pthread_kill,
- StatInt_sleep,
- StatInt_usleep,
- StatInt_nanosleep,
- StatInt_gettimeofday,
- StatInt_fork,
- StatInt_vscanf,
- StatInt_vsscanf,
- StatInt_vfscanf,
- StatInt_scanf,
- StatInt_sscanf,
- StatInt_fscanf,
- StatInt___isoc99_vscanf,
- StatInt___isoc99_vsscanf,
- StatInt___isoc99_vfscanf,
- StatInt___isoc99_scanf,
- StatInt___isoc99_sscanf,
- StatInt___isoc99_fscanf,
- StatInt_on_exit,
- StatInt___cxa_atexit,
- StatInt_localtime,
- StatInt_localtime_r,
- StatInt_gmtime,
- StatInt_gmtime_r,
- StatInt_ctime,
- StatInt_ctime_r,
- StatInt_asctime,
- StatInt_asctime_r,
- StatInt_strptime,
- StatInt_frexp,
- StatInt_frexpf,
- StatInt_frexpl,
- StatInt_getpwnam,
- StatInt_getpwuid,
- StatInt_getgrnam,
- StatInt_getgrgid,
- StatInt_getpwnam_r,
- StatInt_getpwuid_r,
- StatInt_getgrnam_r,
- StatInt_getgrgid_r,
- StatInt_clock_getres,
- StatInt_clock_gettime,
- StatInt_clock_settime,
- StatInt_getitimer,
- StatInt_setitimer,
- StatInt_time,
- StatInt_glob,
- StatInt_glob64,
- StatInt_wait,
- StatInt_waitid,
- StatInt_waitpid,
- StatInt_wait3,
- StatInt_wait4,
- StatInt_inet_ntop,
- StatInt_inet_pton,
- StatInt_inet_aton,
- StatInt_getaddrinfo,
- StatInt_getnameinfo,
- StatInt_getsockname,
- StatInt_gethostent,
- StatInt_gethostbyname,
- StatInt_gethostbyname2,
- StatInt_gethostbyaddr,
- StatInt_gethostent_r,
- StatInt_gethostbyname_r,
- StatInt_gethostbyname2_r,
- StatInt_gethostbyaddr_r,
- StatInt_getsockopt,
- StatInt_modf,
- StatInt_modff,
- StatInt_modfl,
- StatInt_getpeername,
- StatInt_ioctl,
- StatInt_sysinfo,
- StatInt_readdir,
- StatInt_readdir64,
- StatInt_readdir_r,
- StatInt_readdir64_r,
- StatInt_ptrace,
- StatInt_setlocale,
- StatInt_getcwd,
- StatInt_get_current_dir_name,
- StatInt_strtoimax,
- StatInt_strtoumax,
- StatInt_mbstowcs,
- StatInt_mbsrtowcs,
- StatInt_mbsnrtowcs,
- StatInt_wcstombs,
- StatInt_wcsrtombs,
- StatInt_wcsnrtombs,
- StatInt_tcgetattr,
- StatInt_realpath,
- StatInt_canonicalize_file_name,
- StatInt_confstr,
- StatInt_sched_getaffinity,
- StatInt_strerror,
- StatInt_strerror_r,
- StatInt_scandir,
- StatInt_scandir64,
- StatInt_getgroups,
- StatInt_wordexp,
- StatInt_sigwait,
- StatInt_sigwaitinfo,
- StatInt_sigtimedwait,
- StatInt_sigemptyset,
- StatInt_sigfillset,
- StatInt_sigpending,
- StatInt_sigprocmask,
- StatInt_backtrace,
- StatInt_backtrace_symbols,
- StatInt_dlopen,
- StatInt_dlclose,
- StatInt_getmntent,
- StatInt_getmntent_r,
- StatInt_statfs,
- StatInt_statfs64,
- StatInt_fstatfs,
- StatInt_fstatfs64,
- StatInt_statvfs,
- StatInt_statvfs64,
- StatInt_fstatvfs,
- StatInt_fstatvfs64,
- StatInt_initgroups,
- StatInt_ether_ntoa,
- StatInt_ether_aton,
- StatInt_ether_ntoa_r,
- StatInt_ether_aton_r,
- StatInt_ether_ntohost,
- StatInt_ether_hostton,
- StatInt_ether_line,
- StatInt_shmctl,
- StatInt_random_r,
- StatInt_tmpnam,
- StatInt_tmpnam_r,
- StatInt_tempnam,
- StatInt_sincos,
- StatInt_sincosf,
- StatInt_sincosl,
- StatInt_remquo,
- StatInt_remquof,
- StatInt_remquol,
- StatInt_lgamma,
- StatInt_lgammaf,
- StatInt_lgammal,
- StatInt_lgamma_r,
- StatInt_lgammaf_r,
- StatInt_lgammal_r,
- StatInt_drand48_r,
- StatInt_lrand48_r,
- StatInt_getline,
- StatInt_getdelim,
-
- StatInt_pthread_attr_getdetachstate,
- StatInt_pthread_attr_getguardsize,
- StatInt_pthread_attr_getschedparam,
- StatInt_pthread_attr_getschedpolicy,
- StatInt_pthread_attr_getinheritsched,
- StatInt_pthread_attr_getscope,
- StatInt_pthread_attr_getstacksize,
- StatInt_pthread_attr_getstack,
- StatInt_pthread_attr_getaffinity_np,
-
// Dynamic annotations.
StatAnnotation,
StatAnnotateHappensBefore,
@@ -470,6 +170,7 @@ enum StatType {
StatMtxAtExit,
StatMtxMBlock,
StatMtxJavaMBlock,
+ StatMtxDeadlockDetector,
StatMtxFD,
// This must be the last.
diff --git a/lib/tsan/rtl/tsan_suppressions.cc b/lib/tsan/rtl/tsan_suppressions.cc
index 4b0ac04c48a6..299fc80fd262 100644
--- a/lib/tsan/rtl/tsan_suppressions.cc
+++ b/lib/tsan/rtl/tsan_suppressions.cc
@@ -33,7 +33,7 @@ static const char *const std_suppressions =
"race:std::_Sp_counted_ptr_inplace<std::thread::_Impl\n";
// Can be overriden in frontend.
-#ifndef TSAN_GO
+#ifndef SANITIZER_GO
extern "C" const char *WEAK __tsan_default_suppressions() {
return 0;
}
@@ -41,55 +41,16 @@ extern "C" const char *WEAK __tsan_default_suppressions() {
namespace __tsan {
-static SuppressionContext* g_ctx;
-
-static char *ReadFile(const char *filename) {
- if (filename == 0 || filename[0] == 0)
- return 0;
- InternalScopedBuffer<char> tmp(4*1024);
- if (filename[0] == '/' || GetPwd() == 0)
- internal_snprintf(tmp.data(), tmp.size(), "%s", filename);
- else
- internal_snprintf(tmp.data(), tmp.size(), "%s/%s", GetPwd(), filename);
- uptr openrv = OpenFile(tmp.data(), false);
- if (internal_iserror(openrv)) {
- Printf("ThreadSanitizer: failed to open suppressions file '%s'\n",
- tmp.data());
- Die();
- }
- fd_t fd = openrv;
- const uptr fsize = internal_filesize(fd);
- if (fsize == (uptr)-1) {
- Printf("ThreadSanitizer: failed to stat suppressions file '%s'\n",
- tmp.data());
- Die();
- }
- char *buf = (char*)internal_alloc(MBlockSuppression, fsize + 1);
- if (fsize != internal_read(fd, buf, fsize)) {
- Printf("ThreadSanitizer: failed to read suppressions file '%s'\n",
- tmp.data());
- Die();
- }
- internal_close(fd);
- buf[fsize] = 0;
- return buf;
-}
+static bool suppressions_inited = false;
void InitializeSuppressions() {
- ALIGNED(64) static char placeholder_[sizeof(SuppressionContext)];
- g_ctx = new(placeholder_) SuppressionContext;
- const char *supp = ReadFile(flags()->suppressions);
- g_ctx->Parse(supp);
-#ifndef TSAN_GO
- supp = __tsan_default_suppressions();
- g_ctx->Parse(supp);
- g_ctx->Parse(std_suppressions);
+ CHECK(!suppressions_inited);
+ SuppressionContext::InitIfNecessary();
+#ifndef SANITIZER_GO
+ SuppressionContext::Get()->Parse(__tsan_default_suppressions());
+ SuppressionContext::Get()->Parse(std_suppressions);
#endif
-}
-
-SuppressionContext *GetSuppressionContext() {
- CHECK_NE(g_ctx, 0);
- return g_ctx;
+ suppressions_inited = true;
}
SuppressionType conv(ReportType typ) {
@@ -99,62 +60,75 @@ SuppressionType conv(ReportType typ) {
return SuppressionRace;
else if (typ == ReportTypeUseAfterFree)
return SuppressionRace;
+ else if (typ == ReportTypeVptrUseAfterFree)
+ return SuppressionRace;
else if (typ == ReportTypeThreadLeak)
return SuppressionThread;
else if (typ == ReportTypeMutexDestroyLocked)
return SuppressionMutex;
+ else if (typ == ReportTypeMutexDoubleLock)
+ return SuppressionMutex;
+ else if (typ == ReportTypeMutexBadUnlock)
+ return SuppressionMutex;
+ else if (typ == ReportTypeMutexBadReadLock)
+ return SuppressionMutex;
+ else if (typ == ReportTypeMutexBadReadUnlock)
+ return SuppressionMutex;
else if (typ == ReportTypeSignalUnsafe)
return SuppressionSignal;
else if (typ == ReportTypeErrnoInSignal)
return SuppressionNone;
+ else if (typ == ReportTypeDeadlock)
+ return SuppressionDeadlock;
Printf("ThreadSanitizer: unknown report type %d\n", typ),
Die();
}
uptr IsSuppressed(ReportType typ, const ReportStack *stack, Suppression **sp) {
- CHECK(g_ctx);
- if (!g_ctx->SuppressionCount() || stack == 0) return 0;
+ if (!SuppressionContext::Get()->SuppressionCount() || stack == 0 ||
+ !stack->suppressable)
+ return 0;
SuppressionType stype = conv(typ);
if (stype == SuppressionNone)
return 0;
Suppression *s;
- for (const ReportStack *frame = stack; frame; frame = frame->next) {
- if (g_ctx->Match(frame->func, stype, &s) ||
- g_ctx->Match(frame->file, stype, &s) ||
- g_ctx->Match(frame->module, stype, &s)) {
+ for (const SymbolizedStack *frame = stack->frames; frame;
+ frame = frame->next) {
+ const AddressInfo &info = frame->info;
+ if (SuppressionContext::Get()->Match(info.function, stype, &s) ||
+ SuppressionContext::Get()->Match(info.file, stype, &s) ||
+ SuppressionContext::Get()->Match(info.module, stype, &s)) {
DPrintf("ThreadSanitizer: matched suppression '%s'\n", s->templ);
s->hit_count++;
*sp = s;
- return frame->pc;
+ return info.address;
}
}
return 0;
}
uptr IsSuppressed(ReportType typ, const ReportLocation *loc, Suppression **sp) {
- CHECK(g_ctx);
- if (!g_ctx->SuppressionCount() || loc == 0 ||
- loc->type != ReportLocationGlobal)
+ if (!SuppressionContext::Get()->SuppressionCount() || loc == 0 ||
+ loc->type != ReportLocationGlobal || !loc->suppressable)
return 0;
SuppressionType stype = conv(typ);
if (stype == SuppressionNone)
return 0;
Suppression *s;
- if (g_ctx->Match(loc->name, stype, &s) ||
- g_ctx->Match(loc->file, stype, &s) ||
- g_ctx->Match(loc->module, stype, &s)) {
+ const DataInfo &global = loc->global;
+ if (SuppressionContext::Get()->Match(global.name, stype, &s) ||
+ SuppressionContext::Get()->Match(global.module, stype, &s)) {
DPrintf("ThreadSanitizer: matched suppression '%s'\n", s->templ);
s->hit_count++;
*sp = s;
- return loc->addr;
+ return global.start;
}
return 0;
}
void PrintMatchedSuppressions() {
- CHECK(g_ctx);
InternalMmapVector<Suppression *> matched(1);
- g_ctx->GetMatched(&matched);
+ SuppressionContext::Get()->GetMatched(&matched);
if (!matched.size())
return;
int hit_count = 0;
diff --git a/lib/tsan/rtl/tsan_suppressions.h b/lib/tsan/rtl/tsan_suppressions.h
index fe7db588f50f..c618b3db4c2d 100644
--- a/lib/tsan/rtl/tsan_suppressions.h
+++ b/lib/tsan/rtl/tsan_suppressions.h
@@ -22,7 +22,6 @@ void InitializeSuppressions();
void PrintMatchedSuppressions();
uptr IsSuppressed(ReportType typ, const ReportStack *stack, Suppression **sp);
uptr IsSuppressed(ReportType typ, const ReportLocation *loc, Suppression **sp);
-SuppressionContext *GetSuppressionContext();
} // namespace __tsan
diff --git a/lib/tsan/rtl/tsan_symbolize.cc b/lib/tsan/rtl/tsan_symbolize.cc
index 75acf1d8438b..3beb44f7ad3b 100644
--- a/lib/tsan/rtl/tsan_symbolize.cc
+++ b/lib/tsan/rtl/tsan_symbolize.cc
@@ -26,50 +26,16 @@ void EnterSymbolizer() {
ThreadState *thr = cur_thread();
CHECK(!thr->in_symbolizer);
thr->in_symbolizer = true;
+ thr->ignore_interceptors++;
}
void ExitSymbolizer() {
ThreadState *thr = cur_thread();
CHECK(thr->in_symbolizer);
thr->in_symbolizer = false;
+ thr->ignore_interceptors--;
}
-ReportStack *NewReportStackEntry(uptr addr) {
- ReportStack *ent = (ReportStack*)internal_alloc(MBlockReportStack,
- sizeof(ReportStack));
- internal_memset(ent, 0, sizeof(*ent));
- ent->pc = addr;
- return ent;
-}
-
-static ReportStack *NewReportStackEntry(const AddressInfo &info) {
- ReportStack *ent = NewReportStackEntry(info.address);
- ent->module = StripModuleName(info.module);
- ent->offset = info.module_offset;
- if (info.function)
- ent->func = internal_strdup(info.function);
- if (info.file)
- ent->file = internal_strdup(info.file);
- ent->line = info.line;
- ent->col = info.column;
- return ent;
-}
-
-
- ReportStack *next;
- char *module;
- uptr offset;
- uptr pc;
- char *func;
- char *file;
- int line;
- int col;
-
-
-// Denotes fake PC values that come from JIT/JAVA/etc.
-// For such PC values __tsan_symbolize_external() will be called.
-const uptr kExternalPCBit = 1ULL << 60;
-
// May be overriden by JIT/JAVA/etc,
// whatever produces PCs marked with kExternalPCBit.
extern "C" bool __tsan_symbolize_external(uptr pc,
@@ -85,7 +51,7 @@ bool __tsan_symbolize_external(uptr pc,
return false;
}
-ReportStack *SymbolizeCode(uptr addr) {
+SymbolizedStack *SymbolizeCode(uptr addr) {
// Check if PC comes from non-native land.
if (addr & kExternalPCBit) {
// Declare static to not consume too much stack space.
@@ -93,66 +59,30 @@ ReportStack *SymbolizeCode(uptr addr) {
static char func_buf[1024];
static char file_buf[1024];
int line, col;
- if (!__tsan_symbolize_external(addr, func_buf, sizeof(func_buf),
- file_buf, sizeof(file_buf), &line, &col))
- return NewReportStackEntry(addr);
- ReportStack *ent = NewReportStackEntry(addr);
- ent->module = 0;
- ent->offset = 0;
- ent->func = internal_strdup(func_buf);
- ent->file = internal_strdup(file_buf);
- ent->line = line;
- ent->col = col;
- return ent;
- }
- if (!Symbolizer::Get()->IsAvailable())
- return SymbolizeCodeAddr2Line(addr);
- static const uptr kMaxAddrFrames = 16;
- InternalScopedBuffer<AddressInfo> addr_frames(kMaxAddrFrames);
- for (uptr i = 0; i < kMaxAddrFrames; i++)
- new(&addr_frames[i]) AddressInfo();
- uptr addr_frames_num = Symbolizer::Get()->SymbolizeCode(
- addr, addr_frames.data(), kMaxAddrFrames);
- if (addr_frames_num == 0)
- return NewReportStackEntry(addr);
- ReportStack *top = 0;
- ReportStack *bottom = 0;
- for (uptr i = 0; i < addr_frames_num; i++) {
- ReportStack *cur_entry = NewReportStackEntry(addr_frames[i]);
- CHECK(cur_entry);
- addr_frames[i].Clear();
- if (i == 0)
- top = cur_entry;
- else
- bottom->next = cur_entry;
- bottom = cur_entry;
+ SymbolizedStack *frame = SymbolizedStack::New(addr);
+ if (__tsan_symbolize_external(addr, func_buf, sizeof(func_buf), file_buf,
+ sizeof(file_buf), &line, &col)) {
+ frame->info.function = internal_strdup(func_buf);
+ frame->info.file = internal_strdup(file_buf);
+ frame->info.line = line;
+ frame->info.column = col;
+ }
+ return frame;
}
- return top;
+ return Symbolizer::GetOrInit()->SymbolizePC(addr);
}
ReportLocation *SymbolizeData(uptr addr) {
- if (!Symbolizer::Get()->IsAvailable())
- return 0;
DataInfo info;
- if (!Symbolizer::Get()->SymbolizeData(addr, &info))
+ if (!Symbolizer::GetOrInit()->SymbolizeData(addr, &info))
return 0;
- ReportLocation *ent = (ReportLocation*)internal_alloc(MBlockReportStack,
- sizeof(ReportLocation));
- internal_memset(ent, 0, sizeof(*ent));
- ent->type = ReportLocationGlobal;
- ent->module = StripModuleName(info.module);
- ent->offset = info.module_offset;
- if (info.name)
- ent->name = internal_strdup(info.name);
- ent->addr = info.start;
- ent->size = info.size;
+ ReportLocation *ent = ReportLocation::New(ReportLocationGlobal);
+ ent->global = info;
return ent;
}
void SymbolizeFlush() {
- if (!Symbolizer::Get()->IsAvailable())
- return;
- Symbolizer::Get()->Flush();
+ Symbolizer::GetOrInit()->Flush();
}
} // namespace __tsan
diff --git a/lib/tsan/rtl/tsan_symbolize.h b/lib/tsan/rtl/tsan_symbolize.h
index 6282e45b40d5..b59b6cfb8341 100644
--- a/lib/tsan/rtl/tsan_symbolize.h
+++ b/lib/tsan/rtl/tsan_symbolize.h
@@ -18,14 +18,16 @@
namespace __tsan {
+// Denotes fake PC values that come from JIT/JAVA/etc.
+// For such PC values __tsan_symbolize_external() will be called.
+const uptr kExternalPCBit = 1ULL << 60;
+
void EnterSymbolizer();
void ExitSymbolizer();
-ReportStack *SymbolizeCode(uptr addr);
+SymbolizedStack *SymbolizeCode(uptr addr);
ReportLocation *SymbolizeData(uptr addr);
void SymbolizeFlush();
-ReportStack *SymbolizeCodeAddr2Line(uptr addr);
-
ReportStack *NewReportStackEntry(uptr addr);
} // namespace __tsan
diff --git a/lib/tsan/rtl/tsan_symbolize_addr2line_linux.cc b/lib/tsan/rtl/tsan_symbolize_addr2line_linux.cc
deleted file mode 100644
index b186d3b38ec9..000000000000
--- a/lib/tsan/rtl/tsan_symbolize_addr2line_linux.cc
+++ /dev/null
@@ -1,193 +0,0 @@
-//===-- tsan_symbolize_addr2line.cc ---------------------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file is a part of ThreadSanitizer (TSan), a race detector.
-//
-//===----------------------------------------------------------------------===//
-#include "sanitizer_common/sanitizer_common.h"
-#include "sanitizer_common/sanitizer_libc.h"
-#include "tsan_symbolize.h"
-#include "tsan_mman.h"
-#include "tsan_rtl.h"
-#include "tsan_platform.h"
-
-#include <unistd.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <errno.h>
-#include <link.h>
-#include <linux/limits.h>
-#include <sys/types.h>
-
-namespace __tsan {
-
-struct ModuleDesc {
- const char *fullname;
- const char *name;
- uptr base;
- int inp_fd;
- int out_fd;
-};
-
-struct SectionDesc {
- SectionDesc *next;
- ModuleDesc *module;
- uptr base;
- uptr end;
-};
-
-struct DlIteratePhdrCtx {
- SectionDesc *sections;
- bool is_first;
-};
-
-static void NOINLINE InitModule(ModuleDesc *m) {
- int outfd[2] = {};
- if (pipe(&outfd[0])) {
- Printf("ThreadSanitizer: outfd pipe() failed (%d)\n", errno);
- Die();
- }
- int infd[2] = {};
- if (pipe(&infd[0])) {
- Printf("ThreadSanitizer: infd pipe() failed (%d)\n", errno);
- Die();
- }
- int pid = fork();
- if (pid == 0) {
- internal_close(STDOUT_FILENO);
- internal_close(STDIN_FILENO);
- internal_dup2(outfd[0], STDIN_FILENO);
- internal_dup2(infd[1], STDOUT_FILENO);
- internal_close(outfd[0]);
- internal_close(outfd[1]);
- internal_close(infd[0]);
- internal_close(infd[1]);
- for (int fd = getdtablesize(); fd > 2; fd--)
- internal_close(fd);
- execl("/usr/bin/addr2line", "/usr/bin/addr2line", "-Cfe", m->fullname, 0);
- _exit(0);
- } else if (pid < 0) {
- Printf("ThreadSanitizer: failed to fork symbolizer\n");
- Die();
- }
- internal_close(outfd[0]);
- internal_close(infd[1]);
- m->inp_fd = infd[0];
- m->out_fd = outfd[1];
-}
-
-static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *arg) {
- DlIteratePhdrCtx *ctx = (DlIteratePhdrCtx*)arg;
- InternalScopedBuffer<char> tmp(128);
- if (ctx->is_first) {
- internal_snprintf(tmp.data(), tmp.size(), "/proc/%d/exe",
- (int)internal_getpid());
- info->dlpi_name = tmp.data();
- }
- ctx->is_first = false;
- if (info->dlpi_name == 0 || info->dlpi_name[0] == 0)
- return 0;
- ModuleDesc *m = (ModuleDesc*)internal_alloc(MBlockReportStack,
- sizeof(ModuleDesc));
- m->fullname = internal_strdup(info->dlpi_name);
- m->name = internal_strrchr(m->fullname, '/');
- if (m->name)
- m->name += 1;
- else
- m->name = m->fullname;
- m->base = (uptr)info->dlpi_addr;
- m->inp_fd = -1;
- m->out_fd = -1;
- DPrintf2("Module %s %zx\n", m->name, m->base);
- for (int i = 0; i < info->dlpi_phnum; i++) {
- const Elf64_Phdr *s = &info->dlpi_phdr[i];
- DPrintf2(" Section p_type=%zx p_offset=%zx p_vaddr=%zx p_paddr=%zx"
- " p_filesz=%zx p_memsz=%zx p_flags=%zx p_align=%zx\n",
- (uptr)s->p_type, (uptr)s->p_offset, (uptr)s->p_vaddr,
- (uptr)s->p_paddr, (uptr)s->p_filesz, (uptr)s->p_memsz,
- (uptr)s->p_flags, (uptr)s->p_align);
- if (s->p_type != PT_LOAD)
- continue;
- SectionDesc *sec = (SectionDesc*)internal_alloc(MBlockReportStack,
- sizeof(SectionDesc));
- sec->module = m;
- sec->base = info->dlpi_addr + s->p_vaddr;
- sec->end = sec->base + s->p_memsz;
- sec->next = ctx->sections;
- ctx->sections = sec;
- DPrintf2(" Section %zx-%zx\n", sec->base, sec->end);
- }
- return 0;
-}
-
-static SectionDesc *InitSections() {
- DlIteratePhdrCtx ctx = {0, true};
- dl_iterate_phdr(dl_iterate_phdr_cb, &ctx);
- return ctx.sections;
-}
-
-static SectionDesc *GetSectionDesc(uptr addr) {
- static SectionDesc *sections = 0;
- if (sections == 0)
- sections = InitSections();
- for (SectionDesc *s = sections; s; s = s->next) {
- if (addr >= s->base && addr < s->end) {
- if (s->module->inp_fd == -1)
- InitModule(s->module);
- return s;
- }
- }
- return 0;
-}
-
-ReportStack *SymbolizeCodeAddr2Line(uptr addr) {
- SectionDesc *s = GetSectionDesc(addr);
- if (s == 0)
- return NewReportStackEntry(addr);
- ModuleDesc *m = s->module;
- uptr offset = addr - m->base;
- char addrstr[32];
- internal_snprintf(addrstr, sizeof(addrstr), "%p\n", (void*)offset);
- if (0 >= internal_write(m->out_fd, addrstr, internal_strlen(addrstr))) {
- Printf("ThreadSanitizer: can't write from symbolizer (%d, %d)\n",
- m->out_fd, errno);
- Die();
- }
- InternalScopedBuffer<char> func(1024);
- ssize_t len = internal_read(m->inp_fd, func.data(), func.size() - 1);
- if (len <= 0) {
- Printf("ThreadSanitizer: can't read from symbolizer (%d, %d)\n",
- m->inp_fd, errno);
- Die();
- }
- func.data()[len] = 0;
- ReportStack *res = NewReportStackEntry(addr);
- res->module = internal_strdup(m->name);
- res->offset = offset;
- char *pos = (char*)internal_strchr(func.data(), '\n');
- if (pos && func[0] != '?') {
- res->func = (char*)internal_alloc(MBlockReportStack, pos - func.data() + 1);
- internal_memcpy(res->func, func.data(), pos - func.data());
- res->func[pos - func.data()] = 0;
- char *pos2 = (char*)internal_strchr(pos, ':');
- if (pos2) {
- res->file = (char*)internal_alloc(MBlockReportStack, pos2 - pos - 1 + 1);
- internal_memcpy(res->file, pos + 1, pos2 - pos - 1);
- res->file[pos2 - pos - 1] = 0;
- res->line = atoi(pos2 + 1);
- }
- }
- return res;
-}
-
-ReportStack *SymbolizeDataAddr2Line(uptr addr) {
- return 0;
-}
-
-} // namespace __tsan
diff --git a/lib/tsan/rtl/tsan_sync.cc b/lib/tsan/rtl/tsan_sync.cc
index f8f3c40fab04..1041073bed51 100644
--- a/lib/tsan/rtl/tsan_sync.cc
+++ b/lib/tsan/rtl/tsan_sync.cc
@@ -17,290 +17,209 @@
namespace __tsan {
-SyncVar::SyncVar(uptr addr, u64 uid)
- : mtx(MutexTypeSyncVar, StatMtxSyncVar)
- , addr(addr)
- , uid(uid)
- , owner_tid(kInvalidTid)
- , last_lock()
- , recursion()
- , is_rw()
- , is_recursive()
- , is_broken()
- , is_linker_init() {
+void DDMutexInit(ThreadState *thr, uptr pc, SyncVar *s);
+
+SyncVar::SyncVar()
+ : mtx(MutexTypeSyncVar, StatMtxSyncVar) {
+ Reset(0);
+}
+
+void SyncVar::Init(ThreadState *thr, uptr pc, uptr addr, u64 uid) {
+ this->addr = addr;
+ this->uid = uid;
+ this->next = 0;
+
+ creation_stack_id = 0;
+ if (kCppMode) // Go does not use them
+ creation_stack_id = CurrentStackId(thr, pc);
+ if (common_flags()->detect_deadlocks)
+ DDMutexInit(thr, pc, this);
+}
+
+void SyncVar::Reset(ThreadState *thr) {
+ uid = 0;
+ creation_stack_id = 0;
+ owner_tid = kInvalidTid;
+ last_lock = 0;
+ recursion = 0;
+ is_rw = 0;
+ is_recursive = 0;
+ is_broken = 0;
+ is_linker_init = 0;
+
+ if (thr == 0) {
+ CHECK_EQ(clock.size(), 0);
+ CHECK_EQ(read_clock.size(), 0);
+ } else {
+ clock.Reset(&thr->clock_cache);
+ read_clock.Reset(&thr->clock_cache);
+ }
}
-SyncTab::Part::Part()
- : mtx(MutexTypeSyncTab, StatMtxSyncTab)
- , val() {
+MetaMap::MetaMap() {
+ atomic_store(&uid_gen_, 0, memory_order_relaxed);
}
-SyncTab::SyncTab() {
+void MetaMap::AllocBlock(ThreadState *thr, uptr pc, uptr p, uptr sz) {
+ u32 idx = block_alloc_.Alloc(&thr->block_cache);
+ MBlock *b = block_alloc_.Map(idx);
+ b->siz = sz;
+ b->tid = thr->tid;
+ b->stk = CurrentStackId(thr, pc);
+ u32 *meta = MemToMeta(p);
+ DCHECK_EQ(*meta, 0);
+ *meta = idx | kFlagBlock;
}
-SyncTab::~SyncTab() {
- for (int i = 0; i < kPartCount; i++) {
- while (tab_[i].val) {
- SyncVar *tmp = tab_[i].val;
- tab_[i].val = tmp->next;
- DestroyAndFree(tmp);
+uptr MetaMap::FreeBlock(ThreadState *thr, uptr pc, uptr p) {
+ MBlock* b = GetBlock(p);
+ if (b == 0)
+ return 0;
+ uptr sz = RoundUpTo(b->siz, kMetaShadowCell);
+ FreeRange(thr, pc, p, sz);
+ return sz;
+}
+
+void MetaMap::FreeRange(ThreadState *thr, uptr pc, uptr p, uptr sz) {
+ u32 *meta = MemToMeta(p);
+ u32 *end = MemToMeta(p + sz);
+ if (end == meta)
+ end++;
+ for (; meta < end; meta++) {
+ u32 idx = *meta;
+ *meta = 0;
+ for (;;) {
+ if (idx == 0)
+ break;
+ if (idx & kFlagBlock) {
+ block_alloc_.Free(&thr->block_cache, idx & ~kFlagMask);
+ break;
+ } else if (idx & kFlagSync) {
+ DCHECK(idx & kFlagSync);
+ SyncVar *s = sync_alloc_.Map(idx & ~kFlagMask);
+ u32 next = s->next;
+ s->Reset(thr);
+ sync_alloc_.Free(&thr->sync_cache, idx & ~kFlagMask);
+ idx = next;
+ } else {
+ CHECK(0);
+ }
}
}
}
-SyncVar* SyncTab::GetOrCreateAndLock(ThreadState *thr, uptr pc,
- uptr addr, bool write_lock) {
- return GetAndLock(thr, pc, addr, write_lock, true);
+MBlock* MetaMap::GetBlock(uptr p) {
+ u32 *meta = MemToMeta(p);
+ u32 idx = *meta;
+ for (;;) {
+ if (idx == 0)
+ return 0;
+ if (idx & kFlagBlock)
+ return block_alloc_.Map(idx & ~kFlagMask);
+ DCHECK(idx & kFlagSync);
+ SyncVar * s = sync_alloc_.Map(idx & ~kFlagMask);
+ idx = s->next;
+ }
}
-SyncVar* SyncTab::GetIfExistsAndLock(uptr addr, bool write_lock) {
- return GetAndLock(0, 0, addr, write_lock, false);
+SyncVar* MetaMap::GetOrCreateAndLock(ThreadState *thr, uptr pc,
+ uptr addr, bool write_lock) {
+ return GetAndLock(thr, pc, addr, write_lock, true);
}
-SyncVar* SyncTab::Create(ThreadState *thr, uptr pc, uptr addr) {
- StatInc(thr, StatSyncCreated);
- void *mem = internal_alloc(MBlockSync, sizeof(SyncVar));
- const u64 uid = atomic_fetch_add(&uid_gen_, 1, memory_order_relaxed);
- SyncVar *res = new(mem) SyncVar(addr, uid);
-#ifndef TSAN_GO
- res->creation_stack_id = CurrentStackId(thr, pc);
-#endif
- return res;
+SyncVar* MetaMap::GetIfExistsAndLock(uptr addr) {
+ return GetAndLock(0, 0, addr, true, false);
}
-SyncVar* SyncTab::GetAndLock(ThreadState *thr, uptr pc,
+SyncVar* MetaMap::GetAndLock(ThreadState *thr, uptr pc,
uptr addr, bool write_lock, bool create) {
-#ifndef TSAN_GO
- { // NOLINT
- SyncVar *res = GetJavaSync(thr, pc, addr, write_lock, create);
- if (res)
- return res;
- }
-
- // Here we ask only PrimaryAllocator, because
- // SecondaryAllocator::PointerIsMine() is slow and we have fallback on
- // the hashmap anyway.
- if (PrimaryAllocator::PointerIsMine((void*)addr)) {
- MBlock *b = user_mblock(thr, (void*)addr);
- CHECK_NE(b, 0);
- MBlock::ScopedLock l(b);
- SyncVar *res = 0;
- for (res = b->ListHead(); res; res = res->next) {
- if (res->addr == addr)
+ u32 *meta = MemToMeta(addr);
+ u32 idx0 = *meta;
+ u32 myidx = 0;
+ SyncVar *mys = 0;
+ for (;;) {
+ u32 idx = idx0;
+ for (;;) {
+ if (idx == 0)
break;
- }
- if (res == 0) {
- if (!create)
- return 0;
- res = Create(thr, pc, addr);
- b->ListPush(res);
- }
- if (write_lock)
- res->mtx.Lock();
- else
- res->mtx.ReadLock();
- return res;
- }
-#endif
-
- Part *p = &tab_[PartIdx(addr)];
- {
- ReadLock l(&p->mtx);
- for (SyncVar *res = p->val; res; res = res->next) {
- if (res->addr == addr) {
+ if (idx & kFlagBlock)
+ break;
+ DCHECK(idx & kFlagSync);
+ SyncVar * s = sync_alloc_.Map(idx & ~kFlagMask);
+ if (s->addr == addr) {
+ if (myidx != 0) {
+ mys->Reset(thr);
+ sync_alloc_.Free(&thr->sync_cache, myidx);
+ }
if (write_lock)
- res->mtx.Lock();
+ s->mtx.Lock();
else
- res->mtx.ReadLock();
- return res;
+ s->mtx.ReadLock();
+ return s;
}
+ idx = s->next;
}
- }
- if (!create)
- return 0;
- {
- Lock l(&p->mtx);
- SyncVar *res = p->val;
- for (; res; res = res->next) {
- if (res->addr == addr)
- break;
- }
- if (res == 0) {
- res = Create(thr, pc, addr);
- res->next = p->val;
- p->val = res;
+ if (!create)
+ return 0;
+ if (*meta != idx0) {
+ idx0 = *meta;
+ continue;
}
- if (write_lock)
- res->mtx.Lock();
- else
- res->mtx.ReadLock();
- return res;
- }
-}
-SyncVar* SyncTab::GetAndRemove(ThreadState *thr, uptr pc, uptr addr) {
-#ifndef TSAN_GO
- { // NOLINT
- SyncVar *res = GetAndRemoveJavaSync(thr, pc, addr);
- if (res)
- return res;
- }
- if (PrimaryAllocator::PointerIsMine((void*)addr)) {
- MBlock *b = user_mblock(thr, (void*)addr);
- CHECK_NE(b, 0);
- SyncVar *res = 0;
- {
- MBlock::ScopedLock l(b);
- res = b->ListHead();
- if (res) {
- if (res->addr == addr) {
- if (res->is_linker_init)
- return 0;
- b->ListPop();
- } else {
- SyncVar **prev = &res->next;
- res = *prev;
- while (res) {
- if (res->addr == addr) {
- if (res->is_linker_init)
- return 0;
- *prev = res->next;
- break;
- }
- prev = &res->next;
- res = *prev;
- }
- }
- if (res) {
- StatInc(thr, StatSyncDestroyed);
- res->mtx.Lock();
- res->mtx.Unlock();
- }
- }
+ if (myidx == 0) {
+ const u64 uid = atomic_fetch_add(&uid_gen_, 1, memory_order_relaxed);
+ myidx = sync_alloc_.Alloc(&thr->sync_cache);
+ mys = sync_alloc_.Map(myidx);
+ mys->Init(thr, pc, addr, uid);
}
- return res;
- }
-#endif
-
- Part *p = &tab_[PartIdx(addr)];
- SyncVar *res = 0;
- {
- Lock l(&p->mtx);
- SyncVar **prev = &p->val;
- res = *prev;
- while (res) {
- if (res->addr == addr) {
- if (res->is_linker_init)
- return 0;
- *prev = res->next;
- break;
- }
- prev = &res->next;
- res = *prev;
+ mys->next = idx0;
+ if (atomic_compare_exchange_strong((atomic_uint32_t*)meta, &idx0,
+ myidx | kFlagSync, memory_order_release)) {
+ if (write_lock)
+ mys->mtx.Lock();
+ else
+ mys->mtx.ReadLock();
+ return mys;
}
}
- if (res) {
- StatInc(thr, StatSyncDestroyed);
- res->mtx.Lock();
- res->mtx.Unlock();
- }
- return res;
-}
-
-int SyncTab::PartIdx(uptr addr) {
- return (addr >> 3) % kPartCount;
-}
-
-StackTrace::StackTrace()
- : n_()
- , s_()
- , c_() {
}
-StackTrace::StackTrace(uptr *buf, uptr cnt)
- : n_()
- , s_(buf)
- , c_(cnt) {
- CHECK_NE(buf, 0);
- CHECK_NE(cnt, 0);
-}
-
-StackTrace::~StackTrace() {
- Reset();
-}
-
-void StackTrace::Reset() {
- if (s_ && !c_) {
- CHECK_NE(n_, 0);
- internal_free(s_);
- s_ = 0;
- }
- n_ = 0;
-}
-
-void StackTrace::Init(const uptr *pcs, uptr cnt) {
- Reset();
- if (cnt == 0)
- return;
- if (c_) {
- CHECK_NE(s_, 0);
- CHECK_LE(cnt, c_);
- } else {
- s_ = (uptr*)internal_alloc(MBlockStackTrace, cnt * sizeof(s_[0]));
+void MetaMap::MoveMemory(uptr src, uptr dst, uptr sz) {
+ // src and dst can overlap,
+ // there are no concurrent accesses to the regions (e.g. stop-the-world).
+ CHECK_NE(src, dst);
+ CHECK_NE(sz, 0);
+ uptr diff = dst - src;
+ u32 *src_meta = MemToMeta(src);
+ u32 *dst_meta = MemToMeta(dst);
+ u32 *src_meta_end = MemToMeta(src + sz);
+ uptr inc = 1;
+ if (dst > src) {
+ src_meta = MemToMeta(src + sz) - 1;
+ dst_meta = MemToMeta(dst + sz) - 1;
+ src_meta_end = MemToMeta(src) - 1;
+ inc = -1;
}
- n_ = cnt;
- internal_memcpy(s_, pcs, cnt * sizeof(s_[0]));
-}
-
-void StackTrace::ObtainCurrent(ThreadState *thr, uptr toppc) {
- Reset();
- n_ = thr->shadow_stack_pos - thr->shadow_stack;
- if (n_ + !!toppc == 0)
- return;
- uptr start = 0;
- if (c_) {
- CHECK_NE(s_, 0);
- if (n_ + !!toppc > c_) {
- start = n_ - c_ + !!toppc;
- n_ = c_ - !!toppc;
- }
- } else {
- // Cap potentially huge stacks.
- if (n_ + !!toppc > kTraceStackSize) {
- start = n_ - kTraceStackSize + !!toppc;
- n_ = kTraceStackSize - !!toppc;
+ for (; src_meta != src_meta_end; src_meta += inc, dst_meta += inc) {
+ CHECK_EQ(*dst_meta, 0);
+ u32 idx = *src_meta;
+ *src_meta = 0;
+ *dst_meta = idx;
+ // Patch the addresses in sync objects.
+ while (idx != 0) {
+ if (idx & kFlagBlock)
+ break;
+ CHECK(idx & kFlagSync);
+ SyncVar *s = sync_alloc_.Map(idx & ~kFlagMask);
+ s->addr += diff;
+ idx = s->next;
}
- s_ = (uptr*)internal_alloc(MBlockStackTrace,
- (n_ + !!toppc) * sizeof(s_[0]));
- }
- for (uptr i = 0; i < n_; i++)
- s_[i] = thr->shadow_stack[start + i];
- if (toppc) {
- s_[n_] = toppc;
- n_++;
}
}
-void StackTrace::CopyFrom(const StackTrace& other) {
- Reset();
- Init(other.Begin(), other.Size());
-}
-
-bool StackTrace::IsEmpty() const {
- return n_ == 0;
-}
-
-uptr StackTrace::Size() const {
- return n_;
-}
-
-uptr StackTrace::Get(uptr i) const {
- CHECK_LT(i, n_);
- return s_[i];
-}
-
-const uptr *StackTrace::Begin() const {
- return s_;
+void MetaMap::OnThreadIdle(ThreadState *thr) {
+ block_alloc_.FlushCache(&thr->block_cache);
+ sync_alloc_.FlushCache(&thr->sync_cache);
}
} // namespace __tsan
diff --git a/lib/tsan/rtl/tsan_sync.h b/lib/tsan/rtl/tsan_sync.h
index 823af543f590..574810d8a542 100644
--- a/lib/tsan/rtl/tsan_sync.h
+++ b/lib/tsan/rtl/tsan_sync.h
@@ -15,50 +15,22 @@
#include "sanitizer_common/sanitizer_atomic.h"
#include "sanitizer_common/sanitizer_common.h"
-#include "tsan_clock.h"
+#include "sanitizer_common/sanitizer_deadlock_detector_interface.h"
#include "tsan_defs.h"
+#include "tsan_clock.h"
#include "tsan_mutex.h"
+#include "tsan_dense_alloc.h"
namespace __tsan {
-class SlabCache;
-
-class StackTrace {
- public:
- StackTrace();
- // Initialized the object in "static mode",
- // in this mode it never calls malloc/free but uses the provided buffer.
- StackTrace(uptr *buf, uptr cnt);
- ~StackTrace();
- void Reset();
-
- void Init(const uptr *pcs, uptr cnt);
- void ObtainCurrent(ThreadState *thr, uptr toppc);
- bool IsEmpty() const;
- uptr Size() const;
- uptr Get(uptr i) const;
- const uptr *Begin() const;
- void CopyFrom(const StackTrace& other);
-
- private:
- uptr n_;
- uptr *s_;
- const uptr c_;
-
- StackTrace(const StackTrace&);
- void operator = (const StackTrace&);
-};
-
struct SyncVar {
- explicit SyncVar(uptr addr, u64 uid);
+ SyncVar();
static const int kInvalidTid = -1;
+ uptr addr; // overwritten by DenseSlabAlloc freelist
Mutex mtx;
- uptr addr;
- const u64 uid; // Globally unique id.
- SyncClock clock;
- SyncClock read_clock; // Used for rw mutexes only.
+ u64 uid; // Globally unique id.
u32 creation_stack_id;
int owner_tid; // Set only by exclusive owners.
u64 last_lock;
@@ -67,9 +39,16 @@ struct SyncVar {
bool is_recursive;
bool is_broken;
bool is_linker_init;
- SyncVar *next; // In SyncTab hashtable.
+ u32 next; // in MetaMap
+ DDMutex dd;
+ SyncClock read_clock; // Used for rw mutexes only.
+ // The clock is placed last, so that it is situated on a different cache line
+ // with the mtx. This reduces contention for hot sync objects.
+ SyncClock clock;
+
+ void Init(ThreadState *thr, uptr pc, uptr addr, u64 uid);
+ void Reset(ThreadState *thr);
- uptr GetMemoryConsumption();
u64 GetId() const {
// 47 lsb is addr, then 14 bits is low part of uid, then 3 zero bits.
return GetLsb((u64)addr | (uid << 47), 61);
@@ -84,42 +63,39 @@ struct SyncVar {
}
};
-class SyncTab {
+/* MetaMap allows to map arbitrary user pointers onto various descriptors.
+ Currently it maps pointers to heap block descriptors and sync var descs.
+ It uses 1/2 direct shadow, see tsan_platform.h.
+*/
+class MetaMap {
public:
- SyncTab();
- ~SyncTab();
+ MetaMap();
+
+ void AllocBlock(ThreadState *thr, uptr pc, uptr p, uptr sz);
+ uptr FreeBlock(ThreadState *thr, uptr pc, uptr p);
+ void FreeRange(ThreadState *thr, uptr pc, uptr p, uptr sz);
+ MBlock* GetBlock(uptr p);
SyncVar* GetOrCreateAndLock(ThreadState *thr, uptr pc,
uptr addr, bool write_lock);
- SyncVar* GetIfExistsAndLock(uptr addr, bool write_lock);
-
- // If the SyncVar does not exist, returns 0.
- SyncVar* GetAndRemove(ThreadState *thr, uptr pc, uptr addr);
+ SyncVar* GetIfExistsAndLock(uptr addr);
- SyncVar* Create(ThreadState *thr, uptr pc, uptr addr);
+ void MoveMemory(uptr src, uptr dst, uptr sz);
- uptr GetMemoryConsumption(uptr *nsync);
+ void OnThreadIdle(ThreadState *thr);
private:
- struct Part {
- Mutex mtx;
- SyncVar *val;
- char pad[kCacheLineSize - sizeof(Mutex) - sizeof(SyncVar*)]; // NOLINT
- Part();
- };
-
- // FIXME: Implement something more sane.
- static const int kPartCount = 1009;
- Part tab_[kPartCount];
+ static const u32 kFlagMask = 3 << 30;
+ static const u32 kFlagBlock = 1 << 30;
+ static const u32 kFlagSync = 2 << 30;
+ typedef DenseSlabAlloc<MBlock, 1<<16, 1<<12> BlockAlloc;
+ typedef DenseSlabAlloc<SyncVar, 1<<16, 1<<10> SyncAlloc;
+ BlockAlloc block_alloc_;
+ SyncAlloc sync_alloc_;
atomic_uint64_t uid_gen_;
- int PartIdx(uptr addr);
-
- SyncVar* GetAndLock(ThreadState *thr, uptr pc,
- uptr addr, bool write_lock, bool create);
-
- SyncTab(const SyncTab&); // Not implemented.
- void operator = (const SyncTab&); // Not implemented.
+ SyncVar* GetAndLock(ThreadState *thr, uptr pc, uptr addr, bool write_lock,
+ bool create);
};
} // namespace __tsan
diff --git a/lib/tsan/rtl/tsan_trace.h b/lib/tsan/rtl/tsan_trace.h
index 5ed0356e2bf5..1da8752f6fa7 100644
--- a/lib/tsan/rtl/tsan_trace.h
+++ b/lib/tsan/rtl/tsan_trace.h
@@ -15,7 +15,7 @@
#include "tsan_defs.h"
#include "tsan_mutex.h"
-#include "tsan_sync.h"
+#include "tsan_stack_trace.h"
#include "tsan_mutexset.h"
namespace __tsan {
@@ -42,27 +42,21 @@ enum EventType {
typedef u64 Event;
struct TraceHeader {
- StackTrace stack0; // Start stack for the trace.
+#ifndef SANITIZER_GO
+ BufferedStackTrace stack0; // Start stack for the trace.
+#else
+ VarSizeStackTrace stack0;
+#endif
u64 epoch0; // Start epoch for the trace.
MutexSet mset0;
-#ifndef TSAN_GO
- uptr stack0buf[kTraceStackSize];
-#endif
- TraceHeader()
-#ifndef TSAN_GO
- : stack0(stack0buf, kTraceStackSize)
-#else
- : stack0()
-#endif
- , epoch0() {
- }
+ TraceHeader() : stack0(), epoch0() {}
};
struct Trace {
TraceHeader headers[kTraceParts];
Mutex mtx;
-#ifndef TSAN_GO
+#ifndef SANITIZER_GO
// Must be last to catch overflow as paging fault.
// Go shadow stack is dynamically allocated.
uptr shadow_stack[kShadowStackSize];
diff --git a/lib/tsan/rtl/tsan_update_shadow_word_inl.h b/lib/tsan/rtl/tsan_update_shadow_word_inl.h
index a11c9bc52509..c80e0a88d0eb 100644
--- a/lib/tsan/rtl/tsan_update_shadow_word_inl.h
+++ b/lib/tsan/rtl/tsan_update_shadow_word_inl.h
@@ -16,8 +16,7 @@
do {
StatInc(thr, StatShadowProcessed);
const unsigned kAccessSize = 1 << kAccessSizeLog;
- unsigned off = cur.ComputeSearchOffset();
- u64 *sp = &shadow_mem[(idx + off) % kShadowCnt];
+ u64 *sp = &shadow_mem[idx];
old = LoadShadow(sp);
if (old.IsZero()) {
StatInc(thr, StatShadowZero);
@@ -33,16 +32,6 @@ do {
// same thread?
if (Shadow::TidsAreEqual(old, cur)) {
StatInc(thr, StatShadowSameThread);
- if (OldIsInSameSynchEpoch(old, thr)) {
- if (old.IsRWNotWeaker(kAccessIsWrite, kIsAtomic)) {
- // found a slot that holds effectively the same info
- // (that is, same tid, same sync epoch and same size)
- StatInc(thr, StatMopSame);
- return;
- }
- StoreIfNotYetStored(sp, &store_word);
- break;
- }
if (old.IsRWWeakerOrEqual(kAccessIsWrite, kIsAtomic))
StoreIfNotYetStored(sp, &store_word);
break;
diff --git a/lib/tsan/rtl/tsan_vector.h b/lib/tsan/rtl/tsan_vector.h
index fa236b1f1e44..a7fb3fa58d54 100644
--- a/lib/tsan/rtl/tsan_vector.h
+++ b/lib/tsan/rtl/tsan_vector.h
@@ -58,10 +58,18 @@ class Vector {
return begin_[i];
}
- T *PushBack(T v = T()) {
+ T *PushBack() {
EnsureSize(Size() + 1);
- end_[-1] = v;
- return &end_[-1];
+ T *p = &end_[-1];
+ internal_memset(p, 0, sizeof(*p));
+ return p;
+ }
+
+ T *PushBack(const T& v) {
+ EnsureSize(Size() + 1);
+ T *p = &end_[-1];
+ internal_memcpy(p, &v, sizeof(*p));
+ return p;
}
void PopBack() {
@@ -70,11 +78,15 @@ class Vector {
}
void Resize(uptr size) {
+ if (size == 0) {
+ end_ = begin_;
+ return;
+ }
uptr old_size = Size();
EnsureSize(size);
if (old_size < size) {
for (uptr i = old_size; i < size; i++)
- begin_[i] = T();
+ internal_memset(&begin_[i], 0, sizeof(begin_[i]));
}
}
@@ -92,7 +104,7 @@ class Vector {
return;
}
uptr cap0 = last_ - begin_;
- uptr cap = 2 * cap0;
+ uptr cap = cap0 * 5 / 4; // 25% growth
if (cap == 0)
cap = 16;
if (cap < size)
diff --git a/lib/tsan/tests/CMakeLists.txt b/lib/tsan/tests/CMakeLists.txt
index f73a89242859..2e830c3be714 100644
--- a/lib/tsan/tests/CMakeLists.txt
+++ b/lib/tsan/tests/CMakeLists.txt
@@ -6,19 +6,28 @@ set_target_properties(TsanUnitTests PROPERTIES
set(TSAN_UNITTEST_CFLAGS
${TSAN_CFLAGS}
- ${COMPILER_RT_GTEST_INCLUDE_CFLAGS}
+ ${COMPILER_RT_GTEST_CFLAGS}
-I${COMPILER_RT_SOURCE_DIR}/lib
-I${COMPILER_RT_SOURCE_DIR}/lib/tsan/rtl
-DGTEST_HAS_RTTI=0)
+set(TSAN_RTL_HEADERS)
+foreach (header ${TSAN_HEADERS})
+ list(APPEND TSAN_RTL_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/../${header})
+endforeach()
+
# tsan_compile(obj_list, source, arch, {headers})
macro(tsan_compile obj_list source arch)
get_filename_component(basename ${source} NAME)
set(output_obj "${basename}.${arch}.o")
get_target_flags_for_arch(${arch} TARGET_CFLAGS)
+ set(COMPILE_DEPS ${TSAN_RTL_HEADERS} ${ARGN})
+ if(NOT COMPILER_RT_STANDALONE_BUILD)
+ list(APPEND COMPILE_DEPS gtest tsan)
+ endif()
clang_compile(${output_obj} ${source}
CFLAGS ${TSAN_UNITTEST_CFLAGS} ${TARGET_CFLAGS}
- DEPS gtest ${TSAN_RUNTIME_LIBRARIES} ${ARGN})
+ DEPS ${COMPILE_DEPS})
list(APPEND ${obj_list} ${output_obj})
endmacro()
@@ -31,9 +40,16 @@ macro(add_tsan_unittest testname)
tsan_compile(TEST_OBJECTS ${SOURCE} x86_64 ${TEST_HEADERS})
endforeach()
get_target_flags_for_arch(${arch} TARGET_LINK_FLAGS)
+ set(TEST_DEPS ${TEST_OBJECTS})
+ if(NOT COMPILER_RT_STANDALONE_BUILD)
+ list(APPEND TEST_DEPS tsan)
+ endif()
+ # FIXME: Looks like we should link TSan with just-built runtime,
+ # and not rely on -fsanitize=thread, as these tests are essentially
+ # unit tests.
add_compiler_rt_test(TsanUnitTests ${testname}
OBJECTS ${TEST_OBJECTS}
- DEPS ${TSAN_RUNTIME_LIBRARIES} ${TEST_OBJECTS}
+ DEPS ${TEST_DEPS}
LINK_FLAGS ${TARGET_LINK_FLAGS}
-fsanitize=thread
-lstdc++ -lm)
diff --git a/lib/tsan/tests/rtl/tsan_test.cc b/lib/tsan/tests/rtl/tsan_test.cc
index 2184284d39ce..b8b9555c2bff 100644
--- a/lib/tsan/tests/rtl/tsan_test.cc
+++ b/lib/tsan/tests/rtl/tsan_test.cc
@@ -45,6 +45,9 @@ int run_tests(int argc, char **argv) {
return res;
}
+const char *argv0;
+
int main(int argc, char **argv) {
+ argv0 = argv[0];
return run_tests(argc, argv);
}
diff --git a/lib/tsan/tests/rtl/tsan_test_util.h b/lib/tsan/tests/rtl/tsan_test_util.h
index 483a564c8475..84d277b137f0 100644
--- a/lib/tsan/tests/rtl/tsan_test_util.h
+++ b/lib/tsan/tests/rtl/tsan_test_util.h
@@ -37,7 +37,7 @@ class Mutex {
~Mutex();
void Init();
- void StaticInit(); // Emulates static initalization (tsan invisible).
+ void StaticInit(); // Emulates static initialization (tsan invisible).
void Destroy();
void Lock();
bool TryLock();
diff --git a/lib/tsan/tests/rtl/tsan_test_util_linux.cc b/lib/tsan/tests/rtl/tsan_test_util_linux.cc
index a2601486a2e1..9298bf051af2 100644
--- a/lib/tsan/tests/rtl/tsan_test_util_linux.cc
+++ b/lib/tsan/tests/rtl/tsan_test_util_linux.cc
@@ -10,7 +10,7 @@
//
// This file is a part of ThreadSanitizer (TSan), a race detector.
//
-// Test utils, linux implementation.
+// Test utils, Linux and FreeBSD implementation.
//===----------------------------------------------------------------------===//
#include "sanitizer_common/sanitizer_atomic.h"
@@ -263,9 +263,14 @@ void ScopedThread::Impl::HandleEvent(Event *ev) {
}
}
CHECK_NE(tsan_mop, 0);
- errno = ECHRNG;
+#if defined(__FreeBSD__)
+ const int ErrCode = ESOCKTNOSUPPORT;
+#else
+ const int ErrCode = ECHRNG;
+#endif
+ errno = ErrCode;
tsan_mop(ev->ptr);
- CHECK_EQ(errno, ECHRNG); // In no case must errno be changed.
+ CHECK_EQ(ErrCode, errno); // In no case must errno be changed.
break;
}
case Event::VPTR_UPDATE:
diff --git a/lib/tsan/tests/unit/tsan_clock_test.cc b/lib/tsan/tests/unit/tsan_clock_test.cc
index fe886e10bc57..a1fd2b7f6e99 100644
--- a/lib/tsan/tests/unit/tsan_clock_test.cc
+++ b/lib/tsan/tests/unit/tsan_clock_test.cc
@@ -13,110 +13,419 @@
#include "tsan_clock.h"
#include "tsan_rtl.h"
#include "gtest/gtest.h"
+#include <time.h>
namespace __tsan {
+ClockCache cache;
+
TEST(Clock, VectorBasic) {
- ScopedInRtl in_rtl;
- ThreadClock clk;
- CHECK_EQ(clk.size(), 0);
- clk.tick(0);
- CHECK_EQ(clk.size(), 1);
- CHECK_EQ(clk.get(0), 1);
- clk.tick(3);
- CHECK_EQ(clk.size(), 4);
- CHECK_EQ(clk.get(0), 1);
- CHECK_EQ(clk.get(1), 0);
- CHECK_EQ(clk.get(2), 0);
- CHECK_EQ(clk.get(3), 1);
- clk.tick(3);
- CHECK_EQ(clk.get(3), 2);
+ ThreadClock clk(0);
+ ASSERT_EQ(clk.size(), 1U);
+ clk.tick();
+ ASSERT_EQ(clk.size(), 1U);
+ ASSERT_EQ(clk.get(0), 1U);
+ clk.set(3, clk.get(3) + 1);
+ ASSERT_EQ(clk.size(), 4U);
+ ASSERT_EQ(clk.get(0), 1U);
+ ASSERT_EQ(clk.get(1), 0U);
+ ASSERT_EQ(clk.get(2), 0U);
+ ASSERT_EQ(clk.get(3), 1U);
+ clk.set(3, clk.get(3) + 1);
+ ASSERT_EQ(clk.get(3), 2U);
}
TEST(Clock, ChunkedBasic) {
- ScopedInRtl in_rtl;
- ThreadClock vector;
+ ThreadClock vector(0);
SyncClock chunked;
- CHECK_EQ(vector.size(), 0);
- CHECK_EQ(chunked.size(), 0);
- vector.acquire(&chunked);
- CHECK_EQ(vector.size(), 0);
- CHECK_EQ(chunked.size(), 0);
- vector.release(&chunked);
- CHECK_EQ(vector.size(), 0);
- CHECK_EQ(chunked.size(), 0);
- vector.acq_rel(&chunked);
- CHECK_EQ(vector.size(), 0);
- CHECK_EQ(chunked.size(), 0);
+ ASSERT_EQ(vector.size(), 1U);
+ ASSERT_EQ(chunked.size(), 0U);
+ vector.acquire(&cache, &chunked);
+ ASSERT_EQ(vector.size(), 1U);
+ ASSERT_EQ(chunked.size(), 0U);
+ vector.release(&cache, &chunked);
+ ASSERT_EQ(vector.size(), 1U);
+ ASSERT_EQ(chunked.size(), 1U);
+ vector.acq_rel(&cache, &chunked);
+ ASSERT_EQ(vector.size(), 1U);
+ ASSERT_EQ(chunked.size(), 1U);
+ chunked.Reset(&cache);
}
TEST(Clock, AcquireRelease) {
- ScopedInRtl in_rtl;
- ThreadClock vector1;
- vector1.tick(100);
+ ThreadClock vector1(100);
+ vector1.tick();
SyncClock chunked;
- vector1.release(&chunked);
- CHECK_EQ(chunked.size(), 101);
- ThreadClock vector2;
- vector2.acquire(&chunked);
- CHECK_EQ(vector2.size(), 101);
- CHECK_EQ(vector2.get(0), 0);
- CHECK_EQ(vector2.get(1), 0);
- CHECK_EQ(vector2.get(99), 0);
- CHECK_EQ(vector2.get(100), 1);
+ vector1.release(&cache, &chunked);
+ ASSERT_EQ(chunked.size(), 101U);
+ ThreadClock vector2(0);
+ vector2.acquire(&cache, &chunked);
+ ASSERT_EQ(vector2.size(), 101U);
+ ASSERT_EQ(vector2.get(0), 0U);
+ ASSERT_EQ(vector2.get(1), 0U);
+ ASSERT_EQ(vector2.get(99), 0U);
+ ASSERT_EQ(vector2.get(100), 1U);
+ chunked.Reset(&cache);
+}
+
+TEST(Clock, RepeatedAcquire) {
+ ThreadClock thr1(1);
+ thr1.tick();
+ ThreadClock thr2(2);
+ thr2.tick();
+
+ SyncClock sync;
+ thr1.ReleaseStore(&cache, &sync);
+
+ thr2.acquire(&cache, &sync);
+ thr2.acquire(&cache, &sync);
+
+ sync.Reset(&cache);
}
TEST(Clock, ManyThreads) {
- ScopedInRtl in_rtl;
SyncClock chunked;
- for (int i = 0; i < 100; i++) {
- ThreadClock vector;
- vector.tick(i);
- vector.release(&chunked);
- CHECK_EQ(chunked.size(), i + 1);
- vector.acquire(&chunked);
- CHECK_EQ(vector.size(), i + 1);
- }
- ThreadClock vector;
- vector.acquire(&chunked);
- CHECK_EQ(vector.size(), 100);
- for (int i = 0; i < 100; i++)
- CHECK_EQ(vector.get(i), 1);
+ for (unsigned i = 0; i < 100; i++) {
+ ThreadClock vector(0);
+ vector.tick();
+ vector.set(i, 1);
+ vector.release(&cache, &chunked);
+ ASSERT_EQ(i + 1, chunked.size());
+ vector.acquire(&cache, &chunked);
+ ASSERT_EQ(i + 1, vector.size());
+ }
+
+ for (unsigned i = 0; i < 100; i++)
+ ASSERT_EQ(1U, chunked.get(i));
+
+ ThreadClock vector(1);
+ vector.acquire(&cache, &chunked);
+ ASSERT_EQ(100U, vector.size());
+ for (unsigned i = 0; i < 100; i++)
+ ASSERT_EQ(1U, vector.get(i));
+
+ chunked.Reset(&cache);
}
TEST(Clock, DifferentSizes) {
- ScopedInRtl in_rtl;
{
- ThreadClock vector1;
- vector1.tick(10);
- ThreadClock vector2;
- vector2.tick(20);
+ ThreadClock vector1(10);
+ vector1.tick();
+ ThreadClock vector2(20);
+ vector2.tick();
{
SyncClock chunked;
- vector1.release(&chunked);
- CHECK_EQ(chunked.size(), 11);
- vector2.release(&chunked);
- CHECK_EQ(chunked.size(), 21);
+ vector1.release(&cache, &chunked);
+ ASSERT_EQ(chunked.size(), 11U);
+ vector2.release(&cache, &chunked);
+ ASSERT_EQ(chunked.size(), 21U);
+ chunked.Reset(&cache);
}
{
SyncClock chunked;
- vector2.release(&chunked);
- CHECK_EQ(chunked.size(), 21);
- vector1.release(&chunked);
- CHECK_EQ(chunked.size(), 21);
+ vector2.release(&cache, &chunked);
+ ASSERT_EQ(chunked.size(), 21U);
+ vector1.release(&cache, &chunked);
+ ASSERT_EQ(chunked.size(), 21U);
+ chunked.Reset(&cache);
}
{
SyncClock chunked;
- vector1.release(&chunked);
- vector2.acquire(&chunked);
- CHECK_EQ(vector2.size(), 21);
+ vector1.release(&cache, &chunked);
+ vector2.acquire(&cache, &chunked);
+ ASSERT_EQ(vector2.size(), 21U);
+ chunked.Reset(&cache);
}
{
SyncClock chunked;
- vector2.release(&chunked);
- vector1.acquire(&chunked);
- CHECK_EQ(vector1.size(), 21);
+ vector2.release(&cache, &chunked);
+ vector1.acquire(&cache, &chunked);
+ ASSERT_EQ(vector1.size(), 21U);
+ chunked.Reset(&cache);
+ }
+ }
+}
+
+TEST(Clock, Growth) {
+ {
+ ThreadClock vector(10);
+ vector.tick();
+ vector.set(5, 42);
+ SyncClock sync;
+ vector.release(&cache, &sync);
+ ASSERT_EQ(sync.size(), 11U);
+ ASSERT_EQ(sync.get(0), 0ULL);
+ ASSERT_EQ(sync.get(1), 0ULL);
+ ASSERT_EQ(sync.get(5), 42ULL);
+ ASSERT_EQ(sync.get(9), 0ULL);
+ ASSERT_EQ(sync.get(10), 1ULL);
+ sync.Reset(&cache);
+ }
+ {
+ ThreadClock vector1(10);
+ vector1.tick();
+ ThreadClock vector2(20);
+ vector2.tick();
+ SyncClock sync;
+ vector1.release(&cache, &sync);
+ vector2.release(&cache, &sync);
+ ASSERT_EQ(sync.size(), 21U);
+ ASSERT_EQ(sync.get(0), 0ULL);
+ ASSERT_EQ(sync.get(10), 1ULL);
+ ASSERT_EQ(sync.get(19), 0ULL);
+ ASSERT_EQ(sync.get(20), 1ULL);
+ sync.Reset(&cache);
+ }
+ {
+ ThreadClock vector(100);
+ vector.tick();
+ vector.set(5, 42);
+ vector.set(90, 84);
+ SyncClock sync;
+ vector.release(&cache, &sync);
+ ASSERT_EQ(sync.size(), 101U);
+ ASSERT_EQ(sync.get(0), 0ULL);
+ ASSERT_EQ(sync.get(1), 0ULL);
+ ASSERT_EQ(sync.get(5), 42ULL);
+ ASSERT_EQ(sync.get(60), 0ULL);
+ ASSERT_EQ(sync.get(70), 0ULL);
+ ASSERT_EQ(sync.get(90), 84ULL);
+ ASSERT_EQ(sync.get(99), 0ULL);
+ ASSERT_EQ(sync.get(100), 1ULL);
+ sync.Reset(&cache);
+ }
+ {
+ ThreadClock vector1(10);
+ vector1.tick();
+ ThreadClock vector2(100);
+ vector2.tick();
+ SyncClock sync;
+ vector1.release(&cache, &sync);
+ vector2.release(&cache, &sync);
+ ASSERT_EQ(sync.size(), 101U);
+ ASSERT_EQ(sync.get(0), 0ULL);
+ ASSERT_EQ(sync.get(10), 1ULL);
+ ASSERT_EQ(sync.get(99), 0ULL);
+ ASSERT_EQ(sync.get(100), 1ULL);
+ sync.Reset(&cache);
+ }
+}
+
+const int kThreads = 4;
+const int kClocks = 4;
+
+// SimpleSyncClock and SimpleThreadClock implement the same thing as
+// SyncClock and ThreadClock, but in a very simple way.
+struct SimpleSyncClock {
+ u64 clock[kThreads];
+ uptr size;
+
+ SimpleSyncClock() {
+ Reset();
+ }
+
+ void Reset() {
+ size = 0;
+ for (uptr i = 0; i < kThreads; i++)
+ clock[i] = 0;
+ }
+
+ bool verify(const SyncClock *other) const {
+ for (uptr i = 0; i < min(size, other->size()); i++) {
+ if (clock[i] != other->get(i))
+ return false;
+ }
+ for (uptr i = min(size, other->size()); i < max(size, other->size()); i++) {
+ if (i < size && clock[i] != 0)
+ return false;
+ if (i < other->size() && other->get(i) != 0)
+ return false;
+ }
+ return true;
+ }
+};
+
+struct SimpleThreadClock {
+ u64 clock[kThreads];
+ uptr size;
+ unsigned tid;
+
+ explicit SimpleThreadClock(unsigned tid) {
+ this->tid = tid;
+ size = tid + 1;
+ for (uptr i = 0; i < kThreads; i++)
+ clock[i] = 0;
+ }
+
+ void tick() {
+ clock[tid]++;
+ }
+
+ void acquire(const SimpleSyncClock *src) {
+ if (size < src->size)
+ size = src->size;
+ for (uptr i = 0; i < kThreads; i++)
+ clock[i] = max(clock[i], src->clock[i]);
+ }
+
+ void release(SimpleSyncClock *dst) const {
+ if (dst->size < size)
+ dst->size = size;
+ for (uptr i = 0; i < kThreads; i++)
+ dst->clock[i] = max(dst->clock[i], clock[i]);
+ }
+
+ void acq_rel(SimpleSyncClock *dst) {
+ acquire(dst);
+ release(dst);
+ }
+
+ void ReleaseStore(SimpleSyncClock *dst) const {
+ if (dst->size < size)
+ dst->size = size;
+ for (uptr i = 0; i < kThreads; i++)
+ dst->clock[i] = clock[i];
+ }
+
+ bool verify(const ThreadClock *other) const {
+ for (uptr i = 0; i < min(size, other->size()); i++) {
+ if (clock[i] != other->get(i))
+ return false;
+ }
+ for (uptr i = min(size, other->size()); i < max(size, other->size()); i++) {
+ if (i < size && clock[i] != 0)
+ return false;
+ if (i < other->size() && other->get(i) != 0)
+ return false;
}
+ return true;
+ }
+};
+
+static bool ClockFuzzer(bool printing) {
+ // Create kThreads thread clocks.
+ SimpleThreadClock *thr0[kThreads];
+ ThreadClock *thr1[kThreads];
+ unsigned reused[kThreads];
+ for (unsigned i = 0; i < kThreads; i++) {
+ reused[i] = 0;
+ thr0[i] = new SimpleThreadClock(i);
+ thr1[i] = new ThreadClock(i, reused[i]);
+ }
+
+ // Create kClocks sync clocks.
+ SimpleSyncClock *sync0[kClocks];
+ SyncClock *sync1[kClocks];
+ for (unsigned i = 0; i < kClocks; i++) {
+ sync0[i] = new SimpleSyncClock();
+ sync1[i] = new SyncClock();
+ }
+
+ // Do N random operations (acquire, release, etc) and compare results
+ // for SimpleThread/SyncClock and real Thread/SyncClock.
+ for (int i = 0; i < 10000; i++) {
+ unsigned tid = rand() % kThreads;
+ unsigned cid = rand() % kClocks;
+ thr0[tid]->tick();
+ thr1[tid]->tick();
+
+ switch (rand() % 6) {
+ case 0:
+ if (printing)
+ printf("acquire thr%d <- clk%d\n", tid, cid);
+ thr0[tid]->acquire(sync0[cid]);
+ thr1[tid]->acquire(&cache, sync1[cid]);
+ break;
+ case 1:
+ if (printing)
+ printf("release thr%d -> clk%d\n", tid, cid);
+ thr0[tid]->release(sync0[cid]);
+ thr1[tid]->release(&cache, sync1[cid]);
+ break;
+ case 2:
+ if (printing)
+ printf("acq_rel thr%d <> clk%d\n", tid, cid);
+ thr0[tid]->acq_rel(sync0[cid]);
+ thr1[tid]->acq_rel(&cache, sync1[cid]);
+ break;
+ case 3:
+ if (printing)
+ printf("rel_str thr%d >> clk%d\n", tid, cid);
+ thr0[tid]->ReleaseStore(sync0[cid]);
+ thr1[tid]->ReleaseStore(&cache, sync1[cid]);
+ break;
+ case 4:
+ if (printing)
+ printf("reset clk%d\n", cid);
+ sync0[cid]->Reset();
+ sync1[cid]->Reset(&cache);
+ break;
+ case 5:
+ if (printing)
+ printf("reset thr%d\n", tid);
+ u64 epoch = thr0[tid]->clock[tid] + 1;
+ reused[tid]++;
+ delete thr0[tid];
+ thr0[tid] = new SimpleThreadClock(tid);
+ thr0[tid]->clock[tid] = epoch;
+ delete thr1[tid];
+ thr1[tid] = new ThreadClock(tid, reused[tid]);
+ thr1[tid]->set(epoch);
+ break;
+ }
+
+ if (printing) {
+ for (unsigned i = 0; i < kThreads; i++) {
+ printf("thr%d: ", i);
+ thr1[i]->DebugDump(printf);
+ printf("\n");
+ }
+ for (unsigned i = 0; i < kClocks; i++) {
+ printf("clk%d: ", i);
+ sync1[i]->DebugDump(printf);
+ printf("\n");
+ }
+
+ printf("\n");
+ }
+
+ if (!thr0[tid]->verify(thr1[tid]) || !sync0[cid]->verify(sync1[cid])) {
+ if (!printing)
+ return false;
+ printf("differs with model:\n");
+ for (unsigned i = 0; i < kThreads; i++) {
+ printf("thr%d: clock=[", i);
+ for (uptr j = 0; j < thr0[i]->size; j++)
+ printf("%s%llu", j == 0 ? "" : ",", thr0[i]->clock[j]);
+ printf("]\n");
+ }
+ for (unsigned i = 0; i < kClocks; i++) {
+ printf("clk%d: clock=[", i);
+ for (uptr j = 0; j < sync0[i]->size; j++)
+ printf("%s%llu", j == 0 ? "" : ",", sync0[i]->clock[j]);
+ printf("]\n");
+ }
+ return false;
+ }
+ }
+
+ for (unsigned i = 0; i < kClocks; i++) {
+ sync1[i]->Reset(&cache);
+ }
+ return true;
+}
+
+TEST(Clock, Fuzzer) {
+ timespec ts;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ int seed = ts.tv_sec + ts.tv_nsec;
+ printf("seed=%d\n", seed);
+ srand(seed);
+ if (!ClockFuzzer(false)) {
+ // Redo the test with the same seed, but logging operations.
+ srand(seed);
+ ClockFuzzer(true);
+ ASSERT_TRUE(false);
}
}
diff --git a/lib/tsan/tests/unit/tsan_dense_alloc_test.cc b/lib/tsan/tests/unit/tsan_dense_alloc_test.cc
new file mode 100644
index 000000000000..e848e48c6641
--- /dev/null
+++ b/lib/tsan/tests/unit/tsan_dense_alloc_test.cc
@@ -0,0 +1,55 @@
+//===-- tsan_dense_alloc_test.cc ------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+#include "tsan_dense_alloc.h"
+#include "tsan_rtl.h"
+#include "tsan_mman.h"
+#include "gtest/gtest.h"
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <map>
+
+namespace __tsan {
+
+TEST(DenseSlabAlloc, Basic) {
+ typedef DenseSlabAlloc<int, 128, 128> Alloc;
+ typedef Alloc::Cache Cache;
+ typedef Alloc::IndexT IndexT;
+ const int N = 1000;
+
+ Alloc alloc;
+ Cache cache;
+ alloc.InitCache(&cache);
+
+ IndexT blocks[N];
+ for (int ntry = 0; ntry < 3; ntry++) {
+ for (int i = 0; i < N; i++) {
+ IndexT idx = alloc.Alloc(&cache);
+ blocks[i] = idx;
+ EXPECT_NE(idx, 0U);
+ int *v = alloc.Map(idx);
+ *v = i;
+ }
+
+ for (int i = 0; i < N; i++) {
+ IndexT idx = blocks[i];
+ int *v = alloc.Map(idx);
+ EXPECT_EQ(*v, i);
+ alloc.Free(&cache, idx);
+ }
+
+ alloc.FlushCache(&cache);
+ }
+}
+
+} // namespace __tsan
diff --git a/lib/tsan/tests/unit/tsan_flags_test.cc b/lib/tsan/tests/unit/tsan_flags_test.cc
index ffb9c55b605f..22610c0dc42f 100644
--- a/lib/tsan/tests/unit/tsan_flags_test.cc
+++ b/lib/tsan/tests/unit/tsan_flags_test.cc
@@ -13,11 +13,11 @@
#include "tsan_flags.h"
#include "tsan_rtl.h"
#include "gtest/gtest.h"
+#include <string>
namespace __tsan {
TEST(Flags, Basic) {
- ScopedInRtl in_rtl;
// At least should not crash.
Flags f;
InitializeFlags(&f, 0);
@@ -25,7 +25,6 @@ TEST(Flags, Basic) {
}
TEST(Flags, DefaultValues) {
- ScopedInRtl in_rtl;
Flags f;
f.enable_annotations = false;
@@ -35,4 +34,147 @@ TEST(Flags, DefaultValues) {
EXPECT_EQ(true, f.enable_annotations);
}
+static const char *options1 =
+ " enable_annotations=0"
+ " suppress_equal_stacks=0"
+ " suppress_equal_addresses=0"
+ " report_bugs=0"
+ " report_thread_leaks=0"
+ " report_destroy_locked=0"
+ " report_mutex_bugs=0"
+ " report_signal_unsafe=0"
+ " report_atomic_races=0"
+ " force_seq_cst_atomics=0"
+ " print_benign=0"
+ " exitcode=111"
+ " halt_on_error=0"
+ " atexit_sleep_ms=222"
+ " profile_memory=qqq"
+ " flush_memory_ms=444"
+ " flush_symbolizer_ms=555"
+ " memory_limit_mb=666"
+ " stop_on_start=0"
+ " running_on_valgrind=0"
+ " history_size=5"
+ " io_sync=1"
+ " die_after_fork=true"
+ "";
+
+static const char *options2 =
+ " enable_annotations=true"
+ " suppress_equal_stacks=true"
+ " suppress_equal_addresses=true"
+ " report_bugs=true"
+ " report_thread_leaks=true"
+ " report_destroy_locked=true"
+ " report_mutex_bugs=true"
+ " report_signal_unsafe=true"
+ " report_atomic_races=true"
+ " force_seq_cst_atomics=true"
+ " print_benign=true"
+ " exitcode=222"
+ " halt_on_error=true"
+ " atexit_sleep_ms=123"
+ " profile_memory=bbbbb"
+ " flush_memory_ms=234"
+ " flush_symbolizer_ms=345"
+ " memory_limit_mb=456"
+ " stop_on_start=true"
+ " running_on_valgrind=true"
+ " history_size=6"
+ " io_sync=2"
+ " die_after_fork=false"
+ "";
+
+void VerifyOptions1(Flags *f) {
+ EXPECT_EQ(f->enable_annotations, 0);
+ EXPECT_EQ(f->suppress_equal_stacks, 0);
+ EXPECT_EQ(f->suppress_equal_addresses, 0);
+ EXPECT_EQ(f->report_bugs, 0);
+ EXPECT_EQ(f->report_thread_leaks, 0);
+ EXPECT_EQ(f->report_destroy_locked, 0);
+ EXPECT_EQ(f->report_mutex_bugs, 0);
+ EXPECT_EQ(f->report_signal_unsafe, 0);
+ EXPECT_EQ(f->report_atomic_races, 0);
+ EXPECT_EQ(f->force_seq_cst_atomics, 0);
+ EXPECT_EQ(f->print_benign, 0);
+ EXPECT_EQ(f->exitcode, 111);
+ EXPECT_EQ(f->halt_on_error, 0);
+ EXPECT_EQ(f->atexit_sleep_ms, 222);
+ EXPECT_EQ(f->profile_memory, std::string("qqq"));
+ EXPECT_EQ(f->flush_memory_ms, 444);
+ EXPECT_EQ(f->flush_symbolizer_ms, 555);
+ EXPECT_EQ(f->memory_limit_mb, 666);
+ EXPECT_EQ(f->stop_on_start, 0);
+ EXPECT_EQ(f->running_on_valgrind, 0);
+ EXPECT_EQ(f->history_size, 5);
+ EXPECT_EQ(f->io_sync, 1);
+ EXPECT_EQ(f->die_after_fork, true);
+}
+
+void VerifyOptions2(Flags *f) {
+ EXPECT_EQ(f->enable_annotations, true);
+ EXPECT_EQ(f->suppress_equal_stacks, true);
+ EXPECT_EQ(f->suppress_equal_addresses, true);
+ EXPECT_EQ(f->report_bugs, true);
+ EXPECT_EQ(f->report_thread_leaks, true);
+ EXPECT_EQ(f->report_destroy_locked, true);
+ EXPECT_EQ(f->report_mutex_bugs, true);
+ EXPECT_EQ(f->report_signal_unsafe, true);
+ EXPECT_EQ(f->report_atomic_races, true);
+ EXPECT_EQ(f->force_seq_cst_atomics, true);
+ EXPECT_EQ(f->print_benign, true);
+ EXPECT_EQ(f->exitcode, 222);
+ EXPECT_EQ(f->halt_on_error, true);
+ EXPECT_EQ(f->atexit_sleep_ms, 123);
+ EXPECT_EQ(f->profile_memory, std::string("bbbbb"));
+ EXPECT_EQ(f->flush_memory_ms, 234);
+ EXPECT_EQ(f->flush_symbolizer_ms, 345);
+ EXPECT_EQ(f->memory_limit_mb, 456);
+ EXPECT_EQ(f->stop_on_start, true);
+ EXPECT_EQ(f->running_on_valgrind, true);
+ EXPECT_EQ(f->history_size, 6);
+ EXPECT_EQ(f->io_sync, 2);
+ EXPECT_EQ(f->die_after_fork, false);
+}
+
+static const char *test_default_options;
+extern "C" const char *__tsan_default_options() {
+ return test_default_options;
+}
+
+TEST(Flags, ParseDefaultOptions) {
+ Flags f;
+
+ test_default_options = options1;
+ InitializeFlags(&f, "");
+ VerifyOptions1(&f);
+
+ test_default_options = options2;
+ InitializeFlags(&f, "");
+ VerifyOptions2(&f);
+}
+
+TEST(Flags, ParseEnvOptions) {
+ Flags f;
+
+ InitializeFlags(&f, options1);
+ VerifyOptions1(&f);
+
+ InitializeFlags(&f, options2);
+ VerifyOptions2(&f);
+}
+
+TEST(Flags, ParsePriority) {
+ Flags f;
+
+ test_default_options = options2;
+ InitializeFlags(&f, options1);
+ VerifyOptions1(&f);
+
+ test_default_options = options1;
+ InitializeFlags(&f, options2);
+ VerifyOptions2(&f);
+}
+
} // namespace __tsan
diff --git a/lib/tsan/tests/unit/tsan_mman_test.cc b/lib/tsan/tests/unit/tsan_mman_test.cc
index e1ad7ac51ad6..d969989df768 100644
--- a/lib/tsan/tests/unit/tsan_mman_test.cc
+++ b/lib/tsan/tests/unit/tsan_mman_test.cc
@@ -11,24 +11,14 @@
//
//===----------------------------------------------------------------------===//
#include <limits>
+#include <sanitizer/allocator_interface.h>
#include "tsan_mman.h"
#include "tsan_rtl.h"
#include "gtest/gtest.h"
-extern "C" {
-uptr __tsan_get_current_allocated_bytes();
-uptr __tsan_get_heap_size();
-uptr __tsan_get_free_bytes();
-uptr __tsan_get_unmapped_bytes();
-uptr __tsan_get_estimated_allocated_size(uptr size);
-bool __tsan_get_ownership(void *p);
-uptr __tsan_get_allocated_size(void *p);
-}
-
namespace __tsan {
TEST(Mman, Internal) {
- ScopedInRtl in_rtl;
char *p = (char*)internal_alloc(MBlockScopedBuf, 10);
EXPECT_NE(p, (char*)0);
char *p2 = (char*)internal_alloc(MBlockScopedBuf, 20);
@@ -45,7 +35,6 @@ TEST(Mman, Internal) {
}
TEST(Mman, User) {
- ScopedInRtl in_rtl;
ThreadState *thr = cur_thread();
uptr pc = 0;
char *p = (char*)user_alloc(thr, pc, 10);
@@ -53,26 +42,13 @@ TEST(Mman, User) {
char *p2 = (char*)user_alloc(thr, pc, 20);
EXPECT_NE(p2, (char*)0);
EXPECT_NE(p2, p);
- MBlock *b = user_mblock(thr, p);
- EXPECT_NE(b, (MBlock*)0);
- EXPECT_EQ(b->Size(), (uptr)10);
- MBlock *b2 = user_mblock(thr, p2);
- EXPECT_NE(b2, (MBlock*)0);
- EXPECT_EQ(b2->Size(), (uptr)20);
- for (int i = 0; i < 10; i++) {
- p[i] = 42;
- EXPECT_EQ(b, user_mblock(thr, p + i));
- }
- for (int i = 0; i < 20; i++) {
- ((char*)p2)[i] = 42;
- EXPECT_EQ(b2, user_mblock(thr, p2 + i));
- }
+ EXPECT_EQ(10U, user_alloc_usable_size(p));
+ EXPECT_EQ(20U, user_alloc_usable_size(p2));
user_free(thr, pc, p);
user_free(thr, pc, p2);
}
TEST(Mman, UserRealloc) {
- ScopedInRtl in_rtl;
ThreadState *thr = cur_thread();
uptr pc = 0;
{
@@ -118,49 +94,53 @@ TEST(Mman, UserRealloc) {
}
TEST(Mman, UsableSize) {
- ScopedInRtl in_rtl;
ThreadState *thr = cur_thread();
uptr pc = 0;
char *p = (char*)user_alloc(thr, pc, 10);
char *p2 = (char*)user_alloc(thr, pc, 20);
- EXPECT_EQ(0U, user_alloc_usable_size(thr, pc, NULL));
- EXPECT_EQ(10U, user_alloc_usable_size(thr, pc, p));
- EXPECT_EQ(20U, user_alloc_usable_size(thr, pc, p2));
+ EXPECT_EQ(0U, user_alloc_usable_size(NULL));
+ EXPECT_EQ(10U, user_alloc_usable_size(p));
+ EXPECT_EQ(20U, user_alloc_usable_size(p2));
user_free(thr, pc, p);
user_free(thr, pc, p2);
+ EXPECT_EQ(0U, user_alloc_usable_size((void*)0x4123));
}
TEST(Mman, Stats) {
- ScopedInRtl in_rtl;
ThreadState *thr = cur_thread();
- uptr alloc0 = __tsan_get_current_allocated_bytes();
- uptr heap0 = __tsan_get_heap_size();
- uptr free0 = __tsan_get_free_bytes();
- uptr unmapped0 = __tsan_get_unmapped_bytes();
+ uptr alloc0 = __sanitizer_get_current_allocated_bytes();
+ uptr heap0 = __sanitizer_get_heap_size();
+ uptr free0 = __sanitizer_get_free_bytes();
+ uptr unmapped0 = __sanitizer_get_unmapped_bytes();
- EXPECT_EQ(__tsan_get_estimated_allocated_size(10), (uptr)10);
- EXPECT_EQ(__tsan_get_estimated_allocated_size(20), (uptr)20);
- EXPECT_EQ(__tsan_get_estimated_allocated_size(100), (uptr)100);
+ EXPECT_EQ(10U, __sanitizer_get_estimated_allocated_size(10));
+ EXPECT_EQ(20U, __sanitizer_get_estimated_allocated_size(20));
+ EXPECT_EQ(100U, __sanitizer_get_estimated_allocated_size(100));
char *p = (char*)user_alloc(thr, 0, 10);
- EXPECT_EQ(__tsan_get_ownership(p), true);
- EXPECT_EQ(__tsan_get_allocated_size(p), (uptr)10);
+ EXPECT_TRUE(__sanitizer_get_ownership(p));
+ EXPECT_EQ(10U, __sanitizer_get_allocated_size(p));
- EXPECT_EQ(__tsan_get_current_allocated_bytes(), alloc0 + 16);
- EXPECT_GE(__tsan_get_heap_size(), heap0);
- EXPECT_EQ(__tsan_get_free_bytes(), free0);
- EXPECT_EQ(__tsan_get_unmapped_bytes(), unmapped0);
+ EXPECT_EQ(alloc0 + 16, __sanitizer_get_current_allocated_bytes());
+ EXPECT_GE(__sanitizer_get_heap_size(), heap0);
+ EXPECT_EQ(free0, __sanitizer_get_free_bytes());
+ EXPECT_EQ(unmapped0, __sanitizer_get_unmapped_bytes());
user_free(thr, 0, p);
- EXPECT_EQ(__tsan_get_current_allocated_bytes(), alloc0);
- EXPECT_GE(__tsan_get_heap_size(), heap0);
- EXPECT_EQ(__tsan_get_free_bytes(), free0);
- EXPECT_EQ(__tsan_get_unmapped_bytes(), unmapped0);
+ EXPECT_EQ(alloc0, __sanitizer_get_current_allocated_bytes());
+ EXPECT_GE(__sanitizer_get_heap_size(), heap0);
+ EXPECT_EQ(free0, __sanitizer_get_free_bytes());
+ EXPECT_EQ(unmapped0, __sanitizer_get_unmapped_bytes());
}
TEST(Mman, CallocOverflow) {
+#if TSAN_DEBUG
+ // EXPECT_DEATH clones a thread with 4K stack,
+ // which is overflown by tsan memory accesses functions in debug mode.
+ return;
+#endif
size_t kArraySize = 4096;
volatile size_t kMaxSizeT = std::numeric_limits<size_t>::max();
volatile size_t kArraySize2 = kMaxSizeT / kArraySize + 10;
diff --git a/lib/tsan/tests/unit/tsan_stack_test.cc b/lib/tsan/tests/unit/tsan_stack_test.cc
index 9aa2967628cf..92e035d8d000 100644
--- a/lib/tsan/tests/unit/tsan_stack_test.cc
+++ b/lib/tsan/tests/unit/tsan_stack_test.cc
@@ -17,73 +17,79 @@
namespace __tsan {
-static void TestStackTrace(StackTrace *trace) {
- ThreadState thr(0, 0, 0, 0, 0, 0, 0, 0);
+template <typename StackTraceTy>
+static void TestStackTrace(StackTraceTy *trace) {
+ ThreadState thr(0, 0, 0, 0, 0, 0, 0, 0, 0);
uptr stack[128];
thr.shadow_stack = &stack[0];
thr.shadow_stack_pos = &stack[0];
thr.shadow_stack_end = &stack[128];
- trace->ObtainCurrent(&thr, 0);
- EXPECT_EQ(trace->Size(), (uptr)0);
+ ObtainCurrentStack(&thr, 0, trace);
+ EXPECT_EQ(0U, trace->size);
- trace->ObtainCurrent(&thr, 42);
- EXPECT_EQ(trace->Size(), (uptr)1);
- EXPECT_EQ(trace->Get(0), (uptr)42);
+ ObtainCurrentStack(&thr, 42, trace);
+ EXPECT_EQ(1U, trace->size);
+ EXPECT_EQ(42U, trace->trace[0]);
*thr.shadow_stack_pos++ = 100;
*thr.shadow_stack_pos++ = 101;
- trace->ObtainCurrent(&thr, 0);
- EXPECT_EQ(trace->Size(), (uptr)2);
- EXPECT_EQ(trace->Get(0), (uptr)100);
- EXPECT_EQ(trace->Get(1), (uptr)101);
+ ObtainCurrentStack(&thr, 0, trace);
+ EXPECT_EQ(2U, trace->size);
+ EXPECT_EQ(100U, trace->trace[0]);
+ EXPECT_EQ(101U, trace->trace[1]);
- trace->ObtainCurrent(&thr, 42);
- EXPECT_EQ(trace->Size(), (uptr)3);
- EXPECT_EQ(trace->Get(0), (uptr)100);
- EXPECT_EQ(trace->Get(1), (uptr)101);
- EXPECT_EQ(trace->Get(2), (uptr)42);
+ ObtainCurrentStack(&thr, 42, trace);
+ EXPECT_EQ(3U, trace->size);
+ EXPECT_EQ(100U, trace->trace[0]);
+ EXPECT_EQ(101U, trace->trace[1]);
+ EXPECT_EQ(42U, trace->trace[2]);
}
-TEST(StackTrace, Basic) {
- ScopedInRtl in_rtl;
- StackTrace trace;
- TestStackTrace(&trace);
-}
+template<typename StackTraceTy>
+static void TestTrim(StackTraceTy *trace) {
+ ThreadState thr(0, 0, 0, 0, 0, 0, 0, 0, 0);
+ const uptr kShadowStackSize = 2 * kStackTraceMax;
+ uptr stack[kShadowStackSize];
+ thr.shadow_stack = &stack[0];
+ thr.shadow_stack_pos = &stack[0];
+ thr.shadow_stack_end = &stack[kShadowStackSize];
-TEST(StackTrace, StaticBasic) {
- ScopedInRtl in_rtl;
- uptr buf[10];
- StackTrace trace1(buf, 10);
- TestStackTrace(&trace1);
- StackTrace trace2(buf, 3);
- TestStackTrace(&trace2);
-}
+ for (uptr i = 0; i < kShadowStackSize; ++i)
+ *thr.shadow_stack_pos++ = 100 + i;
-TEST(StackTrace, StaticTrim) {
- ScopedInRtl in_rtl;
- uptr buf[2];
- StackTrace trace(buf, 2);
+ ObtainCurrentStack(&thr, 0, trace);
+ EXPECT_EQ(kStackTraceMax, trace->size);
+ for (uptr i = 0; i < kStackTraceMax; i++) {
+ EXPECT_EQ(100 + kStackTraceMax + i, trace->trace[i]);
+ }
- ThreadState thr(0, 0, 0, 0, 0, 0, 0, 0);
- uptr stack[128];
- thr.shadow_stack = &stack[0];
- thr.shadow_stack_pos = &stack[0];
- thr.shadow_stack_end = &stack[128];
+ ObtainCurrentStack(&thr, 42, trace);
+ EXPECT_EQ(kStackTraceMax, trace->size);
+ for (uptr i = 0; i < kStackTraceMax - 1; i++) {
+ EXPECT_EQ(101 + kStackTraceMax + i, trace->trace[i]);
+ }
+ EXPECT_EQ(42U, trace->trace[kStackTraceMax - 1]);
+}
- *thr.shadow_stack_pos++ = 100;
- *thr.shadow_stack_pos++ = 101;
- *thr.shadow_stack_pos++ = 102;
- trace.ObtainCurrent(&thr, 0);
- EXPECT_EQ(trace.Size(), (uptr)2);
- EXPECT_EQ(trace.Get(0), (uptr)101);
- EXPECT_EQ(trace.Get(1), (uptr)102);
+TEST(StackTrace, BasicVarSize) {
+ VarSizeStackTrace trace;
+ TestStackTrace(&trace);
+}
- trace.ObtainCurrent(&thr, 42);
- EXPECT_EQ(trace.Size(), (uptr)2);
- EXPECT_EQ(trace.Get(0), (uptr)102);
- EXPECT_EQ(trace.Get(1), (uptr)42);
+TEST(StackTrace, BasicBuffered) {
+ BufferedStackTrace trace;
+ TestStackTrace(&trace);
+}
+
+TEST(StackTrace, TrimVarSize) {
+ VarSizeStackTrace trace;
+ TestTrim(&trace);
}
+TEST(StackTrace, TrimBuffered) {
+ BufferedStackTrace trace;
+ TestTrim(&trace);
+}
} // namespace __tsan
diff --git a/lib/tsan/tests/unit/tsan_sync_test.cc b/lib/tsan/tests/unit/tsan_sync_test.cc
index dddf0b290883..d3616a1a4b81 100644
--- a/lib/tsan/tests/unit/tsan_sync_test.cc
+++ b/lib/tsan/tests/unit/tsan_sync_test.cc
@@ -12,54 +12,112 @@
//===----------------------------------------------------------------------===//
#include "tsan_sync.h"
#include "tsan_rtl.h"
-#include "tsan_mman.h"
#include "gtest/gtest.h"
-#include <stdlib.h>
-#include <stdint.h>
-#include <map>
-
namespace __tsan {
-TEST(Sync, Table) {
- const uintptr_t kIters = 512*1024;
- const uintptr_t kRange = 10000;
+TEST(MetaMap, Basic) {
+ ThreadState *thr = cur_thread();
+ MetaMap *m = &ctx->metamap;
+ u64 block[1] = {}; // fake malloc block
+ m->AllocBlock(thr, 0, (uptr)&block[0], 1 * sizeof(u64));
+ MBlock *mb = m->GetBlock((uptr)&block[0]);
+ EXPECT_NE(mb, (MBlock*)0);
+ EXPECT_EQ(mb->siz, 1 * sizeof(u64));
+ EXPECT_EQ(mb->tid, thr->tid);
+ uptr sz = m->FreeBlock(thr, 0, (uptr)&block[0]);
+ EXPECT_EQ(sz, 1 * sizeof(u64));
+ mb = m->GetBlock((uptr)&block[0]);
+ EXPECT_EQ(mb, (MBlock*)0);
+}
- ScopedInRtl in_rtl;
+TEST(MetaMap, FreeRange) {
ThreadState *thr = cur_thread();
- uptr pc = 0;
+ MetaMap *m = &ctx->metamap;
+ u64 block[4] = {}; // fake malloc block
+ m->AllocBlock(thr, 0, (uptr)&block[0], 1 * sizeof(u64));
+ m->AllocBlock(thr, 0, (uptr)&block[1], 3 * sizeof(u64));
+ MBlock *mb1 = m->GetBlock((uptr)&block[0]);
+ EXPECT_EQ(mb1->siz, 1 * sizeof(u64));
+ MBlock *mb2 = m->GetBlock((uptr)&block[1]);
+ EXPECT_EQ(mb2->siz, 3 * sizeof(u64));
+ m->FreeRange(thr, 0, (uptr)&block[0], 4 * sizeof(u64));
+ mb1 = m->GetBlock((uptr)&block[0]);
+ EXPECT_EQ(mb1, (MBlock*)0);
+ mb2 = m->GetBlock((uptr)&block[1]);
+ EXPECT_EQ(mb2, (MBlock*)0);
+}
- SyncTab tab;
- SyncVar *golden[kRange] = {};
- unsigned seed = 0;
- for (uintptr_t i = 0; i < kIters; i++) {
- uintptr_t addr = rand_r(&seed) % (kRange - 1) + 1;
- if (rand_r(&seed) % 2) {
- // Get or add.
- SyncVar *v = tab.GetOrCreateAndLock(thr, pc, addr, true);
- EXPECT_TRUE(golden[addr] == 0 || golden[addr] == v);
- EXPECT_EQ(v->addr, addr);
- golden[addr] = v;
- v->mtx.Unlock();
- } else {
- // Remove.
- SyncVar *v = tab.GetAndRemove(thr, pc, addr);
- EXPECT_EQ(golden[addr], v);
- if (v) {
- EXPECT_EQ(v->addr, addr);
- golden[addr] = 0;
- DestroyAndFree(v);
- }
- }
- }
- for (uintptr_t addr = 0; addr < kRange; addr++) {
- if (golden[addr] == 0)
- continue;
- SyncVar *v = tab.GetAndRemove(thr, pc, addr);
- EXPECT_EQ(v, golden[addr]);
- EXPECT_EQ(v->addr, addr);
- DestroyAndFree(v);
- }
+TEST(MetaMap, Sync) {
+ ThreadState *thr = cur_thread();
+ MetaMap *m = &ctx->metamap;
+ u64 block[4] = {}; // fake malloc block
+ m->AllocBlock(thr, 0, (uptr)&block[0], 4 * sizeof(u64));
+ SyncVar *s1 = m->GetIfExistsAndLock((uptr)&block[0]);
+ EXPECT_EQ(s1, (SyncVar*)0);
+ s1 = m->GetOrCreateAndLock(thr, 0, (uptr)&block[0], true);
+ EXPECT_NE(s1, (SyncVar*)0);
+ EXPECT_EQ(s1->addr, (uptr)&block[0]);
+ s1->mtx.Unlock();
+ SyncVar *s2 = m->GetOrCreateAndLock(thr, 0, (uptr)&block[1], false);
+ EXPECT_NE(s2, (SyncVar*)0);
+ EXPECT_EQ(s2->addr, (uptr)&block[1]);
+ s2->mtx.ReadUnlock();
+ m->FreeBlock(thr, 0, (uptr)&block[0]);
+ s1 = m->GetIfExistsAndLock((uptr)&block[0]);
+ EXPECT_EQ(s1, (SyncVar*)0);
+ s2 = m->GetIfExistsAndLock((uptr)&block[1]);
+ EXPECT_EQ(s2, (SyncVar*)0);
+ m->OnThreadIdle(thr);
+}
+
+TEST(MetaMap, MoveMemory) {
+ ThreadState *thr = cur_thread();
+ MetaMap *m = &ctx->metamap;
+ u64 block1[4] = {}; // fake malloc block
+ u64 block2[4] = {}; // fake malloc block
+ m->AllocBlock(thr, 0, (uptr)&block1[0], 3 * sizeof(u64));
+ m->AllocBlock(thr, 0, (uptr)&block1[3], 1 * sizeof(u64));
+ SyncVar *s1 = m->GetOrCreateAndLock(thr, 0, (uptr)&block1[0], true);
+ s1->mtx.Unlock();
+ SyncVar *s2 = m->GetOrCreateAndLock(thr, 0, (uptr)&block1[1], true);
+ s2->mtx.Unlock();
+ m->MoveMemory((uptr)&block1[0], (uptr)&block2[0], 4 * sizeof(u64));
+ MBlock *mb1 = m->GetBlock((uptr)&block1[0]);
+ EXPECT_EQ(mb1, (MBlock*)0);
+ MBlock *mb2 = m->GetBlock((uptr)&block1[3]);
+ EXPECT_EQ(mb2, (MBlock*)0);
+ mb1 = m->GetBlock((uptr)&block2[0]);
+ EXPECT_NE(mb1, (MBlock*)0);
+ EXPECT_EQ(mb1->siz, 3 * sizeof(u64));
+ mb2 = m->GetBlock((uptr)&block2[3]);
+ EXPECT_NE(mb2, (MBlock*)0);
+ EXPECT_EQ(mb2->siz, 1 * sizeof(u64));
+ s1 = m->GetIfExistsAndLock((uptr)&block1[0]);
+ EXPECT_EQ(s1, (SyncVar*)0);
+ s2 = m->GetIfExistsAndLock((uptr)&block1[1]);
+ EXPECT_EQ(s2, (SyncVar*)0);
+ s1 = m->GetIfExistsAndLock((uptr)&block2[0]);
+ EXPECT_NE(s1, (SyncVar*)0);
+ EXPECT_EQ(s1->addr, (uptr)&block2[0]);
+ s1->mtx.Unlock();
+ s2 = m->GetIfExistsAndLock((uptr)&block2[1]);
+ EXPECT_NE(s2, (SyncVar*)0);
+ EXPECT_EQ(s2->addr, (uptr)&block2[1]);
+ s2->mtx.Unlock();
+ m->FreeRange(thr, 0, (uptr)&block2[0], 4 * sizeof(u64));
+}
+
+TEST(MetaMap, ResetSync) {
+ ThreadState *thr = cur_thread();
+ MetaMap *m = &ctx->metamap;
+ u64 block[1] = {}; // fake malloc block
+ m->AllocBlock(thr, 0, (uptr)&block[0], 1 * sizeof(u64));
+ SyncVar *s = m->GetOrCreateAndLock(thr, 0, (uptr)&block[0], true);
+ s->Reset(thr);
+ s->mtx.Unlock();
+ uptr sz = m->FreeBlock(thr, 0, (uptr)&block[0]);
+ EXPECT_EQ(sz, 1 * sizeof(u64));
}
} // namespace __tsan
diff --git a/lib/tsan/tests/unit/tsan_vector_test.cc b/lib/tsan/tests/unit/tsan_vector_test.cc
index cfef6e528ff2..c54ac1ee6de9 100644
--- a/lib/tsan/tests/unit/tsan_vector_test.cc
+++ b/lib/tsan/tests/unit/tsan_vector_test.cc
@@ -17,7 +17,6 @@
namespace __tsan {
TEST(Vector, Basic) {
- ScopedInRtl in_rtl;
Vector<int> v(MBlockScopedBuf);
EXPECT_EQ(v.Size(), (uptr)0);
v.PushBack(42);
@@ -30,7 +29,6 @@ TEST(Vector, Basic) {
}
TEST(Vector, Stride) {
- ScopedInRtl in_rtl;
Vector<int> v(MBlockScopedBuf);
for (int i = 0; i < 1000; i++) {
v.PushBack(i);
diff --git a/lib/ubsan/CMakeLists.txt b/lib/ubsan/CMakeLists.txt
index 675c47f6a65e..09c7a851e075 100644
--- a/lib/ubsan/CMakeLists.txt
+++ b/lib/ubsan/CMakeLists.txt
@@ -2,6 +2,8 @@
set(UBSAN_SOURCES
ubsan_diag.cc
+ ubsan_init.cc
+ ubsan_flags.cc
ubsan_handlers.cc
ubsan_value.cc
)
@@ -14,11 +16,10 @@ set(UBSAN_CXX_SOURCES
include_directories(..)
set(UBSAN_CFLAGS ${SANITIZER_COMMON_CFLAGS})
+append_no_rtti_flag(UBSAN_CFLAGS)
+set(UBSAN_CXXFLAGS ${SANITIZER_COMMON_CFLAGS})
-filter_available_targets(UBSAN_SUPPORTED_ARCH
- x86_64 i386)
-
-set(UBSAN_RUNTIME_LIBRARIES)
+add_custom_target(ubsan)
if(APPLE)
# Build universal binary on APPLE.
@@ -26,31 +27,31 @@ if(APPLE)
ARCH ${UBSAN_SUPPORTED_ARCH}
SOURCES ${UBSAN_SOURCES} ${UBSAN_CXX_SOURCES}
$<TARGET_OBJECTS:RTSanitizerCommon.osx>
- CFLAGS ${UBSAN_CFLAGS})
- list(APPEND UBSAN_RUNTIME_LIBRARIES clang_rt.ubsan_osx)
+ CFLAGS ${UBSAN_CXXFLAGS})
+ add_dependencies(ubsan clang_rt.ubsan_osx)
else()
# Build separate libraries for each target.
foreach(arch ${UBSAN_SUPPORTED_ARCH})
# Main UBSan runtime.
- add_compiler_rt_static_runtime(clang_rt.ubsan-${arch} ${arch}
+ add_compiler_rt_runtime(clang_rt.ubsan-${arch} ${arch} STATIC
SOURCES ${UBSAN_SOURCES}
CFLAGS ${UBSAN_CFLAGS})
# C++-specific parts of UBSan runtime. Requires a C++ ABI library.
- add_compiler_rt_static_runtime(clang_rt.ubsan_cxx-${arch} ${arch}
+ add_compiler_rt_runtime(clang_rt.ubsan_cxx-${arch} ${arch} STATIC
SOURCES ${UBSAN_CXX_SOURCES}
- CFLAGS ${UBSAN_CFLAGS})
- list(APPEND UBSAN_RUNTIME_LIBRARIES
+ CFLAGS ${UBSAN_CXXFLAGS})
+ add_dependencies(ubsan
clang_rt.san-${arch}
clang_rt.ubsan-${arch}
clang_rt.ubsan_cxx-${arch})
- if (UNIX AND NOT ${arch} STREQUAL "i386")
+ if (UNIX AND NOT ${arch} STREQUAL "i386" AND NOT ${arch} STREQUAL "i686")
add_sanitizer_rt_symbols(clang_rt.ubsan-${arch} ubsan.syms.extra)
add_sanitizer_rt_symbols(clang_rt.ubsan_cxx-${arch} ubsan.syms.extra)
- list(APPEND UBSAN_RUNTIME_LIBRARIES
+ add_dependencies(ubsan
clang_rt.ubsan-${arch}-symbols
clang_rt.ubsan_cxx-${arch}-symbols)
endif()
endforeach()
endif()
-add_subdirectory(lit_tests)
+add_dependencies(compiler-rt ubsan)
diff --git a/lib/ubsan/lit_tests/AsanConfig/lit.cfg b/lib/ubsan/lit_tests/AsanConfig/lit.cfg
deleted file mode 100644
index 407e5ec32e60..000000000000
--- a/lib/ubsan/lit_tests/AsanConfig/lit.cfg
+++ /dev/null
@@ -1,25 +0,0 @@
-# -*- Python -*-
-
-import os
-
-def get_required_attr(config, attr_name):
- attr_value = getattr(config, attr_name, None)
- if not attr_value:
- lit_config.fatal(
- "No attribute %r in test configuration! You may need to run "
- "tests from your build directory or add this attribute "
- "to lit.site.cfg " % attr_name)
- return attr_value
-
-ubsan_lit_tests_dir = get_required_attr(config, "ubsan_lit_tests_dir")
-ubsan_lit_cfg = os.path.join(ubsan_lit_tests_dir, "lit.common.cfg")
-lit_config.load_config(config, ubsan_lit_cfg)
-
-config.name = 'UndefinedBehaviorSanitizer-AddressSanitizer'
-
-# Define %clang and %clangxx substitutions to use in test RUN lines.
-config.substitutions.append( ("%clang ", (" " + config.clang +
- " -fsanitize=address ")) )
-config.substitutions.append( ("%clangxx ", (" " + config.clang +
- " -fsanitize=address" +
- " --driver-mode=g++ ")) )
diff --git a/lib/ubsan/lit_tests/AsanConfig/lit.site.cfg.in b/lib/ubsan/lit_tests/AsanConfig/lit.site.cfg.in
deleted file mode 100644
index f75741838f83..000000000000
--- a/lib/ubsan/lit_tests/AsanConfig/lit.site.cfg.in
+++ /dev/null
@@ -1,9 +0,0 @@
-# Load common config for all compiler-rt lit tests.
-lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/lib/lit.common.configured")
-
-# Tool-specific config options.
-config.ubsan_lit_tests_dir = "@UBSAN_LIT_TESTS_DIR@"
-
-# Load tool-specific config that would do the real work.
-print config.ubsan_lit_tests_dir
-lit_config.load_config(config, "@UBSAN_LIT_TESTS_DIR@/AsanConfig/lit.cfg")
diff --git a/lib/ubsan/lit_tests/CMakeLists.txt b/lib/ubsan/lit_tests/CMakeLists.txt
deleted file mode 100644
index 36d8dc1f9205..000000000000
--- a/lib/ubsan/lit_tests/CMakeLists.txt
+++ /dev/null
@@ -1,23 +0,0 @@
-set(UBSAN_LIT_TESTS_DIR ${CMAKE_CURRENT_SOURCE_DIR})
-
-configure_lit_site_cfg(
- ${CMAKE_CURRENT_SOURCE_DIR}/UbsanConfig/lit.site.cfg.in
- ${CMAKE_CURRENT_BINARY_DIR}/UbsanConfig/lit.site.cfg)
-
-configure_lit_site_cfg(
- ${CMAKE_CURRENT_SOURCE_DIR}/AsanConfig/lit.site.cfg.in
- ${CMAKE_CURRENT_BINARY_DIR}/AsanConfig/lit.site.cfg)
-
-if(COMPILER_RT_CAN_EXECUTE_TESTS)
- # Run UBSan output tests only if we're sure that clang would produce
- # working binaries.
- set(UBSAN_TEST_DEPS
- ${SANITIZER_COMMON_LIT_TEST_DEPS}
- ${UBSAN_RUNTIME_LIBRARIES}
- asan_runtime_libraries)
- add_lit_testsuite(check-ubsan "Running UndefinedBehaviorSanitizer tests"
- ${CMAKE_CURRENT_BINARY_DIR}/UbsanConfig
- ${CMAKE_CURRENT_BINARY_DIR}/AsanConfig
- DEPENDS ${UBSAN_TEST_DEPS})
- set_target_properties(check-ubsan PROPERTIES FOLDER "UBSan unittests")
-endif()
diff --git a/lib/ubsan/lit_tests/TestCases/Float/cast-overflow.cpp b/lib/ubsan/lit_tests/TestCases/Float/cast-overflow.cpp
deleted file mode 100644
index 35f9336c904a..000000000000
--- a/lib/ubsan/lit_tests/TestCases/Float/cast-overflow.cpp
+++ /dev/null
@@ -1,99 +0,0 @@
-// RUN: %clangxx -fsanitize=float-cast-overflow %s -o %t
-// RUN: %t _
-// RUN: %t 0 2>&1 | FileCheck %s --check-prefix=CHECK-0
-// RUN: %t 1 2>&1 | FileCheck %s --check-prefix=CHECK-1
-// RUN: %t 2 2>&1 | FileCheck %s --check-prefix=CHECK-2
-// RUN: %t 3 2>&1 | FileCheck %s --check-prefix=CHECK-3
-// RUN: %t 4 2>&1 | FileCheck %s --check-prefix=CHECK-4
-// RUN: %t 5 2>&1 | FileCheck %s --check-prefix=CHECK-5
-// RUN: %t 6 2>&1 | FileCheck %s --check-prefix=CHECK-6
-// FIXME: %t 7 2>&1 | FileCheck %s --check-prefix=CHECK-7
-// RUN: %t 8 2>&1 | FileCheck %s --check-prefix=CHECK-8
-
-// This test assumes float and double are IEEE-754 single- and double-precision.
-
-#include <stdint.h>
-#include <stdio.h>
-#include <string.h>
-
-float Inf;
-float NaN;
-
-int main(int argc, char **argv) {
- float MaxFloatRepresentableAsInt = 0x7fffff80;
- (int)MaxFloatRepresentableAsInt; // ok
- (int)-MaxFloatRepresentableAsInt; // ok
-
- float MinFloatRepresentableAsInt = -0x7fffffff - 1;
- (int)MinFloatRepresentableAsInt; // ok
-
- float MaxFloatRepresentableAsUInt = 0xffffff00u;
- (unsigned int)MaxFloatRepresentableAsUInt; // ok
-
-#ifdef __SIZEOF_INT128__
- unsigned __int128 FloatMaxAsUInt128 = -((unsigned __int128)1 << 104);
- (void)(float)FloatMaxAsUInt128; // ok
-#endif
-
- float NearlyMinusOne = -0.99999;
- unsigned Zero = NearlyMinusOne; // ok
-
- // Build a '+Inf'.
- char InfVal[] = { 0x00, 0x00, 0x80, 0x7f };
- float Inf;
- memcpy(&Inf, InfVal, 4);
-
- // Build a 'NaN'.
- char NaNVal[] = { 0x01, 0x00, 0x80, 0x7f };
- float NaN;
- memcpy(&NaN, NaNVal, 4);
-
- double DblInf = (double)Inf; // ok
-
- switch (argv[1][0]) {
- // FIXME: Produce a source location for these checks and test for it here.
-
- // Floating point -> integer overflow.
- case '0':
- // Note that values between 0x7ffffe00 and 0x80000000 may or may not
- // successfully round-trip, depending on the rounding mode.
- // CHECK-0: runtime error: value 2.14748{{.*}} is outside the range of representable values of type 'int'
- return MaxFloatRepresentableAsInt + 0x80;
- case '1':
- // CHECK-1: runtime error: value -2.14748{{.*}} is outside the range of representable values of type 'int'
- return MinFloatRepresentableAsInt - 0x100;
- case '2':
- // CHECK-2: runtime error: value -1 is outside the range of representable values of type 'unsigned int'
- return (unsigned)-1.0;
- case '3':
- // CHECK-3: runtime error: value 4.2949{{.*}} is outside the range of representable values of type 'unsigned int'
- return (unsigned)(MaxFloatRepresentableAsUInt + 0x100);
-
- case '4':
- // CHECK-4: runtime error: value {{.*}} is outside the range of representable values of type 'int'
- return Inf;
- case '5':
- // CHECK-5: runtime error: value {{.*}} is outside the range of representable values of type 'int'
- return NaN;
-
- // Integer -> floating point overflow.
- case '6':
- // CHECK-6: {{runtime error: value 0xffffff00000000000000000000000001 is outside the range of representable values of type 'float'|__int128 not supported}}
-#ifdef __SIZEOF_INT128__
- return (float)(FloatMaxAsUInt128 + 1);
-#else
- puts("__int128 not supported");
- return 0;
-#endif
- // FIXME: The backend cannot lower __fp16 operations on x86 yet.
- //case '7':
- // (__fp16)65504; // ok
- // // CHECK-7: runtime error: value 65505 is outside the range of representable values of type '__fp16'
- // return (__fp16)65505;
-
- // Floating point -> floating point overflow.
- case '8':
- // CHECK-8: runtime error: value 1e+39 is outside the range of representable values of type 'float'
- return (float)1e39;
- }
-}
diff --git a/lib/ubsan/lit_tests/TestCases/Integer/add-overflow.cpp b/lib/ubsan/lit_tests/TestCases/Integer/add-overflow.cpp
deleted file mode 100644
index 412eb7621033..000000000000
--- a/lib/ubsan/lit_tests/TestCases/Integer/add-overflow.cpp
+++ /dev/null
@@ -1,32 +0,0 @@
-// RUN: %clangxx -DADD_I32 -fsanitize=signed-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=CHECK-ADD_I32
-// RUN: %clangxx -DADD_I64 -fsanitize=signed-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=CHECK-ADD_I64
-// RUN: %clangxx -DADD_I128 -fsanitize=signed-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=CHECK-ADD_I128
-
-#include <stdint.h>
-#include <stdio.h>
-
-int main() {
- // These promote to 'int'.
- (void)(int8_t(0x7f) + int8_t(0x7f));
- (void)(int16_t(0x3fff) + int16_t(0x4000));
-
-#ifdef ADD_I32
- int32_t k = 0x12345678;
- k += 0x789abcde;
- // CHECK-ADD_I32: add-overflow.cpp:[[@LINE-1]]:5: runtime error: signed integer overflow: 305419896 + 2023406814 cannot be represented in type 'int'
-#endif
-
-#ifdef ADD_I64
- (void)(int64_t(8000000000000000000ll) + int64_t(2000000000000000000ll));
- // CHECK-ADD_I64: 8000000000000000000 + 2000000000000000000 cannot be represented in type '{{long( long)?}}'
-#endif
-
-#ifdef ADD_I128
-# ifdef __SIZEOF_INT128__
- (void)((__int128_t(1) << 126) + (__int128_t(1) << 126));
-# else
- puts("__int128 not supported");
-# endif
- // CHECK-ADD_I128: {{0x40000000000000000000000000000000 \+ 0x40000000000000000000000000000000 cannot be represented in type '__int128'|__int128 not supported}}
-#endif
-}
diff --git a/lib/ubsan/lit_tests/TestCases/Integer/div-overflow.cpp b/lib/ubsan/lit_tests/TestCases/Integer/div-overflow.cpp
deleted file mode 100644
index 83aa854485b4..000000000000
--- a/lib/ubsan/lit_tests/TestCases/Integer/div-overflow.cpp
+++ /dev/null
@@ -1,10 +0,0 @@
-// RUN: %clangxx -fsanitize=signed-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s
-
-#include <stdint.h>
-
-int main() {
- unsigned(0x80000000) / -1;
-
- // CHECK: div-overflow.cpp:9:23: runtime error: division of -2147483648 by -1 cannot be represented in type 'int'
- int32_t(0x80000000) / -1;
-}
diff --git a/lib/ubsan/lit_tests/TestCases/Integer/div-zero.cpp b/lib/ubsan/lit_tests/TestCases/Integer/div-zero.cpp
deleted file mode 100644
index 6b8aadfe15e6..000000000000
--- a/lib/ubsan/lit_tests/TestCases/Integer/div-zero.cpp
+++ /dev/null
@@ -1,15 +0,0 @@
-// RUN: %clangxx -fsanitize=integer-divide-by-zero -DDIVIDEND=0 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx -fsanitize=integer-divide-by-zero -DDIVIDEND=1U %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx -fsanitize=float-divide-by-zero -DDIVIDEND=1.5 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx -fsanitize=integer-divide-by-zero -DDIVIDEND='intmax(123)' %s -o %t && %t 2>&1 | FileCheck %s
-
-#ifdef __SIZEOF_INT128__
-typedef __int128 intmax;
-#else
-typedef long long intmax;
-#endif
-
-int main() {
- // CHECK: div-zero.cpp:[[@LINE+1]]:12: runtime error: division by zero
- DIVIDEND / 0;
-}
diff --git a/lib/ubsan/lit_tests/TestCases/Integer/incdec-overflow.cpp b/lib/ubsan/lit_tests/TestCases/Integer/incdec-overflow.cpp
deleted file mode 100644
index 904250a76c79..000000000000
--- a/lib/ubsan/lit_tests/TestCases/Integer/incdec-overflow.cpp
+++ /dev/null
@@ -1,16 +0,0 @@
-// RUN: %clangxx -DOP=n++ -fsanitize=signed-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx -DOP=++n -fsanitize=signed-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx -DOP=m-- -fsanitize=signed-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx -DOP=--m -fsanitize=signed-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s
-
-#include <stdint.h>
-
-int main() {
- int n = 0x7ffffffd;
- n++;
- n++;
- int m = -n - 1;
- // CHECK: incdec-overflow.cpp:15:3: runtime error: signed integer overflow: [[MINUS:-?]]214748364
- // CHECK: + [[MINUS]]1 cannot be represented in type 'int'
- OP;
-}
diff --git a/lib/ubsan/lit_tests/TestCases/Integer/mul-overflow.cpp b/lib/ubsan/lit_tests/TestCases/Integer/mul-overflow.cpp
deleted file mode 100644
index 1cfe23f57213..000000000000
--- a/lib/ubsan/lit_tests/TestCases/Integer/mul-overflow.cpp
+++ /dev/null
@@ -1,14 +0,0 @@
-// RUN: %clangxx -fsanitize=signed-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s
-
-#include <stdint.h>
-
-int main() {
- // These promote to 'int'.
- (void)(int8_t(-2) * int8_t(0x7f));
- (void)(int16_t(0x7fff) * int16_t(0x7fff));
- (void)(uint16_t(0xffff) * int16_t(0x7fff));
- (void)(uint16_t(0xffff) * uint16_t(0x8000));
-
- // CHECK: mul-overflow.cpp:13:27: runtime error: signed integer overflow: 65535 * 32769 cannot be represented in type 'int'
- (void)(uint16_t(0xffff) * uint16_t(0x8001));
-}
diff --git a/lib/ubsan/lit_tests/TestCases/Integer/negate-overflow.cpp b/lib/ubsan/lit_tests/TestCases/Integer/negate-overflow.cpp
deleted file mode 100644
index 6bee3eea2980..000000000000
--- a/lib/ubsan/lit_tests/TestCases/Integer/negate-overflow.cpp
+++ /dev/null
@@ -1,12 +0,0 @@
-// RUN: %clangxx -fsanitize=signed-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=CHECKS
-// RUN: %clangxx -fsanitize=unsigned-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=CHECKU
-
-int main() {
- // CHECKS-NOT: runtime error
- // CHECKU: negate-overflow.cpp:[[@LINE+2]]:3: runtime error: negation of 2147483648 cannot be represented in type 'unsigned int'
- // CHECKU-NOT: cast to an unsigned
- -unsigned(-0x7fffffff - 1); // ok
- // CHECKS: negate-overflow.cpp:[[@LINE+2]]:10: runtime error: negation of -2147483648 cannot be represented in type 'int'; cast to an unsigned type to negate this value to itself
- // CHECKU-NOT: runtime error
- return -(-0x7fffffff - 1);
-}
diff --git a/lib/ubsan/lit_tests/TestCases/Integer/no-recover.cpp b/lib/ubsan/lit_tests/TestCases/Integer/no-recover.cpp
deleted file mode 100644
index 64787b7cfbf5..000000000000
--- a/lib/ubsan/lit_tests/TestCases/Integer/no-recover.cpp
+++ /dev/null
@@ -1,22 +0,0 @@
-// RUN: %clangxx -fsanitize=unsigned-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=RECOVER
-// RUN: %clangxx -fsanitize=unsigned-integer-overflow -fsanitize-recover %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=RECOVER
-// RUN: %clangxx -fsanitize=unsigned-integer-overflow -fno-sanitize-recover %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=ABORT
-
-#include <stdint.h>
-
-int main() {
- // These promote to 'int'.
- (void)(uint8_t(0xff) + uint8_t(0xff));
- (void)(uint16_t(0xf0fff) + uint16_t(0x0fff));
- // RECOVER-NOT: runtime error
- // ABORT-NOT: runtime error
-
- uint32_t k = 0x87654321;
- k += 0xedcba987;
- // RECOVER: no-recover.cpp:[[@LINE-1]]:5: runtime error: unsigned integer overflow: 2271560481 + 3989547399 cannot be represented in type 'unsigned int'
- // ABORT: no-recover.cpp:[[@LINE-2]]:5: runtime error: unsigned integer overflow: 2271560481 + 3989547399 cannot be represented in type 'unsigned int'
-
- (void)(uint64_t(10000000000000000000ull) + uint64_t(9000000000000000000ull));
- // RECOVER: 10000000000000000000 + 9000000000000000000 cannot be represented in type 'unsigned {{long( long)?}}'
- // ABORT-NOT: runtime error
-}
diff --git a/lib/ubsan/lit_tests/TestCases/Integer/shift.cpp b/lib/ubsan/lit_tests/TestCases/Integer/shift.cpp
deleted file mode 100644
index f35fa1f959ae..000000000000
--- a/lib/ubsan/lit_tests/TestCases/Integer/shift.cpp
+++ /dev/null
@@ -1,37 +0,0 @@
-// RUN: %clangxx -DLSH_OVERFLOW -DOP='<<' -fsanitize=shift %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=CHECK-LSH_OVERFLOW
-// RUN: %clangxx -DLSH_OVERFLOW -DOP='<<=' -fsanitize=shift %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=CHECK-LSH_OVERFLOW
-// RUN: %clangxx -DTOO_LOW -DOP='<<' -fsanitize=shift %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=CHECK-TOO_LOW
-// RUN: %clangxx -DTOO_LOW -DOP='>>' -fsanitize=shift %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=CHECK-TOO_LOW
-// RUN: %clangxx -DTOO_LOW -DOP='<<=' -fsanitize=shift %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=CHECK-TOO_LOW
-// RUN: %clangxx -DTOO_LOW -DOP='>>=' -fsanitize=shift %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=CHECK-TOO_LOW
-// RUN: %clangxx -DTOO_HIGH -DOP='<<' -fsanitize=shift %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=CHECK-TOO_HIGH
-// RUN: %clangxx -DTOO_HIGH -DOP='>>' -fsanitize=shift %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=CHECK-TOO_HIGH
-// RUN: %clangxx -DTOO_HIGH -DOP='<<=' -fsanitize=shift %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=CHECK-TOO_HIGH
-// RUN: %clangxx -DTOO_HIGH -DOP='>>=' -fsanitize=shift %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=CHECK-TOO_HIGH
-
-#include <stdint.h>
-
-int main() {
- int a = 1;
- unsigned b = 1;
-
- a <<= 31; // ok in C++11, not ok in C99/C11
- b <<= 31; // ok
- b <<= 1; // still ok, unsigned
-
-#ifdef LSH_OVERFLOW
- // CHECK-LSH_OVERFLOW: shift.cpp:24:5: runtime error: left shift of negative value -2147483648
- a OP 1;
-#endif
-
-#ifdef TOO_LOW
- // CHECK-TOO_LOW: shift.cpp:29:5: runtime error: shift exponent -3 is negative
- a OP (-3);
-#endif
-
-#ifdef TOO_HIGH
- a = 0;
- // CHECK-TOO_HIGH: shift.cpp:35:5: runtime error: shift exponent 32 is too large for 32-bit type 'int'
- a OP 32;
-#endif
-}
diff --git a/lib/ubsan/lit_tests/TestCases/Integer/sub-overflow.cpp b/lib/ubsan/lit_tests/TestCases/Integer/sub-overflow.cpp
deleted file mode 100644
index bf33d293799b..000000000000
--- a/lib/ubsan/lit_tests/TestCases/Integer/sub-overflow.cpp
+++ /dev/null
@@ -1,31 +0,0 @@
-// RUN: %clangxx -DSUB_I32 -fsanitize=signed-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=CHECK-SUB_I32
-// RUN: %clangxx -DSUB_I64 -fsanitize=signed-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=CHECK-SUB_I64
-// RUN: %clangxx -DSUB_I128 -fsanitize=signed-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=CHECK-SUB_I128
-
-#include <stdint.h>
-#include <stdio.h>
-
-int main() {
- // These promote to 'int'.
- (void)(int8_t(-2) - int8_t(0x7f));
- (void)(int16_t(-2) - int16_t(0x7fff));
-
-#ifdef SUB_I32
- (void)(int32_t(-2) - int32_t(0x7fffffff));
- // CHECK-SUB_I32: sub-overflow.cpp:[[@LINE-1]]:22: runtime error: signed integer overflow: -2 - 2147483647 cannot be represented in type 'int'
-#endif
-
-#ifdef SUB_I64
- (void)(int64_t(-8000000000000000000ll) - int64_t(2000000000000000000ll));
- // CHECK-SUB_I64: -8000000000000000000 - 2000000000000000000 cannot be represented in type '{{long( long)?}}'
-#endif
-
-#ifdef SUB_I128
-# ifdef __SIZEOF_INT128__
- (void)(-(__int128_t(1) << 126) - (__int128_t(1) << 126) - 1);
-# else
- puts("__int128 not supported");
-# endif
- // CHECK-SUB_I128: {{0x80000000000000000000000000000000 - 1 cannot be represented in type '__int128'|__int128 not supported}}
-#endif
-}
diff --git a/lib/ubsan/lit_tests/TestCases/Integer/uadd-overflow.cpp b/lib/ubsan/lit_tests/TestCases/Integer/uadd-overflow.cpp
deleted file mode 100644
index 2ef31c0640d1..000000000000
--- a/lib/ubsan/lit_tests/TestCases/Integer/uadd-overflow.cpp
+++ /dev/null
@@ -1,32 +0,0 @@
-// RUN: %clangxx -DADD_I32 -fsanitize=unsigned-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=CHECK-ADD_I32
-// RUN: %clangxx -DADD_I64 -fsanitize=unsigned-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=CHECK-ADD_I64
-// RUN: %clangxx -DADD_I128 -fsanitize=unsigned-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=CHECK-ADD_I128
-
-#include <stdint.h>
-#include <stdio.h>
-
-int main() {
- // These promote to 'int'.
- (void)(uint8_t(0xff) + uint8_t(0xff));
- (void)(uint16_t(0xf0fff) + uint16_t(0x0fff));
-
-#ifdef ADD_I32
- uint32_t k = 0x87654321;
- k += 0xedcba987;
- // CHECK-ADD_I32: uadd-overflow.cpp:[[@LINE-1]]:5: runtime error: unsigned integer overflow: 2271560481 + 3989547399 cannot be represented in type 'unsigned int'
-#endif
-
-#ifdef ADD_I64
- (void)(uint64_t(10000000000000000000ull) + uint64_t(9000000000000000000ull));
- // CHECK-ADD_I64: 10000000000000000000 + 9000000000000000000 cannot be represented in type 'unsigned {{long( long)?}}'
-#endif
-
-#ifdef ADD_I128
-# ifdef __SIZEOF_INT128__
- (void)((__uint128_t(1) << 127) + (__uint128_t(1) << 127));
-# else
- puts("__int128 not supported");
-# endif
- // CHECK-ADD_I128: {{0x80000000000000000000000000000000 \+ 0x80000000000000000000000000000000 cannot be represented in type 'unsigned __int128'|__int128 not supported}}
-#endif
-}
diff --git a/lib/ubsan/lit_tests/TestCases/Integer/uincdec-overflow.cpp b/lib/ubsan/lit_tests/TestCases/Integer/uincdec-overflow.cpp
deleted file mode 100644
index a14bd6a776f5..000000000000
--- a/lib/ubsan/lit_tests/TestCases/Integer/uincdec-overflow.cpp
+++ /dev/null
@@ -1,16 +0,0 @@
-// RUN: %clangxx -DOP=n++ -fsanitize=unsigned-integer-overflow %s -o %t && %t 2>&1 | FileCheck --check-prefix=CHECK-INC %s
-// RUN: %clangxx -DOP=++n -fsanitize=unsigned-integer-overflow %s -o %t && %t 2>&1 | FileCheck --check-prefix=CHECK-INC %s
-// RUN: %clangxx -DOP=m-- -fsanitize=unsigned-integer-overflow %s -o %t && %t 2>&1 | FileCheck --check-prefix=CHECK-DEC %s
-// RUN: %clangxx -DOP=--m -fsanitize=unsigned-integer-overflow %s -o %t && %t 2>&1 | FileCheck --check-prefix=CHECK-DEC %s
-
-#include <stdint.h>
-
-int main() {
- unsigned n = 0xfffffffd;
- n++;
- n++;
- unsigned m = 0;
- // CHECK-INC: uincdec-overflow.cpp:15:3: runtime error: unsigned integer overflow: 4294967295 + 1 cannot be represented in type 'unsigned int'
- // CHECK-DEC: uincdec-overflow.cpp:15:3: runtime error: unsigned integer overflow: 0 - 1 cannot be represented in type 'unsigned int'
- OP;
-}
diff --git a/lib/ubsan/lit_tests/TestCases/Integer/umul-overflow.cpp b/lib/ubsan/lit_tests/TestCases/Integer/umul-overflow.cpp
deleted file mode 100644
index c84bb39ef2f7..000000000000
--- a/lib/ubsan/lit_tests/TestCases/Integer/umul-overflow.cpp
+++ /dev/null
@@ -1,19 +0,0 @@
-// RUN: %clangxx -fsanitize=unsigned-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s
-
-#include <stdint.h>
-
-int main() {
- // These promote to 'int'.
- (void)(int8_t(-2) * int8_t(0x7f));
- (void)(int16_t(0x7fff) * int16_t(0x7fff));
- (void)(uint16_t(0xffff) * int16_t(0x7fff));
- (void)(uint16_t(0xffff) * uint16_t(0x8000));
-
- // Not an unsigned overflow
- (void)(uint16_t(0xffff) * uint16_t(0x8001));
-
- (void)(uint32_t(0xffffffff) * uint32_t(0x2));
- // CHECK: umul-overflow.cpp:15:31: runtime error: unsigned integer overflow: 4294967295 * 2 cannot be represented in type 'unsigned int'
-
- return 0;
-}
diff --git a/lib/ubsan/lit_tests/TestCases/Integer/usub-overflow.cpp b/lib/ubsan/lit_tests/TestCases/Integer/usub-overflow.cpp
deleted file mode 100644
index 78f745578583..000000000000
--- a/lib/ubsan/lit_tests/TestCases/Integer/usub-overflow.cpp
+++ /dev/null
@@ -1,31 +0,0 @@
-// RUN: %clangxx -DSUB_I32 -fsanitize=unsigned-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=CHECK-SUB_I32
-// RUN: %clangxx -DSUB_I64 -fsanitize=unsigned-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=CHECK-SUB_I64
-// RUN: %clangxx -DSUB_I128 -fsanitize=unsigned-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=CHECK-SUB_I128
-
-#include <stdint.h>
-#include <stdio.h>
-
-int main() {
- // These promote to 'int'.
- (void)(uint8_t(0) - uint8_t(0x7f));
- (void)(uint16_t(0) - uint16_t(0x7fff));
-
-#ifdef SUB_I32
- (void)(uint32_t(1) - uint32_t(2));
- // CHECK-SUB_I32: usub-overflow.cpp:[[@LINE-1]]:22: runtime error: unsigned integer overflow: 1 - 2 cannot be represented in type 'unsigned int'
-#endif
-
-#ifdef SUB_I64
- (void)(uint64_t(8000000000000000000ll) - uint64_t(9000000000000000000ll));
- // CHECK-SUB_I64: 8000000000000000000 - 9000000000000000000 cannot be represented in type 'unsigned {{long( long)?}}'
-#endif
-
-#ifdef SUB_I128
-# ifdef __SIZEOF_INT128__
- (void)((__uint128_t(1) << 126) - (__uint128_t(1) << 127));
-# else
- puts("__int128 not supported\n");
-# endif
- // CHECK-SUB_I128: {{0x40000000000000000000000000000000 - 0x80000000000000000000000000000000 cannot be represented in type 'unsigned __int128'|__int128 not supported}}
-#endif
-}
diff --git a/lib/ubsan/lit_tests/TestCases/Misc/bool.cpp b/lib/ubsan/lit_tests/TestCases/Misc/bool.cpp
deleted file mode 100644
index e916e7fb3c1d..000000000000
--- a/lib/ubsan/lit_tests/TestCases/Misc/bool.cpp
+++ /dev/null
@@ -1,10 +0,0 @@
-// RUN: %clangxx -fsanitize=bool %s -O3 -o %T/bool.exe && %T/bool.exe 2>&1 | FileCheck %s
-
-unsigned char NotABool = 123;
-
-int main(int argc, char **argv) {
- bool *p = (bool*)&NotABool;
-
- // CHECK: bool.cpp:9:10: runtime error: load of value 123, which is not a valid value for type 'bool'
- return *p;
-}
diff --git a/lib/ubsan/lit_tests/TestCases/Misc/bounds.cpp b/lib/ubsan/lit_tests/TestCases/Misc/bounds.cpp
deleted file mode 100644
index dc4c4a513c1c..000000000000
--- a/lib/ubsan/lit_tests/TestCases/Misc/bounds.cpp
+++ /dev/null
@@ -1,15 +0,0 @@
-// RUN: %clangxx -fsanitize=bounds %s -O3 -o %T/bounds.exe
-// RUN: %T/bounds.exe 0 0 0
-// RUN: %T/bounds.exe 1 2 3
-// RUN: %T/bounds.exe 2 0 0 2>&1 | FileCheck %s --check-prefix=CHECK-A-2
-// RUN: %T/bounds.exe 0 3 0 2>&1 | FileCheck %s --check-prefix=CHECK-B-3
-// RUN: %T/bounds.exe 0 0 4 2>&1 | FileCheck %s --check-prefix=CHECK-C-4
-
-int main(int argc, char **argv) {
- int arr[2][3][4] = {};
-
- return arr[argv[1][0] - '0'][argv[2][0] - '0'][argv[3][0] - '0'];
- // CHECK-A-2: bounds.cpp:11:10: runtime error: index 2 out of bounds for type 'int [2][3][4]'
- // CHECK-B-3: bounds.cpp:11:10: runtime error: index 3 out of bounds for type 'int [3][4]'
- // CHECK-C-4: bounds.cpp:11:10: runtime error: index 4 out of bounds for type 'int [4]'
-}
diff --git a/lib/ubsan/lit_tests/TestCases/Misc/deduplication.cpp b/lib/ubsan/lit_tests/TestCases/Misc/deduplication.cpp
deleted file mode 100644
index d325bf6dd899..000000000000
--- a/lib/ubsan/lit_tests/TestCases/Misc/deduplication.cpp
+++ /dev/null
@@ -1,25 +0,0 @@
-// RUN: %clangxx -fsanitize=undefined %s -o %t && %t 2>&1 | FileCheck %s
-// Verify deduplication works by ensuring only one diag is emitted.
-#include <limits.h>
-#include <stdio.h>
-
-void overflow() {
- int i = INT_MIN;
- --i;
-}
-
-int main() {
- // CHECK: Start
- fprintf(stderr, "Start\n");
-
- // CHECK: runtime error
- // CHECK-NOT: runtime error
- // CHECK-NOT: runtime error
- overflow();
- overflow();
- overflow();
-
- // CHECK: End
- fprintf(stderr, "End\n");
- return 0;
-}
diff --git a/lib/ubsan/lit_tests/TestCases/Misc/enum.cpp b/lib/ubsan/lit_tests/TestCases/Misc/enum.cpp
deleted file mode 100644
index c5642507ad42..000000000000
--- a/lib/ubsan/lit_tests/TestCases/Misc/enum.cpp
+++ /dev/null
@@ -1,17 +0,0 @@
-// RUN: %clangxx -fsanitize=enum %s -O3 -o %t && %t 2>&1 | FileCheck %s --check-prefix=CHECK-PLAIN
-// RUN: %clangxx -fsanitize=enum -std=c++11 -DE="class E" %s -O3 -o %t && %t
-// RUN: %clangxx -fsanitize=enum -std=c++11 -DE="class E : bool" %s -O3 -o %t && %t 2>&1 | FileCheck %s --check-prefix=CHECK-BOOL
-
-enum E { a = 1 } e;
-#undef E
-
-int main(int argc, char **argv) {
- // memset(&e, 0xff, sizeof(e));
- for (unsigned char *p = (unsigned char*)&e; p != (unsigned char*)(&e + 1); ++p)
- *p = 0xff;
-
- // CHECK-PLAIN: error: load of value 4294967295, which is not a valid value for type 'enum E'
- // FIXME: Support marshalling and display of enum class values.
- // CHECK-BOOL: error: load of value <unknown>, which is not a valid value for type 'enum E'
- return (int)e != -1;
-}
diff --git a/lib/ubsan/lit_tests/TestCases/Misc/missing_return.cpp b/lib/ubsan/lit_tests/TestCases/Misc/missing_return.cpp
deleted file mode 100644
index 7da238e25dca..000000000000
--- a/lib/ubsan/lit_tests/TestCases/Misc/missing_return.cpp
+++ /dev/null
@@ -1,9 +0,0 @@
-// RUN: %clangxx -fsanitize=return %s -O3 -o %t && %t 2>&1 | FileCheck %s
-
-// CHECK: missing_return.cpp:4:5: runtime error: execution reached the end of a value-returning function without returning a value
-int f() {
-}
-
-int main(int, char **argv) {
- return f();
-}
diff --git a/lib/ubsan/lit_tests/TestCases/Misc/unreachable.cpp b/lib/ubsan/lit_tests/TestCases/Misc/unreachable.cpp
deleted file mode 100644
index 75fc3e5bd9a6..000000000000
--- a/lib/ubsan/lit_tests/TestCases/Misc/unreachable.cpp
+++ /dev/null
@@ -1,6 +0,0 @@
-// RUN: %clangxx -fsanitize=unreachable %s -O3 -o %t && %t 2>&1 | FileCheck %s
-
-int main(int, char **argv) {
- // CHECK: unreachable.cpp:5:3: runtime error: execution reached a __builtin_unreachable() call
- __builtin_unreachable();
-}
diff --git a/lib/ubsan/lit_tests/TestCases/Misc/vla.c b/lib/ubsan/lit_tests/TestCases/Misc/vla.c
deleted file mode 100644
index 2fa88addc0d3..000000000000
--- a/lib/ubsan/lit_tests/TestCases/Misc/vla.c
+++ /dev/null
@@ -1,11 +0,0 @@
-// RUN: %clang -fsanitize=vla-bound %s -O3 -o %t
-// RUN: %t 2>&1 | FileCheck %s --check-prefix=CHECK-MINUS-ONE
-// RUN: %t a 2>&1 | FileCheck %s --check-prefix=CHECK-ZERO
-// RUN: %t a b
-
-int main(int argc, char **argv) {
- // CHECK-MINUS-ONE: vla.c:9:11: runtime error: variable length array bound evaluates to non-positive value -1
- // CHECK-ZERO: vla.c:9:11: runtime error: variable length array bound evaluates to non-positive value 0
- int arr[argc - 2];
- return 0;
-}
diff --git a/lib/ubsan/lit_tests/TestCases/TypeCheck/Function/function.cpp b/lib/ubsan/lit_tests/TestCases/TypeCheck/Function/function.cpp
deleted file mode 100644
index 8106ae47ee4f..000000000000
--- a/lib/ubsan/lit_tests/TestCases/TypeCheck/Function/function.cpp
+++ /dev/null
@@ -1,17 +0,0 @@
-// RUN: %clangxx -fsanitize=function %s -O3 -g -o %t
-// RUN: %t 2>&1 | FileCheck %s
-
-#include <stdint.h>
-
-void f() {}
-
-void g(int x) {}
-
-int main(void) {
- // CHECK: runtime error: call to function f() through pointer to incorrect function type 'void (*)(int)'
- // CHECK-NEXT: function.cpp:6: note: f() defined here
- reinterpret_cast<void (*)(int)>(reinterpret_cast<uintptr_t>(f))(42);
-
- // CHECK-NOT: runtime error: call to function g
- reinterpret_cast<void (*)(int)>(reinterpret_cast<uintptr_t>(g))(42);
-}
diff --git a/lib/ubsan/lit_tests/TestCases/TypeCheck/Function/lit.local.cfg b/lib/ubsan/lit_tests/TestCases/TypeCheck/Function/lit.local.cfg
deleted file mode 100644
index 27c61a34387c..000000000000
--- a/lib/ubsan/lit_tests/TestCases/TypeCheck/Function/lit.local.cfg
+++ /dev/null
@@ -1,3 +0,0 @@
-# The function type checker is only supported on x86 and x86_64 for now.
-if config.root.host_arch not in ['x86', 'x86_64']:
- config.unsupported = True
diff --git a/lib/ubsan/lit_tests/TestCases/TypeCheck/misaligned.cpp b/lib/ubsan/lit_tests/TestCases/TypeCheck/misaligned.cpp
deleted file mode 100644
index 9b0b9a1197c0..000000000000
--- a/lib/ubsan/lit_tests/TestCases/TypeCheck/misaligned.cpp
+++ /dev/null
@@ -1,73 +0,0 @@
-// RUN: %clangxx -fsanitize=alignment %s -O3 -o %t
-// RUN: %t l0 && %t s0 && %t r0 && %t m0 && %t f0 && %t n0
-// RUN: %t l1 2>&1 | FileCheck %s --check-prefix=CHECK-LOAD --strict-whitespace
-// RUN: %t s1 2>&1 | FileCheck %s --check-prefix=CHECK-STORE
-// RUN: %t r1 2>&1 | FileCheck %s --check-prefix=CHECK-REFERENCE
-// RUN: %t m1 2>&1 | FileCheck %s --check-prefix=CHECK-MEMBER
-// RUN: %t f1 2>&1 | FileCheck %s --check-prefix=CHECK-MEMFUN
-// RUN: %t n1 2>&1 | FileCheck %s --check-prefix=CHECK-NEW
-
-#include <new>
-
-struct S {
- S() {}
- int f() { return 0; }
- int k;
-};
-
-int main(int, char **argv) {
- char c[] __attribute__((aligned(8))) = { 0, 0, 0, 0, 1, 2, 3, 4, 5 };
-
- // Pointer value may be unspecified here, but behavior is not undefined.
- int *p = (int*)&c[4 + argv[1][1] - '0'];
- S *s = (S*)p;
-
- (void)*p; // ok!
-
- switch (argv[1][0]) {
- case 'l':
- // CHECK-LOAD: misaligned.cpp:[[@LINE+4]]:12: runtime error: load of misaligned address [[PTR:0x[0-9a-f]*]] for type 'int', which requires 4 byte alignment
- // CHECK-LOAD-NEXT: [[PTR]]: note: pointer points here
- // CHECK-LOAD-NEXT: {{^ 00 00 00 01 02 03 04 05}}
- // CHECK-LOAD-NEXT: {{^ \^}}
- return *p && 0;
-
- case 's':
- // CHECK-STORE: misaligned.cpp:[[@LINE+4]]:5: runtime error: store to misaligned address [[PTR:0x[0-9a-f]*]] for type 'int', which requires 4 byte alignment
- // CHECK-STORE-NEXT: [[PTR]]: note: pointer points here
- // CHECK-STORE-NEXT: {{^ 00 00 00 01 02 03 04 05}}
- // CHECK-STORE-NEXT: {{^ \^}}
- *p = 1;
- break;
-
- case 'r':
- // CHECK-REFERENCE: misaligned.cpp:[[@LINE+4]]:15: runtime error: reference binding to misaligned address [[PTR:0x[0-9a-f]*]] for type 'int', which requires 4 byte alignment
- // CHECK-REFERENCE-NEXT: [[PTR]]: note: pointer points here
- // CHECK-REFERENCE-NEXT: {{^ 00 00 00 01 02 03 04 05}}
- // CHECK-REFERENCE-NEXT: {{^ \^}}
- {int &r = *p;}
- break;
-
- case 'm':
- // CHECK-MEMBER: misaligned.cpp:[[@LINE+4]]:15: runtime error: member access within misaligned address [[PTR:0x[0-9a-f]*]] for type 'S', which requires 4 byte alignment
- // CHECK-MEMBER-NEXT: [[PTR]]: note: pointer points here
- // CHECK-MEMBER-NEXT: {{^ 00 00 00 01 02 03 04 05}}
- // CHECK-MEMBER-NEXT: {{^ \^}}
- return s->k && 0;
-
- case 'f':
- // CHECK-MEMFUN: misaligned.cpp:[[@LINE+4]]:12: runtime error: member call on misaligned address [[PTR:0x[0-9a-f]*]] for type 'S', which requires 4 byte alignment
- // CHECK-MEMFUN-NEXT: [[PTR]]: note: pointer points here
- // CHECK-MEMFUN-NEXT: {{^ 00 00 00 01 02 03 04 05}}
- // CHECK-MEMFUN-NEXT: {{^ \^}}
- return s->f() && 0;
-
- case 'n':
- // FIXME: Provide a better source location here.
- // CHECK-NEW: misaligned{{.*}}+0x{{[0-9a-f]*}}): runtime error: constructor call on misaligned address [[PTR:0x[0-9a-f]*]] for type 'S', which requires 4 byte alignment
- // CHECK-NEW-NEXT: [[PTR]]: note: pointer points here
- // CHECK-NEW-NEXT: {{^ 00 00 00 01 02 03 04 05}}
- // CHECK-NEW-NEXT: {{^ \^}}
- return (new (s) S)->k && 0;
- }
-}
diff --git a/lib/ubsan/lit_tests/TestCases/TypeCheck/null.cpp b/lib/ubsan/lit_tests/TestCases/TypeCheck/null.cpp
deleted file mode 100644
index 79726924d213..000000000000
--- a/lib/ubsan/lit_tests/TestCases/TypeCheck/null.cpp
+++ /dev/null
@@ -1,38 +0,0 @@
-// RUN: %clangxx -fsanitize=null %s -O3 -o %t
-// RUN: %t l 2>&1 | FileCheck %s --check-prefix=CHECK-LOAD
-// RUN: %t s 2>&1 | FileCheck %s --check-prefix=CHECK-STORE
-// RUN: %t r 2>&1 | FileCheck %s --check-prefix=CHECK-REFERENCE
-// RUN: %t m 2>&1 | FileCheck %s --check-prefix=CHECK-MEMBER
-// RUN: %t f 2>&1 | FileCheck %s --check-prefix=CHECK-MEMFUN
-
-struct S {
- int f() { return 0; }
- int k;
-};
-
-int main(int, char **argv) {
- int *p = 0;
- S *s = 0;
-
- (void)*p; // ok!
-
- switch (argv[1][0]) {
- case 'l':
- // CHECK-LOAD: null.cpp:22:12: runtime error: load of null pointer of type 'int'
- return *p;
- case 's':
- // CHECK-STORE: null.cpp:25:5: runtime error: store to null pointer of type 'int'
- *p = 1;
- break;
- case 'r':
- // CHECK-REFERENCE: null.cpp:29:15: runtime error: reference binding to null pointer of type 'int'
- {int &r = *p;}
- break;
- case 'm':
- // CHECK-MEMBER: null.cpp:33:15: runtime error: member access within null pointer of type 'S'
- return s->k;
- case 'f':
- // CHECK-MEMFUN: null.cpp:36:12: runtime error: member call on null pointer of type 'S'
- return s->f();
- }
-}
diff --git a/lib/ubsan/lit_tests/TestCases/TypeCheck/vptr.cpp b/lib/ubsan/lit_tests/TestCases/TypeCheck/vptr.cpp
deleted file mode 100644
index 9095f7279a66..000000000000
--- a/lib/ubsan/lit_tests/TestCases/TypeCheck/vptr.cpp
+++ /dev/null
@@ -1,117 +0,0 @@
-// RUN: %clangxx -fsanitize=vptr %s -O3 -o %t
-// RUN: %t rT && %t mT && %t fT && %t cT
-// RUN: %t rU && %t mU && %t fU && %t cU
-// RUN: %t rS && %t rV && %t oV
-// RUN: %t mS 2>&1 | FileCheck %s --check-prefix=CHECK-MEMBER --strict-whitespace
-// RUN: %t fS 2>&1 | FileCheck %s --check-prefix=CHECK-MEMFUN --strict-whitespace
-// RUN: %t cS 2>&1 | FileCheck %s --check-prefix=CHECK-DOWNCAST --strict-whitespace
-// RUN: %t mV 2>&1 | FileCheck %s --check-prefix=CHECK-MEMBER --strict-whitespace
-// RUN: %t fV 2>&1 | FileCheck %s --check-prefix=CHECK-MEMFUN --strict-whitespace
-// RUN: %t cV 2>&1 | FileCheck %s --check-prefix=CHECK-DOWNCAST --strict-whitespace
-// RUN: %t oU 2>&1 | FileCheck %s --check-prefix=CHECK-OFFSET --strict-whitespace
-// RUN: %t m0 2>&1 | FileCheck %s --check-prefix=CHECK-NULL-MEMBER --strict-whitespace
-
-// FIXME: This test produces linker errors on Darwin.
-// XFAIL: darwin
-
-struct S {
- S() : a(0) {}
- ~S() {}
- int a;
- int f() { return 0; }
- virtual int v() { return 0; }
-};
-
-struct T : S {
- T() : b(0) {}
- int b;
- int g() { return 0; }
- virtual int v() { return 1; }
-};
-
-struct U : S, T { virtual int v() { return 2; } };
-
-int main(int, char **argv) {
- T t;
- (void)t.a;
- (void)t.b;
- (void)t.f();
- (void)t.g();
- (void)t.v();
- (void)t.S::v();
-
- U u;
- (void)u.T::a;
- (void)u.b;
- (void)u.T::f();
- (void)u.g();
- (void)u.v();
- (void)u.T::v();
- (void)((T&)u).S::v();
-
- T *p = 0;
- char Buffer[sizeof(U)] = {};
- switch (argv[1][1]) {
- case '0':
- p = reinterpret_cast<T*>(Buffer);
- break;
- case 'S':
- p = reinterpret_cast<T*>(new S);
- break;
- case 'T':
- p = new T;
- break;
- case 'U':
- p = new U;
- break;
- case 'V':
- p = reinterpret_cast<T*>(new U);
- break;
- }
-
- switch (argv[1][0]) {
- case 'r':
- // Binding a reference to storage of appropriate size and alignment is OK.
- {T &r = *p;}
- break;
-
- case 'm':
- // CHECK-MEMBER: vptr.cpp:[[@LINE+5]]:15: runtime error: member access within address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'T'
- // CHECK-MEMBER-NEXT: [[PTR]]: note: object is of type [[DYN_TYPE:'S'|'U']]
- // CHECK-MEMBER-NEXT: {{^ .. .. .. .. .. .. .. .. .. .. .. .. }}
- // CHECK-MEMBER-NEXT: {{^ \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}}
- // CHECK-MEMBER-NEXT: {{^ vptr for}} [[DYN_TYPE]]
- return p->b;
-
- // CHECK-NULL-MEMBER: vptr.cpp:[[@LINE-2]]:15: runtime error: member access within address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'T'
- // CHECK-NULL-MEMBER-NEXT: [[PTR]]: note: object has invalid vptr
- // CHECK-NULL-MEMBER-NEXT: {{^ .. .. .. .. 00 00 00 00 00 00 00 00 }}
- // CHECK-NULL-MEMBER-NEXT: {{^ \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}}
- // CHECK-NULL-MEMBER-NEXT: {{^ invalid vptr}}
-
- case 'f':
- // CHECK-MEMFUN: vptr.cpp:[[@LINE+5]]:12: runtime error: member call on address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'T'
- // CHECK-MEMFUN-NEXT: [[PTR]]: note: object is of type [[DYN_TYPE:'S'|'U']]
- // CHECK-MEMFUN-NEXT: {{^ .. .. .. .. .. .. .. .. .. .. .. .. }}
- // CHECK-MEMFUN-NEXT: {{^ \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}}
- // CHECK-MEMFUN-NEXT: {{^ vptr for}} [[DYN_TYPE]]
- return p->g();
-
- case 'o':
- // CHECK-OFFSET: vptr.cpp:[[@LINE+5]]:12: runtime error: member call on address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'U'
- // CHECK-OFFSET-NEXT: 0x{{[0-9a-f]*}}: note: object is base class subobject at offset {{8|16}} within object of type [[DYN_TYPE:'U']]
- // CHECK-OFFSET-NEXT: {{^ .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. }}
- // CHECK-OFFSET-NEXT: {{^ \^ ( ~~~~~~~~~~~~)?~~~~~~~~~~~ *$}}
- // CHECK-OFFSET-NEXT: {{^ ( )?vptr for}} 'T' base class of [[DYN_TYPE]]
- return reinterpret_cast<U*>(p)->v() - 2;
-
- case 'c':
- // CHECK-DOWNCAST: vptr.cpp:[[@LINE+5]]:5: runtime error: downcast of address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'T'
- // CHECK-DOWNCAST-NEXT: [[PTR]]: note: object is of type [[DYN_TYPE:'S'|'U']]
- // CHECK-DOWNCAST-NEXT: {{^ .. .. .. .. .. .. .. .. .. .. .. .. }}
- // CHECK-DOWNCAST-NEXT: {{^ \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}}
- // CHECK-DOWNCAST-NEXT: {{^ vptr for}} [[DYN_TYPE]]
- static_cast<T*>(reinterpret_cast<S*>(p));
- return 0;
- }
-}
diff --git a/lib/ubsan/lit_tests/UbsanConfig/lit.cfg b/lib/ubsan/lit_tests/UbsanConfig/lit.cfg
deleted file mode 100644
index fcc93035c600..000000000000
--- a/lib/ubsan/lit_tests/UbsanConfig/lit.cfg
+++ /dev/null
@@ -1,23 +0,0 @@
-# -*- Python -*-
-
-import os
-
-def get_required_attr(config, attr_name):
- attr_value = getattr(config, attr_name, None)
- if not attr_value:
- lit_config.fatal(
- "No attribute %r in test configuration! You may need to run "
- "tests from your build directory or add this attribute "
- "to lit.site.cfg " % attr_name)
- return attr_value
-
-ubsan_lit_tests_dir = get_required_attr(config, "ubsan_lit_tests_dir")
-ubsan_lit_cfg = os.path.join(ubsan_lit_tests_dir, "lit.common.cfg")
-lit_config.load_config(config, ubsan_lit_cfg)
-
-config.name = 'UndefinedBehaviorSanitizer-Standalone'
-
-# Define %clang and %clangxx substitutions to use in test RUN lines.
-config.substitutions.append( ("%clang ", (" " + config.clang + " ")) )
-config.substitutions.append( ("%clangxx ", (" " + config.clang +
- " --driver-mode=g++ ")) )
diff --git a/lib/ubsan/lit_tests/UbsanConfig/lit.site.cfg.in b/lib/ubsan/lit_tests/UbsanConfig/lit.site.cfg.in
deleted file mode 100644
index c08fc30d0042..000000000000
--- a/lib/ubsan/lit_tests/UbsanConfig/lit.site.cfg.in
+++ /dev/null
@@ -1,8 +0,0 @@
-# Load common config for all compiler-rt lit tests.
-lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/lib/lit.common.configured")
-
-# Tool-specific config options.
-config.ubsan_lit_tests_dir = "@UBSAN_LIT_TESTS_DIR@"
-
-# Load tool-specific config that would do the real work.
-lit_config.load_config(config, "@UBSAN_LIT_TESTS_DIR@/UbsanConfig/lit.cfg")
diff --git a/lib/ubsan/lit_tests/lit.common.cfg b/lib/ubsan/lit_tests/lit.common.cfg
deleted file mode 100644
index 23c85e9fa065..000000000000
--- a/lib/ubsan/lit_tests/lit.common.cfg
+++ /dev/null
@@ -1,31 +0,0 @@
-# -*- Python -*-
-
-import os
-
-def get_required_attr(config, attr_name):
- attr_value = getattr(config, attr_name, None)
- if not attr_value:
- lit_config.fatal(
- "No attribute %r in test configuration! You may need to run "
- "tests from your build directory or add this attribute "
- "to lit.site.cfg " % attr_name)
- return attr_value
-
-# Setup source root.
-ubsan_lit_tests_dir = get_required_attr(config, 'ubsan_lit_tests_dir')
-config.test_source_root = os.path.join(ubsan_lit_tests_dir, 'TestCases')
-
-def DisplayNoConfigMessage():
- lit_config.fatal("No site specific configuration available! " +
- "Try running your test from the build tree or running " +
- "make check-ubsan")
-
-# Default test suffixes.
-config.suffixes = ['.c', '.cc', '.cpp']
-
-# UndefinedBehaviorSanitizer tests are currently supported on
-# Linux and Darwin only.
-if config.host_os not in ['Linux', 'Darwin']:
- config.unsupported = True
-
-config.pipefail = False
diff --git a/lib/ubsan/ubsan_diag.cc b/lib/ubsan/ubsan_diag.cc
index fa643658ea36..76ce2bd39996 100644
--- a/lib/ubsan/ubsan_diag.cc
+++ b/lib/ubsan/ubsan_diag.cc
@@ -12,15 +12,60 @@
//===----------------------------------------------------------------------===//
#include "ubsan_diag.h"
-#include "sanitizer_common/sanitizer_common.h"
-#include "sanitizer_common/sanitizer_libc.h"
+#include "ubsan_init.h"
+#include "ubsan_flags.h"
#include "sanitizer_common/sanitizer_report_decorator.h"
#include "sanitizer_common/sanitizer_stacktrace.h"
+#include "sanitizer_common/sanitizer_stacktrace_printer.h"
#include "sanitizer_common/sanitizer_symbolizer.h"
#include <stdio.h>
using namespace __ubsan;
+static void MaybePrintStackTrace(uptr pc, uptr bp) {
+ // We assume that flags are already parsed: InitIfNecessary
+ // will definitely be called when we print the first diagnostics message.
+ if (!flags()->print_stacktrace)
+ return;
+ // We can only use slow unwind, as we don't have any information about stack
+ // top/bottom.
+ // FIXME: It's better to respect "fast_unwind_on_fatal" runtime flag and
+ // fetch stack top/bottom information if we have it (e.g. if we're running
+ // under ASan).
+ if (StackTrace::WillUseFastUnwind(false))
+ return;
+ BufferedStackTrace stack;
+ stack.Unwind(kStackTraceMax, pc, bp, 0, 0, 0, false);
+ stack.Print();
+}
+
+static void MaybeReportErrorSummary(Location Loc) {
+ if (!common_flags()->print_summary)
+ return;
+ // Don't try to unwind the stack trace in UBSan summaries: just use the
+ // provided location.
+ if (Loc.isSourceLocation()) {
+ SourceLocation SLoc = Loc.getSourceLocation();
+ if (!SLoc.isInvalid()) {
+ ReportErrorSummary("undefined-behavior", SLoc.getFilename(),
+ SLoc.getLine(), "");
+ return;
+ }
+ }
+ ReportErrorSummary("undefined-behavior");
+}
+
+namespace {
+class Decorator : public SanitizerCommonDecorator {
+ public:
+ Decorator() : SanitizerCommonDecorator() {}
+ const char *Highlight() const { return Green(); }
+ const char *EndHighlight() const { return Default(); }
+ const char *Note() const { return Black(); }
+ const char *EndNote() const { return Default(); }
+};
+}
+
Location __ubsan::getCallerLocation(uptr CallerLoc) {
if (!CallerLoc)
return Location();
@@ -32,19 +77,28 @@ Location __ubsan::getCallerLocation(uptr CallerLoc) {
Location __ubsan::getFunctionLocation(uptr Loc, const char **FName) {
if (!Loc)
return Location();
+ InitIfNecessary();
+
+ SymbolizedStack *Frames = Symbolizer::GetOrInit()->SymbolizePC(Loc);
+ const AddressInfo &Info = Frames->info;
- AddressInfo Info;
- if (!Symbolizer::GetOrInit()->SymbolizeCode(Loc, &Info, 1) ||
- !Info.module || !*Info.module)
+ if (!Info.module) {
+ Frames->ClearAll();
return Location(Loc);
+ }
if (FName && Info.function)
- *FName = Info.function;
+ *FName = internal_strdup(Info.function);
- if (!Info.file)
- return ModuleLocation(Info.module, Info.module_offset);
+ if (!Info.file) {
+ ModuleLocation MLoc(internal_strdup(Info.module), Info.module_offset);
+ Frames->ClearAll();
+ return MLoc;
+ }
- return SourceLocation(Info.file, Info.line, Info.column);
+ SourceLocation SLoc(internal_strdup(Info.file), Info.line, Info.column);
+ Frames->ClearAll();
+ return SLoc;
}
Diag &Diag::operator<<(const TypeDescriptor &V) {
@@ -84,14 +138,16 @@ static void renderLocation(Location Loc) {
if (SLoc.isInvalid())
LocBuffer.append("<unknown>");
else
- PrintSourceLocation(&LocBuffer, SLoc.getFilename(), SLoc.getLine(),
- SLoc.getColumn());
+ RenderSourceLocation(&LocBuffer, SLoc.getFilename(), SLoc.getLine(),
+ SLoc.getColumn(), common_flags()->strip_path_prefix);
break;
}
- case Location::LK_Module:
- PrintModuleAndOffset(&LocBuffer, Loc.getModuleLocation().getModuleName(),
- Loc.getModuleLocation().getOffset());
+ case Location::LK_Module: {
+ ModuleLocation MLoc = Loc.getModuleLocation();
+ RenderModuleLocation(&LocBuffer, MLoc.getModuleName(), MLoc.getOffset(),
+ common_flags()->strip_path_prefix);
break;
+ }
case Location::LK_Memory:
LocBuffer.append("%p", Loc.getMemoryLocation());
break;
@@ -164,36 +220,49 @@ static Range *upperBound(MemoryLocation Loc, Range *Ranges,
return Best;
}
+static inline uptr subtractNoOverflow(uptr LHS, uptr RHS) {
+ return (LHS < RHS) ? 0 : LHS - RHS;
+}
+
+static inline uptr addNoOverflow(uptr LHS, uptr RHS) {
+ const uptr Limit = (uptr)-1;
+ return (LHS > Limit - RHS) ? Limit : LHS + RHS;
+}
+
/// Render a snippet of the address space near a location.
-static void renderMemorySnippet(const __sanitizer::AnsiColorDecorator &Decor,
- MemoryLocation Loc,
+static void renderMemorySnippet(const Decorator &Decor, MemoryLocation Loc,
Range *Ranges, unsigned NumRanges,
const Diag::Arg *Args) {
- const unsigned BytesToShow = 32;
- const unsigned MinBytesNearLoc = 4;
-
// Show at least the 8 bytes surrounding Loc.
- MemoryLocation Min = Loc - MinBytesNearLoc, Max = Loc + MinBytesNearLoc;
+ const unsigned MinBytesNearLoc = 4;
+ MemoryLocation Min = subtractNoOverflow(Loc, MinBytesNearLoc);
+ MemoryLocation Max = addNoOverflow(Loc, MinBytesNearLoc);
+ MemoryLocation OrigMin = Min;
for (unsigned I = 0; I < NumRanges; ++I) {
Min = __sanitizer::Min(Ranges[I].getStart().getMemoryLocation(), Min);
Max = __sanitizer::Max(Ranges[I].getEnd().getMemoryLocation(), Max);
}
// If we have too many interesting bytes, prefer to show bytes after Loc.
+ const unsigned BytesToShow = 32;
if (Max - Min > BytesToShow)
- Min = __sanitizer::Min(Max - BytesToShow, Loc - MinBytesNearLoc);
- Max = Min + BytesToShow;
+ Min = __sanitizer::Min(Max - BytesToShow, OrigMin);
+ Max = addNoOverflow(Min, BytesToShow);
+
+ if (!IsAccessibleMemoryRange(Min, Max - Min)) {
+ Printf("<memory cannot be printed>\n");
+ return;
+ }
// Emit data.
for (uptr P = Min; P != Max; ++P) {
- // FIXME: Check that the address is readable before printing it.
unsigned char C = *reinterpret_cast<const unsigned char*>(P);
Printf("%s%02x", (P % 8 == 0) ? " " : " ", C);
}
Printf("\n");
// Emit highlights.
- Printf(Decor.Green());
+ Printf(Decor.Highlight());
Range *InRange = upperBound(Min, Ranges, NumRanges);
for (uptr P = Min; P != Max; ++P) {
char Pad = ' ', Byte = ' ';
@@ -208,7 +277,7 @@ static void renderMemorySnippet(const __sanitizer::AnsiColorDecorator &Decor,
char Buffer[] = { Pad, Pad, P == Loc ? '^' : Byte, Byte, 0 };
Printf((P % 8 == 0) ? Buffer : &Buffer[1]);
}
- Printf("%s\n", Decor.Default());
+ Printf("%s\n", Decor.EndHighlight());
// Go over the line again, and print names for the ranges.
InRange = 0;
@@ -246,8 +315,9 @@ static void renderMemorySnippet(const __sanitizer::AnsiColorDecorator &Decor,
}
Diag::~Diag() {
- __sanitizer::AnsiColorDecorator Decor(PrintsToTty());
- SpinMutexLock l(&CommonSanitizerReportMutex);
+ // All diagnostics should be printed under report mutex.
+ CommonSanitizerReportMutex.CheckLocked();
+ Decorator Decor;
Printf(Decor.Bold());
renderLocation(Loc);
@@ -255,11 +325,11 @@ Diag::~Diag() {
switch (Level) {
case DL_Error:
Printf("%s runtime error: %s%s",
- Decor.Red(), Decor.Default(), Decor.Bold());
+ Decor.Warning(), Decor.EndWarning(), Decor.Bold());
break;
case DL_Note:
- Printf("%s note: %s", Decor.Black(), Decor.Default());
+ Printf("%s note: %s", Decor.Note(), Decor.EndNote());
break;
}
@@ -271,3 +341,26 @@ Diag::~Diag() {
renderMemorySnippet(Decor, Loc.getMemoryLocation(), Ranges,
NumRanges, Args);
}
+
+ScopedReport::ScopedReport(ReportOptions Opts, Location SummaryLoc)
+ : Opts(Opts), SummaryLoc(SummaryLoc) {
+ InitIfNecessary();
+ CommonSanitizerReportMutex.Lock();
+}
+
+ScopedReport::~ScopedReport() {
+ MaybePrintStackTrace(Opts.pc, Opts.bp);
+ MaybeReportErrorSummary(SummaryLoc);
+ CommonSanitizerReportMutex.Unlock();
+ if (Opts.DieAfterReport || flags()->halt_on_error)
+ Die();
+}
+
+bool __ubsan::MatchSuppression(const char *Str, SuppressionType Type) {
+ Suppression *s;
+ // If .preinit_array is not used, it is possible that the UBSan runtime is not
+ // initialized.
+ if (!SANITIZER_CAN_USE_PREINIT_ARRAY)
+ InitIfNecessary();
+ return SuppressionContext::Get()->Match(Str, Type, &s);
+}
diff --git a/lib/ubsan/ubsan_diag.h b/lib/ubsan/ubsan_diag.h
index 54d15a0cc1ba..296ec0d3f61a 100644
--- a/lib/ubsan/ubsan_diag.h
+++ b/lib/ubsan/ubsan_diag.h
@@ -14,6 +14,8 @@
#define UBSAN_DIAG_H
#include "ubsan_value.h"
+#include "sanitizer_common/sanitizer_stacktrace.h"
+#include "sanitizer_common/sanitizer_suppressions.h"
namespace __ubsan {
@@ -203,6 +205,33 @@ public:
Diag &operator<<(const Range &R) { return AddRange(R); }
};
+struct ReportOptions {
+ /// If DieAfterReport is specified, UBSan will terminate the program after the
+ /// report is printed.
+ bool DieAfterReport;
+ /// pc/bp are used to unwind the stack trace.
+ uptr pc;
+ uptr bp;
+};
+
+#define GET_REPORT_OPTIONS(die_after_report) \
+ GET_CALLER_PC_BP; \
+ ReportOptions Opts = {die_after_report, pc, bp}
+
+/// \brief Instantiate this class before printing diagnostics in the error
+/// report. This class ensures that reports from different threads and from
+/// different sanitizers won't be mixed.
+class ScopedReport {
+ ReportOptions Opts;
+ Location SummaryLoc;
+
+public:
+ ScopedReport(ReportOptions Opts, Location SummaryLoc);
+ ~ScopedReport();
+};
+
+bool MatchSuppression(const char *Str, SuppressionType Type);
+
} // namespace __ubsan
#endif // UBSAN_DIAG_H
diff --git a/lib/ubsan/ubsan_flags.cc b/lib/ubsan/ubsan_flags.cc
new file mode 100644
index 000000000000..eda11f1b265c
--- /dev/null
+++ b/lib/ubsan/ubsan_flags.cc
@@ -0,0 +1,63 @@
+//===-- ubsan_flags.cc ----------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Runtime flags for UndefinedBehaviorSanitizer.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ubsan_flags.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_flags.h"
+
+namespace __ubsan {
+
+static const char *MaybeCallUbsanDefaultOptions() {
+ return (&__ubsan_default_options) ? __ubsan_default_options() : "";
+}
+
+void InitializeCommonFlags() {
+ CommonFlags *cf = common_flags();
+ SetCommonFlagsDefaults(cf);
+ cf->print_summary = false;
+ // Override from user-specified string.
+ ParseCommonFlagsFromString(cf, MaybeCallUbsanDefaultOptions());
+ // Override from environment variable.
+ ParseCommonFlagsFromString(cf, GetEnv("UBSAN_OPTIONS"));
+}
+
+Flags ubsan_flags;
+
+static void ParseFlagsFromString(Flags *f, const char *str) {
+ if (!str)
+ return;
+ ParseFlag(str, &f->halt_on_error, "halt_on_error",
+ "Crash the program after printing the first error report");
+ ParseFlag(str, &f->print_stacktrace, "print_stacktrace",
+ "Include full stacktrace into an error report");
+}
+
+void InitializeFlags() {
+ Flags *f = flags();
+ // Default values.
+ f->halt_on_error = false;
+ f->print_stacktrace = false;
+ // Override from user-specified string.
+ ParseFlagsFromString(f, MaybeCallUbsanDefaultOptions());
+ // Override from environment variable.
+ ParseFlagsFromString(f, GetEnv("UBSAN_OPTIONS"));
+}
+
+} // namespace __ubsan
+
+#if !SANITIZER_SUPPORTS_WEAK_HOOKS
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+const char *__ubsan_default_options() { return ""; }
+} // extern "C"
+#endif
diff --git a/lib/ubsan/ubsan_flags.h b/lib/ubsan/ubsan_flags.h
new file mode 100644
index 000000000000..c496469f5f41
--- /dev/null
+++ b/lib/ubsan/ubsan_flags.h
@@ -0,0 +1,40 @@
+//===-- ubsan_flags.h -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Runtime flags for UndefinedBehaviorSanitizer.
+//
+//===----------------------------------------------------------------------===//
+#ifndef UBSAN_FLAGS_H
+#define UBSAN_FLAGS_H
+
+#include "sanitizer_common/sanitizer_internal_defs.h"
+
+namespace __ubsan {
+
+struct Flags {
+ bool halt_on_error;
+ bool print_stacktrace;
+};
+
+extern Flags ubsan_flags;
+inline Flags *flags() { return &ubsan_flags; }
+
+void InitializeCommonFlags();
+void InitializeFlags();
+
+} // namespace __ubsan
+
+extern "C" {
+// Users may provide their own implementation of __ubsan_default_options to
+// override the default flag values.
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+const char *__ubsan_default_options();
+} // extern "C"
+
+#endif // UBSAN_FLAGS_H
diff --git a/lib/ubsan/ubsan_handlers.cc b/lib/ubsan/ubsan_handlers.cc
index d55643143295..a0ecff943592 100644
--- a/lib/ubsan/ubsan_handlers.cc
+++ b/lib/ubsan/ubsan_handlers.cc
@@ -19,23 +19,35 @@
using namespace __sanitizer;
using namespace __ubsan;
+static bool ignoreReport(SourceLocation SLoc, ReportOptions Opts) {
+ // If source location is already acquired, we don't need to print an error
+ // report for the second time. However, if we're in an unrecoverable handler,
+ // it's possible that location was required by concurrently running thread.
+ // In this case, we should continue the execution to ensure that any of
+ // threads will grab the report mutex and print the report before
+ // crashing the program.
+ return SLoc.isDisabled() && !Opts.DieAfterReport;
+}
+
namespace __ubsan {
- const char *TypeCheckKinds[] = {
+const char *TypeCheckKinds[] = {
"load of", "store to", "reference binding to", "member access within",
- "member call on", "constructor call on", "downcast of", "downcast of"
- };
+ "member call on", "constructor call on", "downcast of", "downcast of",
+ "upcast of", "cast to virtual base of"};
}
static void handleTypeMismatchImpl(TypeMismatchData *Data, ValueHandle Pointer,
- Location FallbackLoc) {
+ Location FallbackLoc, ReportOptions Opts) {
Location Loc = Data->Loc.acquire();
-
// Use the SourceLocation from Data to track deduplication, even if 'invalid'
- if (Loc.getSourceLocation().isDisabled())
+ if (ignoreReport(Loc.getSourceLocation(), Opts))
return;
+
if (Data->Loc.isInvalid())
Loc = FallbackLoc;
+ ScopedReport R(Opts, Loc);
+
if (!Pointer)
Diag(Loc, DL_Error, "%0 null pointer of type %1")
<< TypeCheckKinds[Data->TypeCheckKind] << Data->Type;
@@ -51,70 +63,59 @@ static void handleTypeMismatchImpl(TypeMismatchData *Data, ValueHandle Pointer,
if (Pointer)
Diag(Pointer, DL_Note, "pointer points here");
}
+
void __ubsan::__ubsan_handle_type_mismatch(TypeMismatchData *Data,
ValueHandle Pointer) {
- handleTypeMismatchImpl(Data, Pointer, getCallerLocation());
+ GET_REPORT_OPTIONS(false);
+ handleTypeMismatchImpl(Data, Pointer, getCallerLocation(), Opts);
}
void __ubsan::__ubsan_handle_type_mismatch_abort(TypeMismatchData *Data,
ValueHandle Pointer) {
- handleTypeMismatchImpl(Data, Pointer, getCallerLocation());
+ GET_REPORT_OPTIONS(true);
+ handleTypeMismatchImpl(Data, Pointer, getCallerLocation(), Opts);
Die();
}
/// \brief Common diagnostic emission for various forms of integer overflow.
-template<typename T> static void HandleIntegerOverflow(OverflowData *Data,
- ValueHandle LHS,
- const char *Operator,
- T RHS) {
+template <typename T>
+static void handleIntegerOverflowImpl(OverflowData *Data, ValueHandle LHS,
+ const char *Operator, T RHS,
+ ReportOptions Opts) {
SourceLocation Loc = Data->Loc.acquire();
- if (Loc.isDisabled())
+ if (ignoreReport(Loc, Opts))
return;
+ ScopedReport R(Opts, Loc);
+
Diag(Loc, DL_Error, "%0 integer overflow: "
"%1 %2 %3 cannot be represented in type %4")
<< (Data->Type.isSignedIntegerTy() ? "signed" : "unsigned")
<< Value(Data->Type, LHS) << Operator << RHS << Data->Type;
}
-void __ubsan::__ubsan_handle_add_overflow(OverflowData *Data,
- ValueHandle LHS, ValueHandle RHS) {
- HandleIntegerOverflow(Data, LHS, "+", Value(Data->Type, RHS));
-}
-void __ubsan::__ubsan_handle_add_overflow_abort(OverflowData *Data,
- ValueHandle LHS,
- ValueHandle RHS) {
- __ubsan_handle_add_overflow(Data, LHS, RHS);
- Die();
-}
-
-void __ubsan::__ubsan_handle_sub_overflow(OverflowData *Data,
- ValueHandle LHS, ValueHandle RHS) {
- HandleIntegerOverflow(Data, LHS, "-", Value(Data->Type, RHS));
-}
-void __ubsan::__ubsan_handle_sub_overflow_abort(OverflowData *Data,
- ValueHandle LHS,
- ValueHandle RHS) {
- __ubsan_handle_sub_overflow(Data, LHS, RHS);
- Die();
-}
-
-void __ubsan::__ubsan_handle_mul_overflow(OverflowData *Data,
- ValueHandle LHS, ValueHandle RHS) {
- HandleIntegerOverflow(Data, LHS, "*", Value(Data->Type, RHS));
-}
-void __ubsan::__ubsan_handle_mul_overflow_abort(OverflowData *Data,
- ValueHandle LHS,
- ValueHandle RHS) {
- __ubsan_handle_mul_overflow(Data, LHS, RHS);
- Die();
-}
-
-void __ubsan::__ubsan_handle_negate_overflow(OverflowData *Data,
- ValueHandle OldVal) {
+#define UBSAN_OVERFLOW_HANDLER(handler_name, op, abort) \
+ void __ubsan::handler_name(OverflowData *Data, ValueHandle LHS, \
+ ValueHandle RHS) { \
+ GET_REPORT_OPTIONS(abort); \
+ handleIntegerOverflowImpl(Data, LHS, op, Value(Data->Type, RHS), Opts); \
+ if (abort) Die(); \
+ }
+
+UBSAN_OVERFLOW_HANDLER(__ubsan_handle_add_overflow, "+", false)
+UBSAN_OVERFLOW_HANDLER(__ubsan_handle_add_overflow_abort, "+", true)
+UBSAN_OVERFLOW_HANDLER(__ubsan_handle_sub_overflow, "-", false)
+UBSAN_OVERFLOW_HANDLER(__ubsan_handle_sub_overflow_abort, "-", true)
+UBSAN_OVERFLOW_HANDLER(__ubsan_handle_mul_overflow, "*", false)
+UBSAN_OVERFLOW_HANDLER(__ubsan_handle_mul_overflow_abort, "*", true)
+
+static void handleNegateOverflowImpl(OverflowData *Data, ValueHandle OldVal,
+ ReportOptions Opts) {
SourceLocation Loc = Data->Loc.acquire();
- if (Loc.isDisabled())
+ if (ignoreReport(Loc, Opts))
return;
+ ScopedReport R(Opts, Loc);
+
if (Data->Type.isSignedIntegerTy())
Diag(Loc, DL_Error,
"negation of %0 cannot be represented in type %1; "
@@ -125,18 +126,27 @@ void __ubsan::__ubsan_handle_negate_overflow(OverflowData *Data,
"negation of %0 cannot be represented in type %1")
<< Value(Data->Type, OldVal) << Data->Type;
}
+
+void __ubsan::__ubsan_handle_negate_overflow(OverflowData *Data,
+ ValueHandle OldVal) {
+ GET_REPORT_OPTIONS(false);
+ handleNegateOverflowImpl(Data, OldVal, Opts);
+}
void __ubsan::__ubsan_handle_negate_overflow_abort(OverflowData *Data,
ValueHandle OldVal) {
- __ubsan_handle_negate_overflow(Data, OldVal);
+ GET_REPORT_OPTIONS(true);
+ handleNegateOverflowImpl(Data, OldVal, Opts);
Die();
}
-void __ubsan::__ubsan_handle_divrem_overflow(OverflowData *Data,
- ValueHandle LHS, ValueHandle RHS) {
+static void handleDivremOverflowImpl(OverflowData *Data, ValueHandle LHS,
+ ValueHandle RHS, ReportOptions Opts) {
SourceLocation Loc = Data->Loc.acquire();
- if (Loc.isDisabled())
+ if (ignoreReport(Loc, Opts))
return;
+ ScopedReport R(Opts, Loc);
+
Value LHSVal(Data->Type, LHS);
Value RHSVal(Data->Type, RHS);
if (RHSVal.isMinusOne())
@@ -146,20 +156,29 @@ void __ubsan::__ubsan_handle_divrem_overflow(OverflowData *Data,
else
Diag(Loc, DL_Error, "division by zero");
}
+
+void __ubsan::__ubsan_handle_divrem_overflow(OverflowData *Data,
+ ValueHandle LHS, ValueHandle RHS) {
+ GET_REPORT_OPTIONS(false);
+ handleDivremOverflowImpl(Data, LHS, RHS, Opts);
+}
void __ubsan::__ubsan_handle_divrem_overflow_abort(OverflowData *Data,
ValueHandle LHS,
ValueHandle RHS) {
- __ubsan_handle_divrem_overflow(Data, LHS, RHS);
+ GET_REPORT_OPTIONS(true);
+ handleDivremOverflowImpl(Data, LHS, RHS, Opts);
Die();
}
-void __ubsan::__ubsan_handle_shift_out_of_bounds(ShiftOutOfBoundsData *Data,
- ValueHandle LHS,
- ValueHandle RHS) {
+static void handleShiftOutOfBoundsImpl(ShiftOutOfBoundsData *Data,
+ ValueHandle LHS, ValueHandle RHS,
+ ReportOptions Opts) {
SourceLocation Loc = Data->Loc.acquire();
- if (Loc.isDisabled())
+ if (ignoreReport(Loc, Opts))
return;
+ ScopedReport R(Opts, Loc);
+
Value LHSVal(Data->LHSType, LHS);
Value RHSVal(Data->RHSType, RHS);
if (RHSVal.isNegative())
@@ -175,107 +194,219 @@ void __ubsan::__ubsan_handle_shift_out_of_bounds(ShiftOutOfBoundsData *Data,
"left shift of %0 by %1 places cannot be represented in type %2")
<< LHSVal << RHSVal << Data->LHSType;
}
+
+void __ubsan::__ubsan_handle_shift_out_of_bounds(ShiftOutOfBoundsData *Data,
+ ValueHandle LHS,
+ ValueHandle RHS) {
+ GET_REPORT_OPTIONS(false);
+ handleShiftOutOfBoundsImpl(Data, LHS, RHS, Opts);
+}
void __ubsan::__ubsan_handle_shift_out_of_bounds_abort(
ShiftOutOfBoundsData *Data,
ValueHandle LHS,
ValueHandle RHS) {
- __ubsan_handle_shift_out_of_bounds(Data, LHS, RHS);
+ GET_REPORT_OPTIONS(true);
+ handleShiftOutOfBoundsImpl(Data, LHS, RHS, Opts);
Die();
}
-void __ubsan::__ubsan_handle_out_of_bounds(OutOfBoundsData *Data,
- ValueHandle Index) {
+static void handleOutOfBoundsImpl(OutOfBoundsData *Data, ValueHandle Index,
+ ReportOptions Opts) {
SourceLocation Loc = Data->Loc.acquire();
- if (Loc.isDisabled())
+ if (ignoreReport(Loc, Opts))
return;
+ ScopedReport R(Opts, Loc);
+
Value IndexVal(Data->IndexType, Index);
Diag(Loc, DL_Error, "index %0 out of bounds for type %1")
<< IndexVal << Data->ArrayType;
}
+
+void __ubsan::__ubsan_handle_out_of_bounds(OutOfBoundsData *Data,
+ ValueHandle Index) {
+ GET_REPORT_OPTIONS(false);
+ handleOutOfBoundsImpl(Data, Index, Opts);
+}
void __ubsan::__ubsan_handle_out_of_bounds_abort(OutOfBoundsData *Data,
ValueHandle Index) {
- __ubsan_handle_out_of_bounds(Data, Index);
+ GET_REPORT_OPTIONS(true);
+ handleOutOfBoundsImpl(Data, Index, Opts);
Die();
}
-void __ubsan::__ubsan_handle_builtin_unreachable(UnreachableData *Data) {
+static void handleBuiltinUnreachableImpl(UnreachableData *Data,
+ ReportOptions Opts) {
+ ScopedReport R(Opts, Data->Loc);
Diag(Data->Loc, DL_Error, "execution reached a __builtin_unreachable() call");
+}
+
+void __ubsan::__ubsan_handle_builtin_unreachable(UnreachableData *Data) {
+ GET_REPORT_OPTIONS(true);
+ handleBuiltinUnreachableImpl(Data, Opts);
Die();
}
-void __ubsan::__ubsan_handle_missing_return(UnreachableData *Data) {
+static void handleMissingReturnImpl(UnreachableData *Data, ReportOptions Opts) {
+ ScopedReport R(Opts, Data->Loc);
Diag(Data->Loc, DL_Error,
"execution reached the end of a value-returning function "
"without returning a value");
+}
+
+void __ubsan::__ubsan_handle_missing_return(UnreachableData *Data) {
+ GET_REPORT_OPTIONS(true);
+ handleMissingReturnImpl(Data, Opts);
Die();
}
-void __ubsan::__ubsan_handle_vla_bound_not_positive(VLABoundData *Data,
- ValueHandle Bound) {
+static void handleVLABoundNotPositive(VLABoundData *Data, ValueHandle Bound,
+ ReportOptions Opts) {
SourceLocation Loc = Data->Loc.acquire();
- if (Loc.isDisabled())
+ if (ignoreReport(Loc, Opts))
return;
+ ScopedReport R(Opts, Loc);
+
Diag(Loc, DL_Error, "variable length array bound evaluates to "
"non-positive value %0")
<< Value(Data->Type, Bound);
}
+
+void __ubsan::__ubsan_handle_vla_bound_not_positive(VLABoundData *Data,
+ ValueHandle Bound) {
+ GET_REPORT_OPTIONS(false);
+ handleVLABoundNotPositive(Data, Bound, Opts);
+}
void __ubsan::__ubsan_handle_vla_bound_not_positive_abort(VLABoundData *Data,
- ValueHandle Bound) {
- __ubsan_handle_vla_bound_not_positive(Data, Bound);
+ ValueHandle Bound) {
+ GET_REPORT_OPTIONS(true);
+ handleVLABoundNotPositive(Data, Bound, Opts);
Die();
}
+static void handleFloatCastOverflow(FloatCastOverflowData *Data,
+ ValueHandle From, ReportOptions Opts) {
+ // TODO: Add deduplication once a SourceLocation is generated for this check.
+ Location Loc = getCallerLocation();
+ ScopedReport R(Opts, Loc);
+
+ Diag(Loc, DL_Error,
+ "value %0 is outside the range of representable values of type %2")
+ << Value(Data->FromType, From) << Data->FromType << Data->ToType;
+}
void __ubsan::__ubsan_handle_float_cast_overflow(FloatCastOverflowData *Data,
ValueHandle From) {
- // TODO: Add deduplication once a SourceLocation is generated for this check.
- Diag(getCallerLocation(), DL_Error,
- "value %0 is outside the range of representable values of type %2")
- << Value(Data->FromType, From) << Data->FromType << Data->ToType;
+ GET_REPORT_OPTIONS(false);
+ handleFloatCastOverflow(Data, From, Opts);
}
-void __ubsan::__ubsan_handle_float_cast_overflow_abort(
- FloatCastOverflowData *Data,
- ValueHandle From) {
- Diag(getCallerLocation(), DL_Error,
- "value %0 is outside the range of representable values of type %2")
- << Value(Data->FromType, From) << Data->FromType << Data->ToType;
+void
+__ubsan::__ubsan_handle_float_cast_overflow_abort(FloatCastOverflowData *Data,
+ ValueHandle From) {
+ GET_REPORT_OPTIONS(true);
+ handleFloatCastOverflow(Data, From, Opts);
Die();
}
-void __ubsan::__ubsan_handle_load_invalid_value(InvalidValueData *Data,
- ValueHandle Val) {
+static void handleLoadInvalidValue(InvalidValueData *Data, ValueHandle Val,
+ ReportOptions Opts) {
SourceLocation Loc = Data->Loc.acquire();
- if (Loc.isDisabled())
+ if (ignoreReport(Loc, Opts))
return;
+ ScopedReport R(Opts, Loc);
+
Diag(Loc, DL_Error,
"load of value %0, which is not a valid value for type %1")
<< Value(Data->Type, Val) << Data->Type;
}
+
+void __ubsan::__ubsan_handle_load_invalid_value(InvalidValueData *Data,
+ ValueHandle Val) {
+ GET_REPORT_OPTIONS(false);
+ handleLoadInvalidValue(Data, Val, Opts);
+}
void __ubsan::__ubsan_handle_load_invalid_value_abort(InvalidValueData *Data,
ValueHandle Val) {
- __ubsan_handle_load_invalid_value(Data, Val);
+ GET_REPORT_OPTIONS(true);
+ handleLoadInvalidValue(Data, Val, Opts);
Die();
}
-void __ubsan::__ubsan_handle_function_type_mismatch(
- FunctionTypeMismatchData *Data,
- ValueHandle Function) {
+static void handleFunctionTypeMismatch(FunctionTypeMismatchData *Data,
+ ValueHandle Function,
+ ReportOptions Opts) {
const char *FName = "(unknown)";
Location Loc = getFunctionLocation(Function, &FName);
+ ScopedReport R(Opts, Loc);
+
Diag(Data->Loc, DL_Error,
"call to function %0 through pointer to incorrect function type %1")
<< FName << Data->Type;
Diag(Loc, DL_Note, "%0 defined here") << FName;
}
+void
+__ubsan::__ubsan_handle_function_type_mismatch(FunctionTypeMismatchData *Data,
+ ValueHandle Function) {
+ GET_REPORT_OPTIONS(false);
+ handleFunctionTypeMismatch(Data, Function, Opts);
+}
+
void __ubsan::__ubsan_handle_function_type_mismatch_abort(
- FunctionTypeMismatchData *Data,
- ValueHandle Function) {
- __ubsan_handle_function_type_mismatch(Data, Function);
+ FunctionTypeMismatchData *Data, ValueHandle Function) {
+ GET_REPORT_OPTIONS(true);
+ handleFunctionTypeMismatch(Data, Function, Opts);
+ Die();
+}
+
+static void handleNonNullReturn(NonNullReturnData *Data, ReportOptions Opts) {
+ SourceLocation Loc = Data->Loc.acquire();
+ if (ignoreReport(Loc, Opts))
+ return;
+
+ ScopedReport R(Opts, Loc);
+
+ Diag(Loc, DL_Error, "null pointer returned from function declared to never "
+ "return null");
+ if (!Data->AttrLoc.isInvalid())
+ Diag(Data->AttrLoc, DL_Note, "returns_nonnull attribute specified here");
+}
+
+void __ubsan::__ubsan_handle_nonnull_return(NonNullReturnData *Data) {
+ GET_REPORT_OPTIONS(false);
+ handleNonNullReturn(Data, Opts);
+}
+
+void __ubsan::__ubsan_handle_nonnull_return_abort(NonNullReturnData *Data) {
+ GET_REPORT_OPTIONS(true);
+ handleNonNullReturn(Data, Opts);
+ Die();
+}
+
+static void handleNonNullArg(NonNullArgData *Data, ReportOptions Opts) {
+ SourceLocation Loc = Data->Loc.acquire();
+ if (ignoreReport(Loc, Opts))
+ return;
+
+ ScopedReport R(Opts, Loc);
+
+ Diag(Loc, DL_Error, "null pointer passed as argument %0, which is declared to "
+ "never be null") << Data->ArgIndex;
+ if (!Data->AttrLoc.isInvalid())
+ Diag(Data->AttrLoc, DL_Note, "nonnull attribute specified here");
+}
+
+void __ubsan::__ubsan_handle_nonnull_arg(NonNullArgData *Data) {
+ GET_REPORT_OPTIONS(false);
+ handleNonNullArg(Data, Opts);
+}
+
+void __ubsan::__ubsan_handle_nonnull_arg_abort(NonNullArgData *Data) {
+ GET_REPORT_OPTIONS(true);
+ handleNonNullArg(Data, Opts);
Die();
}
diff --git a/lib/ubsan/ubsan_handlers.h b/lib/ubsan/ubsan_handlers.h
index 14e6f04c2a1b..87149f259607 100644
--- a/lib/ubsan/ubsan_handlers.h
+++ b/lib/ubsan/ubsan_handlers.h
@@ -24,10 +24,14 @@ struct TypeMismatchData {
unsigned char TypeCheckKind;
};
+#define UNRECOVERABLE(checkname, ...) \
+ extern "C" SANITIZER_INTERFACE_ATTRIBUTE NORETURN \
+ void __ubsan_handle_ ## checkname( __VA_ARGS__ );
+
#define RECOVERABLE(checkname, ...) \
extern "C" SANITIZER_INTERFACE_ATTRIBUTE \
void __ubsan_handle_ ## checkname( __VA_ARGS__ ); \
- extern "C" SANITIZER_INTERFACE_ATTRIBUTE \
+ extern "C" SANITIZER_INTERFACE_ATTRIBUTE NORETURN \
void __ubsan_handle_ ## checkname ## _abort( __VA_ARGS__ );
/// \brief Handle a runtime type check failure, caused by either a misaligned
@@ -81,11 +85,9 @@ struct UnreachableData {
};
/// \brief Handle a __builtin_unreachable which is reached.
-extern "C" SANITIZER_INTERFACE_ATTRIBUTE
-void __ubsan_handle_builtin_unreachable(UnreachableData *Data);
+UNRECOVERABLE(builtin_unreachable, UnreachableData *Data)
/// \brief Handle reaching the end of a value-returning function.
-extern "C" SANITIZER_INTERFACE_ATTRIBUTE
-void __ubsan_handle_missing_return(UnreachableData *Data);
+UNRECOVERABLE(missing_return, UnreachableData *Data)
struct VLABoundData {
SourceLocation Loc;
@@ -121,6 +123,23 @@ RECOVERABLE(function_type_mismatch,
FunctionTypeMismatchData *Data,
ValueHandle Val)
+struct NonNullReturnData {
+ SourceLocation Loc;
+ SourceLocation AttrLoc;
+};
+
+/// \brief Handle returning null from function with returns_nonnull attribute.
+RECOVERABLE(nonnull_return, NonNullReturnData *Data)
+
+struct NonNullArgData {
+ SourceLocation Loc;
+ SourceLocation AttrLoc;
+ int ArgIndex;
+};
+
+/// \brief Handle passing null pointer to function with nonnull attribute.
+RECOVERABLE(nonnull_arg, NonNullArgData *Data)
+
}
#endif // UBSAN_HANDLERS_H
diff --git a/lib/ubsan/ubsan_handlers_cxx.cc b/lib/ubsan/ubsan_handlers_cxx.cc
index b6cddefeb4f4..5704c1e6342d 100644
--- a/lib/ubsan/ubsan_handlers_cxx.cc
+++ b/lib/ubsan/ubsan_handlers_cxx.cc
@@ -18,6 +18,7 @@
#include "ubsan_type_hash.h"
#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_suppressions.h"
using namespace __sanitizer;
using namespace __ubsan;
@@ -28,47 +29,54 @@ namespace __ubsan {
static void HandleDynamicTypeCacheMiss(
DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash,
- bool Abort) {
+ ReportOptions Opts) {
if (checkDynamicType((void*)Pointer, Data->TypeInfo, Hash))
// Just a cache miss. The type matches after all.
return;
+ // Check if error report should be suppressed.
+ DynamicTypeInfo DTI = getDynamicTypeInfo((void*)Pointer);
+ if (DTI.isValid() &&
+ MatchSuppression(DTI.getMostDerivedTypeName(), SuppressionVptrCheck))
+ return;
+
SourceLocation Loc = Data->Loc.acquire();
if (Loc.isDisabled())
return;
+ ScopedReport R(Opts, Loc);
+
Diag(Loc, DL_Error,
"%0 address %1 which does not point to an object of type %2")
<< TypeCheckKinds[Data->TypeCheckKind] << (void*)Pointer << Data->Type;
// If possible, say what type it actually points to.
- DynamicTypeInfo DTI = getDynamicTypeInfo((void*)Pointer);
if (!DTI.isValid())
Diag(Pointer, DL_Note, "object has invalid vptr")
- << MangledName(DTI.getMostDerivedTypeName())
- << Range(Pointer, Pointer + sizeof(uptr), "invalid vptr");
+ << MangledName(DTI.getMostDerivedTypeName())
+ << Range(Pointer, Pointer + sizeof(uptr), "invalid vptr");
else if (!DTI.getOffset())
Diag(Pointer, DL_Note, "object is of type %0")
- << MangledName(DTI.getMostDerivedTypeName())
- << Range(Pointer, Pointer + sizeof(uptr), "vptr for %0");
+ << MangledName(DTI.getMostDerivedTypeName())
+ << Range(Pointer, Pointer + sizeof(uptr), "vptr for %0");
else
// FIXME: Find the type at the specified offset, and include that
// in the note.
Diag(Pointer - DTI.getOffset(), DL_Note,
"object is base class subobject at offset %0 within object of type %1")
- << DTI.getOffset() << MangledName(DTI.getMostDerivedTypeName())
- << MangledName(DTI.getSubobjectTypeName())
- << Range(Pointer, Pointer + sizeof(uptr), "vptr for %2 base class of %1");
-
- if (Abort)
- Die();
+ << DTI.getOffset() << MangledName(DTI.getMostDerivedTypeName())
+ << MangledName(DTI.getSubobjectTypeName())
+ << Range(Pointer, Pointer + sizeof(uptr),
+ "vptr for %2 base class of %1");
}
void __ubsan::__ubsan_handle_dynamic_type_cache_miss(
DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash) {
- HandleDynamicTypeCacheMiss(Data, Pointer, Hash, false);
+ GET_REPORT_OPTIONS(false);
+ HandleDynamicTypeCacheMiss(Data, Pointer, Hash, Opts);
}
void __ubsan::__ubsan_handle_dynamic_type_cache_miss_abort(
DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash) {
- HandleDynamicTypeCacheMiss(Data, Pointer, Hash, true);
+ GET_REPORT_OPTIONS(true);
+ HandleDynamicTypeCacheMiss(Data, Pointer, Hash, Opts);
}
diff --git a/lib/ubsan/ubsan_init.cc b/lib/ubsan/ubsan_init.cc
new file mode 100644
index 000000000000..6080e304c122
--- /dev/null
+++ b/lib/ubsan/ubsan_init.cc
@@ -0,0 +1,61 @@
+//===-- ubsan_init.cc -----------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Initialization of UBSan runtime.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ubsan_init.h"
+#include "ubsan_flags.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_libc.h"
+#include "sanitizer_common/sanitizer_mutex.h"
+#include "sanitizer_common/sanitizer_suppressions.h"
+#include "sanitizer_common/sanitizer_symbolizer.h"
+
+using namespace __ubsan;
+
+static bool ubsan_inited;
+
+void __ubsan::InitIfNecessary() {
+#if !SANITIZER_CAN_USE_PREINIT_ARRAY
+ // No need to lock mutex if we're initializing from preinit array.
+ static StaticSpinMutex init_mu;
+ SpinMutexLock l(&init_mu);
+#endif
+ if (LIKELY(ubsan_inited))
+ return;
+ if (0 == internal_strcmp(SanitizerToolName, "SanitizerTool")) {
+ // WARNING: If this condition holds, then either UBSan runs in a standalone
+ // mode, or initializer for another sanitizer hasn't run yet. In a latter
+ // case, another sanitizer will overwrite "SanitizerToolName" and reparse
+ // common flags. It means, that we are not allowed to *use* common flags
+ // in this function.
+ SanitizerToolName = "UndefinedBehaviorSanitizer";
+ InitializeCommonFlags();
+ }
+ // Initialize UBSan-specific flags.
+ InitializeFlags();
+ SuppressionContext::InitIfNecessary();
+ ubsan_inited = true;
+}
+
+#if SANITIZER_CAN_USE_PREINIT_ARRAY
+__attribute__((section(".preinit_array"), used))
+void (*__local_ubsan_preinit)(void) = __ubsan::InitIfNecessary;
+#else
+// Use a dynamic initializer.
+class UbsanInitializer {
+ public:
+ UbsanInitializer() {
+ InitIfNecessary();
+ }
+};
+static UbsanInitializer ubsan_initializer;
+#endif // SANITIZER_CAN_USE_PREINIT_ARRAY
diff --git a/lib/ubsan/ubsan_init.h b/lib/ubsan/ubsan_init.h
new file mode 100644
index 000000000000..18356cfca617
--- /dev/null
+++ b/lib/ubsan/ubsan_init.h
@@ -0,0 +1,24 @@
+//===-- ubsan_init.h --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Initialization function for UBSan runtime.
+//
+//===----------------------------------------------------------------------===//
+#ifndef UBSAN_INIT_H
+#define UBSAN_INIT_H
+
+namespace __ubsan {
+
+// NOTE: This function might take a lock (if .preinit_array initialization is
+// not used). It's generally a bad idea to call it on a fast path.
+void InitIfNecessary();
+
+} // namespace __ubsan
+
+#endif // UBSAN_INIT_H
diff --git a/lib/ubsan/ubsan_type_hash.cc b/lib/ubsan/ubsan_type_hash.cc
index a388bcc6d72e..808a4332d01f 100644
--- a/lib/ubsan/ubsan_type_hash.cc
+++ b/lib/ubsan/ubsan_type_hash.cc
@@ -115,7 +115,8 @@ __ubsan::__ubsan_vptr_type_cache[__ubsan::VptrTypeCacheSize];
/// \brief Determine whether \p Derived has a \p Base base class subobject at
/// offset \p Offset.
-static bool isDerivedFromAtOffset(const abi::__class_type_info *Derived,
+static bool isDerivedFromAtOffset(sptr Object,
+ const abi::__class_type_info *Derived,
const abi::__class_type_info *Base,
sptr Offset) {
if (Derived->__type_name == Base->__type_name)
@@ -123,7 +124,7 @@ static bool isDerivedFromAtOffset(const abi::__class_type_info *Derived,
if (const abi::__si_class_type_info *SI =
dynamic_cast<const abi::__si_class_type_info*>(Derived))
- return isDerivedFromAtOffset(SI->__base_type, Base, Offset);
+ return isDerivedFromAtOffset(Object, SI->__base_type, Base, Offset);
const abi::__vmi_class_type_info *VTI =
dynamic_cast<const abi::__vmi_class_type_info*>(Derived);
@@ -138,13 +139,13 @@ static bool isDerivedFromAtOffset(const abi::__class_type_info *Derived,
sptr OffsetHere = VTI->base_info[base].__offset_flags >>
abi::__base_class_type_info::__offset_shift;
if (VTI->base_info[base].__offset_flags &
- abi::__base_class_type_info::__virtual_mask)
- // For now, just punt on virtual bases and say 'yes'.
- // FIXME: OffsetHere is the offset in the vtable of the virtual base
- // offset. Read the vbase offset out of the vtable and use it.
- return true;
- if (isDerivedFromAtOffset(VTI->base_info[base].__base_type,
- Base, Offset - OffsetHere))
+ abi::__base_class_type_info::__virtual_mask) {
+ sptr VTable = *reinterpret_cast<const sptr *>(Object);
+ OffsetHere = *reinterpret_cast<const sptr *>(VTable + OffsetHere);
+ }
+ if (isDerivedFromAtOffset(Object + OffsetHere,
+ VTI->base_info[base].__base_type, Base,
+ Offset - OffsetHere))
return true;
}
@@ -153,14 +154,15 @@ static bool isDerivedFromAtOffset(const abi::__class_type_info *Derived,
/// \brief Find the derived-most dynamic base class of \p Derived at offset
/// \p Offset.
-static const abi::__class_type_info *findBaseAtOffset(
- const abi::__class_type_info *Derived, sptr Offset) {
+static const abi::__class_type_info *
+findBaseAtOffset(sptr Object, const abi::__class_type_info *Derived,
+ sptr Offset) {
if (!Offset)
return Derived;
if (const abi::__si_class_type_info *SI =
dynamic_cast<const abi::__si_class_type_info*>(Derived))
- return findBaseAtOffset(SI->__base_type, Offset);
+ return findBaseAtOffset(Object, SI->__base_type, Offset);
const abi::__vmi_class_type_info *VTI =
dynamic_cast<const abi::__vmi_class_type_info*>(Derived);
@@ -172,12 +174,13 @@ static const abi::__class_type_info *findBaseAtOffset(
sptr OffsetHere = VTI->base_info[base].__offset_flags >>
abi::__base_class_type_info::__offset_shift;
if (VTI->base_info[base].__offset_flags &
- abi::__base_class_type_info::__virtual_mask)
- // FIXME: Can't handle virtual bases yet.
- continue;
- if (const abi::__class_type_info *Base =
- findBaseAtOffset(VTI->base_info[base].__base_type,
- Offset - OffsetHere))
+ abi::__base_class_type_info::__virtual_mask) {
+ sptr VTable = *reinterpret_cast<const sptr *>(Object);
+ OffsetHere = *reinterpret_cast<const sptr *>(VTable + OffsetHere);
+ }
+ if (const abi::__class_type_info *Base = findBaseAtOffset(
+ Object + OffsetHere, VTI->base_info[base].__base_type,
+ Offset - OffsetHere))
return Base;
}
@@ -229,7 +232,8 @@ bool __ubsan::checkDynamicType(void *Object, void *Type, HashValue Hash) {
return false;
abi::__class_type_info *Base = (abi::__class_type_info*)Type;
- if (!isDerivedFromAtOffset(Derived, Base, -Vtable->Offset))
+ if (!isDerivedFromAtOffset(reinterpret_cast<sptr>(Object), Derived, Base,
+ -Vtable->Offset))
return false;
// Success. Cache this result.
@@ -243,8 +247,9 @@ __ubsan::DynamicTypeInfo __ubsan::getDynamicTypeInfo(void *Object) {
if (!Vtable)
return DynamicTypeInfo(0, 0, 0);
const abi::__class_type_info *ObjectType = findBaseAtOffset(
- static_cast<const abi::__class_type_info*>(Vtable->TypeInfo),
- -Vtable->Offset);
+ reinterpret_cast<sptr>(Object),
+ static_cast<const abi::__class_type_info *>(Vtable->TypeInfo),
+ -Vtable->Offset);
return DynamicTypeInfo(Vtable->TypeInfo->__type_name, -Vtable->Offset,
ObjectType ? ObjectType->__type_name : "<unknown>");
}
diff --git a/lib/ubsan/ubsan_value.cc b/lib/ubsan/ubsan_value.cc
index 5d77350d0c40..ab74720f60cf 100644
--- a/lib/ubsan/ubsan_value.cc
+++ b/lib/ubsan/ubsan_value.cc
@@ -94,6 +94,7 @@ FloatMax Value::getFloatValue() const {
switch (getType().getFloatBitWidth()) {
case 64: return *reinterpret_cast<double*>(Val);
case 80: return *reinterpret_cast<long double*>(Val);
+ case 96: return *reinterpret_cast<long double*>(Val);
case 128: return *reinterpret_cast<long double*>(Val);
}
}
diff --git a/lib/ubsan/ubsan_value.h b/lib/ubsan/ubsan_value.h
index 54ed5ad1931f..a6810844049f 100644
--- a/lib/ubsan/ubsan_value.h
+++ b/lib/ubsan/ubsan_value.h
@@ -14,9 +14,9 @@
#ifndef UBSAN_VALUE_H
#define UBSAN_VALUE_H
-// For now, only support linux and darwin. Other platforms should be easy to
-// add, and probably work as-is.
-#if !defined(__linux__) && !defined(__APPLE__)
+// For now, only support Linux, FreeBSD and Darwin. Other platforms should
+// be easy to add, and probably work as-is.
+#if !defined(__linux__) && !defined(__FreeBSD__) && !defined(__APPLE__)
#error "UBSan not supported for this platform!"
#endif
@@ -25,8 +25,8 @@
// FIXME: Move this out to a config header.
#if __SIZEOF_INT128__
-typedef __int128 s128;
-typedef unsigned __int128 u128;
+__extension__ typedef __int128 s128;
+__extension__ typedef unsigned __int128 u128;
#define HAVE_INT128_T 1
#else
#define HAVE_INT128_T 0
diff --git a/lib/ucmpti2.c b/lib/ucmpti2.c
deleted file mode 100644
index 5466d217428f..000000000000
--- a/lib/ucmpti2.c
+++ /dev/null
@@ -1,42 +0,0 @@
-/* ===-- ucmpti2.c - Implement __ucmpti2 -----------------------------------===
- *
- * 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 __ucmpti2 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-#if __x86_64
-
-/* Returns: if (a < b) returns 0
- * if (a == b) returns 1
- * if (a > b) returns 2
- */
-
-si_int
-__ucmpti2(tu_int a, tu_int b)
-{
- utwords x;
- x.all = a;
- utwords y;
- y.all = b;
- if (x.s.high < y.s.high)
- return 0;
- if (x.s.high > y.s.high)
- return 2;
- if (x.s.low < y.s.low)
- return 0;
- if (x.s.low > y.s.low)
- return 2;
- return 1;
-}
-
-#endif
diff --git a/lib/udivdi3.c b/lib/udivdi3.c
deleted file mode 100644
index 6c0303df3d40..000000000000
--- a/lib/udivdi3.c
+++ /dev/null
@@ -1,25 +0,0 @@
-/* ===-- udivdi3.c - Implement __udivdi3 -----------------------------------===
- *
- * 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 __udivdi3 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-du_int COMPILER_RT_ABI __udivmoddi4(du_int a, du_int b, du_int* rem);
-
-/* Returns: a / b */
-
-COMPILER_RT_ABI du_int
-__udivdi3(du_int a, du_int b)
-{
- return __udivmoddi4(a, b, 0);
-}
diff --git a/lib/udivmoddi4.c b/lib/udivmoddi4.c
deleted file mode 100644
index 57282d5b51c0..000000000000
--- a/lib/udivmoddi4.c
+++ /dev/null
@@ -1,251 +0,0 @@
-/* ===-- udivmoddi4.c - Implement __udivmoddi4 -----------------------------===
- *
- * 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 __udivmoddi4 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-/* Effects: if rem != 0, *rem = a % b
- * Returns: a / b
- */
-
-/* Translated from Figure 3-40 of The PowerPC Compiler Writer's Guide */
-
-COMPILER_RT_ABI du_int
-__udivmoddi4(du_int a, du_int b, du_int* rem)
-{
- const unsigned n_uword_bits = sizeof(su_int) * CHAR_BIT;
- const unsigned n_udword_bits = sizeof(du_int) * CHAR_BIT;
- udwords n;
- n.all = a;
- udwords d;
- d.all = b;
- udwords q;
- udwords r;
- unsigned sr;
- /* special cases, X is unknown, K != 0 */
- if (n.s.high == 0)
- {
- if (d.s.high == 0)
- {
- /* 0 X
- * ---
- * 0 X
- */
- if (rem)
- *rem = n.s.low % d.s.low;
- return n.s.low / d.s.low;
- }
- /* 0 X
- * ---
- * K X
- */
- if (rem)
- *rem = n.s.low;
- return 0;
- }
- /* n.s.high != 0 */
- if (d.s.low == 0)
- {
- if (d.s.high == 0)
- {
- /* K X
- * ---
- * 0 0
- */
- if (rem)
- *rem = n.s.high % d.s.low;
- return n.s.high / d.s.low;
- }
- /* d.s.high != 0 */
- if (n.s.low == 0)
- {
- /* K 0
- * ---
- * K 0
- */
- if (rem)
- {
- r.s.high = n.s.high % d.s.high;
- r.s.low = 0;
- *rem = r.all;
- }
- return n.s.high / d.s.high;
- }
- /* K K
- * ---
- * K 0
- */
- if ((d.s.high & (d.s.high - 1)) == 0) /* if d is a power of 2 */
- {
- if (rem)
- {
- r.s.low = n.s.low;
- r.s.high = n.s.high & (d.s.high - 1);
- *rem = r.all;
- }
- return n.s.high >> __builtin_ctz(d.s.high);
- }
- /* K K
- * ---
- * K 0
- */
- sr = __builtin_clz(d.s.high) - __builtin_clz(n.s.high);
- /* 0 <= sr <= n_uword_bits - 2 or sr large */
- if (sr > n_uword_bits - 2)
- {
- if (rem)
- *rem = n.all;
- return 0;
- }
- ++sr;
- /* 1 <= sr <= n_uword_bits - 1 */
- /* q.all = n.all << (n_udword_bits - sr); */
- q.s.low = 0;
- q.s.high = n.s.low << (n_uword_bits - sr);
- /* r.all = n.all >> sr; */
- r.s.high = n.s.high >> sr;
- r.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr);
- }
- else /* d.s.low != 0 */
- {
- if (d.s.high == 0)
- {
- /* K X
- * ---
- * 0 K
- */
- if ((d.s.low & (d.s.low - 1)) == 0) /* if d is a power of 2 */
- {
- if (rem)
- *rem = n.s.low & (d.s.low - 1);
- if (d.s.low == 1)
- return n.all;
- sr = __builtin_ctz(d.s.low);
- q.s.high = n.s.high >> sr;
- q.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr);
- return q.all;
- }
- /* K X
- * ---
- *0 K
- */
- sr = 1 + n_uword_bits + __builtin_clz(d.s.low) - __builtin_clz(n.s.high);
- /* 2 <= sr <= n_udword_bits - 1
- * q.all = n.all << (n_udword_bits - sr);
- * r.all = n.all >> sr;
- * if (sr == n_uword_bits)
- * {
- * q.s.low = 0;
- * q.s.high = n.s.low;
- * r.s.high = 0;
- * r.s.low = n.s.high;
- * }
- * else if (sr < n_uword_bits) // 2 <= sr <= n_uword_bits - 1
- * {
- * q.s.low = 0;
- * q.s.high = n.s.low << (n_uword_bits - sr);
- * r.s.high = n.s.high >> sr;
- * r.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr);
- * }
- * else // n_uword_bits + 1 <= sr <= n_udword_bits - 1
- * {
- * q.s.low = n.s.low << (n_udword_bits - sr);
- * q.s.high = (n.s.high << (n_udword_bits - sr)) |
- * (n.s.low >> (sr - n_uword_bits));
- * r.s.high = 0;
- * r.s.low = n.s.high >> (sr - n_uword_bits);
- * }
- */
- q.s.low = (n.s.low << (n_udword_bits - sr)) &
- ((si_int)(n_uword_bits - sr) >> (n_uword_bits-1));
- q.s.high = ((n.s.low << ( n_uword_bits - sr)) &
- ((si_int)(sr - n_uword_bits - 1) >> (n_uword_bits-1))) |
- (((n.s.high << (n_udword_bits - sr)) |
- (n.s.low >> (sr - n_uword_bits))) &
- ((si_int)(n_uword_bits - sr) >> (n_uword_bits-1)));
- r.s.high = (n.s.high >> sr) &
- ((si_int)(sr - n_uword_bits) >> (n_uword_bits-1));
- r.s.low = ((n.s.high >> (sr - n_uword_bits)) &
- ((si_int)(n_uword_bits - sr - 1) >> (n_uword_bits-1))) |
- (((n.s.high << (n_uword_bits - sr)) |
- (n.s.low >> sr)) &
- ((si_int)(sr - n_uword_bits) >> (n_uword_bits-1)));
- }
- else
- {
- /* K X
- * ---
- * K K
- */
- sr = __builtin_clz(d.s.high) - __builtin_clz(n.s.high);
- /* 0 <= sr <= n_uword_bits - 1 or sr large */
- if (sr > n_uword_bits - 1)
- {
- if (rem)
- *rem = n.all;
- return 0;
- }
- ++sr;
- /* 1 <= sr <= n_uword_bits */
- /* q.all = n.all << (n_udword_bits - sr); */
- q.s.low = 0;
- q.s.high = n.s.low << (n_uword_bits - sr);
- /* r.all = n.all >> sr;
- * if (sr < n_uword_bits)
- * {
- * r.s.high = n.s.high >> sr;
- * r.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr);
- * }
- * else
- * {
- * r.s.high = 0;
- * r.s.low = n.s.high;
- * }
- */
- r.s.high = (n.s.high >> sr) &
- ((si_int)(sr - n_uword_bits) >> (n_uword_bits-1));
- r.s.low = (n.s.high << (n_uword_bits - sr)) |
- ((n.s.low >> sr) &
- ((si_int)(sr - n_uword_bits) >> (n_uword_bits-1)));
- }
- }
- /* Not a special case
- * q and r are initialized with:
- * q.all = n.all << (n_udword_bits - sr);
- * r.all = n.all >> sr;
- * 1 <= sr <= n_udword_bits - 1
- */
- su_int carry = 0;
- for (; sr > 0; --sr)
- {
- /* r:q = ((r:q) << 1) | carry */
- r.s.high = (r.s.high << 1) | (r.s.low >> (n_uword_bits - 1));
- r.s.low = (r.s.low << 1) | (q.s.high >> (n_uword_bits - 1));
- q.s.high = (q.s.high << 1) | (q.s.low >> (n_uword_bits - 1));
- q.s.low = (q.s.low << 1) | carry;
- /* carry = 0;
- * if (r.all >= d.all)
- * {
- * r.all -= d.all;
- * carry = 1;
- * }
- */
- const di_int s = (di_int)(d.all - r.all - 1) >> (n_udword_bits - 1);
- carry = s & 1;
- r.all -= d.all & s;
- }
- q.all = (q.all << 1) | carry;
- if (rem)
- *rem = r.all;
- return q.all;
-}
diff --git a/lib/udivmodsi4.c b/lib/udivmodsi4.c
deleted file mode 100644
index 5b49089fccc4..000000000000
--- a/lib/udivmodsi4.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/*===-- udivmodsi4.c - Implement __udivmodsi4 ------------------------------===
- *
- * 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 __udivmodsi4 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-extern su_int COMPILER_RT_ABI __udivsi3(su_int n, su_int d);
-
-
-/* Returns: a / b, *rem = a % b */
-
-COMPILER_RT_ABI su_int
-__udivmodsi4(su_int a, su_int b, su_int* rem)
-{
- si_int d = __udivsi3(a,b);
- *rem = a - (d*b);
- return d;
-}
-
-
diff --git a/lib/udivmodti4.c b/lib/udivmodti4.c
deleted file mode 100644
index f619c74955e4..000000000000
--- a/lib/udivmodti4.c
+++ /dev/null
@@ -1,256 +0,0 @@
-/* ===-- udivmodti4.c - Implement __udivmodti4 -----------------------------===
- *
- * 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 __udivmodti4 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-#if __x86_64
-
-/* Effects: if rem != 0, *rem = a % b
- * Returns: a / b
- */
-
-/* Translated from Figure 3-40 of The PowerPC Compiler Writer's Guide */
-
-tu_int
-__udivmodti4(tu_int a, tu_int b, tu_int* rem)
-{
- const unsigned n_udword_bits = sizeof(du_int) * CHAR_BIT;
- const unsigned n_utword_bits = sizeof(tu_int) * CHAR_BIT;
- utwords n;
- n.all = a;
- utwords d;
- d.all = b;
- utwords q;
- utwords r;
- unsigned sr;
- /* special cases, X is unknown, K != 0 */
- if (n.s.high == 0)
- {
- if (d.s.high == 0)
- {
- /* 0 X
- * ---
- * 0 X
- */
- if (rem)
- *rem = n.s.low % d.s.low;
- return n.s.low / d.s.low;
- }
- /* 0 X
- * ---
- * K X
- */
- if (rem)
- *rem = n.s.low;
- return 0;
- }
- /* n.s.high != 0 */
- if (d.s.low == 0)
- {
- if (d.s.high == 0)
- {
- /* K X
- * ---
- * 0 0
- */
- if (rem)
- *rem = n.s.high % d.s.low;
- return n.s.high / d.s.low;
- }
- /* d.s.high != 0 */
- if (n.s.low == 0)
- {
- /* K 0
- * ---
- * K 0
- */
- if (rem)
- {
- r.s.high = n.s.high % d.s.high;
- r.s.low = 0;
- *rem = r.all;
- }
- return n.s.high / d.s.high;
- }
- /* K K
- * ---
- * K 0
- */
- if ((d.s.high & (d.s.high - 1)) == 0) /* if d is a power of 2 */
- {
- if (rem)
- {
- r.s.low = n.s.low;
- r.s.high = n.s.high & (d.s.high - 1);
- *rem = r.all;
- }
- return n.s.high >> __builtin_ctzll(d.s.high);
- }
- /* K K
- * ---
- * K 0
- */
- sr = __builtin_clzll(d.s.high) - __builtin_clzll(n.s.high);
- /* 0 <= sr <= n_udword_bits - 2 or sr large */
- if (sr > n_udword_bits - 2)
- {
- if (rem)
- *rem = n.all;
- return 0;
- }
- ++sr;
- /* 1 <= sr <= n_udword_bits - 1 */
- /* q.all = n.all << (n_utword_bits - sr); */
- q.s.low = 0;
- q.s.high = n.s.low << (n_udword_bits - sr);
- /* r.all = n.all >> sr; */
- r.s.high = n.s.high >> sr;
- r.s.low = (n.s.high << (n_udword_bits - sr)) | (n.s.low >> sr);
- }
- else /* d.s.low != 0 */
- {
- if (d.s.high == 0)
- {
- /* K X
- * ---
- * 0 K
- */
- if ((d.s.low & (d.s.low - 1)) == 0) /* if d is a power of 2 */
- {
- if (rem)
- *rem = n.s.low & (d.s.low - 1);
- if (d.s.low == 1)
- return n.all;
- sr = __builtin_ctzll(d.s.low);
- q.s.high = n.s.high >> sr;
- q.s.low = (n.s.high << (n_udword_bits - sr)) | (n.s.low >> sr);
- return q.all;
- }
- /* K X
- * ---
- * 0 K
- */
- sr = 1 + n_udword_bits + __builtin_clzll(d.s.low)
- - __builtin_clzll(n.s.high);
- /* 2 <= sr <= n_utword_bits - 1
- * q.all = n.all << (n_utword_bits - sr);
- * r.all = n.all >> sr;
- * if (sr == n_udword_bits)
- * {
- * q.s.low = 0;
- * q.s.high = n.s.low;
- * r.s.high = 0;
- * r.s.low = n.s.high;
- * }
- * else if (sr < n_udword_bits) // 2 <= sr <= n_udword_bits - 1
- * {
- * q.s.low = 0;
- * q.s.high = n.s.low << (n_udword_bits - sr);
- * r.s.high = n.s.high >> sr;
- * r.s.low = (n.s.high << (n_udword_bits - sr)) | (n.s.low >> sr);
- * }
- * else // n_udword_bits + 1 <= sr <= n_utword_bits - 1
- * {
- * q.s.low = n.s.low << (n_utword_bits - sr);
- * q.s.high = (n.s.high << (n_utword_bits - sr)) |
- * (n.s.low >> (sr - n_udword_bits));
- * r.s.high = 0;
- * r.s.low = n.s.high >> (sr - n_udword_bits);
- * }
- */
- q.s.low = (n.s.low << (n_utword_bits - sr)) &
- ((di_int)(int)(n_udword_bits - sr) >> (n_udword_bits-1));
- q.s.high = ((n.s.low << ( n_udword_bits - sr)) &
- ((di_int)(int)(sr - n_udword_bits - 1) >> (n_udword_bits-1))) |
- (((n.s.high << (n_utword_bits - sr)) |
- (n.s.low >> (sr - n_udword_bits))) &
- ((di_int)(int)(n_udword_bits - sr) >> (n_udword_bits-1)));
- r.s.high = (n.s.high >> sr) &
- ((di_int)(int)(sr - n_udword_bits) >> (n_udword_bits-1));
- r.s.low = ((n.s.high >> (sr - n_udword_bits)) &
- ((di_int)(int)(n_udword_bits - sr - 1) >> (n_udword_bits-1))) |
- (((n.s.high << (n_udword_bits - sr)) |
- (n.s.low >> sr)) &
- ((di_int)(int)(sr - n_udword_bits) >> (n_udword_bits-1)));
- }
- else
- {
- /* K X
- * ---
- * K K
- */
- sr = __builtin_clzll(d.s.high) - __builtin_clzll(n.s.high);
- /*0 <= sr <= n_udword_bits - 1 or sr large */
- if (sr > n_udword_bits - 1)
- {
- if (rem)
- *rem = n.all;
- return 0;
- }
- ++sr;
- /* 1 <= sr <= n_udword_bits */
- /* q.all = n.all << (n_utword_bits - sr); */
- q.s.low = 0;
- q.s.high = n.s.low << (n_udword_bits - sr);
- /* r.all = n.all >> sr;
- * if (sr < n_udword_bits)
- * {
- * r.s.high = n.s.high >> sr;
- * r.s.low = (n.s.high << (n_udword_bits - sr)) | (n.s.low >> sr);
- * }
- * else
- * {
- * r.s.high = 0;
- * r.s.low = n.s.high;
- * }
- */
- r.s.high = (n.s.high >> sr) &
- ((di_int)(int)(sr - n_udword_bits) >> (n_udword_bits-1));
- r.s.low = (n.s.high << (n_udword_bits - sr)) |
- ((n.s.low >> sr) &
- ((di_int)(int)(sr - n_udword_bits) >> (n_udword_bits-1)));
- }
- }
- /* Not a special case
- * q and r are initialized with:
- * q.all = n.all << (n_utword_bits - sr);
- * r.all = n.all >> sr;
- * 1 <= sr <= n_utword_bits - 1
- */
- su_int carry = 0;
- for (; sr > 0; --sr)
- {
- /* r:q = ((r:q) << 1) | carry */
- r.s.high = (r.s.high << 1) | (r.s.low >> (n_udword_bits - 1));
- r.s.low = (r.s.low << 1) | (q.s.high >> (n_udword_bits - 1));
- q.s.high = (q.s.high << 1) | (q.s.low >> (n_udword_bits - 1));
- q.s.low = (q.s.low << 1) | carry;
- /* carry = 0;
- * if (r.all >= d.all)
- * {
- * r.all -= d.all;
- * carry = 1;
- * }
- */
- const ti_int s = (ti_int)(d.all - r.all - 1) >> (n_utword_bits - 1);
- carry = s & 1;
- r.all -= d.all & s;
- }
- q.all = (q.all << 1) | carry;
- if (rem)
- *rem = r.all;
- return q.all;
-}
-
-#endif /* __x86_64 */
diff --git a/lib/udivti3.c b/lib/udivti3.c
deleted file mode 100644
index d9e1bb46f5c9..000000000000
--- a/lib/udivti3.c
+++ /dev/null
@@ -1,29 +0,0 @@
-/* ===-- udivti3.c - Implement __udivti3 -----------------------------------===
- *
- * 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 __udivti3 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-#if __x86_64
-
-tu_int __udivmodti4(tu_int a, tu_int b, tu_int* rem);
-
-/* Returns: a / b */
-
-tu_int
-__udivti3(tu_int a, tu_int b)
-{
- return __udivmodti4(a, b, 0);
-}
-
-#endif /* __x86_64 */
diff --git a/lib/umoddi3.c b/lib/umoddi3.c
deleted file mode 100644
index 3541ab6e91d8..000000000000
--- a/lib/umoddi3.c
+++ /dev/null
@@ -1,27 +0,0 @@
-/* ===-- umoddi3.c - Implement __umoddi3 -----------------------------------===
- *
- * 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 __umoddi3 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-du_int COMPILER_RT_ABI __udivmoddi4(du_int a, du_int b, du_int* rem);
-
-/* Returns: a % b */
-
-COMPILER_RT_ABI du_int
-__umoddi3(du_int a, du_int b)
-{
- du_int r;
- __udivmoddi4(a, b, &r);
- return r;
-}
diff --git a/lib/umodsi3.c b/lib/umodsi3.c
deleted file mode 100644
index aae741d896d2..000000000000
--- a/lib/umodsi3.c
+++ /dev/null
@@ -1,25 +0,0 @@
-/* ===-- umodsi3.c - Implement __umodsi3 -----------------------------------===
- *
- * 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 __umodsi3 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-/* Returns: a % b */
-
-su_int COMPILER_RT_ABI __udivsi3(su_int a, su_int b);
-
-COMPILER_RT_ABI su_int
-__umodsi3(su_int a, su_int b)
-{
- return a - __udivsi3(a, b) * b;
-}
diff --git a/lib/umodti3.c b/lib/umodti3.c
deleted file mode 100644
index 8ebe7f0dcf03..000000000000
--- a/lib/umodti3.c
+++ /dev/null
@@ -1,31 +0,0 @@
-/* ===-- umodti3.c - Implement __umodti3 -----------------------------------===
- *
- * 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 __umodti3 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
-
-#include "int_lib.h"
-
-#if __x86_64
-
-tu_int __udivmodti4(tu_int a, tu_int b, tu_int* rem);
-
-/* Returns: a % b */
-
-tu_int
-__umodti3(tu_int a, tu_int b)
-{
- tu_int r;
- __udivmodti4(a, b, &r);
- return r;
-}
-
-#endif
diff --git a/lib/x86_64/Makefile.mk b/lib/x86_64/Makefile.mk
deleted file mode 100644
index ee3f9ce8f14e..000000000000
--- a/lib/x86_64/Makefile.mk
+++ /dev/null
@@ -1,20 +0,0 @@
-#===- lib/x86_64/Makefile.mk -------------------------------*- Makefile -*--===#
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-#===------------------------------------------------------------------------===#
-
-ModuleName := builtins
-SubDirs :=
-OnlyArchs := x86_64
-
-AsmSources := $(foreach file,$(wildcard $(Dir)/*.S),$(notdir $(file)))
-Sources := $(foreach file,$(wildcard $(Dir)/*.c),$(notdir $(file)))
-ObjNames := $(Sources:%.c=%.o) $(AsmSources:%.S=%.o)
-Implementation := Optimized
-
-# FIXME: use automatic dependencies?
-Dependencies := $(wildcard lib/*.h $(Dir)/*.h)
diff --git a/lib/x86_64/floatundidf.S b/lib/x86_64/floatundidf.S
deleted file mode 100644
index 1be553b7d1e0..000000000000
--- a/lib/x86_64/floatundidf.S
+++ /dev/null
@@ -1,43 +0,0 @@
-//===-- floatundidf.S - Implement __floatundidf for x86_64 ----------------===//
-//
-// 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 __floatundidf for the compiler_rt library.
-//
-//===----------------------------------------------------------------------===//
-
-#include "../assembly.h"
-
-// double __floatundidf(du_int a);
-
-#ifdef __x86_64__
-
-#ifndef __ELF__
-.const
-#endif
-.align 4
-twop52: .quad 0x4330000000000000
-twop84_plus_twop52:
- .quad 0x4530000000100000
-twop84: .quad 0x4530000000000000
-
-#define REL_ADDR(_a) (_a)(%rip)
-
-.text
-.align 4
-DEFINE_COMPILERRT_FUNCTION(__floatundidf)
- movd %edi, %xmm0 // low 32 bits of a
- shrq $32, %rdi // high 32 bits of a
- orq REL_ADDR(twop84), %rdi // 0x1p84 + a_hi (no rounding occurs)
- orpd REL_ADDR(twop52), %xmm0 // 0x1p52 + a_lo (no rounding occurs)
- movd %rdi, %xmm1
- subsd REL_ADDR(twop84_plus_twop52), %xmm1 // a_hi - 0x1p52 (no rounding occurs)
- addsd %xmm1, %xmm0 // a_hi + a_lo (round happens here)
- ret
-
-#endif // __x86_64__
diff --git a/lib/x86_64/floatundisf.S b/lib/x86_64/floatundisf.S
deleted file mode 100644
index 89d3f07dfcc6..000000000000
--- a/lib/x86_64/floatundisf.S
+++ /dev/null
@@ -1,33 +0,0 @@
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
-
-#include "../assembly.h"
-
-// float __floatundisf(du_int a);
-
-#ifdef __x86_64__
-
-#ifndef __ELF__
-.literal4
-#endif
-two: .single 2.0
-
-#define REL_ADDR(_a) (_a)(%rip)
-
-.text
-.align 4
-DEFINE_COMPILERRT_FUNCTION(__floatundisf)
- movq $1, %rsi
- testq %rdi, %rdi
- js 1f
- cvtsi2ssq %rdi, %xmm0
- ret
-
-1: andq %rdi, %rsi
- shrq %rdi
- orq %rsi, %rdi
- cvtsi2ssq %rdi, %xmm0
- mulss REL_ADDR(two), %xmm0
- ret
-
-#endif // __x86_64__
diff --git a/lib/x86_64/floatundixf.S b/lib/x86_64/floatundixf.S
deleted file mode 100644
index a7243f2c545a..000000000000
--- a/lib/x86_64/floatundixf.S
+++ /dev/null
@@ -1,62 +0,0 @@
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
-
-#include "../assembly.h"
-
-// long double __floatundixf(du_int a);
-
-#ifdef __x86_64__
-
-#ifndef __ELF__
-.const
-#endif
-.align 4
-twop64: .quad 0x43f0000000000000
-
-#define REL_ADDR(_a) (_a)(%rip)
-
-.text
-.align 4
-DEFINE_COMPILERRT_FUNCTION(__floatundixf)
- movq %rdi, -8(%rsp)
- fildq -8(%rsp)
- test %rdi, %rdi
- js 1f
- ret
-1: faddl REL_ADDR(twop64)
- ret
-
-#endif // __x86_64__
-
-
-/* Branch-free implementation is ever so slightly slower, but more beautiful.
- It is likely superior for inlining, so I kept it around for future reference.
-
-#ifdef __x86_64__
-
-.const
-.align 4
-twop52: .quad 0x4330000000000000
-twop84_plus_twop52_neg:
- .quad 0xc530000000100000
-twop84: .quad 0x4530000000000000
-
-#define REL_ADDR(_a) (_a)(%rip)
-
-.text
-.align 4
-DEFINE_COMPILERRT_FUNCTION(__floatundixf)
- movl %edi, %esi // low 32 bits of input
- shrq $32, %rdi // hi 32 bits of input
- orq REL_ADDR(twop84), %rdi // 2^84 + hi (as a double)
- orq REL_ADDR(twop52), %rsi // 2^52 + lo (as a double)
- movq %rdi, -8(%rsp)
- movq %rsi, -16(%rsp)
- fldl REL_ADDR(twop84_plus_twop52_neg)
- faddl -8(%rsp) // hi - 2^52 (as double extended, no rounding occurs)
- faddl -16(%rsp) // hi + lo (as double extended)
- ret
-
-#endif // __x86_64__
-
-*/