aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2014-11-06 22:49:13 +0000
committerDimitry Andric <dim@FreeBSD.org>2014-11-06 22:49:13 +0000
commit8ef50bf3d1c287b5013c3168de77a462dfce3495 (patch)
tree3467f3372c1195b1546172d89af2205a50b1866d
parent11023dc647fd8f41418da90d59db138400d0f334 (diff)
downloadsrc-8ef50bf3d1c287b5013c3168de77a462dfce3495.tar.gz
src-8ef50bf3d1c287b5013c3168de77a462dfce3495.zip
Import compiler-rt release_34 branch r197381.vendor/compiler-rt/compiler-rt-r197381
Notes
Notes: svn path=/vendor/compiler-rt/dist/; revision=274201 svn path=/vendor/compiler-rt/compiler-rt-r197381/; revision=274202; tag=vendor/compiler-rt/compiler-rt-r197381
-rw-r--r--CMakeLists.txt114
-rw-r--r--SDKs/darwin/usr/include/errno.h17
-rw-r--r--SDKs/darwin/usr/include/string.h21
-rw-r--r--SDKs/darwin/usr/include/sys/errno.h31
-rw-r--r--cmake/Modules/AddCompilerRT.cmake66
-rw-r--r--cmake/Modules/CompilerRTUtils.cmake10
-rw-r--r--cmake/Modules/SanitizerUtils.cmake42
-rw-r--r--include/CMakeLists.txt3
-rw-r--r--include/sanitizer/common_interface_defs.h31
-rw-r--r--include/sanitizer/dfsan_interface.h87
-rw-r--r--include/sanitizer/linux_syscall_hooks.h3488
-rw-r--r--include/sanitizer/lsan_interface.h52
-rw-r--r--include/sanitizer/msan_interface.h73
-rw-r--r--lib/CMakeLists.txt66
-rw-r--r--lib/Makefile.mk1
-rw-r--r--lib/apple_versioning.c25
-rw-r--r--lib/arm/Makefile.mk2
-rw-r--r--lib/arm/comparesf2.S17
-rw-r--r--lib/arm/divmodsi4.S2
-rw-r--r--lib/arm/divsi3.S2
-rw-r--r--lib/arm/modsi3.S2
-rw-r--r--lib/arm/switch16.S3
-rw-r--r--lib/arm/switch32.S5
-rw-r--r--lib/arm/switch8.S3
-rw-r--r--lib/arm/switchu8.S3
-rw-r--r--lib/arm/udivmodsi4.S5
-rw-r--r--lib/arm/udivsi3.S5
-rw-r--r--lib/arm/umodsi3.S5
-rw-r--r--lib/asan/CMakeLists.txt116
-rw-r--r--lib/asan/asan.syms5
-rw-r--r--lib/asan/asan.syms.extra3
-rw-r--r--lib/asan/asan_allocator.h11
-rw-r--r--lib/asan/asan_allocator2.cc246
-rw-r--r--lib/asan/asan_blacklist.txt4
-rw-r--r--lib/asan/asan_dll_thunk.cc196
-rw-r--r--lib/asan/asan_fake_stack.cc295
-rw-r--r--lib/asan/asan_fake_stack.h196
-rw-r--r--lib/asan/asan_flags.h20
-rw-r--r--lib/asan/asan_globals.cc8
-rw-r--r--lib/asan/asan_intercepted_functions.h35
-rw-r--r--lib/asan/asan_interceptors.cc219
-rw-r--r--lib/asan/asan_interface_internal.h129
-rw-r--r--lib/asan/asan_internal.h1
-rw-r--r--lib/asan/asan_linux.cc11
-rw-r--r--lib/asan/asan_mac.cc28
-rw-r--r--lib/asan/asan_mac.h12
-rw-r--r--lib/asan/asan_malloc_linux.cc5
-rw-r--r--lib/asan/asan_malloc_mac.cc12
-rw-r--r--lib/asan/asan_malloc_win.cc16
-rw-r--r--lib/asan/asan_mapping.h34
-rw-r--r--lib/asan/asan_poisoning.cc63
-rw-r--r--lib/asan/asan_poisoning.h4
-rw-r--r--lib/asan/asan_posix.cc15
-rw-r--r--lib/asan/asan_report.cc196
-rw-r--r--lib/asan/asan_report.h6
-rw-r--r--lib/asan/asan_rtl.cc125
-rw-r--r--lib/asan/asan_stack.cc9
-rw-r--r--lib/asan/asan_stack.h29
-rw-r--r--lib/asan/asan_stats.cc126
-rw-r--r--lib/asan/asan_stats.h12
-rw-r--r--lib/asan/asan_thread.cc139
-rw-r--r--lib/asan/asan_thread.h70
-rw-r--r--lib/asan/asan_win.cc11
-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.txt28
-rw-r--r--lib/asan/lit_tests/Darwin/unset-insert-libraries-on-exec.cc20
-rw-r--r--lib/asan/lit_tests/Helpers/initialization-blacklist.txt3
-rw-r--r--lib/asan/lit_tests/Linux/interception_failure_test.cc26
-rw-r--r--lib/asan/lit_tests/Linux/interception_malloc_test.cc27
-rw-r--r--lib/asan/lit_tests/Linux/interception_test.cc26
-rw-r--r--lib/asan/lit_tests/Linux/zero-base-shadow.cc31
-rw-r--r--lib/asan/lit_tests/TestCases/Darwin/interface_symbols_darwin.c (renamed from lib/asan/lit_tests/Darwin/interface_symbols_darwin.c)6
-rw-r--r--lib/asan/lit_tests/TestCases/Darwin/lit.local.cfg (renamed from lib/asan/lit_tests/Darwin/lit.local.cfg)0
-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.cc (renamed from lib/asan/lit_tests/Darwin/reexec-insert-libraries-env.cc)4
-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.cc (renamed from lib/asan/lit_tests/Helpers/blacklist-extra.cc)0
-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.cc (renamed from lib/asan/lit_tests/Helpers/init-order-atexit-extra.cc)0
-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.cc (renamed from lib/asan/lit_tests/Helpers/initialization-blacklist-extra.cc)0
-rw-r--r--lib/asan/lit_tests/TestCases/Helpers/initialization-blacklist-extra2.cc (renamed from lib/asan/lit_tests/Helpers/initialization-blacklist-extra2.cc)0
-rw-r--r--lib/asan/lit_tests/TestCases/Helpers/initialization-blacklist.txt3
-rw-r--r--lib/asan/lit_tests/TestCases/Helpers/initialization-bug-extra.cc (renamed from lib/asan/lit_tests/Helpers/initialization-bug-extra.cc)0
-rw-r--r--lib/asan/lit_tests/TestCases/Helpers/initialization-bug-extra2.cc (renamed from lib/asan/lit_tests/Helpers/initialization-bug-extra2.cc)0
-rw-r--r--lib/asan/lit_tests/TestCases/Helpers/initialization-constexpr-extra.cc (renamed from lib/asan/lit_tests/Helpers/initialization-constexpr-extra.cc)0
-rw-r--r--lib/asan/lit_tests/TestCases/Helpers/initialization-nobug-extra.cc (renamed from lib/asan/lit_tests/Helpers/initialization-nobug-extra.cc)0
-rw-r--r--lib/asan/lit_tests/TestCases/Helpers/lit.local.cfg (renamed from lib/asan/lit_tests/Helpers/lit.local.cfg)0
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/asan_prelink_test.cc (renamed from lib/asan/lit_tests/Linux/asan_prelink_test.cc)10
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/clone_test.cc (renamed from lib/asan/lit_tests/Linux/clone_test.cc)12
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/coverage.cc45
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/glob.cc (renamed from lib/asan/lit_tests/Linux/glob.cc)7
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/glob_test_root/aa (renamed from lib/asan/lit_tests/Linux/glob_test_root/aa)0
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/glob_test_root/ab (renamed from lib/asan/lit_tests/Linux/glob_test_root/ab)0
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/glob_test_root/ba (renamed from lib/asan/lit_tests/Linux/glob_test_root/ba)0
-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.cc (renamed from lib/asan/lit_tests/Linux/heavy_uar_test.cc)11
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/initialization-bug-any-order.cc (renamed from lib/asan/lit_tests/Linux/initialization-bug-any-order.cc)10
-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.c (renamed from lib/asan/lit_tests/Linux/interface_symbols_linux.c)5
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/lit.local.cfg (renamed from lib/asan/lit_tests/Linux/lit.local.cfg)0
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/malloc-in-qsort.cc (renamed from lib/asan/lit_tests/Linux/malloc-in-qsort.cc)8
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/malloc_delete_mismatch.cc (renamed from lib/asan/lit_tests/Linux/malloc_delete_mismatch.cc)13
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/overflow-in-qsort.cc (renamed from lib/asan/lit_tests/Linux/overflow-in-qsort.cc)6
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/preinit_test.cc (renamed from lib/asan/lit_tests/Linux/preinit_test.cc)0
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/ptrace.cc52
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/rlimit_mmap_test.cc (renamed from lib/asan/lit_tests/Linux/rlimit_mmap_test.cc)2
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/swapcontext_test.cc (renamed from lib/asan/lit_tests/Linux/swapcontext_test.cc)12
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/syscalls.cc (renamed from lib/asan/lit_tests/Linux/syscalls.cc)6
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/time_null_regtest.cc (renamed from lib/asan/lit_tests/Linux/time_null_regtest.cc)2
-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.cc (renamed from lib/asan/lit_tests/SharedLibs/darwin-dummy-shared-lib-so.cc)0
-rw-r--r--lib/asan/lit_tests/TestCases/SharedLibs/dlclose-test-so.cc (renamed from lib/asan/lit_tests/SharedLibs/dlclose-test-so.cc)0
-rw-r--r--lib/asan/lit_tests/TestCases/SharedLibs/init-order-dlopen-so.cc (renamed from lib/asan/lit_tests/SharedLibs/init-order-dlopen-so.cc)2
-rw-r--r--lib/asan/lit_tests/TestCases/SharedLibs/lit.local.cfg (renamed from lib/asan/lit_tests/SharedLibs/lit.local.cfg)0
-rw-r--r--lib/asan/lit_tests/TestCases/SharedLibs/shared-lib-test-so.cc (renamed from lib/asan/lit_tests/SharedLibs/shared-lib-test-so.cc)5
-rw-r--r--lib/asan/lit_tests/TestCases/allocator_returns_null.cc81
-rw-r--r--lib/asan/lit_tests/TestCases/allow_user_segv.cc (renamed from lib/asan/lit_tests/allow_user_segv.cc)6
-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.cc (renamed from lib/asan/lit_tests/blacklist.cc)22
-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.cc (renamed from lib/asan/lit_tests/deep_stack_uaf.cc)9
-rw-r--r--lib/asan/lit_tests/TestCases/deep_tail_call.cc20
-rw-r--r--lib/asan/lit_tests/TestCases/deep_thread_stack.cc (renamed from lib/asan/lit_tests/deep_thread_stack.cc)12
-rw-r--r--lib/asan/lit_tests/TestCases/default_blacklist.cc (renamed from lib/asan/lit_tests/default_blacklist.cc)0
-rw-r--r--lib/asan/lit_tests/TestCases/default_options.cc (renamed from lib/asan/lit_tests/default_options.cc)0
-rw-r--r--lib/asan/lit_tests/TestCases/dlclose-test.cc (renamed from lib/asan/lit_tests/dlclose-test.cc)28
-rw-r--r--lib/asan/lit_tests/TestCases/double-free.cc25
-rw-r--r--lib/asan/lit_tests/TestCases/force_inline_opt0.cc (renamed from lib/asan/lit_tests/force_inline_opt0.cc)4
-rw-r--r--lib/asan/lit_tests/TestCases/free_hook_realloc.cc32
-rw-r--r--lib/asan/lit_tests/TestCases/global-demangle.cc (renamed from lib/asan/lit_tests/global-demangle.cc)3
-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.cc (renamed from lib/asan/lit_tests/huge_negative_hea_oob.cc)4
-rw-r--r--lib/asan/lit_tests/TestCases/init-order-atexit.cc (renamed from lib/asan/lit_tests/init-order-atexit.cc)4
-rw-r--r--lib/asan/lit_tests/TestCases/init-order-dlopen.cc (renamed from lib/asan/lit_tests/init-order-dlopen.cc)15
-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.cc (renamed from lib/asan/lit_tests/initialization-bug.cc)8
-rw-r--r--lib/asan/lit_tests/TestCases/initialization-constexpr.cc31
-rw-r--r--lib/asan/lit_tests/TestCases/initialization-nobug.cc (renamed from lib/asan/lit_tests/initialization-nobug.cc)16
-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.cc (renamed from lib/asan/lit_tests/invalid-free.cc)9
-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.cc (renamed from lib/asan/lit_tests/log-path_test.cc)0
-rw-r--r--lib/asan/lit_tests/TestCases/log_path_fork_test.cc.disabled (renamed from lib/asan/lit_tests/log_path_fork_test.cc.disabled)0
-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.cc (renamed from lib/asan/lit_tests/malloc_fill.cc)2
-rw-r--r--lib/asan/lit_tests/TestCases/malloc_hook.cc (renamed from lib/asan/lit_tests/malloc_hook.cc)16
-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.cc (renamed from lib/asan/lit_tests/on_error_callback.cc)2
-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.c (renamed from lib/asan/lit_tests/sanity_check_pure_c.c)8
-rw-r--r--lib/asan/lit_tests/TestCases/shared-lib-test.cc42
-rw-r--r--lib/asan/lit_tests/TestCases/sleep_before_dying.c (renamed from lib/asan/lit_tests/sleep_before_dying.c)4
-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.cc (renamed from lib/asan/lit_tests/stack-frame-demangle.cc)2
-rw-r--r--lib/asan/lit_tests/TestCases/stack-oob-frames.cc (renamed from lib/asan/lit_tests/stack-oob-frames.cc)10
-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.c (renamed from lib/asan/lit_tests/strip_path_prefix.c)4
-rw-r--r--lib/asan/lit_tests/TestCases/strncpy-overflow.cc28
-rw-r--r--lib/asan/lit_tests/TestCases/symbolize_callback.cc (renamed from lib/asan/lit_tests/symbolize_callback.cc)2
-rw-r--r--lib/asan/lit_tests/TestCases/throw_call_test.cc (renamed from lib/asan/lit_tests/throw_call_test.cc)0
-rw-r--r--lib/asan/lit_tests/TestCases/throw_invoke_test.cc (renamed from lib/asan/lit_tests/throw_invoke_test.cc)0
-rw-r--r--lib/asan/lit_tests/TestCases/time_interceptor.cc (renamed from lib/asan/lit_tests/time_interceptor.cc)2
-rw-r--r--lib/asan/lit_tests/TestCases/uar_and_exceptions.cc40
-rw-r--r--lib/asan/lit_tests/TestCases/unaligned_loads_and_stores.cc (renamed from lib/asan/lit_tests/unaligned_loads_and_stores.cc)22
-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.cc (renamed from lib/asan/lit_tests/use-after-poison.cc)2
-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.cc (renamed from lib/asan/lit_tests/use-after-scope-inlined.cc)7
-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.cfg26
-rw-r--r--lib/asan/lit_tests/Unit/lit.site.cfg.in23
-rw-r--r--lib/asan/lit_tests/deep_tail_call.cc24
-rw-r--r--lib/asan/lit_tests/double-free.cc18
-rw-r--r--lib/asan/lit_tests/global-overflow.cc25
-rw-r--r--lib/asan/lit_tests/heap-overflow.cc36
-rw-r--r--lib/asan/lit_tests/initialization-blacklist.cc47
-rw-r--r--lib/asan/lit_tests/initialization-constexpr.cc43
-rw-r--r--lib/asan/lit_tests/interface_test.cc8
-rw-r--r--lib/asan/lit_tests/large_func_test.cc63
-rw-r--r--lib/asan/lit_tests/lit.cfg83
-rw-r--r--lib/asan/lit_tests/memcmp_strict_test.cc16
-rw-r--r--lib/asan/lit_tests/memcmp_test.cc19
-rw-r--r--lib/asan/lit_tests/null_deref.cc31
-rw-r--r--lib/asan/lit_tests/partial_right.cc17
-rw-r--r--lib/asan/lit_tests/shared-lib-test.cc54
-rw-r--r--lib/asan/lit_tests/stack-overflow.cc20
-rw-r--r--lib/asan/lit_tests/stack-use-after-return.cc45
-rw-r--r--lib/asan/lit_tests/strncpy-overflow.cc38
-rw-r--r--lib/asan/lit_tests/use-after-free-right.cc46
-rw-r--r--lib/asan/lit_tests/use-after-free.cc43
-rw-r--r--lib/asan/lit_tests/wait.cc77
-rwxr-xr-xlib/asan/scripts/asan_symbolize.py63
-rw-r--r--lib/asan/tests/CMakeLists.txt167
-rw-r--r--lib/asan/tests/asan_fake_stack_test.cc150
-rw-r--r--lib/asan/tests/asan_interface_test.cc426
-rw-r--r--lib/asan/tests/asan_mac_test_helpers.mm39
-rw-r--r--lib/asan/tests/asan_noinst_test.cc645
-rw-r--r--lib/asan/tests/asan_str_test.cc16
-rw-r--r--lib/asan/tests/asan_test.cc45
-rw-r--r--lib/asan/tests/asan_test_utils.h4
-rw-r--r--lib/dfsan/CMakeLists.txt44
-rw-r--r--lib/dfsan/Makefile.mk23
-rw-r--r--lib/dfsan/dfsan.cc265
-rw-r--r--lib/dfsan/dfsan.h67
-rw-r--r--lib/dfsan/dfsan.syms.extra3
-rw-r--r--lib/dfsan/dfsan_custom.cc341
-rw-r--r--lib/dfsan/dfsan_interceptors.cc44
-rw-r--r--lib/dfsan/done_abilist.txt127
-rw-r--r--lib/dfsan/libc_ubuntu1204_abilist.txt3685
-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.py84
-rw-r--r--lib/eprintf.c2
-rw-r--r--lib/int_endianness.h8
-rw-r--r--lib/int_util.c9
-rw-r--r--lib/interception/CMakeLists.txt10
-rw-r--r--lib/interception/interception.h13
-rw-r--r--lib/interception/interception_linux.cc8
-rw-r--r--lib/interception/interception_linux.h10
-rw-r--r--lib/interception/interception_mac.h1
-rw-r--r--lib/interception/interception_win.h3
-rw-r--r--lib/lit.common.cfg20
-rw-r--r--lib/lit.common.configured.in (renamed from lib/asan/lit_tests/lit.site.cfg.in)13
-rw-r--r--lib/lit.common.unit.cfg9
-rw-r--r--lib/lit.common.unit.configured.in23
-rw-r--r--lib/lsan/CMakeLists.txt21
-rw-r--r--lib/lsan/Makefile.mk13
-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.txt25
-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.cfg (renamed from lib/lsan/lit_tests/SharedLibs/lit.local.cfg)0
-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.cc (renamed from lib/lsan/lit_tests/use_globals_initialized.cc)10
-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.cfg26
-rw-r--r--lib/lsan/lit_tests/Unit/lit.site.cfg.in21
-rw-r--r--lib/lsan/lit_tests/lit.cfg50
-rw-r--r--lib/lsan/lit_tests/lit.common.cfg43
-rw-r--r--lib/lsan/lit_tests/lit.site.cfg.in20
-rw-r--r--lib/lsan/lsan.cc36
-rw-r--r--lib/lsan/lsan.h6
-rw-r--r--lib/lsan/lsan_allocator.cc80
-rw-r--r--lib/lsan/lsan_common.cc449
-rw-r--r--lib/lsan/lsan_common.h120
-rw-r--r--lib/lsan/lsan_common_linux.cc52
-rw-r--r--lib/lsan/lsan_interceptors.cc125
-rw-r--r--lib/lsan/lsan_preinit.cc26
-rw-r--r--lib/lsan/lsan_thread.cc9
-rw-r--r--lib/lsan/lsan_thread.h2
-rw-r--r--lib/lsan/tests/CMakeLists.txt39
-rw-r--r--lib/lsan/tests/lsan_dummy_unittest.cc22
-rw-r--r--lib/lsan/tests/lsan_testlib.cc4
-rw-r--r--lib/msan/CMakeLists.txt15
-rw-r--r--lib/msan/lit_tests/CMakeLists.txt19
-rw-r--r--lib/msan/lit_tests/Linux/glob.cc1
-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/syscalls.cc50
-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.cfg26
-rw-r--r--lib/msan/lit_tests/Unit/lit.site.cfg.in20
-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/cxa_atexit.cc28
-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.cc8
-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.cc10
-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.cfg41
-rw-r--r--lib/msan/lit_tests/lit.site.cfg.in21
-rw-r--r--lib/msan/lit_tests/malloc_hook.cc36
-rw-r--r--lib/msan/lit_tests/no_sanitize_memory_prop.cc2
-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/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.cc9
-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.cc199
-rw-r--r--lib/msan/msan.h38
-rw-r--r--lib/msan/msan.syms5
-rw-r--r--lib/msan/msan.syms.extra1
-rw-r--r--lib/msan/msan_allocator.cc99
-rw-r--r--lib/msan/msan_flags.h3
-rw-r--r--lib/msan/msan_interceptors.cc707
-rw-r--r--lib/msan/msan_interface_internal.h55
-rw-r--r--lib/msan/msan_linux.cc44
-rw-r--r--lib/msan/msan_new_delete.cc3
-rw-r--r--lib/msan/msan_report.cc58
-rw-r--r--lib/msan/tests/CMakeLists.txt4
-rw-r--r--lib/msan/tests/msan_test.cc1281
-rw-r--r--lib/msandr/README.txt9
-rw-r--r--lib/msandr/msandr.cc203
-rw-r--r--lib/profile/CMakeLists.txt6
-rw-r--r--lib/profile/GCDAProfiling.c127
-rw-r--r--lib/sanitizer_common/CMakeLists.txt51
-rw-r--r--lib/sanitizer_common/sanitizer_allocator.cc105
-rw-r--r--lib/sanitizer_common/sanitizer_allocator.h164
-rw-r--r--lib/sanitizer_common/sanitizer_allocator_internal.h64
-rw-r--r--lib/sanitizer_common/sanitizer_atomic_clang.h15
-rw-r--r--lib/sanitizer_common/sanitizer_common.cc176
-rw-r--r--lib/sanitizer_common/sanitizer_common.h146
-rw-r--r--lib/sanitizer_common/sanitizer_common_interceptors.inc2332
-rwxr-xr-xlib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc568
-rw-r--r--lib/sanitizer_common/sanitizer_common_interceptors_scanf.inc4
-rw-r--r--lib/sanitizer_common/sanitizer_common_libcdep.cc16
-rw-r--r--lib/sanitizer_common/sanitizer_common_syscalls.inc2723
-rw-r--r--lib/sanitizer_common/sanitizer_coverage.cc113
-rw-r--r--lib/sanitizer_common/sanitizer_flags.cc35
-rw-r--r--lib/sanitizer_common/sanitizer_flags.h24
-rw-r--r--lib/sanitizer_common/sanitizer_internal_defs.h60
-rw-r--r--lib/sanitizer_common/sanitizer_libc.cc11
-rw-r--r--lib/sanitizer_common/sanitizer_libc.h1
-rw-r--r--lib/sanitizer_common/sanitizer_libignore.cc105
-rw-r--r--lib/sanitizer_common/sanitizer_libignore.h84
-rw-r--r--lib/sanitizer_common/sanitizer_linux.cc261
-rw-r--r--lib/sanitizer_common/sanitizer_linux.h27
-rw-r--r--lib/sanitizer_common/sanitizer_linux_libcdep.cc151
-rw-r--r--lib/sanitizer_common/sanitizer_mac.cc49
-rw-r--r--lib/sanitizer_common/sanitizer_mutex.h4
-rw-r--r--lib/sanitizer_common/sanitizer_placement_new.h10
-rw-r--r--lib/sanitizer_common/sanitizer_platform.h7
-rw-r--r--lib/sanitizer_common/sanitizer_platform_interceptors.h95
-rw-r--r--lib/sanitizer_common/sanitizer_platform_limits_linux.cc95
-rw-r--r--lib/sanitizer_common/sanitizer_platform_limits_posix.cc924
-rw-r--r--lib/sanitizer_common/sanitizer_platform_limits_posix.h920
-rw-r--r--lib/sanitizer_common/sanitizer_posix.cc89
-rw-r--r--lib/sanitizer_common/sanitizer_posix_libcdep.cc22
-rw-r--r--lib/sanitizer_common/sanitizer_printf.cc98
-rw-r--r--lib/sanitizer_common/sanitizer_procmaps.h15
-rw-r--r--lib/sanitizer_common/sanitizer_quarantine.h13
-rw-r--r--lib/sanitizer_common/sanitizer_report_decorator.h2
-rw-r--r--lib/sanitizer_common/sanitizer_stackdepot.cc34
-rw-r--r--lib/sanitizer_common/sanitizer_stackdepot.h26
-rw-r--r--lib/sanitizer_common/sanitizer_stacktrace.cc204
-rw-r--r--lib/sanitizer_common/sanitizer_stacktrace.h58
-rw-r--r--lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc28
-rw-r--r--lib/sanitizer_common/sanitizer_stoptheworld.h2
-rw-r--r--lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc216
-rw-r--r--lib/sanitizer_common/sanitizer_suppressions.cc153
-rw-r--r--lib/sanitizer_common/sanitizer_suppressions.h61
-rw-r--r--lib/sanitizer_common/sanitizer_symbolizer.cc63
-rw-r--r--lib/sanitizer_common/sanitizer_symbolizer.h149
-rw-r--r--lib/sanitizer_common/sanitizer_symbolizer_itanium.cc44
-rw-r--r--lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc446
-rw-r--r--lib/sanitizer_common/sanitizer_symbolizer_linux_libcdep.cc227
-rw-r--r--lib/sanitizer_common/sanitizer_symbolizer_mac.cc40
-rw-r--r--lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc601
-rw-r--r--lib/sanitizer_common/sanitizer_symbolizer_win.cc21
-rw-r--r--lib/sanitizer_common/sanitizer_syscall_linux_x86_64.inc16
-rw-r--r--lib/sanitizer_common/sanitizer_thread_registry.cc14
-rw-r--r--lib/sanitizer_common/sanitizer_thread_registry.h1
-rw-r--r--lib/sanitizer_common/sanitizer_win.cc71
-rwxr-xr-xlib/sanitizer_common/scripts/check_lint.sh97
-rwxr-xr-xlib/sanitizer_common/scripts/cpplint.py4024
-rwxr-xr-xlib/sanitizer_common/scripts/gen_dynamic_list.py85
-rwxr-xr-xlib/sanitizer_common/scripts/sancov.py56
-rw-r--r--lib/sanitizer_common/tests/CMakeLists.txt30
-rw-r--r--lib/sanitizer_common/tests/lit.cfg28
-rw-r--r--lib/sanitizer_common/tests/lit.site.cfg.in20
-rw-r--r--lib/sanitizer_common/tests/sanitizer_allocator_test.cc91
-rw-r--r--lib/sanitizer_common/tests/sanitizer_common_test.cc102
-rw-r--r--lib/sanitizer_common/tests/sanitizer_ioctl_test.cc77
-rw-r--r--lib/sanitizer_common/tests/sanitizer_libc_test.cc7
-rw-r--r--lib/sanitizer_common/tests/sanitizer_linux_test.cc37
-rw-r--r--lib/sanitizer_common/tests/sanitizer_mutex_test.cc1
-rw-r--r--lib/sanitizer_common/tests/sanitizer_nolibc_test.cc31
-rw-r--r--lib/sanitizer_common/tests/sanitizer_nolibc_test_main.cc19
-rw-r--r--lib/sanitizer_common/tests/sanitizer_posix_test.cc62
-rw-r--r--lib/sanitizer_common/tests/sanitizer_printf_test.cc32
-rw-r--r--lib/sanitizer_common/tests/sanitizer_procmaps_test.cc30
-rw-r--r--lib/sanitizer_common/tests/sanitizer_scanf_interceptor_test.cc2
-rw-r--r--lib/sanitizer_common/tests/sanitizer_stackdepot_test.cc23
-rw-r--r--lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc31
-rw-r--r--lib/sanitizer_common/tests/sanitizer_stoptheworld_test.cc4
-rw-r--r--lib/sanitizer_common/tests/sanitizer_suppressions_test.cc152
-rw-r--r--lib/sanitizer_common/tests/sanitizer_test_main.cc3
-rw-r--r--lib/sanitizer_common/tests/sanitizer_test_utils.h8
-rw-r--r--lib/sanitizer_common/tests/sanitizer_thread_registry_test.cc3
-rw-r--r--lib/tsan/CMakeLists.txt64
-rw-r--r--lib/tsan/Makefile.old9
-rwxr-xr-xlib/tsan/check_cmake.sh20
-rwxr-xr-xlib/tsan/go/buildgo.sh7
-rw-r--r--lib/tsan/go/test.c20
-rw-r--r--lib/tsan/go/tsan_go.cc40
-rw-r--r--lib/tsan/lit_tests/CMakeLists.txt4
-rw-r--r--lib/tsan/lit_tests/Unit/lit.cfg21
-rw-r--r--lib/tsan/lit_tests/Unit/lit.site.cfg.in20
-rw-r--r--lib/tsan/lit_tests/allocator_returns_null.cc64
-rw-r--r--lib/tsan/lit_tests/atomic_free.cc2
-rw-r--r--lib/tsan/lit_tests/atomic_free2.cc2
-rw-r--r--lib/tsan/lit_tests/atomic_race.cc2
-rw-r--r--lib/tsan/lit_tests/atomic_stack.cc2
-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_norace2.cc30
-rw-r--r--lib/tsan/lit_tests/fd_location.cc2
-rw-r--r--lib/tsan/lit_tests/fd_pipe_race.cc2
-rw-r--r--lib/tsan/lit_tests/fd_stdout_race.cc2
-rw-r--r--lib/tsan/lit_tests/free_race.c23
-rw-r--r--lib/tsan/lit_tests/free_race.c.supp2
-rw-r--r--lib/tsan/lit_tests/free_race2.c2
-rw-r--r--lib/tsan/lit_tests/global_race.cc25
-rw-r--r--lib/tsan/lit_tests/halt_on_error.cc25
-rw-r--r--lib/tsan/lit_tests/heap_race.cc2
-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_sync.cc30
-rw-r--r--lib/tsan/lit_tests/inlined_memcpy_race.cc2
-rw-r--r--lib/tsan/lit_tests/java.h1
-rw-r--r--lib/tsan/lit_tests/java_lock_rec_race.cc2
-rw-r--r--lib/tsan/lit_tests/java_race.cc2
-rw-r--r--lib/tsan/lit_tests/java_race_move.cc2
-rw-r--r--lib/tsan/lit_tests/lit.cfg40
-rw-r--r--lib/tsan/lit_tests/lit.site.cfg.in20
-rw-r--r--lib/tsan/lit_tests/load_shared_lib.cc2
-rw-r--r--lib/tsan/lit_tests/longjmp3.cc2
-rw-r--r--lib/tsan/lit_tests/longjmp4.cc2
-rw-r--r--lib/tsan/lit_tests/malloc_overflow.cc3
-rw-r--r--lib/tsan/lit_tests/malloc_stack.cc2
-rw-r--r--lib/tsan/lit_tests/memcpy_race.cc2
-rw-r--r--lib/tsan/lit_tests/mop_with_offset.cc2
-rw-r--r--lib/tsan/lit_tests/mop_with_offset2.cc2
-rw-r--r--lib/tsan/lit_tests/mutex_destroy_locked.cc2
-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.cc2
-rw-r--r--lib/tsan/lit_tests/mutexset2.cc2
-rw-r--r--lib/tsan/lit_tests/mutexset3.cc2
-rw-r--r--lib/tsan/lit_tests/mutexset4.cc2
-rw-r--r--lib/tsan/lit_tests/mutexset5.cc2
-rw-r--r--lib/tsan/lit_tests/mutexset6.cc2
-rw-r--r--lib/tsan/lit_tests/mutexset7.cc2
-rw-r--r--lib/tsan/lit_tests/mutexset8.cc2
-rw-r--r--lib/tsan/lit_tests/oob_race.cc2
-rw-r--r--lib/tsan/lit_tests/race_on_barrier.c2
-rw-r--r--lib/tsan/lit_tests/race_on_barrier2.c2
-rw-r--r--lib/tsan/lit_tests/race_on_heap.cc2
-rw-r--r--lib/tsan/lit_tests/race_on_mutex.c2
-rw-r--r--lib/tsan/lit_tests/race_on_mutex2.c2
-rw-r--r--lib/tsan/lit_tests/race_on_read.cc2
-rw-r--r--lib/tsan/lit_tests/race_on_write.cc2
-rw-r--r--lib/tsan/lit_tests/race_with_finished_thread.cc2
-rw-r--r--lib/tsan/lit_tests/signal_errno.cc2
-rw-r--r--lib/tsan/lit_tests/signal_malloc.cc2
-rw-r--r--lib/tsan/lit_tests/sigsuspend.cc38
-rw-r--r--lib/tsan/lit_tests/simple_race.c2
-rw-r--r--lib/tsan/lit_tests/simple_race.cc2
-rw-r--r--lib/tsan/lit_tests/simple_stack.c2
-rw-r--r--lib/tsan/lit_tests/simple_stack2.cc2
-rw-r--r--lib/tsan/lit_tests/sleep_sync.cc2
-rw-r--r--lib/tsan/lit_tests/sleep_sync2.cc2
-rw-r--r--lib/tsan/lit_tests/stack_race.cc2
-rw-r--r--lib/tsan/lit_tests/stack_race2.cc2
-rw-r--r--lib/tsan/lit_tests/static_init3.cc2
-rw-r--r--lib/tsan/lit_tests/suppress_same_address.cc2
-rw-r--r--lib/tsan/lit_tests/suppress_same_stacks.cc2
-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.sh6
-rw-r--r--lib/tsan/lit_tests/thread_leak3.c2
-rw-r--r--lib/tsan/lit_tests/thread_leak5.c2
-rw-r--r--lib/tsan/lit_tests/thread_name.cc2
-rw-r--r--lib/tsan/lit_tests/thread_name2.cc32
-rw-r--r--lib/tsan/lit_tests/tiny_race.c12
-rw-r--r--lib/tsan/lit_tests/tls_race.cc2
-rw-r--r--lib/tsan/lit_tests/tls_race2.cc2
-rw-r--r--lib/tsan/lit_tests/unaligned_race.cc2
-rw-r--r--lib/tsan/lit_tests/vptr_harmful_race.cc2
-rw-r--r--lib/tsan/lit_tests/vptr_harmful_race2.cc2
-rw-r--r--lib/tsan/lit_tests/write_in_reader_lock.cc2
-rw-r--r--lib/tsan/rtl/CMakeLists.txt51
-rw-r--r--lib/tsan/rtl/tsan.syms5
-rw-r--r--lib/tsan/rtl/tsan.syms.extra14
-rw-r--r--lib/tsan/rtl/tsan_defs.h7
-rw-r--r--lib/tsan/rtl/tsan_fd.cc36
-rw-r--r--lib/tsan/rtl/tsan_flags.cc73
-rw-r--r--lib/tsan/rtl/tsan_flags.h19
-rw-r--r--lib/tsan/rtl/tsan_interceptors.cc573
-rw-r--r--lib/tsan/rtl/tsan_interface.cc42
-rw-r--r--lib/tsan/rtl/tsan_interface.h52
-rw-r--r--lib/tsan/rtl/tsan_interface_ann.cc26
-rw-r--r--lib/tsan/rtl/tsan_interface_ann.h4
-rw-r--r--lib/tsan/rtl/tsan_interface_atomic.cc73
-rw-r--r--lib/tsan/rtl/tsan_interface_java.cc4
-rw-r--r--lib/tsan/rtl/tsan_mman.cc24
-rw-r--r--lib/tsan/rtl/tsan_platform.h11
-rw-r--r--lib/tsan/rtl/tsan_platform_linux.cc101
-rw-r--r--lib/tsan/rtl/tsan_report.cc69
-rw-r--r--lib/tsan/rtl/tsan_rtl.cc101
-rw-r--r--lib/tsan/rtl/tsan_rtl.h40
-rw-r--r--lib/tsan/rtl/tsan_rtl_mutex.cc128
-rw-r--r--lib/tsan/rtl/tsan_rtl_report.cc67
-rw-r--r--lib/tsan/rtl/tsan_rtl_thread.cc56
-rw-r--r--lib/tsan/rtl/tsan_stat.cc105
-rw-r--r--lib/tsan/rtl/tsan_stat.h105
-rw-r--r--lib/tsan/rtl/tsan_suppressions.cc196
-rw-r--r--lib/tsan/rtl/tsan_suppressions.h21
-rw-r--r--lib/tsan/rtl/tsan_symbolize.cc100
-rw-r--r--lib/tsan/rtl/tsan_symbolize.h2
-rw-r--r--lib/tsan/rtl/tsan_symbolize_addr2line_linux.cc1
-rw-r--r--lib/tsan/rtl/tsan_sync.cc5
-rw-r--r--lib/tsan/rtl/tsan_trace.h5
-rw-r--r--lib/tsan/rtl/tsan_update_shadow_word_inl.h3
-rw-r--r--lib/tsan/tests/CMakeLists.txt56
-rw-r--r--lib/tsan/tests/rtl/CMakeLists.txt14
-rw-r--r--lib/tsan/tests/unit/CMakeLists.txt10
-rw-r--r--lib/tsan/tests/unit/tsan_mman_test.cc4
-rw-r--r--lib/tsan/tests/unit/tsan_stack_test.cc9
-rw-r--r--lib/tsan/tests/unit/tsan_suppressions_test.cc128
-rw-r--r--lib/tsan/tests/unit/tsan_unit_test_main.cc19
-rw-r--r--lib/ubsan/CMakeLists.txt19
-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.txt24
-rw-r--r--lib/ubsan/lit_tests/Integer/div-zero.cpp15
-rw-r--r--lib/ubsan/lit_tests/Integer/incdec-overflow.cpp16
-rw-r--r--lib/ubsan/lit_tests/Integer/shift.cpp37
-rw-r--r--lib/ubsan/lit_tests/Integer/uincdec-overflow.cpp16
-rw-r--r--lib/ubsan/lit_tests/Misc/bool.cpp11
-rw-r--r--lib/ubsan/lit_tests/TestCases/Float/cast-overflow.cpp (renamed from lib/ubsan/lit_tests/Float/cast-overflow.cpp)2
-rw-r--r--lib/ubsan/lit_tests/TestCases/Integer/add-overflow.cpp (renamed from lib/ubsan/lit_tests/Integer/add-overflow.cpp)6
-rw-r--r--lib/ubsan/lit_tests/TestCases/Integer/div-overflow.cpp (renamed from lib/ubsan/lit_tests/Integer/div-overflow.cpp)2
-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.cpp (renamed from lib/ubsan/lit_tests/Integer/mul-overflow.cpp)2
-rw-r--r--lib/ubsan/lit_tests/TestCases/Integer/negate-overflow.cpp (renamed from lib/ubsan/lit_tests/Integer/negate-overflow.cpp)4
-rw-r--r--lib/ubsan/lit_tests/TestCases/Integer/no-recover.cpp (renamed from lib/ubsan/lit_tests/Integer/no-recover.cpp)8
-rw-r--r--lib/ubsan/lit_tests/TestCases/Integer/shift.cpp37
-rw-r--r--lib/ubsan/lit_tests/TestCases/Integer/sub-overflow.cpp (renamed from lib/ubsan/lit_tests/Integer/sub-overflow.cpp)6
-rw-r--r--lib/ubsan/lit_tests/TestCases/Integer/uadd-overflow.cpp (renamed from lib/ubsan/lit_tests/Integer/uadd-overflow.cpp)8
-rw-r--r--lib/ubsan/lit_tests/TestCases/Integer/uincdec-overflow.cpp16
-rw-r--r--lib/ubsan/lit_tests/TestCases/Integer/umul-overflow.cpp (renamed from lib/ubsan/lit_tests/Integer/umul-overflow.cpp)2
-rw-r--r--lib/ubsan/lit_tests/TestCases/Integer/usub-overflow.cpp (renamed from lib/ubsan/lit_tests/Integer/usub-overflow.cpp)8
-rw-r--r--lib/ubsan/lit_tests/TestCases/Misc/bool.cpp10
-rw-r--r--lib/ubsan/lit_tests/TestCases/Misc/bounds.cpp (renamed from lib/ubsan/lit_tests/Misc/bounds.cpp)2
-rw-r--r--lib/ubsan/lit_tests/TestCases/Misc/deduplication.cpp (renamed from lib/ubsan/lit_tests/Misc/deduplication.cpp)2
-rw-r--r--lib/ubsan/lit_tests/TestCases/Misc/enum.cpp (renamed from lib/ubsan/lit_tests/Misc/enum.cpp)6
-rw-r--r--lib/ubsan/lit_tests/TestCases/Misc/missing_return.cpp (renamed from lib/ubsan/lit_tests/Misc/missing_return.cpp)2
-rw-r--r--lib/ubsan/lit_tests/TestCases/Misc/unreachable.cpp (renamed from lib/ubsan/lit_tests/Misc/unreachable.cpp)2
-rw-r--r--lib/ubsan/lit_tests/TestCases/Misc/vla.c (renamed from lib/ubsan/lit_tests/Misc/vla.c)0
-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.cpp (renamed from lib/ubsan/lit_tests/TypeCheck/misaligned.cpp)4
-rw-r--r--lib/ubsan/lit_tests/TestCases/TypeCheck/null.cpp (renamed from lib/ubsan/lit_tests/TypeCheck/null.cpp)2
-rw-r--r--lib/ubsan/lit_tests/TestCases/TypeCheck/vptr.cpp (renamed from lib/ubsan/lit_tests/TypeCheck/vptr.cpp)4
-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.cfg66
-rw-r--r--lib/ubsan/lit_tests/lit.common.cfg31
-rw-r--r--lib/ubsan/lit_tests/lit.site.cfg.in20
-rw-r--r--lib/ubsan/ubsan.syms1
-rw-r--r--lib/ubsan/ubsan.syms.extra1
-rw-r--r--lib/ubsan/ubsan_diag.cc34
-rw-r--r--lib/ubsan/ubsan_diag.h6
-rw-r--r--lib/ubsan/ubsan_handlers.cc31
-rw-r--r--lib/ubsan/ubsan_handlers.h11
-rw-r--r--lib/ubsan/ubsan_type_hash.cc16
-rw-r--r--make/AppleBI.mk46
-rw-r--r--make/platform/clang_darwin.mk49
-rw-r--r--make/platform/clang_darwin_embedded.mk250
-rw-r--r--make/platform/clang_linux.mk20
-rw-r--r--make/platform/darwin_bni.mk12
679 files changed, 36733 insertions, 7815 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a57751ce6f61..a4424086c696 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -15,6 +15,9 @@ include(LLVMParseArguments)
# runtime libraries.
cmake_minimum_required(VERSION 2.8.8)
+# Top level target used to build all compiler-rt libraries.
+add_custom_target(compiler-rt)
+
# Compute the Clang version from the LLVM version.
# FIXME: We should be able to reuse CLANG_VERSION variable calculated
# in Clang cmake files, instead of copying the rules here.
@@ -36,21 +39,24 @@ set(CMAKE_MODULE_PATH
include(AddCompilerRT)
set(COMPILER_RT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
+set(COMPILER_RT_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
# Setup custom SDK sysroots.
set(COMPILER_RT_DARWIN_SDK_SYSROOT ${COMPILER_RT_SOURCE_DIR}/SDKs/darwin)
set(COMPILER_RT_LINUX_SDK_SYSROOT ${COMPILER_RT_SOURCE_DIR}/SDKs/linux)
+include(SanitizerUtils)
# Detect whether the current target platform is 32-bit or 64-bit, and setup
# the correct commandline flags needed to attempt to target 32-bit and 64-bit.
-if(CMAKE_SIZEOF_VOID_P EQUAL 4 OR LLVM_BUILD_32_BITS)
+if (NOT CMAKE_SIZEOF_VOID_P EQUAL 4 AND
+ NOT CMAKE_SIZEOF_VOID_P EQUAL 8)
+ message(FATAL_ERROR "Please use architecture with 4 or 8 byte pointers.")
+endif()
+if (NOT MSVC)
set(TARGET_64_BIT_CFLAGS "-m64")
- set(TARGET_32_BIT_CFLAGS "")
+ set(TARGET_32_BIT_CFLAGS "-m32")
else()
- if(NOT CMAKE_SIZEOF_VOID_P EQUAL 8)
- message(FATAL_ERROR "Please use a sane architecture with 4 or 8 byte pointers.")
- endif()
set(TARGET_64_BIT_CFLAGS "")
- set(TARGET_32_BIT_CFLAGS "-m32")
+ set(TARGET_32_BIT_CFLAGS "")
endif()
# List of architectures we can target.
@@ -86,13 +92,12 @@ macro(test_target_arch arch)
endmacro()
if("${LLVM_NATIVE_ARCH}" STREQUAL "X86")
- test_target_arch(x86_64 ${TARGET_64_BIT_CFLAGS})
+ if (NOT MSVC)
+ test_target_arch(x86_64 ${TARGET_64_BIT_CFLAGS})
+ endif()
test_target_arch(i386 ${TARGET_32_BIT_CFLAGS})
elseif("${LLVM_NATIVE_ARCH}" STREQUAL "PowerPC")
- # Explicitly set -m flag on powerpc, because on ppc64 defaults for gcc and
- # clang are different.
- test_target_arch(powerpc64 "-m64")
- test_target_arch(powerpc "-m32")
+ test_target_arch(powerpc64 ${TARGET_64_BIT_CFLAGS})
endif()
# We only support running instrumented tests when we're not cross compiling
@@ -119,26 +124,43 @@ function(filter_available_targets out_var)
set(${out_var} ${archs} PARENT_SCOPE)
endfunction()
+option(COMPILER_RT_DEBUG "Build runtimes with full debug info" OFF)
+
+# COMPILER_RT_DEBUG_PYBOOL is used by lit.common.configured.in.
+pythonize_bool(COMPILER_RT_DEBUG)
+
# Provide some common commmandline flags for Sanitizer runtimes.
-set(SANITIZER_COMMON_CFLAGS
- -fPIC
- -fno-builtin
- -fno-exceptions
- -fomit-frame-pointer
- -funwind-tables
- -fno-stack-protector
- -Wno-gnu # Variadic macros with 0 arguments for ...
- -O3
- )
-if(NOT WIN32)
- list(APPEND SANITIZER_COMMON_CFLAGS -fvisibility=hidden)
-endif()
-# Build sanitizer runtimes with debug info.
-check_cxx_compiler_flag(-gline-tables-only SUPPORTS_GLINE_TABLES_ONLY_FLAG)
-if(SUPPORTS_GLINE_TABLES_ONLY_FLAG)
- list(APPEND SANITIZER_COMMON_CFLAGS -gline-tables-only)
+if (NOT MSVC)
+ set(SANITIZER_COMMON_CFLAGS
+ -fPIC
+ -fno-builtin
+ -fno-exceptions
+ -fomit-frame-pointer
+ -funwind-tables
+ -fno-stack-protector
+ -Wno-gnu # Variadic macros with 0 arguments for ...
+ -fvisibility=hidden
+ )
+ if (NOT COMPILER_RT_DEBUG)
+ list(APPEND SANITIZER_COMMON_CFLAGS -O3)
+ endif()
else()
- list(APPEND SANITIZER_COMMON_CFLAGS -g)
+ set(SANITIZER_COMMON_CFLAGS
+ /MT
+ /Zi
+ /Oy-
+ /GS-
+ /wd4722
+ )
+endif()
+# Build sanitizer runtimes with debug info. (MSVC gets /Zi above)
+if (NOT MSVC)
+ check_cxx_compiler_flag(-gline-tables-only SUPPORTS_GLINE_TABLES_ONLY_FLAG)
+ if(SUPPORTS_GLINE_TABLES_ONLY_FLAG AND NOT COMPILER_RT_DEBUG)
+ list(APPEND SANITIZER_COMMON_CFLAGS -gline-tables-only)
+ else()
+ list(APPEND SANITIZER_COMMON_CFLAGS -g)
+ endif()
endif()
# Warnings suppressions.
check_cxx_compiler_flag(-Wno-variadic-macros SUPPORTS_NO_VARIADIC_MACROS_FLAG)
@@ -155,30 +177,50 @@ check_cxx_compiler_flag(-Wno-non-virtual-dtor SUPPORTS_NO_NON_VIRTUAL_DTOR_FLAG)
if (SUPPORTS_NO_NON_VIRTUAL_DTOR_FLAG)
list(APPEND SANITIZER_COMMON_CFLAGS -Wno-non-virtual-dtor)
endif()
+check_cxx_compiler_flag(-Wglobal-constructors SUPPORTS_GLOBAL_CONSTRUCTORS_FLAG)
+# Not all sanitizers forbid global constructors.
-# Setup min Mac OS X version.
if(APPLE)
+ # Obtain the iOS Simulator SDK path from xcodebuild.
+ execute_process(
+ COMMAND xcodebuild -version -sdk iphonesimulator Path
+ OUTPUT_VARIABLE IOSSIM_SDK_DIR
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ )
+ set(SANITIZER_COMMON_SUPPORTED_DARWIN_OS osx)
+ if (IOSSIM_SDK_DIR)
+ list(APPEND SANITIZER_COMMON_SUPPORTED_DARWIN_OS iossim)
+ endif()
+
if(COMPILER_RT_USES_LIBCXX)
set(SANITIZER_MIN_OSX_VERSION 10.7)
else()
- set(SANITIZER_MIN_OSX_VERSION 10.5)
+ set(SANITIZER_MIN_OSX_VERSION 10.6)
endif()
- list(APPEND SANITIZER_COMMON_CFLAGS
- -mmacosx-version-min=${SANITIZER_MIN_OSX_VERSION})
+ set(DARWIN_osx_CFLAGS -mmacosx-version-min=${SANITIZER_MIN_OSX_VERSION})
+ set(DARWIN_iossim_CFLAGS
+ -mios-simulator-version-min=7.0 -isysroot ${IOSSIM_SDK_DIR})
+ set(DARWIN_osx_LINKFLAGS)
+ set(DARWIN_iossim_LINKFLAGS
+ -Wl,-ios_simulator_version_min,7.0.0
+ -mios-simulator-version-min=7.0
+ -isysroot ${IOSSIM_SDK_DIR})
endif()
# Architectures supported by Sanitizer runtimes. Specific sanitizers may
# support only subset of these (e.g. TSan works on x86_64 only).
filter_available_targets(SANITIZER_COMMON_SUPPORTED_ARCH
- x86_64 i386 powerpc64 powerpc)
+ x86_64 i386 powerpc64)
-# Add the public header's directory to the includes for all of compiler-rt.
-include_directories(include)
add_subdirectory(include)
set(SANITIZER_COMMON_LIT_TEST_DEPS
clang clang-headers FileCheck count not llvm-nm llvm-symbolizer
compiler-rt-headers)
+# Check code style when running lit tests for sanitizers.
+if(UNIX)
+ list(APPEND SANITIZER_COMMON_LIT_TEST_DEPS SanitizerLintCheck)
+endif()
add_subdirectory(lib)
diff --git a/SDKs/darwin/usr/include/errno.h b/SDKs/darwin/usr/include/errno.h
new file mode 100644
index 000000000000..f06e53713398
--- /dev/null
+++ b/SDKs/darwin/usr/include/errno.h
@@ -0,0 +1,17 @@
+/* ===-- errno.h - stub SDK 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 is a stub SDK header file. This file is not part of the interface of
+ * this library nor an official version of the appropriate SDK header. It is
+ * intended only to stub the features of this header required by compiler-rt.
+ *
+ * ===-----------------------------------------------------------------------===
+ */
+
+#include <sys/errno.h>
diff --git a/SDKs/darwin/usr/include/string.h b/SDKs/darwin/usr/include/string.h
index c7da1f57ba57..c6ab5d8e5876 100644
--- a/SDKs/darwin/usr/include/string.h
+++ b/SDKs/darwin/usr/include/string.h
@@ -28,4 +28,25 @@ char *strdup(const char *);
size_t strlen(const char *);
char *strncpy(char *, const char *, size_t);
+/* Determine the appropriate strerror() function. */
+#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__)
+# if defined(__i386)
+# define __STRERROR_NAME "_strerror$UNIX2003"
+# elif defined(__x86_64__) || defined(__arm)
+# define __STRERROR_NAME "_strerror"
+# else
+# error "unrecognized architecture for targetting OS X"
+# endif
+#elif defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__)
+# if defined(__i386) || defined (__x86_64) || defined(__arm)
+# define __STRERROR_NAME "_strerror"
+# else
+# error "unrecognized architecture for targetting iOS"
+# endif
+#else
+# error "unrecognized architecture for targetting Darwin"
+#endif
+
+char *strerror(int) __asm(__STRERROR_NAME);
+
#endif /* __STRING_H__ */
diff --git a/SDKs/darwin/usr/include/sys/errno.h b/SDKs/darwin/usr/include/sys/errno.h
new file mode 100644
index 000000000000..4befe385535a
--- /dev/null
+++ b/SDKs/darwin/usr/include/sys/errno.h
@@ -0,0 +1,31 @@
+/* ===-- errno.h - stub SDK 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 is a stub SDK header file. This file is not part of the interface of
+ * this library nor an official version of the appropriate SDK header. It is
+ * intended only to stub the features of this header required by compiler-rt.
+ *
+ * ===-----------------------------------------------------------------------===
+ */
+
+#ifndef _SYS_ERRNO_H_
+#define _SYS_ERRNO_H_
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+extern int *__error(void);
+#define errno (*__error())
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/cmake/Modules/AddCompilerRT.cmake b/cmake/Modules/AddCompilerRT.cmake
index bf114a401ef0..fd117ac522ca 100644
--- a/cmake/Modules/AddCompilerRT.cmake
+++ b/cmake/Modules/AddCompilerRT.cmake
@@ -6,29 +6,35 @@ include(CompilerRTUtils)
# with name "<name>.<arch>" if architecture can be targeted.
# add_compiler_rt_object_library(<name> <arch>
# SOURCES <source files>
-# CFLAGS <compile flags>)
+# CFLAGS <compile flags>
+# DEFS <compile definitions>)
macro(add_compiler_rt_object_library name arch)
if(CAN_TARGET_${arch})
- parse_arguments(LIB "SOURCES;CFLAGS" "" ${ARGN})
+ parse_arguments(LIB "SOURCES;CFLAGS;DEFS" "" ${ARGN})
add_library(${name}.${arch} OBJECT ${LIB_SOURCES})
set_target_compile_flags(${name}.${arch}
${TARGET_${arch}_CFLAGS} ${LIB_CFLAGS})
+ set_property(TARGET ${name}.${arch} APPEND PROPERTY
+ COMPILE_DEFINITIONS ${LIB_DEFS})
else()
message(FATAL_ERROR "Archtecture ${arch} can't be targeted")
endif()
endmacro()
-# Same as above, but adds universal osx library with name "<name>.osx"
-# targeting multiple architectures.
-# add_compiler_rt_osx_object_library(<name> ARCH <architectures>
-# SOURCES <source files>
-# CFLAGS <compile flags>)
-macro(add_compiler_rt_osx_object_library name)
- parse_arguments(LIB "ARCH;SOURCES;CFLAGS" "" ${ARGN})
- set(libname "${name}.osx")
+# Same as above, but adds universal osx library for either OSX or iOS simulator
+# with name "<name>.<os>" targeting multiple architectures.
+# add_compiler_rt_darwin_object_library(<name> <os> ARCH <architectures>
+# SOURCES <source files>
+# CFLAGS <compile flags>
+# DEFS <compile definitions>)
+macro(add_compiler_rt_darwin_object_library name os)
+ parse_arguments(LIB "ARCH;SOURCES;CFLAGS;DEFS" "" ${ARGN})
+ set(libname "${name}.${os}")
add_library(${libname} OBJECT ${LIB_SOURCES})
- set_target_compile_flags(${libname} ${LIB_CFLAGS})
+ set_target_compile_flags(${libname} ${LIB_CFLAGS} ${DARWIN_${os}_CFLAGS})
set_target_properties(${libname} PROPERTIES OSX_ARCHITECTURES "${LIB_ARCH}")
+ set_property(TARGET ${libname} APPEND PROPERTY
+ COMPILE_DEFINITIONS ${LIB_DEFS})
endmacro()
# Adds static runtime for a given architecture and puts it in the proper
@@ -36,11 +42,10 @@ endmacro()
# add_compiler_rt_static_runtime(<name> <arch>
# SOURCES <source files>
# CFLAGS <compile flags>
-# DEFS <compile definitions>
-# SYMS <symbols file>)
+# DEFS <compile definitions>)
macro(add_compiler_rt_static_runtime name arch)
if(CAN_TARGET_${arch})
- parse_arguments(LIB "SOURCES;CFLAGS;DEFS;SYMS" "" ${ARGN})
+ parse_arguments(LIB "SOURCES;CFLAGS;DEFS" "" ${ARGN})
add_library(${name} STATIC ${LIB_SOURCES})
# Setup compile flags and definitions.
set_target_compile_flags(${name}
@@ -53,13 +58,7 @@ macro(add_compiler_rt_static_runtime name arch)
# Add installation command.
install(TARGETS ${name}
ARCHIVE DESTINATION ${COMPILER_RT_LIBRARY_INSTALL_DIR})
- # Generate the .syms file if possible.
- if(LIB_SYMS)
- get_target_property(libfile ${name} LOCATION)
- configure_file(${LIB_SYMS} ${libfile}.syms)
- install(FILES ${libfile}.syms
- DESTINATION ${COMPILER_RT_LIBRARY_INSTALL_DIR})
- endif(LIB_SYMS)
+ add_dependencies(compiler-rt ${name})
else()
message(FATAL_ERROR "Archtecture ${arch} can't be targeted")
endif()
@@ -82,19 +81,22 @@ macro(add_compiler_rt_osx_static_runtime name)
ARCHIVE_OUTPUT_DIRECTORY ${COMPILER_RT_LIBRARY_OUTPUT_DIR})
install(TARGETS ${name}
ARCHIVE DESTINATION ${COMPILER_RT_LIBRARY_INSTALL_DIR})
+ add_dependencies(compiler-rt ${name})
endmacro()
-# Adds dynamic runtime library on osx, which supports multiple architectures.
-# add_compiler_rt_osx_dynamic_runtime(<name> ARCH <architectures>
-# SOURCES <source files>
-# CFLAGS <compile flags>
-# DEFS <compile definitions>
-# LINKFLAGS <link flags>)
-macro(add_compiler_rt_osx_dynamic_runtime name)
+# Adds dynamic runtime library on osx/iossim, which supports multiple
+# architectures.
+# add_compiler_rt_darwin_dynamic_runtime(<name> <os>
+# ARCH <architectures>
+# SOURCES <source files>
+# CFLAGS <compile flags>
+# DEFS <compile definitions>
+# LINKFLAGS <link flags>)
+macro(add_compiler_rt_darwin_dynamic_runtime name os)
parse_arguments(LIB "ARCH;SOURCES;CFLAGS;DEFS;LINKFLAGS" "" ${ARGN})
add_library(${name} SHARED ${LIB_SOURCES})
- set_target_compile_flags(${name} ${LIB_CFLAGS})
- set_target_link_flags(${name} ${LIB_LINKFLAGS})
+ set_target_compile_flags(${name} ${LIB_CFLAGS} ${DARWIN_${os}_CFLAGS})
+ set_target_link_flags(${name} ${LIB_LINKFLAGS} ${DARWIN_${os}_LINKFLAGS})
set_property(TARGET ${name} APPEND PROPERTY
COMPILE_DEFINITIONS ${LIB_DEFS})
set_target_properties(${name} PROPERTIES
@@ -102,14 +104,16 @@ macro(add_compiler_rt_osx_dynamic_runtime name)
LIBRARY_OUTPUT_DIRECTORY ${COMPILER_RT_LIBRARY_OUTPUT_DIR})
install(TARGETS ${name}
LIBRARY DESTINATION ${COMPILER_RT_LIBRARY_INSTALL_DIR})
+ add_dependencies(compiler-rt ${name})
endmacro()
# Unittests support.
set(COMPILER_RT_GTEST_PATH ${LLVM_MAIN_SRC_DIR}/utils/unittest/googletest)
-set(COMPILER_RT_GTEST_SOURCE ${COMPILER_RT_GTEST_PATH}/gtest-all.cc)
+set(COMPILER_RT_GTEST_SOURCE ${COMPILER_RT_GTEST_PATH}/src/gtest-all.cc)
set(COMPILER_RT_GTEST_INCLUDE_CFLAGS
-DGTEST_NO_LLVM_RAW_OSTREAM=1
-I${COMPILER_RT_GTEST_PATH}/include
+ -I${COMPILER_RT_GTEST_PATH}
)
# Use Clang to link objects into a single executable with just-built
diff --git a/cmake/Modules/CompilerRTUtils.cmake b/cmake/Modules/CompilerRTUtils.cmake
index f9760f40dbd5..fce37e3eb49a 100644
--- a/cmake/Modules/CompilerRTUtils.cmake
+++ b/cmake/Modules/CompilerRTUtils.cmake
@@ -26,3 +26,13 @@ function(find_flag_in_string flag_string flag out_var)
set(${out_var} FALSE PARENT_SCOPE)
endif()
endfunction()
+
+# Set the variable var_PYBOOL to True if var holds a true-ish string,
+# otherwise set it to False.
+macro(pythonize_bool var)
+ if (${var})
+ set(${var}_PYBOOL True)
+ else()
+ set(${var}_PYBOOL False)
+ endif()
+endmacro()
diff --git a/cmake/Modules/SanitizerUtils.cmake b/cmake/Modules/SanitizerUtils.cmake
new file mode 100644
index 000000000000..0836edee2644
--- /dev/null
+++ b/cmake/Modules/SanitizerUtils.cmake
@@ -0,0 +1,42 @@
+include(LLVMParseArguments)
+
+set(SANITIZER_GEN_DYNAMIC_LIST
+ ${COMPILER_RT_SOURCE_DIR}/lib/sanitizer_common/scripts/gen_dynamic_list.py)
+
+set(SANITIZER_LINT_SCRIPT
+ ${COMPILER_RT_SOURCE_DIR}/lib/sanitizer_common/scripts/check_lint.sh)
+
+# Create a target "<name>-symbols" that would generate the list of symbols
+# that need to be exported from sanitizer runtime "<name>". Function
+# interceptors are exported automatically, user can also provide files with
+# symbol names that should be exported as well.
+# add_sanitizer_rt_symbols(<name> <files with extra symbols to export>)
+macro(add_sanitizer_rt_symbols name)
+ get_target_property(libfile ${name} LOCATION)
+ set(symsfile "${libfile}.syms")
+ add_custom_command(OUTPUT ${symsfile}
+ COMMAND ${PYTHON_EXECUTABLE}
+ ${SANITIZER_GEN_DYNAMIC_LIST} ${libfile} ${ARGN}
+ > ${symsfile}
+ DEPENDS ${name} ${SANITIZER_GEN_DYNAMIC_LIST} ${ARGN}
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+ COMMENT "Generating exported symbols for ${name}"
+ VERBATIM)
+ add_custom_target(${name}-symbols ALL
+ DEPENDS ${symsfile}
+ SOURCES ${SANITIZER_GEN_DYNAMIC_LIST} ${ARGN})
+ install(FILES ${symsfile} DESTINATION ${COMPILER_RT_LIBRARY_INSTALL_DIR})
+ add_dependencies(compiler-rt ${name}-symbols)
+endmacro()
+
+# Add target to check code style for sanitizer runtimes.
+if(UNIX)
+ add_custom_target(SanitizerLintCheck
+ COMMAND LLVM_CHECKOUT=${LLVM_MAIN_SRC_DIR} SILENT=1 TMPDIR=
+ PYTHON_EXECUTABLE=${PYTHON_EXECUTABLE}
+ ${SANITIZER_LINT_SCRIPT}
+ DEPENDS ${SANITIZER_LINT_SCRIPT}
+ COMMENT "Running lint check for sanitizer sources..."
+ VERBATIM)
+endif()
+
diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt
index 700b5326b06c..d8a73872ba44 100644
--- a/include/CMakeLists.txt
+++ b/include/CMakeLists.txt
@@ -1,7 +1,9 @@
set(SANITIZER_HEADERS
sanitizer/asan_interface.h
sanitizer/common_interface_defs.h
+ sanitizer/dfsan_interface.h
sanitizer/linux_syscall_hooks.h
+ sanitizer/lsan_interface.h
sanitizer/msan_interface.h)
set(output_dir ${LLVM_BINARY_DIR}/lib/clang/${CLANG_VERSION}/include)
@@ -32,6 +34,7 @@ foreach( f ${SANITIZER_HEADERS} )
endforeach( f )
add_custom_target(compiler-rt-headers ALL DEPENDS ${out_files})
+add_dependencies(compiler-rt compiler-rt-headers)
# Install sanitizer headers.
install(FILES ${SANITIZER_HEADERS}
diff --git a/include/sanitizer/common_interface_defs.h b/include/sanitizer/common_interface_defs.h
index 31d0dea5484b..4cc2aeae23cb 100644
--- a/include/sanitizer/common_interface_defs.h
+++ b/include/sanitizer/common_interface_defs.h
@@ -27,10 +27,6 @@ extern "C" {
// Tell the tools to write their reports to "path.<pid>" instead of stderr.
void __sanitizer_set_report_path(const char *path);
- // Tell the tools to write their reports to given file descriptor instead of
- // stderr.
- void __sanitizer_set_report_fd(int fd);
-
// 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.
@@ -51,6 +47,33 @@ extern "C" {
void __sanitizer_unaligned_store32(void *p, uint32_t x);
void __sanitizer_unaligned_store64(void *p, uint64_t x);
+ // Record and dump coverage info.
+ void __sanitizer_cov_dump();
+
+ // Annotate the current state of a contiguous container, such as
+ // std::vector, std::string or similar.
+ // A contiguous container is a container that keeps all of its elements
+ // in a contiguous region of memory. The container owns the region of memory
+ // [beg, end); the memory [beg, mid) is used to store the current elements
+ // and the memory [mid, end) is reserved for future elements;
+ // end <= mid <= end. For example, in "std::vector<> v"
+ // beg = &v[0];
+ // end = beg + v.capacity() * sizeof(v[0]);
+ // mid = beg + v.size() * sizeof(v[0]);
+ //
+ // This annotation tells the Sanitizer tool about the current state of the
+ // container so that the tool can report errors when memory from [mid, end)
+ // is accessed. Insert this annotation into methods like push_back/pop_back.
+ // Supply the old and the new values of mid (old_mid/new_mid).
+ // In the initial state mid == end and so should be the final
+ // state when the container is destroyed or when it reallocates the storage.
+ //
+ // Use with caution and don't use for anything other than vector-like classes.
+ //
+ // For AddressSanitizer, 'beg' should be 8-aligned.
+ void __sanitizer_annotate_contiguous_container(void *beg, void *end,
+ void *old_mid, void *new_mid);
+
#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/include/sanitizer/dfsan_interface.h b/include/sanitizer/dfsan_interface.h
new file mode 100644
index 000000000000..f14d45a2b2a1
--- /dev/null
+++ b/include/sanitizer/dfsan_interface.h
@@ -0,0 +1,87 @@
+//===-- dfsan_interface.h -------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of DataFlowSanitizer.
+//
+// Public interface header.
+//===----------------------------------------------------------------------===//
+#ifndef DFSAN_INTERFACE_H
+#define DFSAN_INTERFACE_H
+
+#include <stddef.h>
+#include <stdint.h>
+#include <sanitizer/common_interface_defs.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef uint16_t dfsan_label;
+
+/// Stores information associated with a specific label identifier. A label
+/// may be a base label created using dfsan_create_label, with associated
+/// text description and user data, or an automatically created union label,
+/// which represents the union of two label identifiers (which may themselves
+/// be base or union labels).
+struct dfsan_label_info {
+ // Fields for union labels, set to 0 for base labels.
+ dfsan_label l1;
+ dfsan_label l2;
+
+ // Fields for base labels.
+ const char *desc;
+ void *userdata;
+};
+
+/// Computes the union of \c l1 and \c l2, possibly creating a union label in
+/// the process.
+dfsan_label dfsan_union(dfsan_label l1, dfsan_label l2);
+
+/// Creates and returns a base label with the given description and user data.
+dfsan_label dfsan_create_label(const char *desc, void *userdata);
+
+/// Sets the label for each address in [addr,addr+size) to \c label.
+void dfsan_set_label(dfsan_label label, void *addr, size_t size);
+
+/// Sets the label for each address in [addr,addr+size) to the union of the
+/// current label for that address and \c label.
+void dfsan_add_label(dfsan_label label, void *addr, size_t size);
+
+/// Retrieves the label associated with the given data.
+///
+/// The type of 'data' is arbitrary. The function accepts a value of any type,
+/// which can be truncated or extended (implicitly or explicitly) as necessary.
+/// The truncation/extension operations will preserve the label of the original
+/// value.
+dfsan_label dfsan_get_label(long data);
+
+/// Retrieves the label associated with the data at the given address.
+dfsan_label dfsan_read_label(const void *addr, size_t size);
+
+/// Retrieves a pointer to the dfsan_label_info struct for the given label.
+const struct dfsan_label_info *dfsan_get_label_info(dfsan_label label);
+
+/// Returns whether the given label label contains the label elem.
+int dfsan_has_label(dfsan_label label, dfsan_label elem);
+
+/// If the given label label contains a label with the description desc, returns
+/// that label, else returns 0.
+dfsan_label dfsan_has_label_with_desc(dfsan_label label, const char *desc);
+
+#ifdef __cplusplus
+} // extern "C"
+
+template <typename T>
+void dfsan_set_label(dfsan_label label, T &data) { // NOLINT
+ dfsan_set_label(label, (void *)&data, sizeof(T));
+}
+
+#endif
+
+#endif // DFSAN_INTERFACE_H
diff --git a/include/sanitizer/linux_syscall_hooks.h b/include/sanitizer/linux_syscall_hooks.h
index 894d5c2bebff..89867c15190a 100644
--- a/include/sanitizer/linux_syscall_hooks.h
+++ b/include/sanitizer/linux_syscall_hooks.h
@@ -15,788 +15,3056 @@
// actions for the active sanitizer.
// Usage:
// __sanitizer_syscall_pre_getfoo(...args...);
-// int res = syscall(__NR_getfoo, ...args...);
+// long res = syscall(__NR_getfoo, ...args...);
// __sanitizer_syscall_post_getfoo(res, ...args...);
//===----------------------------------------------------------------------===//
#ifndef SANITIZER_LINUX_SYSCALL_HOOKS_H
#define SANITIZER_LINUX_SYSCALL_HOOKS_H
-#ifdef __cplusplus
-extern "C" {
-#endif
+#define __sanitizer_syscall_pre_time(tloc) \
+ __sanitizer_syscall_pre_impl_time((long)(tloc))
+#define __sanitizer_syscall_post_time(res, tloc) \
+ __sanitizer_syscall_post_impl_time(res, (long)(tloc))
+#define __sanitizer_syscall_pre_stime(tptr) \
+ __sanitizer_syscall_pre_impl_stime((long)(tptr))
+#define __sanitizer_syscall_post_stime(res, tptr) \
+ __sanitizer_syscall_post_impl_stime(res, (long)(tptr))
+#define __sanitizer_syscall_pre_gettimeofday(tv, tz) \
+ __sanitizer_syscall_pre_impl_gettimeofday((long)(tv), (long)(tz))
+#define __sanitizer_syscall_post_gettimeofday(res, tv, tz) \
+ __sanitizer_syscall_post_impl_gettimeofday(res, (long)(tv), (long)(tz))
+#define __sanitizer_syscall_pre_settimeofday(tv, tz) \
+ __sanitizer_syscall_pre_impl_settimeofday((long)(tv), (long)(tz))
+#define __sanitizer_syscall_post_settimeofday(res, tv, tz) \
+ __sanitizer_syscall_post_impl_settimeofday(res, (long)(tv), (long)(tz))
+#define __sanitizer_syscall_pre_adjtimex(txc_p) \
+ __sanitizer_syscall_pre_impl_adjtimex((long)(txc_p))
+#define __sanitizer_syscall_post_adjtimex(res, txc_p) \
+ __sanitizer_syscall_post_impl_adjtimex(res, (long)(txc_p))
+#define __sanitizer_syscall_pre_times(tbuf) \
+ __sanitizer_syscall_pre_impl_times((long)(tbuf))
+#define __sanitizer_syscall_post_times(res, tbuf) \
+ __sanitizer_syscall_post_impl_times(res, (long)(tbuf))
+#define __sanitizer_syscall_pre_gettid() __sanitizer_syscall_pre_impl_gettid()
+#define __sanitizer_syscall_post_gettid(res) \
+ __sanitizer_syscall_post_impl_gettid(res)
+#define __sanitizer_syscall_pre_nanosleep(rqtp, rmtp) \
+ __sanitizer_syscall_pre_impl_nanosleep((long)(rqtp), (long)(rmtp))
+#define __sanitizer_syscall_post_nanosleep(res, rqtp, rmtp) \
+ __sanitizer_syscall_post_impl_nanosleep(res, (long)(rqtp), (long)(rmtp))
+#define __sanitizer_syscall_pre_alarm(seconds) \
+ __sanitizer_syscall_pre_impl_alarm((long)(seconds))
+#define __sanitizer_syscall_post_alarm(res, seconds) \
+ __sanitizer_syscall_post_impl_alarm(res, (long)(seconds))
+#define __sanitizer_syscall_pre_getpid() __sanitizer_syscall_pre_impl_getpid()
+#define __sanitizer_syscall_post_getpid(res) \
+ __sanitizer_syscall_post_impl_getpid(res)
+#define __sanitizer_syscall_pre_getppid() __sanitizer_syscall_pre_impl_getppid()
+#define __sanitizer_syscall_post_getppid(res) \
+ __sanitizer_syscall_post_impl_getppid(res)
+#define __sanitizer_syscall_pre_getuid() __sanitizer_syscall_pre_impl_getuid()
+#define __sanitizer_syscall_post_getuid(res) \
+ __sanitizer_syscall_post_impl_getuid(res)
+#define __sanitizer_syscall_pre_geteuid() __sanitizer_syscall_pre_impl_geteuid()
+#define __sanitizer_syscall_post_geteuid(res) \
+ __sanitizer_syscall_post_impl_geteuid(res)
+#define __sanitizer_syscall_pre_getgid() __sanitizer_syscall_pre_impl_getgid()
+#define __sanitizer_syscall_post_getgid(res) \
+ __sanitizer_syscall_post_impl_getgid(res)
+#define __sanitizer_syscall_pre_getegid() __sanitizer_syscall_pre_impl_getegid()
+#define __sanitizer_syscall_post_getegid(res) \
+ __sanitizer_syscall_post_impl_getegid(res)
+#define __sanitizer_syscall_pre_getresuid(ruid, euid, suid) \
+ __sanitizer_syscall_pre_impl_getresuid((long)(ruid), (long)(euid), \
+ (long)(suid))
+#define __sanitizer_syscall_post_getresuid(res, ruid, euid, suid) \
+ __sanitizer_syscall_post_impl_getresuid(res, (long)(ruid), (long)(euid), \
+ (long)(suid))
+#define __sanitizer_syscall_pre_getresgid(rgid, egid, sgid) \
+ __sanitizer_syscall_pre_impl_getresgid((long)(rgid), (long)(egid), \
+ (long)(sgid))
+#define __sanitizer_syscall_post_getresgid(res, rgid, egid, sgid) \
+ __sanitizer_syscall_post_impl_getresgid(res, (long)(rgid), (long)(egid), \
+ (long)(sgid))
+#define __sanitizer_syscall_pre_getpgid(pid) \
+ __sanitizer_syscall_pre_impl_getpgid((long)(pid))
+#define __sanitizer_syscall_post_getpgid(res, pid) \
+ __sanitizer_syscall_post_impl_getpgid(res, (long)(pid))
+#define __sanitizer_syscall_pre_getpgrp() __sanitizer_syscall_pre_impl_getpgrp()
+#define __sanitizer_syscall_post_getpgrp(res) \
+ __sanitizer_syscall_post_impl_getpgrp(res)
+#define __sanitizer_syscall_pre_getsid(pid) \
+ __sanitizer_syscall_pre_impl_getsid((long)(pid))
+#define __sanitizer_syscall_post_getsid(res, pid) \
+ __sanitizer_syscall_post_impl_getsid(res, (long)(pid))
+#define __sanitizer_syscall_pre_getgroups(gidsetsize, grouplist) \
+ __sanitizer_syscall_pre_impl_getgroups((long)(gidsetsize), (long)(grouplist))
+#define __sanitizer_syscall_post_getgroups(res, gidsetsize, grouplist) \
+ __sanitizer_syscall_post_impl_getgroups(res, (long)(gidsetsize), \
+ (long)(grouplist))
+#define __sanitizer_syscall_pre_setregid(rgid, egid) \
+ __sanitizer_syscall_pre_impl_setregid((long)(rgid), (long)(egid))
+#define __sanitizer_syscall_post_setregid(res, rgid, egid) \
+ __sanitizer_syscall_post_impl_setregid(res, (long)(rgid), (long)(egid))
+#define __sanitizer_syscall_pre_setgid(gid) \
+ __sanitizer_syscall_pre_impl_setgid((long)(gid))
+#define __sanitizer_syscall_post_setgid(res, gid) \
+ __sanitizer_syscall_post_impl_setgid(res, (long)(gid))
+#define __sanitizer_syscall_pre_setreuid(ruid, euid) \
+ __sanitizer_syscall_pre_impl_setreuid((long)(ruid), (long)(euid))
+#define __sanitizer_syscall_post_setreuid(res, ruid, euid) \
+ __sanitizer_syscall_post_impl_setreuid(res, (long)(ruid), (long)(euid))
+#define __sanitizer_syscall_pre_setuid(uid) \
+ __sanitizer_syscall_pre_impl_setuid((long)(uid))
+#define __sanitizer_syscall_post_setuid(res, uid) \
+ __sanitizer_syscall_post_impl_setuid(res, (long)(uid))
+#define __sanitizer_syscall_pre_setresuid(ruid, euid, suid) \
+ __sanitizer_syscall_pre_impl_setresuid((long)(ruid), (long)(euid), \
+ (long)(suid))
+#define __sanitizer_syscall_post_setresuid(res, ruid, euid, suid) \
+ __sanitizer_syscall_post_impl_setresuid(res, (long)(ruid), (long)(euid), \
+ (long)(suid))
+#define __sanitizer_syscall_pre_setresgid(rgid, egid, sgid) \
+ __sanitizer_syscall_pre_impl_setresgid((long)(rgid), (long)(egid), \
+ (long)(sgid))
+#define __sanitizer_syscall_post_setresgid(res, rgid, egid, sgid) \
+ __sanitizer_syscall_post_impl_setresgid(res, (long)(rgid), (long)(egid), \
+ (long)(sgid))
+#define __sanitizer_syscall_pre_setfsuid(uid) \
+ __sanitizer_syscall_pre_impl_setfsuid((long)(uid))
+#define __sanitizer_syscall_post_setfsuid(res, uid) \
+ __sanitizer_syscall_post_impl_setfsuid(res, (long)(uid))
+#define __sanitizer_syscall_pre_setfsgid(gid) \
+ __sanitizer_syscall_pre_impl_setfsgid((long)(gid))
+#define __sanitizer_syscall_post_setfsgid(res, gid) \
+ __sanitizer_syscall_post_impl_setfsgid(res, (long)(gid))
+#define __sanitizer_syscall_pre_setpgid(pid, pgid) \
+ __sanitizer_syscall_pre_impl_setpgid((long)(pid), (long)(pgid))
+#define __sanitizer_syscall_post_setpgid(res, pid, pgid) \
+ __sanitizer_syscall_post_impl_setpgid(res, (long)(pid), (long)(pgid))
+#define __sanitizer_syscall_pre_setsid() __sanitizer_syscall_pre_impl_setsid()
+#define __sanitizer_syscall_post_setsid(res) \
+ __sanitizer_syscall_post_impl_setsid(res)
+#define __sanitizer_syscall_pre_setgroups(gidsetsize, grouplist) \
+ __sanitizer_syscall_pre_impl_setgroups((long)(gidsetsize), (long)(grouplist))
+#define __sanitizer_syscall_post_setgroups(res, gidsetsize, grouplist) \
+ __sanitizer_syscall_post_impl_setgroups(res, (long)(gidsetsize), \
+ (long)(grouplist))
+#define __sanitizer_syscall_pre_acct(name) \
+ __sanitizer_syscall_pre_impl_acct((long)(name))
+#define __sanitizer_syscall_post_acct(res, name) \
+ __sanitizer_syscall_post_impl_acct(res, (long)(name))
+#define __sanitizer_syscall_pre_capget(header, dataptr) \
+ __sanitizer_syscall_pre_impl_capget((long)(header), (long)(dataptr))
+#define __sanitizer_syscall_post_capget(res, header, dataptr) \
+ __sanitizer_syscall_post_impl_capget(res, (long)(header), (long)(dataptr))
+#define __sanitizer_syscall_pre_capset(header, data) \
+ __sanitizer_syscall_pre_impl_capset((long)(header), (long)(data))
+#define __sanitizer_syscall_post_capset(res, header, data) \
+ __sanitizer_syscall_post_impl_capset(res, (long)(header), (long)(data))
+#define __sanitizer_syscall_pre_personality(personality) \
+ __sanitizer_syscall_pre_impl_personality((long)(personality))
+#define __sanitizer_syscall_post_personality(res, personality) \
+ __sanitizer_syscall_post_impl_personality(res, (long)(personality))
+#define __sanitizer_syscall_pre_sigpending(set) \
+ __sanitizer_syscall_pre_impl_sigpending((long)(set))
+#define __sanitizer_syscall_post_sigpending(res, set) \
+ __sanitizer_syscall_post_impl_sigpending(res, (long)(set))
+#define __sanitizer_syscall_pre_sigprocmask(how, set, oset) \
+ __sanitizer_syscall_pre_impl_sigprocmask((long)(how), (long)(set), \
+ (long)(oset))
+#define __sanitizer_syscall_post_sigprocmask(res, how, set, oset) \
+ __sanitizer_syscall_post_impl_sigprocmask(res, (long)(how), (long)(set), \
+ (long)(oset))
+#define __sanitizer_syscall_pre_getitimer(which, value) \
+ __sanitizer_syscall_pre_impl_getitimer((long)(which), (long)(value))
+#define __sanitizer_syscall_post_getitimer(res, which, value) \
+ __sanitizer_syscall_post_impl_getitimer(res, (long)(which), (long)(value))
+#define __sanitizer_syscall_pre_setitimer(which, value, ovalue) \
+ __sanitizer_syscall_pre_impl_setitimer((long)(which), (long)(value), \
+ (long)(ovalue))
+#define __sanitizer_syscall_post_setitimer(res, which, value, ovalue) \
+ __sanitizer_syscall_post_impl_setitimer(res, (long)(which), (long)(value), \
+ (long)(ovalue))
+#define __sanitizer_syscall_pre_timer_create(which_clock, timer_event_spec, \
+ created_timer_id) \
+ __sanitizer_syscall_pre_impl_timer_create( \
+ (long)(which_clock), (long)(timer_event_spec), (long)(created_timer_id))
+#define __sanitizer_syscall_post_timer_create( \
+ res, which_clock, timer_event_spec, created_timer_id) \
+ __sanitizer_syscall_post_impl_timer_create(res, (long)(which_clock), \
+ (long)(timer_event_spec), \
+ (long)(created_timer_id))
+#define __sanitizer_syscall_pre_timer_gettime(timer_id, setting) \
+ __sanitizer_syscall_pre_impl_timer_gettime((long)(timer_id), (long)(setting))
+#define __sanitizer_syscall_post_timer_gettime(res, timer_id, setting) \
+ __sanitizer_syscall_post_impl_timer_gettime(res, (long)(timer_id), \
+ (long)(setting))
+#define __sanitizer_syscall_pre_timer_getoverrun(timer_id) \
+ __sanitizer_syscall_pre_impl_timer_getoverrun((long)(timer_id))
+#define __sanitizer_syscall_post_timer_getoverrun(res, timer_id) \
+ __sanitizer_syscall_post_impl_timer_getoverrun(res, (long)(timer_id))
+#define __sanitizer_syscall_pre_timer_settime(timer_id, flags, new_setting, \
+ old_setting) \
+ __sanitizer_syscall_pre_impl_timer_settime((long)(timer_id), (long)(flags), \
+ (long)(new_setting), \
+ (long)(old_setting))
+#define __sanitizer_syscall_post_timer_settime(res, timer_id, flags, \
+ new_setting, old_setting) \
+ __sanitizer_syscall_post_impl_timer_settime( \
+ res, (long)(timer_id), (long)(flags), (long)(new_setting), \
+ (long)(old_setting))
+#define __sanitizer_syscall_pre_timer_delete(timer_id) \
+ __sanitizer_syscall_pre_impl_timer_delete((long)(timer_id))
+#define __sanitizer_syscall_post_timer_delete(res, timer_id) \
+ __sanitizer_syscall_post_impl_timer_delete(res, (long)(timer_id))
+#define __sanitizer_syscall_pre_clock_settime(which_clock, tp) \
+ __sanitizer_syscall_pre_impl_clock_settime((long)(which_clock), (long)(tp))
+#define __sanitizer_syscall_post_clock_settime(res, which_clock, tp) \
+ __sanitizer_syscall_post_impl_clock_settime(res, (long)(which_clock), \
+ (long)(tp))
+#define __sanitizer_syscall_pre_clock_gettime(which_clock, tp) \
+ __sanitizer_syscall_pre_impl_clock_gettime((long)(which_clock), (long)(tp))
+#define __sanitizer_syscall_post_clock_gettime(res, which_clock, tp) \
+ __sanitizer_syscall_post_impl_clock_gettime(res, (long)(which_clock), \
+ (long)(tp))
+#define __sanitizer_syscall_pre_clock_adjtime(which_clock, tx) \
+ __sanitizer_syscall_pre_impl_clock_adjtime((long)(which_clock), (long)(tx))
+#define __sanitizer_syscall_post_clock_adjtime(res, which_clock, tx) \
+ __sanitizer_syscall_post_impl_clock_adjtime(res, (long)(which_clock), \
+ (long)(tx))
+#define __sanitizer_syscall_pre_clock_getres(which_clock, tp) \
+ __sanitizer_syscall_pre_impl_clock_getres((long)(which_clock), (long)(tp))
+#define __sanitizer_syscall_post_clock_getres(res, which_clock, tp) \
+ __sanitizer_syscall_post_impl_clock_getres(res, (long)(which_clock), \
+ (long)(tp))
+#define __sanitizer_syscall_pre_clock_nanosleep(which_clock, flags, rqtp, \
+ rmtp) \
+ __sanitizer_syscall_pre_impl_clock_nanosleep( \
+ (long)(which_clock), (long)(flags), (long)(rqtp), (long)(rmtp))
+#define __sanitizer_syscall_post_clock_nanosleep(res, which_clock, flags, \
+ rqtp, rmtp) \
+ __sanitizer_syscall_post_impl_clock_nanosleep( \
+ res, (long)(which_clock), (long)(flags), (long)(rqtp), (long)(rmtp))
+#define __sanitizer_syscall_pre_nice(increment) \
+ __sanitizer_syscall_pre_impl_nice((long)(increment))
+#define __sanitizer_syscall_post_nice(res, increment) \
+ __sanitizer_syscall_post_impl_nice(res, (long)(increment))
+#define __sanitizer_syscall_pre_sched_setscheduler(pid, policy, param) \
+ __sanitizer_syscall_pre_impl_sched_setscheduler((long)(pid), (long)(policy), \
+ (long)(param))
+#define __sanitizer_syscall_post_sched_setscheduler(res, pid, policy, param) \
+ __sanitizer_syscall_post_impl_sched_setscheduler( \
+ res, (long)(pid), (long)(policy), (long)(param))
+#define __sanitizer_syscall_pre_sched_setparam(pid, param) \
+ __sanitizer_syscall_pre_impl_sched_setparam((long)(pid), (long)(param))
+#define __sanitizer_syscall_post_sched_setparam(res, pid, param) \
+ __sanitizer_syscall_post_impl_sched_setparam(res, (long)(pid), (long)(param))
+#define __sanitizer_syscall_pre_sched_getscheduler(pid) \
+ __sanitizer_syscall_pre_impl_sched_getscheduler((long)(pid))
+#define __sanitizer_syscall_post_sched_getscheduler(res, pid) \
+ __sanitizer_syscall_post_impl_sched_getscheduler(res, (long)(pid))
+#define __sanitizer_syscall_pre_sched_getparam(pid, param) \
+ __sanitizer_syscall_pre_impl_sched_getparam((long)(pid), (long)(param))
+#define __sanitizer_syscall_post_sched_getparam(res, pid, param) \
+ __sanitizer_syscall_post_impl_sched_getparam(res, (long)(pid), (long)(param))
+#define __sanitizer_syscall_pre_sched_setaffinity(pid, len, user_mask_ptr) \
+ __sanitizer_syscall_pre_impl_sched_setaffinity((long)(pid), (long)(len), \
+ (long)(user_mask_ptr))
+#define __sanitizer_syscall_post_sched_setaffinity(res, pid, len, \
+ user_mask_ptr) \
+ __sanitizer_syscall_post_impl_sched_setaffinity( \
+ res, (long)(pid), (long)(len), (long)(user_mask_ptr))
+#define __sanitizer_syscall_pre_sched_getaffinity(pid, len, user_mask_ptr) \
+ __sanitizer_syscall_pre_impl_sched_getaffinity((long)(pid), (long)(len), \
+ (long)(user_mask_ptr))
+#define __sanitizer_syscall_post_sched_getaffinity(res, pid, len, \
+ user_mask_ptr) \
+ __sanitizer_syscall_post_impl_sched_getaffinity( \
+ res, (long)(pid), (long)(len), (long)(user_mask_ptr))
+#define __sanitizer_syscall_pre_sched_yield() \
+ __sanitizer_syscall_pre_impl_sched_yield()
+#define __sanitizer_syscall_post_sched_yield(res) \
+ __sanitizer_syscall_post_impl_sched_yield(res)
+#define __sanitizer_syscall_pre_sched_get_priority_max(policy) \
+ __sanitizer_syscall_pre_impl_sched_get_priority_max((long)(policy))
+#define __sanitizer_syscall_post_sched_get_priority_max(res, policy) \
+ __sanitizer_syscall_post_impl_sched_get_priority_max(res, (long)(policy))
+#define __sanitizer_syscall_pre_sched_get_priority_min(policy) \
+ __sanitizer_syscall_pre_impl_sched_get_priority_min((long)(policy))
+#define __sanitizer_syscall_post_sched_get_priority_min(res, policy) \
+ __sanitizer_syscall_post_impl_sched_get_priority_min(res, (long)(policy))
+#define __sanitizer_syscall_pre_sched_rr_get_interval(pid, interval) \
+ __sanitizer_syscall_pre_impl_sched_rr_get_interval((long)(pid), \
+ (long)(interval))
+#define __sanitizer_syscall_post_sched_rr_get_interval(res, pid, interval) \
+ __sanitizer_syscall_post_impl_sched_rr_get_interval(res, (long)(pid), \
+ (long)(interval))
+#define __sanitizer_syscall_pre_setpriority(which, who, niceval) \
+ __sanitizer_syscall_pre_impl_setpriority((long)(which), (long)(who), \
+ (long)(niceval))
+#define __sanitizer_syscall_post_setpriority(res, which, who, niceval) \
+ __sanitizer_syscall_post_impl_setpriority(res, (long)(which), (long)(who), \
+ (long)(niceval))
+#define __sanitizer_syscall_pre_getpriority(which, who) \
+ __sanitizer_syscall_pre_impl_getpriority((long)(which), (long)(who))
+#define __sanitizer_syscall_post_getpriority(res, which, who) \
+ __sanitizer_syscall_post_impl_getpriority(res, (long)(which), (long)(who))
+#define __sanitizer_syscall_pre_shutdown(arg0, arg1) \
+ __sanitizer_syscall_pre_impl_shutdown((long)(arg0), (long)(arg1))
+#define __sanitizer_syscall_post_shutdown(res, arg0, arg1) \
+ __sanitizer_syscall_post_impl_shutdown(res, (long)(arg0), (long)(arg1))
+#define __sanitizer_syscall_pre_reboot(magic1, magic2, cmd, arg) \
+ __sanitizer_syscall_pre_impl_reboot((long)(magic1), (long)(magic2), \
+ (long)(cmd), (long)(arg))
+#define __sanitizer_syscall_post_reboot(res, magic1, magic2, cmd, arg) \
+ __sanitizer_syscall_post_impl_reboot(res, (long)(magic1), (long)(magic2), \
+ (long)(cmd), (long)(arg))
+#define __sanitizer_syscall_pre_restart_syscall() \
+ __sanitizer_syscall_pre_impl_restart_syscall()
+#define __sanitizer_syscall_post_restart_syscall(res) \
+ __sanitizer_syscall_post_impl_restart_syscall(res)
+#define __sanitizer_syscall_pre_kexec_load(entry, nr_segments, segments, \
+ flags) \
+ __sanitizer_syscall_pre_impl_kexec_load((long)(entry), (long)(nr_segments), \
+ (long)(segments), (long)(flags))
+#define __sanitizer_syscall_post_kexec_load(res, entry, nr_segments, segments, \
+ flags) \
+ __sanitizer_syscall_post_impl_kexec_load(res, (long)(entry), \
+ (long)(nr_segments), \
+ (long)(segments), (long)(flags))
+#define __sanitizer_syscall_pre_exit(error_code) \
+ __sanitizer_syscall_pre_impl_exit((long)(error_code))
+#define __sanitizer_syscall_post_exit(res, error_code) \
+ __sanitizer_syscall_post_impl_exit(res, (long)(error_code))
+#define __sanitizer_syscall_pre_exit_group(error_code) \
+ __sanitizer_syscall_pre_impl_exit_group((long)(error_code))
+#define __sanitizer_syscall_post_exit_group(res, error_code) \
+ __sanitizer_syscall_post_impl_exit_group(res, (long)(error_code))
+#define __sanitizer_syscall_pre_wait4(pid, stat_addr, options, ru) \
+ __sanitizer_syscall_pre_impl_wait4((long)(pid), (long)(stat_addr), \
+ (long)(options), (long)(ru))
+#define __sanitizer_syscall_post_wait4(res, pid, stat_addr, options, ru) \
+ __sanitizer_syscall_post_impl_wait4(res, (long)(pid), (long)(stat_addr), \
+ (long)(options), (long)(ru))
+#define __sanitizer_syscall_pre_waitid(which, pid, infop, options, ru) \
+ __sanitizer_syscall_pre_impl_waitid( \
+ (long)(which), (long)(pid), (long)(infop), (long)(options), (long)(ru))
+#define __sanitizer_syscall_post_waitid(res, which, pid, infop, options, ru) \
+ __sanitizer_syscall_post_impl_waitid(res, (long)(which), (long)(pid), \
+ (long)(infop), (long)(options), \
+ (long)(ru))
+#define __sanitizer_syscall_pre_waitpid(pid, stat_addr, options) \
+ __sanitizer_syscall_pre_impl_waitpid((long)(pid), (long)(stat_addr), \
+ (long)(options))
+#define __sanitizer_syscall_post_waitpid(res, pid, stat_addr, options) \
+ __sanitizer_syscall_post_impl_waitpid(res, (long)(pid), (long)(stat_addr), \
+ (long)(options))
+#define __sanitizer_syscall_pre_set_tid_address(tidptr) \
+ __sanitizer_syscall_pre_impl_set_tid_address((long)(tidptr))
+#define __sanitizer_syscall_post_set_tid_address(res, tidptr) \
+ __sanitizer_syscall_post_impl_set_tid_address(res, (long)(tidptr))
+#define __sanitizer_syscall_pre_init_module(umod, len, uargs) \
+ __sanitizer_syscall_pre_impl_init_module((long)(umod), (long)(len), \
+ (long)(uargs))
+#define __sanitizer_syscall_post_init_module(res, umod, len, uargs) \
+ __sanitizer_syscall_post_impl_init_module(res, (long)(umod), (long)(len), \
+ (long)(uargs))
+#define __sanitizer_syscall_pre_delete_module(name_user, flags) \
+ __sanitizer_syscall_pre_impl_delete_module((long)(name_user), (long)(flags))
+#define __sanitizer_syscall_post_delete_module(res, name_user, flags) \
+ __sanitizer_syscall_post_impl_delete_module(res, (long)(name_user), \
+ (long)(flags))
+#define __sanitizer_syscall_pre_rt_sigprocmask(how, set, oset, sigsetsize) \
+ __sanitizer_syscall_pre_impl_rt_sigprocmask( \
+ (long)(how), (long)(set), (long)(oset), (long)(sigsetsize))
+#define __sanitizer_syscall_post_rt_sigprocmask(res, how, set, oset, \
+ sigsetsize) \
+ __sanitizer_syscall_post_impl_rt_sigprocmask( \
+ res, (long)(how), (long)(set), (long)(oset), (long)(sigsetsize))
+#define __sanitizer_syscall_pre_rt_sigpending(set, sigsetsize) \
+ __sanitizer_syscall_pre_impl_rt_sigpending((long)(set), (long)(sigsetsize))
+#define __sanitizer_syscall_post_rt_sigpending(res, set, sigsetsize) \
+ __sanitizer_syscall_post_impl_rt_sigpending(res, (long)(set), \
+ (long)(sigsetsize))
+#define __sanitizer_syscall_pre_rt_sigtimedwait(uthese, uinfo, uts, \
+ sigsetsize) \
+ __sanitizer_syscall_pre_impl_rt_sigtimedwait( \
+ (long)(uthese), (long)(uinfo), (long)(uts), (long)(sigsetsize))
+#define __sanitizer_syscall_post_rt_sigtimedwait(res, uthese, uinfo, uts, \
+ sigsetsize) \
+ __sanitizer_syscall_post_impl_rt_sigtimedwait( \
+ res, (long)(uthese), (long)(uinfo), (long)(uts), (long)(sigsetsize))
+#define __sanitizer_syscall_pre_rt_tgsigqueueinfo(tgid, pid, sig, uinfo) \
+ __sanitizer_syscall_pre_impl_rt_tgsigqueueinfo((long)(tgid), (long)(pid), \
+ (long)(sig), (long)(uinfo))
+#define __sanitizer_syscall_post_rt_tgsigqueueinfo(res, tgid, pid, sig, uinfo) \
+ __sanitizer_syscall_post_impl_rt_tgsigqueueinfo( \
+ res, (long)(tgid), (long)(pid), (long)(sig), (long)(uinfo))
+#define __sanitizer_syscall_pre_kill(pid, sig) \
+ __sanitizer_syscall_pre_impl_kill((long)(pid), (long)(sig))
+#define __sanitizer_syscall_post_kill(res, pid, sig) \
+ __sanitizer_syscall_post_impl_kill(res, (long)(pid), (long)(sig))
+#define __sanitizer_syscall_pre_tgkill(tgid, pid, sig) \
+ __sanitizer_syscall_pre_impl_tgkill((long)(tgid), (long)(pid), (long)(sig))
+#define __sanitizer_syscall_post_tgkill(res, tgid, pid, sig) \
+ __sanitizer_syscall_post_impl_tgkill(res, (long)(tgid), (long)(pid), \
+ (long)(sig))
+#define __sanitizer_syscall_pre_tkill(pid, sig) \
+ __sanitizer_syscall_pre_impl_tkill((long)(pid), (long)(sig))
+#define __sanitizer_syscall_post_tkill(res, pid, sig) \
+ __sanitizer_syscall_post_impl_tkill(res, (long)(pid), (long)(sig))
+#define __sanitizer_syscall_pre_rt_sigqueueinfo(pid, sig, uinfo) \
+ __sanitizer_syscall_pre_impl_rt_sigqueueinfo((long)(pid), (long)(sig), \
+ (long)(uinfo))
+#define __sanitizer_syscall_post_rt_sigqueueinfo(res, pid, sig, uinfo) \
+ __sanitizer_syscall_post_impl_rt_sigqueueinfo(res, (long)(pid), (long)(sig), \
+ (long)(uinfo))
+#define __sanitizer_syscall_pre_sgetmask() \
+ __sanitizer_syscall_pre_impl_sgetmask()
+#define __sanitizer_syscall_post_sgetmask(res) \
+ __sanitizer_syscall_post_impl_sgetmask(res)
+#define __sanitizer_syscall_pre_ssetmask(newmask) \
+ __sanitizer_syscall_pre_impl_ssetmask((long)(newmask))
+#define __sanitizer_syscall_post_ssetmask(res, newmask) \
+ __sanitizer_syscall_post_impl_ssetmask(res, (long)(newmask))
+#define __sanitizer_syscall_pre_signal(sig, handler) \
+ __sanitizer_syscall_pre_impl_signal((long)(sig), (long)(handler))
+#define __sanitizer_syscall_post_signal(res, sig, handler) \
+ __sanitizer_syscall_post_impl_signal(res, (long)(sig), (long)(handler))
+#define __sanitizer_syscall_pre_pause() __sanitizer_syscall_pre_impl_pause()
+#define __sanitizer_syscall_post_pause(res) \
+ __sanitizer_syscall_post_impl_pause(res)
+#define __sanitizer_syscall_pre_sync() __sanitizer_syscall_pre_impl_sync()
+#define __sanitizer_syscall_post_sync(res) \
+ __sanitizer_syscall_post_impl_sync(res)
+#define __sanitizer_syscall_pre_fsync(fd) \
+ __sanitizer_syscall_pre_impl_fsync((long)(fd))
+#define __sanitizer_syscall_post_fsync(res, fd) \
+ __sanitizer_syscall_post_impl_fsync(res, (long)(fd))
+#define __sanitizer_syscall_pre_fdatasync(fd) \
+ __sanitizer_syscall_pre_impl_fdatasync((long)(fd))
+#define __sanitizer_syscall_post_fdatasync(res, fd) \
+ __sanitizer_syscall_post_impl_fdatasync(res, (long)(fd))
+#define __sanitizer_syscall_pre_bdflush(func, data) \
+ __sanitizer_syscall_pre_impl_bdflush((long)(func), (long)(data))
+#define __sanitizer_syscall_post_bdflush(res, func, data) \
+ __sanitizer_syscall_post_impl_bdflush(res, (long)(func), (long)(data))
+#define __sanitizer_syscall_pre_mount(dev_name, dir_name, type, flags, data) \
+ __sanitizer_syscall_pre_impl_mount((long)(dev_name), (long)(dir_name), \
+ (long)(type), (long)(flags), \
+ (long)(data))
+#define __sanitizer_syscall_post_mount(res, dev_name, dir_name, type, flags, \
+ data) \
+ __sanitizer_syscall_post_impl_mount(res, (long)(dev_name), (long)(dir_name), \
+ (long)(type), (long)(flags), \
+ (long)(data))
+#define __sanitizer_syscall_pre_umount(name, flags) \
+ __sanitizer_syscall_pre_impl_umount((long)(name), (long)(flags))
+#define __sanitizer_syscall_post_umount(res, name, flags) \
+ __sanitizer_syscall_post_impl_umount(res, (long)(name), (long)(flags))
+#define __sanitizer_syscall_pre_oldumount(name) \
+ __sanitizer_syscall_pre_impl_oldumount((long)(name))
+#define __sanitizer_syscall_post_oldumount(res, name) \
+ __sanitizer_syscall_post_impl_oldumount(res, (long)(name))
+#define __sanitizer_syscall_pre_truncate(path, length) \
+ __sanitizer_syscall_pre_impl_truncate((long)(path), (long)(length))
+#define __sanitizer_syscall_post_truncate(res, path, length) \
+ __sanitizer_syscall_post_impl_truncate(res, (long)(path), (long)(length))
+#define __sanitizer_syscall_pre_ftruncate(fd, length) \
+ __sanitizer_syscall_pre_impl_ftruncate((long)(fd), (long)(length))
+#define __sanitizer_syscall_post_ftruncate(res, fd, length) \
+ __sanitizer_syscall_post_impl_ftruncate(res, (long)(fd), (long)(length))
+#define __sanitizer_syscall_pre_stat(filename, statbuf) \
+ __sanitizer_syscall_pre_impl_stat((long)(filename), (long)(statbuf))
+#define __sanitizer_syscall_post_stat(res, filename, statbuf) \
+ __sanitizer_syscall_post_impl_stat(res, (long)(filename), (long)(statbuf))
+#define __sanitizer_syscall_pre_statfs(path, buf) \
+ __sanitizer_syscall_pre_impl_statfs((long)(path), (long)(buf))
+#define __sanitizer_syscall_post_statfs(res, path, buf) \
+ __sanitizer_syscall_post_impl_statfs(res, (long)(path), (long)(buf))
+#define __sanitizer_syscall_pre_statfs64(path, sz, buf) \
+ __sanitizer_syscall_pre_impl_statfs64((long)(path), (long)(sz), (long)(buf))
+#define __sanitizer_syscall_post_statfs64(res, path, sz, buf) \
+ __sanitizer_syscall_post_impl_statfs64(res, (long)(path), (long)(sz), \
+ (long)(buf))
+#define __sanitizer_syscall_pre_fstatfs(fd, buf) \
+ __sanitizer_syscall_pre_impl_fstatfs((long)(fd), (long)(buf))
+#define __sanitizer_syscall_post_fstatfs(res, fd, buf) \
+ __sanitizer_syscall_post_impl_fstatfs(res, (long)(fd), (long)(buf))
+#define __sanitizer_syscall_pre_fstatfs64(fd, sz, buf) \
+ __sanitizer_syscall_pre_impl_fstatfs64((long)(fd), (long)(sz), (long)(buf))
+#define __sanitizer_syscall_post_fstatfs64(res, fd, sz, buf) \
+ __sanitizer_syscall_post_impl_fstatfs64(res, (long)(fd), (long)(sz), \
+ (long)(buf))
+#define __sanitizer_syscall_pre_lstat(filename, statbuf) \
+ __sanitizer_syscall_pre_impl_lstat((long)(filename), (long)(statbuf))
+#define __sanitizer_syscall_post_lstat(res, filename, statbuf) \
+ __sanitizer_syscall_post_impl_lstat(res, (long)(filename), (long)(statbuf))
+#define __sanitizer_syscall_pre_fstat(fd, statbuf) \
+ __sanitizer_syscall_pre_impl_fstat((long)(fd), (long)(statbuf))
+#define __sanitizer_syscall_post_fstat(res, fd, statbuf) \
+ __sanitizer_syscall_post_impl_fstat(res, (long)(fd), (long)(statbuf))
+#define __sanitizer_syscall_pre_newstat(filename, statbuf) \
+ __sanitizer_syscall_pre_impl_newstat((long)(filename), (long)(statbuf))
+#define __sanitizer_syscall_post_newstat(res, filename, statbuf) \
+ __sanitizer_syscall_post_impl_newstat(res, (long)(filename), (long)(statbuf))
+#define __sanitizer_syscall_pre_newlstat(filename, statbuf) \
+ __sanitizer_syscall_pre_impl_newlstat((long)(filename), (long)(statbuf))
+#define __sanitizer_syscall_post_newlstat(res, filename, statbuf) \
+ __sanitizer_syscall_post_impl_newlstat(res, (long)(filename), (long)(statbuf))
+#define __sanitizer_syscall_pre_newfstat(fd, statbuf) \
+ __sanitizer_syscall_pre_impl_newfstat((long)(fd), (long)(statbuf))
+#define __sanitizer_syscall_post_newfstat(res, fd, statbuf) \
+ __sanitizer_syscall_post_impl_newfstat(res, (long)(fd), (long)(statbuf))
+#define __sanitizer_syscall_pre_ustat(dev, ubuf) \
+ __sanitizer_syscall_pre_impl_ustat((long)(dev), (long)(ubuf))
+#define __sanitizer_syscall_post_ustat(res, dev, ubuf) \
+ __sanitizer_syscall_post_impl_ustat(res, (long)(dev), (long)(ubuf))
+#define __sanitizer_syscall_pre_stat64(filename, statbuf) \
+ __sanitizer_syscall_pre_impl_stat64((long)(filename), (long)(statbuf))
+#define __sanitizer_syscall_post_stat64(res, filename, statbuf) \
+ __sanitizer_syscall_post_impl_stat64(res, (long)(filename), (long)(statbuf))
+#define __sanitizer_syscall_pre_fstat64(fd, statbuf) \
+ __sanitizer_syscall_pre_impl_fstat64((long)(fd), (long)(statbuf))
+#define __sanitizer_syscall_post_fstat64(res, fd, statbuf) \
+ __sanitizer_syscall_post_impl_fstat64(res, (long)(fd), (long)(statbuf))
+#define __sanitizer_syscall_pre_lstat64(filename, statbuf) \
+ __sanitizer_syscall_pre_impl_lstat64((long)(filename), (long)(statbuf))
+#define __sanitizer_syscall_post_lstat64(res, filename, statbuf) \
+ __sanitizer_syscall_post_impl_lstat64(res, (long)(filename), (long)(statbuf))
+#define __sanitizer_syscall_pre_setxattr(path, name, value, size, flags) \
+ __sanitizer_syscall_pre_impl_setxattr( \
+ (long)(path), (long)(name), (long)(value), (long)(size), (long)(flags))
+#define __sanitizer_syscall_post_setxattr(res, path, name, value, size, flags) \
+ __sanitizer_syscall_post_impl_setxattr(res, (long)(path), (long)(name), \
+ (long)(value), (long)(size), \
+ (long)(flags))
+#define __sanitizer_syscall_pre_lsetxattr(path, name, value, size, flags) \
+ __sanitizer_syscall_pre_impl_lsetxattr( \
+ (long)(path), (long)(name), (long)(value), (long)(size), (long)(flags))
+#define __sanitizer_syscall_post_lsetxattr(res, path, name, value, size, \
+ flags) \
+ __sanitizer_syscall_post_impl_lsetxattr(res, (long)(path), (long)(name), \
+ (long)(value), (long)(size), \
+ (long)(flags))
+#define __sanitizer_syscall_pre_fsetxattr(fd, name, value, size, flags) \
+ __sanitizer_syscall_pre_impl_fsetxattr( \
+ (long)(fd), (long)(name), (long)(value), (long)(size), (long)(flags))
+#define __sanitizer_syscall_post_fsetxattr(res, fd, name, value, size, flags) \
+ __sanitizer_syscall_post_impl_fsetxattr(res, (long)(fd), (long)(name), \
+ (long)(value), (long)(size), \
+ (long)(flags))
+#define __sanitizer_syscall_pre_getxattr(path, name, value, size) \
+ __sanitizer_syscall_pre_impl_getxattr((long)(path), (long)(name), \
+ (long)(value), (long)(size))
+#define __sanitizer_syscall_post_getxattr(res, path, name, value, size) \
+ __sanitizer_syscall_post_impl_getxattr(res, (long)(path), (long)(name), \
+ (long)(value), (long)(size))
+#define __sanitizer_syscall_pre_lgetxattr(path, name, value, size) \
+ __sanitizer_syscall_pre_impl_lgetxattr((long)(path), (long)(name), \
+ (long)(value), (long)(size))
+#define __sanitizer_syscall_post_lgetxattr(res, path, name, value, size) \
+ __sanitizer_syscall_post_impl_lgetxattr(res, (long)(path), (long)(name), \
+ (long)(value), (long)(size))
+#define __sanitizer_syscall_pre_fgetxattr(fd, name, value, size) \
+ __sanitizer_syscall_pre_impl_fgetxattr((long)(fd), (long)(name), \
+ (long)(value), (long)(size))
+#define __sanitizer_syscall_post_fgetxattr(res, fd, name, value, size) \
+ __sanitizer_syscall_post_impl_fgetxattr(res, (long)(fd), (long)(name), \
+ (long)(value), (long)(size))
+#define __sanitizer_syscall_pre_listxattr(path, list, size) \
+ __sanitizer_syscall_pre_impl_listxattr((long)(path), (long)(list), \
+ (long)(size))
+#define __sanitizer_syscall_post_listxattr(res, path, list, size) \
+ __sanitizer_syscall_post_impl_listxattr(res, (long)(path), (long)(list), \
+ (long)(size))
+#define __sanitizer_syscall_pre_llistxattr(path, list, size) \
+ __sanitizer_syscall_pre_impl_llistxattr((long)(path), (long)(list), \
+ (long)(size))
+#define __sanitizer_syscall_post_llistxattr(res, path, list, size) \
+ __sanitizer_syscall_post_impl_llistxattr(res, (long)(path), (long)(list), \
+ (long)(size))
+#define __sanitizer_syscall_pre_flistxattr(fd, list, size) \
+ __sanitizer_syscall_pre_impl_flistxattr((long)(fd), (long)(list), \
+ (long)(size))
+#define __sanitizer_syscall_post_flistxattr(res, fd, list, size) \
+ __sanitizer_syscall_post_impl_flistxattr(res, (long)(fd), (long)(list), \
+ (long)(size))
+#define __sanitizer_syscall_pre_removexattr(path, name) \
+ __sanitizer_syscall_pre_impl_removexattr((long)(path), (long)(name))
+#define __sanitizer_syscall_post_removexattr(res, path, name) \
+ __sanitizer_syscall_post_impl_removexattr(res, (long)(path), (long)(name))
+#define __sanitizer_syscall_pre_lremovexattr(path, name) \
+ __sanitizer_syscall_pre_impl_lremovexattr((long)(path), (long)(name))
+#define __sanitizer_syscall_post_lremovexattr(res, path, name) \
+ __sanitizer_syscall_post_impl_lremovexattr(res, (long)(path), (long)(name))
+#define __sanitizer_syscall_pre_fremovexattr(fd, name) \
+ __sanitizer_syscall_pre_impl_fremovexattr((long)(fd), (long)(name))
+#define __sanitizer_syscall_post_fremovexattr(res, fd, name) \
+ __sanitizer_syscall_post_impl_fremovexattr(res, (long)(fd), (long)(name))
+#define __sanitizer_syscall_pre_brk(brk) \
+ __sanitizer_syscall_pre_impl_brk((long)(brk))
+#define __sanitizer_syscall_post_brk(res, brk) \
+ __sanitizer_syscall_post_impl_brk(res, (long)(brk))
+#define __sanitizer_syscall_pre_mprotect(start, len, prot) \
+ __sanitizer_syscall_pre_impl_mprotect((long)(start), (long)(len), \
+ (long)(prot))
+#define __sanitizer_syscall_post_mprotect(res, start, len, prot) \
+ __sanitizer_syscall_post_impl_mprotect(res, (long)(start), (long)(len), \
+ (long)(prot))
+#define __sanitizer_syscall_pre_mremap(addr, old_len, new_len, flags, \
+ new_addr) \
+ __sanitizer_syscall_pre_impl_mremap((long)(addr), (long)(old_len), \
+ (long)(new_len), (long)(flags), \
+ (long)(new_addr))
+#define __sanitizer_syscall_post_mremap(res, addr, old_len, new_len, flags, \
+ new_addr) \
+ __sanitizer_syscall_post_impl_mremap(res, (long)(addr), (long)(old_len), \
+ (long)(new_len), (long)(flags), \
+ (long)(new_addr))
+#define __sanitizer_syscall_pre_remap_file_pages(start, size, prot, pgoff, \
+ flags) \
+ __sanitizer_syscall_pre_impl_remap_file_pages( \
+ (long)(start), (long)(size), (long)(prot), (long)(pgoff), (long)(flags))
+#define __sanitizer_syscall_post_remap_file_pages(res, start, size, prot, \
+ pgoff, flags) \
+ __sanitizer_syscall_post_impl_remap_file_pages(res, (long)(start), \
+ (long)(size), (long)(prot), \
+ (long)(pgoff), (long)(flags))
+#define __sanitizer_syscall_pre_msync(start, len, flags) \
+ __sanitizer_syscall_pre_impl_msync((long)(start), (long)(len), (long)(flags))
+#define __sanitizer_syscall_post_msync(res, start, len, flags) \
+ __sanitizer_syscall_post_impl_msync(res, (long)(start), (long)(len), \
+ (long)(flags))
+#define __sanitizer_syscall_pre_munmap(addr, len) \
+ __sanitizer_syscall_pre_impl_munmap((long)(addr), (long)(len))
+#define __sanitizer_syscall_post_munmap(res, addr, len) \
+ __sanitizer_syscall_post_impl_munmap(res, (long)(addr), (long)(len))
+#define __sanitizer_syscall_pre_mlock(start, len) \
+ __sanitizer_syscall_pre_impl_mlock((long)(start), (long)(len))
+#define __sanitizer_syscall_post_mlock(res, start, len) \
+ __sanitizer_syscall_post_impl_mlock(res, (long)(start), (long)(len))
+#define __sanitizer_syscall_pre_munlock(start, len) \
+ __sanitizer_syscall_pre_impl_munlock((long)(start), (long)(len))
+#define __sanitizer_syscall_post_munlock(res, start, len) \
+ __sanitizer_syscall_post_impl_munlock(res, (long)(start), (long)(len))
+#define __sanitizer_syscall_pre_mlockall(flags) \
+ __sanitizer_syscall_pre_impl_mlockall((long)(flags))
+#define __sanitizer_syscall_post_mlockall(res, flags) \
+ __sanitizer_syscall_post_impl_mlockall(res, (long)(flags))
+#define __sanitizer_syscall_pre_munlockall() \
+ __sanitizer_syscall_pre_impl_munlockall()
+#define __sanitizer_syscall_post_munlockall(res) \
+ __sanitizer_syscall_post_impl_munlockall(res)
+#define __sanitizer_syscall_pre_madvise(start, len, behavior) \
+ __sanitizer_syscall_pre_impl_madvise((long)(start), (long)(len), \
+ (long)(behavior))
+#define __sanitizer_syscall_post_madvise(res, start, len, behavior) \
+ __sanitizer_syscall_post_impl_madvise(res, (long)(start), (long)(len), \
+ (long)(behavior))
+#define __sanitizer_syscall_pre_mincore(start, len, vec) \
+ __sanitizer_syscall_pre_impl_mincore((long)(start), (long)(len), (long)(vec))
+#define __sanitizer_syscall_post_mincore(res, start, len, vec) \
+ __sanitizer_syscall_post_impl_mincore(res, (long)(start), (long)(len), \
+ (long)(vec))
+#define __sanitizer_syscall_pre_pivot_root(new_root, put_old) \
+ __sanitizer_syscall_pre_impl_pivot_root((long)(new_root), (long)(put_old))
+#define __sanitizer_syscall_post_pivot_root(res, new_root, put_old) \
+ __sanitizer_syscall_post_impl_pivot_root(res, (long)(new_root), \
+ (long)(put_old))
+#define __sanitizer_syscall_pre_chroot(filename) \
+ __sanitizer_syscall_pre_impl_chroot((long)(filename))
+#define __sanitizer_syscall_post_chroot(res, filename) \
+ __sanitizer_syscall_post_impl_chroot(res, (long)(filename))
+#define __sanitizer_syscall_pre_mknod(filename, mode, dev) \
+ __sanitizer_syscall_pre_impl_mknod((long)(filename), (long)(mode), \
+ (long)(dev))
+#define __sanitizer_syscall_post_mknod(res, filename, mode, dev) \
+ __sanitizer_syscall_post_impl_mknod(res, (long)(filename), (long)(mode), \
+ (long)(dev))
+#define __sanitizer_syscall_pre_link(oldname, newname) \
+ __sanitizer_syscall_pre_impl_link((long)(oldname), (long)(newname))
+#define __sanitizer_syscall_post_link(res, oldname, newname) \
+ __sanitizer_syscall_post_impl_link(res, (long)(oldname), (long)(newname))
+#define __sanitizer_syscall_pre_symlink(old, new_) \
+ __sanitizer_syscall_pre_impl_symlink((long)(old), (long)(new_))
+#define __sanitizer_syscall_post_symlink(res, old, new_) \
+ __sanitizer_syscall_post_impl_symlink(res, (long)(old), (long)(new_))
+#define __sanitizer_syscall_pre_unlink(pathname) \
+ __sanitizer_syscall_pre_impl_unlink((long)(pathname))
+#define __sanitizer_syscall_post_unlink(res, pathname) \
+ __sanitizer_syscall_post_impl_unlink(res, (long)(pathname))
+#define __sanitizer_syscall_pre_rename(oldname, newname) \
+ __sanitizer_syscall_pre_impl_rename((long)(oldname), (long)(newname))
+#define __sanitizer_syscall_post_rename(res, oldname, newname) \
+ __sanitizer_syscall_post_impl_rename(res, (long)(oldname), (long)(newname))
+#define __sanitizer_syscall_pre_chmod(filename, mode) \
+ __sanitizer_syscall_pre_impl_chmod((long)(filename), (long)(mode))
+#define __sanitizer_syscall_post_chmod(res, filename, mode) \
+ __sanitizer_syscall_post_impl_chmod(res, (long)(filename), (long)(mode))
+#define __sanitizer_syscall_pre_fchmod(fd, mode) \
+ __sanitizer_syscall_pre_impl_fchmod((long)(fd), (long)(mode))
+#define __sanitizer_syscall_post_fchmod(res, fd, mode) \
+ __sanitizer_syscall_post_impl_fchmod(res, (long)(fd), (long)(mode))
+#define __sanitizer_syscall_pre_fcntl(fd, cmd, arg) \
+ __sanitizer_syscall_pre_impl_fcntl((long)(fd), (long)(cmd), (long)(arg))
+#define __sanitizer_syscall_post_fcntl(res, fd, cmd, arg) \
+ __sanitizer_syscall_post_impl_fcntl(res, (long)(fd), (long)(cmd), (long)(arg))
+#define __sanitizer_syscall_pre_fcntl64(fd, cmd, arg) \
+ __sanitizer_syscall_pre_impl_fcntl64((long)(fd), (long)(cmd), (long)(arg))
+#define __sanitizer_syscall_post_fcntl64(res, fd, cmd, arg) \
+ __sanitizer_syscall_post_impl_fcntl64(res, (long)(fd), (long)(cmd), \
+ (long)(arg))
+#define __sanitizer_syscall_pre_pipe(fildes) \
+ __sanitizer_syscall_pre_impl_pipe((long)(fildes))
+#define __sanitizer_syscall_post_pipe(res, fildes) \
+ __sanitizer_syscall_post_impl_pipe(res, (long)(fildes))
+#define __sanitizer_syscall_pre_pipe2(fildes, flags) \
+ __sanitizer_syscall_pre_impl_pipe2((long)(fildes), (long)(flags))
+#define __sanitizer_syscall_post_pipe2(res, fildes, flags) \
+ __sanitizer_syscall_post_impl_pipe2(res, (long)(fildes), (long)(flags))
+#define __sanitizer_syscall_pre_dup(fildes) \
+ __sanitizer_syscall_pre_impl_dup((long)(fildes))
+#define __sanitizer_syscall_post_dup(res, fildes) \
+ __sanitizer_syscall_post_impl_dup(res, (long)(fildes))
+#define __sanitizer_syscall_pre_dup2(oldfd, newfd) \
+ __sanitizer_syscall_pre_impl_dup2((long)(oldfd), (long)(newfd))
+#define __sanitizer_syscall_post_dup2(res, oldfd, newfd) \
+ __sanitizer_syscall_post_impl_dup2(res, (long)(oldfd), (long)(newfd))
+#define __sanitizer_syscall_pre_dup3(oldfd, newfd, flags) \
+ __sanitizer_syscall_pre_impl_dup3((long)(oldfd), (long)(newfd), (long)(flags))
+#define __sanitizer_syscall_post_dup3(res, oldfd, newfd, flags) \
+ __sanitizer_syscall_post_impl_dup3(res, (long)(oldfd), (long)(newfd), \
+ (long)(flags))
+#define __sanitizer_syscall_pre_ioperm(from, num, on) \
+ __sanitizer_syscall_pre_impl_ioperm((long)(from), (long)(num), (long)(on))
+#define __sanitizer_syscall_post_ioperm(res, from, num, on) \
+ __sanitizer_syscall_post_impl_ioperm(res, (long)(from), (long)(num), \
+ (long)(on))
+#define __sanitizer_syscall_pre_ioctl(fd, cmd, arg) \
+ __sanitizer_syscall_pre_impl_ioctl((long)(fd), (long)(cmd), (long)(arg))
+#define __sanitizer_syscall_post_ioctl(res, fd, cmd, arg) \
+ __sanitizer_syscall_post_impl_ioctl(res, (long)(fd), (long)(cmd), (long)(arg))
+#define __sanitizer_syscall_pre_flock(fd, cmd) \
+ __sanitizer_syscall_pre_impl_flock((long)(fd), (long)(cmd))
+#define __sanitizer_syscall_post_flock(res, fd, cmd) \
+ __sanitizer_syscall_post_impl_flock(res, (long)(fd), (long)(cmd))
+#define __sanitizer_syscall_pre_io_setup(nr_reqs, ctx) \
+ __sanitizer_syscall_pre_impl_io_setup((long)(nr_reqs), (long)(ctx))
+#define __sanitizer_syscall_post_io_setup(res, nr_reqs, ctx) \
+ __sanitizer_syscall_post_impl_io_setup(res, (long)(nr_reqs), (long)(ctx))
+#define __sanitizer_syscall_pre_io_destroy(ctx) \
+ __sanitizer_syscall_pre_impl_io_destroy((long)(ctx))
+#define __sanitizer_syscall_post_io_destroy(res, ctx) \
+ __sanitizer_syscall_post_impl_io_destroy(res, (long)(ctx))
+#define __sanitizer_syscall_pre_io_getevents(ctx_id, min_nr, nr, events, \
+ timeout) \
+ __sanitizer_syscall_pre_impl_io_getevents((long)(ctx_id), (long)(min_nr), \
+ (long)(nr), (long)(events), \
+ (long)(timeout))
+#define __sanitizer_syscall_post_io_getevents(res, ctx_id, min_nr, nr, events, \
+ timeout) \
+ __sanitizer_syscall_post_impl_io_getevents(res, (long)(ctx_id), \
+ (long)(min_nr), (long)(nr), \
+ (long)(events), (long)(timeout))
+#define __sanitizer_syscall_pre_io_submit(ctx_id, arg1, arg2) \
+ __sanitizer_syscall_pre_impl_io_submit((long)(ctx_id), (long)(arg1), \
+ (long)(arg2))
+#define __sanitizer_syscall_post_io_submit(res, ctx_id, arg1, arg2) \
+ __sanitizer_syscall_post_impl_io_submit(res, (long)(ctx_id), (long)(arg1), \
+ (long)(arg2))
+#define __sanitizer_syscall_pre_io_cancel(ctx_id, iocb, result) \
+ __sanitizer_syscall_pre_impl_io_cancel((long)(ctx_id), (long)(iocb), \
+ (long)(result))
+#define __sanitizer_syscall_post_io_cancel(res, ctx_id, iocb, result) \
+ __sanitizer_syscall_post_impl_io_cancel(res, (long)(ctx_id), (long)(iocb), \
+ (long)(result))
+#define __sanitizer_syscall_pre_sendfile(out_fd, in_fd, offset, count) \
+ __sanitizer_syscall_pre_impl_sendfile((long)(out_fd), (long)(in_fd), \
+ (long)(offset), (long)(count))
+#define __sanitizer_syscall_post_sendfile(res, out_fd, in_fd, offset, count) \
+ __sanitizer_syscall_post_impl_sendfile(res, (long)(out_fd), (long)(in_fd), \
+ (long)(offset), (long)(count))
+#define __sanitizer_syscall_pre_sendfile64(out_fd, in_fd, offset, count) \
+ __sanitizer_syscall_pre_impl_sendfile64((long)(out_fd), (long)(in_fd), \
+ (long)(offset), (long)(count))
+#define __sanitizer_syscall_post_sendfile64(res, out_fd, in_fd, offset, count) \
+ __sanitizer_syscall_post_impl_sendfile64(res, (long)(out_fd), (long)(in_fd), \
+ (long)(offset), (long)(count))
+#define __sanitizer_syscall_pre_readlink(path, buf, bufsiz) \
+ __sanitizer_syscall_pre_impl_readlink((long)(path), (long)(buf), \
+ (long)(bufsiz))
+#define __sanitizer_syscall_post_readlink(res, path, buf, bufsiz) \
+ __sanitizer_syscall_post_impl_readlink(res, (long)(path), (long)(buf), \
+ (long)(bufsiz))
+#define __sanitizer_syscall_pre_creat(pathname, mode) \
+ __sanitizer_syscall_pre_impl_creat((long)(pathname), (long)(mode))
+#define __sanitizer_syscall_post_creat(res, pathname, mode) \
+ __sanitizer_syscall_post_impl_creat(res, (long)(pathname), (long)(mode))
+#define __sanitizer_syscall_pre_open(filename, flags, mode) \
+ __sanitizer_syscall_pre_impl_open((long)(filename), (long)(flags), \
+ (long)(mode))
+#define __sanitizer_syscall_post_open(res, filename, flags, mode) \
+ __sanitizer_syscall_post_impl_open(res, (long)(filename), (long)(flags), \
+ (long)(mode))
+#define __sanitizer_syscall_pre_close(fd) \
+ __sanitizer_syscall_pre_impl_close((long)(fd))
+#define __sanitizer_syscall_post_close(res, fd) \
+ __sanitizer_syscall_post_impl_close(res, (long)(fd))
+#define __sanitizer_syscall_pre_access(filename, mode) \
+ __sanitizer_syscall_pre_impl_access((long)(filename), (long)(mode))
+#define __sanitizer_syscall_post_access(res, filename, mode) \
+ __sanitizer_syscall_post_impl_access(res, (long)(filename), (long)(mode))
+#define __sanitizer_syscall_pre_vhangup() __sanitizer_syscall_pre_impl_vhangup()
+#define __sanitizer_syscall_post_vhangup(res) \
+ __sanitizer_syscall_post_impl_vhangup(res)
+#define __sanitizer_syscall_pre_chown(filename, user, group) \
+ __sanitizer_syscall_pre_impl_chown((long)(filename), (long)(user), \
+ (long)(group))
+#define __sanitizer_syscall_post_chown(res, filename, user, group) \
+ __sanitizer_syscall_post_impl_chown(res, (long)(filename), (long)(user), \
+ (long)(group))
+#define __sanitizer_syscall_pre_lchown(filename, user, group) \
+ __sanitizer_syscall_pre_impl_lchown((long)(filename), (long)(user), \
+ (long)(group))
+#define __sanitizer_syscall_post_lchown(res, filename, user, group) \
+ __sanitizer_syscall_post_impl_lchown(res, (long)(filename), (long)(user), \
+ (long)(group))
+#define __sanitizer_syscall_pre_fchown(fd, user, group) \
+ __sanitizer_syscall_pre_impl_fchown((long)(fd), (long)(user), (long)(group))
+#define __sanitizer_syscall_post_fchown(res, fd, user, group) \
+ __sanitizer_syscall_post_impl_fchown(res, (long)(fd), (long)(user), \
+ (long)(group))
+#define __sanitizer_syscall_pre_chown16(filename, user, group) \
+ __sanitizer_syscall_pre_impl_chown16((long)(filename), (long)user, \
+ (long)group)
+#define __sanitizer_syscall_post_chown16(res, filename, user, group) \
+ __sanitizer_syscall_post_impl_chown16(res, (long)(filename), (long)user, \
+ (long)group)
+#define __sanitizer_syscall_pre_lchown16(filename, user, group) \
+ __sanitizer_syscall_pre_impl_lchown16((long)(filename), (long)user, \
+ (long)group)
+#define __sanitizer_syscall_post_lchown16(res, filename, user, group) \
+ __sanitizer_syscall_post_impl_lchown16(res, (long)(filename), (long)user, \
+ (long)group)
+#define __sanitizer_syscall_pre_fchown16(fd, user, group) \
+ __sanitizer_syscall_pre_impl_fchown16((long)(fd), (long)user, (long)group)
+#define __sanitizer_syscall_post_fchown16(res, fd, user, group) \
+ __sanitizer_syscall_post_impl_fchown16(res, (long)(fd), (long)user, \
+ (long)group)
+#define __sanitizer_syscall_pre_setregid16(rgid, egid) \
+ __sanitizer_syscall_pre_impl_setregid16((long)rgid, (long)egid)
+#define __sanitizer_syscall_post_setregid16(res, rgid, egid) \
+ __sanitizer_syscall_post_impl_setregid16(res, (long)rgid, (long)egid)
+#define __sanitizer_syscall_pre_setgid16(gid) \
+ __sanitizer_syscall_pre_impl_setgid16((long)gid)
+#define __sanitizer_syscall_post_setgid16(res, gid) \
+ __sanitizer_syscall_post_impl_setgid16(res, (long)gid)
+#define __sanitizer_syscall_pre_setreuid16(ruid, euid) \
+ __sanitizer_syscall_pre_impl_setreuid16((long)ruid, (long)euid)
+#define __sanitizer_syscall_post_setreuid16(res, ruid, euid) \
+ __sanitizer_syscall_post_impl_setreuid16(res, (long)ruid, (long)euid)
+#define __sanitizer_syscall_pre_setuid16(uid) \
+ __sanitizer_syscall_pre_impl_setuid16((long)uid)
+#define __sanitizer_syscall_post_setuid16(res, uid) \
+ __sanitizer_syscall_post_impl_setuid16(res, (long)uid)
+#define __sanitizer_syscall_pre_setresuid16(ruid, euid, suid) \
+ __sanitizer_syscall_pre_impl_setresuid16((long)ruid, (long)euid, (long)suid)
+#define __sanitizer_syscall_post_setresuid16(res, ruid, euid, suid) \
+ __sanitizer_syscall_post_impl_setresuid16(res, (long)ruid, (long)euid, \
+ (long)suid)
+#define __sanitizer_syscall_pre_getresuid16(ruid, euid, suid) \
+ __sanitizer_syscall_pre_impl_getresuid16((long)(ruid), (long)(euid), \
+ (long)(suid))
+#define __sanitizer_syscall_post_getresuid16(res, ruid, euid, suid) \
+ __sanitizer_syscall_post_impl_getresuid16(res, (long)(ruid), (long)(euid), \
+ (long)(suid))
+#define __sanitizer_syscall_pre_setresgid16(rgid, egid, sgid) \
+ __sanitizer_syscall_pre_impl_setresgid16((long)rgid, (long)egid, (long)sgid)
+#define __sanitizer_syscall_post_setresgid16(res, rgid, egid, sgid) \
+ __sanitizer_syscall_post_impl_setresgid16(res, (long)rgid, (long)egid, \
+ (long)sgid)
+#define __sanitizer_syscall_pre_getresgid16(rgid, egid, sgid) \
+ __sanitizer_syscall_pre_impl_getresgid16((long)(rgid), (long)(egid), \
+ (long)(sgid))
+#define __sanitizer_syscall_post_getresgid16(res, rgid, egid, sgid) \
+ __sanitizer_syscall_post_impl_getresgid16(res, (long)(rgid), (long)(egid), \
+ (long)(sgid))
+#define __sanitizer_syscall_pre_setfsuid16(uid) \
+ __sanitizer_syscall_pre_impl_setfsuid16((long)uid)
+#define __sanitizer_syscall_post_setfsuid16(res, uid) \
+ __sanitizer_syscall_post_impl_setfsuid16(res, (long)uid)
+#define __sanitizer_syscall_pre_setfsgid16(gid) \
+ __sanitizer_syscall_pre_impl_setfsgid16((long)gid)
+#define __sanitizer_syscall_post_setfsgid16(res, gid) \
+ __sanitizer_syscall_post_impl_setfsgid16(res, (long)gid)
+#define __sanitizer_syscall_pre_getgroups16(gidsetsize, grouplist) \
+ __sanitizer_syscall_pre_impl_getgroups16((long)(gidsetsize), \
+ (long)(grouplist))
+#define __sanitizer_syscall_post_getgroups16(res, gidsetsize, grouplist) \
+ __sanitizer_syscall_post_impl_getgroups16(res, (long)(gidsetsize), \
+ (long)(grouplist))
+#define __sanitizer_syscall_pre_setgroups16(gidsetsize, grouplist) \
+ __sanitizer_syscall_pre_impl_setgroups16((long)(gidsetsize), \
+ (long)(grouplist))
+#define __sanitizer_syscall_post_setgroups16(res, gidsetsize, grouplist) \
+ __sanitizer_syscall_post_impl_setgroups16(res, (long)(gidsetsize), \
+ (long)(grouplist))
+#define __sanitizer_syscall_pre_getuid16() \
+ __sanitizer_syscall_pre_impl_getuid16()
+#define __sanitizer_syscall_post_getuid16(res) \
+ __sanitizer_syscall_post_impl_getuid16(res)
+#define __sanitizer_syscall_pre_geteuid16() \
+ __sanitizer_syscall_pre_impl_geteuid16()
+#define __sanitizer_syscall_post_geteuid16(res) \
+ __sanitizer_syscall_post_impl_geteuid16(res)
+#define __sanitizer_syscall_pre_getgid16() \
+ __sanitizer_syscall_pre_impl_getgid16()
+#define __sanitizer_syscall_post_getgid16(res) \
+ __sanitizer_syscall_post_impl_getgid16(res)
+#define __sanitizer_syscall_pre_getegid16() \
+ __sanitizer_syscall_pre_impl_getegid16()
+#define __sanitizer_syscall_post_getegid16(res) \
+ __sanitizer_syscall_post_impl_getegid16(res)
+#define __sanitizer_syscall_pre_utime(filename, times) \
+ __sanitizer_syscall_pre_impl_utime((long)(filename), (long)(times))
+#define __sanitizer_syscall_post_utime(res, filename, times) \
+ __sanitizer_syscall_post_impl_utime(res, (long)(filename), (long)(times))
+#define __sanitizer_syscall_pre_utimes(filename, utimes) \
+ __sanitizer_syscall_pre_impl_utimes((long)(filename), (long)(utimes))
+#define __sanitizer_syscall_post_utimes(res, filename, utimes) \
+ __sanitizer_syscall_post_impl_utimes(res, (long)(filename), (long)(utimes))
+#define __sanitizer_syscall_pre_lseek(fd, offset, origin) \
+ __sanitizer_syscall_pre_impl_lseek((long)(fd), (long)(offset), (long)(origin))
+#define __sanitizer_syscall_post_lseek(res, fd, offset, origin) \
+ __sanitizer_syscall_post_impl_lseek(res, (long)(fd), (long)(offset), \
+ (long)(origin))
+#define __sanitizer_syscall_pre_llseek(fd, offset_high, offset_low, result, \
+ origin) \
+ __sanitizer_syscall_pre_impl_llseek((long)(fd), (long)(offset_high), \
+ (long)(offset_low), (long)(result), \
+ (long)(origin))
+#define __sanitizer_syscall_post_llseek(res, fd, offset_high, offset_low, \
+ result, origin) \
+ __sanitizer_syscall_post_impl_llseek(res, (long)(fd), (long)(offset_high), \
+ (long)(offset_low), (long)(result), \
+ (long)(origin))
+#define __sanitizer_syscall_pre_read(fd, buf, count) \
+ __sanitizer_syscall_pre_impl_read((long)(fd), (long)(buf), (long)(count))
+#define __sanitizer_syscall_post_read(res, fd, buf, count) \
+ __sanitizer_syscall_post_impl_read(res, (long)(fd), (long)(buf), \
+ (long)(count))
+#define __sanitizer_syscall_pre_readv(fd, vec, vlen) \
+ __sanitizer_syscall_pre_impl_readv((long)(fd), (long)(vec), (long)(vlen))
+#define __sanitizer_syscall_post_readv(res, fd, vec, vlen) \
+ __sanitizer_syscall_post_impl_readv(res, (long)(fd), (long)(vec), \
+ (long)(vlen))
+#define __sanitizer_syscall_pre_write(fd, buf, count) \
+ __sanitizer_syscall_pre_impl_write((long)(fd), (long)(buf), (long)(count))
+#define __sanitizer_syscall_post_write(res, fd, buf, count) \
+ __sanitizer_syscall_post_impl_write(res, (long)(fd), (long)(buf), \
+ (long)(count))
+#define __sanitizer_syscall_pre_writev(fd, vec, vlen) \
+ __sanitizer_syscall_pre_impl_writev((long)(fd), (long)(vec), (long)(vlen))
+#define __sanitizer_syscall_post_writev(res, fd, vec, vlen) \
+ __sanitizer_syscall_post_impl_writev(res, (long)(fd), (long)(vec), \
+ (long)(vlen))
-void __sanitizer_syscall_pre_rt_sigpending(void *p, size_t s);
-void __sanitizer_syscall_pre_getdents(int fd, void *dirp, int count);
-void __sanitizer_syscall_pre_getdents64(int fd, void *dirp, int count);
-void __sanitizer_syscall_pre_recvmsg(int sockfd, void *msg, int flags);
-void __sanitizer_syscall_pre_wait4(int pid, int *status, int options, void *r);
-void __sanitizer_syscall_pre_waitpid(int pid, int *status, int options);
+#ifdef _LP64
+#define __sanitizer_syscall_pre_pread64(fd, buf, count, pos) \
+ __sanitizer_syscall_pre_impl_pread64((long)(fd), (long)(buf), (long)(count), \
+ (long)(pos))
+#define __sanitizer_syscall_post_pread64(res, fd, buf, count, pos) \
+ __sanitizer_syscall_post_impl_pread64(res, (long)(fd), (long)(buf), \
+ (long)(count), (long)(pos))
+#define __sanitizer_syscall_pre_pwrite64(fd, buf, count, pos) \
+ __sanitizer_syscall_pre_impl_pwrite64((long)(fd), (long)(buf), \
+ (long)(count), (long)(pos))
+#define __sanitizer_syscall_post_pwrite64(res, fd, buf, count, pos) \
+ __sanitizer_syscall_post_impl_pwrite64(res, (long)(fd), (long)(buf), \
+ (long)(count), (long)(pos))
+#else
+#define __sanitizer_syscall_pre_pread64(fd, buf, count, pos0, pos1) \
+ __sanitizer_syscall_pre_impl_pread64((long)(fd), (long)(buf), (long)(count), \
+ (long)(pos0), (long)(pos1))
+#define __sanitizer_syscall_post_pread64(res, fd, buf, count, pos0, pos1) \
+ __sanitizer_syscall_post_impl_pread64(res, (long)(fd), (long)(buf), \
+ (long)(count), (long)(pos0), \
+ (long)(pos1))
+#define __sanitizer_syscall_pre_pwrite64(fd, buf, count, pos0, pos1) \
+ __sanitizer_syscall_pre_impl_pwrite64( \
+ (long)(fd), (long)(buf), (long)(count), (long)(pos0), (long)(pos1))
+#define __sanitizer_syscall_post_pwrite64(res, fd, buf, count, pos0, pos1) \
+ __sanitizer_syscall_post_impl_pwrite64( \
+ res, (long)(fd), (long)(buf), (long)(count), (long)(pos0), (long)(pos1))
+#endif
-void __sanitizer_syscall_post_rt_sigpending(long res, void *p, size_t s);
-void __sanitizer_syscall_post_getdents(long res, int fd, void *dirp, int count);
-void __sanitizer_syscall_post_getdents64(long res, int fd, void *dirp,
- int count);
-void __sanitizer_syscall_post_recvmsg(long res, int sockfd, void *msg,
- int flags);
-void __sanitizer_syscall_post_wait4(long res, int pid, int *status, int options,
- void *r);
-void __sanitizer_syscall_post_waitpid(long res, int pid, int *status,
- int options);
+#define __sanitizer_syscall_pre_preadv(fd, vec, vlen, pos_l, pos_h) \
+ __sanitizer_syscall_pre_impl_preadv((long)(fd), (long)(vec), (long)(vlen), \
+ (long)(pos_l), (long)(pos_h))
+#define __sanitizer_syscall_post_preadv(res, fd, vec, vlen, pos_l, pos_h) \
+ __sanitizer_syscall_post_impl_preadv(res, (long)(fd), (long)(vec), \
+ (long)(vlen), (long)(pos_l), \
+ (long)(pos_h))
+#define __sanitizer_syscall_pre_pwritev(fd, vec, vlen, pos_l, pos_h) \
+ __sanitizer_syscall_pre_impl_pwritev((long)(fd), (long)(vec), (long)(vlen), \
+ (long)(pos_l), (long)(pos_h))
+#define __sanitizer_syscall_post_pwritev(res, fd, vec, vlen, pos_l, pos_h) \
+ __sanitizer_syscall_post_impl_pwritev(res, (long)(fd), (long)(vec), \
+ (long)(vlen), (long)(pos_l), \
+ (long)(pos_h))
+#define __sanitizer_syscall_pre_getcwd(buf, size) \
+ __sanitizer_syscall_pre_impl_getcwd((long)(buf), (long)(size))
+#define __sanitizer_syscall_post_getcwd(res, buf, size) \
+ __sanitizer_syscall_post_impl_getcwd(res, (long)(buf), (long)(size))
+#define __sanitizer_syscall_pre_mkdir(pathname, mode) \
+ __sanitizer_syscall_pre_impl_mkdir((long)(pathname), (long)(mode))
+#define __sanitizer_syscall_post_mkdir(res, pathname, mode) \
+ __sanitizer_syscall_post_impl_mkdir(res, (long)(pathname), (long)(mode))
+#define __sanitizer_syscall_pre_chdir(filename) \
+ __sanitizer_syscall_pre_impl_chdir((long)(filename))
+#define __sanitizer_syscall_post_chdir(res, filename) \
+ __sanitizer_syscall_post_impl_chdir(res, (long)(filename))
+#define __sanitizer_syscall_pre_fchdir(fd) \
+ __sanitizer_syscall_pre_impl_fchdir((long)(fd))
+#define __sanitizer_syscall_post_fchdir(res, fd) \
+ __sanitizer_syscall_post_impl_fchdir(res, (long)(fd))
+#define __sanitizer_syscall_pre_rmdir(pathname) \
+ __sanitizer_syscall_pre_impl_rmdir((long)(pathname))
+#define __sanitizer_syscall_post_rmdir(res, pathname) \
+ __sanitizer_syscall_post_impl_rmdir(res, (long)(pathname))
+#define __sanitizer_syscall_pre_lookup_dcookie(cookie64, buf, len) \
+ __sanitizer_syscall_pre_impl_lookup_dcookie((long)(cookie64), (long)(buf), \
+ (long)(len))
+#define __sanitizer_syscall_post_lookup_dcookie(res, cookie64, buf, len) \
+ __sanitizer_syscall_post_impl_lookup_dcookie(res, (long)(cookie64), \
+ (long)(buf), (long)(len))
+#define __sanitizer_syscall_pre_quotactl(cmd, special, id, addr) \
+ __sanitizer_syscall_pre_impl_quotactl((long)(cmd), (long)(special), \
+ (long)(id), (long)(addr))
+#define __sanitizer_syscall_post_quotactl(res, cmd, special, id, addr) \
+ __sanitizer_syscall_post_impl_quotactl(res, (long)(cmd), (long)(special), \
+ (long)(id), (long)(addr))
+#define __sanitizer_syscall_pre_getdents(fd, dirent, count) \
+ __sanitizer_syscall_pre_impl_getdents((long)(fd), (long)(dirent), \
+ (long)(count))
+#define __sanitizer_syscall_post_getdents(res, fd, dirent, count) \
+ __sanitizer_syscall_post_impl_getdents(res, (long)(fd), (long)(dirent), \
+ (long)(count))
+#define __sanitizer_syscall_pre_getdents64(fd, dirent, count) \
+ __sanitizer_syscall_pre_impl_getdents64((long)(fd), (long)(dirent), \
+ (long)(count))
+#define __sanitizer_syscall_post_getdents64(res, fd, dirent, count) \
+ __sanitizer_syscall_post_impl_getdents64(res, (long)(fd), (long)(dirent), \
+ (long)(count))
+#define __sanitizer_syscall_pre_setsockopt(fd, level, optname, optval, optlen) \
+ __sanitizer_syscall_pre_impl_setsockopt((long)(fd), (long)(level), \
+ (long)(optname), (long)(optval), \
+ (long)(optlen))
+#define __sanitizer_syscall_post_setsockopt(res, fd, level, optname, optval, \
+ optlen) \
+ __sanitizer_syscall_post_impl_setsockopt(res, (long)(fd), (long)(level), \
+ (long)(optname), (long)(optval), \
+ (long)(optlen))
+#define __sanitizer_syscall_pre_getsockopt(fd, level, optname, optval, optlen) \
+ __sanitizer_syscall_pre_impl_getsockopt((long)(fd), (long)(level), \
+ (long)(optname), (long)(optval), \
+ (long)(optlen))
+#define __sanitizer_syscall_post_getsockopt(res, fd, level, optname, optval, \
+ optlen) \
+ __sanitizer_syscall_post_impl_getsockopt(res, (long)(fd), (long)(level), \
+ (long)(optname), (long)(optval), \
+ (long)(optlen))
+#define __sanitizer_syscall_pre_bind(arg0, arg1, arg2) \
+ __sanitizer_syscall_pre_impl_bind((long)(arg0), (long)(arg1), (long)(arg2))
+#define __sanitizer_syscall_post_bind(res, arg0, arg1, arg2) \
+ __sanitizer_syscall_post_impl_bind(res, (long)(arg0), (long)(arg1), \
+ (long)(arg2))
+#define __sanitizer_syscall_pre_connect(arg0, arg1, arg2) \
+ __sanitizer_syscall_pre_impl_connect((long)(arg0), (long)(arg1), (long)(arg2))
+#define __sanitizer_syscall_post_connect(res, arg0, arg1, arg2) \
+ __sanitizer_syscall_post_impl_connect(res, (long)(arg0), (long)(arg1), \
+ (long)(arg2))
+#define __sanitizer_syscall_pre_accept(arg0, arg1, arg2) \
+ __sanitizer_syscall_pre_impl_accept((long)(arg0), (long)(arg1), (long)(arg2))
+#define __sanitizer_syscall_post_accept(res, arg0, arg1, arg2) \
+ __sanitizer_syscall_post_impl_accept(res, (long)(arg0), (long)(arg1), \
+ (long)(arg2))
+#define __sanitizer_syscall_pre_accept4(arg0, arg1, arg2, arg3) \
+ __sanitizer_syscall_pre_impl_accept4((long)(arg0), (long)(arg1), \
+ (long)(arg2), (long)(arg3))
+#define __sanitizer_syscall_post_accept4(res, arg0, arg1, arg2, arg3) \
+ __sanitizer_syscall_post_impl_accept4(res, (long)(arg0), (long)(arg1), \
+ (long)(arg2), (long)(arg3))
+#define __sanitizer_syscall_pre_getsockname(arg0, arg1, arg2) \
+ __sanitizer_syscall_pre_impl_getsockname((long)(arg0), (long)(arg1), \
+ (long)(arg2))
+#define __sanitizer_syscall_post_getsockname(res, arg0, arg1, arg2) \
+ __sanitizer_syscall_post_impl_getsockname(res, (long)(arg0), (long)(arg1), \
+ (long)(arg2))
+#define __sanitizer_syscall_pre_getpeername(arg0, arg1, arg2) \
+ __sanitizer_syscall_pre_impl_getpeername((long)(arg0), (long)(arg1), \
+ (long)(arg2))
+#define __sanitizer_syscall_post_getpeername(res, arg0, arg1, arg2) \
+ __sanitizer_syscall_post_impl_getpeername(res, (long)(arg0), (long)(arg1), \
+ (long)(arg2))
+#define __sanitizer_syscall_pre_send(arg0, arg1, arg2, arg3) \
+ __sanitizer_syscall_pre_impl_send((long)(arg0), (long)(arg1), (long)(arg2), \
+ (long)(arg3))
+#define __sanitizer_syscall_post_send(res, arg0, arg1, arg2, arg3) \
+ __sanitizer_syscall_post_impl_send(res, (long)(arg0), (long)(arg1), \
+ (long)(arg2), (long)(arg3))
+#define __sanitizer_syscall_pre_sendto(arg0, arg1, arg2, arg3, arg4, arg5) \
+ __sanitizer_syscall_pre_impl_sendto((long)(arg0), (long)(arg1), \
+ (long)(arg2), (long)(arg3), \
+ (long)(arg4), (long)(arg5))
+#define __sanitizer_syscall_post_sendto(res, arg0, arg1, arg2, arg3, arg4, \
+ arg5) \
+ __sanitizer_syscall_post_impl_sendto(res, (long)(arg0), (long)(arg1), \
+ (long)(arg2), (long)(arg3), \
+ (long)(arg4), (long)(arg5))
+#define __sanitizer_syscall_pre_sendmsg(fd, msg, flags) \
+ __sanitizer_syscall_pre_impl_sendmsg((long)(fd), (long)(msg), (long)(flags))
+#define __sanitizer_syscall_post_sendmsg(res, fd, msg, flags) \
+ __sanitizer_syscall_post_impl_sendmsg(res, (long)(fd), (long)(msg), \
+ (long)(flags))
+#define __sanitizer_syscall_pre_sendmmsg(fd, msg, vlen, flags) \
+ __sanitizer_syscall_pre_impl_sendmmsg((long)(fd), (long)(msg), (long)(vlen), \
+ (long)(flags))
+#define __sanitizer_syscall_post_sendmmsg(res, fd, msg, vlen, flags) \
+ __sanitizer_syscall_post_impl_sendmmsg(res, (long)(fd), (long)(msg), \
+ (long)(vlen), (long)(flags))
+#define __sanitizer_syscall_pre_recv(arg0, arg1, arg2, arg3) \
+ __sanitizer_syscall_pre_impl_recv((long)(arg0), (long)(arg1), (long)(arg2), \
+ (long)(arg3))
+#define __sanitizer_syscall_post_recv(res, arg0, arg1, arg2, arg3) \
+ __sanitizer_syscall_post_impl_recv(res, (long)(arg0), (long)(arg1), \
+ (long)(arg2), (long)(arg3))
+#define __sanitizer_syscall_pre_recvfrom(arg0, arg1, arg2, arg3, arg4, arg5) \
+ __sanitizer_syscall_pre_impl_recvfrom((long)(arg0), (long)(arg1), \
+ (long)(arg2), (long)(arg3), \
+ (long)(arg4), (long)(arg5))
+#define __sanitizer_syscall_post_recvfrom(res, arg0, arg1, arg2, arg3, arg4, \
+ arg5) \
+ __sanitizer_syscall_post_impl_recvfrom(res, (long)(arg0), (long)(arg1), \
+ (long)(arg2), (long)(arg3), \
+ (long)(arg4), (long)(arg5))
+#define __sanitizer_syscall_pre_recvmsg(fd, msg, flags) \
+ __sanitizer_syscall_pre_impl_recvmsg((long)(fd), (long)(msg), (long)(flags))
+#define __sanitizer_syscall_post_recvmsg(res, fd, msg, flags) \
+ __sanitizer_syscall_post_impl_recvmsg(res, (long)(fd), (long)(msg), \
+ (long)(flags))
+#define __sanitizer_syscall_pre_recvmmsg(fd, msg, vlen, flags, timeout) \
+ __sanitizer_syscall_pre_impl_recvmmsg((long)(fd), (long)(msg), (long)(vlen), \
+ (long)(flags), (long)(timeout))
+#define __sanitizer_syscall_post_recvmmsg(res, fd, msg, vlen, flags, timeout) \
+ __sanitizer_syscall_post_impl_recvmmsg(res, (long)(fd), (long)(msg), \
+ (long)(vlen), (long)(flags), \
+ (long)(timeout))
+#define __sanitizer_syscall_pre_socket(arg0, arg1, arg2) \
+ __sanitizer_syscall_pre_impl_socket((long)(arg0), (long)(arg1), (long)(arg2))
+#define __sanitizer_syscall_post_socket(res, arg0, arg1, arg2) \
+ __sanitizer_syscall_post_impl_socket(res, (long)(arg0), (long)(arg1), \
+ (long)(arg2))
+#define __sanitizer_syscall_pre_socketpair(arg0, arg1, arg2, arg3) \
+ __sanitizer_syscall_pre_impl_socketpair((long)(arg0), (long)(arg1), \
+ (long)(arg2), (long)(arg3))
+#define __sanitizer_syscall_post_socketpair(res, arg0, arg1, arg2, arg3) \
+ __sanitizer_syscall_post_impl_socketpair(res, (long)(arg0), (long)(arg1), \
+ (long)(arg2), (long)(arg3))
+#define __sanitizer_syscall_pre_socketcall(call, args) \
+ __sanitizer_syscall_pre_impl_socketcall((long)(call), (long)(args))
+#define __sanitizer_syscall_post_socketcall(res, call, args) \
+ __sanitizer_syscall_post_impl_socketcall(res, (long)(call), (long)(args))
+#define __sanitizer_syscall_pre_listen(arg0, arg1) \
+ __sanitizer_syscall_pre_impl_listen((long)(arg0), (long)(arg1))
+#define __sanitizer_syscall_post_listen(res, arg0, arg1) \
+ __sanitizer_syscall_post_impl_listen(res, (long)(arg0), (long)(arg1))
+#define __sanitizer_syscall_pre_poll(ufds, nfds, timeout) \
+ __sanitizer_syscall_pre_impl_poll((long)(ufds), (long)(nfds), (long)(timeout))
+#define __sanitizer_syscall_post_poll(res, ufds, nfds, timeout) \
+ __sanitizer_syscall_post_impl_poll(res, (long)(ufds), (long)(nfds), \
+ (long)(timeout))
+#define __sanitizer_syscall_pre_select(n, inp, outp, exp, tvp) \
+ __sanitizer_syscall_pre_impl_select((long)(n), (long)(inp), (long)(outp), \
+ (long)(exp), (long)(tvp))
+#define __sanitizer_syscall_post_select(res, n, inp, outp, exp, tvp) \
+ __sanitizer_syscall_post_impl_select(res, (long)(n), (long)(inp), \
+ (long)(outp), (long)(exp), (long)(tvp))
+#define __sanitizer_syscall_pre_old_select(arg) \
+ __sanitizer_syscall_pre_impl_old_select((long)(arg))
+#define __sanitizer_syscall_post_old_select(res, arg) \
+ __sanitizer_syscall_post_impl_old_select(res, (long)(arg))
+#define __sanitizer_syscall_pre_epoll_create(size) \
+ __sanitizer_syscall_pre_impl_epoll_create((long)(size))
+#define __sanitizer_syscall_post_epoll_create(res, size) \
+ __sanitizer_syscall_post_impl_epoll_create(res, (long)(size))
+#define __sanitizer_syscall_pre_epoll_create1(flags) \
+ __sanitizer_syscall_pre_impl_epoll_create1((long)(flags))
+#define __sanitizer_syscall_post_epoll_create1(res, flags) \
+ __sanitizer_syscall_post_impl_epoll_create1(res, (long)(flags))
+#define __sanitizer_syscall_pre_epoll_ctl(epfd, op, fd, event) \
+ __sanitizer_syscall_pre_impl_epoll_ctl((long)(epfd), (long)(op), (long)(fd), \
+ (long)(event))
+#define __sanitizer_syscall_post_epoll_ctl(res, epfd, op, fd, event) \
+ __sanitizer_syscall_post_impl_epoll_ctl(res, (long)(epfd), (long)(op), \
+ (long)(fd), (long)(event))
+#define __sanitizer_syscall_pre_epoll_wait(epfd, events, maxevents, timeout) \
+ __sanitizer_syscall_pre_impl_epoll_wait((long)(epfd), (long)(events), \
+ (long)(maxevents), (long)(timeout))
+#define __sanitizer_syscall_post_epoll_wait(res, epfd, events, maxevents, \
+ timeout) \
+ __sanitizer_syscall_post_impl_epoll_wait(res, (long)(epfd), (long)(events), \
+ (long)(maxevents), (long)(timeout))
+#define __sanitizer_syscall_pre_epoll_pwait(epfd, events, maxevents, timeout, \
+ sigmask, sigsetsize) \
+ __sanitizer_syscall_pre_impl_epoll_pwait( \
+ (long)(epfd), (long)(events), (long)(maxevents), (long)(timeout), \
+ (long)(sigmask), (long)(sigsetsize))
+#define __sanitizer_syscall_post_epoll_pwait(res, epfd, events, maxevents, \
+ timeout, sigmask, sigsetsize) \
+ __sanitizer_syscall_post_impl_epoll_pwait( \
+ res, (long)(epfd), (long)(events), (long)(maxevents), (long)(timeout), \
+ (long)(sigmask), (long)(sigsetsize))
+#define __sanitizer_syscall_pre_gethostname(name, len) \
+ __sanitizer_syscall_pre_impl_gethostname((long)(name), (long)(len))
+#define __sanitizer_syscall_post_gethostname(res, name, len) \
+ __sanitizer_syscall_post_impl_gethostname(res, (long)(name), (long)(len))
+#define __sanitizer_syscall_pre_sethostname(name, len) \
+ __sanitizer_syscall_pre_impl_sethostname((long)(name), (long)(len))
+#define __sanitizer_syscall_post_sethostname(res, name, len) \
+ __sanitizer_syscall_post_impl_sethostname(res, (long)(name), (long)(len))
+#define __sanitizer_syscall_pre_setdomainname(name, len) \
+ __sanitizer_syscall_pre_impl_setdomainname((long)(name), (long)(len))
+#define __sanitizer_syscall_post_setdomainname(res, name, len) \
+ __sanitizer_syscall_post_impl_setdomainname(res, (long)(name), (long)(len))
+#define __sanitizer_syscall_pre_newuname(name) \
+ __sanitizer_syscall_pre_impl_newuname((long)(name))
+#define __sanitizer_syscall_post_newuname(res, name) \
+ __sanitizer_syscall_post_impl_newuname(res, (long)(name))
+#define __sanitizer_syscall_pre_uname(arg0) \
+ __sanitizer_syscall_pre_impl_uname((long)(arg0))
+#define __sanitizer_syscall_post_uname(res, arg0) \
+ __sanitizer_syscall_post_impl_uname(res, (long)(arg0))
+#define __sanitizer_syscall_pre_olduname(arg0) \
+ __sanitizer_syscall_pre_impl_olduname((long)(arg0))
+#define __sanitizer_syscall_post_olduname(res, arg0) \
+ __sanitizer_syscall_post_impl_olduname(res, (long)(arg0))
+#define __sanitizer_syscall_pre_getrlimit(resource, rlim) \
+ __sanitizer_syscall_pre_impl_getrlimit((long)(resource), (long)(rlim))
+#define __sanitizer_syscall_post_getrlimit(res, resource, rlim) \
+ __sanitizer_syscall_post_impl_getrlimit(res, (long)(resource), (long)(rlim))
+#define __sanitizer_syscall_pre_old_getrlimit(resource, rlim) \
+ __sanitizer_syscall_pre_impl_old_getrlimit((long)(resource), (long)(rlim))
+#define __sanitizer_syscall_post_old_getrlimit(res, resource, rlim) \
+ __sanitizer_syscall_post_impl_old_getrlimit(res, (long)(resource), \
+ (long)(rlim))
+#define __sanitizer_syscall_pre_setrlimit(resource, rlim) \
+ __sanitizer_syscall_pre_impl_setrlimit((long)(resource), (long)(rlim))
+#define __sanitizer_syscall_post_setrlimit(res, resource, rlim) \
+ __sanitizer_syscall_post_impl_setrlimit(res, (long)(resource), (long)(rlim))
+#define __sanitizer_syscall_pre_prlimit64(pid, resource, new_rlim, old_rlim) \
+ __sanitizer_syscall_pre_impl_prlimit64((long)(pid), (long)(resource), \
+ (long)(new_rlim), (long)(old_rlim))
+#define __sanitizer_syscall_post_prlimit64(res, pid, resource, new_rlim, \
+ old_rlim) \
+ __sanitizer_syscall_post_impl_prlimit64(res, (long)(pid), (long)(resource), \
+ (long)(new_rlim), (long)(old_rlim))
+#define __sanitizer_syscall_pre_getrusage(who, ru) \
+ __sanitizer_syscall_pre_impl_getrusage((long)(who), (long)(ru))
+#define __sanitizer_syscall_post_getrusage(res, who, ru) \
+ __sanitizer_syscall_post_impl_getrusage(res, (long)(who), (long)(ru))
+#define __sanitizer_syscall_pre_umask(mask) \
+ __sanitizer_syscall_pre_impl_umask((long)(mask))
+#define __sanitizer_syscall_post_umask(res, mask) \
+ __sanitizer_syscall_post_impl_umask(res, (long)(mask))
+#define __sanitizer_syscall_pre_msgget(key, msgflg) \
+ __sanitizer_syscall_pre_impl_msgget((long)(key), (long)(msgflg))
+#define __sanitizer_syscall_post_msgget(res, key, msgflg) \
+ __sanitizer_syscall_post_impl_msgget(res, (long)(key), (long)(msgflg))
+#define __sanitizer_syscall_pre_msgsnd(msqid, msgp, msgsz, msgflg) \
+ __sanitizer_syscall_pre_impl_msgsnd((long)(msqid), (long)(msgp), \
+ (long)(msgsz), (long)(msgflg))
+#define __sanitizer_syscall_post_msgsnd(res, msqid, msgp, msgsz, msgflg) \
+ __sanitizer_syscall_post_impl_msgsnd(res, (long)(msqid), (long)(msgp), \
+ (long)(msgsz), (long)(msgflg))
+#define __sanitizer_syscall_pre_msgrcv(msqid, msgp, msgsz, msgtyp, msgflg) \
+ __sanitizer_syscall_pre_impl_msgrcv((long)(msqid), (long)(msgp), \
+ (long)(msgsz), (long)(msgtyp), \
+ (long)(msgflg))
+#define __sanitizer_syscall_post_msgrcv(res, msqid, msgp, msgsz, msgtyp, \
+ msgflg) \
+ __sanitizer_syscall_post_impl_msgrcv(res, (long)(msqid), (long)(msgp), \
+ (long)(msgsz), (long)(msgtyp), \
+ (long)(msgflg))
+#define __sanitizer_syscall_pre_msgctl(msqid, cmd, buf) \
+ __sanitizer_syscall_pre_impl_msgctl((long)(msqid), (long)(cmd), (long)(buf))
+#define __sanitizer_syscall_post_msgctl(res, msqid, cmd, buf) \
+ __sanitizer_syscall_post_impl_msgctl(res, (long)(msqid), (long)(cmd), \
+ (long)(buf))
+#define __sanitizer_syscall_pre_semget(key, nsems, semflg) \
+ __sanitizer_syscall_pre_impl_semget((long)(key), (long)(nsems), \
+ (long)(semflg))
+#define __sanitizer_syscall_post_semget(res, key, nsems, semflg) \
+ __sanitizer_syscall_post_impl_semget(res, (long)(key), (long)(nsems), \
+ (long)(semflg))
+#define __sanitizer_syscall_pre_semop(semid, sops, nsops) \
+ __sanitizer_syscall_pre_impl_semop((long)(semid), (long)(sops), (long)(nsops))
+#define __sanitizer_syscall_post_semop(res, semid, sops, nsops) \
+ __sanitizer_syscall_post_impl_semop(res, (long)(semid), (long)(sops), \
+ (long)(nsops))
+#define __sanitizer_syscall_pre_semctl(semid, semnum, cmd, arg) \
+ __sanitizer_syscall_pre_impl_semctl((long)(semid), (long)(semnum), \
+ (long)(cmd), (long)(arg))
+#define __sanitizer_syscall_post_semctl(res, semid, semnum, cmd, arg) \
+ __sanitizer_syscall_post_impl_semctl(res, (long)(semid), (long)(semnum), \
+ (long)(cmd), (long)(arg))
+#define __sanitizer_syscall_pre_semtimedop(semid, sops, nsops, timeout) \
+ __sanitizer_syscall_pre_impl_semtimedop((long)(semid), (long)(sops), \
+ (long)(nsops), (long)(timeout))
+#define __sanitizer_syscall_post_semtimedop(res, semid, sops, nsops, timeout) \
+ __sanitizer_syscall_post_impl_semtimedop(res, (long)(semid), (long)(sops), \
+ (long)(nsops), (long)(timeout))
+#define __sanitizer_syscall_pre_shmat(shmid, shmaddr, shmflg) \
+ __sanitizer_syscall_pre_impl_shmat((long)(shmid), (long)(shmaddr), \
+ (long)(shmflg))
+#define __sanitizer_syscall_post_shmat(res, shmid, shmaddr, shmflg) \
+ __sanitizer_syscall_post_impl_shmat(res, (long)(shmid), (long)(shmaddr), \
+ (long)(shmflg))
+#define __sanitizer_syscall_pre_shmget(key, size, flag) \
+ __sanitizer_syscall_pre_impl_shmget((long)(key), (long)(size), (long)(flag))
+#define __sanitizer_syscall_post_shmget(res, key, size, flag) \
+ __sanitizer_syscall_post_impl_shmget(res, (long)(key), (long)(size), \
+ (long)(flag))
+#define __sanitizer_syscall_pre_shmdt(shmaddr) \
+ __sanitizer_syscall_pre_impl_shmdt((long)(shmaddr))
+#define __sanitizer_syscall_post_shmdt(res, shmaddr) \
+ __sanitizer_syscall_post_impl_shmdt(res, (long)(shmaddr))
+#define __sanitizer_syscall_pre_shmctl(shmid, cmd, buf) \
+ __sanitizer_syscall_pre_impl_shmctl((long)(shmid), (long)(cmd), (long)(buf))
+#define __sanitizer_syscall_post_shmctl(res, shmid, cmd, buf) \
+ __sanitizer_syscall_post_impl_shmctl(res, (long)(shmid), (long)(cmd), \
+ (long)(buf))
+#define __sanitizer_syscall_pre_ipc(call, first, second, third, ptr, fifth) \
+ __sanitizer_syscall_pre_impl_ipc((long)(call), (long)(first), \
+ (long)(second), (long)(third), (long)(ptr), \
+ (long)(fifth))
+#define __sanitizer_syscall_post_ipc(res, call, first, second, third, ptr, \
+ fifth) \
+ __sanitizer_syscall_post_impl_ipc(res, (long)(call), (long)(first), \
+ (long)(second), (long)(third), \
+ (long)(ptr), (long)(fifth))
+#define __sanitizer_syscall_pre_mq_open(name, oflag, mode, attr) \
+ __sanitizer_syscall_pre_impl_mq_open((long)(name), (long)(oflag), \
+ (long)(mode), (long)(attr))
+#define __sanitizer_syscall_post_mq_open(res, name, oflag, mode, attr) \
+ __sanitizer_syscall_post_impl_mq_open(res, (long)(name), (long)(oflag), \
+ (long)(mode), (long)(attr))
+#define __sanitizer_syscall_pre_mq_unlink(name) \
+ __sanitizer_syscall_pre_impl_mq_unlink((long)(name))
+#define __sanitizer_syscall_post_mq_unlink(res, name) \
+ __sanitizer_syscall_post_impl_mq_unlink(res, (long)(name))
+#define __sanitizer_syscall_pre_mq_timedsend(mqdes, msg_ptr, msg_len, \
+ msg_prio, abs_timeout) \
+ __sanitizer_syscall_pre_impl_mq_timedsend((long)(mqdes), (long)(msg_ptr), \
+ (long)(msg_len), (long)(msg_prio), \
+ (long)(abs_timeout))
+#define __sanitizer_syscall_post_mq_timedsend(res, mqdes, msg_ptr, msg_len, \
+ msg_prio, abs_timeout) \
+ __sanitizer_syscall_post_impl_mq_timedsend( \
+ res, (long)(mqdes), (long)(msg_ptr), (long)(msg_len), (long)(msg_prio), \
+ (long)(abs_timeout))
+#define __sanitizer_syscall_pre_mq_timedreceive(mqdes, msg_ptr, msg_len, \
+ msg_prio, abs_timeout) \
+ __sanitizer_syscall_pre_impl_mq_timedreceive( \
+ (long)(mqdes), (long)(msg_ptr), (long)(msg_len), (long)(msg_prio), \
+ (long)(abs_timeout))
+#define __sanitizer_syscall_post_mq_timedreceive(res, mqdes, msg_ptr, msg_len, \
+ msg_prio, abs_timeout) \
+ __sanitizer_syscall_post_impl_mq_timedreceive( \
+ res, (long)(mqdes), (long)(msg_ptr), (long)(msg_len), (long)(msg_prio), \
+ (long)(abs_timeout))
+#define __sanitizer_syscall_pre_mq_notify(mqdes, notification) \
+ __sanitizer_syscall_pre_impl_mq_notify((long)(mqdes), (long)(notification))
+#define __sanitizer_syscall_post_mq_notify(res, mqdes, notification) \
+ __sanitizer_syscall_post_impl_mq_notify(res, (long)(mqdes), \
+ (long)(notification))
+#define __sanitizer_syscall_pre_mq_getsetattr(mqdes, mqstat, omqstat) \
+ __sanitizer_syscall_pre_impl_mq_getsetattr((long)(mqdes), (long)(mqstat), \
+ (long)(omqstat))
+#define __sanitizer_syscall_post_mq_getsetattr(res, mqdes, mqstat, omqstat) \
+ __sanitizer_syscall_post_impl_mq_getsetattr(res, (long)(mqdes), \
+ (long)(mqstat), (long)(omqstat))
+#define __sanitizer_syscall_pre_pciconfig_iobase(which, bus, devfn) \
+ __sanitizer_syscall_pre_impl_pciconfig_iobase((long)(which), (long)(bus), \
+ (long)(devfn))
+#define __sanitizer_syscall_post_pciconfig_iobase(res, which, bus, devfn) \
+ __sanitizer_syscall_post_impl_pciconfig_iobase(res, (long)(which), \
+ (long)(bus), (long)(devfn))
+#define __sanitizer_syscall_pre_pciconfig_read(bus, dfn, off, len, buf) \
+ __sanitizer_syscall_pre_impl_pciconfig_read( \
+ (long)(bus), (long)(dfn), (long)(off), (long)(len), (long)(buf))
+#define __sanitizer_syscall_post_pciconfig_read(res, bus, dfn, off, len, buf) \
+ __sanitizer_syscall_post_impl_pciconfig_read( \
+ res, (long)(bus), (long)(dfn), (long)(off), (long)(len), (long)(buf))
+#define __sanitizer_syscall_pre_pciconfig_write(bus, dfn, off, len, buf) \
+ __sanitizer_syscall_pre_impl_pciconfig_write( \
+ (long)(bus), (long)(dfn), (long)(off), (long)(len), (long)(buf))
+#define __sanitizer_syscall_post_pciconfig_write(res, bus, dfn, off, len, buf) \
+ __sanitizer_syscall_post_impl_pciconfig_write( \
+ res, (long)(bus), (long)(dfn), (long)(off), (long)(len), (long)(buf))
+#define __sanitizer_syscall_pre_swapon(specialfile, swap_flags) \
+ __sanitizer_syscall_pre_impl_swapon((long)(specialfile), (long)(swap_flags))
+#define __sanitizer_syscall_post_swapon(res, specialfile, swap_flags) \
+ __sanitizer_syscall_post_impl_swapon(res, (long)(specialfile), \
+ (long)(swap_flags))
+#define __sanitizer_syscall_pre_swapoff(specialfile) \
+ __sanitizer_syscall_pre_impl_swapoff((long)(specialfile))
+#define __sanitizer_syscall_post_swapoff(res, specialfile) \
+ __sanitizer_syscall_post_impl_swapoff(res, (long)(specialfile))
+#define __sanitizer_syscall_pre_sysctl(args) \
+ __sanitizer_syscall_pre_impl_sysctl((long)(args))
+#define __sanitizer_syscall_post_sysctl(res, args) \
+ __sanitizer_syscall_post_impl_sysctl(res, (long)(args))
+#define __sanitizer_syscall_pre_sysinfo(info) \
+ __sanitizer_syscall_pre_impl_sysinfo((long)(info))
+#define __sanitizer_syscall_post_sysinfo(res, info) \
+ __sanitizer_syscall_post_impl_sysinfo(res, (long)(info))
+#define __sanitizer_syscall_pre_sysfs(option, arg1, arg2) \
+ __sanitizer_syscall_pre_impl_sysfs((long)(option), (long)(arg1), (long)(arg2))
+#define __sanitizer_syscall_post_sysfs(res, option, arg1, arg2) \
+ __sanitizer_syscall_post_impl_sysfs(res, (long)(option), (long)(arg1), \
+ (long)(arg2))
+#define __sanitizer_syscall_pre_syslog(type, buf, len) \
+ __sanitizer_syscall_pre_impl_syslog((long)(type), (long)(buf), (long)(len))
+#define __sanitizer_syscall_post_syslog(res, type, buf, len) \
+ __sanitizer_syscall_post_impl_syslog(res, (long)(type), (long)(buf), \
+ (long)(len))
+#define __sanitizer_syscall_pre_uselib(library) \
+ __sanitizer_syscall_pre_impl_uselib((long)(library))
+#define __sanitizer_syscall_post_uselib(res, library) \
+ __sanitizer_syscall_post_impl_uselib(res, (long)(library))
+#define __sanitizer_syscall_pre_ni_syscall() \
+ __sanitizer_syscall_pre_impl_ni_syscall()
+#define __sanitizer_syscall_post_ni_syscall(res) \
+ __sanitizer_syscall_post_impl_ni_syscall(res)
+#define __sanitizer_syscall_pre_ptrace(request, pid, addr, data) \
+ __sanitizer_syscall_pre_impl_ptrace((long)(request), (long)(pid), \
+ (long)(addr), (long)(data))
+#define __sanitizer_syscall_post_ptrace(res, request, pid, addr, data) \
+ __sanitizer_syscall_post_impl_ptrace(res, (long)(request), (long)(pid), \
+ (long)(addr), (long)(data))
+#define __sanitizer_syscall_pre_add_key(_type, _description, _payload, plen, \
+ destringid) \
+ __sanitizer_syscall_pre_impl_add_key((long)(_type), (long)(_description), \
+ (long)(_payload), (long)(plen), \
+ (long)(destringid))
+#define __sanitizer_syscall_post_add_key(res, _type, _description, _payload, \
+ plen, destringid) \
+ __sanitizer_syscall_post_impl_add_key( \
+ res, (long)(_type), (long)(_description), (long)(_payload), \
+ (long)(plen), (long)(destringid))
+#define __sanitizer_syscall_pre_request_key(_type, _description, \
+ _callout_info, destringid) \
+ __sanitizer_syscall_pre_impl_request_key( \
+ (long)(_type), (long)(_description), (long)(_callout_info), \
+ (long)(destringid))
+#define __sanitizer_syscall_post_request_key(res, _type, _description, \
+ _callout_info, destringid) \
+ __sanitizer_syscall_post_impl_request_key( \
+ res, (long)(_type), (long)(_description), (long)(_callout_info), \
+ (long)(destringid))
+#define __sanitizer_syscall_pre_keyctl(cmd, arg2, arg3, arg4, arg5) \
+ __sanitizer_syscall_pre_impl_keyctl((long)(cmd), (long)(arg2), (long)(arg3), \
+ (long)(arg4), (long)(arg5))
+#define __sanitizer_syscall_post_keyctl(res, cmd, arg2, arg3, arg4, arg5) \
+ __sanitizer_syscall_post_impl_keyctl(res, (long)(cmd), (long)(arg2), \
+ (long)(arg3), (long)(arg4), \
+ (long)(arg5))
+#define __sanitizer_syscall_pre_ioprio_set(which, who, ioprio) \
+ __sanitizer_syscall_pre_impl_ioprio_set((long)(which), (long)(who), \
+ (long)(ioprio))
+#define __sanitizer_syscall_post_ioprio_set(res, which, who, ioprio) \
+ __sanitizer_syscall_post_impl_ioprio_set(res, (long)(which), (long)(who), \
+ (long)(ioprio))
+#define __sanitizer_syscall_pre_ioprio_get(which, who) \
+ __sanitizer_syscall_pre_impl_ioprio_get((long)(which), (long)(who))
+#define __sanitizer_syscall_post_ioprio_get(res, which, who) \
+ __sanitizer_syscall_post_impl_ioprio_get(res, (long)(which), (long)(who))
+#define __sanitizer_syscall_pre_set_mempolicy(mode, nmask, maxnode) \
+ __sanitizer_syscall_pre_impl_set_mempolicy((long)(mode), (long)(nmask), \
+ (long)(maxnode))
+#define __sanitizer_syscall_post_set_mempolicy(res, mode, nmask, maxnode) \
+ __sanitizer_syscall_post_impl_set_mempolicy(res, (long)(mode), \
+ (long)(nmask), (long)(maxnode))
+#define __sanitizer_syscall_pre_migrate_pages(pid, maxnode, from, to) \
+ __sanitizer_syscall_pre_impl_migrate_pages((long)(pid), (long)(maxnode), \
+ (long)(from), (long)(to))
+#define __sanitizer_syscall_post_migrate_pages(res, pid, maxnode, from, to) \
+ __sanitizer_syscall_post_impl_migrate_pages( \
+ res, (long)(pid), (long)(maxnode), (long)(from), (long)(to))
+#define __sanitizer_syscall_pre_move_pages(pid, nr_pages, pages, nodes, \
+ status, flags) \
+ __sanitizer_syscall_pre_impl_move_pages((long)(pid), (long)(nr_pages), \
+ (long)(pages), (long)(nodes), \
+ (long)(status), (long)(flags))
+#define __sanitizer_syscall_post_move_pages(res, pid, nr_pages, pages, nodes, \
+ status, flags) \
+ __sanitizer_syscall_post_impl_move_pages(res, (long)(pid), (long)(nr_pages), \
+ (long)(pages), (long)(nodes), \
+ (long)(status), (long)(flags))
+#define __sanitizer_syscall_pre_mbind(start, len, mode, nmask, maxnode, flags) \
+ __sanitizer_syscall_pre_impl_mbind((long)(start), (long)(len), (long)(mode), \
+ (long)(nmask), (long)(maxnode), \
+ (long)(flags))
+#define __sanitizer_syscall_post_mbind(res, start, len, mode, nmask, maxnode, \
+ flags) \
+ __sanitizer_syscall_post_impl_mbind(res, (long)(start), (long)(len), \
+ (long)(mode), (long)(nmask), \
+ (long)(maxnode), (long)(flags))
+#define __sanitizer_syscall_pre_get_mempolicy(policy, nmask, maxnode, addr, \
+ flags) \
+ __sanitizer_syscall_pre_impl_get_mempolicy((long)(policy), (long)(nmask), \
+ (long)(maxnode), (long)(addr), \
+ (long)(flags))
+#define __sanitizer_syscall_post_get_mempolicy(res, policy, nmask, maxnode, \
+ addr, flags) \
+ __sanitizer_syscall_post_impl_get_mempolicy(res, (long)(policy), \
+ (long)(nmask), (long)(maxnode), \
+ (long)(addr), (long)(flags))
+#define __sanitizer_syscall_pre_inotify_init() \
+ __sanitizer_syscall_pre_impl_inotify_init()
+#define __sanitizer_syscall_post_inotify_init(res) \
+ __sanitizer_syscall_post_impl_inotify_init(res)
+#define __sanitizer_syscall_pre_inotify_init1(flags) \
+ __sanitizer_syscall_pre_impl_inotify_init1((long)(flags))
+#define __sanitizer_syscall_post_inotify_init1(res, flags) \
+ __sanitizer_syscall_post_impl_inotify_init1(res, (long)(flags))
+#define __sanitizer_syscall_pre_inotify_add_watch(fd, path, mask) \
+ __sanitizer_syscall_pre_impl_inotify_add_watch((long)(fd), (long)(path), \
+ (long)(mask))
+#define __sanitizer_syscall_post_inotify_add_watch(res, fd, path, mask) \
+ __sanitizer_syscall_post_impl_inotify_add_watch(res, (long)(fd), \
+ (long)(path), (long)(mask))
+#define __sanitizer_syscall_pre_inotify_rm_watch(fd, wd) \
+ __sanitizer_syscall_pre_impl_inotify_rm_watch((long)(fd), (long)(wd))
+#define __sanitizer_syscall_post_inotify_rm_watch(res, fd, wd) \
+ __sanitizer_syscall_post_impl_inotify_rm_watch(res, (long)(fd), (long)(wd))
+#define __sanitizer_syscall_pre_spu_run(fd, unpc, ustatus) \
+ __sanitizer_syscall_pre_impl_spu_run((long)(fd), (long)(unpc), \
+ (long)(ustatus))
+#define __sanitizer_syscall_post_spu_run(res, fd, unpc, ustatus) \
+ __sanitizer_syscall_post_impl_spu_run(res, (long)(fd), (long)(unpc), \
+ (long)(ustatus))
+#define __sanitizer_syscall_pre_spu_create(name, flags, mode, fd) \
+ __sanitizer_syscall_pre_impl_spu_create((long)(name), (long)(flags), \
+ (long)(mode), (long)(fd))
+#define __sanitizer_syscall_post_spu_create(res, name, flags, mode, fd) \
+ __sanitizer_syscall_post_impl_spu_create(res, (long)(name), (long)(flags), \
+ (long)(mode), (long)(fd))
+#define __sanitizer_syscall_pre_mknodat(dfd, filename, mode, dev) \
+ __sanitizer_syscall_pre_impl_mknodat((long)(dfd), (long)(filename), \
+ (long)(mode), (long)(dev))
+#define __sanitizer_syscall_post_mknodat(res, dfd, filename, mode, dev) \
+ __sanitizer_syscall_post_impl_mknodat(res, (long)(dfd), (long)(filename), \
+ (long)(mode), (long)(dev))
+#define __sanitizer_syscall_pre_mkdirat(dfd, pathname, mode) \
+ __sanitizer_syscall_pre_impl_mkdirat((long)(dfd), (long)(pathname), \
+ (long)(mode))
+#define __sanitizer_syscall_post_mkdirat(res, dfd, pathname, mode) \
+ __sanitizer_syscall_post_impl_mkdirat(res, (long)(dfd), (long)(pathname), \
+ (long)(mode))
+#define __sanitizer_syscall_pre_unlinkat(dfd, pathname, flag) \
+ __sanitizer_syscall_pre_impl_unlinkat((long)(dfd), (long)(pathname), \
+ (long)(flag))
+#define __sanitizer_syscall_post_unlinkat(res, dfd, pathname, flag) \
+ __sanitizer_syscall_post_impl_unlinkat(res, (long)(dfd), (long)(pathname), \
+ (long)(flag))
+#define __sanitizer_syscall_pre_symlinkat(oldname, newdfd, newname) \
+ __sanitizer_syscall_pre_impl_symlinkat((long)(oldname), (long)(newdfd), \
+ (long)(newname))
+#define __sanitizer_syscall_post_symlinkat(res, oldname, newdfd, newname) \
+ __sanitizer_syscall_post_impl_symlinkat(res, (long)(oldname), \
+ (long)(newdfd), (long)(newname))
+#define __sanitizer_syscall_pre_linkat(olddfd, oldname, newdfd, newname, \
+ flags) \
+ __sanitizer_syscall_pre_impl_linkat((long)(olddfd), (long)(oldname), \
+ (long)(newdfd), (long)(newname), \
+ (long)(flags))
+#define __sanitizer_syscall_post_linkat(res, olddfd, oldname, newdfd, newname, \
+ flags) \
+ __sanitizer_syscall_post_impl_linkat(res, (long)(olddfd), (long)(oldname), \
+ (long)(newdfd), (long)(newname), \
+ (long)(flags))
+#define __sanitizer_syscall_pre_renameat(olddfd, oldname, newdfd, newname) \
+ __sanitizer_syscall_pre_impl_renameat((long)(olddfd), (long)(oldname), \
+ (long)(newdfd), (long)(newname))
+#define __sanitizer_syscall_post_renameat(res, olddfd, oldname, newdfd, \
+ newname) \
+ __sanitizer_syscall_post_impl_renameat(res, (long)(olddfd), (long)(oldname), \
+ (long)(newdfd), (long)(newname))
+#define __sanitizer_syscall_pre_futimesat(dfd, filename, utimes) \
+ __sanitizer_syscall_pre_impl_futimesat((long)(dfd), (long)(filename), \
+ (long)(utimes))
+#define __sanitizer_syscall_post_futimesat(res, dfd, filename, utimes) \
+ __sanitizer_syscall_post_impl_futimesat(res, (long)(dfd), (long)(filename), \
+ (long)(utimes))
+#define __sanitizer_syscall_pre_faccessat(dfd, filename, mode) \
+ __sanitizer_syscall_pre_impl_faccessat((long)(dfd), (long)(filename), \
+ (long)(mode))
+#define __sanitizer_syscall_post_faccessat(res, dfd, filename, mode) \
+ __sanitizer_syscall_post_impl_faccessat(res, (long)(dfd), (long)(filename), \
+ (long)(mode))
+#define __sanitizer_syscall_pre_fchmodat(dfd, filename, mode) \
+ __sanitizer_syscall_pre_impl_fchmodat((long)(dfd), (long)(filename), \
+ (long)(mode))
+#define __sanitizer_syscall_post_fchmodat(res, dfd, filename, mode) \
+ __sanitizer_syscall_post_impl_fchmodat(res, (long)(dfd), (long)(filename), \
+ (long)(mode))
+#define __sanitizer_syscall_pre_fchownat(dfd, filename, user, group, flag) \
+ __sanitizer_syscall_pre_impl_fchownat((long)(dfd), (long)(filename), \
+ (long)(user), (long)(group), \
+ (long)(flag))
+#define __sanitizer_syscall_post_fchownat(res, dfd, filename, user, group, \
+ flag) \
+ __sanitizer_syscall_post_impl_fchownat(res, (long)(dfd), (long)(filename), \
+ (long)(user), (long)(group), \
+ (long)(flag))
+#define __sanitizer_syscall_pre_openat(dfd, filename, flags, mode) \
+ __sanitizer_syscall_pre_impl_openat((long)(dfd), (long)(filename), \
+ (long)(flags), (long)(mode))
+#define __sanitizer_syscall_post_openat(res, dfd, filename, flags, mode) \
+ __sanitizer_syscall_post_impl_openat(res, (long)(dfd), (long)(filename), \
+ (long)(flags), (long)(mode))
+#define __sanitizer_syscall_pre_newfstatat(dfd, filename, statbuf, flag) \
+ __sanitizer_syscall_pre_impl_newfstatat((long)(dfd), (long)(filename), \
+ (long)(statbuf), (long)(flag))
+#define __sanitizer_syscall_post_newfstatat(res, dfd, filename, statbuf, flag) \
+ __sanitizer_syscall_post_impl_newfstatat(res, (long)(dfd), (long)(filename), \
+ (long)(statbuf), (long)(flag))
+#define __sanitizer_syscall_pre_fstatat64(dfd, filename, statbuf, flag) \
+ __sanitizer_syscall_pre_impl_fstatat64((long)(dfd), (long)(filename), \
+ (long)(statbuf), (long)(flag))
+#define __sanitizer_syscall_post_fstatat64(res, dfd, filename, statbuf, flag) \
+ __sanitizer_syscall_post_impl_fstatat64(res, (long)(dfd), (long)(filename), \
+ (long)(statbuf), (long)(flag))
+#define __sanitizer_syscall_pre_readlinkat(dfd, path, buf, bufsiz) \
+ __sanitizer_syscall_pre_impl_readlinkat((long)(dfd), (long)(path), \
+ (long)(buf), (long)(bufsiz))
+#define __sanitizer_syscall_post_readlinkat(res, dfd, path, buf, bufsiz) \
+ __sanitizer_syscall_post_impl_readlinkat(res, (long)(dfd), (long)(path), \
+ (long)(buf), (long)(bufsiz))
+#define __sanitizer_syscall_pre_utimensat(dfd, filename, utimes, flags) \
+ __sanitizer_syscall_pre_impl_utimensat((long)(dfd), (long)(filename), \
+ (long)(utimes), (long)(flags))
+#define __sanitizer_syscall_post_utimensat(res, dfd, filename, utimes, flags) \
+ __sanitizer_syscall_post_impl_utimensat(res, (long)(dfd), (long)(filename), \
+ (long)(utimes), (long)(flags))
+#define __sanitizer_syscall_pre_unshare(unshare_flags) \
+ __sanitizer_syscall_pre_impl_unshare((long)(unshare_flags))
+#define __sanitizer_syscall_post_unshare(res, unshare_flags) \
+ __sanitizer_syscall_post_impl_unshare(res, (long)(unshare_flags))
+#define __sanitizer_syscall_pre_splice(fd_in, off_in, fd_out, off_out, len, \
+ flags) \
+ __sanitizer_syscall_pre_impl_splice((long)(fd_in), (long)(off_in), \
+ (long)(fd_out), (long)(off_out), \
+ (long)(len), (long)(flags))
+#define __sanitizer_syscall_post_splice(res, fd_in, off_in, fd_out, off_out, \
+ len, flags) \
+ __sanitizer_syscall_post_impl_splice(res, (long)(fd_in), (long)(off_in), \
+ (long)(fd_out), (long)(off_out), \
+ (long)(len), (long)(flags))
+#define __sanitizer_syscall_pre_vmsplice(fd, iov, nr_segs, flags) \
+ __sanitizer_syscall_pre_impl_vmsplice((long)(fd), (long)(iov), \
+ (long)(nr_segs), (long)(flags))
+#define __sanitizer_syscall_post_vmsplice(res, fd, iov, nr_segs, flags) \
+ __sanitizer_syscall_post_impl_vmsplice(res, (long)(fd), (long)(iov), \
+ (long)(nr_segs), (long)(flags))
+#define __sanitizer_syscall_pre_tee(fdin, fdout, len, flags) \
+ __sanitizer_syscall_pre_impl_tee((long)(fdin), (long)(fdout), (long)(len), \
+ (long)(flags))
+#define __sanitizer_syscall_post_tee(res, fdin, fdout, len, flags) \
+ __sanitizer_syscall_post_impl_tee(res, (long)(fdin), (long)(fdout), \
+ (long)(len), (long)(flags))
+#define __sanitizer_syscall_pre_get_robust_list(pid, head_ptr, len_ptr) \
+ __sanitizer_syscall_pre_impl_get_robust_list((long)(pid), (long)(head_ptr), \
+ (long)(len_ptr))
+#define __sanitizer_syscall_post_get_robust_list(res, pid, head_ptr, len_ptr) \
+ __sanitizer_syscall_post_impl_get_robust_list( \
+ res, (long)(pid), (long)(head_ptr), (long)(len_ptr))
+#define __sanitizer_syscall_pre_set_robust_list(head, len) \
+ __sanitizer_syscall_pre_impl_set_robust_list((long)(head), (long)(len))
+#define __sanitizer_syscall_post_set_robust_list(res, head, len) \
+ __sanitizer_syscall_post_impl_set_robust_list(res, (long)(head), (long)(len))
+#define __sanitizer_syscall_pre_getcpu(cpu, node, cache) \
+ __sanitizer_syscall_pre_impl_getcpu((long)(cpu), (long)(node), (long)(cache))
+#define __sanitizer_syscall_post_getcpu(res, cpu, node, cache) \
+ __sanitizer_syscall_post_impl_getcpu(res, (long)(cpu), (long)(node), \
+ (long)(cache))
+#define __sanitizer_syscall_pre_signalfd(ufd, user_mask, sizemask) \
+ __sanitizer_syscall_pre_impl_signalfd((long)(ufd), (long)(user_mask), \
+ (long)(sizemask))
+#define __sanitizer_syscall_post_signalfd(res, ufd, user_mask, sizemask) \
+ __sanitizer_syscall_post_impl_signalfd(res, (long)(ufd), (long)(user_mask), \
+ (long)(sizemask))
+#define __sanitizer_syscall_pre_signalfd4(ufd, user_mask, sizemask, flags) \
+ __sanitizer_syscall_pre_impl_signalfd4((long)(ufd), (long)(user_mask), \
+ (long)(sizemask), (long)(flags))
+#define __sanitizer_syscall_post_signalfd4(res, ufd, user_mask, sizemask, \
+ flags) \
+ __sanitizer_syscall_post_impl_signalfd4(res, (long)(ufd), (long)(user_mask), \
+ (long)(sizemask), (long)(flags))
+#define __sanitizer_syscall_pre_timerfd_create(clockid, flags) \
+ __sanitizer_syscall_pre_impl_timerfd_create((long)(clockid), (long)(flags))
+#define __sanitizer_syscall_post_timerfd_create(res, clockid, flags) \
+ __sanitizer_syscall_post_impl_timerfd_create(res, (long)(clockid), \
+ (long)(flags))
+#define __sanitizer_syscall_pre_timerfd_settime(ufd, flags, utmr, otmr) \
+ __sanitizer_syscall_pre_impl_timerfd_settime((long)(ufd), (long)(flags), \
+ (long)(utmr), (long)(otmr))
+#define __sanitizer_syscall_post_timerfd_settime(res, ufd, flags, utmr, otmr) \
+ __sanitizer_syscall_post_impl_timerfd_settime( \
+ res, (long)(ufd), (long)(flags), (long)(utmr), (long)(otmr))
+#define __sanitizer_syscall_pre_timerfd_gettime(ufd, otmr) \
+ __sanitizer_syscall_pre_impl_timerfd_gettime((long)(ufd), (long)(otmr))
+#define __sanitizer_syscall_post_timerfd_gettime(res, ufd, otmr) \
+ __sanitizer_syscall_post_impl_timerfd_gettime(res, (long)(ufd), (long)(otmr))
+#define __sanitizer_syscall_pre_eventfd(count) \
+ __sanitizer_syscall_pre_impl_eventfd((long)(count))
+#define __sanitizer_syscall_post_eventfd(res, count) \
+ __sanitizer_syscall_post_impl_eventfd(res, (long)(count))
+#define __sanitizer_syscall_pre_eventfd2(count, flags) \
+ __sanitizer_syscall_pre_impl_eventfd2((long)(count), (long)(flags))
+#define __sanitizer_syscall_post_eventfd2(res, count, flags) \
+ __sanitizer_syscall_post_impl_eventfd2(res, (long)(count), (long)(flags))
+#define __sanitizer_syscall_pre_old_readdir(arg0, arg1, arg2) \
+ __sanitizer_syscall_pre_impl_old_readdir((long)(arg0), (long)(arg1), \
+ (long)(arg2))
+#define __sanitizer_syscall_post_old_readdir(res, arg0, arg1, arg2) \
+ __sanitizer_syscall_post_impl_old_readdir(res, (long)(arg0), (long)(arg1), \
+ (long)(arg2))
+#define __sanitizer_syscall_pre_pselect6(arg0, arg1, arg2, arg3, arg4, arg5) \
+ __sanitizer_syscall_pre_impl_pselect6((long)(arg0), (long)(arg1), \
+ (long)(arg2), (long)(arg3), \
+ (long)(arg4), (long)(arg5))
+#define __sanitizer_syscall_post_pselect6(res, arg0, arg1, arg2, arg3, arg4, \
+ arg5) \
+ __sanitizer_syscall_post_impl_pselect6(res, (long)(arg0), (long)(arg1), \
+ (long)(arg2), (long)(arg3), \
+ (long)(arg4), (long)(arg5))
+#define __sanitizer_syscall_pre_ppoll(arg0, arg1, arg2, arg3, arg4) \
+ __sanitizer_syscall_pre_impl_ppoll((long)(arg0), (long)(arg1), (long)(arg2), \
+ (long)(arg3), (long)(arg4))
+#define __sanitizer_syscall_post_ppoll(res, arg0, arg1, arg2, arg3, arg4) \
+ __sanitizer_syscall_post_impl_ppoll(res, (long)(arg0), (long)(arg1), \
+ (long)(arg2), (long)(arg3), \
+ (long)(arg4))
+#define __sanitizer_syscall_pre_syncfs(fd) \
+ __sanitizer_syscall_pre_impl_syncfs((long)(fd))
+#define __sanitizer_syscall_post_syncfs(res, fd) \
+ __sanitizer_syscall_post_impl_syncfs(res, (long)(fd))
+#define __sanitizer_syscall_pre_perf_event_open(attr_uptr, pid, cpu, group_fd, \
+ flags) \
+ __sanitizer_syscall_pre_impl_perf_event_open((long)(attr_uptr), (long)(pid), \
+ (long)(cpu), (long)(group_fd), \
+ (long)(flags))
+#define __sanitizer_syscall_post_perf_event_open(res, attr_uptr, pid, cpu, \
+ group_fd, flags) \
+ __sanitizer_syscall_post_impl_perf_event_open( \
+ res, (long)(attr_uptr), (long)(pid), (long)(cpu), (long)(group_fd), \
+ (long)(flags))
+#define __sanitizer_syscall_pre_mmap_pgoff(addr, len, prot, flags, fd, pgoff) \
+ __sanitizer_syscall_pre_impl_mmap_pgoff((long)(addr), (long)(len), \
+ (long)(prot), (long)(flags), \
+ (long)(fd), (long)(pgoff))
+#define __sanitizer_syscall_post_mmap_pgoff(res, addr, len, prot, flags, fd, \
+ pgoff) \
+ __sanitizer_syscall_post_impl_mmap_pgoff(res, (long)(addr), (long)(len), \
+ (long)(prot), (long)(flags), \
+ (long)(fd), (long)(pgoff))
+#define __sanitizer_syscall_pre_old_mmap(arg) \
+ __sanitizer_syscall_pre_impl_old_mmap((long)(arg))
+#define __sanitizer_syscall_post_old_mmap(res, arg) \
+ __sanitizer_syscall_post_impl_old_mmap(res, (long)(arg))
+#define __sanitizer_syscall_pre_name_to_handle_at(dfd, name, handle, mnt_id, \
+ flag) \
+ __sanitizer_syscall_pre_impl_name_to_handle_at( \
+ (long)(dfd), (long)(name), (long)(handle), (long)(mnt_id), (long)(flag))
+#define __sanitizer_syscall_post_name_to_handle_at(res, dfd, name, handle, \
+ mnt_id, flag) \
+ __sanitizer_syscall_post_impl_name_to_handle_at( \
+ res, (long)(dfd), (long)(name), (long)(handle), (long)(mnt_id), \
+ (long)(flag))
+#define __sanitizer_syscall_pre_open_by_handle_at(mountdirfd, handle, flags) \
+ __sanitizer_syscall_pre_impl_open_by_handle_at( \
+ (long)(mountdirfd), (long)(handle), (long)(flags))
+#define __sanitizer_syscall_post_open_by_handle_at(res, mountdirfd, handle, \
+ flags) \
+ __sanitizer_syscall_post_impl_open_by_handle_at( \
+ res, (long)(mountdirfd), (long)(handle), (long)(flags))
+#define __sanitizer_syscall_pre_setns(fd, nstype) \
+ __sanitizer_syscall_pre_impl_setns((long)(fd), (long)(nstype))
+#define __sanitizer_syscall_post_setns(res, fd, nstype) \
+ __sanitizer_syscall_post_impl_setns(res, (long)(fd), (long)(nstype))
+#define __sanitizer_syscall_pre_process_vm_readv(pid, lvec, liovcnt, rvec, \
+ riovcnt, flags) \
+ __sanitizer_syscall_pre_impl_process_vm_readv( \
+ (long)(pid), (long)(lvec), (long)(liovcnt), (long)(rvec), \
+ (long)(riovcnt), (long)(flags))
+#define __sanitizer_syscall_post_process_vm_readv(res, pid, lvec, liovcnt, \
+ rvec, riovcnt, flags) \
+ __sanitizer_syscall_post_impl_process_vm_readv( \
+ res, (long)(pid), (long)(lvec), (long)(liovcnt), (long)(rvec), \
+ (long)(riovcnt), (long)(flags))
+#define __sanitizer_syscall_pre_process_vm_writev(pid, lvec, liovcnt, rvec, \
+ riovcnt, flags) \
+ __sanitizer_syscall_pre_impl_process_vm_writev( \
+ (long)(pid), (long)(lvec), (long)(liovcnt), (long)(rvec), \
+ (long)(riovcnt), (long)(flags))
+#define __sanitizer_syscall_post_process_vm_writev(res, pid, lvec, liovcnt, \
+ rvec, riovcnt, flags) \
+ __sanitizer_syscall_post_impl_process_vm_writev( \
+ res, (long)(pid), (long)(lvec), (long)(liovcnt), (long)(rvec), \
+ (long)(riovcnt), (long)(flags))
+#define __sanitizer_syscall_pre_fork() \
+ __sanitizer_syscall_pre_impl_fork()
+#define __sanitizer_syscall_post_fork(res) \
+ __sanitizer_syscall_post_impl_fork(res)
+#define __sanitizer_syscall_pre_vfork() \
+ __sanitizer_syscall_pre_impl_vfork()
+#define __sanitizer_syscall_post_vfork(res) \
+ __sanitizer_syscall_post_impl_vfork(res)
// And now a few syscalls we don't handle yet.
-
-#define __sanitizer_syscall_pre_accept(...)
-#define __sanitizer_syscall_pre_accept4(...)
-#define __sanitizer_syscall_pre_access(...)
-#define __sanitizer_syscall_pre_acct(...)
-#define __sanitizer_syscall_pre_add_key(...)
-#define __sanitizer_syscall_pre_adjtimex(...)
#define __sanitizer_syscall_pre_afs_syscall(...)
-#define __sanitizer_syscall_pre_alarm(...)
#define __sanitizer_syscall_pre_arch_prctl(...)
-#define __sanitizer_syscall_pre_bdflush(...)
-#define __sanitizer_syscall_pre_bind(...)
#define __sanitizer_syscall_pre_break(...)
-#define __sanitizer_syscall_pre_brk(...)
-#define __sanitizer_syscall_pre_capget(...)
-#define __sanitizer_syscall_pre_capset(...)
-#define __sanitizer_syscall_pre_chdir(...)
-#define __sanitizer_syscall_pre_chmod(...)
-#define __sanitizer_syscall_pre_chown(...)
#define __sanitizer_syscall_pre_chown32(...)
-#define __sanitizer_syscall_pre_chroot(...)
-#define __sanitizer_syscall_pre_clock_adjtime(...)
-#define __sanitizer_syscall_pre_clock_getres(...)
-#define __sanitizer_syscall_pre_clock_gettime(...)
-#define __sanitizer_syscall_pre_clock_nanosleep(...)
-#define __sanitizer_syscall_pre_clock_settime(...)
#define __sanitizer_syscall_pre_clone(...)
-#define __sanitizer_syscall_pre_close(...)
-#define __sanitizer_syscall_pre_connect(...)
-#define __sanitizer_syscall_pre_creat(...)
#define __sanitizer_syscall_pre_create_module(...)
-#define __sanitizer_syscall_pre_delete_module(...)
-#define __sanitizer_syscall_pre_dup(...)
-#define __sanitizer_syscall_pre_dup2(...)
-#define __sanitizer_syscall_pre_dup3(...)
-#define __sanitizer_syscall_pre_epoll_create(...)
-#define __sanitizer_syscall_pre_epoll_create1(...)
-#define __sanitizer_syscall_pre_epoll_ctl(...)
#define __sanitizer_syscall_pre_epoll_ctl_old(...)
-#define __sanitizer_syscall_pre_epoll_pwait(...)
-#define __sanitizer_syscall_pre_epoll_wait(...)
#define __sanitizer_syscall_pre_epoll_wait_old(...)
-#define __sanitizer_syscall_pre_eventfd(...)
-#define __sanitizer_syscall_pre_eventfd2(...)
#define __sanitizer_syscall_pre_execve(...)
-#define __sanitizer_syscall_pre_exit(...)
-#define __sanitizer_syscall_pre_exit_group(...)
-#define __sanitizer_syscall_pre_faccessat(...)
#define __sanitizer_syscall_pre_fadvise64(...)
#define __sanitizer_syscall_pre_fadvise64_64(...)
#define __sanitizer_syscall_pre_fallocate(...)
#define __sanitizer_syscall_pre_fanotify_init(...)
#define __sanitizer_syscall_pre_fanotify_mark(...)
-#define __sanitizer_syscall_pre_fchdir(...)
-#define __sanitizer_syscall_pre_fchmod(...)
-#define __sanitizer_syscall_pre_fchmodat(...)
-#define __sanitizer_syscall_pre_fchown(...)
#define __sanitizer_syscall_pre_fchown32(...)
-#define __sanitizer_syscall_pre_fchownat(...)
-#define __sanitizer_syscall_pre_fcntl(...)
-#define __sanitizer_syscall_pre_fcntl64(...)
-#define __sanitizer_syscall_pre_fdatasync(...)
-#define __sanitizer_syscall_pre_fgetxattr(...)
-#define __sanitizer_syscall_pre_flistxattr(...)
-#define __sanitizer_syscall_pre_flock(...)
-#define __sanitizer_syscall_pre_fork(...)
-#define __sanitizer_syscall_pre_fremovexattr(...)
-#define __sanitizer_syscall_pre_fsetxattr(...)
-#define __sanitizer_syscall_pre_fstat(...)
-#define __sanitizer_syscall_pre_fstat64(...)
-#define __sanitizer_syscall_pre_fstatat64(...)
-#define __sanitizer_syscall_pre_fstatfs(...)
-#define __sanitizer_syscall_pre_fstatfs64(...)
-#define __sanitizer_syscall_pre_fsync(...)
#define __sanitizer_syscall_pre_ftime(...)
-#define __sanitizer_syscall_pre_ftruncate(...)
#define __sanitizer_syscall_pre_ftruncate64(...)
#define __sanitizer_syscall_pre_futex(...)
-#define __sanitizer_syscall_pre_futimesat(...)
-#define __sanitizer_syscall_pre_getcpu(...)
-#define __sanitizer_syscall_pre_getcwd(...)
-#define __sanitizer_syscall_pre_getegid(...)
#define __sanitizer_syscall_pre_getegid32(...)
-#define __sanitizer_syscall_pre_geteuid(...)
#define __sanitizer_syscall_pre_geteuid32(...)
-#define __sanitizer_syscall_pre_getgid(...)
#define __sanitizer_syscall_pre_getgid32(...)
-#define __sanitizer_syscall_pre_getgroups(...)
#define __sanitizer_syscall_pre_getgroups32(...)
-#define __sanitizer_syscall_pre_getitimer(...)
#define __sanitizer_syscall_pre_get_kernel_syms(...)
-#define __sanitizer_syscall_pre_get_mempolicy(...)
-#define __sanitizer_syscall_pre_getpeername(...)
-#define __sanitizer_syscall_pre_getpgid(...)
-#define __sanitizer_syscall_pre_getpgrp(...)
-#define __sanitizer_syscall_pre_getpid(...)
#define __sanitizer_syscall_pre_getpmsg(...)
-#define __sanitizer_syscall_pre_getppid(...)
-#define __sanitizer_syscall_pre_getpriority(...)
-#define __sanitizer_syscall_pre_getresgid(...)
#define __sanitizer_syscall_pre_getresgid32(...)
-#define __sanitizer_syscall_pre_getresuid(...)
#define __sanitizer_syscall_pre_getresuid32(...)
-#define __sanitizer_syscall_pre_getrlimit(...)
-#define __sanitizer_syscall_pre_get_robust_list(...)
-#define __sanitizer_syscall_pre_getrusage(...)
-#define __sanitizer_syscall_pre_getsid(...)
-#define __sanitizer_syscall_pre_getsockname(...)
-#define __sanitizer_syscall_pre_getsockopt(...)
#define __sanitizer_syscall_pre_get_thread_area(...)
-#define __sanitizer_syscall_pre_gettid(...)
-#define __sanitizer_syscall_pre_gettimeofday(...)
-#define __sanitizer_syscall_pre_getuid(...)
#define __sanitizer_syscall_pre_getuid32(...)
-#define __sanitizer_syscall_pre_getxattr(...)
#define __sanitizer_syscall_pre_gtty(...)
#define __sanitizer_syscall_pre_idle(...)
-#define __sanitizer_syscall_pre_init_module(...)
-#define __sanitizer_syscall_pre_inotify_add_watch(...)
-#define __sanitizer_syscall_pre_inotify_init(...)
-#define __sanitizer_syscall_pre_inotify_init1(...)
-#define __sanitizer_syscall_pre_inotify_rm_watch(...)
-#define __sanitizer_syscall_pre_io_cancel(...)
-#define __sanitizer_syscall_pre_ioctl(...)
-#define __sanitizer_syscall_pre_io_destroy(...)
-#define __sanitizer_syscall_pre_io_getevents(...)
-#define __sanitizer_syscall_pre_ioperm(...)
#define __sanitizer_syscall_pre_iopl(...)
-#define __sanitizer_syscall_pre_ioprio_get(...)
-#define __sanitizer_syscall_pre_ioprio_set(...)
-#define __sanitizer_syscall_pre_io_setup(...)
-#define __sanitizer_syscall_pre_io_submit(...)
-#define __sanitizer_syscall_pre_ipc(...)
-#define __sanitizer_syscall_pre_kexec_load(...)
-#define __sanitizer_syscall_pre_keyctl(...)
-#define __sanitizer_syscall_pre_kill(...)
-#define __sanitizer_syscall_pre_lchown(...)
#define __sanitizer_syscall_pre_lchown32(...)
-#define __sanitizer_syscall_pre_lgetxattr(...)
-#define __sanitizer_syscall_pre_link(...)
-#define __sanitizer_syscall_pre_linkat(...)
-#define __sanitizer_syscall_pre_listen(...)
-#define __sanitizer_syscall_pre_listxattr(...)
-#define __sanitizer_syscall_pre_llistxattr(...)
#define __sanitizer_syscall_pre__llseek(...)
#define __sanitizer_syscall_pre_lock(...)
-#define __sanitizer_syscall_pre_lookup_dcookie(...)
-#define __sanitizer_syscall_pre_lremovexattr(...)
-#define __sanitizer_syscall_pre_lseek(...)
-#define __sanitizer_syscall_pre_lsetxattr(...)
-#define __sanitizer_syscall_pre_lstat(...)
-#define __sanitizer_syscall_pre_lstat64(...)
-#define __sanitizer_syscall_pre_madvise(...)
#define __sanitizer_syscall_pre_madvise1(...)
-#define __sanitizer_syscall_pre_mbind(...)
-#define __sanitizer_syscall_pre_migrate_pages(...)
-#define __sanitizer_syscall_pre_mincore(...)
-#define __sanitizer_syscall_pre_mkdir(...)
-#define __sanitizer_syscall_pre_mkdirat(...)
-#define __sanitizer_syscall_pre_mknod(...)
-#define __sanitizer_syscall_pre_mknodat(...)
-#define __sanitizer_syscall_pre_mlock(...)
-#define __sanitizer_syscall_pre_mlockall(...)
#define __sanitizer_syscall_pre_mmap(...)
#define __sanitizer_syscall_pre_mmap2(...)
#define __sanitizer_syscall_pre_modify_ldt(...)
-#define __sanitizer_syscall_pre_mount(...)
-#define __sanitizer_syscall_pre_move_pages(...)
-#define __sanitizer_syscall_pre_mprotect(...)
#define __sanitizer_syscall_pre_mpx(...)
-#define __sanitizer_syscall_pre_mq_getsetattr(...)
-#define __sanitizer_syscall_pre_mq_notify(...)
-#define __sanitizer_syscall_pre_mq_open(...)
-#define __sanitizer_syscall_pre_mq_timedreceive(...)
-#define __sanitizer_syscall_pre_mq_timedsend(...)
-#define __sanitizer_syscall_pre_mq_unlink(...)
-#define __sanitizer_syscall_pre_mremap(...)
-#define __sanitizer_syscall_pre_msgctl(...)
-#define __sanitizer_syscall_pre_msgget(...)
-#define __sanitizer_syscall_pre_msgrcv(...)
-#define __sanitizer_syscall_pre_msgsnd(...)
-#define __sanitizer_syscall_pre_msync(...)
-#define __sanitizer_syscall_pre_munlock(...)
-#define __sanitizer_syscall_pre_munlockall(...)
-#define __sanitizer_syscall_pre_munmap(...)
-#define __sanitizer_syscall_pre_name_to_handle_at(...)
-#define __sanitizer_syscall_pre_nanosleep(...)
-#define __sanitizer_syscall_pre_newfstatat(...)
#define __sanitizer_syscall_pre__newselect(...)
#define __sanitizer_syscall_pre_nfsservctl(...)
-#define __sanitizer_syscall_pre_nice(...)
#define __sanitizer_syscall_pre_oldfstat(...)
#define __sanitizer_syscall_pre_oldlstat(...)
#define __sanitizer_syscall_pre_oldolduname(...)
#define __sanitizer_syscall_pre_oldstat(...)
-#define __sanitizer_syscall_pre_olduname(...)
-#define __sanitizer_syscall_pre_open(...)
-#define __sanitizer_syscall_pre_openat(...)
-#define __sanitizer_syscall_pre_open_by_handle_at(...)
-#define __sanitizer_syscall_pre_pause(...)
-#define __sanitizer_syscall_pre_perf_event_open(...)
-#define __sanitizer_syscall_pre_personality(...)
-#define __sanitizer_syscall_pre_pipe(...)
-#define __sanitizer_syscall_pre_pipe2(...)
-#define __sanitizer_syscall_pre_pivot_root(...)
-#define __sanitizer_syscall_pre_poll(...)
-#define __sanitizer_syscall_pre_ppoll(...)
#define __sanitizer_syscall_pre_prctl(...)
-#define __sanitizer_syscall_pre_pread64(...)
-#define __sanitizer_syscall_pre_preadv(...)
-#define __sanitizer_syscall_pre_prlimit64(...)
-#define __sanitizer_syscall_pre_process_vm_readv(...)
-#define __sanitizer_syscall_pre_process_vm_writev(...)
#define __sanitizer_syscall_pre_prof(...)
#define __sanitizer_syscall_pre_profil(...)
-#define __sanitizer_syscall_pre_pselect6(...)
-#define __sanitizer_syscall_pre_ptrace(...)
#define __sanitizer_syscall_pre_putpmsg(...)
-#define __sanitizer_syscall_pre_pwrite64(...)
-#define __sanitizer_syscall_pre_pwritev(...)
#define __sanitizer_syscall_pre_query_module(...)
-#define __sanitizer_syscall_pre_quotactl(...)
-#define __sanitizer_syscall_pre_read(...)
#define __sanitizer_syscall_pre_readahead(...)
#define __sanitizer_syscall_pre_readdir(...)
-#define __sanitizer_syscall_pre_readlink(...)
-#define __sanitizer_syscall_pre_readlinkat(...)
-#define __sanitizer_syscall_pre_readv(...)
-#define __sanitizer_syscall_pre_reboot(...)
-#define __sanitizer_syscall_pre_recvfrom(...)
-#define __sanitizer_syscall_pre_recvmmsg(...)
-#define __sanitizer_syscall_pre_remap_file_pages(...)
-#define __sanitizer_syscall_pre_removexattr(...)
-#define __sanitizer_syscall_pre_rename(...)
-#define __sanitizer_syscall_pre_renameat(...)
-#define __sanitizer_syscall_pre_request_key(...)
-#define __sanitizer_syscall_pre_restart_syscall(...)
-#define __sanitizer_syscall_pre_rmdir(...)
#define __sanitizer_syscall_pre_rt_sigaction(...)
-#define __sanitizer_syscall_pre_rt_sigprocmask(...)
-#define __sanitizer_syscall_pre_rt_sigqueueinfo(...)
#define __sanitizer_syscall_pre_rt_sigreturn(...)
#define __sanitizer_syscall_pre_rt_sigsuspend(...)
-#define __sanitizer_syscall_pre_rt_sigtimedwait(...)
-#define __sanitizer_syscall_pre_rt_tgsigqueueinfo(...)
-#define __sanitizer_syscall_pre_sched_getaffinity(...)
-#define __sanitizer_syscall_pre_sched_getparam(...)
-#define __sanitizer_syscall_pre_sched_get_priority_max(...)
-#define __sanitizer_syscall_pre_sched_get_priority_min(...)
-#define __sanitizer_syscall_pre_sched_getscheduler(...)
-#define __sanitizer_syscall_pre_sched_rr_get_interval(...)
-#define __sanitizer_syscall_pre_sched_setaffinity(...)
-#define __sanitizer_syscall_pre_sched_setparam(...)
-#define __sanitizer_syscall_pre_sched_setscheduler(...)
-#define __sanitizer_syscall_pre_sched_yield(...)
#define __sanitizer_syscall_pre_security(...)
-#define __sanitizer_syscall_pre_select(...)
-#define __sanitizer_syscall_pre_semctl(...)
-#define __sanitizer_syscall_pre_semget(...)
-#define __sanitizer_syscall_pre_semop(...)
-#define __sanitizer_syscall_pre_semtimedop(...)
-#define __sanitizer_syscall_pre_sendfile(...)
-#define __sanitizer_syscall_pre_sendfile64(...)
-#define __sanitizer_syscall_pre_sendmmsg(...)
-#define __sanitizer_syscall_pre_sendmsg(...)
-#define __sanitizer_syscall_pre_sendto(...)
-#define __sanitizer_syscall_pre_setdomainname(...)
-#define __sanitizer_syscall_pre_setfsgid(...)
#define __sanitizer_syscall_pre_setfsgid32(...)
-#define __sanitizer_syscall_pre_setfsuid(...)
#define __sanitizer_syscall_pre_setfsuid32(...)
-#define __sanitizer_syscall_pre_setgid(...)
#define __sanitizer_syscall_pre_setgid32(...)
-#define __sanitizer_syscall_pre_setgroups(...)
#define __sanitizer_syscall_pre_setgroups32(...)
-#define __sanitizer_syscall_pre_sethostname(...)
-#define __sanitizer_syscall_pre_setitimer(...)
-#define __sanitizer_syscall_pre_set_mempolicy(...)
-#define __sanitizer_syscall_pre_setns(...)
-#define __sanitizer_syscall_pre_setpgid(...)
-#define __sanitizer_syscall_pre_setpriority(...)
-#define __sanitizer_syscall_pre_setregid(...)
#define __sanitizer_syscall_pre_setregid32(...)
-#define __sanitizer_syscall_pre_setresgid(...)
#define __sanitizer_syscall_pre_setresgid32(...)
-#define __sanitizer_syscall_pre_setresuid(...)
#define __sanitizer_syscall_pre_setresuid32(...)
-#define __sanitizer_syscall_pre_setreuid(...)
#define __sanitizer_syscall_pre_setreuid32(...)
-#define __sanitizer_syscall_pre_setrlimit(...)
-#define __sanitizer_syscall_pre_set_robust_list(...)
-#define __sanitizer_syscall_pre_setsid(...)
-#define __sanitizer_syscall_pre_setsockopt(...)
#define __sanitizer_syscall_pre_set_thread_area(...)
-#define __sanitizer_syscall_pre_set_tid_address(...)
-#define __sanitizer_syscall_pre_settimeofday(...)
-#define __sanitizer_syscall_pre_setuid(...)
#define __sanitizer_syscall_pre_setuid32(...)
-#define __sanitizer_syscall_pre_setxattr(...)
-#define __sanitizer_syscall_pre_sgetmask(...)
-#define __sanitizer_syscall_pre_shmat(...)
-#define __sanitizer_syscall_pre_shmctl(...)
-#define __sanitizer_syscall_pre_shmdt(...)
-#define __sanitizer_syscall_pre_shmget(...)
-#define __sanitizer_syscall_pre_shutdown(...)
#define __sanitizer_syscall_pre_sigaction(...)
#define __sanitizer_syscall_pre_sigaltstack(...)
-#define __sanitizer_syscall_pre_signal(...)
-#define __sanitizer_syscall_pre_signalfd(...)
-#define __sanitizer_syscall_pre_signalfd4(...)
-#define __sanitizer_syscall_pre_sigpending(...)
-#define __sanitizer_syscall_pre_sigprocmask(...)
#define __sanitizer_syscall_pre_sigreturn(...)
#define __sanitizer_syscall_pre_sigsuspend(...)
-#define __sanitizer_syscall_pre_socket(...)
-#define __sanitizer_syscall_pre_socketcall(...)
-#define __sanitizer_syscall_pre_socketpair(...)
-#define __sanitizer_syscall_pre_splice(...)
-#define __sanitizer_syscall_pre_ssetmask(...)
-#define __sanitizer_syscall_pre_stat(...)
-#define __sanitizer_syscall_pre_stat64(...)
-#define __sanitizer_syscall_pre_statfs(...)
-#define __sanitizer_syscall_pre_statfs64(...)
-#define __sanitizer_syscall_pre_stime(...)
#define __sanitizer_syscall_pre_stty(...)
-#define __sanitizer_syscall_pre_swapoff(...)
-#define __sanitizer_syscall_pre_swapon(...)
-#define __sanitizer_syscall_pre_symlink(...)
-#define __sanitizer_syscall_pre_symlinkat(...)
-#define __sanitizer_syscall_pre_sync(...)
#define __sanitizer_syscall_pre_sync_file_range(...)
-#define __sanitizer_syscall_pre_syncfs(...)
#define __sanitizer_syscall_pre__sysctl(...)
-#define __sanitizer_syscall_pre_sysfs(...)
-#define __sanitizer_syscall_pre_sysinfo(...)
-#define __sanitizer_syscall_pre_syslog(...)
-#define __sanitizer_syscall_pre_tee(...)
-#define __sanitizer_syscall_pre_tgkill(...)
-#define __sanitizer_syscall_pre_time(...)
-#define __sanitizer_syscall_pre_timer_create(...)
-#define __sanitizer_syscall_pre_timer_delete(...)
-#define __sanitizer_syscall_pre_timerfd_create(...)
-#define __sanitizer_syscall_pre_timerfd_gettime(...)
-#define __sanitizer_syscall_pre_timerfd_settime(...)
-#define __sanitizer_syscall_pre_timer_getoverrun(...)
-#define __sanitizer_syscall_pre_timer_gettime(...)
-#define __sanitizer_syscall_pre_timer_settime(...)
-#define __sanitizer_syscall_pre_times(...)
-#define __sanitizer_syscall_pre_tkill(...)
-#define __sanitizer_syscall_pre_truncate(...)
#define __sanitizer_syscall_pre_truncate64(...)
#define __sanitizer_syscall_pre_tuxcall(...)
#define __sanitizer_syscall_pre_ugetrlimit(...)
#define __sanitizer_syscall_pre_ulimit(...)
-#define __sanitizer_syscall_pre_umask(...)
-#define __sanitizer_syscall_pre_umount(...)
#define __sanitizer_syscall_pre_umount2(...)
-#define __sanitizer_syscall_pre_uname(...)
-#define __sanitizer_syscall_pre_unlink(...)
-#define __sanitizer_syscall_pre_unlinkat(...)
-#define __sanitizer_syscall_pre_unshare(...)
-#define __sanitizer_syscall_pre_uselib(...)
-#define __sanitizer_syscall_pre_ustat(...)
-#define __sanitizer_syscall_pre_utime(...)
-#define __sanitizer_syscall_pre_utimensat(...)
-#define __sanitizer_syscall_pre_utimes(...)
-#define __sanitizer_syscall_pre_vfork(...)
-#define __sanitizer_syscall_pre_vhangup(...)
#define __sanitizer_syscall_pre_vm86(...)
#define __sanitizer_syscall_pre_vm86old(...)
-#define __sanitizer_syscall_pre_vmsplice(...)
#define __sanitizer_syscall_pre_vserver(...)
-#define __sanitizer_syscall_pre_waitid(...)
-#define __sanitizer_syscall_pre_write(...)
-#define __sanitizer_syscall_pre_writev(...)
-#define __sanitizer_syscall_post_accept4(res, ...)
-#define __sanitizer_syscall_post_accept(res, ...)
-#define __sanitizer_syscall_post_access(res, ...)
-#define __sanitizer_syscall_post_acct(res, ...)
-#define __sanitizer_syscall_post_add_key(res, ...)
-#define __sanitizer_syscall_post_adjtimex(res, ...)
#define __sanitizer_syscall_post_afs_syscall(res, ...)
-#define __sanitizer_syscall_post_alarm(res, ...)
#define __sanitizer_syscall_post_arch_prctl(res, ...)
-#define __sanitizer_syscall_post_bdflush(res, ...)
-#define __sanitizer_syscall_post_bind(res, ...)
#define __sanitizer_syscall_post_break(res, ...)
-#define __sanitizer_syscall_post_brk(res, ...)
-#define __sanitizer_syscall_post_capget(res, ...)
-#define __sanitizer_syscall_post_capset(res, ...)
-#define __sanitizer_syscall_post_chdir(res, ...)
-#define __sanitizer_syscall_post_chmod(res, ...)
#define __sanitizer_syscall_post_chown32(res, ...)
-#define __sanitizer_syscall_post_chown(res, ...)
-#define __sanitizer_syscall_post_chroot(res, ...)
-#define __sanitizer_syscall_post_clock_adjtime(res, ...)
-#define __sanitizer_syscall_post_clock_getres(res, ...)
-#define __sanitizer_syscall_post_clock_gettime(res, ...)
-#define __sanitizer_syscall_post_clock_nanosleep(res, ...)
-#define __sanitizer_syscall_post_clock_settime(res, ...)
#define __sanitizer_syscall_post_clone(res, ...)
-#define __sanitizer_syscall_post_close(res, ...)
-#define __sanitizer_syscall_post_connect(res, ...)
#define __sanitizer_syscall_post_create_module(res, ...)
-#define __sanitizer_syscall_post_creat(res, ...)
-#define __sanitizer_syscall_post_delete_module(res, ...)
-#define __sanitizer_syscall_post_dup2(res, ...)
-#define __sanitizer_syscall_post_dup3(res, ...)
-#define __sanitizer_syscall_post_dup(res, ...)
-#define __sanitizer_syscall_post_epoll_create1(res, ...)
-#define __sanitizer_syscall_post_epoll_create(res, ...)
#define __sanitizer_syscall_post_epoll_ctl_old(res, ...)
-#define __sanitizer_syscall_post_epoll_ctl(res, ...)
-#define __sanitizer_syscall_post_epoll_pwait(res, ...)
#define __sanitizer_syscall_post_epoll_wait_old(res, ...)
-#define __sanitizer_syscall_post_epoll_wait(res, ...)
-#define __sanitizer_syscall_post_eventfd2(res, ...)
-#define __sanitizer_syscall_post_eventfd(res, ...)
#define __sanitizer_syscall_post_execve(res, ...)
-#define __sanitizer_syscall_post_exit_group(res, ...)
-#define __sanitizer_syscall_post_exit(res, ...)
-#define __sanitizer_syscall_post_faccessat(res, ...)
-#define __sanitizer_syscall_post_fadvise64_64(res, ...)
#define __sanitizer_syscall_post_fadvise64(res, ...)
+#define __sanitizer_syscall_post_fadvise64_64(res, ...)
#define __sanitizer_syscall_post_fallocate(res, ...)
#define __sanitizer_syscall_post_fanotify_init(res, ...)
#define __sanitizer_syscall_post_fanotify_mark(res, ...)
-#define __sanitizer_syscall_post_fchdir(res, ...)
-#define __sanitizer_syscall_post_fchmodat(res, ...)
-#define __sanitizer_syscall_post_fchmod(res, ...)
#define __sanitizer_syscall_post_fchown32(res, ...)
-#define __sanitizer_syscall_post_fchownat(res, ...)
-#define __sanitizer_syscall_post_fchown(res, ...)
-#define __sanitizer_syscall_post_fcntl64(res, ...)
-#define __sanitizer_syscall_post_fcntl(res, ...)
-#define __sanitizer_syscall_post_fdatasync(res, ...)
-#define __sanitizer_syscall_post_fgetxattr(res, ...)
-#define __sanitizer_syscall_post_flistxattr(res, ...)
-#define __sanitizer_syscall_post_flock(res, ...)
-#define __sanitizer_syscall_post_fork(res, ...)
-#define __sanitizer_syscall_post_fremovexattr(res, ...)
-#define __sanitizer_syscall_post_fsetxattr(res, ...)
-#define __sanitizer_syscall_post_fstat64(res, ...)
-#define __sanitizer_syscall_post_fstatat64(res, ...)
-#define __sanitizer_syscall_post_fstatfs64(res, ...)
-#define __sanitizer_syscall_post_fstatfs(res, ...)
-#define __sanitizer_syscall_post_fstat(res, ...)
-#define __sanitizer_syscall_post_fsync(res, ...)
#define __sanitizer_syscall_post_ftime(res, ...)
#define __sanitizer_syscall_post_ftruncate64(res, ...)
-#define __sanitizer_syscall_post_ftruncate(res, ...)
#define __sanitizer_syscall_post_futex(res, ...)
-#define __sanitizer_syscall_post_futimesat(res, ...)
-#define __sanitizer_syscall_post_getcpu(res, ...)
-#define __sanitizer_syscall_post_getcwd(res, ...)
#define __sanitizer_syscall_post_getegid32(res, ...)
-#define __sanitizer_syscall_post_getegid(res, ...)
#define __sanitizer_syscall_post_geteuid32(res, ...)
-#define __sanitizer_syscall_post_geteuid(res, ...)
#define __sanitizer_syscall_post_getgid32(res, ...)
-#define __sanitizer_syscall_post_getgid(res, ...)
#define __sanitizer_syscall_post_getgroups32(res, ...)
-#define __sanitizer_syscall_post_getgroups(res, ...)
-#define __sanitizer_syscall_post_getitimer(res, ...)
#define __sanitizer_syscall_post_get_kernel_syms(res, ...)
-#define __sanitizer_syscall_post_get_mempolicy(res, ...)
-#define __sanitizer_syscall_post_getpeername(res, ...)
-#define __sanitizer_syscall_post_getpgid(res, ...)
-#define __sanitizer_syscall_post_getpgrp(res, ...)
-#define __sanitizer_syscall_post_getpid(res, ...)
#define __sanitizer_syscall_post_getpmsg(res, ...)
-#define __sanitizer_syscall_post_getppid(res, ...)
-#define __sanitizer_syscall_post_getpriority(res, ...)
#define __sanitizer_syscall_post_getresgid32(res, ...)
-#define __sanitizer_syscall_post_getresgid(res, ...)
#define __sanitizer_syscall_post_getresuid32(res, ...)
-#define __sanitizer_syscall_post_getresuid(res, ...)
-#define __sanitizer_syscall_post_getrlimit(res, ...)
-#define __sanitizer_syscall_post_get_robust_list(res, ...)
-#define __sanitizer_syscall_post_getrusage(res, ...)
-#define __sanitizer_syscall_post_getsid(res, ...)
-#define __sanitizer_syscall_post_getsockname(res, ...)
-#define __sanitizer_syscall_post_getsockopt(res, ...)
#define __sanitizer_syscall_post_get_thread_area(res, ...)
-#define __sanitizer_syscall_post_gettid(res, ...)
-#define __sanitizer_syscall_post_gettimeofday(res, ...)
#define __sanitizer_syscall_post_getuid32(res, ...)
-#define __sanitizer_syscall_post_getuid(res, ...)
-#define __sanitizer_syscall_post_getxattr(res, ...)
#define __sanitizer_syscall_post_gtty(res, ...)
#define __sanitizer_syscall_post_idle(res, ...)
-#define __sanitizer_syscall_post_init_module(res, ...)
-#define __sanitizer_syscall_post_inotify_add_watch(res, ...)
-#define __sanitizer_syscall_post_inotify_init1(res, ...)
-#define __sanitizer_syscall_post_inotify_init(res, ...)
-#define __sanitizer_syscall_post_inotify_rm_watch(res, ...)
-#define __sanitizer_syscall_post_io_cancel(res, ...)
-#define __sanitizer_syscall_post_ioctl(res, ...)
-#define __sanitizer_syscall_post_io_destroy(res, ...)
-#define __sanitizer_syscall_post_io_getevents(res, ...)
-#define __sanitizer_syscall_post_ioperm(res, ...)
#define __sanitizer_syscall_post_iopl(res, ...)
-#define __sanitizer_syscall_post_ioprio_get(res, ...)
-#define __sanitizer_syscall_post_ioprio_set(res, ...)
-#define __sanitizer_syscall_post_io_setup(res, ...)
-#define __sanitizer_syscall_post_io_submit(res, ...)
-#define __sanitizer_syscall_post_ipc(res, ...)
-#define __sanitizer_syscall_post_kexec_load(res, ...)
-#define __sanitizer_syscall_post_keyctl(res, ...)
-#define __sanitizer_syscall_post_kill(res, ...)
#define __sanitizer_syscall_post_lchown32(res, ...)
-#define __sanitizer_syscall_post_lchown(res, ...)
-#define __sanitizer_syscall_post_lgetxattr(res, ...)
-#define __sanitizer_syscall_post_linkat(res, ...)
-#define __sanitizer_syscall_post_link(res, ...)
-#define __sanitizer_syscall_post_listen(res, ...)
-#define __sanitizer_syscall_post_listxattr(res, ...)
-#define __sanitizer_syscall_post_llistxattr(res, ...)
#define __sanitizer_syscall_post__llseek(res, ...)
#define __sanitizer_syscall_post_lock(res, ...)
-#define __sanitizer_syscall_post_lookup_dcookie(res, ...)
-#define __sanitizer_syscall_post_lremovexattr(res, ...)
-#define __sanitizer_syscall_post_lseek(res, ...)
-#define __sanitizer_syscall_post_lsetxattr(res, ...)
-#define __sanitizer_syscall_post_lstat64(res, ...)
-#define __sanitizer_syscall_post_lstat(res, ...)
#define __sanitizer_syscall_post_madvise1(res, ...)
-#define __sanitizer_syscall_post_madvise(res, ...)
-#define __sanitizer_syscall_post_mbind(res, ...)
-#define __sanitizer_syscall_post_migrate_pages(res, ...)
-#define __sanitizer_syscall_post_mincore(res, ...)
-#define __sanitizer_syscall_post_mkdirat(res, ...)
-#define __sanitizer_syscall_post_mkdir(res, ...)
-#define __sanitizer_syscall_post_mknodat(res, ...)
-#define __sanitizer_syscall_post_mknod(res, ...)
-#define __sanitizer_syscall_post_mlockall(res, ...)
-#define __sanitizer_syscall_post_mlock(res, ...)
#define __sanitizer_syscall_post_mmap2(res, ...)
#define __sanitizer_syscall_post_mmap(res, ...)
#define __sanitizer_syscall_post_modify_ldt(res, ...)
-#define __sanitizer_syscall_post_mount(res, ...)
-#define __sanitizer_syscall_post_move_pages(res, ...)
-#define __sanitizer_syscall_post_mprotect(res, ...)
#define __sanitizer_syscall_post_mpx(res, ...)
-#define __sanitizer_syscall_post_mq_getsetattr(res, ...)
-#define __sanitizer_syscall_post_mq_notify(res, ...)
-#define __sanitizer_syscall_post_mq_open(res, ...)
-#define __sanitizer_syscall_post_mq_timedreceive(res, ...)
-#define __sanitizer_syscall_post_mq_timedsend(res, ...)
-#define __sanitizer_syscall_post_mq_unlink(res, ...)
-#define __sanitizer_syscall_post_mremap(res, ...)
-#define __sanitizer_syscall_post_msgctl(res, ...)
-#define __sanitizer_syscall_post_msgget(res, ...)
-#define __sanitizer_syscall_post_msgrcv(res, ...)
-#define __sanitizer_syscall_post_msgsnd(res, ...)
-#define __sanitizer_syscall_post_msync(res, ...)
-#define __sanitizer_syscall_post_munlockall(res, ...)
-#define __sanitizer_syscall_post_munlock(res, ...)
-#define __sanitizer_syscall_post_munmap(res, ...)
-#define __sanitizer_syscall_post_name_to_handle_at(res, ...)
-#define __sanitizer_syscall_post_nanosleep(res, ...)
-#define __sanitizer_syscall_post_newfstatat(res, ...)
#define __sanitizer_syscall_post__newselect(res, ...)
#define __sanitizer_syscall_post_nfsservctl(res, ...)
-#define __sanitizer_syscall_post_nice(res, ...)
#define __sanitizer_syscall_post_oldfstat(res, ...)
#define __sanitizer_syscall_post_oldlstat(res, ...)
#define __sanitizer_syscall_post_oldolduname(res, ...)
#define __sanitizer_syscall_post_oldstat(res, ...)
-#define __sanitizer_syscall_post_olduname(res, ...)
-#define __sanitizer_syscall_post_openat(res, ...)
-#define __sanitizer_syscall_post_open_by_handle_at(res, ...)
-#define __sanitizer_syscall_post_open(res, ...)
-#define __sanitizer_syscall_post_pause(res, ...)
-#define __sanitizer_syscall_post_perf_event_open(res, ...)
-#define __sanitizer_syscall_post_personality(res, ...)
-#define __sanitizer_syscall_post_pipe2(res, ...)
-#define __sanitizer_syscall_post_pipe(res, ...)
-#define __sanitizer_syscall_post_pivot_root(res, ...)
-#define __sanitizer_syscall_post_poll(res, ...)
-#define __sanitizer_syscall_post_ppoll(res, ...)
#define __sanitizer_syscall_post_prctl(res, ...)
-#define __sanitizer_syscall_post_pread64(res, ...)
-#define __sanitizer_syscall_post_preadv(res, ...)
-#define __sanitizer_syscall_post_prlimit64(res, ...)
-#define __sanitizer_syscall_post_process_vm_readv(res, ...)
-#define __sanitizer_syscall_post_process_vm_writev(res, ...)
#define __sanitizer_syscall_post_profil(res, ...)
#define __sanitizer_syscall_post_prof(res, ...)
-#define __sanitizer_syscall_post_pselect6(res, ...)
-#define __sanitizer_syscall_post_ptrace(res, ...)
#define __sanitizer_syscall_post_putpmsg(res, ...)
-#define __sanitizer_syscall_post_pwrite64(res, ...)
-#define __sanitizer_syscall_post_pwritev(res, ...)
#define __sanitizer_syscall_post_query_module(res, ...)
-#define __sanitizer_syscall_post_quotactl(res, ...)
#define __sanitizer_syscall_post_readahead(res, ...)
#define __sanitizer_syscall_post_readdir(res, ...)
-#define __sanitizer_syscall_post_readlinkat(res, ...)
-#define __sanitizer_syscall_post_readlink(res, ...)
-#define __sanitizer_syscall_post_read(res, ...)
-#define __sanitizer_syscall_post_readv(res, ...)
-#define __sanitizer_syscall_post_reboot(res, ...)
-#define __sanitizer_syscall_post_recvfrom(res, ...)
-#define __sanitizer_syscall_post_recvmmsg(res, ...)
-#define __sanitizer_syscall_post_remap_file_pages(res, ...)
-#define __sanitizer_syscall_post_removexattr(res, ...)
-#define __sanitizer_syscall_post_renameat(res, ...)
-#define __sanitizer_syscall_post_rename(res, ...)
-#define __sanitizer_syscall_post_request_key(res, ...)
-#define __sanitizer_syscall_post_restart_syscall(res, ...)
-#define __sanitizer_syscall_post_rmdir(res, ...)
#define __sanitizer_syscall_post_rt_sigaction(res, ...)
-#define __sanitizer_syscall_post_rt_sigprocmask(res, ...)
-#define __sanitizer_syscall_post_rt_sigqueueinfo(res, ...)
#define __sanitizer_syscall_post_rt_sigreturn(res, ...)
#define __sanitizer_syscall_post_rt_sigsuspend(res, ...)
-#define __sanitizer_syscall_post_rt_sigtimedwait(res, ...)
-#define __sanitizer_syscall_post_rt_tgsigqueueinfo(res, ...)
-#define __sanitizer_syscall_post_sched_getaffinity(res, ...)
-#define __sanitizer_syscall_post_sched_getparam(res, ...)
-#define __sanitizer_syscall_post_sched_get_priority_max(res, ...)
-#define __sanitizer_syscall_post_sched_get_priority_min(res, ...)
-#define __sanitizer_syscall_post_sched_getscheduler(res, ...)
-#define __sanitizer_syscall_post_sched_rr_get_interval(res, ...)
-#define __sanitizer_syscall_post_sched_setaffinity(res, ...)
-#define __sanitizer_syscall_post_sched_setparam(res, ...)
-#define __sanitizer_syscall_post_sched_setscheduler(res, ...)
-#define __sanitizer_syscall_post_sched_yield(res, ...)
#define __sanitizer_syscall_post_security(res, ...)
-#define __sanitizer_syscall_post_select(res, ...)
-#define __sanitizer_syscall_post_semctl(res, ...)
-#define __sanitizer_syscall_post_semget(res, ...)
-#define __sanitizer_syscall_post_semop(res, ...)
-#define __sanitizer_syscall_post_semtimedop(res, ...)
-#define __sanitizer_syscall_post_sendfile64(res, ...)
-#define __sanitizer_syscall_post_sendfile(res, ...)
-#define __sanitizer_syscall_post_sendmmsg(res, ...)
-#define __sanitizer_syscall_post_sendmsg(res, ...)
-#define __sanitizer_syscall_post_sendto(res, ...)
-#define __sanitizer_syscall_post_setdomainname(res, ...)
#define __sanitizer_syscall_post_setfsgid32(res, ...)
-#define __sanitizer_syscall_post_setfsgid(res, ...)
#define __sanitizer_syscall_post_setfsuid32(res, ...)
-#define __sanitizer_syscall_post_setfsuid(res, ...)
#define __sanitizer_syscall_post_setgid32(res, ...)
-#define __sanitizer_syscall_post_setgid(res, ...)
#define __sanitizer_syscall_post_setgroups32(res, ...)
-#define __sanitizer_syscall_post_setgroups(res, ...)
-#define __sanitizer_syscall_post_sethostname(res, ...)
-#define __sanitizer_syscall_post_setitimer(res, ...)
-#define __sanitizer_syscall_post_set_mempolicy(res, ...)
-#define __sanitizer_syscall_post_setns(res, ...)
-#define __sanitizer_syscall_post_setpgid(res, ...)
-#define __sanitizer_syscall_post_setpriority(res, ...)
#define __sanitizer_syscall_post_setregid32(res, ...)
-#define __sanitizer_syscall_post_setregid(res, ...)
#define __sanitizer_syscall_post_setresgid32(res, ...)
-#define __sanitizer_syscall_post_setresgid(res, ...)
#define __sanitizer_syscall_post_setresuid32(res, ...)
-#define __sanitizer_syscall_post_setresuid(res, ...)
#define __sanitizer_syscall_post_setreuid32(res, ...)
-#define __sanitizer_syscall_post_setreuid(res, ...)
-#define __sanitizer_syscall_post_setrlimit(res, ...)
-#define __sanitizer_syscall_post_set_robust_list(res, ...)
-#define __sanitizer_syscall_post_setsid(res, ...)
-#define __sanitizer_syscall_post_setsockopt(res, ...)
#define __sanitizer_syscall_post_set_thread_area(res, ...)
-#define __sanitizer_syscall_post_set_tid_address(res, ...)
-#define __sanitizer_syscall_post_settimeofday(res, ...)
#define __sanitizer_syscall_post_setuid32(res, ...)
-#define __sanitizer_syscall_post_setuid(res, ...)
-#define __sanitizer_syscall_post_setxattr(res, ...)
-#define __sanitizer_syscall_post_sgetmask(res, ...)
-#define __sanitizer_syscall_post_shmat(res, ...)
-#define __sanitizer_syscall_post_shmctl(res, ...)
-#define __sanitizer_syscall_post_shmdt(res, ...)
-#define __sanitizer_syscall_post_shmget(res, ...)
-#define __sanitizer_syscall_post_shutdown(res, ...)
#define __sanitizer_syscall_post_sigaction(res, ...)
#define __sanitizer_syscall_post_sigaltstack(res, ...)
-#define __sanitizer_syscall_post_signalfd4(res, ...)
-#define __sanitizer_syscall_post_signalfd(res, ...)
-#define __sanitizer_syscall_post_signal(res, ...)
-#define __sanitizer_syscall_post_sigpending(res, ...)
-#define __sanitizer_syscall_post_sigprocmask(res, ...)
#define __sanitizer_syscall_post_sigreturn(res, ...)
#define __sanitizer_syscall_post_sigsuspend(res, ...)
-#define __sanitizer_syscall_post_socketcall(res, ...)
-#define __sanitizer_syscall_post_socketpair(res, ...)
-#define __sanitizer_syscall_post_socket(res, ...)
-#define __sanitizer_syscall_post_splice(res, ...)
-#define __sanitizer_syscall_post_ssetmask(res, ...)
-#define __sanitizer_syscall_post_stat64(res, ...)
-#define __sanitizer_syscall_post_statfs64(res, ...)
-#define __sanitizer_syscall_post_statfs(res, ...)
-#define __sanitizer_syscall_post_stat(res, ...)
-#define __sanitizer_syscall_post_stime(res, ...)
#define __sanitizer_syscall_post_stty(res, ...)
-#define __sanitizer_syscall_post_swapoff(res, ...)
-#define __sanitizer_syscall_post_swapon(res, ...)
-#define __sanitizer_syscall_post_symlinkat(res, ...)
-#define __sanitizer_syscall_post_symlink(res, ...)
#define __sanitizer_syscall_post_sync_file_range(res, ...)
-#define __sanitizer_syscall_post_syncfs(res, ...)
-#define __sanitizer_syscall_post_sync(res, ...)
#define __sanitizer_syscall_post__sysctl(res, ...)
-#define __sanitizer_syscall_post_sysfs(res, ...)
-#define __sanitizer_syscall_post_sysinfo(res, ...)
-#define __sanitizer_syscall_post_syslog(res, ...)
-#define __sanitizer_syscall_post_tee(res, ...)
-#define __sanitizer_syscall_post_tgkill(res, ...)
-#define __sanitizer_syscall_post_timer_create(res, ...)
-#define __sanitizer_syscall_post_timer_delete(res, ...)
-#define __sanitizer_syscall_post_time(res, ...)
-#define __sanitizer_syscall_post_timerfd_create(res, ...)
-#define __sanitizer_syscall_post_timerfd_gettime(res, ...)
-#define __sanitizer_syscall_post_timerfd_settime(res, ...)
-#define __sanitizer_syscall_post_timer_getoverrun(res, ...)
-#define __sanitizer_syscall_post_timer_gettime(res, ...)
-#define __sanitizer_syscall_post_timer_settime(res, ...)
-#define __sanitizer_syscall_post_times(res, ...)
-#define __sanitizer_syscall_post_tkill(res, ...)
#define __sanitizer_syscall_post_truncate64(res, ...)
-#define __sanitizer_syscall_post_truncate(res, ...)
#define __sanitizer_syscall_post_tuxcall(res, ...)
#define __sanitizer_syscall_post_ugetrlimit(res, ...)
#define __sanitizer_syscall_post_ulimit(res, ...)
-#define __sanitizer_syscall_post_umask(res, ...)
#define __sanitizer_syscall_post_umount2(res, ...)
-#define __sanitizer_syscall_post_umount(res, ...)
-#define __sanitizer_syscall_post_uname(res, ...)
-#define __sanitizer_syscall_post_unlinkat(res, ...)
-#define __sanitizer_syscall_post_unlink(res, ...)
-#define __sanitizer_syscall_post_unshare(res, ...)
-#define __sanitizer_syscall_post_uselib(res, ...)
-#define __sanitizer_syscall_post_ustat(res, ...)
-#define __sanitizer_syscall_post_utimensat(res, ...)
-#define __sanitizer_syscall_post_utime(res, ...)
-#define __sanitizer_syscall_post_utimes(res, ...)
-#define __sanitizer_syscall_post_vfork(res, ...)
-#define __sanitizer_syscall_post_vhangup(res, ...)
#define __sanitizer_syscall_post_vm86old(res, ...)
#define __sanitizer_syscall_post_vm86(res, ...)
-#define __sanitizer_syscall_post_vmsplice(res, ...)
#define __sanitizer_syscall_post_vserver(res, ...)
-#define __sanitizer_syscall_post_waitid(res, ...)
-#define __sanitizer_syscall_post_write(res, ...)
-#define __sanitizer_syscall_post_writev(res, ...)
#ifdef __cplusplus
-} // extern "C"
+extern "C" {
+#endif
+
+// Private declarations. Do not call directly from user code. Use macros above.
+void __sanitizer_syscall_pre_impl_time(long tloc);
+void __sanitizer_syscall_post_impl_time(long res, long tloc);
+void __sanitizer_syscall_pre_impl_stime(long tptr);
+void __sanitizer_syscall_post_impl_stime(long res, long tptr);
+void __sanitizer_syscall_pre_impl_gettimeofday(long tv, long tz);
+void __sanitizer_syscall_post_impl_gettimeofday(long res, long tv, long tz);
+void __sanitizer_syscall_pre_impl_settimeofday(long tv, long tz);
+void __sanitizer_syscall_post_impl_settimeofday(long res, long tv, long tz);
+void __sanitizer_syscall_pre_impl_adjtimex(long txc_p);
+void __sanitizer_syscall_post_impl_adjtimex(long res, long txc_p);
+void __sanitizer_syscall_pre_impl_times(long tbuf);
+void __sanitizer_syscall_post_impl_times(long res, long tbuf);
+void __sanitizer_syscall_pre_impl_gettid();
+void __sanitizer_syscall_post_impl_gettid(long res);
+void __sanitizer_syscall_pre_impl_nanosleep(long rqtp, long rmtp);
+void __sanitizer_syscall_post_impl_nanosleep(long res, long rqtp, long rmtp);
+void __sanitizer_syscall_pre_impl_alarm(long seconds);
+void __sanitizer_syscall_post_impl_alarm(long res, long seconds);
+void __sanitizer_syscall_pre_impl_getpid();
+void __sanitizer_syscall_post_impl_getpid(long res);
+void __sanitizer_syscall_pre_impl_getppid();
+void __sanitizer_syscall_post_impl_getppid(long res);
+void __sanitizer_syscall_pre_impl_getuid();
+void __sanitizer_syscall_post_impl_getuid(long res);
+void __sanitizer_syscall_pre_impl_geteuid();
+void __sanitizer_syscall_post_impl_geteuid(long res);
+void __sanitizer_syscall_pre_impl_getgid();
+void __sanitizer_syscall_post_impl_getgid(long res);
+void __sanitizer_syscall_pre_impl_getegid();
+void __sanitizer_syscall_post_impl_getegid(long res);
+void __sanitizer_syscall_pre_impl_getresuid(long ruid, long euid, long suid);
+void __sanitizer_syscall_post_impl_getresuid(long res, long ruid, long euid,
+ long suid);
+void __sanitizer_syscall_pre_impl_getresgid(long rgid, long egid, long sgid);
+void __sanitizer_syscall_post_impl_getresgid(long res, long rgid, long egid,
+ long sgid);
+void __sanitizer_syscall_pre_impl_getpgid(long pid);
+void __sanitizer_syscall_post_impl_getpgid(long res, long pid);
+void __sanitizer_syscall_pre_impl_getpgrp();
+void __sanitizer_syscall_post_impl_getpgrp(long res);
+void __sanitizer_syscall_pre_impl_getsid(long pid);
+void __sanitizer_syscall_post_impl_getsid(long res, long pid);
+void __sanitizer_syscall_pre_impl_getgroups(long gidsetsize, long grouplist);
+void __sanitizer_syscall_post_impl_getgroups(long res, long gidsetsize,
+ long grouplist);
+void __sanitizer_syscall_pre_impl_setregid(long rgid, long egid);
+void __sanitizer_syscall_post_impl_setregid(long res, long rgid, long egid);
+void __sanitizer_syscall_pre_impl_setgid(long gid);
+void __sanitizer_syscall_post_impl_setgid(long res, long gid);
+void __sanitizer_syscall_pre_impl_setreuid(long ruid, long euid);
+void __sanitizer_syscall_post_impl_setreuid(long res, long ruid, long euid);
+void __sanitizer_syscall_pre_impl_setuid(long uid);
+void __sanitizer_syscall_post_impl_setuid(long res, long uid);
+void __sanitizer_syscall_pre_impl_setresuid(long ruid, long euid, long suid);
+void __sanitizer_syscall_post_impl_setresuid(long res, long ruid, long euid,
+ long suid);
+void __sanitizer_syscall_pre_impl_setresgid(long rgid, long egid, long sgid);
+void __sanitizer_syscall_post_impl_setresgid(long res, long rgid, long egid,
+ long sgid);
+void __sanitizer_syscall_pre_impl_setfsuid(long uid);
+void __sanitizer_syscall_post_impl_setfsuid(long res, long uid);
+void __sanitizer_syscall_pre_impl_setfsgid(long gid);
+void __sanitizer_syscall_post_impl_setfsgid(long res, long gid);
+void __sanitizer_syscall_pre_impl_setpgid(long pid, long pgid);
+void __sanitizer_syscall_post_impl_setpgid(long res, long pid, long pgid);
+void __sanitizer_syscall_pre_impl_setsid();
+void __sanitizer_syscall_post_impl_setsid(long res);
+void __sanitizer_syscall_pre_impl_setgroups(long gidsetsize, long grouplist);
+void __sanitizer_syscall_post_impl_setgroups(long res, long gidsetsize,
+ long grouplist);
+void __sanitizer_syscall_pre_impl_acct(long name);
+void __sanitizer_syscall_post_impl_acct(long res, long name);
+void __sanitizer_syscall_pre_impl_capget(long header, long dataptr);
+void __sanitizer_syscall_post_impl_capget(long res, long header, long dataptr);
+void __sanitizer_syscall_pre_impl_capset(long header, long data);
+void __sanitizer_syscall_post_impl_capset(long res, long header, long data);
+void __sanitizer_syscall_pre_impl_personality(long personality);
+void __sanitizer_syscall_post_impl_personality(long res, long personality);
+void __sanitizer_syscall_pre_impl_sigpending(long set);
+void __sanitizer_syscall_post_impl_sigpending(long res, long set);
+void __sanitizer_syscall_pre_impl_sigprocmask(long how, long set, long oset);
+void __sanitizer_syscall_post_impl_sigprocmask(long res, long how, long set,
+ long oset);
+void __sanitizer_syscall_pre_impl_getitimer(long which, long value);
+void __sanitizer_syscall_post_impl_getitimer(long res, long which, long value);
+void __sanitizer_syscall_pre_impl_setitimer(long which, long value,
+ long ovalue);
+void __sanitizer_syscall_post_impl_setitimer(long res, long which, long value,
+ long ovalue);
+void __sanitizer_syscall_pre_impl_timer_create(long which_clock,
+ long timer_event_spec,
+ long created_timer_id);
+void __sanitizer_syscall_post_impl_timer_create(long res, long which_clock,
+ long timer_event_spec,
+ long created_timer_id);
+void __sanitizer_syscall_pre_impl_timer_gettime(long timer_id, long setting);
+void __sanitizer_syscall_post_impl_timer_gettime(long res, long timer_id,
+ long setting);
+void __sanitizer_syscall_pre_impl_timer_getoverrun(long timer_id);
+void __sanitizer_syscall_post_impl_timer_getoverrun(long res, long timer_id);
+void __sanitizer_syscall_pre_impl_timer_settime(long timer_id, long flags,
+ long new_setting,
+ long old_setting);
+void __sanitizer_syscall_post_impl_timer_settime(long res, long timer_id,
+ long flags, long new_setting,
+ long old_setting);
+void __sanitizer_syscall_pre_impl_timer_delete(long timer_id);
+void __sanitizer_syscall_post_impl_timer_delete(long res, long timer_id);
+void __sanitizer_syscall_pre_impl_clock_settime(long which_clock, long tp);
+void __sanitizer_syscall_post_impl_clock_settime(long res, long which_clock,
+ long tp);
+void __sanitizer_syscall_pre_impl_clock_gettime(long which_clock, long tp);
+void __sanitizer_syscall_post_impl_clock_gettime(long res, long which_clock,
+ long tp);
+void __sanitizer_syscall_pre_impl_clock_adjtime(long which_clock, long tx);
+void __sanitizer_syscall_post_impl_clock_adjtime(long res, long which_clock,
+ long tx);
+void __sanitizer_syscall_pre_impl_clock_getres(long which_clock, long tp);
+void __sanitizer_syscall_post_impl_clock_getres(long res, long which_clock,
+ long tp);
+void __sanitizer_syscall_pre_impl_clock_nanosleep(long which_clock, long flags,
+ long rqtp, long rmtp);
+void __sanitizer_syscall_post_impl_clock_nanosleep(long res, long which_clock,
+ long flags, long rqtp,
+ long rmtp);
+void __sanitizer_syscall_pre_impl_nice(long increment);
+void __sanitizer_syscall_post_impl_nice(long res, long increment);
+void __sanitizer_syscall_pre_impl_sched_setscheduler(long pid, long policy,
+ long param);
+void __sanitizer_syscall_post_impl_sched_setscheduler(long res, long pid,
+ long policy, long param);
+void __sanitizer_syscall_pre_impl_sched_setparam(long pid, long param);
+void __sanitizer_syscall_post_impl_sched_setparam(long res, long pid,
+ long param);
+void __sanitizer_syscall_pre_impl_sched_getscheduler(long pid);
+void __sanitizer_syscall_post_impl_sched_getscheduler(long res, long pid);
+void __sanitizer_syscall_pre_impl_sched_getparam(long pid, long param);
+void __sanitizer_syscall_post_impl_sched_getparam(long res, long pid,
+ long param);
+void __sanitizer_syscall_pre_impl_sched_setaffinity(long pid, long len,
+ long user_mask_ptr);
+void __sanitizer_syscall_post_impl_sched_setaffinity(long res, long pid,
+ long len,
+ long user_mask_ptr);
+void __sanitizer_syscall_pre_impl_sched_getaffinity(long pid, long len,
+ long user_mask_ptr);
+void __sanitizer_syscall_post_impl_sched_getaffinity(long res, long pid,
+ long len,
+ long user_mask_ptr);
+void __sanitizer_syscall_pre_impl_sched_yield();
+void __sanitizer_syscall_post_impl_sched_yield(long res);
+void __sanitizer_syscall_pre_impl_sched_get_priority_max(long policy);
+void __sanitizer_syscall_post_impl_sched_get_priority_max(long res,
+ long policy);
+void __sanitizer_syscall_pre_impl_sched_get_priority_min(long policy);
+void __sanitizer_syscall_post_impl_sched_get_priority_min(long res,
+ long policy);
+void __sanitizer_syscall_pre_impl_sched_rr_get_interval(long pid,
+ long interval);
+void __sanitizer_syscall_post_impl_sched_rr_get_interval(long res, long pid,
+ long interval);
+void __sanitizer_syscall_pre_impl_setpriority(long which, long who,
+ long niceval);
+void __sanitizer_syscall_post_impl_setpriority(long res, long which, long who,
+ long niceval);
+void __sanitizer_syscall_pre_impl_getpriority(long which, long who);
+void __sanitizer_syscall_post_impl_getpriority(long res, long which, long who);
+void __sanitizer_syscall_pre_impl_shutdown(long arg0, long arg1);
+void __sanitizer_syscall_post_impl_shutdown(long res, long arg0, long arg1);
+void __sanitizer_syscall_pre_impl_reboot(long magic1, long magic2, long cmd,
+ long arg);
+void __sanitizer_syscall_post_impl_reboot(long res, long magic1, long magic2,
+ long cmd, long arg);
+void __sanitizer_syscall_pre_impl_restart_syscall();
+void __sanitizer_syscall_post_impl_restart_syscall(long res);
+void __sanitizer_syscall_pre_impl_kexec_load(long entry, long nr_segments,
+ long segments, long flags);
+void __sanitizer_syscall_post_impl_kexec_load(long res, long entry,
+ long nr_segments, long segments,
+ long flags);
+void __sanitizer_syscall_pre_impl_exit(long error_code);
+void __sanitizer_syscall_post_impl_exit(long res, long error_code);
+void __sanitizer_syscall_pre_impl_exit_group(long error_code);
+void __sanitizer_syscall_post_impl_exit_group(long res, long error_code);
+void __sanitizer_syscall_pre_impl_wait4(long pid, long stat_addr, long options,
+ long ru);
+void __sanitizer_syscall_post_impl_wait4(long res, long pid, long stat_addr,
+ long options, long ru);
+void __sanitizer_syscall_pre_impl_waitid(long which, long pid, long infop,
+ long options, long ru);
+void __sanitizer_syscall_post_impl_waitid(long res, long which, long pid,
+ long infop, long options, long ru);
+void __sanitizer_syscall_pre_impl_waitpid(long pid, long stat_addr,
+ long options);
+void __sanitizer_syscall_post_impl_waitpid(long res, long pid, long stat_addr,
+ long options);
+void __sanitizer_syscall_pre_impl_set_tid_address(long tidptr);
+void __sanitizer_syscall_post_impl_set_tid_address(long res, long tidptr);
+void __sanitizer_syscall_pre_impl_init_module(long umod, long len, long uargs);
+void __sanitizer_syscall_post_impl_init_module(long res, long umod, long len,
+ long uargs);
+void __sanitizer_syscall_pre_impl_delete_module(long name_user, long flags);
+void __sanitizer_syscall_post_impl_delete_module(long res, long name_user,
+ long flags);
+void __sanitizer_syscall_pre_impl_rt_sigprocmask(long how, long set, long oset,
+ long sigsetsize);
+void __sanitizer_syscall_post_impl_rt_sigprocmask(long res, long how, long set,
+ long oset, long sigsetsize);
+void __sanitizer_syscall_pre_impl_rt_sigpending(long set, long sigsetsize);
+void __sanitizer_syscall_post_impl_rt_sigpending(long res, long set,
+ long sigsetsize);
+void __sanitizer_syscall_pre_impl_rt_sigtimedwait(long uthese, long uinfo,
+ long uts, long sigsetsize);
+void __sanitizer_syscall_post_impl_rt_sigtimedwait(long res, long uthese,
+ long uinfo, long uts,
+ long sigsetsize);
+void __sanitizer_syscall_pre_impl_rt_tgsigqueueinfo(long tgid, long pid,
+ long sig, long uinfo);
+void __sanitizer_syscall_post_impl_rt_tgsigqueueinfo(long res, long tgid,
+ long pid, long sig,
+ long uinfo);
+void __sanitizer_syscall_pre_impl_kill(long pid, long sig);
+void __sanitizer_syscall_post_impl_kill(long res, long pid, long sig);
+void __sanitizer_syscall_pre_impl_tgkill(long tgid, long pid, long sig);
+void __sanitizer_syscall_post_impl_tgkill(long res, long tgid, long pid,
+ long sig);
+void __sanitizer_syscall_pre_impl_tkill(long pid, long sig);
+void __sanitizer_syscall_post_impl_tkill(long res, long pid, long sig);
+void __sanitizer_syscall_pre_impl_rt_sigqueueinfo(long pid, long sig,
+ long uinfo);
+void __sanitizer_syscall_post_impl_rt_sigqueueinfo(long res, long pid, long sig,
+ long uinfo);
+void __sanitizer_syscall_pre_impl_sgetmask();
+void __sanitizer_syscall_post_impl_sgetmask(long res);
+void __sanitizer_syscall_pre_impl_ssetmask(long newmask);
+void __sanitizer_syscall_post_impl_ssetmask(long res, long newmask);
+void __sanitizer_syscall_pre_impl_signal(long sig, long handler);
+void __sanitizer_syscall_post_impl_signal(long res, long sig, long handler);
+void __sanitizer_syscall_pre_impl_pause();
+void __sanitizer_syscall_post_impl_pause(long res);
+void __sanitizer_syscall_pre_impl_sync();
+void __sanitizer_syscall_post_impl_sync(long res);
+void __sanitizer_syscall_pre_impl_fsync(long fd);
+void __sanitizer_syscall_post_impl_fsync(long res, long fd);
+void __sanitizer_syscall_pre_impl_fdatasync(long fd);
+void __sanitizer_syscall_post_impl_fdatasync(long res, long fd);
+void __sanitizer_syscall_pre_impl_bdflush(long func, long data);
+void __sanitizer_syscall_post_impl_bdflush(long res, long func, long data);
+void __sanitizer_syscall_pre_impl_mount(long dev_name, long dir_name, long type,
+ long flags, long data);
+void __sanitizer_syscall_post_impl_mount(long res, long dev_name, long dir_name,
+ long type, long flags, long data);
+void __sanitizer_syscall_pre_impl_umount(long name, long flags);
+void __sanitizer_syscall_post_impl_umount(long res, long name, long flags);
+void __sanitizer_syscall_pre_impl_oldumount(long name);
+void __sanitizer_syscall_post_impl_oldumount(long res, long name);
+void __sanitizer_syscall_pre_impl_truncate(long path, long length);
+void __sanitizer_syscall_post_impl_truncate(long res, long path, long length);
+void __sanitizer_syscall_pre_impl_ftruncate(long fd, long length);
+void __sanitizer_syscall_post_impl_ftruncate(long res, long fd, long length);
+void __sanitizer_syscall_pre_impl_stat(long filename, long statbuf);
+void __sanitizer_syscall_post_impl_stat(long res, long filename, long statbuf);
+void __sanitizer_syscall_pre_impl_statfs(long path, long buf);
+void __sanitizer_syscall_post_impl_statfs(long res, long path, long buf);
+void __sanitizer_syscall_pre_impl_statfs64(long path, long sz, long buf);
+void __sanitizer_syscall_post_impl_statfs64(long res, long path, long sz,
+ long buf);
+void __sanitizer_syscall_pre_impl_fstatfs(long fd, long buf);
+void __sanitizer_syscall_post_impl_fstatfs(long res, long fd, long buf);
+void __sanitizer_syscall_pre_impl_fstatfs64(long fd, long sz, long buf);
+void __sanitizer_syscall_post_impl_fstatfs64(long res, long fd, long sz,
+ long buf);
+void __sanitizer_syscall_pre_impl_lstat(long filename, long statbuf);
+void __sanitizer_syscall_post_impl_lstat(long res, long filename, long statbuf);
+void __sanitizer_syscall_pre_impl_fstat(long fd, long statbuf);
+void __sanitizer_syscall_post_impl_fstat(long res, long fd, long statbuf);
+void __sanitizer_syscall_pre_impl_newstat(long filename, long statbuf);
+void __sanitizer_syscall_post_impl_newstat(long res, long filename,
+ long statbuf);
+void __sanitizer_syscall_pre_impl_newlstat(long filename, long statbuf);
+void __sanitizer_syscall_post_impl_newlstat(long res, long filename,
+ long statbuf);
+void __sanitizer_syscall_pre_impl_newfstat(long fd, long statbuf);
+void __sanitizer_syscall_post_impl_newfstat(long res, long fd, long statbuf);
+void __sanitizer_syscall_pre_impl_ustat(long dev, long ubuf);
+void __sanitizer_syscall_post_impl_ustat(long res, long dev, long ubuf);
+void __sanitizer_syscall_pre_impl_stat64(long filename, long statbuf);
+void __sanitizer_syscall_post_impl_stat64(long res, long filename,
+ long statbuf);
+void __sanitizer_syscall_pre_impl_fstat64(long fd, long statbuf);
+void __sanitizer_syscall_post_impl_fstat64(long res, long fd, long statbuf);
+void __sanitizer_syscall_pre_impl_lstat64(long filename, long statbuf);
+void __sanitizer_syscall_post_impl_lstat64(long res, long filename,
+ long statbuf);
+void __sanitizer_syscall_pre_impl_setxattr(long path, long name, long value,
+ long size, long flags);
+void __sanitizer_syscall_post_impl_setxattr(long res, long path, long name,
+ long value, long size, long flags);
+void __sanitizer_syscall_pre_impl_lsetxattr(long path, long name, long value,
+ long size, long flags);
+void __sanitizer_syscall_post_impl_lsetxattr(long res, long path, long name,
+ long value, long size, long flags);
+void __sanitizer_syscall_pre_impl_fsetxattr(long fd, long name, long value,
+ long size, long flags);
+void __sanitizer_syscall_post_impl_fsetxattr(long res, long fd, long name,
+ long value, long size, long flags);
+void __sanitizer_syscall_pre_impl_getxattr(long path, long name, long value,
+ long size);
+void __sanitizer_syscall_post_impl_getxattr(long res, long path, long name,
+ long value, long size);
+void __sanitizer_syscall_pre_impl_lgetxattr(long path, long name, long value,
+ long size);
+void __sanitizer_syscall_post_impl_lgetxattr(long res, long path, long name,
+ long value, long size);
+void __sanitizer_syscall_pre_impl_fgetxattr(long fd, long name, long value,
+ long size);
+void __sanitizer_syscall_post_impl_fgetxattr(long res, long fd, long name,
+ long value, long size);
+void __sanitizer_syscall_pre_impl_listxattr(long path, long list, long size);
+void __sanitizer_syscall_post_impl_listxattr(long res, long path, long list,
+ long size);
+void __sanitizer_syscall_pre_impl_llistxattr(long path, long list, long size);
+void __sanitizer_syscall_post_impl_llistxattr(long res, long path, long list,
+ long size);
+void __sanitizer_syscall_pre_impl_flistxattr(long fd, long list, long size);
+void __sanitizer_syscall_post_impl_flistxattr(long res, long fd, long list,
+ long size);
+void __sanitizer_syscall_pre_impl_removexattr(long path, long name);
+void __sanitizer_syscall_post_impl_removexattr(long res, long path, long name);
+void __sanitizer_syscall_pre_impl_lremovexattr(long path, long name);
+void __sanitizer_syscall_post_impl_lremovexattr(long res, long path, long name);
+void __sanitizer_syscall_pre_impl_fremovexattr(long fd, long name);
+void __sanitizer_syscall_post_impl_fremovexattr(long res, long fd, long name);
+void __sanitizer_syscall_pre_impl_brk(long brk);
+void __sanitizer_syscall_post_impl_brk(long res, long brk);
+void __sanitizer_syscall_pre_impl_mprotect(long start, long len, long prot);
+void __sanitizer_syscall_post_impl_mprotect(long res, long start, long len,
+ long prot);
+void __sanitizer_syscall_pre_impl_mremap(long addr, long old_len, long new_len,
+ long flags, long new_addr);
+void __sanitizer_syscall_post_impl_mremap(long res, long addr, long old_len,
+ long new_len, long flags,
+ long new_addr);
+void __sanitizer_syscall_pre_impl_remap_file_pages(long start, long size,
+ long prot, long pgoff,
+ long flags);
+void __sanitizer_syscall_post_impl_remap_file_pages(long res, long start,
+ long size, long prot,
+ long pgoff, long flags);
+void __sanitizer_syscall_pre_impl_msync(long start, long len, long flags);
+void __sanitizer_syscall_post_impl_msync(long res, long start, long len,
+ long flags);
+void __sanitizer_syscall_pre_impl_munmap(long addr, long len);
+void __sanitizer_syscall_post_impl_munmap(long res, long addr, long len);
+void __sanitizer_syscall_pre_impl_mlock(long start, long len);
+void __sanitizer_syscall_post_impl_mlock(long res, long start, long len);
+void __sanitizer_syscall_pre_impl_munlock(long start, long len);
+void __sanitizer_syscall_post_impl_munlock(long res, long start, long len);
+void __sanitizer_syscall_pre_impl_mlockall(long flags);
+void __sanitizer_syscall_post_impl_mlockall(long res, long flags);
+void __sanitizer_syscall_pre_impl_munlockall();
+void __sanitizer_syscall_post_impl_munlockall(long res);
+void __sanitizer_syscall_pre_impl_madvise(long start, long len, long behavior);
+void __sanitizer_syscall_post_impl_madvise(long res, long start, long len,
+ long behavior);
+void __sanitizer_syscall_pre_impl_mincore(long start, long len, long vec);
+void __sanitizer_syscall_post_impl_mincore(long res, long start, long len,
+ long vec);
+void __sanitizer_syscall_pre_impl_pivot_root(long new_root, long put_old);
+void __sanitizer_syscall_post_impl_pivot_root(long res, long new_root,
+ long put_old);
+void __sanitizer_syscall_pre_impl_chroot(long filename);
+void __sanitizer_syscall_post_impl_chroot(long res, long filename);
+void __sanitizer_syscall_pre_impl_mknod(long filename, long mode, long dev);
+void __sanitizer_syscall_post_impl_mknod(long res, long filename, long mode,
+ long dev);
+void __sanitizer_syscall_pre_impl_link(long oldname, long newname);
+void __sanitizer_syscall_post_impl_link(long res, long oldname, long newname);
+void __sanitizer_syscall_pre_impl_symlink(long old, long new_);
+void __sanitizer_syscall_post_impl_symlink(long res, long old, long new_);
+void __sanitizer_syscall_pre_impl_unlink(long pathname);
+void __sanitizer_syscall_post_impl_unlink(long res, long pathname);
+void __sanitizer_syscall_pre_impl_rename(long oldname, long newname);
+void __sanitizer_syscall_post_impl_rename(long res, long oldname, long newname);
+void __sanitizer_syscall_pre_impl_chmod(long filename, long mode);
+void __sanitizer_syscall_post_impl_chmod(long res, long filename, long mode);
+void __sanitizer_syscall_pre_impl_fchmod(long fd, long mode);
+void __sanitizer_syscall_post_impl_fchmod(long res, long fd, long mode);
+void __sanitizer_syscall_pre_impl_fcntl(long fd, long cmd, long arg);
+void __sanitizer_syscall_post_impl_fcntl(long res, long fd, long cmd, long arg);
+void __sanitizer_syscall_pre_impl_fcntl64(long fd, long cmd, long arg);
+void __sanitizer_syscall_post_impl_fcntl64(long res, long fd, long cmd,
+ long arg);
+void __sanitizer_syscall_pre_impl_pipe(long fildes);
+void __sanitizer_syscall_post_impl_pipe(long res, long fildes);
+void __sanitizer_syscall_pre_impl_pipe2(long fildes, long flags);
+void __sanitizer_syscall_post_impl_pipe2(long res, long fildes, long flags);
+void __sanitizer_syscall_pre_impl_dup(long fildes);
+void __sanitizer_syscall_post_impl_dup(long res, long fildes);
+void __sanitizer_syscall_pre_impl_dup2(long oldfd, long newfd);
+void __sanitizer_syscall_post_impl_dup2(long res, long oldfd, long newfd);
+void __sanitizer_syscall_pre_impl_dup3(long oldfd, long newfd, long flags);
+void __sanitizer_syscall_post_impl_dup3(long res, long oldfd, long newfd,
+ long flags);
+void __sanitizer_syscall_pre_impl_ioperm(long from, long num, long on);
+void __sanitizer_syscall_post_impl_ioperm(long res, long from, long num,
+ long on);
+void __sanitizer_syscall_pre_impl_ioctl(long fd, long cmd, long arg);
+void __sanitizer_syscall_post_impl_ioctl(long res, long fd, long cmd, long arg);
+void __sanitizer_syscall_pre_impl_flock(long fd, long cmd);
+void __sanitizer_syscall_post_impl_flock(long res, long fd, long cmd);
+void __sanitizer_syscall_pre_impl_io_setup(long nr_reqs, long ctx);
+void __sanitizer_syscall_post_impl_io_setup(long res, long nr_reqs, long ctx);
+void __sanitizer_syscall_pre_impl_io_destroy(long ctx);
+void __sanitizer_syscall_post_impl_io_destroy(long res, long ctx);
+void __sanitizer_syscall_pre_impl_io_getevents(long ctx_id, long min_nr,
+ long nr, long events,
+ long timeout);
+void __sanitizer_syscall_post_impl_io_getevents(long res, long ctx_id,
+ long min_nr, long nr,
+ long events, long timeout);
+void __sanitizer_syscall_pre_impl_io_submit(long ctx_id, long arg1, long arg2);
+void __sanitizer_syscall_post_impl_io_submit(long res, long ctx_id, long arg1,
+ long arg2);
+void __sanitizer_syscall_pre_impl_io_cancel(long ctx_id, long iocb,
+ long result);
+void __sanitizer_syscall_post_impl_io_cancel(long res, long ctx_id, long iocb,
+ long result);
+void __sanitizer_syscall_pre_impl_sendfile(long out_fd, long in_fd, long offset,
+ long count);
+void __sanitizer_syscall_post_impl_sendfile(long res, long out_fd, long in_fd,
+ long offset, long count);
+void __sanitizer_syscall_pre_impl_sendfile64(long out_fd, long in_fd,
+ long offset, long count);
+void __sanitizer_syscall_post_impl_sendfile64(long res, long out_fd, long in_fd,
+ long offset, long count);
+void __sanitizer_syscall_pre_impl_readlink(long path, long buf, long bufsiz);
+void __sanitizer_syscall_post_impl_readlink(long res, long path, long buf,
+ long bufsiz);
+void __sanitizer_syscall_pre_impl_creat(long pathname, long mode);
+void __sanitizer_syscall_post_impl_creat(long res, long pathname, long mode);
+void __sanitizer_syscall_pre_impl_open(long filename, long flags, long mode);
+void __sanitizer_syscall_post_impl_open(long res, long filename, long flags,
+ long mode);
+void __sanitizer_syscall_pre_impl_close(long fd);
+void __sanitizer_syscall_post_impl_close(long res, long fd);
+void __sanitizer_syscall_pre_impl_access(long filename, long mode);
+void __sanitizer_syscall_post_impl_access(long res, long filename, long mode);
+void __sanitizer_syscall_pre_impl_vhangup();
+void __sanitizer_syscall_post_impl_vhangup(long res);
+void __sanitizer_syscall_pre_impl_chown(long filename, long user, long group);
+void __sanitizer_syscall_post_impl_chown(long res, long filename, long user,
+ long group);
+void __sanitizer_syscall_pre_impl_lchown(long filename, long user, long group);
+void __sanitizer_syscall_post_impl_lchown(long res, long filename, long user,
+ long group);
+void __sanitizer_syscall_pre_impl_fchown(long fd, long user, long group);
+void __sanitizer_syscall_post_impl_fchown(long res, long fd, long user,
+ long group);
+void __sanitizer_syscall_pre_impl_chown16(long filename, long user, long group);
+void __sanitizer_syscall_post_impl_chown16(long res, long filename, long user,
+ long group);
+void __sanitizer_syscall_pre_impl_lchown16(long filename, long user,
+ long group);
+void __sanitizer_syscall_post_impl_lchown16(long res, long filename, long user,
+ long group);
+void __sanitizer_syscall_pre_impl_fchown16(long fd, long user, long group);
+void __sanitizer_syscall_post_impl_fchown16(long res, long fd, long user,
+ long group);
+void __sanitizer_syscall_pre_impl_setregid16(long rgid, long egid);
+void __sanitizer_syscall_post_impl_setregid16(long res, long rgid, long egid);
+void __sanitizer_syscall_pre_impl_setgid16(long gid);
+void __sanitizer_syscall_post_impl_setgid16(long res, long gid);
+void __sanitizer_syscall_pre_impl_setreuid16(long ruid, long euid);
+void __sanitizer_syscall_post_impl_setreuid16(long res, long ruid, long euid);
+void __sanitizer_syscall_pre_impl_setuid16(long uid);
+void __sanitizer_syscall_post_impl_setuid16(long res, long uid);
+void __sanitizer_syscall_pre_impl_setresuid16(long ruid, long euid, long suid);
+void __sanitizer_syscall_post_impl_setresuid16(long res, long ruid, long euid,
+ long suid);
+void __sanitizer_syscall_pre_impl_getresuid16(long ruid, long euid, long suid);
+void __sanitizer_syscall_post_impl_getresuid16(long res, long ruid, long euid,
+ long suid);
+void __sanitizer_syscall_pre_impl_setresgid16(long rgid, long egid, long sgid);
+void __sanitizer_syscall_post_impl_setresgid16(long res, long rgid, long egid,
+ long sgid);
+void __sanitizer_syscall_pre_impl_getresgid16(long rgid, long egid, long sgid);
+void __sanitizer_syscall_post_impl_getresgid16(long res, long rgid, long egid,
+ long sgid);
+void __sanitizer_syscall_pre_impl_setfsuid16(long uid);
+void __sanitizer_syscall_post_impl_setfsuid16(long res, long uid);
+void __sanitizer_syscall_pre_impl_setfsgid16(long gid);
+void __sanitizer_syscall_post_impl_setfsgid16(long res, long gid);
+void __sanitizer_syscall_pre_impl_getgroups16(long gidsetsize, long grouplist);
+void __sanitizer_syscall_post_impl_getgroups16(long res, long gidsetsize,
+ long grouplist);
+void __sanitizer_syscall_pre_impl_setgroups16(long gidsetsize, long grouplist);
+void __sanitizer_syscall_post_impl_setgroups16(long res, long gidsetsize,
+ long grouplist);
+void __sanitizer_syscall_pre_impl_getuid16();
+void __sanitizer_syscall_post_impl_getuid16(long res);
+void __sanitizer_syscall_pre_impl_geteuid16();
+void __sanitizer_syscall_post_impl_geteuid16(long res);
+void __sanitizer_syscall_pre_impl_getgid16();
+void __sanitizer_syscall_post_impl_getgid16(long res);
+void __sanitizer_syscall_pre_impl_getegid16();
+void __sanitizer_syscall_post_impl_getegid16(long res);
+void __sanitizer_syscall_pre_impl_utime(long filename, long times);
+void __sanitizer_syscall_post_impl_utime(long res, long filename, long times);
+void __sanitizer_syscall_pre_impl_utimes(long filename, long utimes);
+void __sanitizer_syscall_post_impl_utimes(long res, long filename, long utimes);
+void __sanitizer_syscall_pre_impl_lseek(long fd, long offset, long origin);
+void __sanitizer_syscall_post_impl_lseek(long res, long fd, long offset,
+ long origin);
+void __sanitizer_syscall_pre_impl_llseek(long fd, long offset_high,
+ long offset_low, long result,
+ long origin);
+void __sanitizer_syscall_post_impl_llseek(long res, long fd, long offset_high,
+ long offset_low, long result,
+ long origin);
+void __sanitizer_syscall_pre_impl_read(long fd, long buf, long count);
+void __sanitizer_syscall_post_impl_read(long res, long fd, long buf,
+ long count);
+void __sanitizer_syscall_pre_impl_readv(long fd, long vec, long vlen);
+void __sanitizer_syscall_post_impl_readv(long res, long fd, long vec,
+ long vlen);
+void __sanitizer_syscall_pre_impl_write(long fd, long buf, long count);
+void __sanitizer_syscall_post_impl_write(long res, long fd, long buf,
+ long count);
+void __sanitizer_syscall_pre_impl_writev(long fd, long vec, long vlen);
+void __sanitizer_syscall_post_impl_writev(long res, long fd, long vec,
+ long vlen);
+
+#ifdef _LP64
+void __sanitizer_syscall_pre_impl_pread64(long fd, long buf, long count,
+ long pos);
+void __sanitizer_syscall_post_impl_pread64(long res, long fd, long buf,
+ long count, long pos);
+void __sanitizer_syscall_pre_impl_pwrite64(long fd, long buf, long count,
+ long pos);
+void __sanitizer_syscall_post_impl_pwrite64(long res, long fd, long buf,
+ long count, long pos);
+#else
+void __sanitizer_syscall_pre_impl_pread64(long fd, long buf, long count,
+ long pos0, long pos1);
+void __sanitizer_syscall_post_impl_pread64(long res, long fd, long buf,
+ long count, long pos0, long pos1);
+void __sanitizer_syscall_pre_impl_pwrite64(long fd, long buf, long count,
+ long pos0, long pos1);
+void __sanitizer_syscall_post_impl_pwrite64(long res, long fd, long buf,
+ long count, long pos0, long pos1);
+#endif
+
+void __sanitizer_syscall_pre_impl_preadv(long fd, long vec, long vlen,
+ long pos_l, long pos_h);
+void __sanitizer_syscall_post_impl_preadv(long res, long fd, long vec,
+ long vlen, long pos_l, long pos_h);
+void __sanitizer_syscall_pre_impl_pwritev(long fd, long vec, long vlen,
+ long pos_l, long pos_h);
+void __sanitizer_syscall_post_impl_pwritev(long res, long fd, long vec,
+ long vlen, long pos_l, long pos_h);
+void __sanitizer_syscall_pre_impl_getcwd(long buf, long size);
+void __sanitizer_syscall_post_impl_getcwd(long res, long buf, long size);
+void __sanitizer_syscall_pre_impl_mkdir(long pathname, long mode);
+void __sanitizer_syscall_post_impl_mkdir(long res, long pathname, long mode);
+void __sanitizer_syscall_pre_impl_chdir(long filename);
+void __sanitizer_syscall_post_impl_chdir(long res, long filename);
+void __sanitizer_syscall_pre_impl_fchdir(long fd);
+void __sanitizer_syscall_post_impl_fchdir(long res, long fd);
+void __sanitizer_syscall_pre_impl_rmdir(long pathname);
+void __sanitizer_syscall_post_impl_rmdir(long res, long pathname);
+void __sanitizer_syscall_pre_impl_lookup_dcookie(long cookie64, long buf,
+ long len);
+void __sanitizer_syscall_post_impl_lookup_dcookie(long res, long cookie64,
+ long buf, long len);
+void __sanitizer_syscall_pre_impl_quotactl(long cmd, long special, long id,
+ long addr);
+void __sanitizer_syscall_post_impl_quotactl(long res, long cmd, long special,
+ long id, long addr);
+void __sanitizer_syscall_pre_impl_getdents(long fd, long dirent, long count);
+void __sanitizer_syscall_post_impl_getdents(long res, long fd, long dirent,
+ long count);
+void __sanitizer_syscall_pre_impl_getdents64(long fd, long dirent, long count);
+void __sanitizer_syscall_post_impl_getdents64(long res, long fd, long dirent,
+ long count);
+void __sanitizer_syscall_pre_impl_setsockopt(long fd, long level, long optname,
+ long optval, long optlen);
+void __sanitizer_syscall_post_impl_setsockopt(long res, long fd, long level,
+ long optname, long optval,
+ long optlen);
+void __sanitizer_syscall_pre_impl_getsockopt(long fd, long level, long optname,
+ long optval, long optlen);
+void __sanitizer_syscall_post_impl_getsockopt(long res, long fd, long level,
+ long optname, long optval,
+ long optlen);
+void __sanitizer_syscall_pre_impl_bind(long arg0, long arg1, long arg2);
+void __sanitizer_syscall_post_impl_bind(long res, long arg0, long arg1,
+ long arg2);
+void __sanitizer_syscall_pre_impl_connect(long arg0, long arg1, long arg2);
+void __sanitizer_syscall_post_impl_connect(long res, long arg0, long arg1,
+ long arg2);
+void __sanitizer_syscall_pre_impl_accept(long arg0, long arg1, long arg2);
+void __sanitizer_syscall_post_impl_accept(long res, long arg0, long arg1,
+ long arg2);
+void __sanitizer_syscall_pre_impl_accept4(long arg0, long arg1, long arg2,
+ long arg3);
+void __sanitizer_syscall_post_impl_accept4(long res, long arg0, long arg1,
+ long arg2, long arg3);
+void __sanitizer_syscall_pre_impl_getsockname(long arg0, long arg1, long arg2);
+void __sanitizer_syscall_post_impl_getsockname(long res, long arg0, long arg1,
+ long arg2);
+void __sanitizer_syscall_pre_impl_getpeername(long arg0, long arg1, long arg2);
+void __sanitizer_syscall_post_impl_getpeername(long res, long arg0, long arg1,
+ long arg2);
+void __sanitizer_syscall_pre_impl_send(long arg0, long arg1, long arg2,
+ long arg3);
+void __sanitizer_syscall_post_impl_send(long res, long arg0, long arg1,
+ long arg2, long arg3);
+void __sanitizer_syscall_pre_impl_sendto(long arg0, long arg1, long arg2,
+ long arg3, long arg4, long arg5);
+void __sanitizer_syscall_post_impl_sendto(long res, long arg0, long arg1,
+ long arg2, long arg3, long arg4,
+ long arg5);
+void __sanitizer_syscall_pre_impl_sendmsg(long fd, long msg, long flags);
+void __sanitizer_syscall_post_impl_sendmsg(long res, long fd, long msg,
+ long flags);
+void __sanitizer_syscall_pre_impl_sendmmsg(long fd, long msg, long vlen,
+ long flags);
+void __sanitizer_syscall_post_impl_sendmmsg(long res, long fd, long msg,
+ long vlen, long flags);
+void __sanitizer_syscall_pre_impl_recv(long arg0, long arg1, long arg2,
+ long arg3);
+void __sanitizer_syscall_post_impl_recv(long res, long arg0, long arg1,
+ long arg2, long arg3);
+void __sanitizer_syscall_pre_impl_recvfrom(long arg0, long arg1, long arg2,
+ long arg3, long arg4, long arg5);
+void __sanitizer_syscall_post_impl_recvfrom(long res, long arg0, long arg1,
+ long arg2, long arg3, long arg4,
+ long arg5);
+void __sanitizer_syscall_pre_impl_recvmsg(long fd, long msg, long flags);
+void __sanitizer_syscall_post_impl_recvmsg(long res, long fd, long msg,
+ long flags);
+void __sanitizer_syscall_pre_impl_recvmmsg(long fd, long msg, long vlen,
+ long flags, long timeout);
+void __sanitizer_syscall_post_impl_recvmmsg(long res, long fd, long msg,
+ long vlen, long flags,
+ long timeout);
+void __sanitizer_syscall_pre_impl_socket(long arg0, long arg1, long arg2);
+void __sanitizer_syscall_post_impl_socket(long res, long arg0, long arg1,
+ long arg2);
+void __sanitizer_syscall_pre_impl_socketpair(long arg0, long arg1, long arg2,
+ long arg3);
+void __sanitizer_syscall_post_impl_socketpair(long res, long arg0, long arg1,
+ long arg2, long arg3);
+void __sanitizer_syscall_pre_impl_socketcall(long call, long args);
+void __sanitizer_syscall_post_impl_socketcall(long res, long call, long args);
+void __sanitizer_syscall_pre_impl_listen(long arg0, long arg1);
+void __sanitizer_syscall_post_impl_listen(long res, long arg0, long arg1);
+void __sanitizer_syscall_pre_impl_poll(long ufds, long nfds, long timeout);
+void __sanitizer_syscall_post_impl_poll(long res, long ufds, long nfds,
+ long timeout);
+void __sanitizer_syscall_pre_impl_select(long n, long inp, long outp, long exp,
+ long tvp);
+void __sanitizer_syscall_post_impl_select(long res, long n, long inp, long outp,
+ long exp, long tvp);
+void __sanitizer_syscall_pre_impl_old_select(long arg);
+void __sanitizer_syscall_post_impl_old_select(long res, long arg);
+void __sanitizer_syscall_pre_impl_epoll_create(long size);
+void __sanitizer_syscall_post_impl_epoll_create(long res, long size);
+void __sanitizer_syscall_pre_impl_epoll_create1(long flags);
+void __sanitizer_syscall_post_impl_epoll_create1(long res, long flags);
+void __sanitizer_syscall_pre_impl_epoll_ctl(long epfd, long op, long fd,
+ long event);
+void __sanitizer_syscall_post_impl_epoll_ctl(long res, long epfd, long op,
+ long fd, long event);
+void __sanitizer_syscall_pre_impl_epoll_wait(long epfd, long events,
+ long maxevents, long timeout);
+void __sanitizer_syscall_post_impl_epoll_wait(long res, long epfd, long events,
+ long maxevents, long timeout);
+void __sanitizer_syscall_pre_impl_epoll_pwait(long epfd, long events,
+ long maxevents, long timeout,
+ long sigmask, long sigsetsize);
+void __sanitizer_syscall_post_impl_epoll_pwait(long res, long epfd, long events,
+ long maxevents, long timeout,
+ long sigmask, long sigsetsize);
+void __sanitizer_syscall_pre_impl_gethostname(long name, long len);
+void __sanitizer_syscall_post_impl_gethostname(long res, long name, long len);
+void __sanitizer_syscall_pre_impl_sethostname(long name, long len);
+void __sanitizer_syscall_post_impl_sethostname(long res, long name, long len);
+void __sanitizer_syscall_pre_impl_setdomainname(long name, long len);
+void __sanitizer_syscall_post_impl_setdomainname(long res, long name, long len);
+void __sanitizer_syscall_pre_impl_newuname(long name);
+void __sanitizer_syscall_post_impl_newuname(long res, long name);
+void __sanitizer_syscall_pre_impl_uname(long arg0);
+void __sanitizer_syscall_post_impl_uname(long res, long arg0);
+void __sanitizer_syscall_pre_impl_olduname(long arg0);
+void __sanitizer_syscall_post_impl_olduname(long res, long arg0);
+void __sanitizer_syscall_pre_impl_getrlimit(long resource, long rlim);
+void __sanitizer_syscall_post_impl_getrlimit(long res, long resource,
+ long rlim);
+void __sanitizer_syscall_pre_impl_old_getrlimit(long resource, long rlim);
+void __sanitizer_syscall_post_impl_old_getrlimit(long res, long resource,
+ long rlim);
+void __sanitizer_syscall_pre_impl_setrlimit(long resource, long rlim);
+void __sanitizer_syscall_post_impl_setrlimit(long res, long resource,
+ long rlim);
+void __sanitizer_syscall_pre_impl_prlimit64(long pid, long resource,
+ long new_rlim, long old_rlim);
+void __sanitizer_syscall_post_impl_prlimit64(long res, long pid, long resource,
+ long new_rlim, long old_rlim);
+void __sanitizer_syscall_pre_impl_getrusage(long who, long ru);
+void __sanitizer_syscall_post_impl_getrusage(long res, long who, long ru);
+void __sanitizer_syscall_pre_impl_umask(long mask);
+void __sanitizer_syscall_post_impl_umask(long res, long mask);
+void __sanitizer_syscall_pre_impl_msgget(long key, long msgflg);
+void __sanitizer_syscall_post_impl_msgget(long res, long key, long msgflg);
+void __sanitizer_syscall_pre_impl_msgsnd(long msqid, long msgp, long msgsz,
+ long msgflg);
+void __sanitizer_syscall_post_impl_msgsnd(long res, long msqid, long msgp,
+ long msgsz, long msgflg);
+void __sanitizer_syscall_pre_impl_msgrcv(long msqid, long msgp, long msgsz,
+ long msgtyp, long msgflg);
+void __sanitizer_syscall_post_impl_msgrcv(long res, long msqid, long msgp,
+ long msgsz, long msgtyp, long msgflg);
+void __sanitizer_syscall_pre_impl_msgctl(long msqid, long cmd, long buf);
+void __sanitizer_syscall_post_impl_msgctl(long res, long msqid, long cmd,
+ long buf);
+void __sanitizer_syscall_pre_impl_semget(long key, long nsems, long semflg);
+void __sanitizer_syscall_post_impl_semget(long res, long key, long nsems,
+ long semflg);
+void __sanitizer_syscall_pre_impl_semop(long semid, long sops, long nsops);
+void __sanitizer_syscall_post_impl_semop(long res, long semid, long sops,
+ long nsops);
+void __sanitizer_syscall_pre_impl_semctl(long semid, long semnum, long cmd,
+ long arg);
+void __sanitizer_syscall_post_impl_semctl(long res, long semid, long semnum,
+ long cmd, long arg);
+void __sanitizer_syscall_pre_impl_semtimedop(long semid, long sops, long nsops,
+ long timeout);
+void __sanitizer_syscall_post_impl_semtimedop(long res, long semid, long sops,
+ long nsops, long timeout);
+void __sanitizer_syscall_pre_impl_shmat(long shmid, long shmaddr, long shmflg);
+void __sanitizer_syscall_post_impl_shmat(long res, long shmid, long shmaddr,
+ long shmflg);
+void __sanitizer_syscall_pre_impl_shmget(long key, long size, long flag);
+void __sanitizer_syscall_post_impl_shmget(long res, long key, long size,
+ long flag);
+void __sanitizer_syscall_pre_impl_shmdt(long shmaddr);
+void __sanitizer_syscall_post_impl_shmdt(long res, long shmaddr);
+void __sanitizer_syscall_pre_impl_shmctl(long shmid, long cmd, long buf);
+void __sanitizer_syscall_post_impl_shmctl(long res, long shmid, long cmd,
+ long buf);
+void __sanitizer_syscall_pre_impl_ipc(long call, long first, long second,
+ long third, long ptr, long fifth);
+void __sanitizer_syscall_post_impl_ipc(long res, long call, long first,
+ long second, long third, long ptr,
+ long fifth);
+void __sanitizer_syscall_pre_impl_mq_open(long name, long oflag, long mode,
+ long attr);
+void __sanitizer_syscall_post_impl_mq_open(long res, long name, long oflag,
+ long mode, long attr);
+void __sanitizer_syscall_pre_impl_mq_unlink(long name);
+void __sanitizer_syscall_post_impl_mq_unlink(long res, long name);
+void __sanitizer_syscall_pre_impl_mq_timedsend(long mqdes, long msg_ptr,
+ long msg_len, long msg_prio,
+ long abs_timeout);
+void __sanitizer_syscall_post_impl_mq_timedsend(long res, long mqdes,
+ long msg_ptr, long msg_len,
+ long msg_prio,
+ long abs_timeout);
+void __sanitizer_syscall_pre_impl_mq_timedreceive(long mqdes, long msg_ptr,
+ long msg_len, long msg_prio,
+ long abs_timeout);
+void __sanitizer_syscall_post_impl_mq_timedreceive(long res, long mqdes,
+ long msg_ptr, long msg_len,
+ long msg_prio,
+ long abs_timeout);
+void __sanitizer_syscall_pre_impl_mq_notify(long mqdes, long notification);
+void __sanitizer_syscall_post_impl_mq_notify(long res, long mqdes,
+ long notification);
+void __sanitizer_syscall_pre_impl_mq_getsetattr(long mqdes, long mqstat,
+ long omqstat);
+void __sanitizer_syscall_post_impl_mq_getsetattr(long res, long mqdes,
+ long mqstat, long omqstat);
+void __sanitizer_syscall_pre_impl_pciconfig_iobase(long which, long bus,
+ long devfn);
+void __sanitizer_syscall_post_impl_pciconfig_iobase(long res, long which,
+ long bus, long devfn);
+void __sanitizer_syscall_pre_impl_pciconfig_read(long bus, long dfn, long off,
+ long len, long buf);
+void __sanitizer_syscall_post_impl_pciconfig_read(long res, long bus, long dfn,
+ long off, long len, long buf);
+void __sanitizer_syscall_pre_impl_pciconfig_write(long bus, long dfn, long off,
+ long len, long buf);
+void __sanitizer_syscall_post_impl_pciconfig_write(long res, long bus, long dfn,
+ long off, long len,
+ long buf);
+void __sanitizer_syscall_pre_impl_swapon(long specialfile, long swap_flags);
+void __sanitizer_syscall_post_impl_swapon(long res, long specialfile,
+ long swap_flags);
+void __sanitizer_syscall_pre_impl_swapoff(long specialfile);
+void __sanitizer_syscall_post_impl_swapoff(long res, long specialfile);
+void __sanitizer_syscall_pre_impl_sysctl(long args);
+void __sanitizer_syscall_post_impl_sysctl(long res, long args);
+void __sanitizer_syscall_pre_impl_sysinfo(long info);
+void __sanitizer_syscall_post_impl_sysinfo(long res, long info);
+void __sanitizer_syscall_pre_impl_sysfs(long option, long arg1, long arg2);
+void __sanitizer_syscall_post_impl_sysfs(long res, long option, long arg1,
+ long arg2);
+void __sanitizer_syscall_pre_impl_syslog(long type, long buf, long len);
+void __sanitizer_syscall_post_impl_syslog(long res, long type, long buf,
+ long len);
+void __sanitizer_syscall_pre_impl_uselib(long library);
+void __sanitizer_syscall_post_impl_uselib(long res, long library);
+void __sanitizer_syscall_pre_impl_ni_syscall();
+void __sanitizer_syscall_post_impl_ni_syscall(long res);
+void __sanitizer_syscall_pre_impl_ptrace(long request, long pid, long addr,
+ long data);
+void __sanitizer_syscall_post_impl_ptrace(long res, long request, long pid,
+ long addr, long data);
+void __sanitizer_syscall_pre_impl_add_key(long _type, long _description,
+ long _payload, long plen,
+ long destringid);
+void __sanitizer_syscall_post_impl_add_key(long res, long _type,
+ long _description, long _payload,
+ long plen, long destringid);
+void __sanitizer_syscall_pre_impl_request_key(long _type, long _description,
+ long _callout_info,
+ long destringid);
+void __sanitizer_syscall_post_impl_request_key(long res, long _type,
+ long _description,
+ long _callout_info,
+ long destringid);
+void __sanitizer_syscall_pre_impl_keyctl(long cmd, long arg2, long arg3,
+ long arg4, long arg5);
+void __sanitizer_syscall_post_impl_keyctl(long res, long cmd, long arg2,
+ long arg3, long arg4, long arg5);
+void __sanitizer_syscall_pre_impl_ioprio_set(long which, long who, long ioprio);
+void __sanitizer_syscall_post_impl_ioprio_set(long res, long which, long who,
+ long ioprio);
+void __sanitizer_syscall_pre_impl_ioprio_get(long which, long who);
+void __sanitizer_syscall_post_impl_ioprio_get(long res, long which, long who);
+void __sanitizer_syscall_pre_impl_set_mempolicy(long mode, long nmask,
+ long maxnode);
+void __sanitizer_syscall_post_impl_set_mempolicy(long res, long mode,
+ long nmask, long maxnode);
+void __sanitizer_syscall_pre_impl_migrate_pages(long pid, long maxnode,
+ long from, long to);
+void __sanitizer_syscall_post_impl_migrate_pages(long res, long pid,
+ long maxnode, long from,
+ long to);
+void __sanitizer_syscall_pre_impl_move_pages(long pid, long nr_pages,
+ long pages, long nodes,
+ long status, long flags);
+void __sanitizer_syscall_post_impl_move_pages(long res, long pid, long nr_pages,
+ long pages, long nodes,
+ long status, long flags);
+void __sanitizer_syscall_pre_impl_mbind(long start, long len, long mode,
+ long nmask, long maxnode, long flags);
+void __sanitizer_syscall_post_impl_mbind(long res, long start, long len,
+ long mode, long nmask, long maxnode,
+ long flags);
+void __sanitizer_syscall_pre_impl_get_mempolicy(long policy, long nmask,
+ long maxnode, long addr,
+ long flags);
+void __sanitizer_syscall_post_impl_get_mempolicy(long res, long policy,
+ long nmask, long maxnode,
+ long addr, long flags);
+void __sanitizer_syscall_pre_impl_inotify_init();
+void __sanitizer_syscall_post_impl_inotify_init(long res);
+void __sanitizer_syscall_pre_impl_inotify_init1(long flags);
+void __sanitizer_syscall_post_impl_inotify_init1(long res, long flags);
+void __sanitizer_syscall_pre_impl_inotify_add_watch(long fd, long path,
+ long mask);
+void __sanitizer_syscall_post_impl_inotify_add_watch(long res, long fd,
+ long path, long mask);
+void __sanitizer_syscall_pre_impl_inotify_rm_watch(long fd, long wd);
+void __sanitizer_syscall_post_impl_inotify_rm_watch(long res, long fd, long wd);
+void __sanitizer_syscall_pre_impl_spu_run(long fd, long unpc, long ustatus);
+void __sanitizer_syscall_post_impl_spu_run(long res, long fd, long unpc,
+ long ustatus);
+void __sanitizer_syscall_pre_impl_spu_create(long name, long flags, long mode,
+ long fd);
+void __sanitizer_syscall_post_impl_spu_create(long res, long name, long flags,
+ long mode, long fd);
+void __sanitizer_syscall_pre_impl_mknodat(long dfd, long filename, long mode,
+ long dev);
+void __sanitizer_syscall_post_impl_mknodat(long res, long dfd, long filename,
+ long mode, long dev);
+void __sanitizer_syscall_pre_impl_mkdirat(long dfd, long pathname, long mode);
+void __sanitizer_syscall_post_impl_mkdirat(long res, long dfd, long pathname,
+ long mode);
+void __sanitizer_syscall_pre_impl_unlinkat(long dfd, long pathname, long flag);
+void __sanitizer_syscall_post_impl_unlinkat(long res, long dfd, long pathname,
+ long flag);
+void __sanitizer_syscall_pre_impl_symlinkat(long oldname, long newdfd,
+ long newname);
+void __sanitizer_syscall_post_impl_symlinkat(long res, long oldname,
+ long newdfd, long newname);
+void __sanitizer_syscall_pre_impl_linkat(long olddfd, long oldname, long newdfd,
+ long newname, long flags);
+void __sanitizer_syscall_post_impl_linkat(long res, long olddfd, long oldname,
+ long newdfd, long newname,
+ long flags);
+void __sanitizer_syscall_pre_impl_renameat(long olddfd, long oldname,
+ long newdfd, long newname);
+void __sanitizer_syscall_post_impl_renameat(long res, long olddfd, long oldname,
+ long newdfd, long newname);
+void __sanitizer_syscall_pre_impl_futimesat(long dfd, long filename,
+ long utimes);
+void __sanitizer_syscall_post_impl_futimesat(long res, long dfd, long filename,
+ long utimes);
+void __sanitizer_syscall_pre_impl_faccessat(long dfd, long filename, long mode);
+void __sanitizer_syscall_post_impl_faccessat(long res, long dfd, long filename,
+ long mode);
+void __sanitizer_syscall_pre_impl_fchmodat(long dfd, long filename, long mode);
+void __sanitizer_syscall_post_impl_fchmodat(long res, long dfd, long filename,
+ long mode);
+void __sanitizer_syscall_pre_impl_fchownat(long dfd, long filename, long user,
+ long group, long flag);
+void __sanitizer_syscall_post_impl_fchownat(long res, long dfd, long filename,
+ long user, long group, long flag);
+void __sanitizer_syscall_pre_impl_openat(long dfd, long filename, long flags,
+ long mode);
+void __sanitizer_syscall_post_impl_openat(long res, long dfd, long filename,
+ long flags, long mode);
+void __sanitizer_syscall_pre_impl_newfstatat(long dfd, long filename,
+ long statbuf, long flag);
+void __sanitizer_syscall_post_impl_newfstatat(long res, long dfd, long filename,
+ long statbuf, long flag);
+void __sanitizer_syscall_pre_impl_fstatat64(long dfd, long filename,
+ long statbuf, long flag);
+void __sanitizer_syscall_post_impl_fstatat64(long res, long dfd, long filename,
+ long statbuf, long flag);
+void __sanitizer_syscall_pre_impl_readlinkat(long dfd, long path, long buf,
+ long bufsiz);
+void __sanitizer_syscall_post_impl_readlinkat(long res, long dfd, long path,
+ long buf, long bufsiz);
+void __sanitizer_syscall_pre_impl_utimensat(long dfd, long filename,
+ long utimes, long flags);
+void __sanitizer_syscall_post_impl_utimensat(long res, long dfd, long filename,
+ long utimes, long flags);
+void __sanitizer_syscall_pre_impl_unshare(long unshare_flags);
+void __sanitizer_syscall_post_impl_unshare(long res, long unshare_flags);
+void __sanitizer_syscall_pre_impl_splice(long fd_in, long off_in, long fd_out,
+ long off_out, long len, long flags);
+void __sanitizer_syscall_post_impl_splice(long res, long fd_in, long off_in,
+ long fd_out, long off_out, long len,
+ long flags);
+void __sanitizer_syscall_pre_impl_vmsplice(long fd, long iov, long nr_segs,
+ long flags);
+void __sanitizer_syscall_post_impl_vmsplice(long res, long fd, long iov,
+ long nr_segs, long flags);
+void __sanitizer_syscall_pre_impl_tee(long fdin, long fdout, long len,
+ long flags);
+void __sanitizer_syscall_post_impl_tee(long res, long fdin, long fdout,
+ long len, long flags);
+void __sanitizer_syscall_pre_impl_get_robust_list(long pid, long head_ptr,
+ long len_ptr);
+void __sanitizer_syscall_post_impl_get_robust_list(long res, long pid,
+ long head_ptr, long len_ptr);
+void __sanitizer_syscall_pre_impl_set_robust_list(long head, long len);
+void __sanitizer_syscall_post_impl_set_robust_list(long res, long head,
+ long len);
+void __sanitizer_syscall_pre_impl_getcpu(long cpu, long node, long cache);
+void __sanitizer_syscall_post_impl_getcpu(long res, long cpu, long node,
+ long cache);
+void __sanitizer_syscall_pre_impl_signalfd(long ufd, long user_mask,
+ long sizemask);
+void __sanitizer_syscall_post_impl_signalfd(long res, long ufd, long user_mask,
+ long sizemask);
+void __sanitizer_syscall_pre_impl_signalfd4(long ufd, long user_mask,
+ long sizemask, long flags);
+void __sanitizer_syscall_post_impl_signalfd4(long res, long ufd, long user_mask,
+ long sizemask, long flags);
+void __sanitizer_syscall_pre_impl_timerfd_create(long clockid, long flags);
+void __sanitizer_syscall_post_impl_timerfd_create(long res, long clockid,
+ long flags);
+void __sanitizer_syscall_pre_impl_timerfd_settime(long ufd, long flags,
+ long utmr, long otmr);
+void __sanitizer_syscall_post_impl_timerfd_settime(long res, long ufd,
+ long flags, long utmr,
+ long otmr);
+void __sanitizer_syscall_pre_impl_timerfd_gettime(long ufd, long otmr);
+void __sanitizer_syscall_post_impl_timerfd_gettime(long res, long ufd,
+ long otmr);
+void __sanitizer_syscall_pre_impl_eventfd(long count);
+void __sanitizer_syscall_post_impl_eventfd(long res, long count);
+void __sanitizer_syscall_pre_impl_eventfd2(long count, long flags);
+void __sanitizer_syscall_post_impl_eventfd2(long res, long count, long flags);
+void __sanitizer_syscall_pre_impl_old_readdir(long arg0, long arg1, long arg2);
+void __sanitizer_syscall_post_impl_old_readdir(long res, long arg0, long arg1,
+ long arg2);
+void __sanitizer_syscall_pre_impl_pselect6(long arg0, long arg1, long arg2,
+ long arg3, long arg4, long arg5);
+void __sanitizer_syscall_post_impl_pselect6(long res, long arg0, long arg1,
+ long arg2, long arg3, long arg4,
+ long arg5);
+void __sanitizer_syscall_pre_impl_ppoll(long arg0, long arg1, long arg2,
+ long arg3, long arg4);
+void __sanitizer_syscall_post_impl_ppoll(long res, long arg0, long arg1,
+ long arg2, long arg3, long arg4);
+void __sanitizer_syscall_pre_impl_fanotify_init(long flags, long event_f_flags);
+void __sanitizer_syscall_post_impl_fanotify_init(long res, long flags,
+ long event_f_flags);
+void __sanitizer_syscall_pre_impl_fanotify_mark(long fanotify_fd, long flags,
+ long mask, long fd,
+ long pathname);
+void __sanitizer_syscall_post_impl_fanotify_mark(long res, long fanotify_fd,
+ long flags, long mask, long fd,
+ long pathname);
+void __sanitizer_syscall_pre_impl_syncfs(long fd);
+void __sanitizer_syscall_post_impl_syncfs(long res, long fd);
+void __sanitizer_syscall_pre_impl_perf_event_open(long attr_uptr, long pid,
+ long cpu, long group_fd,
+ long flags);
+void __sanitizer_syscall_post_impl_perf_event_open(long res, long attr_uptr,
+ long pid, long cpu,
+ long group_fd, long flags);
+void __sanitizer_syscall_pre_impl_mmap_pgoff(long addr, long len, long prot,
+ long flags, long fd, long pgoff);
+void __sanitizer_syscall_post_impl_mmap_pgoff(long res, long addr, long len,
+ long prot, long flags, long fd,
+ long pgoff);
+void __sanitizer_syscall_pre_impl_old_mmap(long arg);
+void __sanitizer_syscall_post_impl_old_mmap(long res, long arg);
+void __sanitizer_syscall_pre_impl_name_to_handle_at(long dfd, long name,
+ long handle, long mnt_id,
+ long flag);
+void __sanitizer_syscall_post_impl_name_to_handle_at(long res, long dfd,
+ long name, long handle,
+ long mnt_id, long flag);
+void __sanitizer_syscall_pre_impl_open_by_handle_at(long mountdirfd,
+ long handle, long flags);
+void __sanitizer_syscall_post_impl_open_by_handle_at(long res, long mountdirfd,
+ long handle, long flags);
+void __sanitizer_syscall_pre_impl_setns(long fd, long nstype);
+void __sanitizer_syscall_post_impl_setns(long res, long fd, long nstype);
+void __sanitizer_syscall_pre_impl_process_vm_readv(long pid, long lvec,
+ long liovcnt, long rvec,
+ long riovcnt, long flags);
+void __sanitizer_syscall_post_impl_process_vm_readv(long res, long pid,
+ long lvec, long liovcnt,
+ long rvec, long riovcnt,
+ long flags);
+void __sanitizer_syscall_pre_impl_process_vm_writev(long pid, long lvec,
+ long liovcnt, long rvec,
+ long riovcnt, long flags);
+void __sanitizer_syscall_post_impl_process_vm_writev(long res, long pid,
+ long lvec, long liovcnt,
+ long rvec, long riovcnt,
+ long flags);
+void __sanitizer_syscall_pre_impl_fork();
+void __sanitizer_syscall_post_impl_fork(long res);
+void __sanitizer_syscall_pre_impl_vfork();
+void __sanitizer_syscall_post_impl_vfork(long res);
+
+#ifdef __cplusplus
+} // extern "C"
#endif
-#endif // SANITIZER_LINUX_SYSCALL_HOOKS_H
+#endif // SANITIZER_LINUX_SYSCALL_HOOKS_H
diff --git a/include/sanitizer/lsan_interface.h b/include/sanitizer/lsan_interface.h
new file mode 100644
index 000000000000..df256c0e5384
--- /dev/null
+++ b/include/sanitizer/lsan_interface.h
@@ -0,0 +1,52 @@
+//===-- sanitizer/lsan_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 LeakSanitizer.
+//
+// Public interface header.
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_LSAN_INTERFACE_H
+#define SANITIZER_LSAN_INTERFACE_H
+
+#include <sanitizer/common_interface_defs.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ // Allocations made between calls to __lsan_disable() and __lsan_enable() will
+ // be treated as non-leaks. Disable/enable pairs may be nested.
+ void __lsan_disable();
+ void __lsan_enable();
+ // The heap object into which p points will be treated as a non-leak.
+ void __lsan_ignore_object(const void *p);
+ // The user may optionally provide this function to disallow leak checking
+ // for the program it is linked into (if the return value is non-zero). This
+ // function must be defined as returning a constant value; any behavior beyond
+ // that is unsupported.
+ int __lsan_is_turned_off();
+ // Calling this function makes LSan enter the leak checking phase immediately.
+ // Use this if normal end-of-process leak checking happens too late (e.g. if
+ // you have intentional memory leaks in your shutdown code). Calling this
+ // function overrides end-of-process leak checking; it must be called at
+ // most once per process. This function will terminate the process if there
+ // are memory leaks and the exit_code flag is non-zero.
+ void __lsan_do_leak_check();
+#ifdef __cplusplus
+} // extern "C"
+
+namespace __lsan {
+class ScopedDisabler {
+ public:
+ ScopedDisabler() { __lsan_disable(); }
+ ~ScopedDisabler() { __lsan_enable(); }
+};
+} // namespace __lsan
+#endif
+
+#endif // SANITIZER_LSAN_INTERFACE_H
diff --git a/include/sanitizer/msan_interface.h b/include/sanitizer/msan_interface.h
index 9eff7b597b69..63af84fc3ff1 100644
--- a/include/sanitizer/msan_interface.h
+++ b/include/sanitizer/msan_interface.h
@@ -27,10 +27,10 @@ extern "C" {
/* Set raw origin for the memory range. */
- void __msan_set_origin(const void *a, size_t size, uint32_t origin);
+ void __msan_set_origin(const volatile void *a, size_t size, uint32_t origin);
/* Get raw origin for an address. */
- uint32_t __msan_get_origin(const void *a);
+ uint32_t __msan_get_origin(const volatile void *a);
/* Returns non-zero if tracking origins. */
int __msan_get_track_origins();
@@ -39,18 +39,19 @@ extern "C" {
uint32_t __msan_get_umr_origin();
/* Make memory region fully initialized (without changing its contents). */
- void __msan_unpoison(const void *a, size_t size);
+ void __msan_unpoison(const volatile void *a, size_t size);
/* Make memory region fully uninitialized (without changing its contents). */
- void __msan_poison(const void *a, size_t size);
+ void __msan_poison(const volatile void *a, size_t size);
/* Make memory region partially uninitialized (without changing its contents).
*/
- void __msan_partial_poison(const void* data, void* shadow, size_t size);
+ void __msan_partial_poison(const volatile void *data, void *shadow,
+ size_t size);
/* Returns the offset of the first (at least partially) poisoned byte in the
memory range, or -1 if the whole range is good. */
- intptr_t __msan_test_shadow(const void *x, size_t size);
+ intptr_t __msan_test_shadow(const volatile void *x, size_t size);
/* Set exit code when error(s) were detected.
Value of 0 means don't change the program exit code. */
@@ -63,9 +64,14 @@ extern "C" {
The last line will verify that a UMR happened. */
void __msan_set_expect_umr(int expect_umr);
+ /* Change the value of keep_going flag. Non-zero value means don't terminate
+ program execution when an error is detected. This will not affect error in
+ modules that were compiled without the corresponding compiler flag. */
+ void __msan_set_keep_going(int keep_going);
+
/* Print shadow and origin for the memory range to stdout in a human-readable
format. */
- void __msan_print_shadow(const void *x, size_t size);
+ void __msan_print_shadow(const volatile void *x, size_t size);
/* Print current function arguments shadow and origin to stdout in a
human-readable format. */
@@ -76,7 +82,58 @@ extern "C" {
/* Tell MSan about newly allocated memory (ex.: custom allocator).
Memory will be marked uninitialized, with origin at the call site. */
- void __msan_allocated_memory(const void* data, size_t size);
+ void __msan_allocated_memory(const volatile void* data, size_t size);
+
+ /* This function may be optionally provided by user and should return
+ a string containing Msan runtime options. See msan_flags.h for details. */
+ const char* __msan_default_options();
+
+
+ /***********************************/
+ /* Allocator statistics interface. */
+
+ /* Returns the estimated number of bytes that will be reserved by allocator
+ for request of "size" bytes. If Msan allocator can't allocate that much
+ memory, returns the maximal possible allocation size, otherwise returns
+ "size". */
+ size_t __msan_get_estimated_allocated_size(size_t size);
+
+ /* Returns true if p was returned by the Msan allocator and
+ is not yet freed. */
+ int __msan_get_ownership(const volatile void *p);
+
+ /* Returns the number of bytes reserved for the pointer p.
+ Requires (get_ownership(p) == true) or (p == 0). */
+ size_t __msan_get_allocated_size(const volatile void *p);
+
+ /* Number of bytes, allocated and not yet freed by the application. */
+ size_t __msan_get_current_allocated_bytes();
+
+ /* Number of bytes, mmaped by msan allocator to fulfill allocation requests.
+ Generally, for request of X bytes, allocator can reserve and add to free
+ lists a large number of chunks of size X to use them for future requests.
+ All these chunks count toward the heap size. Currently, allocator never
+ releases memory to OS (instead, it just puts freed chunks to free
+ lists). */
+ size_t __msan_get_heap_size();
+
+ /* Number of bytes, mmaped by msan allocator, which can be used to fulfill
+ allocation requests. When a user program frees memory chunk, it can first
+ fall into quarantine and will count toward __msan_get_free_bytes()
+ later. */
+ size_t __msan_get_free_bytes();
+
+ /* Number of bytes in unmapped pages, that are released to OS. Currently,
+ always returns 0. */
+ size_t __msan_get_unmapped_bytes();
+
+ /* Malloc hooks that may be optionally provided by user.
+ __msan_malloc_hook(ptr, size) is called immediately after
+ allocation of "size" bytes, which returned "ptr".
+ __msan_free_hook(ptr) is called immediately before
+ deallocation of "ptr". */
+ void __msan_malloc_hook(const volatile void *ptr, size_t size);
+ void __msan_free_hook(const volatile void *ptr);
#else // __has_feature(memory_sanitizer)
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index f07ab1e1872b..b620828beb2b 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -1,22 +1,36 @@
# First, add the subdirectories which contain feature-based runtime libraries
# and several convenience helper libraries.
-if(CMAKE_SYSTEM_NAME MATCHES "Darwin|Linux")
+
+# Don't build sanitizers in the bootstrap build.
+if(LLVM_USE_SANITIZER STREQUAL "")
# AddressSanitizer is supported on Linux and Mac OS X.
- # Windows support is work in progress.
- add_subdirectory(asan)
- add_subdirectory(interception)
- add_subdirectory(sanitizer_common)
- if(NOT ANDROID)
+ # 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()
-endif()
-if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux" AND NOT ANDROID)
- # ThreadSanitizer and MemorySanitizer are supported on Linux only.
- add_subdirectory(tsan)
- add_subdirectory(msan)
- add_subdirectory(msandr)
- add_subdirectory(lsan)
+ 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()
endif()
# The top-level lib directory contains a large amount of C code which provides
@@ -181,10 +195,22 @@ set(i386_SOURCES
i386/umoddi3.S
${GENERIC_SOURCES})
-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 (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()
+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)
+
+configure_lit_site_cfg(
+ ${CMAKE_CURRENT_SOURCE_DIR}/lit.common.unit.configured.in
+ ${CMAKE_CURRENT_BINARY_DIR}/lit.common.unit.configured)
+
diff --git a/lib/Makefile.mk b/lib/Makefile.mk
index 8054c35aa362..f9d7800cc4c4 100644
--- a/lib/Makefile.mk
+++ b/lib/Makefile.mk
@@ -22,6 +22,7 @@ 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)))
diff --git a/lib/apple_versioning.c b/lib/apple_versioning.c
index 09f149f14cf7..3797a1ab02da 100644
--- a/lib/apple_versioning.c
+++ b/lib/apple_versioning.c
@@ -9,19 +9,20 @@
*/
-
#if __APPLE__
- #if __arm__
+ #include <Availability.h>
+
+ #if __IPHONE_OS_VERSION_MIN_REQUIRED
#define NOT_HERE_BEFORE_10_6(sym)
- #define NOT_HERE_IN_10_8_AND_EARLIER(sym)
- #elif __ppc__
- #define NOT_HERE_BEFORE_10_6(sym) \
- extern const char sym##_tmp3 __asm("$ld$hide$os10.3$_" #sym ); \
- __attribute__((visibility("default"))) const char sym##_tmp3 = 0; \
- extern const char sym##_tmp4 __asm("$ld$hide$os10.4$_" #sym ); \
- __attribute__((visibility("default"))) const char sym##_tmp4 = 0; \
- extern const char sym##_tmp5 __asm("$ld$hide$os10.5$_" #sym ); \
- __attribute__((visibility("default"))) const char sym##_tmp5 = 0;
+ #define NOT_HERE_IN_10_8_AND_EARLIER(sym) \
+ extern const char sym##_tmp61 __asm("$ld$hide$os6.1$_" #sym ); \
+ __attribute__((visibility("default"))) const char sym##_tmp61 = 0; \
+ extern const char sym##_tmp60 __asm("$ld$hide$os6.0$_" #sym ); \
+ __attribute__((visibility("default"))) const char sym##_tmp60 = 0; \
+ extern const char sym##_tmp51 __asm("$ld$hide$os5.1$_" #sym ); \
+ __attribute__((visibility("default"))) const char sym##_tmp51 = 0; \
+ extern const char sym##_tmp50 __asm("$ld$hide$os5.0$_" #sym ); \
+ __attribute__((visibility("default"))) const char sym##_tmp50 = 0;
#else
#define NOT_HERE_BEFORE_10_6(sym) \
extern const char sym##_tmp4 __asm("$ld$hide$os10.4$_" #sym ); \
@@ -35,7 +36,7 @@
__attribute__((visibility("default"))) const char sym##_tmp7 = 0; \
extern const char sym##_tmp6 __asm("$ld$hide$os10.6$_" #sym ); \
__attribute__((visibility("default"))) const char sym##_tmp6 = 0;
- #endif /* __ppc__ */
+ #endif
/* Symbols in libSystem.dylib in 10.6 and later,
diff --git a/lib/arm/Makefile.mk b/lib/arm/Makefile.mk
index 04dec88a9714..a2df115f926f 100644
--- a/lib/arm/Makefile.mk
+++ b/lib/arm/Makefile.mk
@@ -9,7 +9,7 @@
ModuleName := builtins
SubDirs :=
-OnlyArchs := armv5 armv6 armv7 armv7f armv7k armv7s
+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)))
diff --git a/lib/arm/comparesf2.S b/lib/arm/comparesf2.S
index ee18203392dc..ce6f4b9efd00 100644
--- a/lib/arm/comparesf2.S
+++ b/lib/arm/comparesf2.S
@@ -59,12 +59,14 @@ DEFINE_COMPILERRT_FUNCTION(__nesf2)
// 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
@@ -77,23 +79,27 @@ DEFINE_COMPILERRT_FUNCTION(__nesf2)
// 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.
- orrne r0, r0, #1
+ 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
@@ -108,12 +114,18 @@ DEFINE_COMPILERRT_FUNCTION(__gtsf2)
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
- orrne r0, r0, #1
+ it ne
+ orrne r0, r0, #1
cmp r2, #0xff000000
+ ite ls
cmpls r3, #0xff000000
movhi r0, #-1
bx lr
@@ -125,6 +137,7 @@ DEFINE_COMPILERRT_FUNCTION(__unordsf2)
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/divmodsi4.S b/lib/arm/divmodsi4.S
index d31e510c8f38..6495a8b4cc3a 100644
--- a/lib/arm/divmodsi4.S
+++ b/lib/arm/divmodsi4.S
@@ -24,7 +24,7 @@
.syntax unified
.align 3
DEFINE_COMPILERRT_FUNCTION(__divmodsi4)
-#if __ARM_ARCH_7S__
+#if __ARM_ARCH_EXT_IDIV__
tst r1, r1
beq LOCAL_LABEL(divzero)
mov r3, r0
diff --git a/lib/arm/divsi3.S b/lib/arm/divsi3.S
index e76fe31bb782..b631db292b8a 100644
--- a/lib/arm/divsi3.S
+++ b/lib/arm/divsi3.S
@@ -25,7 +25,7 @@
// 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_7S__
+#if __ARM_ARCH_EXT_IDIV__
tst r1,r1
beq LOCAL_LABEL(divzero)
sdiv r0, r0, r1
diff --git a/lib/arm/modsi3.S b/lib/arm/modsi3.S
index 04595011d0ec..fe75b41b1331 100644
--- a/lib/arm/modsi3.S
+++ b/lib/arm/modsi3.S
@@ -23,7 +23,7 @@
.syntax unified
.align 3
DEFINE_COMPILERRT_FUNCTION(__modsi3)
-#if __ARM_ARCH_7S__
+#if __ARM_ARCH_EXT_IDIV__
tst r1, r1
beq LOCAL_LABEL(divzero)
sdiv r2, r0, r1
diff --git a/lib/arm/switch16.S b/lib/arm/switch16.S
index e8f08c49c5df..9c3f0cf9915f 100644
--- a/lib/arm/switch16.S
+++ b/lib/arm/switch16.S
@@ -34,8 +34,9 @@ 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
- ldrshcc r0, [r0, #1] // load 16-bit element if r0 is in range
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
diff --git a/lib/arm/switch32.S b/lib/arm/switch32.S
index 7008fccb18ee..3152dfa1d0be 100644
--- a/lib/arm/switch32.S
+++ b/lib/arm/switch32.S
@@ -34,9 +34,10 @@ 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
- ldrcc r0, [r0, #3] // load 32-bit element if r0 is in range
add ip, lr, ip, lsl #2 // compute address of last element in table
- ldrcs r0, [ip, #3] // load 32-bit element if r0 out of range
+ 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
diff --git a/lib/arm/switch8.S b/lib/arm/switch8.S
index e784b4082e1f..15729ebc3165 100644
--- a/lib/arm/switch8.S
+++ b/lib/arm/switch8.S
@@ -33,7 +33,8 @@
DEFINE_COMPILERRT_PRIVATE_FUNCTION(__switch8)
ldrb ip, [lr, #-1] // get first byte in table
cmp r0, ip // signed compare with index
- ldrsbcc r0, [lr, r0] // get indexed byte out of table
+ 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
diff --git a/lib/arm/switchu8.S b/lib/arm/switchu8.S
index 19bed2f664d7..0a4efac88abe 100644
--- a/lib/arm/switchu8.S
+++ b/lib/arm/switchu8.S
@@ -33,7 +33,8 @@
DEFINE_COMPILERRT_PRIVATE_FUNCTION(__switchu8)
ldrb ip, [lr, #-1] // get first byte in table
cmp r0, ip // compare with index
- ldrbcc r0, [lr, r0] // get indexed byte out of table
+ 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
diff --git a/lib/arm/udivmodsi4.S b/lib/arm/udivmodsi4.S
index 9956cd48442f..aee2776671f7 100644
--- a/lib/arm/udivmodsi4.S
+++ b/lib/arm/udivmodsi4.S
@@ -31,7 +31,7 @@
.syntax unified
.align 3
DEFINE_COMPILERRT_FUNCTION(__udivmodsi4)
-#if __ARM_ARCH_7S__
+#if __ARM_ARCH_EXT_IDIV__
tst r1, r1
beq LOCAL_LABEL(divzero)
mov r3, r0
@@ -74,14 +74,17 @@ LOCAL_LABEL(mainLoop):
// 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
diff --git a/lib/arm/udivsi3.S b/lib/arm/udivsi3.S
index 28979fee4bdc..2bb14123ca31 100644
--- a/lib/arm/udivsi3.S
+++ b/lib/arm/udivsi3.S
@@ -33,7 +33,7 @@
// 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_7S__
+#if __ARM_ARCH_EXT_IDIV__
tst r1,r1
beq LOCAL_LABEL(divzero)
udiv r0, r0, r1
@@ -73,14 +73,17 @@ LOCAL_LABEL(mainLoop):
// 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):
diff --git a/lib/arm/umodsi3.S b/lib/arm/umodsi3.S
index 328e7054b857..092a4f1a2062 100644
--- a/lib/arm/umodsi3.S
+++ b/lib/arm/umodsi3.S
@@ -23,7 +23,7 @@
.syntax unified
.align 3
DEFINE_COMPILERRT_FUNCTION(__umodsi3)
-#if __ARM_ARCH_7S__
+#if __ARM_ARCH_EXT_IDIV__
tst r1, r1
beq LOCAL_LABEL(divzero)
udiv r2, r0, r1
@@ -57,13 +57,16 @@ LOCAL_LABEL(mainLoop):
// 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/asan/CMakeLists.txt b/lib/asan/CMakeLists.txt
index a567a4d3e970..ad3f05488ebf 100644
--- a/lib/asan/CMakeLists.txt
+++ b/lib/asan/CMakeLists.txt
@@ -19,18 +19,19 @@ set(ASAN_SOURCES
asan_stack.cc
asan_stats.cc
asan_thread.cc
- asan_win.cc
- )
-
-set(ASAN_DYLIB_SOURCES
- ${ASAN_SOURCES}
- )
+ asan_win.cc)
include_directories(..)
-set(ASAN_CFLAGS
- ${SANITIZER_COMMON_CFLAGS}
- -fno-rtti)
+if (NOT MSVC)
+ set(ASAN_CFLAGS
+ ${SANITIZER_COMMON_CFLAGS}
+ -fno-rtti)
+else()
+ set(ASAN_CFLAGS
+ ${SANITIZER_COMMON_CFLAGS}
+ /GR-)
+endif()
set(ASAN_COMMON_DEFINITIONS
ASAN_HAS_EXCEPTIONS=1)
@@ -40,6 +41,10 @@ if(ANDROID)
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
@@ -48,29 +53,55 @@ endif()
# Architectures supported by ASan.
filter_available_targets(ASAN_SUPPORTED_ARCH
- x86_64 i386 powerpc64 powerpc)
+ x86_64 i386 powerpc64)
+# 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}
+ 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})
+ endforeach()
+endif()
+
+# Build ASan runtimes shipped with Clang.
set(ASAN_RUNTIME_LIBRARIES)
if(APPLE)
- # Build universal binary on APPLE.
- add_compiler_rt_osx_dynamic_runtime(clang_rt.asan_osx_dynamic
- ARCH ${ASAN_SUPPORTED_ARCH}
- SOURCES ${ASAN_DYLIB_SOURCES}
- $<TARGET_OBJECTS:RTInterception.osx>
- $<TARGET_OBJECTS:RTSanitizerCommon.osx>
- CFLAGS ${ASAN_CFLAGS}
- DEFS ${ASAN_COMMON_DEFINITIONS}
+ foreach (os ${SANITIZER_COMMON_SUPPORTED_DARWIN_OS})
# Dynamic lookup is needed because shadow scale and offset are
# provided by the instrumented modules.
- LINKFLAGS "-framework Foundation"
- "-undefined dynamic_lookup")
- list(APPEND ASAN_RUNTIME_LIBRARIES clang_rt.asan_osx_dynamic)
+ 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}>
+ $<TARGET_OBJECTS:RTInterception.${os}>
+ $<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)
+ endforeach()
+
elseif(ANDROID)
add_library(clang_rt.asan-arm-android SHARED
- ${ASAN_SOURCES}
+ $<TARGET_OBJECTS:RTAsan.arm.android>
$<TARGET_OBJECTS:RTInterception.arm.android>
- $<TARGET_OBJECTS:RTSanitizerCommon.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
@@ -78,23 +109,44 @@ elseif(ANDROID)
target_link_libraries(clang_rt.asan-arm-android dl)
list(APPEND ASAN_RUNTIME_LIBRARIES clang_rt.asan-arm-android)
else()
- # Otherwise, build separate libraries for each target.
+ # Build separate libraries for each target.
foreach(arch ${ASAN_SUPPORTED_ARCH})
+ set(ASAN_RUNTIME_OBJECTS
+ $<TARGET_OBJECTS:RTAsan.${arch}>
+ $<TARGET_OBJECTS:RTInterception.${arch}>
+ $<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
+ $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>)
+ if (NOT WIN32)
+ # We can't build Leak Sanitizer on Windows yet.
+ list(APPEND ASAN_RUNTIME_OBJECTS $<TARGET_OBJECTS:RTLSanCommon.${arch}>)
+ endif()
+
add_compiler_rt_static_runtime(clang_rt.asan-${arch} ${arch}
- SOURCES ${ASAN_SOURCES}
- $<TARGET_OBJECTS:RTInterception.${arch}>
- $<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
- $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>
- $<TARGET_OBJECTS:RTLSanCommon.${arch}>
+ SOURCES ${ASAN_RUNTIME_OBJECTS}
CFLAGS ${ASAN_CFLAGS}
- DEFS ${ASAN_COMMON_DEFINITIONS}
- SYMS asan.syms)
+ DEFS ${ASAN_COMMON_DEFINITIONS})
list(APPEND ASAN_RUNTIME_LIBRARIES clang_rt.asan-${arch})
+ if (UNIX AND NOT ${arch} STREQUAL "i386")
+ add_sanitizer_rt_symbols(clang_rt.asan-${arch} asan.syms.extra)
+ list(APPEND ASAN_RUNTIME_LIBRARIES 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})
+ endif()
endforeach()
endif()
add_compiler_rt_resource_file(asan_blacklist asan_blacklist.txt)
+# All ASan runtime dependencies.
+add_custom_target(asan_runtime_libraries
+ DEPENDS asan_blacklist ${ASAN_RUNTIME_LIBRARIES})
+
if(LLVM_INCLUDE_TESTS)
add_subdirectory(tests)
endif()
diff --git a/lib/asan/asan.syms b/lib/asan/asan.syms
deleted file mode 100644
index fce367314093..000000000000
--- a/lib/asan/asan.syms
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- __asan_*;
- __sanitizer_syscall_pre_*;
- __sanitizer_syscall_post_*;
-};
diff --git a/lib/asan/asan.syms.extra b/lib/asan/asan.syms.extra
new file mode 100644
index 000000000000..007aafe380a8
--- /dev/null
+++ b/lib/asan/asan.syms.extra
@@ -0,0 +1,3 @@
+__asan_*
+__lsan_*
+__ubsan_*
diff --git a/lib/asan/asan_allocator.h b/lib/asan/asan_allocator.h
index f817ce352ee2..c5fcbbb5d64b 100644
--- a/lib/asan/asan_allocator.h
+++ b/lib/asan/asan_allocator.h
@@ -35,10 +35,11 @@ void InitializeAllocator();
class AsanChunkView {
public:
explicit AsanChunkView(AsanChunk *chunk) : chunk_(chunk) {}
- bool IsValid() { return chunk_ != 0; }
- uptr Beg(); // first byte of user memory.
- uptr End(); // last byte of user memory.
- uptr UsedSize(); // size requested by the user.
+ bool IsValid(); // Checks if AsanChunkView points to a valid allocated
+ // or quarantined chunk.
+ uptr Beg(); // First byte of user memory.
+ uptr End(); // Last byte of user memory.
+ uptr UsedSize(); // Size requested by the user.
uptr AllocTid();
uptr FreeTid();
void GetAllocStack(StackTrace *stack);
@@ -114,7 +115,7 @@ void *asan_pvalloc(uptr size, StackTrace *stack);
int asan_posix_memalign(void **memptr, uptr alignment, uptr size,
StackTrace *stack);
-uptr asan_malloc_usable_size(void *ptr, StackTrace *stack);
+uptr asan_malloc_usable_size(void *ptr, uptr pc, uptr bp);
uptr asan_mz_size(const void *ptr);
void asan_mz_force_lock();
diff --git a/lib/asan/asan_allocator2.cc b/lib/asan/asan_allocator2.cc
index d74aa553a288..7a29975d711e 100644
--- a/lib/asan/asan_allocator2.cc
+++ b/lib/asan/asan_allocator2.cc
@@ -94,7 +94,7 @@ AllocatorCache *GetAllocatorCache(AsanThreadLocalMallocStorage *ms) {
static Allocator allocator;
static const uptr kMaxAllowedMallocSize =
- FIRST_32_SECOND_64(3UL << 30, 8UL << 30);
+ FIRST_32_SECOND_64(3UL << 30, 64UL << 30);
static const uptr kMaxThreadLocalQuarantine =
FIRST_32_SECOND_64(1 << 18, 1 << 20);
@@ -146,14 +146,15 @@ static uptr ComputeRZLog(uptr user_requested_size) {
// ChunkBase consists of ChunkHeader and other bytes that overlap with user
// memory.
-// If a memory chunk is allocated by memalign and we had to increase the
-// allocation size to achieve the proper alignment, then we store this magic
+// If the left redzone is greater than the ChunkHeader size we store a magic
// value in the first uptr word of the memory block and store the address of
// ChunkBase in the next uptr.
-// M B ? ? ? L L L L L L H H U U U U U U
-// M -- magic value kMemalignMagic
+// M B L L L L L L L L L H H U U U U U U
+// | ^
+// ---------------------|
+// M -- magic value kAllocBegMagic
// B -- address of ChunkHeader pointing to the first 'H'
-static const uptr kMemalignMagic = 0xCC6E96B9;
+static const uptr kAllocBegMagic = 0xCC6E96B9;
struct ChunkHeader {
// 1-st 8 bytes.
@@ -185,14 +186,19 @@ COMPILER_CHECK(kChunkHeader2Size <= 16);
struct AsanChunk: ChunkBase {
uptr Beg() { return reinterpret_cast<uptr>(this) + kChunkHeaderSize; }
- uptr UsedSize() {
+ uptr UsedSize(bool locked_version = false) {
if (user_requested_size != SizeClassMap::kMaxSize)
return user_requested_size;
- return *reinterpret_cast<uptr *>(allocator.GetMetaData(AllocBeg()));
- }
- void *AllocBeg() {
- if (from_memalign)
+ return *reinterpret_cast<uptr *>(
+ allocator.GetMetaData(AllocBeg(locked_version)));
+ }
+ void *AllocBeg(bool locked_version = false) {
+ if (from_memalign) {
+ if (locked_version)
+ return allocator.GetBlockBeginFastLocked(
+ reinterpret_cast<void *>(this));
return allocator.GetBlockBegin(reinterpret_cast<void *>(this));
+ }
return reinterpret_cast<void*>(Beg() - RZLog2Size(rz_log));
}
// If we don't use stack depot, we store the alloc/free stack traces
@@ -212,11 +218,14 @@ struct AsanChunk: ChunkBase {
uptr available = RoundUpTo(user_requested_size, SHADOW_GRANULARITY);
return (available - kChunkHeader2Size) / sizeof(u32);
}
- bool AddrIsInside(uptr addr) {
- return (addr >= Beg()) && (addr < Beg() + UsedSize());
+ bool AddrIsInside(uptr addr, bool locked_version = false) {
+ return (addr >= Beg()) && (addr < Beg() + UsedSize(locked_version));
}
};
+bool AsanChunkView::IsValid() {
+ return chunk_ != 0 && chunk_->chunk_state != CHUNK_AVAILABLE;
+}
uptr AsanChunkView::Beg() { return chunk_->Beg(); }
uptr AsanChunkView::End() { return Beg() + UsedSize(); }
uptr AsanChunkView::UsedSize() { return chunk_->UsedSize(); }
@@ -227,25 +236,16 @@ static void GetStackTraceFromId(u32 id, StackTrace *stack) {
CHECK(id);
uptr size = 0;
const uptr *trace = StackDepotGet(id, &size);
- CHECK_LT(size, kStackTraceMax);
- internal_memcpy(stack->trace, trace, sizeof(uptr) * size);
- stack->size = size;
+ CHECK(trace);
+ stack->CopyFrom(trace, size);
}
void AsanChunkView::GetAllocStack(StackTrace *stack) {
- if (flags()->use_stack_depot)
- GetStackTraceFromId(chunk_->alloc_context_id, stack);
- else
- StackTrace::UncompressStack(stack, chunk_->AllocStackBeg(),
- chunk_->AllocStackSize());
+ GetStackTraceFromId(chunk_->alloc_context_id, stack);
}
void AsanChunkView::GetFreeStack(StackTrace *stack) {
- if (flags()->use_stack_depot)
- GetStackTraceFromId(chunk_->free_context_id, stack);
- else
- StackTrace::UncompressStack(stack, chunk_->FreeStackBeg(),
- chunk_->FreeStackSize());
+ GetStackTraceFromId(chunk_->free_context_id, stack);
}
struct QuarantineCallback;
@@ -276,10 +276,13 @@ struct QuarantineCallback {
RoundUpTo(m->UsedSize(), SHADOW_GRANULARITY),
kAsanHeapLeftRedzoneMagic);
void *p = reinterpret_cast<void *>(m->AllocBeg());
- if (m->from_memalign) {
- uptr *memalign_magic = reinterpret_cast<uptr *>(p);
- CHECK_EQ(memalign_magic[0], kMemalignMagic);
- CHECK_EQ(memalign_magic[1], reinterpret_cast<uptr>(m));
+ if (p != m) {
+ uptr *alloc_magic = reinterpret_cast<uptr *>(p);
+ CHECK_EQ(alloc_magic[0], kAllocBegMagic);
+ // Clear the magic value, as allocator internals may overwrite the
+ // contents of deallocated chunk, confusing GetAsanChunk lookup.
+ alloc_magic[0] = 0;
+ CHECK_EQ(alloc_magic[1], reinterpret_cast<uptr>(m));
}
// Statistics.
@@ -341,7 +344,7 @@ static void *Allocate(uptr size, uptr alignment, StackTrace *stack,
if (size > kMaxAllowedMallocSize || needed_size > kMaxAllowedMallocSize) {
Report("WARNING: AddressSanitizer failed to allocate %p bytes\n",
(void*)size);
- return 0;
+ return AllocatorReturnNull();
}
AsanThread *t = GetCurrentThread();
@@ -355,8 +358,6 @@ static void *Allocate(uptr size, uptr alignment, StackTrace *stack,
allocated = allocator.Allocate(cache, needed_size, 8, false);
}
uptr alloc_beg = reinterpret_cast<uptr>(allocated);
- // Clear the first allocated word (an old kMemalignMagic may still be there).
- reinterpret_cast<uptr *>(alloc_beg)[0] = 0;
uptr alloc_end = alloc_beg + needed_size;
uptr beg_plus_redzone = alloc_beg + rz_size;
uptr user_beg = beg_plus_redzone;
@@ -373,11 +374,10 @@ static void *Allocate(uptr size, uptr alignment, StackTrace *stack,
CHECK_EQ(alloc_tid, m->alloc_tid); // Does alloc_tid fit into the bitfield?
m->free_tid = kInvalidTid;
m->from_memalign = user_beg != beg_plus_redzone;
- if (m->from_memalign) {
- CHECK_LE(beg_plus_redzone + 2 * sizeof(uptr), user_beg);
- uptr *memalign_magic = reinterpret_cast<uptr *>(alloc_beg);
- memalign_magic[0] = kMemalignMagic;
- memalign_magic[1] = chunk_beg;
+ if (alloc_beg != chunk_beg) {
+ CHECK_LE(alloc_beg+ 2 * sizeof(uptr), chunk_beg);
+ reinterpret_cast<uptr *>(alloc_beg)[0] = kAllocBegMagic;
+ reinterpret_cast<uptr *>(alloc_beg)[1] = chunk_beg;
}
if (using_primary_allocator) {
CHECK(size);
@@ -391,12 +391,7 @@ static void *Allocate(uptr size, uptr alignment, StackTrace *stack,
meta[1] = chunk_beg;
}
- if (fl.use_stack_depot) {
- m->alloc_context_id = StackDepotPut(stack->trace, stack->size);
- } else {
- m->alloc_context_id = 0;
- StackTrace::CompressStack(stack, m->AllocStackBeg(), m->AllocStackSize());
- }
+ m->alloc_context_id = StackDepotPut(stack->trace, stack->size);
uptr size_rounded_down_to_granularity = RoundDownTo(size, SHADOW_GRANULARITY);
// Unpoison the bulk of the memory region.
@@ -405,7 +400,7 @@ static void *Allocate(uptr size, uptr alignment, StackTrace *stack,
// Deal with the end of the region if size is not aligned to granularity.
if (size != size_rounded_down_to_granularity && fl.poison_heap) {
u8 *shadow = (u8*)MemToShadow(user_beg + size_rounded_down_to_granularity);
- *shadow = size & (SHADOW_GRANULARITY - 1);
+ *shadow = fl.poison_partial ? (size & (SHADOW_GRANULARITY - 1)) : 0;
}
AsanStats &thread_stats = GetCurrentThreadStats();
@@ -422,23 +417,30 @@ static void *Allocate(uptr size, uptr alignment, StackTrace *stack,
uptr fill_size = Min(size, (uptr)fl.max_malloc_fill_size);
REAL(memset)(res, fl.malloc_fill_byte, fill_size);
}
+#if CAN_SANITIZE_LEAKS
+ m->lsan_tag = __lsan::DisabledInThisThread() ? __lsan::kIgnored
+ : __lsan::kDirectlyLeaked;
+#endif
// Must be the last mutation of metadata in this function.
atomic_store((atomic_uint8_t *)m, CHUNK_ALLOCATED, memory_order_release);
ASAN_MALLOC_HOOK(res, size);
return res;
}
+static void ReportInvalidFree(void *ptr, u8 chunk_state, StackTrace *stack) {
+ if (chunk_state == CHUNK_QUARANTINE)
+ ReportDoubleFree((uptr)ptr, stack);
+ else
+ ReportFreeNotMalloced((uptr)ptr, stack);
+}
+
static void AtomicallySetQuarantineFlag(AsanChunk *m,
void *ptr, StackTrace *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,
- CHUNK_QUARANTINE, memory_order_acquire)) {
- if (old_chunk_state == CHUNK_QUARANTINE)
- ReportDoubleFree((uptr)ptr, stack);
- else
- ReportFreeNotMalloced((uptr)ptr, stack);
- }
+ CHUNK_QUARANTINE, memory_order_acquire))
+ ReportInvalidFree(ptr, old_chunk_state, stack);
CHECK_EQ(CHUNK_ALLOCATED, old_chunk_state);
}
@@ -448,12 +450,6 @@ static void QuarantineChunk(AsanChunk *m, void *ptr,
StackTrace *stack, AllocType alloc_type) {
CHECK_EQ(m->chunk_state, CHUNK_QUARANTINE);
- // FIXME: if the free hook produces an ASan report (e.g. due to a bug),
- // printing the report may crash as the AsanChunk free-related fields have not
- // been updated yet. We might need to introduce yet another chunk state to
- // handle this correctly, but don't want to yet.
- ASAN_FREE_HOOK(ptr);
-
if (m->alloc_type != alloc_type && flags()->alloc_dealloc_mismatch)
ReportAllocTypeMismatch((uptr)ptr, stack,
(AllocType)m->alloc_type, (AllocType)alloc_type);
@@ -463,12 +459,7 @@ static void QuarantineChunk(AsanChunk *m, void *ptr,
CHECK_EQ(m->free_tid, kInvalidTid);
AsanThread *t = GetCurrentThread();
m->free_tid = t ? t->tid() : 0;
- if (flags()->use_stack_depot) {
- m->free_context_id = StackDepotPut(stack->trace, stack->size);
- } else {
- m->free_context_id = 0;
- StackTrace::CompressStack(stack, m->FreeStackBeg(), m->FreeStackSize());
- }
+ m->free_context_id = StackDepotPut(stack->trace, stack->size);
// Poison the region.
PoisonShadow(m->Beg(),
RoundUpTo(m->UsedSize(), SHADOW_GRANULARITY),
@@ -498,6 +489,7 @@ static void Deallocate(void *ptr, StackTrace *stack, AllocType alloc_type) {
uptr chunk_beg = p - kChunkHeaderSize;
AsanChunk *m = reinterpret_cast<AsanChunk *>(chunk_beg);
+ 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);
@@ -513,50 +505,45 @@ static void *Reallocate(void *old_ptr, uptr new_size, StackTrace *stack) {
thread_stats.reallocs++;
thread_stats.realloced += new_size;
- // Must mark the chunk as quarantined before any changes to its metadata.
- // This also ensures that other threads can't deallocate it in the meantime.
- AtomicallySetQuarantineFlag(m, old_ptr, stack);
-
- uptr old_size = m->UsedSize();
- uptr memcpy_size = Min(new_size, old_size);
void *new_ptr = Allocate(new_size, 8, stack, FROM_MALLOC, true);
if (new_ptr) {
+ u8 chunk_state = m->chunk_state;
+ if (chunk_state != CHUNK_ALLOCATED)
+ ReportInvalidFree(old_ptr, chunk_state, stack);
CHECK_NE(REAL(memcpy), (void*)0);
+ uptr memcpy_size = Min(new_size, m->UsedSize());
+ // If realloc() races with free(), we may start copying freed memory.
+ // However, we will report racy double-free later anyway.
REAL(memcpy)(new_ptr, old_ptr, memcpy_size);
- QuarantineChunk(m, old_ptr, stack, FROM_MALLOC);
+ Deallocate(old_ptr, stack, FROM_MALLOC);
}
return new_ptr;
}
-static AsanChunk *GetAsanChunkByAddr(uptr p) {
- void *ptr = reinterpret_cast<void *>(p);
- uptr alloc_beg = reinterpret_cast<uptr>(allocator.GetBlockBegin(ptr));
+// Assumes alloc_beg == allocator.GetBlockBegin(alloc_beg).
+static AsanChunk *GetAsanChunk(void *alloc_beg) {
if (!alloc_beg) return 0;
- uptr *memalign_magic = reinterpret_cast<uptr *>(alloc_beg);
- if (memalign_magic[0] == kMemalignMagic) {
- AsanChunk *m = reinterpret_cast<AsanChunk *>(memalign_magic[1]);
- CHECK(m->from_memalign);
- return m;
- }
- if (!allocator.FromPrimary(ptr)) {
- uptr *meta = reinterpret_cast<uptr *>(
- allocator.GetMetaData(reinterpret_cast<void *>(alloc_beg)));
+ if (!allocator.FromPrimary(alloc_beg)) {
+ uptr *meta = reinterpret_cast<uptr *>(allocator.GetMetaData(alloc_beg));
AsanChunk *m = reinterpret_cast<AsanChunk *>(meta[1]);
return m;
}
- uptr actual_size = allocator.GetActuallyAllocatedSize(ptr);
- CHECK_LE(actual_size, SizeClassMap::kMaxSize);
- // We know the actually allocted size, but we don't know the redzone size.
- // Just try all possible redzone sizes.
- for (u32 rz_log = 0; rz_log < 8; rz_log++) {
- u32 rz_size = RZLog2Size(rz_log);
- uptr max_possible_size = actual_size - rz_size;
- if (ComputeRZLog(max_possible_size) != rz_log)
- continue;
- return reinterpret_cast<AsanChunk *>(
- alloc_beg + rz_size - kChunkHeaderSize);
- }
- return 0;
+ uptr *alloc_magic = reinterpret_cast<uptr *>(alloc_beg);
+ if (alloc_magic[0] == kAllocBegMagic)
+ return reinterpret_cast<AsanChunk *>(alloc_magic[1]);
+ return reinterpret_cast<AsanChunk *>(alloc_beg);
+}
+
+static AsanChunk *GetAsanChunkByAddr(uptr p) {
+ void *alloc_beg = allocator.GetBlockBegin(reinterpret_cast<void *>(p));
+ return GetAsanChunk(alloc_beg);
+}
+
+// Allocator must be locked when this function is called.
+static AsanChunk *GetAsanChunkByAddrFastLocked(uptr p) {
+ void *alloc_beg =
+ allocator.GetBlockBeginFastLocked(reinterpret_cast<void *>(p));
+ return GetAsanChunk(alloc_beg);
}
static uptr AllocationSize(uptr p) {
@@ -621,24 +608,22 @@ void PrintInternalAllocatorStats() {
allocator.PrintStats();
}
-SANITIZER_INTERFACE_ATTRIBUTE
void *asan_memalign(uptr alignment, uptr size, StackTrace *stack,
AllocType alloc_type) {
return Allocate(size, alignment, stack, alloc_type, true);
}
-SANITIZER_INTERFACE_ATTRIBUTE
void asan_free(void *ptr, StackTrace *stack, AllocType alloc_type) {
Deallocate(ptr, stack, alloc_type);
}
-SANITIZER_INTERFACE_ATTRIBUTE
void *asan_malloc(uptr size, StackTrace *stack) {
return Allocate(size, 8, stack, FROM_MALLOC, true);
}
void *asan_calloc(uptr nmemb, uptr size, StackTrace *stack) {
- if (CallocShouldReturnNullDueToOverflow(size, nmemb)) return 0;
+ if (CallocShouldReturnNullDueToOverflow(size, nmemb))
+ return AllocatorReturnNull();
void *ptr = Allocate(nmemb * size, 8, stack, FROM_MALLOC, false);
// If the memory comes from the secondary allocator no need to clear it
// as it comes directly from mmap.
@@ -679,12 +664,13 @@ int asan_posix_memalign(void **memptr, uptr alignment, uptr size,
return 0;
}
-uptr asan_malloc_usable_size(void *ptr, StackTrace *stack) {
- CHECK(stack);
+uptr asan_malloc_usable_size(void *ptr, uptr pc, uptr bp) {
if (ptr == 0) return 0;
uptr usable_size = AllocationSize(reinterpret_cast<uptr>(ptr));
- if (flags()->check_malloc_usable_size && (usable_size == 0))
- ReportMallocUsableSizeNotOwned((uptr)ptr, stack);
+ if (flags()->check_malloc_usable_size && (usable_size == 0)) {
+ GET_STACK_TRACE_FATAL(pc, bp);
+ ReportMallocUsableSizeNotOwned((uptr)ptr, &stack);
+ }
return usable_size;
}
@@ -719,25 +705,26 @@ void GetAllocatorGlobalRange(uptr *begin, uptr *end) {
*end = *begin + sizeof(__asan::allocator);
}
-void *PointsIntoChunk(void* p) {
+uptr PointsIntoChunk(void* p) {
uptr addr = reinterpret_cast<uptr>(p);
- __asan::AsanChunk *m = __asan::GetAsanChunkByAddr(addr);
+ __asan::AsanChunk *m = __asan::GetAsanChunkByAddrFastLocked(addr);
if (!m) return 0;
uptr chunk = m->Beg();
- if ((m->chunk_state == __asan::CHUNK_ALLOCATED) && m->AddrIsInside(addr))
- return reinterpret_cast<void *>(chunk);
+ if ((m->chunk_state == __asan::CHUNK_ALLOCATED) &&
+ m->AddrIsInside(addr, /*locked_version=*/true))
+ return chunk;
return 0;
}
-void *GetUserBegin(void *p) {
- __asan::AsanChunk *m = __asan::GetAsanChunkByAddr(reinterpret_cast<uptr>(p));
+uptr GetUserBegin(uptr chunk) {
+ __asan::AsanChunk *m =
+ __asan::GetAsanChunkByAddrFastLocked(chunk);
CHECK(m);
- return reinterpret_cast<void *>(m->Beg());
+ return m->Beg();
}
-LsanMetadata::LsanMetadata(void *chunk) {
- uptr addr = reinterpret_cast<uptr>(chunk);
- metadata_ = reinterpret_cast<void *>(addr - __asan::kChunkHeaderSize);
+LsanMetadata::LsanMetadata(uptr chunk) {
+ metadata_ = reinterpret_cast<void *>(chunk - __asan::kChunkHeaderSize);
}
bool LsanMetadata::allocated() const {
@@ -757,7 +744,7 @@ void LsanMetadata::set_tag(ChunkTag value) {
uptr LsanMetadata::requested_size() const {
__asan::AsanChunk *m = reinterpret_cast<__asan::AsanChunk *>(metadata_);
- return m->UsedSize();
+ return m->UsedSize(/*locked_version=*/true);
}
u32 LsanMetadata::stack_trace_id() const {
@@ -765,18 +752,23 @@ u32 LsanMetadata::stack_trace_id() const {
return m->alloc_context_id;
}
-template <typename Callable> void ForEachChunk(Callable const &callback) {
- __asan::allocator.ForEachChunk(callback);
+void ForEachChunk(ForEachChunkCallback callback, void *arg) {
+ __asan::allocator.ForEachChunk(callback, arg);
+}
+
+IgnoreObjectResult IgnoreObjectLocked(const void *p) {
+ uptr addr = reinterpret_cast<uptr>(p);
+ __asan::AsanChunk *m = __asan::GetAsanChunkByAddr(addr);
+ if (!m) return kIgnoreObjectInvalid;
+ if ((m->chunk_state == __asan::CHUNK_ALLOCATED) && m->AddrIsInside(addr)) {
+ if (m->lsan_tag == kIgnored)
+ return kIgnoreObjectAlreadyIgnored;
+ m->lsan_tag = __lsan::kIgnored;
+ return kIgnoreObjectSuccess;
+ } else {
+ return kIgnoreObjectInvalid;
+ }
}
-#if CAN_SANITIZE_LEAKS
-template void ForEachChunk<ProcessPlatformSpecificAllocationsCb>(
- ProcessPlatformSpecificAllocationsCb const &callback);
-template void ForEachChunk<PrintLeakedCb>(PrintLeakedCb const &callback);
-template void ForEachChunk<CollectLeaksCb>(CollectLeaksCb const &callback);
-template void ForEachChunk<MarkIndirectlyLeakedCb>(
- MarkIndirectlyLeakedCb const &callback);
-template void ForEachChunk<ClearTagCb>(ClearTagCb const &callback);
-#endif // CAN_SANITIZE_LEAKS
} // namespace __lsan
// ---------------------- Interface ---------------- {{{1
@@ -808,12 +800,12 @@ uptr __asan_get_allocated_size(const void *p) {
#if !SANITIZER_SUPPORTS_WEAK_HOOKS
// Provide default (no-op) implementation of malloc hooks.
extern "C" {
-SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
void __asan_malloc_hook(void *ptr, uptr size) {
(void)ptr;
(void)size;
}
-SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
void __asan_free_hook(void *ptr) {
(void)ptr;
}
diff --git a/lib/asan/asan_blacklist.txt b/lib/asan/asan_blacklist.txt
index 03da08598d23..63b3c315b26b 100644
--- a/lib/asan/asan_blacklist.txt
+++ b/lib/asan/asan_blacklist.txt
@@ -6,5 +6,5 @@
# fun:*bad_function_name*
# src:file_with_tricky_code.cc
# global:*global_with_bad_access_or_initialization*
-# global-init:*global_with_initialization_issues*
-# global-init-type:*Namespace::ClassName*
+# global:*global_with_initialization_issues*=init
+# type:*Namespace::ClassName*=init
diff --git a/lib/asan/asan_dll_thunk.cc b/lib/asan/asan_dll_thunk.cc
new file mode 100644
index 000000000000..cedd60d342f6
--- /dev/null
+++ b/lib/asan/asan_dll_thunk.cc
@@ -0,0 +1,196 @@
+//===-- 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 23eebe64e612..d3e55bff1e6e 100644
--- a/lib/asan/asan_fake_stack.cc
+++ b/lib/asan/asan_fake_stack.cc
@@ -17,167 +17,204 @@
namespace __asan {
-FakeStack::FakeStack() {
- CHECK(REAL(memset));
- REAL(memset)(this, 0, sizeof(*this));
+static const u64 kMagic1 = kAsanStackAfterReturnMagic;
+static const u64 kMagic2 = (kMagic1 << 8) | kMagic1;
+static const u64 kMagic4 = (kMagic2 << 16) | kMagic2;
+static const u64 kMagic8 = (kMagic4 << 32) | kMagic4;
+
+// For small size classes inline PoisonShadow for better performance.
+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++)
+ shadow[i] = magic;
+ } else {
+ // The size class is too big, it's cheaper to poison only size bytes.
+ PoisonShadow(ptr, size, static_cast<u8>(magic));
+ }
}
-bool FakeStack::AddrIsInSizeClass(uptr addr, uptr size_class) {
- uptr mem = allocated_size_classes_[size_class];
- uptr size = ClassMmapSize(size_class);
- bool res = mem && addr >= mem && addr < mem + size;
+FakeStack *FakeStack::Create(uptr stack_size_log) {
+ static uptr kMinStackSizeLog = 16;
+ static uptr kMaxStackSizeLog = FIRST_32_SECOND_64(24, 28);
+ if (stack_size_log < kMinStackSizeLog)
+ stack_size_log = kMinStackSizeLog;
+ if (stack_size_log > kMaxStackSizeLog)
+ stack_size_log = kMaxStackSizeLog;
+ FakeStack *res = reinterpret_cast<FakeStack *>(
+ MmapOrDie(RequiredSize(stack_size_log), "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);
+ }
return res;
}
-uptr FakeStack::AddrIsInFakeStack(uptr addr) {
- for (uptr size_class = 0; size_class < kNumberOfSizeClasses; size_class++) {
- if (!AddrIsInSizeClass(addr, size_class)) continue;
- uptr size_class_first_ptr = allocated_size_classes_[size_class];
- uptr size = ClassSize(size_class);
- CHECK_LE(size_class_first_ptr, addr);
- CHECK_GT(size_class_first_ptr + ClassMmapSize(size_class), addr);
- return size_class_first_ptr + ((addr - size_class_first_ptr) / size) * size;
- }
- return 0;
+void FakeStack::Destroy() {
+ PoisonAll(0);
+ UnmapOrDie(this, RequiredSize(stack_size_log_));
}
-// We may want to compute this during compilation.
-ALWAYS_INLINE uptr FakeStack::ComputeSizeClass(uptr alloc_size) {
- uptr rounded_size = RoundUpToPowerOfTwo(alloc_size);
- uptr log = Log2(rounded_size);
- CHECK_LE(alloc_size, (1UL << log));
- CHECK_GT(alloc_size, (1UL << (log-1)));
- uptr res = log < kMinStackFrameSizeLog ? 0 : log - kMinStackFrameSizeLog;
- CHECK_LT(res, kNumberOfSizeClasses);
- CHECK_GE(ClassSize(res), rounded_size);
- return res;
+void FakeStack::PoisonAll(u8 magic) {
+ PoisonShadow(reinterpret_cast<uptr>(this), RequiredSize(stack_size_log()),
+ magic);
}
-void FakeFrameFifo::FifoPush(FakeFrame *node) {
- CHECK(node);
- node->next = 0;
- if (first_ == 0 && last_ == 0) {
- first_ = last_ = node;
- } else {
- CHECK(first_);
- CHECK(last_);
- last_->next = node;
- last_ = node;
+ALWAYS_INLINE USED
+FakeFrame *FakeStack::Allocate(uptr stack_size_log, uptr class_id,
+ uptr real_stack) {
+ CHECK_LT(class_id, kNumberOfSizeClasses);
+ if (needs_gc_)
+ GC(real_stack);
+ uptr &hint_position = hint_position_[class_id];
+ const int num_iter = NumberOfFrames(stack_size_log, class_id);
+ u8 *flags = GetFlags(stack_size_log, class_id);
+ for (int i = 0; i < num_iter; i++) {
+ uptr pos = ModuloNumberOfFrames(stack_size_log, class_id, hint_position++);
+ // This part is tricky. On one hand, checking and setting flags[pos]
+ // should be atomic to ensure async-signal safety. But on the other hand,
+ // if the signal arrives between checking and setting flags[pos], the
+ // signal handler's fake stack will start from a different hint_position
+ // and so will not touch this particular byte. So, it is safe to do this
+ // with regular non-atimic load and store (at least I was not able to make
+ // this code crash).
+ if (flags[pos]) continue;
+ flags[pos] = 1;
+ FakeFrame *res = reinterpret_cast<FakeFrame *>(
+ GetFrame(stack_size_log, class_id, pos));
+ res->real_stack = real_stack;
+ *SavedFlagPtr(reinterpret_cast<uptr>(res), class_id) = &flags[pos];
+ return res;
}
+ return 0; // We are out of fake stack.
}
-FakeFrame *FakeFrameFifo::FifoPop() {
- CHECK(first_ && last_ && "Exhausted fake stack");
- FakeFrame *res = 0;
- if (first_ == last_) {
- res = first_;
- first_ = last_ = 0;
- } else {
- res = first_;
- first_ = first_->next;
- }
- return res;
+uptr FakeStack::AddrIsInFakeStack(uptr ptr) {
+ 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);
+ if (ptr < beg || ptr >= end) return 0;
+ uptr class_id = (ptr - beg) >> stack_size_log;
+ uptr base = beg + (class_id << stack_size_log);
+ 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);
}
-void FakeStack::Init(uptr stack_size) {
- stack_size_ = stack_size;
- alive_ = true;
+void FakeStack::HandleNoReturn() {
+ needs_gc_ = true;
}
-void FakeStack::Cleanup() {
- alive_ = false;
- for (uptr i = 0; i < kNumberOfSizeClasses; i++) {
- uptr mem = allocated_size_classes_[i];
- if (mem) {
- PoisonShadow(mem, ClassMmapSize(i), 0);
- allocated_size_classes_[i] = 0;
- UnmapOrDie((void*)mem, ClassMmapSize(i));
+// When throw, longjmp or some such happens we don't call OnFree() and
+// as the result may leak one or more fake frames, but the good news is that
+// we are notified about all such events by HandleNoReturn().
+// If we recently had such no-return event we need to collect garbage frames.
+// We do it based on their 'real_stack' values -- everything that is lower
+// than the current real_stack is garbage.
+NOINLINE void FakeStack::GC(uptr real_stack) {
+ uptr collected = 0;
+ for (uptr class_id = 0; class_id < kNumberOfSizeClasses; class_id++) {
+ u8 *flags = GetFlags(stack_size_log(), class_id);
+ for (uptr i = 0, n = NumberOfFrames(stack_size_log(), class_id); i < n;
+ i++) {
+ if (flags[i] == 0) continue; // not allocated.
+ FakeFrame *ff = reinterpret_cast<FakeFrame *>(
+ GetFrame(stack_size_log(), class_id, i));
+ if (ff->real_stack < real_stack) {
+ flags[i] = 0;
+ collected++;
+ }
}
}
+ needs_gc_ = false;
}
-uptr FakeStack::ClassMmapSize(uptr size_class) {
- return RoundUpToPowerOfTwo(stack_size_);
+void FakeStack::ForEachFakeFrame(RangeIteratorCallback callback, void *arg) {
+ for (uptr class_id = 0; class_id < kNumberOfSizeClasses; class_id++) {
+ u8 *flags = GetFlags(stack_size_log(), class_id);
+ for (uptr i = 0, n = NumberOfFrames(stack_size_log(), class_id); i < n;
+ i++) {
+ if (flags[i] == 0) continue; // not allocated.
+ FakeFrame *ff = reinterpret_cast<FakeFrame *>(
+ GetFrame(stack_size_log(), class_id, i));
+ uptr begin = reinterpret_cast<uptr>(ff);
+ callback(begin, begin + FakeStack::BytesInSizeClass(class_id), arg);
+ }
+ }
}
-void FakeStack::AllocateOneSizeClass(uptr size_class) {
- CHECK(ClassMmapSize(size_class) >= GetPageSizeCached());
- uptr new_mem = (uptr)MmapOrDie(
- ClassMmapSize(size_class), __FUNCTION__);
- // Printf("T%d new_mem[%zu]: %p-%p mmap %zu\n",
- // GetCurrentThread()->tid(),
- // size_class, new_mem, new_mem + ClassMmapSize(size_class),
- // ClassMmapSize(size_class));
- uptr i;
- for (i = 0; i < ClassMmapSize(size_class);
- i += ClassSize(size_class)) {
- size_classes_[size_class].FifoPush((FakeFrame*)(new_mem + i));
- }
- CHECK(i == ClassMmapSize(size_class));
- allocated_size_classes_[size_class] = new_mem;
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+static THREADLOCAL FakeStack *fake_stack_tls;
+
+FakeStack *GetTLSFakeStack() {
+ return fake_stack_tls;
+}
+void SetTLSFakeStack(FakeStack *fs) {
+ fake_stack_tls = fs;
}
+#else
+FakeStack *GetTLSFakeStack() { return 0; }
+void SetTLSFakeStack(FakeStack *fs) { }
+#endif // SANITIZER_LINUX && !SANITIZER_ANDROID
-ALWAYS_INLINE uptr FakeStack::AllocateStack(uptr size, uptr real_stack) {
- if (!alive_) return real_stack;
- CHECK(size <= kMaxStackMallocSize && size > 1);
- uptr size_class = ComputeSizeClass(size);
- if (!allocated_size_classes_[size_class]) {
- AllocateOneSizeClass(size_class);
- }
- FakeFrame *fake_frame = size_classes_[size_class].FifoPop();
- CHECK(fake_frame);
- fake_frame->size_minus_one = size - 1;
- fake_frame->real_stack = real_stack;
- while (FakeFrame *top = call_stack_.top()) {
- if (top->real_stack > real_stack) break;
- call_stack_.LifoPop();
- DeallocateFrame(top);
- }
- call_stack_.LifoPush(fake_frame);
- uptr ptr = (uptr)fake_frame;
- PoisonShadow(ptr, size, 0);
- return ptr;
+static FakeStack *GetFakeStack() {
+ AsanThread *t = GetCurrentThread();
+ if (!t) return 0;
+ return t->fake_stack();
}
-ALWAYS_INLINE void FakeStack::DeallocateFrame(FakeFrame *fake_frame) {
- CHECK(alive_);
- uptr size = fake_frame->size_minus_one + 1;
- uptr size_class = ComputeSizeClass(size);
- CHECK(allocated_size_classes_[size_class]);
- uptr ptr = (uptr)fake_frame;
- CHECK(AddrIsInSizeClass(ptr, size_class));
- CHECK(AddrIsInSizeClass(ptr + size - 1, size_class));
- size_classes_[size_class].FifoPush(fake_frame);
+static FakeStack *GetFakeStackFast() {
+ if (FakeStack *fs = GetTLSFakeStack())
+ return fs;
+ if (!__asan_option_detect_stack_use_after_return)
+ return 0;
+ return GetFakeStack();
+}
+
+ALWAYS_INLINE uptr OnMalloc(uptr class_id, uptr size, uptr real_stack) {
+ FakeStack *fs = GetFakeStackFast();
+ if (!fs) return real_stack;
+ FakeFrame *ff = fs->Allocate(fs->stack_size_log(), class_id, real_stack);
+ if (!ff)
+ return real_stack; // Out of fake stack, return the real one.
+ uptr ptr = reinterpret_cast<uptr>(ff);
+ SetShadow(ptr, size, class_id, 0);
+ return ptr;
}
-ALWAYS_INLINE void FakeStack::OnFree(uptr ptr, uptr size, uptr real_stack) {
- FakeFrame *fake_frame = (FakeFrame*)ptr;
- CHECK_EQ(fake_frame->magic, kRetiredStackFrameMagic);
- CHECK_NE(fake_frame->descr, 0);
- CHECK_EQ(fake_frame->size_minus_one, size - 1);
- PoisonShadow(ptr, size, kAsanStackAfterReturnMagic);
+ALWAYS_INLINE void OnFree(uptr ptr, uptr class_id, uptr size, uptr real_stack) {
+ if (ptr == real_stack)
+ return;
+ FakeStack::Deallocate(ptr, class_id);
+ SetShadow(ptr, size, class_id, kMagic8);
}
} // namespace __asan
// ---------------------- Interface ---------------- {{{1
-using namespace __asan; // NOLINT
-
-uptr __asan_stack_malloc(uptr size, uptr real_stack) {
- if (!flags()->use_fake_stack) return real_stack;
- AsanThread *t = GetCurrentThread();
- if (!t) {
- // TSD is gone, use the real stack.
- return real_stack;
+#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); \
+ } \
+ 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); \
}
- uptr ptr = t->fake_stack().AllocateStack(size, real_stack);
- // Printf("__asan_stack_malloc %p %zu %p\n", ptr, size, real_stack);
- return ptr;
-}
-void __asan_stack_free(uptr ptr, uptr size, uptr real_stack) {
- if (!flags()->use_fake_stack) return;
- if (ptr != real_stack) {
- FakeStack::OnFree(ptr, size, real_stack);
- }
-}
+DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(0)
+DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(1)
+DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(2)
+DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(3)
+DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(4)
+DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(5)
+DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(6)
+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)
diff --git a/lib/asan/asan_fake_stack.h b/lib/asan/asan_fake_stack.h
index 308b4c571832..f17ee0268917 100644
--- a/lib/asan/asan_fake_stack.h
+++ b/lib/asan/asan_fake_stack.h
@@ -9,12 +9,14 @@
//
// This file is a part of AddressSanitizer, an address sanity checker.
//
-// ASan-private header for asan_fake_stack.cc
+// ASan-private header for asan_fake_stack.cc, implements FakeStack.
//===----------------------------------------------------------------------===//
#ifndef ASAN_FAKE_STACK_H
#define ASAN_FAKE_STACK_H
+#include "sanitizer_common/sanitizer_common.h"
+
namespace __asan {
// Fake stack frame contains local variables of one function.
@@ -22,96 +24,148 @@ struct FakeFrame {
uptr magic; // Modified by the instrumented code.
uptr descr; // Modified by the instrumented code.
uptr pc; // Modified by the instrumented code.
- u64 real_stack : 48;
- u64 size_minus_one : 16;
- // End of the first 32 bytes.
- // The rest should not be used when the frame is active.
- FakeFrame *next;
-};
-
-struct FakeFrameFifo {
- public:
- void FifoPush(FakeFrame *node);
- FakeFrame *FifoPop();
- private:
- FakeFrame *first_, *last_;
-};
-
-template<uptr kMaxNumberOfFrames>
-class FakeFrameLifo {
- public:
- explicit FakeFrameLifo(LinkerInitialized) {}
- FakeFrameLifo() : n_frames_(0) {}
- void LifoPush(FakeFrame *node) {
- CHECK_LT(n_frames_, kMaxNumberOfFrames);
- frames_[n_frames_++] = node;
- }
- void LifoPop() {
- CHECK(n_frames_);
- n_frames_--;
- }
- FakeFrame *top() {
- if (n_frames_ == 0)
- return 0;
- return frames_[n_frames_ - 1];
- }
- private:
- uptr n_frames_;
- FakeFrame *frames_[kMaxNumberOfFrames];
+ uptr real_stack;
};
// For each thread we create a fake stack and place stack objects on this fake
// stack instead of the real stack. The fake stack is not really a stack but
// a fast malloc-like allocator so that when a function exits the fake stack
-// is not poped but remains there for quite some time until gets used again.
+// is not popped but remains there for quite some time until gets used again.
// So, we poison the objects on the fake stack when function returns.
// It helps us find use-after-return bugs.
-// We can not rely on __asan_stack_free being called on every function exit,
-// so we maintain a lifo list of all current fake frames and update it on every
-// call to __asan_stack_malloc.
+//
+// The FakeStack objects is allocated by a single mmap call and has no other
+// pointers. The size of the fake stack depends on the actual thread stack size
+// and thus can not be a constant.
+// stack_size is a power of two greater or equal to the thread's stack size;
+// we store it as its logarithm (stack_size_log).
+// FakeStack has kNumberOfSizeClasses (11) size classes, each size class
+// is a power of two, starting from 64 bytes. Each size class occupies
+// stack_size bytes and thus can allocate
+// NumberOfFrames=(stack_size/BytesInSizeClass) fake frames (also a power of 2).
+// For each size class we have NumberOfFrames allocation flags,
+// each flag indicates whether the given frame is currently allocated.
+// All flags for size classes 0 .. 10 are stored in a single contiguous region
+// followed by another contiguous region which contains the actual memory for
+// size classes. The addresses are computed by GetFlags and GetFrame without
+// any memory accesses solely based on 'this' and stack_size_log.
+// Allocate() flips the appropriate allocation flag atomically, thus achieving
+// async-signal safety.
+// This allocator does not have quarantine per se, but it tries to allocate the
+// frames in round robin fasion to maximize the delay between a deallocation
+// and the next allocation.
class FakeStack {
- public:
- FakeStack();
- explicit FakeStack(LinkerInitialized x) : call_stack_(x) {}
- void Init(uptr stack_size);
- void StopUsingFakeStack() { alive_ = false; }
- void Cleanup();
- uptr AllocateStack(uptr size, uptr real_stack);
- static void OnFree(uptr ptr, uptr size, uptr real_stack);
- // Return the bottom of the maped region.
- uptr AddrIsInFakeStack(uptr addr);
- bool StackSize() { return stack_size_; }
-
- private:
- static const uptr kMinStackFrameSizeLog = 9; // Min frame is 512B.
+ static const uptr kMinStackFrameSizeLog = 6; // Min frame is 64B.
static const uptr kMaxStackFrameSizeLog = 16; // Max stack frame is 64K.
- static const uptr kMaxStackMallocSize = 1 << kMaxStackFrameSizeLog;
+
+ public:
static const uptr kNumberOfSizeClasses =
- kMaxStackFrameSizeLog - kMinStackFrameSizeLog + 1;
- static const uptr kMaxRecursionDepth = 1023;
+ kMaxStackFrameSizeLog - kMinStackFrameSizeLog + 1;
+
+ // CTOR: create the FakeStack as a single mmap-ed object.
+ static FakeStack *Create(uptr stack_size_log);
+
+ void Destroy();
+
+ // stack_size_log is at least 15 (stack_size >= 32K).
+ static uptr SizeRequiredForFlags(uptr stack_size_log) {
+ return 1UL << (stack_size_log + 1 - kMinStackFrameSizeLog);
+ }
- bool AddrIsInSizeClass(uptr addr, uptr size_class);
+ // Each size class occupies stack_size bytes.
+ static uptr SizeRequiredForFrames(uptr stack_size_log) {
+ return (1ULL << stack_size_log) * kNumberOfSizeClasses;
+ }
+
+ // Number of bytes requires for the whole object.
+ static uptr RequiredSize(uptr stack_size_log) {
+ return kFlagsOffset + SizeRequiredForFlags(stack_size_log) +
+ SizeRequiredForFrames(stack_size_log);
+ }
+
+ // Offset of the given flag from the first flag.
+ // The flags for class 0 begin at offset 000000000
+ // The flags for class 1 begin at offset 100000000
+ // ....................2................ 110000000
+ // ....................3................ 111000000
+ // and so on.
+ static uptr FlagsOffset(uptr stack_size_log, uptr class_id) {
+ uptr t = kNumberOfSizeClasses - 1 - class_id;
+ const uptr all_ones = (1 << (kNumberOfSizeClasses - 1)) - 1;
+ return ((all_ones >> t) << t) << (stack_size_log - 15);
+ }
+
+ static uptr NumberOfFrames(uptr stack_size_log, uptr class_id) {
+ return 1UL << (stack_size_log - kMinStackFrameSizeLog - class_id);
+ }
+
+ // Divide n by the numbe of frames in size class.
+ static uptr ModuloNumberOfFrames(uptr stack_size_log, uptr class_id, uptr n) {
+ return n & (NumberOfFrames(stack_size_log, class_id) - 1);
+ }
+
+ // The the pointer to the flags of the given class_id.
+ u8 *GetFlags(uptr stack_size_log, uptr class_id) {
+ return reinterpret_cast<u8 *>(this) + kFlagsOffset +
+ FlagsOffset(stack_size_log, class_id);
+ }
+
+ // Get frame by class_id and pos.
+ u8 *GetFrame(uptr stack_size_log, uptr class_id, uptr pos) {
+ return reinterpret_cast<u8 *>(this) + kFlagsOffset +
+ SizeRequiredForFlags(stack_size_log) +
+ (1 << stack_size_log) * class_id + BytesInSizeClass(class_id) * pos;
+ }
+
+ // Allocate the fake frame.
+ FakeFrame *Allocate(uptr stack_size_log, uptr class_id, uptr real_stack);
+
+ // Deallocate the fake frame: read the saved flag address and write 0 there.
+ static void Deallocate(uptr x, uptr class_id) {
+ **SavedFlagPtr(x, class_id) = 0;
+ }
+
+ // Poison the entire FakeStack's shadow with the magic value.
+ void PoisonAll(u8 magic);
+
+ // Return the beginning of the FakeFrame or 0 if the address is not ours.
+ uptr AddrIsInFakeStack(uptr addr);
- // Each size class should be large enough to hold all frames.
- uptr ClassMmapSize(uptr size_class);
+ // Number of bytes in a fake frame of this size class.
+ static uptr BytesInSizeClass(uptr class_id) {
+ return 1UL << (class_id + kMinStackFrameSizeLog);
+ }
- uptr ClassSize(uptr size_class) {
- return 1UL << (size_class + kMinStackFrameSizeLog);
+ // The fake frame is guaranteed to have a right redzone.
+ // We use the last word of that redzone to store the address of the flag
+ // that corresponds to the current frame to make faster deallocation.
+ static u8 **SavedFlagPtr(uptr x, uptr class_id) {
+ return reinterpret_cast<u8 **>(x + BytesInSizeClass(class_id) - sizeof(x));
}
- void DeallocateFrame(FakeFrame *fake_frame);
+ uptr stack_size_log() const { return stack_size_log_; }
+
+ void HandleNoReturn();
+ void GC(uptr real_stack);
- uptr ComputeSizeClass(uptr alloc_size);
- void AllocateOneSizeClass(uptr size_class);
+ void ForEachFakeFrame(RangeIteratorCallback callback, void *arg);
- uptr stack_size_;
- bool alive_;
+ private:
+ FakeStack() { }
+ static const uptr kFlagsOffset = 4096; // This is were the flags begin.
+ // Must match the number of uses of DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID
+ COMPILER_CHECK(kNumberOfSizeClasses == 11);
+ static const uptr kMaxStackMallocSize = 1 << kMaxStackFrameSizeLog;
- uptr allocated_size_classes_[kNumberOfSizeClasses];
- FakeFrameFifo size_classes_[kNumberOfSizeClasses];
- FakeFrameLifo<kMaxRecursionDepth> call_stack_;
+ uptr hint_position_[kNumberOfSizeClasses];
+ uptr stack_size_log_;
+ // a bit is set if something was allocated from the corresponding size class.
+ bool needs_gc_;
};
+FakeStack *GetTLSFakeStack();
+void SetTLSFakeStack(FakeStack *fs);
+
} // namespace __asan
#endif // ASAN_FAKE_STACK_H
diff --git a/lib/asan/asan_flags.h b/lib/asan/asan_flags.h
index 2f3bc9051ae1..89662f28b29c 100644
--- a/lib/asan/asan_flags.h
+++ b/lib/asan/asan_flags.h
@@ -32,8 +32,6 @@ struct Flags {
// Lower value may reduce memory usage but increase the chance of
// false negatives.
int quarantine_size;
- // Verbosity level (0 - silent, 1 - a bit of output, 2+ - more output).
- int verbosity;
// Size (in bytes) of redzones around heap objects.
// Requirement: redzone >= 32, is a power of two.
int redzone;
@@ -52,8 +50,10 @@ struct Flags {
bool replace_intrin;
// Used on Mac only.
bool mac_ignore_invalid_free;
- // ASan allocator flag.
- bool use_fake_stack;
+ // 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 max_malloc_fill_size, malloc_fill_byte;
@@ -83,6 +83,9 @@ struct Flags {
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;
@@ -93,23 +96,20 @@ struct Flags {
// but also thread creation stacks for threads that created those threads,
// etc. up to main thread.
bool print_full_thread_history;
- // ASan will write logs to "log_path.pid" instead of stderr.
- const char *log_path;
// 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 alloc_dealloc_mismatch;
- // Use stack depot instead of storing stacks in the redzones.
- bool use_stack_depot;
// If true, assume that memcmp(p1, p2, n) always reads n bytes before
// comparing p1 and p2.
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;
- // Invoke LeakSanitizer at process exit.
- bool detect_leaks;
};
extern Flags asan_flags_dont_use_directly;
diff --git a/lib/asan/asan_globals.cc b/lib/asan/asan_globals.cc
index 301ea44f2ca5..81699676b574 100644
--- a/lib/asan/asan_globals.cc
+++ b/lib/asan/asan_globals.cc
@@ -41,7 +41,7 @@ struct DynInitGlobal {
Global g;
bool initialized;
};
-typedef InternalVector<DynInitGlobal> VectorOfGlobals;
+typedef InternalMmapVector<DynInitGlobal> VectorOfGlobals;
// Lazy-initialized and never deleted.
static VectorOfGlobals *dynamic_init_globals;
@@ -94,15 +94,13 @@ static void RegisterGlobal(const Global *g) {
CHECK(AddrIsAlignedByGranularity(g->size_with_redzone));
if (flags()->poison_heap)
PoisonRedZones(*g);
- ListOfGlobals *l =
- (ListOfGlobals*)allocator_for_globals.Allocate(sizeof(ListOfGlobals));
+ ListOfGlobals *l = new(allocator_for_globals) ListOfGlobals;
l->g = g;
l->next = list_of_all_globals;
list_of_all_globals = l;
if (g->has_dynamic_init) {
if (dynamic_init_globals == 0) {
- void *mem = allocator_for_globals.Allocate(sizeof(VectorOfGlobals));
- dynamic_init_globals = new(mem)
+ dynamic_init_globals = new(allocator_for_globals)
VectorOfGlobals(kDynamicInitGlobalsInitialCapacity);
}
DynInitGlobal dyn_global = { *g, false };
diff --git a/lib/asan/asan_intercepted_functions.h b/lib/asan/asan_intercepted_functions.h
index 842781cdb17f..de42cd6d5ca6 100644
--- a/lib/asan/asan_intercepted_functions.h
+++ b/lib/asan/asan_intercepted_functions.h
@@ -14,15 +14,8 @@
#ifndef ASAN_INTERCEPTED_FUNCTIONS_H
#define ASAN_INTERCEPTED_FUNCTIONS_H
-#include "asan_internal.h"
-#include "interception/interception.h"
#include "sanitizer_common/sanitizer_platform_interceptors.h"
-#include <stdarg.h>
-#include <stddef.h>
-
-using __sanitizer::uptr;
-
// Use macro to describe if specific function should be
// intercepted on a given platform.
#if !SANITIZER_WINDOWS
@@ -83,32 +76,4 @@ using __sanitizer::uptr;
# define ASAN_INTERCEPT___CXA_ATEXIT 0
#endif
-# if SANITIZER_WINDOWS
-extern "C" {
-// Windows threads.
-__declspec(dllimport)
-void* __stdcall CreateThread(void *sec, uptr st, void* start,
- void *arg, DWORD fl, DWORD *id);
-
-int memcmp(const void *a1, const void *a2, uptr size);
-void memmove(void *to, const void *from, uptr size);
-void* memset(void *block, int c, uptr size);
-void* memcpy(void *to, const void *from, uptr size);
-char* strcat(char *to, const char* from); // NOLINT
-char* strchr(const char *str, int c);
-int strcmp(const char *s1, const char* s2);
-char* strcpy(char *to, const char* from); // NOLINT
-uptr strlen(const char *s);
-char* strncat(char *to, const char* from, uptr size);
-int strncmp(const char *s1, const char* s2, uptr size);
-char* strncpy(char *to, const char* from, uptr size);
-uptr strnlen(const char *s, uptr maxlen);
-int atoi(const char *nptr);
-long atol(const char *nptr); // NOLINT
-long strtol(const char *nptr, char **endptr, int base); // NOLINT
-void longjmp(void *env, int value);
-double frexp(double x, int *expptr);
-}
-# endif
-
#endif // ASAN_INTERCEPTED_FUNCTIONS_H
diff --git a/lib/asan/asan_interceptors.cc b/lib/asan/asan_interceptors.cc
index 7e7deea29634..a25827b6b9ae 100644
--- a/lib/asan/asan_interceptors.cc
+++ b/lib/asan/asan_interceptors.cc
@@ -53,7 +53,7 @@ static inline bool QuickCheckForUnpoisonedRegion(uptr beg, uptr 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_WRITE_RANGE(offset, size) ACCESS_MEMORY_RANGE(offset, size, true)
// Behavior of functions like "memcpy" or "strcpy" is undefined
// if memory intervals overlap. We report error in this case.
@@ -94,9 +94,9 @@ void SetThreadName(const char *name) {
asanThreadRegistry().SetThreadName(t->tid(), name);
}
-static void DisableStrictInitOrderChecker() {
- if (flags()->strict_init_order)
- flags()->check_initialization_order = false;
+int OnExit() {
+ // FIXME: ask frontend whether we need to return failure.
+ return 0;
}
} // namespace __asan
@@ -104,26 +104,69 @@ static void DisableStrictInitOrderChecker() {
// ---------------------- Wrappers ---------------- {{{1
using namespace __asan; // NOLINT
+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"); \
+ } while (0)
+#else
+// OS X interceptors don't need to be initialized with INTERCEPT_FUNCTION.
+#define ASAN_INTERCEPT_FUNC(name)
+#endif // SANITIZER_MAC
+
+#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; \
- ENSURE_ASAN_INITED(); \
+#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(); \
+ } while (false)
+#define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd) \
+ do { \
+ } while (false)
+#define COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd) \
+ do { \
+ } while (false)
+#define COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, newfd) \
+ do { \
} while (false)
-#define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd) do { } while (false)
-#define COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd) do { } while (false)
#define COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, name) SetThreadName(name)
+// Should be asanThreadRegistry().SetThreadNameByUserId(thread, name)
+// But asan does not remember UserId's for threads (pthread_t);
+// and remembers all ever existed threads, so the linear search by UserId
+// can be slow.
+#define COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name) \
+ do { \
+ } while (false)
+#define COMMON_INTERCEPTOR_BLOCK_REAL(name) REAL(name)
+#define COMMON_INTERCEPTOR_ON_EXIT(ctx) OnExit()
#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)
-#define COMMON_SYSCALL_POST_READ_RANGE(p, s)
-#define COMMON_SYSCALL_POST_WRITE_RANGE(p, s)
+#define COMMON_SYSCALL_POST_READ_RANGE(p, s) \
+ do { \
+ (void)(p); \
+ (void)(s); \
+ } while (false)
+#define COMMON_SYSCALL_POST_WRITE_RANGE(p, s) \
+ do { \
+ (void)(p); \
+ (void)(s); \
+ } while (false)
#include "sanitizer_common/sanitizer_common_syscalls.inc"
static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) {
@@ -133,16 +176,16 @@ static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) {
}
#if ASAN_INTERCEPT_PTHREAD_CREATE
-extern "C" int pthread_attr_getdetachstate(void *attr, int *v);
-
INTERCEPTOR(int, pthread_create, void *thread,
void *attr, void *(*start_routine)(void*), void *arg) {
+ EnsureMainThreadIDIsCorrect();
// Strict init-order checking in thread-hostile.
- DisableStrictInitOrderChecker();
+ if (flags()->strict_init_order)
+ StopInitOrderChecking();
GET_STACK_TRACE_THREAD;
int detached = 0;
if (attr != 0)
- pthread_attr_getdetachstate(attr, &detached);
+ REAL(pthread_attr_getdetachstate)(attr, &detached);
u32 current_tid = GetCurrentTidOrInvalid();
AsanThread *t = AsanThread::Create(start_routine, arg);
@@ -170,7 +213,7 @@ INTERCEPTOR(int, sigaction, int signum, const struct sigaction *act,
#elif SANITIZER_POSIX
// We need to have defined REAL(sigaction) on posix systems.
DEFINE_REAL(int, sigaction, int signum, const struct sigaction *act,
- struct sigaction *oldact);
+ struct sigaction *oldact)
#endif // ASAN_INTERCEPT_SIGNAL_AND_SIGACTION
#if ASAN_INTERCEPT_SWAPCONTEXT
@@ -240,13 +283,15 @@ INTERCEPTOR(void, __cxa_throw, void *a, void *b, void *c) {
// Since asan maps 16T of RAM, mlock is completely unfriendly to asan.
// All functions return 0 (success).
static void MlockIsUnsupported() {
- static bool printed = 0;
+ static bool printed = false;
if (printed) return;
printed = true;
- Printf("INFO: AddressSanitizer ignores mlock/mlockall/munlock/munlockall\n");
+ if (common_flags()->verbosity > 0) {
+ Printf("INFO: AddressSanitizer ignores "
+ "mlock/mlockall/munlock/munlockall\n");
+ }
}
-extern "C" {
INTERCEPTOR(int, mlock, const void *addr, uptr len) {
MlockIsUnsupported();
return 0;
@@ -266,7 +311,6 @@ INTERCEPTOR(int, munlockall, void) {
MlockIsUnsupported();
return 0;
}
-} // extern "C"
static inline int CharCmp(unsigned char c1, unsigned char c2) {
return (c1 == c2) ? 0 : (c1 < c2) ? -1 : 1;
@@ -300,7 +344,23 @@ INTERCEPTOR(int, memcmp, const void *a1, const void *a2, uptr size) {
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); \
+}
+
+INTERCEPTOR(void*, memmove, void *to, const void *from, uptr size) MEMMOVE_BODY
+
INTERCEPTOR(void*, memcpy, void *to, const void *from, uptr size) {
+#if !SANITIZER_MAC
if (!asan_inited) return internal_memcpy(to, from, size);
// memcpy is called during __asan_init() from the internals
// of printf(...).
@@ -317,24 +377,19 @@ INTERCEPTOR(void*, memcpy, void *to, const void *from, uptr 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.
+ // 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);
-}
-
-INTERCEPTOR(void*, memmove, void *to, const void *from, uptr size) {
- 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);
- }
- // Interposing of resolver functions is broken on Mac OS 10.7 and 10.8.
- // See also http://code.google.com/p/address-sanitizer/issues/detail?id=116.
- return internal_memmove(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()
+ // calls. If we just disable error reporting with
+ // 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
+#endif // !SANITIZER_MAC
}
INTERCEPTOR(void*, memset, void *block, int c, uptr size) {
@@ -375,7 +430,7 @@ INTERCEPTOR(char*, index, const char *string, int c)
DECLARE_REAL(char*, index, const char *string, int c)
OVERRIDE_FUNCTION(index, strchr);
# else
-DEFINE_REAL(char*, index, const char *string, int c);
+DEFINE_REAL(char*, index, const char *string, int c)
# endif
# endif
#endif // ASAN_INTERCEPT_INDEX
@@ -418,24 +473,6 @@ INTERCEPTOR(char*, strncat, char *to, const char *from, uptr size) {
return REAL(strncat)(to, from, size);
}
-INTERCEPTOR(int, strcmp, const char *s1, const char *s2) {
- if (!asan_inited) return internal_strcmp(s1, s2);
- if (asan_init_is_running) {
- return REAL(strcmp)(s1, s2);
- }
- ENSURE_ASAN_INITED();
- unsigned char c1, c2;
- uptr i;
- for (i = 0; ; i++) {
- c1 = (unsigned char)s1[i];
- c2 = (unsigned char)s2[i];
- if (c1 != c2 || c1 == '\0') break;
- }
- ASAN_READ_RANGE(s1, i + 1);
- ASAN_READ_RANGE(s2, i + 1);
- return CharCmp(c1, c2);
-}
-
INTERCEPTOR(char*, strcpy, char *to, const char *from) { // NOLINT
#if SANITIZER_MAC
if (!asan_inited) return REAL(strcpy)(to, from); // NOLINT
@@ -457,21 +494,16 @@ INTERCEPTOR(char*, strcpy, char *to, const char *from) { // NOLINT
#if ASAN_INTERCEPT_STRDUP
INTERCEPTOR(char*, strdup, const char *s) {
-#if SANITIZER_MAC
- // FIXME: because internal_strdup() uses InternalAlloc(), which currently
- // just calls malloc() on Mac, we can't use internal_strdup() with the
- // dynamic runtime. We can remove the call to REAL(strdup) once InternalAlloc
- // starts using mmap() instead.
- // See also http://code.google.com/p/address-sanitizer/issues/detail?id=123.
- if (!asan_inited) return REAL(strdup)(s);
-#endif
if (!asan_inited) return internal_strdup(s);
ENSURE_ASAN_INITED();
+ uptr length = REAL(strlen)(s);
if (flags()->replace_str) {
- uptr length = REAL(strlen)(s);
ASAN_READ_RANGE(s, length + 1);
}
- return REAL(strdup)(s);
+ GET_STACK_TRACE_MALLOC;
+ void *new_mem = asan_malloc(length + 1, &stack);
+ REAL(memcpy)(new_mem, s, length + 1);
+ return reinterpret_cast<char*>(new_mem);
}
#endif
@@ -490,24 +522,13 @@ INTERCEPTOR(uptr, strlen, const char *s) {
return length;
}
-INTERCEPTOR(int, strncmp, const char *s1, const char *s2, uptr size) {
- if (!asan_inited) return internal_strncmp(s1, s2, size);
- // strncmp is called from malloc_default_purgeable_zone()
- // in __asan::ReplaceSystemAlloc() on Mac.
- if (asan_init_is_running) {
- return REAL(strncmp)(s1, s2, size);
+INTERCEPTOR(uptr, wcslen, const wchar_t *s) {
+ uptr length = REAL(wcslen)(s);
+ if (!asan_init_is_running) {
+ ENSURE_ASAN_INITED();
+ ASAN_READ_RANGE(s, (length + 1) * sizeof(wchar_t));
}
- ENSURE_ASAN_INITED();
- unsigned char c1 = 0, c2 = 0;
- uptr i;
- for (i = 0; i < size; i++) {
- c1 = (unsigned char)s1[i];
- c2 = (unsigned char)s2[i];
- if (c1 != c2 || c1 == '\0') break;
- }
- ASAN_READ_RANGE(s1, Min(i + 1, size));
- ASAN_READ_RANGE(s2, Min(i + 1, size));
- return CharCmp(c1, c2);
+ return length;
}
INTERCEPTOR(char*, strncpy, char *to, const char *from, uptr size) {
@@ -644,6 +665,9 @@ static void AtCxaAtexit(void *unused) {
#if ASAN_INTERCEPT___CXA_ATEXIT
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);
+#endif
ENSURE_ASAN_INITED();
int res = REAL(__cxa_atexit)(func, arg, dso_handle);
REAL(__cxa_atexit)(AtCxaAtexit, 0, 0);
@@ -651,26 +675,22 @@ INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg,
}
#endif // ASAN_INTERCEPT___CXA_ATEXIT
-#define ASAN_INTERCEPT_FUNC(name) do { \
- if (!INTERCEPT_FUNCTION(name) && flags()->verbosity > 0) \
- Report("AddressSanitizer: failed to intercept '" #name "'\n"); \
- } while (0)
-
#if SANITIZER_WINDOWS
INTERCEPTOR_WINAPI(DWORD, CreateThread,
void* security, uptr stack_size,
DWORD (__stdcall *start_routine)(void*), void* arg,
- DWORD flags, void* tid) {
+ DWORD thr_flags, void* tid) {
// Strict init-order checking in thread-hostile.
- DisableStrictInitOrderChecker();
+ 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 };
- int detached = 0; // FIXME: how can we determine it on Windows?
+ 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, flags, tid);
+ asan_thread_start, t, thr_flags, tid);
}
namespace __asan {
@@ -687,9 +707,6 @@ void InitializeAsanInterceptors() {
static bool was_called_once;
CHECK(was_called_once == false);
was_called_once = true;
-#if SANITIZER_MAC
- return;
-#else
SANITIZER_COMMON_INTERCEPTORS_INIT;
// Intercept mem* functions.
@@ -703,11 +720,10 @@ void InitializeAsanInterceptors() {
// Intercept str* functions.
ASAN_INTERCEPT_FUNC(strcat); // NOLINT
ASAN_INTERCEPT_FUNC(strchr);
- ASAN_INTERCEPT_FUNC(strcmp);
ASAN_INTERCEPT_FUNC(strcpy); // NOLINT
ASAN_INTERCEPT_FUNC(strlen);
+ ASAN_INTERCEPT_FUNC(wcslen);
ASAN_INTERCEPT_FUNC(strncat);
- ASAN_INTERCEPT_FUNC(strncmp);
ASAN_INTERCEPT_FUNC(strncpy);
#if ASAN_INTERCEPT_STRDUP
ASAN_INTERCEPT_FUNC(strdup);
@@ -771,10 +787,9 @@ void InitializeAsanInterceptors() {
InitializeWindowsInterceptors();
#endif
- if (flags()->verbosity > 0) {
+ if (common_flags()->verbosity > 0) {
Report("AddressSanitizer: libc interceptors initialized\n");
}
-#endif // SANITIZER_MAC
}
} // namespace __asan
diff --git a/lib/asan/asan_interface_internal.h b/lib/asan/asan_interface_internal.h
index 24f76253bccd..5c1d025296fb 100644
--- a/lib/asan/asan_interface_internal.h
+++ b/lib/asan/asan_interface_internal.h
@@ -30,7 +30,7 @@ extern "C" {
// v2=>v3: stack frame description (created by the compiler)
// contains the function PC as the 3-rd field (see
// DescribeAddressIfStack).
- void __asan_init_v3() SANITIZER_INTERFACE_ATTRIBUTE;
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_init_v3();
#define __asan_init __asan_init_v3
// This structure describes an instrumented global variable.
@@ -46,96 +46,85 @@ extern "C" {
// These two functions should be called by the instrumented code.
// 'globals' is an array of structures describing 'n' globals.
- void __asan_register_globals(__asan_global *globals, uptr n)
- SANITIZER_INTERFACE_ATTRIBUTE;
- void __asan_unregister_globals(__asan_global *globals, uptr n)
- SANITIZER_INTERFACE_ATTRIBUTE;
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __asan_register_globals(__asan_global *globals, uptr n);
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __asan_unregister_globals(__asan_global *globals, uptr n);
// These two functions should be called before and after dynamic initializers
// of a single module run, respectively.
- void __asan_before_dynamic_init(const char *module_name)
- SANITIZER_INTERFACE_ATTRIBUTE;
- void __asan_after_dynamic_init()
- SANITIZER_INTERFACE_ATTRIBUTE;
-
- // These two functions are used by the instrumented code in the
- // use-after-return mode. __asan_stack_malloc allocates size bytes of
- // fake stack and __asan_stack_free poisons it. real_stack is a pointer to
- // the real stack region.
- uptr __asan_stack_malloc(uptr size, uptr real_stack)
- SANITIZER_INTERFACE_ATTRIBUTE;
- void __asan_stack_free(uptr ptr, uptr size, uptr real_stack)
- SANITIZER_INTERFACE_ATTRIBUTE;
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __asan_before_dynamic_init(const char *module_name);
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __asan_after_dynamic_init();
// These two functions are used by instrumented code in the
// use-after-scope mode. They mark memory for local variables as
// unaddressable when they leave scope and addressable before the
// function exits.
- void __asan_poison_stack_memory(uptr addr, uptr size)
- SANITIZER_INTERFACE_ATTRIBUTE;
- void __asan_unpoison_stack_memory(uptr addr, uptr size)
- SANITIZER_INTERFACE_ATTRIBUTE;
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __asan_poison_stack_memory(uptr addr, uptr size);
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __asan_unpoison_stack_memory(uptr addr, uptr size);
// Performs cleanup before a NoReturn function. Must be called before things
// like _exit and execl to avoid false positives on stack.
- void __asan_handle_no_return() SANITIZER_INTERFACE_ATTRIBUTE;
+ SANITIZER_INTERFACE_ATTRIBUTE void __asan_handle_no_return();
- void __asan_poison_memory_region(void const volatile *addr, uptr size)
- SANITIZER_INTERFACE_ATTRIBUTE;
- void __asan_unpoison_memory_region(void const volatile *addr, uptr size)
- SANITIZER_INTERFACE_ATTRIBUTE;
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __asan_poison_memory_region(void const volatile *addr, uptr size);
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __asan_unpoison_memory_region(void const volatile *addr, uptr size);
- bool __asan_address_is_poisoned(void const volatile *addr)
- SANITIZER_INTERFACE_ATTRIBUTE;
+ SANITIZER_INTERFACE_ATTRIBUTE
+ bool __asan_address_is_poisoned(void const volatile *addr);
- uptr __asan_region_is_poisoned(uptr beg, uptr size)
- SANITIZER_INTERFACE_ATTRIBUTE;
+ SANITIZER_INTERFACE_ATTRIBUTE
+ uptr __asan_region_is_poisoned(uptr beg, uptr size);
- void __asan_describe_address(uptr addr)
- SANITIZER_INTERFACE_ATTRIBUTE;
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __asan_describe_address(uptr addr);
+ SANITIZER_INTERFACE_ATTRIBUTE
void __asan_report_error(uptr pc, uptr bp, uptr sp,
- uptr addr, bool is_write, uptr access_size)
- SANITIZER_INTERFACE_ATTRIBUTE;
+ uptr addr, bool is_write, uptr access_size);
- int __asan_set_error_exit_code(int exit_code)
- SANITIZER_INTERFACE_ATTRIBUTE;
- void __asan_set_death_callback(void (*callback)(void))
- SANITIZER_INTERFACE_ATTRIBUTE;
- void __asan_set_error_report_callback(void (*callback)(const char*))
- SANITIZER_INTERFACE_ATTRIBUTE;
+ SANITIZER_INTERFACE_ATTRIBUTE
+ int __asan_set_error_exit_code(int exit_code);
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __asan_set_death_callback(void (*callback)(void));
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __asan_set_error_report_callback(void (*callback)(const char*));
- /* OPTIONAL */ void __asan_on_error()
- SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
+ 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_WEAK_ATTRIBUTE 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;
-
- /* OPTIONAL */ const char* __asan_default_options()
- SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
-
- /* OPTIONAL */ void __asan_malloc_hook(void *ptr, uptr size)
- SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
- /* OPTIONAL */ void __asan_free_hook(void *ptr)
- SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
+ 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;
} // extern "C"
#endif // ASAN_INTERFACE_INTERNAL_H
diff --git a/lib/asan/asan_internal.h b/lib/asan/asan_internal.h
index 7a4d74472bcd..70e55ea0afef 100644
--- a/lib/asan/asan_internal.h
+++ b/lib/asan/asan_internal.h
@@ -98,6 +98,7 @@ void StopInitOrderChecking();
void AsanTSDInit(void (*destructor)(void *tsd));
void *AsanTSDGet();
void AsanTSDSet(void *tsd);
+void PlatformTSDDtor(void *tsd);
void AppendToErrorMessageBuffer(const char *buffer);
diff --git a/lib/asan/asan_linux.cc b/lib/asan/asan_linux.cc
index 17bb4ca5f01c..39eec3bfd301 100644
--- a/lib/asan/asan_linux.cc
+++ b/lib/asan/asan_linux.cc
@@ -58,6 +58,12 @@ void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
*pc = ucontext->uc_mcontext.arm_pc;
*bp = ucontext->uc_mcontext.arm_fp;
*sp = ucontext->uc_mcontext.arm_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__)
ucontext_t *ucontext = (ucontext_t*)context;
*pc = ucontext->uc_mcontext.gregs[REG_RIP];
@@ -89,6 +95,11 @@ void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
stk_ptr = (uptr *) *sp;
*bp = stk_ptr[15];
# endif
+# elif defined(__mips__)
+ ucontext_t *ucontext = (ucontext_t*)context;
+ *pc = ucontext->uc_mcontext.gregs[31];
+ *bp = ucontext->uc_mcontext.gregs[30];
+ *sp = ucontext->uc_mcontext.gregs[29];
#else
# error "Unsupported arch"
#endif
diff --git a/lib/asan/asan_mac.cc b/lib/asan/asan_mac.cc
index 4313534008e7..e27d70adb81e 100644
--- a/lib/asan/asan_mac.cc
+++ b/lib/asan/asan_mac.cc
@@ -21,6 +21,7 @@
#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 <crt_externs.h> // for _NSGetArgv
@@ -52,7 +53,9 @@ void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
# endif // SANITIZER_WORDSIZE
}
-int GetMacosVersion() {
+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]);
@@ -68,6 +71,7 @@ int GetMacosVersion() {
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;
}
}
@@ -75,6 +79,18 @@ int GetMacosVersion() {
}
}
+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
// into memmove$VARIANT$sse42.
@@ -158,7 +174,7 @@ void MaybeReexec() {
// Set DYLD_INSERT_LIBRARIES equal to the runtime dylib name.
setenv(kDyldInsertLibraries, info.dli_fname, /*overwrite*/0);
}
- if (flags()->verbosity >= 1) {
+ 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");
@@ -295,7 +311,7 @@ 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 (flags()->verbosity >= 2) {
+ if (common_flags()->verbosity >= 2) {
Report("asan_dispatch_call_block_and_release(): "
"context: %p, pthread_self: %p\n",
block, pthread_self());
@@ -330,7 +346,7 @@ asan_block_context_t *alloc_asan_context(void *ctxt, dispatch_function_t func,
dispatch_function_t func) { \
GET_STACK_TRACE_THREAD; \
asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack); \
- if (flags()->verbosity >= 2) { \
+ if (common_flags()->verbosity >= 2) { \
Report(#dispatch_x_f "(): context: %p, pthread_self: %p\n", \
asan_ctxt, pthread_self()); \
PRINT_CURRENT_STACK(); \
@@ -348,7 +364,7 @@ INTERCEPTOR(void, dispatch_after_f, dispatch_time_t when,
dispatch_function_t func) {
GET_STACK_TRACE_THREAD;
asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack);
- if (flags()->verbosity >= 2) {
+ if (common_flags()->verbosity >= 2) {
Report("dispatch_after_f: %p\n", asan_ctxt);
PRINT_CURRENT_STACK();
}
@@ -361,7 +377,7 @@ INTERCEPTOR(void, dispatch_group_async_f, dispatch_group_t group,
dispatch_function_t func) {
GET_STACK_TRACE_THREAD;
asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack);
- if (flags()->verbosity >= 2) {
+ if (common_flags()->verbosity >= 2) {
Report("dispatch_group_async_f(): context: %p, pthread_self: %p\n",
asan_ctxt, pthread_self());
PRINT_CURRENT_STACK();
diff --git a/lib/asan/asan_mac.h b/lib/asan/asan_mac.h
index b1a1966dbc6e..827b8b001699 100644
--- a/lib/asan/asan_mac.h
+++ b/lib/asan/asan_mac.h
@@ -12,7 +12,7 @@
// Mac-specific ASan definitions.
//===----------------------------------------------------------------------===//
#ifndef ASAN_MAC_H
-#define 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
@@ -36,12 +36,14 @@ typedef struct __CFRuntimeBase {
#endif
} CFRuntimeBase;
-enum {
- MACOS_VERSION_UNKNOWN = 0,
+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_MOUNTAIN_LION,
+ MACOS_VERSION_MAVERICKS
};
// Used by asan_malloc_mac.cc and asan_mac.cc
@@ -49,7 +51,7 @@ extern "C" void __CFInitialize();
namespace __asan {
-int GetMacosVersion();
+MacosVersion GetMacosVersion();
void MaybeReplaceCFAllocator();
} // namespace __asan
diff --git a/lib/asan/asan_malloc_linux.cc b/lib/asan/asan_malloc_linux.cc
index 20e636b9b3c0..24b7f6977927 100644
--- a/lib/asan/asan_malloc_linux.cc
+++ b/lib/asan/asan_malloc_linux.cc
@@ -105,8 +105,9 @@ INTERCEPTOR(void*, __libc_memalign, uptr align, uptr s)
ALIAS("memalign");
INTERCEPTOR(uptr, malloc_usable_size, void *ptr) {
- GET_STACK_TRACE_MALLOC;
- return asan_malloc_usable_size(ptr, &stack);
+ GET_CURRENT_PC_BP_SP;
+ (void)sp;
+ return asan_malloc_usable_size(ptr, pc, bp);
}
// We avoid including malloc.h for portability reasons.
diff --git a/lib/asan/asan_malloc_mac.cc b/lib/asan/asan_malloc_mac.cc
index 4f353cb99ca7..f9f08f0201c2 100644
--- a/lib/asan/asan_malloc_mac.cc
+++ b/lib/asan/asan_malloc_mac.cc
@@ -19,6 +19,7 @@
#include <CoreFoundation/CFBase.h>
#include <dlfcn.h>
#include <malloc/malloc.h>
+#include <sys/mman.h>
#include "asan_allocator.h"
#include "asan_interceptors.h"
@@ -42,10 +43,19 @@ INTERCEPTOR(malloc_zone_t *, malloc_create_zone,
vm_size_t start_size, unsigned zone_flags) {
if (!asan_inited) __asan_init();
GET_STACK_TRACE_MALLOC;
+ uptr page_size = GetPageSizeCached();
+ uptr allocated_size = RoundUpTo(sizeof(asan_zone), page_size);
malloc_zone_t *new_zone =
- (malloc_zone_t*)asan_malloc(sizeof(asan_zone), &stack);
+ (malloc_zone_t*)asan_memalign(page_size, allocated_size,
+ &stack, FROM_MALLOC);
internal_memcpy(new_zone, &asan_zone, sizeof(asan_zone));
new_zone->zone_name = NULL; // The name will be changed anyway.
+ if (GetMacosVersion() >= MACOS_VERSION_LION) {
+ // Prevent the client app from overwriting the zone contents.
+ // Library functions that need to modify the zone will set PROT_WRITE on it.
+ // This matches the behavior of malloc_create_zone() on OSX 10.7 and higher.
+ mprotect(new_zone, allocated_size, PROT_READ);
+ }
return new_zone;
}
diff --git a/lib/asan/asan_malloc_win.cc b/lib/asan/asan_malloc_win.cc
index 31fb777c7045..73e4c825092c 100644
--- a/lib/asan/asan_malloc_win.cc
+++ b/lib/asan/asan_malloc_win.cc
@@ -32,11 +32,13 @@ using namespace __asan; // NOLINT
// revisited in the future.
extern "C" {
+SANITIZER_INTERFACE_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) {
free(ptr);
}
@@ -45,38 +47,46 @@ void cfree(void *ptr) {
CHECK(!"cfree() should not be used on Windows?");
}
+SANITIZER_INTERFACE_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) {
return malloc(size);
}
+SANITIZER_INTERFACE_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);
}
+SANITIZER_INTERFACE_ATTRIBUTE
void *_calloc_impl(size_t nmemb, size_t size, int *errno_tmp) {
return calloc(nmemb, size);
}
+SANITIZER_INTERFACE_ATTRIBUTE
void *realloc(void *ptr, size_t size) {
GET_STACK_TRACE_MALLOC;
return asan_realloc(ptr, size, &stack);
}
+SANITIZER_INTERFACE_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) {
if (!p)
return calloc(n, elem_size);
@@ -86,9 +96,11 @@ void* _recalloc(void* p, size_t n, size_t elem_size) {
return realloc(p, size);
}
+SANITIZER_INTERFACE_ATTRIBUTE
size_t _msize(void *ptr) {
- GET_STACK_TRACE_MALLOC;
- return asan_malloc_usable_size(ptr, &stack);
+ GET_CURRENT_PC_BP_SP;
+ (void)sp;
+ return asan_malloc_usable_size(ptr, pc, bp);
}
int _CrtDbgReport(int, const char*, int,
diff --git a/lib/asan/asan_mapping.h b/lib/asan/asan_mapping.h
index f04629222419..1fecaeb35e1e 100644
--- a/lib/asan/asan_mapping.h
+++ b/lib/asan/asan_mapping.h
@@ -49,6 +49,20 @@
// || `[0x24000000, 0x27ffffff]` || 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 ||
+
+static const u64 kDefaultShadowScale = 3;
+static const u64 kDefaultShadowOffset32 = 1ULL << 29;
+static const u64 kDefaultShadowOffset64 = 1ULL << 44;
+static const u64 kDefaultShort64bitShadowOffset = 0x7FFF8000; // < 2G.
+static const u64 kPPC64_ShadowOffset64 = 1ULL << 41;
+static const u64 kMIPS32_ShadowOffset32 = 0x0aaa8000;
#if ASAN_FLEXIBLE_MAPPING_AND_OFFSET == 1
extern SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_mapping_scale;
@@ -56,22 +70,23 @@ extern SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_mapping_offset;
# define SHADOW_SCALE (__asan_mapping_scale)
# define SHADOW_OFFSET (__asan_mapping_offset)
#else
+# define SHADOW_SCALE kDefaultShadowScale
# if SANITIZER_ANDROID
-# define SHADOW_SCALE (3)
# define SHADOW_OFFSET (0)
# else
-# define SHADOW_SCALE (3)
# if SANITIZER_WORDSIZE == 32
-# define SHADOW_OFFSET (1 << 29)
+# if defined(__mips__)
+# define SHADOW_OFFSET kMIPS32_ShadowOffset32
+# else
+# define SHADOW_OFFSET kDefaultShadowOffset32
+# endif
# else
# if defined(__powerpc64__)
-# define SHADOW_OFFSET (1ULL << 41)
+# define SHADOW_OFFSET kPPC64_ShadowOffset64
+# elif SANITIZER_MAC
+# define SHADOW_OFFSET kDefaultShadowOffset64
# else
-# if SANITIZER_MAC
-# define SHADOW_OFFSET (1ULL << 44)
-# else
-# define SHADOW_OFFSET 0x7fff8000ULL
-# endif
+# define SHADOW_OFFSET kDefaultShort64bitShadowOffset
# endif
# endif
# endif
@@ -133,7 +148,6 @@ static uptr kHighMemEnd = 0x7fffffffffffULL;
static uptr kMidMemBeg = 0x3000000000ULL;
static uptr kMidMemEnd = 0x4fffffffffULL;
#else
-SANITIZER_INTERFACE_ATTRIBUTE
extern uptr kHighMemEnd, kMidMemBeg, kMidMemEnd; // Initialized in __asan_init.
#endif
diff --git a/lib/asan/asan_poisoning.cc b/lib/asan/asan_poisoning.cc
index 772b5e64b027..280aaeb909a3 100644
--- a/lib/asan/asan_poisoning.cc
+++ b/lib/asan/asan_poisoning.cc
@@ -14,6 +14,7 @@
#include "asan_poisoning.h"
#include "sanitizer_common/sanitizer_libc.h"
+#include "sanitizer_common/sanitizer_flags.h"
namespace __asan {
@@ -68,7 +69,7 @@ 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 (flags()->verbosity >= 1) {
+ if (common_flags()->verbosity >= 1) {
Printf("Trying to poison memory region [%p, %p)\n",
(void*)beg_addr, (void*)end_addr);
}
@@ -110,7 +111,7 @@ 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 (flags()->verbosity >= 1) {
+ if (common_flags()->verbosity >= 1) {
Printf("Trying to unpoison memory region [%p, %p)\n",
(void*)beg_addr, (void*)end_addr);
}
@@ -183,37 +184,37 @@ uptr __asan_region_is_poisoned(uptr beg, uptr size) {
extern "C" SANITIZER_INTERFACE_ATTRIBUTE
-u16 __sanitizer_unaligned_load16(const u16 *p) {
+u16 __sanitizer_unaligned_load16(const uu16 *p) {
CHECK_SMALL_REGION(p, sizeof(*p), false);
return *p;
}
extern "C" SANITIZER_INTERFACE_ATTRIBUTE
-u32 __sanitizer_unaligned_load32(const u32 *p) {
+u32 __sanitizer_unaligned_load32(const uu32 *p) {
CHECK_SMALL_REGION(p, sizeof(*p), false);
return *p;
}
extern "C" SANITIZER_INTERFACE_ATTRIBUTE
-u64 __sanitizer_unaligned_load64(const u64 *p) {
+u64 __sanitizer_unaligned_load64(const uu64 *p) {
CHECK_SMALL_REGION(p, sizeof(*p), false);
return *p;
}
extern "C" SANITIZER_INTERFACE_ATTRIBUTE
-void __sanitizer_unaligned_store16(u16 *p, u16 x) {
+void __sanitizer_unaligned_store16(uu16 *p, u16 x) {
CHECK_SMALL_REGION(p, sizeof(*p), true);
*p = x;
}
extern "C" SANITIZER_INTERFACE_ATTRIBUTE
-void __sanitizer_unaligned_store32(u32 *p, u32 x) {
+void __sanitizer_unaligned_store32(uu32 *p, u32 x) {
CHECK_SMALL_REGION(p, sizeof(*p), true);
*p = x;
}
extern "C" SANITIZER_INTERFACE_ATTRIBUTE
-void __sanitizer_unaligned_store64(u64 *p, u64 x) {
+void __sanitizer_unaligned_store64(uu64 *p, u64 x) {
CHECK_SMALL_REGION(p, sizeof(*p), true);
*p = x;
}
@@ -244,13 +245,55 @@ static void PoisonAlignedStackMemory(uptr addr, uptr size, bool do_poison) {
}
void __asan_poison_stack_memory(uptr addr, uptr size) {
- if (flags()->verbosity > 0)
+ if (common_flags()->verbosity > 0)
Report("poisoning: %p %zx\n", (void*)addr, size);
PoisonAlignedStackMemory(addr, size, true);
}
void __asan_unpoison_stack_memory(uptr addr, uptr size) {
- if (flags()->verbosity > 0)
+ if (common_flags()->verbosity > 0)
Report("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) {
+ uptr beg = reinterpret_cast<uptr>(beg_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));
+ 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);
+ // 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);
+ if (a + granularity <= d1)
+ CHECK_EQ(*(u8*)MemToShadow(a), 0);
+ if (d2 + granularity <= c && c <= end)
+ CHECK_EQ(*(u8 *)MemToShadow(c - granularity), kAsanUserPoisonedMemoryMagic);
+
+ // 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);
+ if (b1 != b2) {
+ CHECK_EQ(b2 - b1, granularity);
+ *(u8*)MemToShadow(b1) = static_cast<u8>(b - b1);
+ }
+}
diff --git a/lib/asan/asan_poisoning.h b/lib/asan/asan_poisoning.h
index 86f81e5d0ae5..fbac21196b8f 100644
--- a/lib/asan/asan_poisoning.h
+++ b/lib/asan/asan_poisoning.h
@@ -43,6 +43,7 @@ ALWAYS_INLINE void FastPoisonShadow(uptr aligned_beg, uptr aligned_size,
ALWAYS_INLINE void FastPoisonShadowPartialRightRedzone(
uptr aligned_addr, uptr size, uptr redzone_size, u8 value) {
DCHECK(flags()->poison_heap);
+ bool poison_partial = flags()->poison_partial;
u8 *shadow = (u8*)MEM_TO_SHADOW(aligned_addr);
for (uptr i = 0; i < redzone_size; i += SHADOW_GRANULARITY, shadow++) {
if (i + SHADOW_GRANULARITY <= size) {
@@ -50,7 +51,8 @@ ALWAYS_INLINE void FastPoisonShadowPartialRightRedzone(
} else if (i >= size) {
*shadow = (SHADOW_GRANULARITY == 128) ? 0xff : value; // unaddressable
} else {
- *shadow = size - i; // first size-i bytes are addressable
+ // first size-i bytes are addressable
+ *shadow = poison_partial ? static_cast<u8>(size - i) : 0;
}
}
}
diff --git a/lib/asan/asan_posix.cc b/lib/asan/asan_posix.cc
index 5126a756d1c8..bcc6b381a785 100644
--- a/lib/asan/asan_posix.cc
+++ b/lib/asan/asan_posix.cc
@@ -1,4 +1,4 @@
-//===-- asan_linux.cc -----------------------------------------------------===//
+//===-- asan_posix.cc -----------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -44,7 +44,7 @@ static void MaybeInstallSigaction(int signum,
sigact.sa_flags = SA_SIGINFO;
if (flags()->use_sigaltstack) sigact.sa_flags |= SA_ONSTACK;
CHECK_EQ(0, REAL(sigaction)(signum, &sigact, 0));
- if (flags()->verbosity >= 1) {
+ if (common_flags()->verbosity >= 1) {
Report("Installed the sigaction for signal %d\n", signum);
}
}
@@ -71,7 +71,7 @@ void SetAlternateSignalStack() {
altstack.ss_flags = 0;
altstack.ss_size = kAltStackSize;
CHECK_EQ(0, sigaltstack(&altstack, 0));
- if (flags()->verbosity > 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);
@@ -116,6 +116,15 @@ void AsanTSDSet(void *tsd) {
pthread_setspecific(tsd_key, tsd);
}
+void PlatformTSDDtor(void *tsd) {
+ AsanThreadContext *context = (AsanThreadContext*)tsd;
+ if (context->destructor_iterations > 1) {
+ context->destructor_iterations--;
+ CHECK_EQ(0, pthread_setspecific(tsd_key, tsd));
+ return;
+ }
+ AsanThread::TSDDtor(tsd);
+}
} // namespace __asan
#endif // SANITIZER_LINUX || SANITIZER_MAC
diff --git a/lib/asan/asan_report.cc b/lib/asan/asan_report.cc
index aeeebf452ca8..ed4e433c7a54 100644
--- a/lib/asan/asan_report.cc
+++ b/lib/asan/asan_report.cc
@@ -20,6 +20,7 @@
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_flags.h"
#include "sanitizer_common/sanitizer_report_decorator.h"
+#include "sanitizer_common/sanitizer_stackdepot.h"
#include "sanitizer_common/sanitizer_symbolizer.h"
namespace __asan {
@@ -44,15 +45,6 @@ void AppendToErrorMessageBuffer(const char *buffer) {
}
// ---------------------- Decorator ------------------------------ {{{1
-bool PrintsToTtyCached() {
- static int cached = 0;
- static bool prints_to_tty;
- if (!cached) { // Ok wrt threads since we are printing only from one thread.
- prints_to_tty = PrintsToTty();
- cached = 1;
- }
- return prints_to_tty;
-}
class Decorator: private __sanitizer::AnsiColorDecorator {
public:
Decorator() : __sanitizer::AnsiColorDecorator(PrintsToTtyCached()) { }
@@ -113,7 +105,7 @@ static void PrintShadowBytes(const char *before, u8 *bytes,
for (uptr i = 0; i < n; i++) {
u8 *p = bytes + i;
const char *before = p == guilty ? "[" :
- p - 1 == guilty ? "" : " ";
+ (p - 1 == guilty && i != 0) ? "" : " ";
const char *after = p == guilty ? "]" : "";
PrintShadowByte(before, *p, after);
}
@@ -125,7 +117,7 @@ static void PrintLegend() {
"application bytes):\n", (int)SHADOW_GRANULARITY);
PrintShadowByte(" Addressable: ", 0);
Printf(" Partially addressable: ");
- for (uptr i = 1; i < SHADOW_GRANULARITY; i++)
+ for (u8 i = 1; i < SHADOW_GRANULARITY; i++)
PrintShadowByte("", i, " ");
Printf("\n");
PrintShadowByte(" Heap left redzone: ", kAsanHeapLeftRedzoneMagic);
@@ -175,6 +167,11 @@ static void PrintZoneForPointer(uptr ptr, uptr zone_ptr,
}
}
+static void DescribeThread(AsanThread *t) {
+ if (t)
+ DescribeThread(t->context());
+}
+
// ---------------------- Address Descriptions ------------------- {{{1
static bool IsASCII(unsigned char c) {
@@ -184,7 +181,9 @@ 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') ? Demangle(name) : name;
+ return (name[0] == '_' && name[1] == 'Z')
+ ? Symbolizer::Get()->Demangle(name)
+ : name;
}
// Check if the global is a zero-terminated ASCII string. If so, print it.
@@ -264,10 +263,53 @@ 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;
+ uptr addr_end = addr + access_size;
+ const char *pos_descr = 0;
+ // 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_end <= var_end)
+ pos_descr = "is inside"; // May happen if this is a use-after-return.
+ else if (addr < var_end)
+ pos_descr = "partially overflows";
+ else if (addr_end <= next_var_beg &&
+ next_var_beg - addr_end >= addr - var_end)
+ pos_descr = "overflows";
+ } else {
+ if (addr_end > var_beg)
+ pos_descr = "partially underflows";
+ else if (addr >= prev_var_end &&
+ addr - prev_var_end >= var_beg - addr_end)
+ pos_descr = "underflows";
+ }
+ Printf(" [%zd, %zd) '%s'", var_beg, var_beg + var_size, var_name);
+ 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());
+ } else {
+ Printf("\n");
+ }
+}
+
+struct StackVarDescr {
+ uptr beg;
+ uptr size;
+ const char *name_pos;
+ uptr name_len;
+};
+
bool DescribeAddressIfStack(uptr addr, uptr access_size) {
AsanThread *t = FindThreadByStackAddress(addr);
if (!t) return false;
- const sptr kBufSize = 4095;
+ const uptr kBufSize = 4095;
char buf[kBufSize];
uptr offset = 0;
uptr frame_pc = 0;
@@ -306,31 +348,44 @@ bool DescribeAddressIfStack(uptr addr, uptr access_size) {
PrintStack(&alloca_stack);
// Report the number of stack objects.
char *p;
- uptr n_objects = internal_simple_strtoll(frame_descr, &p, 10);
+ 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;
- sptr len;
- beg = internal_simple_strtoll(p, &p, 10);
- size = internal_simple_strtoll(p, &p, 10);
- len = internal_simple_strtoll(p, &p, 10);
- if (beg <= 0 || size <= 0 || len < 0 || *p != ' ') {
+ 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++;
- buf[0] = 0;
- internal_strncat(buf, p, Min(kBufSize, len));
+ vars[i].beg = beg;
+ vars[i].size = size;
+ vars[i].name_pos = p;
+ vars[i].name_len = len;
p += len;
- Printf(" [%zu, %zu) '%s'\n", beg, beg + size, buf);
+ }
+ 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,
+ 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");
- DescribeThread(t->context());
+ DescribeThread(t);
return true;
}
@@ -360,7 +415,11 @@ static void DescribeAccessToHeapChunk(AsanChunkView chunk, uptr addr,
void DescribeHeapAddress(uptr addr, uptr access_size) {
AsanChunkView chunk = FindHeapChunkByAddress(addr);
- if (!chunk.IsValid()) return;
+ if (!chunk.IsValid()) {
+ Printf("AddressSanitizer can not describe address in more detail "
+ "(wild memory access suspected).\n");
+ return;
+ }
DescribeAccessToHeapChunk(chunk, addr, access_size);
CHECK(chunk.AllocTid() != kInvalidTid);
asanThreadRegistry().CheckLocked();
@@ -368,13 +427,11 @@ void DescribeHeapAddress(uptr addr, uptr access_size) {
GetThreadContextByTidLocked(chunk.AllocTid());
StackTrace alloc_stack;
chunk.GetAllocStack(&alloc_stack);
- AsanThread *t = GetCurrentThread();
- CHECK(t);
char tname[128];
Decorator d;
+ AsanThreadContext *free_thread = 0;
if (chunk.FreeTid() != kInvalidTid) {
- AsanThreadContext *free_thread =
- GetThreadContextByTidLocked(chunk.FreeTid());
+ free_thread = GetThreadContextByTidLocked(chunk.FreeTid());
Printf("%sfreed by thread T%d%s here:%s\n", d.Allocation(),
free_thread->tid,
ThreadNameWithParenthesis(free_thread, tname, sizeof(tname)),
@@ -386,19 +443,17 @@ void DescribeHeapAddress(uptr addr, uptr access_size) {
d.Allocation(), alloc_thread->tid,
ThreadNameWithParenthesis(alloc_thread, tname, sizeof(tname)),
d.EndAllocation());
- PrintStack(&alloc_stack);
- DescribeThread(t->context());
- DescribeThread(free_thread);
- DescribeThread(alloc_thread);
} else {
Printf("%sallocated by thread T%d%s here:%s\n", d.Allocation(),
alloc_thread->tid,
ThreadNameWithParenthesis(alloc_thread, tname, sizeof(tname)),
d.EndAllocation());
- PrintStack(&alloc_stack);
- DescribeThread(t->context());
- DescribeThread(alloc_thread);
}
+ PrintStack(&alloc_stack);
+ DescribeThread(GetCurrentThread());
+ if (free_thread)
+ DescribeThread(free_thread);
+ DescribeThread(alloc_thread);
}
void DescribeAddress(uptr addr, uptr access_size) {
@@ -431,7 +486,9 @@ void DescribeThread(AsanThreadContext *context) {
context->parent_tid,
ThreadNameWithParenthesis(context->parent_tid,
tname, sizeof(tname)));
- PrintStack(&context->stack);
+ uptr stack_size;
+ const uptr *stack_trace = StackDepotGet(context->stack_id, &stack_size);
+ PrintStack(stack_trace, stack_size);
// Recursively described parent thread if needed.
if (flags()->print_full_thread_history) {
AsanThreadContext *parent_context =
@@ -476,21 +533,11 @@ class ScopedInErrorReport {
reporting_thread_tid = GetCurrentTidOrInvalid();
Printf("===================================================="
"=============\n");
- if (reporting_thread_tid != kInvalidTid) {
- // We started reporting an error message. Stop using the fake stack
- // in case we call an instrumented function from a symbolizer.
- AsanThread *curr_thread = GetCurrentThread();
- CHECK(curr_thread);
- curr_thread->fake_stack().StopUsingFakeStack();
- }
}
// Destructor is NORETURN, as functions that report errors are.
NORETURN ~ScopedInErrorReport() {
// Make sure the current thread is announced.
- AsanThread *curr_thread = GetCurrentThread();
- if (curr_thread) {
- DescribeThread(curr_thread->context());
- }
+ DescribeThread(GetCurrentThread());
// Print memory stats.
if (flags()->print_stats)
__asan_print_accumulated_stats();
@@ -502,22 +549,6 @@ class ScopedInErrorReport {
}
};
-static void ReportSummary(const char *error_type, StackTrace *stack) {
- if (!stack->size) return;
- if (IsSymbolizerAvailable()) {
- AddressInfo ai;
- // 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]);
- SymbolizeCode(pc, &ai, 1);
- ReportErrorSummary(error_type,
- StripPathPrefix(ai.file,
- common_flags()->strip_path_prefix),
- ai.line, ai.function);
- }
- // FIXME: do we need to print anything at all if there is no symbolizer?
-}
-
void ReportSIGSEGV(uptr pc, uptr sp, uptr bp, uptr addr) {
ScopedInErrorReport in_report;
Decorator d;
@@ -527,13 +558,13 @@ void ReportSIGSEGV(uptr pc, uptr sp, uptr bp, uptr addr) {
(void*)addr, (void*)pc, (void*)sp, (void*)bp,
GetCurrentTidOrInvalid());
Printf("%s", d.EndWarning());
- Printf("AddressSanitizer can not provide additional info.\n");
GET_STACK_TRACE_FATAL(pc, bp);
PrintStack(&stack);
- ReportSummary("SEGV", &stack);
+ Printf("AddressSanitizer can not provide additional info.\n");
+ ReportErrorSummary("SEGV", &stack);
}
-void ReportDoubleFree(uptr addr, StackTrace *stack) {
+void ReportDoubleFree(uptr addr, StackTrace *free_stack) {
ScopedInErrorReport in_report;
Decorator d;
Printf("%s", d.Warning());
@@ -543,14 +574,15 @@ void ReportDoubleFree(uptr addr, StackTrace *stack) {
"thread T%d%s:\n",
addr, curr_tid,
ThreadNameWithParenthesis(curr_tid, tname, sizeof(tname)));
-
Printf("%s", d.EndWarning());
- PrintStack(stack);
+ CHECK_GT(free_stack->size, 0);
+ GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp);
+ PrintStack(&stack);
DescribeHeapAddress(addr, 1);
- ReportSummary("double-free", stack);
+ ReportErrorSummary("double-free", &stack);
}
-void ReportFreeNotMalloced(uptr addr, StackTrace *stack) {
+void ReportFreeNotMalloced(uptr addr, StackTrace *free_stack) {
ScopedInErrorReport in_report;
Decorator d;
Printf("%s", d.Warning());
@@ -560,12 +592,14 @@ void ReportFreeNotMalloced(uptr addr, StackTrace *stack) {
"which was not malloc()-ed: %p in thread T%d%s\n", addr,
curr_tid, ThreadNameWithParenthesis(curr_tid, tname, sizeof(tname)));
Printf("%s", d.EndWarning());
- PrintStack(stack);
+ CHECK_GT(free_stack->size, 0);
+ GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp);
+ PrintStack(&stack);
DescribeHeapAddress(addr, 1);
- ReportSummary("bad-free", stack);
+ ReportErrorSummary("bad-free", &stack);
}
-void ReportAllocTypeMismatch(uptr addr, StackTrace *stack,
+void ReportAllocTypeMismatch(uptr addr, StackTrace *free_stack,
AllocType alloc_type,
AllocType dealloc_type) {
static const char *alloc_names[] =
@@ -579,9 +613,11 @@ void ReportAllocTypeMismatch(uptr addr, StackTrace *stack,
Report("ERROR: AddressSanitizer: alloc-dealloc-mismatch (%s vs %s) on %p\n",
alloc_names[alloc_type], dealloc_names[dealloc_type], addr);
Printf("%s", d.EndWarning());
- PrintStack(stack);
+ CHECK_GT(free_stack->size, 0);
+ GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp);
+ PrintStack(&stack);
DescribeHeapAddress(addr, 1);
- ReportSummary("alloc-dealloc-mismatch", stack);
+ 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");
}
@@ -596,7 +632,7 @@ void ReportMallocUsableSizeNotOwned(uptr addr, StackTrace *stack) {
Printf("%s", d.EndWarning());
PrintStack(stack);
DescribeHeapAddress(addr, 1);
- ReportSummary("bad-malloc_usable_size", stack);
+ ReportErrorSummary("bad-malloc_usable_size", stack);
}
void ReportAsanGetAllocatedSizeNotOwned(uptr addr, StackTrace *stack) {
@@ -609,7 +645,7 @@ void ReportAsanGetAllocatedSizeNotOwned(uptr addr, StackTrace *stack) {
Printf("%s", d.EndWarning());
PrintStack(stack);
DescribeHeapAddress(addr, 1);
- ReportSummary("bad-__asan_get_allocated_size", stack);
+ ReportErrorSummary("bad-__asan_get_allocated_size", stack);
}
void ReportStringFunctionMemoryRangesOverlap(
@@ -627,7 +663,7 @@ void ReportStringFunctionMemoryRangesOverlap(
PrintStack(stack);
DescribeAddress((uptr)offset1, length1);
DescribeAddress((uptr)offset2, length2);
- ReportSummary(bug_type, stack);
+ ReportErrorSummary(bug_type, stack);
}
// ----------------------- Mac-specific reports ----------------- {{{1
@@ -737,7 +773,7 @@ void __asan_report_error(uptr pc, uptr bp, uptr sp,
PrintStack(&stack);
DescribeAddress(addr, access_size);
- ReportSummary(bug_descr, &stack);
+ ReportErrorSummary(bug_descr, &stack);
PrintShadowMemoryForAddress(addr);
}
@@ -758,6 +794,6 @@ void __asan_describe_address(uptr addr) {
#if !SANITIZER_SUPPORTS_WEAK_HOOKS
// Provide default implementation of __asan_on_error that does nothing
// and may be overriden by user.
-SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE NOINLINE
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE NOINLINE
void __asan_on_error() {}
#endif
diff --git a/lib/asan/asan_report.h b/lib/asan/asan_report.h
index db271fc10e97..f55b57bd4d9f 100644
--- a/lib/asan/asan_report.h
+++ b/lib/asan/asan_report.h
@@ -33,9 +33,9 @@ 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 *stack);
-void NORETURN ReportFreeNotMalloced(uptr addr, StackTrace *stack);
-void NORETURN ReportAllocTypeMismatch(uptr addr, StackTrace *stack,
+void NORETURN ReportDoubleFree(uptr addr, StackTrace *free_stack);
+void NORETURN ReportFreeNotMalloced(uptr addr, StackTrace *free_stack);
+void NORETURN ReportAllocTypeMismatch(uptr addr, StackTrace *free_stack,
AllocType alloc_type,
AllocType dealloc_type);
void NORETURN ReportMallocUsableSizeNotOwned(uptr addr,
diff --git a/lib/asan/asan_rtl.cc b/lib/asan/asan_rtl.cc
index f989c5c0d2a5..11f05954d31e 100644
--- a/lib/asan/asan_rtl.cc
+++ b/lib/asan/asan_rtl.cc
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "asan_allocator.h"
#include "asan_interceptors.h"
+#include "asan_interface_internal.h"
#include "asan_internal.h"
#include "asan_mapping.h"
#include "asan_poisoning.h"
@@ -26,6 +27,8 @@
#include "sanitizer_common/sanitizer_symbolizer.h"
#include "lsan/lsan_common.h"
+int __asan_option_detect_stack_use_after_return; // Global interface symbol.
+
namespace __asan {
uptr AsanMappingProfile[kAsanMappingProfileSize];
@@ -89,7 +92,6 @@ static void ParseFlagsFromString(Flags *f, const char *str) {
CHECK((uptr)common_flags()->malloc_context_size <= kStackTraceMax);
ParseFlag(str, &f->quarantine_size, "quarantine_size");
- ParseFlag(str, &f->verbosity, "verbosity");
ParseFlag(str, &f->redzone, "redzone");
CHECK_GE(f->redzone, 16);
CHECK(IsPowerOfTwo(f->redzone));
@@ -101,7 +103,9 @@ static void ParseFlagsFromString(Flags *f, const char *str) {
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");
- ParseFlag(str, &f->use_fake_stack, "use_fake_stack");
+ 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");
@@ -116,30 +120,25 @@ static void ParseFlagsFromString(Flags *f, const char *str) {
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->log_path, "log_path");
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->use_stack_depot, "use_stack_depot");
ParseFlag(str, &f->strict_memcmp, "strict_memcmp");
ParseFlag(str, &f->strict_init_order, "strict_init_order");
- ParseFlag(str, &f->detect_leaks, "detect_leaks");
}
void InitializeFlags(Flags *f, const char *env) {
CommonFlags *cf = common_flags();
+ SetCommonFlagDefaults();
cf->external_symbolizer_path = GetEnv("ASAN_SYMBOLIZER_PATH");
- cf->symbolize = true;
cf->malloc_context_size = kDefaultMallocContextSize;
- cf->fast_unwind_on_fatal = false;
- cf->fast_unwind_on_malloc = true;
- cf->strip_path_prefix = "";
internal_memset(f, 0, sizeof(*f));
f->quarantine_size = (ASAN_LOW_MEMORY) ? 1UL << 26 : 1UL << 28;
- f->verbosity = 0;
f->redzone = 16;
f->debug = false;
f->report_globals = 1;
@@ -147,7 +146,8 @@ void InitializeFlags(Flags *f, const char *env) {
f->replace_str = true;
f->replace_intrin = true;
f->mac_ignore_invalid_free = false;
- f->use_fake_stack = true;
+ f->detect_stack_use_after_return = false; // Also needs the compiler flag.
+ f->uar_stack_size_log = 0;
f->max_malloc_fill_size = 0x1000; // By default, fill only the first 4K.
f->malloc_fill_byte = 0xbe;
f->exitcode = ASAN_DEFAULT_FAILURE_EXITCODE;
@@ -162,25 +162,24 @@ void InitializeFlags(Flags *f, const char *env) {
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->log_path = 0;
f->poison_heap = true;
- // Turn off alloc/dealloc mismatch checker on Mac for now.
- // TODO(glider): Fix known issues and enable this back.
- f->alloc_dealloc_mismatch = (SANITIZER_MAC == 0);;
- f->use_stack_depot = true;
+ f->poison_partial = true;
+ // Turn off alloc/dealloc mismatch checker on Mac and Windows for now.
+ // TODO(glider,timurrrr): Fix known issues and enable this back.
+ f->alloc_dealloc_mismatch = (SANITIZER_MAC == 0) && (SANITIZER_WINDOWS == 0);
f->strict_memcmp = true;
f->strict_init_order = false;
- f->detect_leaks = false;
// Override from compile definition.
ParseFlagsFromString(f, MaybeUseAsanDefaultOptionsCompileDefiniton());
// Override from user-specified string.
ParseFlagsFromString(f, MaybeCallAsanDefaultOptions());
- if (flags()->verbosity) {
+ if (common_flags()->verbosity) {
Report("Using the defaults from __asan_default_options: %s\n",
MaybeCallAsanDefaultOptions());
}
@@ -189,17 +188,17 @@ void InitializeFlags(Flags *f, const char *env) {
ParseFlagsFromString(f, env);
#if !CAN_SANITIZE_LEAKS
- if (f->detect_leaks) {
+ if (cf->detect_leaks) {
Report("%s: detect_leaks is not supported on this platform.\n",
SanitizerToolName);
- f->detect_leaks = false;
+ cf->detect_leaks = false;
}
#endif
- if (f->detect_leaks && !f->use_stack_depot) {
- Report("%s: detect_leaks is ignored (requires use_stack_depot).\n",
- SanitizerToolName);
- f->detect_leaks = false;
+ // Make "strict_init_order" imply "check_initialization_order".
+ // TODO(samsonov): Use a single runtime flag for an init-order checker.
+ if (f->strict_init_order) {
+ f->check_initialization_order = true;
}
}
@@ -305,8 +304,6 @@ static NOINLINE void force_interface_symbols() {
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;
- case 28: __asan_stack_free(0, 0, 0); break;
- case 29: __asan_stack_malloc(0, 0); break;
case 30: __asan_before_dynamic_init(0); break;
case 31: __asan_after_dynamic_init(); break;
case 32: __asan_poison_stack_memory(0, 0); break;
@@ -328,22 +325,12 @@ static void asan_atexit() {
static void InitializeHighMemEnd() {
#if !ASAN_FIXED_MAPPING
-#if SANITIZER_WORDSIZE == 64
-# if defined(__powerpc64__)
- // FIXME:
- // 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
- // 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.
- kHighMemEnd = (1ULL << 44) - 1; // 0x00000fffffffffffUL
-# else
- kHighMemEnd = (1ULL << 47) - 1; // 0x00007fffffffffffUL;
-# endif
-#else // SANITIZER_WORDSIZE == 32
- kHighMemEnd = (1ULL << 32) - 1; // 0xffffffff;
-#endif // SANITIZER_WORDSIZE
+ kHighMemEnd = GetMaxVirtualAddress();
+ // Increase kHighMemEnd to make sure it's properly
+ // aligned together with kHighMemBeg:
+ kHighMemEnd |= SHADOW_GRANULARITY * GetPageSizeCached() - 1;
#endif // !ASAN_FIXED_MAPPING
+ CHECK_EQ((kHighMemBeg % GetPageSizeCached()), 0);
}
static void ProtectGap(uptr a, uptr size) {
@@ -385,6 +372,7 @@ static void PrintAddressSpaceLayout() {
}
Printf("\n");
Printf("red_zone=%zu\n", (uptr)flags()->redzone);
+ Printf("quarantine_size=%zuM\n", (uptr)flags()->quarantine_size >> 20);
Printf("malloc_context_size=%zu\n",
(uptr)common_flags()->malloc_context_size);
@@ -405,7 +393,7 @@ using namespace __asan; // NOLINT
#if !SANITIZER_SUPPORTS_WEAK_HOOKS
extern "C" {
-SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
const char* __asan_default_options() { return ""; }
} // extern "C"
#endif
@@ -438,6 +426,8 @@ void NOINLINE __asan_handle_no_return() {
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)) {
@@ -463,9 +453,11 @@ void __asan_init() {
// initialization steps look at flags().
const char *options = GetEnv("ASAN_OPTIONS");
InitializeFlags(flags(), options);
- __sanitizer_set_report_path(flags()->log_path);
+ __sanitizer_set_report_path(common_flags()->log_path);
+ __asan_option_detect_stack_use_after_return =
+ flags()->detect_stack_use_after_return;
- if (flags()->verbosity && options) {
+ if (common_flags()->verbosity && options) {
Report("Parsed ASAN_OPTIONS: %s\n", options);
}
@@ -475,21 +467,16 @@ void __asan_init() {
// Setup internal allocator callback.
SetLowLevelAllocateCallback(OnLowLevelAllocate);
- if (flags()->atexit) {
- Atexit(asan_atexit);
- }
-
- // interceptors
InitializeAsanInterceptors();
ReplaceSystemMalloc();
ReplaceOperatorsNewAndDelete();
uptr shadow_start = kLowShadowBeg;
- if (kLowShadowBeg) shadow_start -= GetMmapGranularity();
- uptr shadow_end = kHighShadowEnd;
+ if (kLowShadowBeg)
+ shadow_start -= GetMmapGranularity();
bool full_shadow_is_available =
- MemoryRangeIsAvailable(shadow_start, shadow_end);
+ MemoryRangeIsAvailable(shadow_start, kHighShadowEnd);
#if SANITIZER_LINUX && defined(__x86_64__) && !ASAN_FIXED_MAPPING
if (!full_shadow_is_available) {
@@ -498,7 +485,7 @@ void __asan_init() {
}
#endif
- if (flags()->verbosity)
+ if (common_flags()->verbosity)
PrintAddressSpaceLayout();
if (flags()->disable_core) {
@@ -515,7 +502,7 @@ void __asan_init() {
ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1);
} else if (kMidMemBeg &&
MemoryRangeIsAvailable(shadow_start, kMidMemBeg - 1) &&
- MemoryRangeIsAvailable(kMidMemEnd + 1, shadow_end)) {
+ MemoryRangeIsAvailable(kMidMemEnd + 1, kHighShadowEnd)) {
CHECK(kLowShadowBeg != kLowShadowEnd);
// mmap the low shadow plus at least one page at the left.
ReserveShadowMemoryRange(shadow_start, kLowShadowEnd);
@@ -534,12 +521,18 @@ void __asan_init() {
Die();
}
+ AsanTSDInit(PlatformTSDDtor);
InstallSignalHandlers();
+
+ // Allocator should be initialized before starting external symbolizer, as
+ // fork() on Mac locks the allocator.
+ InitializeAllocator();
+
// Start symbolizer process if necessary.
- const char* external_symbolizer = common_flags()->external_symbolizer_path;
- if (common_flags()->symbolize && external_symbolizer &&
- external_symbolizer[0]) {
- InitializeExternalSymbolizer(external_symbolizer);
+ 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
@@ -547,8 +540,16 @@ void __asan_init() {
asan_inited = 1;
asan_init_is_running = false;
+ if (flags()->atexit)
+ Atexit(asan_atexit);
+
+ if (flags()->coverage)
+ Atexit(__sanitizer_cov_dump);
+
+ // interceptors
+ InitTlsSize();
+
// Create main thread.
- AsanTSDInit(AsanThread::TSDDtor);
AsanThread *main_thread = AsanThread::Create(0, 0);
CreateThreadContextArgs create_main_args = { main_thread, 0 };
u32 main_tid = asanThreadRegistry().CreateThread(
@@ -558,16 +559,14 @@ void __asan_init() {
main_thread->ThreadStart(internal_getpid());
force_interface_symbols(); // no-op.
- InitializeAllocator();
-
#if CAN_SANITIZE_LEAKS
__lsan::InitCommonLsan();
- if (flags()->detect_leaks) {
+ if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit) {
Atexit(__lsan::DoLeakCheck);
}
#endif // CAN_SANITIZE_LEAKS
- if (flags()->verbosity) {
+ if (common_flags()->verbosity) {
Report("AddressSanitizer Init done\n");
}
}
diff --git a/lib/asan/asan_stack.cc b/lib/asan/asan_stack.cc
index 21dae7df096a..0bc5a5f2d036 100644
--- a/lib/asan/asan_stack.cc
+++ b/lib/asan/asan_stack.cc
@@ -24,9 +24,12 @@ static bool MaybeCallAsanSymbolize(const void *pc, char *out_buffer,
: false;
}
+void PrintStack(const uptr *trace, uptr size) {
+ StackTrace::PrintStack(trace, size, MaybeCallAsanSymbolize);
+}
+
void PrintStack(StackTrace *stack) {
- stack->PrintStack(stack->trace, stack->size, common_flags()->symbolize,
- common_flags()->strip_path_prefix, MaybeCallAsanSymbolize);
+ PrintStack(stack->trace, stack->size);
}
} // namespace __asan
@@ -37,7 +40,7 @@ void PrintStack(StackTrace *stack) {
// 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_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE NOINLINE
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE NOINLINE
bool __asan_symbolize(const void *pc, char *out_buffer, int out_size) {
return false;
}
diff --git a/lib/asan/asan_stack.h b/lib/asan/asan_stack.h
index 176aa183c93b..7f5fd661eec8 100644
--- a/lib/asan/asan_stack.h
+++ b/lib/asan/asan_stack.h
@@ -22,6 +22,7 @@
namespace __asan {
void PrintStack(StackTrace *stack);
+void PrintStack(const uptr *trace, uptr size);
} // namespace __asan
@@ -29,21 +30,21 @@ void PrintStack(StackTrace *stack);
// 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.
#if SANITIZER_WINDOWS
-#define GET_STACK_TRACE_WITH_PC_AND_BP(max_s, pc, bp, fast) \
- StackTrace stack; \
- GetStackTrace(&stack, max_s, pc, bp, 0, 0, fast)
+#define GET_STACK_TRACE_WITH_PC_AND_BP(max_s, pc, bp, fast) \
+ StackTrace stack; \
+ stack.Unwind(max_s, pc, bp, 0, 0, fast)
#else
-#define GET_STACK_TRACE_WITH_PC_AND_BP(max_s, pc, bp, fast) \
- StackTrace stack; \
- { \
- uptr stack_top = 0, stack_bottom = 0; \
- AsanThread *t; \
- if (asan_inited && (t = GetCurrentThread())) { \
- stack_top = t->stack_top(); \
- stack_bottom = t->stack_bottom(); \
- } \
- GetStackTrace(&stack, max_s, pc, bp, \
- stack_top, stack_bottom, fast); \
+#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); \
+ } \
}
#endif // SANITIZER_WINDOWS
diff --git a/lib/asan/asan_stats.cc b/lib/asan/asan_stats.cc
index ba7c1ab6e91a..73dc3c5ac44f 100644
--- a/lib/asan/asan_stats.cc
+++ b/lib/asan/asan_stats.cc
@@ -21,6 +21,10 @@
namespace __asan {
AsanStats::AsanStats() {
+ Clear();
+}
+
+void AsanStats::Clear() {
CHECK(REAL(memset));
REAL(memset)(this, 0, sizeof(AsanStats));
}
@@ -54,77 +58,63 @@ void AsanStats::Print() {
malloc_large, malloc_small_slow);
}
-static BlockingMutex print_lock(LINKER_INITIALIZED);
-
-static void PrintAccumulatedStats() {
- AsanStats stats;
- GetAccumulatedStats(&stats);
- // Use lock to keep reports from mixing up.
- 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);
- PrintInternalAllocatorStats();
+void AsanStats::MergeFrom(const AsanStats *stats) {
+ uptr *dst_ptr = reinterpret_cast<uptr*>(this);
+ const uptr *src_ptr = reinterpret_cast<const uptr*>(stats);
+ uptr num_fields = sizeof(*this) / sizeof(uptr);
+ for (uptr i = 0; i < num_fields; i++)
+ dst_ptr[i] += src_ptr[i];
}
+static BlockingMutex print_lock(LINKER_INITIALIZED);
+
static AsanStats unknown_thread_stats(LINKER_INITIALIZED);
-static AsanStats accumulated_stats(LINKER_INITIALIZED);
+static AsanStats dead_threads_stats(LINKER_INITIALIZED);
+static BlockingMutex dead_threads_stats_lock(LINKER_INITIALIZED);
// Required for malloc_zone_statistics() on OS X. This can't be stored in
// per-thread AsanStats.
static uptr max_malloced_memory;
-static BlockingMutex acc_stats_lock(LINKER_INITIALIZED);
-
-static void FlushToAccumulatedStatsUnlocked(AsanStats *stats) {
- acc_stats_lock.CheckLocked();
- uptr *dst = (uptr*)&accumulated_stats;
- uptr *src = (uptr*)stats;
- uptr num_fields = sizeof(*stats) / sizeof(uptr);
- for (uptr i = 0; i < num_fields; i++) {
- dst[i] += src[i];
- src[i] = 0;
- }
-}
-static void FlushThreadStats(ThreadContextBase *tctx_base, void *arg) {
+static void MergeThreadStats(ThreadContextBase *tctx_base, void *arg) {
+ AsanStats *accumulated_stats = reinterpret_cast<AsanStats*>(arg);
AsanThreadContext *tctx = static_cast<AsanThreadContext*>(tctx_base);
if (AsanThread *t = tctx->thread)
- FlushToAccumulatedStatsUnlocked(&t->stats());
+ accumulated_stats->MergeFrom(&t->stats());
}
-static void UpdateAccumulatedStatsUnlocked() {
- acc_stats_lock.CheckLocked();
+static void GetAccumulatedStats(AsanStats *stats) {
+ stats->Clear();
{
ThreadRegistryLock l(&asanThreadRegistry());
- asanThreadRegistry().RunCallbackForEachThreadLocked(FlushThreadStats, 0);
+ asanThreadRegistry()
+ .RunCallbackForEachThreadLocked(MergeThreadStats, stats);
+ }
+ stats->MergeFrom(&unknown_thread_stats);
+ {
+ BlockingMutexLock lock(&dead_threads_stats_lock);
+ stats->MergeFrom(&dead_threads_stats);
}
- FlushToAccumulatedStatsUnlocked(&unknown_thread_stats);
// This is not very accurate: we may miss allocation peaks that happen
// between two updates of accumulated_stats_. For more accurate bookkeeping
// the maximum should be updated on every malloc(), which is unacceptable.
- if (max_malloced_memory < accumulated_stats.malloced) {
- max_malloced_memory = accumulated_stats.malloced;
+ if (max_malloced_memory < stats->malloced) {
+ max_malloced_memory = stats->malloced;
}
}
-void FlushToAccumulatedStats(AsanStats *stats) {
- BlockingMutexLock lock(&acc_stats_lock);
- FlushToAccumulatedStatsUnlocked(stats);
-}
-
-void GetAccumulatedStats(AsanStats *stats) {
- BlockingMutexLock lock(&acc_stats_lock);
- UpdateAccumulatedStatsUnlocked();
- internal_memcpy(stats, &accumulated_stats, sizeof(accumulated_stats));
+void FlushToDeadThreadStats(AsanStats *stats) {
+ BlockingMutexLock lock(&dead_threads_stats_lock);
+ dead_threads_stats.MergeFrom(stats);
+ stats->Clear();
}
void FillMallocStatistics(AsanMallocStats *malloc_stats) {
- BlockingMutexLock lock(&acc_stats_lock);
- UpdateAccumulatedStatsUnlocked();
- malloc_stats->blocks_in_use = accumulated_stats.mallocs;
- malloc_stats->size_in_use = accumulated_stats.malloced;
+ AsanStats stats;
+ GetAccumulatedStats(&stats);
+ malloc_stats->blocks_in_use = stats.mallocs;
+ malloc_stats->size_in_use = stats.malloced;
malloc_stats->max_size_in_use = max_malloced_memory;
- malloc_stats->size_allocated = accumulated_stats.mmaped;
+ malloc_stats->size_allocated = stats.mmaped;
}
AsanStats &GetCurrentThreadStats() {
@@ -132,36 +122,48 @@ AsanStats &GetCurrentThreadStats() {
return (t) ? t->stats() : unknown_thread_stats;
}
+static void PrintAccumulatedStats() {
+ AsanStats stats;
+ GetAccumulatedStats(&stats);
+ // Use lock to keep reports from mixing up.
+ 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);
+ PrintInternalAllocatorStats();
+}
+
} // namespace __asan
// ---------------------- Interface ---------------- {{{1
using namespace __asan; // NOLINT
uptr __asan_get_current_allocated_bytes() {
- BlockingMutexLock lock(&acc_stats_lock);
- UpdateAccumulatedStatsUnlocked();
- uptr malloced = accumulated_stats.malloced;
- uptr freed = accumulated_stats.freed;
+ AsanStats stats;
+ GetAccumulatedStats(&stats);
+ uptr malloced = stats.malloced;
+ uptr freed = stats.freed;
// Return sane value if malloced < freed due to racy
// way we update accumulated stats.
return (malloced > freed) ? malloced - freed : 1;
}
uptr __asan_get_heap_size() {
- BlockingMutexLock lock(&acc_stats_lock);
- UpdateAccumulatedStatsUnlocked();
- return accumulated_stats.mmaped - accumulated_stats.munmaped;
+ AsanStats stats;
+ GetAccumulatedStats(&stats);
+ return stats.mmaped - stats.munmaped;
}
uptr __asan_get_free_bytes() {
- BlockingMutexLock lock(&acc_stats_lock);
- UpdateAccumulatedStatsUnlocked();
- uptr total_free = accumulated_stats.mmaped
- - accumulated_stats.munmaped
- + accumulated_stats.really_freed
- + accumulated_stats.really_freed_redzones;
- uptr total_used = accumulated_stats.malloced
- + accumulated_stats.malloced_redzones;
+ AsanStats stats;
+ GetAccumulatedStats(&stats);
+ uptr total_free = stats.mmaped
+ - stats.munmaped
+ + stats.really_freed
+ + stats.really_freed_redzones;
+ uptr total_used = stats.malloced
+ + stats.malloced_redzones;
// Return sane value if total_free < total_used due to racy
// way we update accumulated stats.
return (total_free > total_used) ? total_free - total_used : 1;
diff --git a/lib/asan/asan_stats.h b/lib/asan/asan_stats.h
index 68495fb33f95..e3030e88fdc2 100644
--- a/lib/asan/asan_stats.h
+++ b/lib/asan/asan_stats.h
@@ -52,18 +52,16 @@ struct AsanStats {
// Default ctor for thread-local stats.
AsanStats();
- // Prints formatted stats to stderr.
- void Print();
+ void Print(); // Prints formatted stats to stderr.
+ void Clear();
+ void MergeFrom(const AsanStats *stats);
};
// Returns stats for GetCurrentThread(), or stats for fake "unknown thread"
// if GetCurrentThread() returns 0.
AsanStats &GetCurrentThreadStats();
-// Flushes all thread-local stats to accumulated stats, and makes
-// a copy of accumulated stats.
-void GetAccumulatedStats(AsanStats *stats);
-// Flushes a given stats into accumulated stats.
-void FlushToAccumulatedStats(AsanStats *stats);
+// Flushes a given stats into accumulated stats of dead threads.
+void FlushToDeadThreadStats(AsanStats *stats);
// A cross-platform equivalent of malloc_statistics_t on Mac OS.
struct AsanMallocStats {
diff --git a/lib/asan/asan_thread.cc b/lib/asan/asan_thread.cc
index da28381031a5..328ac2fcd398 100644
--- a/lib/asan/asan_thread.cc
+++ b/lib/asan/asan_thread.cc
@@ -19,6 +19,7 @@
#include "asan_mapping.h"
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_placement_new.h"
+#include "sanitizer_common/sanitizer_stackdepot.h"
#include "lsan/lsan_common.h"
namespace __asan {
@@ -27,9 +28,8 @@ namespace __asan {
void AsanThreadContext::OnCreated(void *arg) {
CreateThreadContextArgs *args = static_cast<CreateThreadContextArgs*>(arg);
- if (args->stack) {
- internal_memcpy(&stack, args->stack, sizeof(stack));
- }
+ if (args->stack)
+ stack_id = StackDepotPut(args->stack->trace, args->stack->size);
thread = args->thread;
thread->set_context(this);
}
@@ -39,12 +39,16 @@ void AsanThreadContext::OnFinished() {
thread = 0;
}
-static char thread_registry_placeholder[sizeof(ThreadRegistry)];
+// MIPS requires aligned address
+static ALIGNED(16) char thread_registry_placeholder[sizeof(ThreadRegistry)];
static ThreadRegistry *asan_thread_registry;
+static BlockingMutex mu_for_thread_context(LINKER_INITIALIZED);
+static LowLevelAllocator allocator_for_thread_context;
+
static ThreadContextBase *GetAsanThreadContext(u32 tid) {
- void *mem = MmapOrDie(sizeof(AsanThreadContext), "AsanThreadContext");
- return new(mem) AsanThreadContext(tid);
+ BlockingMutexLock lock(&mu_for_thread_context);
+ return new(allocator_for_thread_context) AsanThreadContext(tid);
}
ThreadRegistry &asanThreadRegistry() {
@@ -84,40 +88,68 @@ AsanThread *AsanThread::Create(thread_callback_t start_routine,
void AsanThread::TSDDtor(void *tsd) {
AsanThreadContext *context = (AsanThreadContext*)tsd;
- if (flags()->verbosity >= 1)
+ if (common_flags()->verbosity >= 1)
Report("T%d TSDDtor\n", context->tid);
if (context->thread)
context->thread->Destroy();
}
void AsanThread::Destroy() {
- if (flags()->verbosity >= 1) {
+ if (common_flags()->verbosity >= 1) {
Report("T%d exited\n", tid());
}
+ malloc_storage().CommitBack();
+ if (flags()->use_sigaltstack) UnsetAlternateSignalStack();
asanThreadRegistry().FinishThread(tid());
- FlushToAccumulatedStats(&stats_);
+ 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.
- ClearShadowForThreadStack();
- fake_stack().Cleanup();
+ ClearShadowForThreadStackAndTLS();
+ DeleteFakeStack();
uptr size = RoundUpTo(sizeof(AsanThread), GetPageSizeCached());
UnmapOrDie(this, size);
}
+// We want to create the FakeStack lazyly on the first use, but not eralier
+// than the stack size is known and the procedure has to be async-signal safe.
+FakeStack *AsanThread::AsyncSignalSafeLazyInitFakeStack() {
+ uptr stack_size = this->stack_size();
+ if (stack_size == 0) // stack_size is not yet available, don't use FakeStack.
+ return 0;
+ uptr old_val = 0;
+ // fake_stack_ has 3 states:
+ // 0 -- not initialized
+ // 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 (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);
+ fake_stack_ = FakeStack::Create(stack_size_log);
+ SetTLSFakeStack(fake_stack_);
+ return fake_stack_;
+ }
+ return 0;
+}
+
void AsanThread::Init() {
- SetThreadStackTopAndBottom();
+ SetThreadStackAndTls();
CHECK(AddrIsInMem(stack_bottom_));
CHECK(AddrIsInMem(stack_top_ - 1));
- ClearShadowForThreadStack();
- if (flags()->verbosity >= 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_.Init(stack_size());
+ fake_stack_ = 0; // Will be initialized lazily if needed.
AsanPlatformThreadInit();
}
@@ -135,22 +167,33 @@ thread_return_t AsanThread::ThreadStart(uptr os_id) {
}
thread_return_t res = start_routine_(arg_);
- malloc_storage().CommitBack();
- if (flags()->use_sigaltstack) UnsetAlternateSignalStack();
- this->Destroy();
+ // On POSIX systems we defer this to the TSD destructor. LSan will consider
+ // the thread's memory as non-live from the moment we call Destroy(), even
+ // though that memory might contain pointers to heap objects which will be
+ // cleaned up by a user-defined TSD destructor. Thus, calling Destroy() before
+ // the TSD destructors have run might cause false positives in LSan.
+ if (!SANITIZER_POSIX)
+ this->Destroy();
return res;
}
-void AsanThread::SetThreadStackTopAndBottom() {
- GetThreadStackTopAndBottom(tid() == 0, &stack_top_, &stack_bottom_);
+void AsanThread::SetThreadStackAndTls() {
+ uptr tls_size = 0;
+ GetThreadStackAndTls(tid() == 0, &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 AsanThread::ClearShadowForThreadStack() {
+void AsanThread::ClearShadowForThreadStackAndTLS() {
PoisonShadow(stack_bottom_, stack_top_ - stack_bottom_, 0);
+ if (tls_begin_ != tls_end_)
+ PoisonShadow(tls_begin_, tls_end_ - tls_begin_, 0);
}
const char *AsanThread::GetFrameNameByAddr(uptr addr, uptr *offset,
@@ -158,8 +201,8 @@ const char *AsanThread::GetFrameNameByAddr(uptr addr, uptr *offset,
uptr bottom = 0;
if (AddrIsInStack(addr)) {
bottom = stack_bottom();
- } else {
- bottom = fake_stack().AddrIsInFakeStack(addr);
+ } else if (has_fake_stack()) {
+ bottom = fake_stack()->AddrIsInFakeStack(addr);
CHECK(bottom);
*offset = addr - bottom;
*frame_pc = ((uptr*)bottom)[2];
@@ -195,13 +238,16 @@ static bool ThreadStackContainsAddress(ThreadContextBase *tctx_base,
void *addr) {
AsanThreadContext *tctx = static_cast<AsanThreadContext*>(tctx_base);
AsanThread *t = tctx->thread;
- return (t && t->fake_stack().StackSize() &&
- (t->fake_stack().AddrIsInFakeStack((uptr)addr) ||
- t->AddrIsInStack((uptr)addr)));
+ if (!t) return false;
+ if (t->AddrIsInStack((uptr)addr)) return true;
+ if (t->has_fake_stack() && t->fake_stack()->AddrIsInFakeStack((uptr)addr))
+ return true;
+ return false;
}
AsanThread *GetCurrentThread() {
- AsanThreadContext *context = (AsanThreadContext*)AsanTSDGet();
+ AsanThreadContext *context =
+ reinterpret_cast<AsanThreadContext *>(AsanTSDGet());
if (!context) {
if (SANITIZER_ANDROID) {
// On Android, libc constructor is called _after_ asan_init, and cleans up
@@ -222,7 +268,7 @@ AsanThread *GetCurrentThread() {
void SetCurrentThread(AsanThread *t) {
CHECK(t->context());
- if (flags()->verbosity >= 2) {
+ if (common_flags()->verbosity >= 2) {
Report("SetCurrentThread: %p for thread %p\n",
t->context(), (void*)GetThreadSelf());
}
@@ -244,6 +290,20 @@ AsanThread *FindThreadByStackAddress(uptr addr) {
(void *)addr));
return tctx ? tctx->thread : 0;
}
+
+void EnsureMainThreadIDIsCorrect() {
+ AsanThreadContext *context =
+ reinterpret_cast<AsanThreadContext *>(AsanTSDGet());
+ if (context && (context->tid == 0))
+ context->os_id = GetTid();
+}
+
+__asan::AsanThread *GetAsanThreadByOsIDLocked(uptr os_id) {
+ __asan::AsanThreadContext *context = static_cast<__asan::AsanThreadContext *>(
+ __asan::asanThreadRegistry().FindThreadContextByOsIDLocked(os_id));
+ if (!context) return 0;
+ return context->thread;
+}
} // namespace __asan
// --- Implementation of LSan-specific functions --- {{{1
@@ -251,8 +311,23 @@ namespace __lsan {
bool GetThreadRangesLocked(uptr os_id, uptr *stack_begin, uptr *stack_end,
uptr *tls_begin, uptr *tls_end,
uptr *cache_begin, uptr *cache_end) {
- // FIXME: Stub.
- return false;
+ __asan::AsanThread *t = __asan::GetAsanThreadByOsIDLocked(os_id);
+ if (!t) return false;
+ *stack_begin = t->stack_bottom();
+ *stack_end = t->stack_top();
+ *tls_begin = t->tls_begin();
+ *tls_end = t->tls_end();
+ // ASan doesn't keep allocator caches in TLS, so these are unused.
+ *cache_begin = 0;
+ *cache_end = 0;
+ return true;
+}
+
+void ForEachExtraStackRange(uptr os_id, RangeIteratorCallback callback,
+ void *arg) {
+ __asan::AsanThread *t = __asan::GetAsanThreadByOsIDLocked(os_id);
+ if (t && t->has_fake_stack())
+ t->fake_stack()->ForEachFakeFrame(callback, arg);
}
void LockThreadRegistry() {
@@ -262,4 +337,8 @@ void LockThreadRegistry() {
void UnlockThreadRegistry() {
__asan::asanThreadRegistry().Unlock();
}
+
+void EnsureMainThreadIDIsCorrect() {
+ __asan::EnsureMainThreadIDIsCorrect();
+}
} // namespace __lsan
diff --git a/lib/asan/asan_thread.h b/lib/asan/asan_thread.h
index 14062b62f751..11771ecd09f0 100644
--- a/lib/asan/asan_thread.h
+++ b/lib/asan/asan_thread.h
@@ -19,6 +19,7 @@
#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"
#include "sanitizer_common/sanitizer_thread_registry.h"
@@ -36,11 +37,13 @@ class AsanThreadContext : public ThreadContextBase {
explicit AsanThreadContext(int tid)
: ThreadContextBase(tid),
announced(false),
+ destructor_iterations(kPthreadDestructorIterations),
+ stack_id(0),
thread(0) {
- internal_memset(&stack, 0, sizeof(stack));
}
bool announced;
- StackTrace stack;
+ u8 destructor_iterations;
+ u32 stack_id;
AsanThread *thread;
void OnCreated(void *arg);
@@ -48,7 +51,7 @@ class AsanThreadContext : public ThreadContextBase {
};
// AsanThreadContext objects are never freed, so we need many of them.
-COMPILER_CHECK(sizeof(AsanThreadContext) <= 4096);
+COMPILER_CHECK(sizeof(AsanThreadContext) <= 256);
// AsanThread are stored in TSD and destroyed when the thread dies.
class AsanThread {
@@ -62,7 +65,9 @@ class AsanThread {
uptr stack_top() { return stack_top_; }
uptr stack_bottom() { return stack_bottom_; }
- uptr stack_size() { return stack_top_ - stack_bottom_; }
+ uptr stack_size() { return stack_size_; }
+ uptr tls_begin() { return tls_begin_; }
+ uptr tls_end() { return tls_end_; }
u32 tid() { return context_->tid; }
AsanThreadContext *context() { return context_; }
void set_context(AsanThreadContext *context) { context_ = context; }
@@ -73,23 +78,68 @@ class AsanThread {
return addr >= stack_bottom_ && addr < stack_top_;
}
- FakeStack &fake_stack() { return fake_stack_; }
+ void DeleteFakeStack() {
+ if (!fake_stack_) return;
+ FakeStack *t = fake_stack_;
+ fake_stack_ = 0;
+ SetTLSFakeStack(0);
+ t->Destroy();
+ }
+
+ bool has_fake_stack() {
+ return (reinterpret_cast<uptr>(fake_stack_) > 1);
+ }
+
+ FakeStack *fake_stack() {
+ if (!__asan_option_detect_stack_use_after_return)
+ return 0;
+ if (!has_fake_stack())
+ return AsyncSignalSafeLazyInitFakeStack();
+ return fake_stack_;
+ }
+
+ // 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; }
+
AsanThreadLocalMallocStorage &malloc_storage() { return malloc_storage_; }
AsanStats &stats() { return stats_; }
private:
- AsanThread() {}
- void SetThreadStackTopAndBottom();
- void ClearShadowForThreadStack();
+ AsanThread() : unwinding(false) {}
+ void SetThreadStackAndTls();
+ void ClearShadowForThreadStackAndTLS();
+ FakeStack *AsyncSignalSafeLazyInitFakeStack();
+
AsanThreadContext *context_;
thread_callback_t start_routine_;
void *arg_;
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 tls_begin_;
+ uptr tls_end_;
- FakeStack fake_stack_;
+ FakeStack *fake_stack_;
AsanThreadLocalMallocStorage malloc_storage_;
AsanStats stats_;
+ bool unwinding;
+};
+
+// ScopedUnwinding is a scope for stacktracing member of a context
+class ScopedUnwinding {
+ public:
+ explicit ScopedUnwinding(AsanThread *t) : thread(t) {
+ t->setUnwinding(true);
+ }
+ ~ScopedUnwinding() { thread->setUnwinding(false); }
+
+ private:
+ AsanThread *thread;
};
struct CreateThreadContextArgs {
@@ -109,6 +159,8 @@ void SetCurrentThread(AsanThread *t);
u32 GetCurrentTidOrInvalid();
AsanThread *FindThreadByStackAddress(uptr addr);
+// Used to handle fork().
+void EnsureMainThreadIDIsCorrect();
} // namespace __asan
#endif // ASAN_THREAD_H
diff --git a/lib/asan/asan_win.cc b/lib/asan/asan_win.cc
index f74de7227ed2..9e66b3417a1e 100644
--- a/lib/asan/asan_win.cc
+++ b/lib/asan/asan_win.cc
@@ -25,6 +25,14 @@
#include "sanitizer_common/sanitizer_libc.h"
#include "sanitizer_common/sanitizer_mutex.h"
+extern "C" {
+ SANITIZER_INTERFACE_ATTRIBUTE
+ int __asan_should_detect_stack_use_after_return() {
+ __asan_init();
+ return __asan_option_detect_stack_use_after_return;
+ }
+}
+
namespace __asan {
// ---------------------- Stacktraces, symbols, etc. ---------------- {{{1
@@ -52,6 +60,9 @@ void AsanTSDSet(void *tsd) {
fake_tsd = tsd;
}
+void PlatformTSDDtor(void *tsd) {
+ AsanThread::TSDDtor(tsd);
+}
// ---------------------- Various stuff ---------------- {{{1
void MaybeReexec() {
// No need to re-exec on Windows.
diff --git a/lib/asan/lit_tests/32bitConfig/lit.site.cfg.in b/lib/asan/lit_tests/32bitConfig/lit.site.cfg.in
new file mode 100644
index 000000000000..faef4e8c9b17
--- /dev/null
+++ b/lib/asan/lit_tests/32bitConfig/lit.site.cfg.in
@@ -0,0 +1,13 @@
+## 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
new file mode 100644
index 000000000000..a35994484d5f
--- /dev/null
+++ b/lib/asan/lit_tests/64bitConfig/lit.site.cfg.in
@@ -0,0 +1,12 @@
+## 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
index d2420b50da83..72a3f5439b70 100644
--- a/lib/asan/lit_tests/CMakeLists.txt
+++ b/lib/asan/lit_tests/CMakeLists.txt
@@ -2,8 +2,13 @@ set(ASAN_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/..)
set(ASAN_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
+ ${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(
@@ -12,21 +17,26 @@ configure_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}
- asan_blacklist)
+ asan_runtime_libraries)
set(ASAN_TEST_PARAMS
- asan_site_config=${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg
- )
+ 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"
- ${CMAKE_CURRENT_BINARY_DIR}
+ ${ASAN_TESTSUITES}
PARAMS ${ASAN_TEST_PARAMS}
- DEPENDS ${ASAN_TEST_DEPS}
- )
+ DEPENDS ${ASAN_TEST_DEPS})
set_target_properties(check-asan PROPERTIES FOLDER "ASan tests")
endif()
diff --git a/lib/asan/lit_tests/Darwin/unset-insert-libraries-on-exec.cc b/lib/asan/lit_tests/Darwin/unset-insert-libraries-on-exec.cc
deleted file mode 100644
index cf89949cf942..000000000000
--- a/lib/asan/lit_tests/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 -m64 %s -o %t
-// RUN: %clangxx -m64 %p/../SharedLibs/darwin-dummy-shared-lib-so.cc \
-// RUN: -dynamiclib -o darwin-dummy-shared-lib-so.dylib
-
-// Make sure DYLD_INSERT_LIBRARIES doesn't contain the runtime library before
-// execl().
-
-// RUN: %t >/dev/null 2>&1
-// RUN: DYLD_INSERT_LIBRARIES=darwin-dummy-shared-lib-so.dylib \
-// RUN: %t 2>&1 | FileCheck %s || exit 1
-#include <unistd.h>
-int main() {
- execl("/bin/bash", "/bin/bash", "-c",
- "echo DYLD_INSERT_LIBRARIES=$DYLD_INSERT_LIBRARIES", NULL);
- // CHECK: {{DYLD_INSERT_LIBRARIES=.*darwin-dummy-shared-lib-so.dylib.*}}
- return 0;
-}
diff --git a/lib/asan/lit_tests/Helpers/initialization-blacklist.txt b/lib/asan/lit_tests/Helpers/initialization-blacklist.txt
deleted file mode 100644
index fa4a83667f4b..000000000000
--- a/lib/asan/lit_tests/Helpers/initialization-blacklist.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-global-init:*badGlobal*
-global-init-type:*badNamespace::BadClass*
-global-init-src:*initialization-blacklist-extra2.cc
diff --git a/lib/asan/lit_tests/Linux/interception_failure_test.cc b/lib/asan/lit_tests/Linux/interception_failure_test.cc
deleted file mode 100644
index dfad909f528c..000000000000
--- a/lib/asan/lit_tests/Linux/interception_failure_test.cc
+++ /dev/null
@@ -1,26 +0,0 @@
-// If user provides his own libc functions, ASan doesn't
-// intercept these functions.
-
-// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m64 -O1 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m64 -O2 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m64 -O3 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m32 -O0 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m32 -O1 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m32 -O2 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m32 -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/Linux/interception_malloc_test.cc b/lib/asan/lit_tests/Linux/interception_malloc_test.cc
deleted file mode 100644
index 8f66788e9a82..000000000000
--- a/lib/asan/lit_tests/Linux/interception_malloc_test.cc
+++ /dev/null
@@ -1,27 +0,0 @@
-// ASan interceptor can be accessed with __interceptor_ prefix.
-
-// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m64 -O1 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m64 -O2 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m64 -O3 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m32 -O0 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m32 -O1 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m32 -O2 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m32 -O3 %s -o %t && %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/Linux/interception_test.cc b/lib/asan/lit_tests/Linux/interception_test.cc
deleted file mode 100644
index 94fb499f2f87..000000000000
--- a/lib/asan/lit_tests/Linux/interception_test.cc
+++ /dev/null
@@ -1,26 +0,0 @@
-// ASan interceptor can be accessed with __interceptor_ prefix.
-
-// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m64 -O1 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m64 -O2 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m64 -O3 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m32 -O0 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m32 -O1 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m32 -O2 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m32 -O3 %s -o %t && %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/Linux/zero-base-shadow.cc b/lib/asan/lit_tests/Linux/zero-base-shadow.cc
deleted file mode 100644
index 682e7e8d7e59..000000000000
--- a/lib/asan/lit_tests/Linux/zero-base-shadow.cc
+++ /dev/null
@@ -1,31 +0,0 @@
-// RUN: %clangxx_asan -m64 -O0 -fsanitize-address-zero-base-shadow -fPIE -pie %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-64 < %t.out
-// RUN: %clangxx_asan -m64 -O1 -fsanitize-address-zero-base-shadow -fPIE -pie %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-64 < %t.out
-// RUN: %clangxx_asan -m64 -O2 -fsanitize-address-zero-base-shadow -fPIE -pie %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-64 < %t.out
-// RUN: %clangxx_asan -m32 -O0 -fsanitize-address-zero-base-shadow -fPIE -pie %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-32 < %t.out
-// RUN: %clangxx_asan -m32 -O1 -fsanitize-address-zero-base-shadow -fPIE -pie %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-32 < %t.out
-// RUN: %clangxx_asan -m32 -O2 -fsanitize-address-zero-base-shadow -fPIE -pie %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-32 < %t.out
-
-// Zero-base shadow only works on x86_64 and i386.
-// REQUIRES: x86_64-supported-target,i386-supported-target
-
-#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-shadow.cc:}}[[@LINE-2]]
- // CHECK: {{Address 0x.* is .* frame}}
- // CHECK: main
-
- // Check that shadow for stack memory occupies lower part of address space.
- // CHECK-64: =>0x0f
- // CHECK-32: =>0x1
- return res;
-}
diff --git a/lib/asan/lit_tests/Darwin/interface_symbols_darwin.c b/lib/asan/lit_tests/TestCases/Darwin/interface_symbols_darwin.c
index 3fca6e915324..b453b64cafd2 100644
--- a/lib/asan/lit_tests/Darwin/interface_symbols_darwin.c
+++ b/lib/asan/lit_tests/TestCases/Darwin/interface_symbols_darwin.c
@@ -2,7 +2,7 @@
// If you're changing this file, please also change
// ../Linux/interface_symbols.c
-// RUN: %clang -fsanitize=address -dead_strip -O2 %s -o %t.exe
+// 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" | \
@@ -16,7 +16,7 @@
// RUN: | grep -v "__asan_default_options" \
// RUN: | grep -v "__asan_on_error" > %t.symbols
-// RUN: cat %p/../../asan_interface_internal.h \
+// 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/(.*//" \
@@ -33,6 +33,8 @@
// 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 -
diff --git a/lib/asan/lit_tests/Darwin/lit.local.cfg b/lib/asan/lit_tests/TestCases/Darwin/lit.local.cfg
index a85dfcd24c08..a85dfcd24c08 100644
--- a/lib/asan/lit_tests/Darwin/lit.local.cfg
+++ b/lib/asan/lit_tests/TestCases/Darwin/lit.local.cfg
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
new file mode 100644
index 000000000000..807a8283e788
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Darwin/malloc_set_zone_name-mprotect.cc
@@ -0,0 +1,51 @@
+// 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
new file mode 100644
index 000000000000..d5f6c7c12e67
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Darwin/malloc_zone-protected.cc
@@ -0,0 +1,20 @@
+// 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/Darwin/reexec-insert-libraries-env.cc b/lib/asan/lit_tests/TestCases/Darwin/reexec-insert-libraries-env.cc
index 40a459fd84db..208fe43ac7e4 100644
--- a/lib/asan/lit_tests/Darwin/reexec-insert-libraries-env.cc
+++ b/lib/asan/lit_tests/TestCases/Darwin/reexec-insert-libraries-env.cc
@@ -2,8 +2,8 @@
// This is a regression test for
// https://code.google.com/p/address-sanitizer/issues/detail?id=159
-// RUN: %clangxx_asan -m64 %s -o %t
-// RUN: %clangxx -m64 %p/../SharedLibs/darwin-dummy-shared-lib-so.cc \
+// 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.
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
new file mode 100644
index 000000000000..fa0dd4f9df88
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Darwin/unset-insert-libraries-on-exec.cc
@@ -0,0 +1,20 @@
+// 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/Helpers/blacklist-extra.cc b/lib/asan/lit_tests/TestCases/Helpers/blacklist-extra.cc
index 627115cdda2b..627115cdda2b 100644
--- a/lib/asan/lit_tests/Helpers/blacklist-extra.cc
+++ b/lib/asan/lit_tests/TestCases/Helpers/blacklist-extra.cc
diff --git a/lib/asan/lit_tests/TestCases/Helpers/echo-env.cc b/lib/asan/lit_tests/TestCases/Helpers/echo-env.cc
new file mode 100644
index 000000000000..65e91c155c84
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Helpers/echo-env.cc
@@ -0,0 +1,19 @@
+// 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/Helpers/init-order-atexit-extra.cc b/lib/asan/lit_tests/TestCases/Helpers/init-order-atexit-extra.cc
index e4189d19d099..e4189d19d099 100644
--- a/lib/asan/lit_tests/Helpers/init-order-atexit-extra.cc
+++ b/lib/asan/lit_tests/TestCases/Helpers/init-order-atexit-extra.cc
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
new file mode 100644
index 000000000000..d4606f0afb52
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Helpers/init-order-pthread-create-extra.cc
@@ -0,0 +1,2 @@
+void *bar(void *input);
+void *glob2 = bar((void*)0x2345);
diff --git a/lib/asan/lit_tests/Helpers/initialization-blacklist-extra.cc b/lib/asan/lit_tests/TestCases/Helpers/initialization-blacklist-extra.cc
index 09aed2112d5e..09aed2112d5e 100644
--- a/lib/asan/lit_tests/Helpers/initialization-blacklist-extra.cc
+++ b/lib/asan/lit_tests/TestCases/Helpers/initialization-blacklist-extra.cc
diff --git a/lib/asan/lit_tests/Helpers/initialization-blacklist-extra2.cc b/lib/asan/lit_tests/TestCases/Helpers/initialization-blacklist-extra2.cc
index 69455a0a6fc9..69455a0a6fc9 100644
--- a/lib/asan/lit_tests/Helpers/initialization-blacklist-extra2.cc
+++ b/lib/asan/lit_tests/TestCases/Helpers/initialization-blacklist-extra2.cc
diff --git a/lib/asan/lit_tests/TestCases/Helpers/initialization-blacklist.txt b/lib/asan/lit_tests/TestCases/Helpers/initialization-blacklist.txt
new file mode 100644
index 000000000000..83294635622d
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Helpers/initialization-blacklist.txt
@@ -0,0 +1,3 @@
+global:*badGlobal*=init
+type:*badNamespace::BadClass*=init
+src:*initialization-blacklist-extra2.cc=init
diff --git a/lib/asan/lit_tests/Helpers/initialization-bug-extra.cc b/lib/asan/lit_tests/TestCases/Helpers/initialization-bug-extra.cc
index 3c4cb411defa..3c4cb411defa 100644
--- a/lib/asan/lit_tests/Helpers/initialization-bug-extra.cc
+++ b/lib/asan/lit_tests/TestCases/Helpers/initialization-bug-extra.cc
diff --git a/lib/asan/lit_tests/Helpers/initialization-bug-extra2.cc b/lib/asan/lit_tests/TestCases/Helpers/initialization-bug-extra2.cc
index a3d8f190e58b..a3d8f190e58b 100644
--- a/lib/asan/lit_tests/Helpers/initialization-bug-extra2.cc
+++ b/lib/asan/lit_tests/TestCases/Helpers/initialization-bug-extra2.cc
diff --git a/lib/asan/lit_tests/Helpers/initialization-constexpr-extra.cc b/lib/asan/lit_tests/TestCases/Helpers/initialization-constexpr-extra.cc
index b32466a981b3..b32466a981b3 100644
--- a/lib/asan/lit_tests/Helpers/initialization-constexpr-extra.cc
+++ b/lib/asan/lit_tests/TestCases/Helpers/initialization-constexpr-extra.cc
diff --git a/lib/asan/lit_tests/Helpers/initialization-nobug-extra.cc b/lib/asan/lit_tests/TestCases/Helpers/initialization-nobug-extra.cc
index 886165affd76..886165affd76 100644
--- a/lib/asan/lit_tests/Helpers/initialization-nobug-extra.cc
+++ b/lib/asan/lit_tests/TestCases/Helpers/initialization-nobug-extra.cc
diff --git a/lib/asan/lit_tests/Helpers/lit.local.cfg b/lib/asan/lit_tests/TestCases/Helpers/lit.local.cfg
index 2fc4d99456b0..2fc4d99456b0 100644
--- a/lib/asan/lit_tests/Helpers/lit.local.cfg
+++ b/lib/asan/lit_tests/TestCases/Helpers/lit.local.cfg
diff --git a/lib/asan/lit_tests/Linux/asan_prelink_test.cc b/lib/asan/lit_tests/TestCases/Linux/asan_prelink_test.cc
index c209c39c8c42..0f158c1bb3dd 100644
--- a/lib/asan/lit_tests/Linux/asan_prelink_test.cc
+++ b/lib/asan/lit_tests/TestCases/Linux/asan_prelink_test.cc
@@ -3,13 +3,13 @@
// or gold's flag -Ttext (we try the first flag first, if that fails we
// try the second flag).
//
-// RUN: %clangxx_asan -m64 -c %s -o %t.o
-// RUN: %clangxx_asan -m64 -DBUILD_SO=1 -fPIC -shared %s -o %t.so -Wl,-Ttext-segment=0x3600000000 ||\
-// RUN: %clangxx_asan -m64 -DBUILD_SO=1 -fPIC -shared %s -o %t.so -Wl,-Ttext=0x3600000000
-// RUN: %clangxx_asan -m64 %t.o %t.so -Wl,-R. -o %t
+// 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
+// REQUIRES: x86_64-supported-target, asan-64-bits
#if BUILD_SO
int G;
int *getG() {
diff --git a/lib/asan/lit_tests/Linux/clone_test.cc b/lib/asan/lit_tests/TestCases/Linux/clone_test.cc
index ca13b22425f2..0e12f35b400a 100644
--- a/lib/asan/lit_tests/Linux/clone_test.cc
+++ b/lib/asan/lit_tests/TestCases/Linux/clone_test.cc
@@ -1,14 +1,10 @@
// Regression test for:
// http://code.google.com/p/address-sanitizer/issues/detail?id=37
-// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t | FileCheck %s
-// RUN: %clangxx_asan -m64 -O1 %s -o %t && %t | FileCheck %s
-// RUN: %clangxx_asan -m64 -O2 %s -o %t && %t | FileCheck %s
-// RUN: %clangxx_asan -m64 -O3 %s -o %t && %t | FileCheck %s
-// RUN: %clangxx_asan -m32 -O0 %s -o %t && %t | FileCheck %s
-// RUN: %clangxx_asan -m32 -O1 %s -o %t && %t | FileCheck %s
-// RUN: %clangxx_asan -m32 -O2 %s -o %t && %t | FileCheck %s
-// RUN: %clangxx_asan -m32 -O3 %s -o %t && %t | FileCheck %s
+// 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>
diff --git a/lib/asan/lit_tests/TestCases/Linux/coverage.cc b/lib/asan/lit_tests/TestCases/Linux/coverage.cc
new file mode 100644
index 000000000000..4373e9b13c68
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Linux/coverage.cc
@@ -0,0 +1,45 @@
+// 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/Linux/glob.cc b/lib/asan/lit_tests/TestCases/Linux/glob.cc
index e05228ff39e3..123768b099ed 100644
--- a/lib/asan/lit_tests/Linux/glob.cc
+++ b/lib/asan/lit_tests/TestCases/Linux/glob.cc
@@ -1,7 +1,5 @@
-// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t %p 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m64 -O3 %s -o %t && %t %p 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m32 -O0 %s -o %t && %t %p 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m32 -O3 %s -o %t && %t %p 2>&1 | FileCheck %s
+// 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>
@@ -24,6 +22,7 @@ int main(int argc, char *argv[]) {
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/Linux/glob_test_root/aa b/lib/asan/lit_tests/TestCases/Linux/glob_test_root/aa
index e69de29bb2d1..e69de29bb2d1 100644
--- a/lib/asan/lit_tests/Linux/glob_test_root/aa
+++ b/lib/asan/lit_tests/TestCases/Linux/glob_test_root/aa
diff --git a/lib/asan/lit_tests/Linux/glob_test_root/ab b/lib/asan/lit_tests/TestCases/Linux/glob_test_root/ab
index e69de29bb2d1..e69de29bb2d1 100644
--- a/lib/asan/lit_tests/Linux/glob_test_root/ab
+++ b/lib/asan/lit_tests/TestCases/Linux/glob_test_root/ab
diff --git a/lib/asan/lit_tests/Linux/glob_test_root/ba b/lib/asan/lit_tests/TestCases/Linux/glob_test_root/ba
index e69de29bb2d1..e69de29bb2d1 100644
--- a/lib/asan/lit_tests/Linux/glob_test_root/ba
+++ b/lib/asan/lit_tests/TestCases/Linux/glob_test_root/ba
diff --git a/lib/asan/lit_tests/TestCases/Linux/heap-overflow-large.cc b/lib/asan/lit_tests/TestCases/Linux/heap-overflow-large.cc
new file mode 100644
index 000000000000..67e9c3718d59
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Linux/heap-overflow-large.cc
@@ -0,0 +1,23 @@
+// 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/Linux/heavy_uar_test.cc b/lib/asan/lit_tests/TestCases/Linux/heavy_uar_test.cc
index c0f4560fb4e7..27b179e83624 100644
--- a/lib/asan/lit_tests/Linux/heavy_uar_test.cc
+++ b/lib/asan/lit_tests/TestCases/Linux/heavy_uar_test.cc
@@ -1,9 +1,8 @@
-// RUN: %clangxx_asan -fsanitize=use-after-return -m64 -O0 %s -o %t && \
-// RUN: %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -fsanitize=use-after-return -m64 -O2 %s -o %t && \
-// RUN: %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -fsanitize=use-after-return -m32 -O2 %s -o %t && \
-// RUN: %t 2>&1 | %symbolize | FileCheck %s
+// 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>
diff --git a/lib/asan/lit_tests/Linux/initialization-bug-any-order.cc b/lib/asan/lit_tests/TestCases/Linux/initialization-bug-any-order.cc
index 4f41dda18128..042a07e428d9 100644
--- a/lib/asan/lit_tests/Linux/initialization-bug-any-order.cc
+++ b/lib/asan/lit_tests/TestCases/Linux/initialization-bug-any-order.cc
@@ -3,12 +3,10 @@
// independently on order in which we list source files (if we specify
// strict init-order checking).
-// RUN: %clangxx_asan -m64 -O0 %s %p/../Helpers/initialization-bug-extra.cc -o %t
-// RUN: ASAN_OPTIONS=check_initialization_order=true:strict_init_order=true %t 2>&1 \
-// RUN: | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m64 -O0 %p/../Helpers/initialization-bug-extra.cc %s -o %t
-// RUN: ASAN_OPTIONS=check_initialization_order=true:strict_init_order=true %t 2>&1 \
-// RUN: | %symbolize | FileCheck %s
+// 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.
diff --git a/lib/asan/lit_tests/TestCases/Linux/interception_failure_test.cc b/lib/asan/lit_tests/TestCases/Linux/interception_failure_test.cc
new file mode 100644
index 000000000000..9d161aa2dccb
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Linux/interception_failure_test.cc
@@ -0,0 +1,22 @@
+// 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
new file mode 100644
index 000000000000..cdd7239ab7bc
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Linux/interception_malloc_test.cc
@@ -0,0 +1,23 @@
+// 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
new file mode 100644
index 000000000000..198e1f3884dd
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Linux/interception_readdir_r_test.cc
@@ -0,0 +1,59 @@
+// 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
new file mode 100644
index 000000000000..2b3316d7dc8a
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Linux/interception_test.cc
@@ -0,0 +1,22 @@
+// 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/Linux/interface_symbols_linux.c b/lib/asan/lit_tests/TestCases/Linux/interface_symbols_linux.c
index 4134c8744043..d6ceda7af8b6 100644
--- a/lib/asan/lit_tests/Linux/interface_symbols_linux.c
+++ b/lib/asan/lit_tests/TestCases/Linux/interface_symbols_linux.c
@@ -1,14 +1,15 @@
// Check the presense of interface symbols in compiled file.
-// RUN: %clang -fsanitize=address -O2 %s -o %t.exe
+// 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: cat %p/../../../asan_interface_internal.h \
// RUN: | sed "s/\/\/.*//" | sed "s/typedef.*//" \
// RUN: | grep -v "OPTIONAL" \
// RUN: | grep "__asan_.*(" | sed "s/.* __asan_/__asan_/;s/(.*//" \
diff --git a/lib/asan/lit_tests/Linux/lit.local.cfg b/lib/asan/lit_tests/TestCases/Linux/lit.local.cfg
index 57271b8078a4..57271b8078a4 100644
--- a/lib/asan/lit_tests/Linux/lit.local.cfg
+++ b/lib/asan/lit_tests/TestCases/Linux/lit.local.cfg
diff --git a/lib/asan/lit_tests/Linux/malloc-in-qsort.cc b/lib/asan/lit_tests/TestCases/Linux/malloc-in-qsort.cc
index ee2e81f0d2ab..3251b35e143c 100644
--- a/lib/asan/lit_tests/Linux/malloc-in-qsort.cc
+++ b/lib/asan/lit_tests/TestCases/Linux/malloc-in-qsort.cc
@@ -1,6 +1,6 @@
-// RUN: %clangxx_asan -m64 -O2 %s -o %t
-// RUN: ASAN_OPTIONS=fast_unwind_on_malloc=1 %t 2>&1 | %symbolize | FileCheck %s --check-prefix=CHECK-FAST
-// RUN: ASAN_OPTIONS=fast_unwind_on_malloc=0 %t 2>&1 | %symbolize | FileCheck %s --check-prefix=CHECK-SLOW
+// 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).
@@ -9,6 +9,8 @@
// 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>
diff --git a/lib/asan/lit_tests/Linux/malloc_delete_mismatch.cc b/lib/asan/lit_tests/TestCases/Linux/malloc_delete_mismatch.cc
index f34b33a38fb3..7010eb2de2e7 100644
--- a/lib/asan/lit_tests/Linux/malloc_delete_mismatch.cc
+++ b/lib/asan/lit_tests/TestCases/Linux/malloc_delete_mismatch.cc
@@ -2,11 +2,16 @@
// is set.
// RUN: %clangxx_asan -g %s -o %t 2>&1
-// RUN: ASAN_OPTIONS=alloc_dealloc_mismatch=1 %t 2>&1 | \
-// RUN: %symbolize | FileCheck %s
+
+// 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;
@@ -21,6 +26,6 @@ int main() {
// CHECK: #{{.*}}main
// CHECK: is located 0 bytes inside of 10-byte region
// CHECK-NEXT: allocated by thread T0 here:
-// CHECK-NEXT: #0{{.*}}malloc
-// CHECK: #{{.*}}main
+// 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/Linux/overflow-in-qsort.cc b/lib/asan/lit_tests/TestCases/Linux/overflow-in-qsort.cc
index 8bc43ca0a5c3..139977261ec9 100644
--- a/lib/asan/lit_tests/Linux/overflow-in-qsort.cc
+++ b/lib/asan/lit_tests/TestCases/Linux/overflow-in-qsort.cc
@@ -1,6 +1,6 @@
-// RUN: %clangxx_asan -m64 -O2 %s -o %t
-// RUN: ASAN_OPTIONS=fast_unwind_on_fatal=1 %t 2>&1 | %symbolize | FileCheck %s --check-prefix=CHECK-FAST
-// RUN: ASAN_OPTIONS=fast_unwind_on_fatal=0 %t 2>&1 | %symbolize | FileCheck %s --check-prefix=CHECK-SLOW
+// 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).
diff --git a/lib/asan/lit_tests/Linux/preinit_test.cc b/lib/asan/lit_tests/TestCases/Linux/preinit_test.cc
index 28e509472c0c..28e509472c0c 100644
--- a/lib/asan/lit_tests/Linux/preinit_test.cc
+++ b/lib/asan/lit_tests/TestCases/Linux/preinit_test.cc
diff --git a/lib/asan/lit_tests/TestCases/Linux/ptrace.cc b/lib/asan/lit_tests/TestCases/Linux/ptrace.cc
new file mode 100644
index 000000000000..8831b81efa96
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Linux/ptrace.cc
@@ -0,0 +1,52 @@
+// 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/Linux/rlimit_mmap_test.cc b/lib/asan/lit_tests/TestCases/Linux/rlimit_mmap_test.cc
index 86794756c76f..0d1d4baa7671 100644
--- a/lib/asan/lit_tests/Linux/rlimit_mmap_test.cc
+++ b/lib/asan/lit_tests/TestCases/Linux/rlimit_mmap_test.cc
@@ -1,5 +1,5 @@
// Check that we properly report mmap failure.
-// RUN: %clangxx_asan %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan %s -o %t && not %t 2>&1 | FileCheck %s
#include <stdlib.h>
#include <assert.h>
#include <sys/time.h>
diff --git a/lib/asan/lit_tests/Linux/swapcontext_test.cc b/lib/asan/lit_tests/TestCases/Linux/swapcontext_test.cc
index 47a8d9891f51..6cbb69a35321 100644
--- a/lib/asan/lit_tests/Linux/swapcontext_test.cc
+++ b/lib/asan/lit_tests/TestCases/Linux/swapcontext_test.cc
@@ -1,13 +1,9 @@
// Check that ASan plays well with easy cases of makecontext/swapcontext.
-// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m64 -O1 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m64 -O2 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m64 -O3 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m32 -O0 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m32 -O1 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m32 -O2 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m32 -O3 %s -o %t && %t 2>&1 | FileCheck %s
+// 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
diff --git a/lib/asan/lit_tests/Linux/syscalls.cc b/lib/asan/lit_tests/TestCases/Linux/syscalls.cc
index b2edcfb92375..4bcbe446113e 100644
--- a/lib/asan/lit_tests/Linux/syscalls.cc
+++ b/lib/asan/lit_tests/TestCases/Linux/syscalls.cc
@@ -1,5 +1,5 @@
-// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m64 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
+// 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>
@@ -17,6 +17,6 @@ int main(int argc, char *argv[]) {
__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_pre_recvmsg
+ // CHECK: #0 {{.*}} in __sanitizer_syscall{{.*}}recvmsg
return 0;
}
diff --git a/lib/asan/lit_tests/Linux/time_null_regtest.cc b/lib/asan/lit_tests/TestCases/Linux/time_null_regtest.cc
index 975bca3d105a..566409be6a19 100644
--- a/lib/asan/lit_tests/Linux/time_null_regtest.cc
+++ b/lib/asan/lit_tests/TestCases/Linux/time_null_regtest.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_asan -m64 -O0 %s -fsanitize-address-zero-base-shadow -pie -o %t && %t 2>&1 | %symbolize | FileCheck %s
+// 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
diff --git a/lib/asan/lit_tests/TestCases/Linux/tsd_dtor_leak.cc b/lib/asan/lit_tests/TestCases/Linux/tsd_dtor_leak.cc
new file mode 100644
index 000000000000..a1d89ee437d4
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Linux/tsd_dtor_leak.cc
@@ -0,0 +1,39 @@
+// 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
new file mode 100644
index 000000000000..9663859dfefd
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Linux/uar_signals.cc
@@ -0,0 +1,70 @@
+// 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
new file mode 100644
index 000000000000..d67c4f954e43
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Linux/unpoison_tls.cc
@@ -0,0 +1,35 @@
+// 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
new file mode 100644
index 000000000000..e6bcc5597471
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Linux/zero-base-shadow32.cc
@@ -0,0 +1,24 @@
+// 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
new file mode 100644
index 000000000000..1db725c95752
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Linux/zero-base-shadow64.cc
@@ -0,0 +1,24 @@
+// 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/SharedLibs/darwin-dummy-shared-lib-so.cc b/lib/asan/lit_tests/TestCases/SharedLibs/darwin-dummy-shared-lib-so.cc
index 5d939991476e..5d939991476e 100644
--- a/lib/asan/lit_tests/SharedLibs/darwin-dummy-shared-lib-so.cc
+++ b/lib/asan/lit_tests/TestCases/SharedLibs/darwin-dummy-shared-lib-so.cc
diff --git a/lib/asan/lit_tests/SharedLibs/dlclose-test-so.cc b/lib/asan/lit_tests/TestCases/SharedLibs/dlclose-test-so.cc
index 73e00507358a..73e00507358a 100644
--- a/lib/asan/lit_tests/SharedLibs/dlclose-test-so.cc
+++ b/lib/asan/lit_tests/TestCases/SharedLibs/dlclose-test-so.cc
diff --git a/lib/asan/lit_tests/SharedLibs/init-order-dlopen-so.cc b/lib/asan/lit_tests/TestCases/SharedLibs/init-order-dlopen-so.cc
index 20ef2d8a00bb..dc097a520d03 100644
--- a/lib/asan/lit_tests/SharedLibs/init-order-dlopen-so.cc
+++ b/lib/asan/lit_tests/TestCases/SharedLibs/init-order-dlopen-so.cc
@@ -1,7 +1,7 @@
#include <stdio.h>
#include <unistd.h>
-void inc_global();
+extern "C" void inc_global();
int slow_init() {
sleep(1);
diff --git a/lib/asan/lit_tests/SharedLibs/lit.local.cfg b/lib/asan/lit_tests/TestCases/SharedLibs/lit.local.cfg
index b3677c17a0f2..b3677c17a0f2 100644
--- a/lib/asan/lit_tests/SharedLibs/lit.local.cfg
+++ b/lib/asan/lit_tests/TestCases/SharedLibs/lit.local.cfg
diff --git a/lib/asan/lit_tests/SharedLibs/shared-lib-test-so.cc b/lib/asan/lit_tests/TestCases/SharedLibs/shared-lib-test-so.cc
index 686a24578082..6ef565ce47b3 100644
--- a/lib/asan/lit_tests/SharedLibs/shared-lib-test-so.cc
+++ b/lib/asan/lit_tests/TestCases/SharedLibs/shared-lib-test-so.cc
@@ -19,3 +19,8 @@ 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
new file mode 100644
index 000000000000..595c9e252f86
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/allocator_returns_null.cc
@@ -0,0 +1,81 @@
+// 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/allow_user_segv.cc b/lib/asan/lit_tests/TestCases/allow_user_segv.cc
index f8aed0d4ca80..55cf6044e7a0 100644
--- a/lib/asan/lit_tests/allow_user_segv.cc
+++ b/lib/asan/lit_tests/TestCases/allow_user_segv.cc
@@ -1,10 +1,8 @@
// Regression test for
// https://code.google.com/p/address-sanitizer/issues/detail?id=180
-// RUN: %clangxx_asan -m64 -O0 %s -o %t && ASAN_OPTIONS=allow_user_segv_handler=true %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m64 -O2 %s -o %t && ASAN_OPTIONS=allow_user_segv_handler=true %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m32 -O0 %s -o %t && ASAN_OPTIONS=allow_user_segv_handler=true %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m32 -O2 %s -o %t && ASAN_OPTIONS=allow_user_segv_handler=true %t 2>&1 | FileCheck %s
+// 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>
diff --git a/lib/asan/lit_tests/TestCases/asan-symbolize-sanity-test.cc b/lib/asan/lit_tests/TestCases/asan-symbolize-sanity-test.cc
new file mode 100644
index 000000000000..0efe245bb6b5
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/asan-symbolize-sanity-test.cc
@@ -0,0 +1,39 @@
+// 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
new file mode 100644
index 000000000000..b0a501576945
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/assign_large_valloc_to_global.cc
@@ -0,0 +1,8 @@
+// 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
new file mode 100644
index 000000000000..e3b1269d25cc
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/atexit_stats.cc
@@ -0,0 +1,13 @@
+// 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/blacklist.cc b/lib/asan/lit_tests/TestCases/blacklist.cc
index 6cfc1500c503..46625ee7bdb5 100644
--- a/lib/asan/lit_tests/blacklist.cc
+++ b/lib/asan/lit_tests/TestCases/blacklist.cc
@@ -3,25 +3,19 @@
// RUN: echo "fun:*brokenFunction*" > %tmp
// RUN: echo "global:*badGlobal*" >> %tmp
// RUN: echo "src:*blacklist-extra.cc" >> %tmp
-// RUN: %clangxx_asan -fsanitize-blacklist=%tmp -m64 -O0 %s -o %t \
+// 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 -m64 -O1 %s -o %t \
+// 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 -m64 -O2 %s -o %t \
+// 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 -m64 -O3 %s -o %t \
-// RUN: %p/Helpers/blacklist-extra.cc && %t 2>&1
-// RUN: %clangxx_asan -fsanitize-blacklist=%tmp -m32 -O0 %s -o %t \
-// RUN: %p/Helpers/blacklist-extra.cc && %t 2>&1
-// RUN: %clangxx_asan -fsanitize-blacklist=%tmp -m32 -O1 %s -o %t \
-// RUN: %p/Helpers/blacklist-extra.cc && %t 2>&1
-// RUN: %clangxx_asan -fsanitize-blacklist=%tmp -m32 -O2 %s -o %t \
-// RUN: %p/Helpers/blacklist-extra.cc && %t 2>&1
-// RUN: %clangxx_asan -fsanitize-blacklist=%tmp -m32 -O3 %s -o %t \
+// 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.
-int badGlobal;
+// 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];
}
diff --git a/lib/asan/lit_tests/TestCases/contiguous_container.cc b/lib/asan/lit_tests/TestCases/contiguous_container.cc
new file mode 100644
index 000000000000..aa97592c7bb9
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/contiguous_container.cc
@@ -0,0 +1,47 @@
+// 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
new file mode 100644
index 000000000000..669cf150bdfb
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/current_allocated_bytes.cc
@@ -0,0 +1,43 @@
+// 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
new file mode 100644
index 000000000000..e24704b9019e
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/deep_call_stack.cc
@@ -0,0 +1,25 @@
+// 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/deep_stack_uaf.cc b/lib/asan/lit_tests/TestCases/deep_stack_uaf.cc
index 7b32798fefcc..920411c4ac52 100644
--- a/lib/asan/lit_tests/deep_stack_uaf.cc
+++ b/lib/asan/lit_tests/TestCases/deep_stack_uaf.cc
@@ -1,12 +1,7 @@
// Check that we can store lots of stack frames if asked to.
-// RUN: %clangxx_asan -m64 -O0 %s -o %t 2>&1
-// RUN: ASAN_OPTIONS=malloc_context_size=120:redzone=512 %t 2>&1 | \
-// RUN: %symbolize | FileCheck %s
-
-// RUN: %clangxx_asan -m32 -O0 %s -o %t 2>&1
-// RUN: ASAN_OPTIONS=malloc_context_size=120:redzone=512 %t 2>&1 | \
-// RUN: %symbolize | FileCheck %s
+// 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>
diff --git a/lib/asan/lit_tests/TestCases/deep_tail_call.cc b/lib/asan/lit_tests/TestCases/deep_tail_call.cc
new file mode 100644
index 000000000000..2e7aa8e0208f
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/deep_tail_call.cc
@@ -0,0 +1,20 @@
+// 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/deep_thread_stack.cc b/lib/asan/lit_tests/TestCases/deep_thread_stack.cc
index 781508d61616..92e0d66c82eb 100644
--- a/lib/asan/lit_tests/deep_thread_stack.cc
+++ b/lib/asan/lit_tests/TestCases/deep_thread_stack.cc
@@ -1,11 +1,7 @@
-// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m64 -O1 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m64 -O2 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m64 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m32 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m32 -O1 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m32 -O2 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m32 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
+// 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>
diff --git a/lib/asan/lit_tests/default_blacklist.cc b/lib/asan/lit_tests/TestCases/default_blacklist.cc
index 25a1ae1752b0..25a1ae1752b0 100644
--- a/lib/asan/lit_tests/default_blacklist.cc
+++ b/lib/asan/lit_tests/TestCases/default_blacklist.cc
diff --git a/lib/asan/lit_tests/default_options.cc b/lib/asan/lit_tests/TestCases/default_options.cc
index 84b80557b852..84b80557b852 100644
--- a/lib/asan/lit_tests/default_options.cc
+++ b/lib/asan/lit_tests/TestCases/default_options.cc
diff --git a/lib/asan/lit_tests/dlclose-test.cc b/lib/asan/lit_tests/TestCases/dlclose-test.cc
index b15895bf3579..03ed16016116 100644
--- a/lib/asan/lit_tests/dlclose-test.cc
+++ b/lib/asan/lit_tests/TestCases/dlclose-test.cc
@@ -14,30 +14,18 @@
// It works on i368/x86_64 Linux, but not necessary anywhere else.
// REQUIRES: x86_64-supported-target,i386-supported-target
-// RUN: %clangxx_asan -m64 -O0 %p/SharedLibs/dlclose-test-so.cc \
+// RUN: %clangxx_asan -O0 %p/SharedLibs/dlclose-test-so.cc \
// RUN: -fPIC -shared -o %t-so.so
-// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m64 -O1 %p/SharedLibs/dlclose-test-so.cc \
+// 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 -m64 -O1 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m64 -O2 %p/SharedLibs/dlclose-test-so.cc \
+// 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 -m64 -O2 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m64 -O3 %p/SharedLibs/dlclose-test-so.cc \
+// 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 -m64 -O3 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m32 -O0 %p/SharedLibs/dlclose-test-so.cc \
-// RUN: -fPIC -shared -o %t-so.so
-// RUN: %clangxx_asan -m32 -O0 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m32 -O1 %p/SharedLibs/dlclose-test-so.cc \
-// RUN: -fPIC -shared -o %t-so.so
-// RUN: %clangxx_asan -m32 -O1 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m32 -O2 %p/SharedLibs/dlclose-test-so.cc \
-// RUN: -fPIC -shared -o %t-so.so
-// RUN: %clangxx_asan -m32 -O2 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m32 -O3 %p/SharedLibs/dlclose-test-so.cc \
-// RUN: -fPIC -shared -o %t-so.so
-// RUN: %clangxx_asan -m32 -O3 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O3 %s -o %t && %t 2>&1 | FileCheck %s
#include <assert.h>
#include <dlfcn.h>
diff --git a/lib/asan/lit_tests/TestCases/double-free.cc b/lib/asan/lit_tests/TestCases/double-free.cc
new file mode 100644
index 000000000000..6bfd4fa2c7e5
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/double-free.cc
@@ -0,0 +1,25 @@
+// 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/force_inline_opt0.cc b/lib/asan/lit_tests/TestCases/force_inline_opt0.cc
index 955ce38156fb..775a66dfe2fe 100644
--- a/lib/asan/lit_tests/force_inline_opt0.cc
+++ b/lib/asan/lit_tests/TestCases/force_inline_opt0.cc
@@ -1,7 +1,7 @@
// This test checks that we are no instrumenting a memory access twice
// (before and after inlining)
-// RUN: %clangxx_asan -m64 -O1 %s -o %t && %t
-// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t
+// 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;
diff --git a/lib/asan/lit_tests/TestCases/free_hook_realloc.cc b/lib/asan/lit_tests/TestCases/free_hook_realloc.cc
new file mode 100644
index 000000000000..7a71964b0032
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/free_hook_realloc.cc
@@ -0,0 +1,32 @@
+// 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/global-demangle.cc b/lib/asan/lit_tests/TestCases/global-demangle.cc
index 5696a38a7705..d050b70f0fca 100644
--- a/lib/asan/lit_tests/global-demangle.cc
+++ b/lib/asan/lit_tests/TestCases/global-demangle.cc
@@ -1,5 +1,4 @@
-// Don't run through %symbolize to avoid c++filt demangling.
-// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s
namespace XXX {
class YYY {
diff --git a/lib/asan/lit_tests/TestCases/global-overflow.cc b/lib/asan/lit_tests/TestCases/global-overflow.cc
new file mode 100644
index 000000000000..0f080f55f2f1
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/global-overflow.cc
@@ -0,0 +1,21 @@
+// 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
new file mode 100644
index 000000000000..2c943a36014f
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/heap-overflow.cc
@@ -0,0 +1,24 @@
+// 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/huge_negative_hea_oob.cc b/lib/asan/lit_tests/TestCases/huge_negative_hea_oob.cc
index a09e3bf87d60..58a44c5fb68e 100644
--- a/lib/asan/lit_tests/huge_negative_hea_oob.cc
+++ b/lib/asan/lit_tests/TestCases/huge_negative_hea_oob.cc
@@ -1,5 +1,5 @@
-// RUN: %clangxx_asan -m64 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m64 -O %s -o %t && %t 2>&1 | FileCheck %s
+// 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>
diff --git a/lib/asan/lit_tests/init-order-atexit.cc b/lib/asan/lit_tests/TestCases/init-order-atexit.cc
index 45f4f17c0cb0..e38cdd273d58 100644
--- a/lib/asan/lit_tests/init-order-atexit.cc
+++ b/lib/asan/lit_tests/TestCases/init-order-atexit.cc
@@ -4,8 +4,8 @@
// (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 -m64 -O0 %s %p/Helpers/init-order-atexit-extra.cc -o %t
-// RUN: ASAN_OPTIONS=check_initialization_order=true:strict_init_order=true %t 2>&1 | FileCheck %s
+// 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>
diff --git a/lib/asan/lit_tests/init-order-dlopen.cc b/lib/asan/lit_tests/TestCases/init-order-dlopen.cc
index 228f44204c99..d30d11999246 100644
--- a/lib/asan/lit_tests/init-order-dlopen.cc
+++ b/lib/asan/lit_tests/TestCases/init-order-dlopen.cc
@@ -1,14 +1,18 @@
// Regression test for
// https://code.google.com/p/address-sanitizer/issues/detail?id=178
-// RUN: %clangxx_asan -m64 -O0 %p/SharedLibs/init-order-dlopen-so.cc \
-// RUN: -fPIC -shared -o %t-so.so
+// 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 -m64 -O0 %s -o %t -Wl,--export-dynamic || \
-// RUN: %clangxx_asan -m64 -O0 %s -o %t
-// RUN: ASAN_OPTIONS=check_initialization_order=true:strict_init_order=true %t 2>&1 | FileCheck %s
+// 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>
@@ -24,6 +28,7 @@ int foo() {
int global = foo();
__attribute__((visibility("default")))
+extern "C"
void inc_global() {
global++;
}
diff --git a/lib/asan/lit_tests/TestCases/init-order-pthread-create.cc b/lib/asan/lit_tests/TestCases/init-order-pthread-create.cc
new file mode 100644
index 000000000000..52031216d5bb
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/init-order-pthread-create.cc
@@ -0,0 +1,32 @@
+// 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
new file mode 100644
index 000000000000..f40fcc082f9a
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/initialization-blacklist.cc
@@ -0,0 +1,32 @@
+// 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/initialization-bug.cc b/lib/asan/lit_tests/TestCases/initialization-bug.cc
index ee2c725f0b13..fb289b1c7ebe 100644
--- a/lib/asan/lit_tests/initialization-bug.cc
+++ b/lib/asan/lit_tests/TestCases/initialization-bug.cc
@@ -1,11 +1,7 @@
// Test to make sure basic initialization order errors are caught.
-// RUN: %clangxx_asan -m64 -O0 %s %p/Helpers/initialization-bug-extra2.cc -o %t
-// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1 \
-// RUN: | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m32 -O0 %s %p/Helpers/initialization-bug-extra2.cc -o %t
-// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1 \
-// RUN: | %symbolize | FileCheck %s
+// 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.
diff --git a/lib/asan/lit_tests/TestCases/initialization-constexpr.cc b/lib/asan/lit_tests/TestCases/initialization-constexpr.cc
new file mode 100644
index 000000000000..65c95edd5081
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/initialization-constexpr.cc
@@ -0,0 +1,31 @@
+// 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/initialization-nobug.cc b/lib/asan/lit_tests/TestCases/initialization-nobug.cc
index 407226e29a1b..ed37d137f8cb 100644
--- a/lib/asan/lit_tests/initialization-nobug.cc
+++ b/lib/asan/lit_tests/TestCases/initialization-nobug.cc
@@ -1,21 +1,13 @@
// A collection of various initializers which shouldn't trip up initialization
// order checking. If successful, this will just return 0.
-// RUN: %clangxx_asan -m64 -O0 %s %p/Helpers/initialization-nobug-extra.cc -fsanitize=init-order -o %t
+// 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 -m64 -O1 %s %p/Helpers/initialization-nobug-extra.cc -fsanitize=init-order -o %t
+// 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 -m64 -O2 %s %p/Helpers/initialization-nobug-extra.cc -fsanitize=init-order -o %t
+// 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 -m64 -O3 %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 -m32 -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 -m32 -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 -m32 -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 -m32 -O3 %s %p/Helpers/initialization-nobug-extra.cc -fsanitize=init-order -o %t
+// 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:
diff --git a/lib/asan/lit_tests/TestCases/inline.cc b/lib/asan/lit_tests/TestCases/inline.cc
new file mode 100644
index 000000000000..792aff59f4ba
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/inline.cc
@@ -0,0 +1,19 @@
+// 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
new file mode 100644
index 000000000000..297b5526e9d9
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/interface_test.cc
@@ -0,0 +1,8 @@
+// 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/invalid-free.cc b/lib/asan/lit_tests/TestCases/invalid-free.cc
index 0ef064056b63..f940b501279a 100644
--- a/lib/asan/lit_tests/invalid-free.cc
+++ b/lib/asan/lit_tests/TestCases/invalid-free.cc
@@ -1,4 +1,9 @@
-// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
+// 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>
@@ -11,6 +16,6 @@ int main(int argc, char **argv) {
// CHECK: invalid-free.cc:[[@LINE-2]]
// CHECK: is located 5 bytes inside of 10-byte region
// CHECK: allocated by thread T0 here:
- // CHECK: invalid-free.cc:[[@LINE-8]]
+ // 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
new file mode 100644
index 000000000000..08ca688d3872
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/ioctl.cc
@@ -0,0 +1,24 @@
+// 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
new file mode 100644
index 000000000000..0534bcd31142
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/large_func_test.cc
@@ -0,0 +1,51 @@
+// 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/log-path_test.cc b/lib/asan/lit_tests/TestCases/log-path_test.cc
index 1072670fbff4..1072670fbff4 100644
--- a/lib/asan/lit_tests/log-path_test.cc
+++ b/lib/asan/lit_tests/TestCases/log-path_test.cc
diff --git a/lib/asan/lit_tests/log_path_fork_test.cc.disabled b/lib/asan/lit_tests/TestCases/log_path_fork_test.cc.disabled
index c6c1b49e994d..c6c1b49e994d 100644
--- a/lib/asan/lit_tests/log_path_fork_test.cc.disabled
+++ b/lib/asan/lit_tests/TestCases/log_path_fork_test.cc.disabled
diff --git a/lib/asan/lit_tests/TestCases/lsan_annotations.cc b/lib/asan/lit_tests/TestCases/lsan_annotations.cc
new file mode 100644
index 000000000000..c55ab8692eb5
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/lsan_annotations.cc
@@ -0,0 +1,16 @@
+// 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
new file mode 100644
index 000000000000..266ce66f59e2
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/malloc_context_size.cc
@@ -0,0 +1,27 @@
+// 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/malloc_fill.cc b/lib/asan/lit_tests/TestCases/malloc_fill.cc
index c23516b33299..57f50d1438b7 100644
--- a/lib/asan/lit_tests/malloc_fill.cc
+++ b/lib/asan/lit_tests/TestCases/malloc_fill.cc
@@ -1,5 +1,5 @@
// Check that we fill malloc-ed memory correctly.
-// RUN: %clangxx_asan -m64 %s -o %t
+// 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
diff --git a/lib/asan/lit_tests/malloc_hook.cc b/lib/asan/lit_tests/TestCases/malloc_hook.cc
index 6435d105ee26..83be1020ea43 100644
--- a/lib/asan/lit_tests/malloc_hook.cc
+++ b/lib/asan/lit_tests/TestCases/malloc_hook.cc
@@ -4,19 +4,31 @@
#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) {
- write(1, "MallocHook\n", sizeof("MallocHook\n"));
+ if (__asan_get_ownership(ptr)) {
+ write(1, "MallocHook\n", sizeof("MallocHook\n"));
+ global_ptr = ptr;
+ }
}
void __asan_free_hook(void *ptr) {
- write(1, "FreeHook\n", sizeof("FreeHook\n"));
+ 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
diff --git a/lib/asan/lit_tests/TestCases/memcmp_strict_test.cc b/lib/asan/lit_tests/TestCases/memcmp_strict_test.cc
new file mode 100644
index 000000000000..e06a8c7e9e2f
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/memcmp_strict_test.cc
@@ -0,0 +1,15 @@
+// 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
new file mode 100644
index 000000000000..758311ddc476
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/memcmp_test.cc
@@ -0,0 +1,17 @@
+// 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
new file mode 100644
index 000000000000..476418324cc5
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/null_deref.cc
@@ -0,0 +1,19 @@
+// 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/on_error_callback.cc b/lib/asan/lit_tests/TestCases/on_error_callback.cc
index bb94d9fb579b..d0cec2eb2703 100644
--- a/lib/asan/lit_tests/on_error_callback.cc
+++ b/lib/asan/lit_tests/TestCases/on_error_callback.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_asan -O2 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s
#include <stdio.h>
#include <stdlib.h>
diff --git a/lib/asan/lit_tests/TestCases/partial_right.cc b/lib/asan/lit_tests/TestCases/partial_right.cc
new file mode 100644
index 000000000000..a000a913d6be
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/partial_right.cc
@@ -0,0 +1,13 @@
+// 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
new file mode 100644
index 000000000000..f7c48bf597b6
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/poison_partial.cc
@@ -0,0 +1,19 @@
+// 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
new file mode 100644
index 000000000000..949c9b54f8a3
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/print_summary.cc
@@ -0,0 +1,14 @@
+// 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
new file mode 100644
index 000000000000..ba17505f37ac
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/readv.cc
@@ -0,0 +1,32 @@
+// 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/sanity_check_pure_c.c b/lib/asan/lit_tests/TestCases/sanity_check_pure_c.c
index 3d830653e33e..df150675bd97 100644
--- a/lib/asan/lit_tests/sanity_check_pure_c.c
+++ b/lib/asan/lit_tests/TestCases/sanity_check_pure_c.c
@@ -1,10 +1,10 @@
// Sanity checking a test in pure C.
-// RUN: %clang -g -fsanitize=address -O2 %s -o %t
-// RUN: %t 2>&1 | %symbolize | FileCheck %s
+// 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 -g -fsanitize=address -O2 %s -pie -o %t
-// RUN: %t 2>&1 | %symbolize | FileCheck %s
+// RUN: %clang_asan -O2 %s -pie -o %t
+// RUN: not %t 2>&1 | FileCheck %s
#include <stdlib.h>
int main() {
diff --git a/lib/asan/lit_tests/TestCases/shared-lib-test.cc b/lib/asan/lit_tests/TestCases/shared-lib-test.cc
new file mode 100644
index 000000000000..126903a55866
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/shared-lib-test.cc
@@ -0,0 +1,42 @@
+// 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/sleep_before_dying.c b/lib/asan/lit_tests/TestCases/sleep_before_dying.c
index df9eba276039..8dee9f2778ce 100644
--- a/lib/asan/lit_tests/sleep_before_dying.c
+++ b/lib/asan/lit_tests/TestCases/sleep_before_dying.c
@@ -1,5 +1,5 @@
-// RUN: %clang -g -fsanitize=address -O2 %s -o %t
-// RUN: ASAN_OPTIONS="sleep_before_dying=1" %t 2>&1 | FileCheck %s
+// 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() {
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
new file mode 100644
index 000000000000..91820db0142a
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/stack-buffer-overflow-with-position.cc
@@ -0,0 +1,45 @@
+// 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/stack-frame-demangle.cc b/lib/asan/lit_tests/TestCases/stack-frame-demangle.cc
index bb8de16b2b8a..2b83ecc2923b 100644
--- a/lib/asan/lit_tests/stack-frame-demangle.cc
+++ b/lib/asan/lit_tests/TestCases/stack-frame-demangle.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
+// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s
#include <string.h>
diff --git a/lib/asan/lit_tests/stack-oob-frames.cc b/lib/asan/lit_tests/TestCases/stack-oob-frames.cc
index 0395522252e8..909e700b3d00 100644
--- a/lib/asan/lit_tests/stack-oob-frames.cc
+++ b/lib/asan/lit_tests/TestCases/stack-oob-frames.cc
@@ -1,8 +1,8 @@
-// RUN: %clangxx_asan -m64 -O1 %s -o %t
-// RUN: %t 0 2>&1 | %symbolize | FileCheck %s --check-prefix=CHECK0
-// RUN: %t 1 2>&1 | %symbolize | FileCheck %s --check-prefix=CHECK1
-// RUN: %t 2 2>&1 | %symbolize | FileCheck %s --check-prefix=CHECK2
-// RUN: %t 3 2>&1 | %symbolize | FileCheck %s --check-prefix=CHECK3
+// 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) {
diff --git a/lib/asan/lit_tests/TestCases/stack-overflow.cc b/lib/asan/lit_tests/TestCases/stack-overflow.cc
new file mode 100644
index 000000000000..adf1c0784f70
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/stack-overflow.cc
@@ -0,0 +1,16 @@
+// 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
new file mode 100644
index 000000000000..5ed42a8c0c97
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/stack-use-after-return.cc
@@ -0,0 +1,77 @@
+// 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
new file mode 100644
index 000000000000..e92afd3caaf9
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/strdup_oob_test.cc
@@ -0,0 +1,19 @@
+// 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
new file mode 100644
index 000000000000..0df009b83f9c
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/strerror_r_test.cc
@@ -0,0 +1,13 @@
+// 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/strip_path_prefix.c b/lib/asan/lit_tests/TestCases/strip_path_prefix.c
index ef7bf98ab3c2..c4d6ba49d5e3 100644
--- a/lib/asan/lit_tests/strip_path_prefix.c
+++ b/lib/asan/lit_tests/TestCases/strip_path_prefix.c
@@ -1,5 +1,5 @@
-// RUN: %clang -g -fsanitize=address -O2 %s -o %t
-// RUN: ASAN_OPTIONS="strip_path_prefix='/'" %t 2>&1 | FileCheck %s
+// RUN: %clang_asan -O2 %s -o %t
+// RUN: ASAN_OPTIONS="strip_path_prefix='/'" not %t 2>&1 | FileCheck %s
#include <stdlib.h>
int main() {
diff --git a/lib/asan/lit_tests/TestCases/strncpy-overflow.cc b/lib/asan/lit_tests/TestCases/strncpy-overflow.cc
new file mode 100644
index 000000000000..f91e191fde23
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/strncpy-overflow.cc
@@ -0,0 +1,28 @@
+// 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/symbolize_callback.cc b/lib/asan/lit_tests/TestCases/symbolize_callback.cc
index 0691d501e24d..058b3150fbba 100644
--- a/lib/asan/lit_tests/symbolize_callback.cc
+++ b/lib/asan/lit_tests/TestCases/symbolize_callback.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_asan -O2 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s
#include <stdio.h>
#include <stdlib.h>
diff --git a/lib/asan/lit_tests/throw_call_test.cc b/lib/asan/lit_tests/TestCases/throw_call_test.cc
index 974bc51d97c5..974bc51d97c5 100644
--- a/lib/asan/lit_tests/throw_call_test.cc
+++ b/lib/asan/lit_tests/TestCases/throw_call_test.cc
diff --git a/lib/asan/lit_tests/throw_invoke_test.cc b/lib/asan/lit_tests/TestCases/throw_invoke_test.cc
index 077a940e8d19..077a940e8d19 100644
--- a/lib/asan/lit_tests/throw_invoke_test.cc
+++ b/lib/asan/lit_tests/TestCases/throw_invoke_test.cc
diff --git a/lib/asan/lit_tests/time_interceptor.cc b/lib/asan/lit_tests/TestCases/time_interceptor.cc
index f5f2ad62b815..3be00d60c01d 100644
--- a/lib/asan/lit_tests/time_interceptor.cc
+++ b/lib/asan/lit_tests/TestCases/time_interceptor.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
+// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s
// Test the time() interceptor.
diff --git a/lib/asan/lit_tests/TestCases/uar_and_exceptions.cc b/lib/asan/lit_tests/TestCases/uar_and_exceptions.cc
new file mode 100644
index 000000000000..c967531c2c02
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/uar_and_exceptions.cc
@@ -0,0 +1,40 @@
+// 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/unaligned_loads_and_stores.cc b/lib/asan/lit_tests/TestCases/unaligned_loads_and_stores.cc
index bcae089b427b..d50566c44e9a 100644
--- a/lib/asan/lit_tests/unaligned_loads_and_stores.cc
+++ b/lib/asan/lit_tests/TestCases/unaligned_loads_and_stores.cc
@@ -1,15 +1,15 @@
-// RUN: %clangxx_asan -O0 -I %p/../../../include %s -o %t
-// RUN: %t A 2>&1 | %symbolize | FileCheck --check-prefix=CHECK-A %s
-// RUN: %t B 2>&1 | %symbolize | FileCheck --check-prefix=CHECK-B %s
-// RUN: %t C 2>&1 | %symbolize | FileCheck --check-prefix=CHECK-C %s
-// RUN: %t D 2>&1 | %symbolize | FileCheck --check-prefix=CHECK-D %s
-// RUN: %t E 2>&1 | %symbolize | FileCheck --check-prefix=CHECK-E %s
+// 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: %t K 2>&1 | %symbolize | FileCheck --check-prefix=CHECK-K %s
-// RUN: %t L 2>&1 | %symbolize | FileCheck --check-prefix=CHECK-L %s
-// RUN: %t M 2>&1 | %symbolize | FileCheck --check-prefix=CHECK-M %s
-// RUN: %t N 2>&1 | %symbolize | FileCheck --check-prefix=CHECK-N %s
-// RUN: %t O 2>&1 | %symbolize | FileCheck --check-prefix=CHECK-O %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>
diff --git a/lib/asan/lit_tests/TestCases/use-after-free-right.cc b/lib/asan/lit_tests/TestCases/use-after-free-right.cc
new file mode 100644
index 000000000000..88d91f53d24e
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/use-after-free-right.cc
@@ -0,0 +1,34 @@
+// 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
new file mode 100644
index 000000000000..84ba479c1393
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/use-after-free.cc
@@ -0,0 +1,31 @@
+// 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/use-after-poison.cc b/lib/asan/lit_tests/TestCases/use-after-poison.cc
index d87342900245..e3bc6ecee7f2 100644
--- a/lib/asan/lit_tests/use-after-poison.cc
+++ b/lib/asan/lit_tests/TestCases/use-after-poison.cc
@@ -1,5 +1,5 @@
// Check that __asan_poison_memory_region works.
-// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
+// 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
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
new file mode 100644
index 000000000000..32fa6ad8a464
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/use-after-scope-dtor-order.cc
@@ -0,0 +1,25 @@
+// 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/use-after-scope-inlined.cc b/lib/asan/lit_tests/TestCases/use-after-scope-inlined.cc
index 5c121ea187eb..0bad048e3b8f 100644
--- a/lib/asan/lit_tests/use-after-scope-inlined.cc
+++ b/lib/asan/lit_tests/TestCases/use-after-scope-inlined.cc
@@ -2,10 +2,7 @@
// happens. "always_inline" is not enough, as Clang doesn't emit
// llvm.lifetime intrinsics at -O0.
//
-// RUN: %clangxx_asan -m64 -O2 -fsanitize=use-after-scope %s -o %t && \
-// RUN: %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m32 -O2 -fsanitize=use-after-scope %s -o %t && \
-// RUN: %t 2>&1 | %symbolize | FileCheck %s
+// RUN: %clangxx_asan -O2 -fsanitize=use-after-scope %s -o %t && not %t 2>&1 | FileCheck %s
int *arr;
@@ -21,7 +18,7 @@ int main(int argc, char *argv[]) {
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: #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
diff --git a/lib/asan/lit_tests/TestCases/use-after-scope-nobug.cc b/lib/asan/lit_tests/TestCases/use-after-scope-nobug.cc
new file mode 100644
index 000000000000..c23acf76eaee
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/use-after-scope-nobug.cc
@@ -0,0 +1,14 @@
+// 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
new file mode 100644
index 000000000000..13d714f9def7
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/use-after-scope-temp.cc
@@ -0,0 +1,29 @@
+// 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
new file mode 100644
index 000000000000..c46c9594c314
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/use-after-scope.cc
@@ -0,0 +1,16 @@
+// 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
new file mode 100644
index 000000000000..b5580dc88675
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/wait.cc
@@ -0,0 +1,63 @@
+// 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.cfg b/lib/asan/lit_tests/Unit/lit.cfg
deleted file mode 100644
index e24361b014e9..000000000000
--- a/lib/asan/lit_tests/Unit/lit.cfg
+++ /dev/null
@@ -1,26 +0,0 @@
-# -*- Python -*-
-
-import os
-
-def get_required_attr(config, attr_name):
- attr_value = getattr(config, attr_name, None)
- if not attr_value:
- lit.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 attributes common for all compiler-rt projects.
-compiler_rt_src_root = get_required_attr(config, 'compiler_rt_src_root')
-compiler_rt_lit_unit_cfg = os.path.join(compiler_rt_src_root, "lib",
- "lit.common.unit.cfg")
-lit.load_config(config, compiler_rt_lit_unit_cfg)
-
-# 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.
-asan_binary_dir = get_required_attr(config, "asan_binary_dir")
-config.test_exec_root = os.path.join(asan_binary_dir, "tests")
-config.test_source_root = config.test_exec_root
diff --git a/lib/asan/lit_tests/Unit/lit.site.cfg.in b/lib/asan/lit_tests/Unit/lit.site.cfg.in
index 315d24d1ed09..a45870c9b0e1 100644
--- a/lib/asan/lit_tests/Unit/lit.site.cfg.in
+++ b/lib/asan/lit_tests/Unit/lit.site.cfg.in
@@ -1,17 +1,16 @@
## Autogenerated by LLVM/Clang configuration.
# Do not edit!
-config.target_triple = "@TARGET_TRIPLE@"
-config.llvm_src_root = "@LLVM_SOURCE_DIR@"
-config.compiler_rt_src_root = "@COMPILER_RT_SOURCE_DIR@"
-config.llvm_build_mode = "@LLVM_BUILD_MODE@"
-config.asan_binary_dir = "@ASAN_BINARY_DIR@"
+# Load common config for all compiler-rt unit tests.
+lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/lib/lit.common.unit.configured")
-try:
- config.llvm_build_mode = config.llvm_build_mode % lit.params
-except KeyError,e:
- key, = e.args
- lit.fatal("unable to find %r parameter, use '--param=%s=VALUE'" % (key, key))
+# Setup config name.
+config.name = 'AddressSanitizer-Unit'
-# Let the main config do the real work.
-lit.load_config(config, "@ASAN_SOURCE_DIR@/lit_tests/Unit/lit.cfg")
+# 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/deep_tail_call.cc b/lib/asan/lit_tests/deep_tail_call.cc
deleted file mode 100644
index 6aa15e81f6ec..000000000000
--- a/lib/asan/lit_tests/deep_tail_call.cc
+++ /dev/null
@@ -1,24 +0,0 @@
-// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m64 -O1 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m64 -O2 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m64 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m32 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m32 -O1 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m32 -O2 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m32 -O3 %s -o %t && %t 2>&1 | %symbolize | 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/double-free.cc b/lib/asan/lit_tests/double-free.cc
deleted file mode 100644
index 9e201117c563..000000000000
--- a/lib/asan/lit_tests/double-free.cc
+++ /dev/null
@@ -1,18 +0,0 @@
-// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | %symbolize | 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: double-free.cc:[[@LINE-2]]
- // CHECK: freed by thread T0 here:
- // CHECK: double-free.cc:[[@LINE-5]]
- // CHECK: allocated by thread T0 here:
- // CHECK: double-free.cc:[[@LINE-10]]
- return res;
-}
diff --git a/lib/asan/lit_tests/global-overflow.cc b/lib/asan/lit_tests/global-overflow.cc
deleted file mode 100644
index 6a2f12e106fe..000000000000
--- a/lib/asan/lit_tests/global-overflow.cc
+++ /dev/null
@@ -1,25 +0,0 @@
-// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m64 -O1 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m64 -O2 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m64 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m32 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m32 -O1 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m32 -O2 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m32 -O3 %s -o %t && %t 2>&1 | %symbolize | 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/heap-overflow.cc b/lib/asan/lit_tests/heap-overflow.cc
deleted file mode 100644
index f1d719cd0b20..000000000000
--- a/lib/asan/lit_tests/heap-overflow.cc
+++ /dev/null
@@ -1,36 +0,0 @@
-// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m64 -O1 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m64 -O2 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m64 -O3 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m32 -O0 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m32 -O1 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m32 -O2 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m32 -O3 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-
-#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:21}}
-
- // CHECK-Darwin: {{ #0 0x.* in _?wrap_malloc.*}}
- // CHECK-Darwin: {{ #1 0x.* in _?main .*heap-overflow.cc:21}}
- free(x);
- return res;
-}
diff --git a/lib/asan/lit_tests/initialization-blacklist.cc b/lib/asan/lit_tests/initialization-blacklist.cc
deleted file mode 100644
index 12fbc49ed91b..000000000000
--- a/lib/asan/lit_tests/initialization-blacklist.cc
+++ /dev/null
@@ -1,47 +0,0 @@
-// Test for blacklist functionality of initialization-order checker.
-
-// RUN: %clangxx_asan -m64 -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 -m64 -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 -m64 -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
-// RUN: %clangxx_asan -m32 -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 -m32 -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 -m32 -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/initialization-constexpr.cc b/lib/asan/lit_tests/initialization-constexpr.cc
deleted file mode 100644
index ba5410674f76..000000000000
--- a/lib/asan/lit_tests/initialization-constexpr.cc
+++ /dev/null
@@ -1,43 +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 -m64 -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 -m64 -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 -m64 -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 -m64 -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
-// RUN: %clangxx_asan -m32 -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 -m32 -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 -m32 -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 -m32 -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/interface_test.cc b/lib/asan/lit_tests/interface_test.cc
deleted file mode 100644
index 428a109fe70d..000000000000
--- a/lib/asan/lit_tests/interface_test.cc
+++ /dev/null
@@ -1,8 +0,0 @@
-// Check that user may include ASan interface header.
-// RUN: %clang -fsanitize=address -I %p/../../../include %s -o %t && %t
-// RUN: %clang -I %p/../../../include %s -o %t && %t
-#include <sanitizer/asan_interface.h>
-
-int main() {
- return 0;
-}
diff --git a/lib/asan/lit_tests/large_func_test.cc b/lib/asan/lit_tests/large_func_test.cc
deleted file mode 100644
index ceecc29b7b0a..000000000000
--- a/lib/asan/lit_tests/large_func_test.cc
+++ /dev/null
@@ -1,63 +0,0 @@
-// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m64 -O1 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m64 -O2 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m64 -O3 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m32 -O0 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m32 -O1 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m32 -O2 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m32 -O3 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-
-#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/lit.cfg b/lib/asan/lit_tests/lit.cfg
index 5daecd9e557d..71a700c6ac3b 100644
--- a/lib/asan/lit_tests/lit.cfg
+++ b/lib/asan/lit_tests/lit.cfg
@@ -2,24 +2,27 @@
import os
+import lit.util
+
def get_required_attr(config, attr_name):
attr_value = getattr(config, attr_name, None)
if not attr_value:
- lit.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)
+ 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.name = 'AddressSanitizer' + config.bits
# Setup source root.
config.test_source_root = os.path.dirname(__file__)
def DisplayNoConfigMessage():
- lit.fatal("No site specific configuration available! " +
- "Try running your test from the build tree or running " +
- "make check-asan")
+ 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)
@@ -27,9 +30,9 @@ 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.params.get('asan_site_config', None)
+ asan_site_cfg = lit_config.params.get('asan_site_config', None)
if (asan_site_cfg) and (os.path.exists(asan_site_cfg)):
- lit.load_config(config, 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
@@ -45,51 +48,45 @@ if llvm_src_root is None:
if (not asan_site_cfg) or (not os.path.exists(asan_site_cfg)):
DisplayNoConfigMessage()
- lit.load_config(config, asan_site_cfg)
+ lit_config.load_config(config, asan_site_cfg)
raise SystemExit
-# Setup attributes common for all compiler-rt projects.
-compiler_rt_src_root = get_required_attr(config, "compiler_rt_src_root")
-compiler_rt_lit_cfg = os.path.join(compiler_rt_src_root, "lib",
- "lit.common.cfg")
-if (not compiler_rt_lit_cfg) or (not os.path.exists(compiler_rt_lit_cfg)):
- lit.fatal("Can't find common compiler-rt lit config at: %r"
- % compiler_rt_lit_cfg)
-lit.load_config(config, compiler_rt_lit_cfg)
-
# Setup default compiler flags used with -fsanitize=address option.
# FIXME: Review the set of required flags and check if it can be reduced.
-clang_asan_cxxflags = ("-ccc-cxx "
- + "-fsanitize=address "
- + "-mno-omit-leaf-frame-pointer "
- + "-fno-omit-frame-pointer "
- + "-fno-optimize-sibling-calls "
- + "-g")
+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 external LLVM symbolizer to run AddressSanitizer output tests.
-llvm_tools_dir = getattr(config, 'llvm_tools_dir', None)
-if llvm_tools_dir:
- config.environment['LLVM_SYMBOLIZER_PATH'] = os.path.join(
- llvm_tools_dir, "llvm-symbolizer")
-
-# Setup path to symbolizer script.
-# FIXME: Instead we should copy this script to the build tree and point
-# at it there.
-asan_source_dir = os.path.join(config.test_source_root, "..")
-symbolizer = os.path.join(asan_source_dir,
- 'scripts', 'asan_symbolize.py')
-if not os.path.exists(symbolizer):
- lit.fatal("Can't find symbolizer script on path %r" % symbolizer)
-# Define %symbolize substitution that filters output through
-# symbolizer and c++filt (for demangling).
-config.substitutions.append( ("%symbolize ", (" " + symbolizer +
- " | c++filt " )))
+# 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']
diff --git a/lib/asan/lit_tests/memcmp_strict_test.cc b/lib/asan/lit_tests/memcmp_strict_test.cc
deleted file mode 100644
index 00bf921c744a..000000000000
--- a/lib/asan/lit_tests/memcmp_strict_test.cc
+++ /dev/null
@@ -1,16 +0,0 @@
-// RUN: %clangxx_asan -m64 -O0 %s -o %t && ASAN_OPTIONS=strict_memcmp=0 %t 2>&1 | %symbolize | FileCheck %s --check-prefix=CHECK-nonstrict
-// RUN: %clangxx_asan -m64 -O0 %s -o %t && ASAN_OPTIONS=strict_memcmp=1 %t 2>&1 | %symbolize | FileCheck %s --check-prefix=CHECK-strict
-// Default to strict_memcmp=1.
-// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s --check-prefix=CHECK-strict
-
-#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-nonstrict: {{res: -1}}
- // CHECK-strict: AddressSanitizer: stack-buffer-overflow
- return 0;
-}
diff --git a/lib/asan/lit_tests/memcmp_test.cc b/lib/asan/lit_tests/memcmp_test.cc
deleted file mode 100644
index ac3f7f32ea75..000000000000
--- a/lib/asan/lit_tests/memcmp_test.cc
+++ /dev/null
@@ -1,19 +0,0 @@
-// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m64 -O1 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m64 -O2 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m64 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m32 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m32 -O1 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m32 -O2 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m32 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-
-#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/null_deref.cc b/lib/asan/lit_tests/null_deref.cc
deleted file mode 100644
index 60a521d1c210..000000000000
--- a/lib/asan/lit_tests/null_deref.cc
+++ /dev/null
@@ -1,31 +0,0 @@
-// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m64 -O1 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m64 -O2 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m64 -O3 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m32 -O0 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m32 -O1 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m32 -O2 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m32 -O3 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-
-__attribute__((noinline))
-static void NullDeref(int *ptr) {
- // CHECK: ERROR: AddressSanitizer: SEGV on unknown address
- // CHECK: {{0x0*00028 .*pc 0x.*}}
- // CHECK: {{AddressSanitizer can not provide additional info.}}
- 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]]
-}
diff --git a/lib/asan/lit_tests/partial_right.cc b/lib/asan/lit_tests/partial_right.cc
deleted file mode 100644
index c579262726f9..000000000000
--- a/lib/asan/lit_tests/partial_right.cc
+++ /dev/null
@@ -1,17 +0,0 @@
-// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m64 -O1 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m64 -O2 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m64 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m32 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m32 -O1 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m32 -O2 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m32 -O3 %s -o %t && %t 2>&1 | %symbolize | 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/shared-lib-test.cc b/lib/asan/lit_tests/shared-lib-test.cc
deleted file mode 100644
index 05bf3ecdf4f9..000000000000
--- a/lib/asan/lit_tests/shared-lib-test.cc
+++ /dev/null
@@ -1,54 +0,0 @@
-// RUN: %clangxx_asan -m64 -O0 %p/SharedLibs/shared-lib-test-so.cc \
-// RUN: -fPIC -shared -o %t-so.so
-// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m64 -O1 %p/SharedLibs/shared-lib-test-so.cc \
-// RUN: -fPIC -shared -o %t-so.so
-// RUN: %clangxx_asan -m64 -O1 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m64 -O2 %p/SharedLibs/shared-lib-test-so.cc \
-// RUN: -fPIC -shared -o %t-so.so
-// RUN: %clangxx_asan -m64 -O2 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m64 -O3 %p/SharedLibs/shared-lib-test-so.cc \
-// RUN: -fPIC -shared -o %t-so.so
-// RUN: %clangxx_asan -m64 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m32 -O0 %p/SharedLibs/shared-lib-test-so.cc \
-// RUN: -fPIC -shared -o %t-so.so
-// RUN: %clangxx_asan -m32 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m32 -O1 %p/SharedLibs/shared-lib-test-so.cc \
-// RUN: -fPIC -shared -o %t-so.so
-// RUN: %clangxx_asan -m32 -O1 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m32 -O2 %p/SharedLibs/shared-lib-test-so.cc \
-// RUN: -fPIC -shared -o %t-so.so
-// RUN: %clangxx_asan -m32 -O2 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m32 -O3 %p/SharedLibs/shared-lib-test-so.cc \
-// RUN: -fPIC -shared -o %t-so.so
-// RUN: %clangxx_asan -m32 -O3 %s -o %t && %t 2>&1 | %symbolize | 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/stack-overflow.cc b/lib/asan/lit_tests/stack-overflow.cc
deleted file mode 100644
index 25ea43af48a4..000000000000
--- a/lib/asan/lit_tests/stack-overflow.cc
+++ /dev/null
@@ -1,20 +0,0 @@
-// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m64 -O1 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m64 -O2 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m64 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m32 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m32 -O1 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m32 -O2 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m32 -O3 %s -o %t && %t 2>&1 | %symbolize | 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/stack-use-after-return.cc b/lib/asan/lit_tests/stack-use-after-return.cc
deleted file mode 100644
index f8d8a1a2ae39..000000000000
--- a/lib/asan/lit_tests/stack-use-after-return.cc
+++ /dev/null
@@ -1,45 +0,0 @@
-// XFAIL: *
-// RUN: %clangxx_asan -fsanitize=use-after-return -m64 -O0 %s -o %t && \
-// RUN: %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -fsanitize=use-after-return -m64 -O1 %s -o %t && \
-// RUN: %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -fsanitize=use-after-return -m64 -O2 %s -o %t && \
-// RUN: %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -fsanitize=use-after-return -m64 -O3 %s -o %t && \
-// RUN: %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -fsanitize=use-after-return -m32 -O0 %s -o %t && \
-// RUN: %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -fsanitize=use-after-return -m32 -O1 %s -o %t && \
-// RUN: %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -fsanitize=use-after-return -m32 -O2 %s -o %t && \
-// RUN: %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -fsanitize=use-after-return -m32 -O3 %s -o %t && \
-// RUN: %t 2>&1 | %symbolize | FileCheck %s
-
-#include <stdio.h>
-
-__attribute__((noinline))
-char *Ident(char *x) {
- fprintf(stderr, "1: %p\n", x);
- return x;
-}
-
-__attribute__((noinline))
-char *Func1() {
- char local;
- 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 frame <{{.*}}Func1{{.*}}> of T0's stack
-}
-
-int main(int argc, char **argv) {
- Func2(Func1());
- return 0;
-}
diff --git a/lib/asan/lit_tests/strncpy-overflow.cc b/lib/asan/lit_tests/strncpy-overflow.cc
deleted file mode 100644
index 5133b5c1653e..000000000000
--- a/lib/asan/lit_tests/strncpy-overflow.cc
+++ /dev/null
@@ -1,38 +0,0 @@
-// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m64 -O1 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m64 -O2 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m64 -O3 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m32 -O0 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m32 -O1 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m32 -O2 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m32 -O3 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-
-#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/use-after-free-right.cc b/lib/asan/lit_tests/use-after-free-right.cc
deleted file mode 100644
index b0de07b04a08..000000000000
--- a/lib/asan/lit_tests/use-after-free-right.cc
+++ /dev/null
@@ -1,46 +0,0 @@
-// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m64 -O1 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m64 -O2 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m64 -O3 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m32 -O0 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m32 -O1 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m32 -O2 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m32 -O3 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-
-// 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:25}}
- // 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:24}}
-
- // CHECK-Darwin: {{ #0 0x.* in _?wrap_free}}
- // CHECK-Darwin: {{ #1 0x.* in _?main .*use-after-free-right.cc:24}}
-
- // CHECK: {{previously allocated by thread T0 here:}}
-
- // CHECK-Linux: {{ #0 0x.* in .*malloc}}
- // CHECK-Linux: {{ #1 0x.* in main .*use-after-free-right.cc:23}}
-
- // CHECK-Darwin: {{ #0 0x.* in _?wrap_malloc.*}}
- // CHECK-Darwin: {{ #1 0x.* in _?main .*use-after-free-right.cc:23}}
-}
diff --git a/lib/asan/lit_tests/use-after-free.cc b/lib/asan/lit_tests/use-after-free.cc
deleted file mode 100644
index aee185dc4518..000000000000
--- a/lib/asan/lit_tests/use-after-free.cc
+++ /dev/null
@@ -1,43 +0,0 @@
-// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m64 -O1 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m64 -O2 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m64 -O3 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m32 -O0 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m32 -O1 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m32 -O2 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m32 -O3 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-
-#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:22}}
- // 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:21}}
-
- // CHECK-Darwin: {{ #0 0x.* in _?wrap_free}}
- // CHECK-Darwin: {{ #1 0x.* in _?main .*use-after-free.cc:21}}
-
- // CHECK: {{previously allocated by thread T0 here:}}
-
- // CHECK-Linux: {{ #0 0x.* in .*malloc}}
- // CHECK-Linux: {{ #1 0x.* in main .*use-after-free.cc:20}}
-
- // CHECK-Darwin: {{ #0 0x.* in _?wrap_malloc.*}}
- // CHECK-Darwin: {{ #1 0x.* in _?main .*use-after-free.cc:20}}
-}
diff --git a/lib/asan/lit_tests/wait.cc b/lib/asan/lit_tests/wait.cc
deleted file mode 100644
index 88fbb17176fa..000000000000
--- a/lib/asan/lit_tests/wait.cc
+++ /dev/null
@@ -1,77 +0,0 @@
-// RUN: %clangxx_asan -DWAIT -m64 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -DWAIT -m64 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -DWAIT -m32 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -DWAIT -m32 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-
-// RUN: %clangxx_asan -DWAITPID -m64 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -DWAITPID -m64 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -DWAITPID -m32 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -DWAITPID -m32 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-
-// RUN: %clangxx_asan -DWAITID -m64 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -DWAITID -m64 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -DWAITID -m32 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -DWAITID -m32 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-
-// RUN: %clangxx_asan -DWAIT3 -m64 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -DWAIT3 -m64 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -DWAIT3 -m32 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -DWAIT3 -m32 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-
-// RUN: %clangxx_asan -DWAIT4 -m64 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -DWAIT4 -m64 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -DWAIT4 -m32 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -DWAIT4 -m32 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-
-// RUN: %clangxx_asan -DWAIT3_RUSAGE -m64 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -DWAIT3_RUSAGE -m64 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -DWAIT3_RUSAGE -m32 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -DWAIT3_RUSAGE -m32 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-
-// RUN: %clangxx_asan -DWAIT4_RUSAGE -m64 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -DWAIT4_RUSAGE -m64 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -DWAIT4_RUSAGE -m32 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -DWAIT4_RUSAGE -m32 -O3 %s -o %t && %t 2>&1 | %symbolize | 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/scripts/asan_symbolize.py b/lib/asan/scripts/asan_symbolize.py
index bd3bf1e9b53e..a398fcf10361 100755
--- a/lib/asan/scripts/asan_symbolize.py
+++ b/lib/asan/scripts/asan_symbolize.py
@@ -10,14 +10,14 @@
import bisect
import getopt
import os
+import pty
import re
import subprocess
import sys
+import termios
llvm_symbolizer = None
symbolizers = {}
-filetypes = {}
-vmaddrs = {}
DEBUG = False
demangle = False;
@@ -101,8 +101,10 @@ class LLVMSymbolizer(Symbolizer):
def LLVMSymbolizerFactory(system):
symbolizer_path = os.getenv('LLVM_SYMBOLIZER_PATH')
if not symbolizer_path:
- # Assume llvm-symbolizer is in PATH.
- symbolizer_path = 'llvm-symbolizer'
+ 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)
@@ -137,6 +139,36 @@ class Addr2LineSymbolizer(Symbolizer):
return ['%s in %s %s' % (addr, function_name, file_name)]
+class UnbufferedLineConverter(object):
+ """
+ Wrap a child process that responds to each line of input with one line of
+ output. Uses pty to trick the child into providing unbuffered output.
+ """
+ def __init__(self, args, close_stderr=False):
+ pid, fd = pty.fork()
+ if pid == 0:
+ # We're the child. Transfer control to command.
+ if close_stderr:
+ dev_null = os.open('/dev/null', 0)
+ os.dup2(dev_null, 2)
+ os.execvp(args[0], args)
+ else:
+ # Disable echoing.
+ attr = termios.tcgetattr(fd)
+ attr[3] = attr[3] & ~termios.ECHO
+ termios.tcsetattr(fd, termios.TCSANOW, attr)
+ # Set up a file()-like interface to the child process
+ self.r = os.fdopen(fd, "r", 1)
+ self.w = os.fdopen(os.dup(fd), "w", 1)
+
+ def convert(self, line):
+ self.w.write(line + "\n")
+ return self.readline()
+
+ def readline(self):
+ return self.r.readline().rstrip()
+
+
class DarwinSymbolizer(Symbolizer):
def __init__(self, addr, binary):
super(DarwinSymbolizer, self).__init__()
@@ -146,29 +178,21 @@ class DarwinSymbolizer(Symbolizer):
self.arch = 'x86_64'
else:
self.arch = 'i386'
- self.vmaddr = None
- self.pipe = None
-
- def write_addr_to_pipe(self, offset):
- print >> self.pipe.stdin, '0x%x' % int(offset, 16)
+ self.open_atos()
def open_atos(self):
if DEBUG:
print 'atos -o %s -arch %s' % (self.binary, self.arch)
cmdline = ['atos', '-o', self.binary, '-arch', self.arch]
- self.pipe = subprocess.Popen(cmdline,
- stdin=subprocess.PIPE,
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
+ self.atos = UnbufferedLineConverter(cmdline, close_stderr=True)
def symbolize(self, addr, binary, offset):
"""Overrides Symbolizer.symbolize."""
if self.binary != binary:
return None
- self.open_atos()
- self.write_addr_to_pipe(offset)
- self.pipe.stdin.close()
- atos_line = self.pipe.stdout.readline().rstrip()
+ atos_line = self.atos.convert('0x%x' % int(offset, 16))
+ while "got symbolicator for" in atos_line:
+ atos_line = self.atos.readline()
# A well-formed atos response looks like this:
# foo(type1, type2) (in object.name) (filename.cc:80)
match = re.match('^(.*) \(in (.*)\) \((.*:\d*)\)$', atos_line)
@@ -331,7 +355,10 @@ class SymbolizationLoop(object):
def process_stdin(self):
self.frame_no = 0
- for line in sys.stdin:
+ while True:
+ line = sys.stdin.readline()
+ if not line:
+ break
self.current_line = line.rstrip()
#0 0x7f6e35cf2e45 (/blah/foo.so+0x11fe45)
stack_trace_line_format = (
diff --git a/lib/asan/tests/CMakeLists.txt b/lib/asan/tests/CMakeLists.txt
index 80d6f5d67aad..fc0f1788bd35 100644
--- a/lib/asan/tests/CMakeLists.txt
+++ b/lib/asan/tests/CMakeLists.txt
@@ -36,13 +36,9 @@ set(ASAN_UNITTEST_COMMON_CFLAGS
-Wall
-Wno-format
-Werror
+ -Werror=sign-compare
-g
- -O2
-)
-
-if(ASAN_TESTS_USE_ZERO_BASE_SHADOW)
- list(APPEND ASAN_UNITTEST_COMMON_CFLAGS -fPIE)
-endif()
+ -O2)
if(SUPPORTS_NO_VARIADIC_MACROS_FLAG)
list(APPEND ASAN_UNITTEST_COMMON_CFLAGS -Wno-variadic-macros)
endif()
@@ -62,24 +58,7 @@ else()
-DASAN_NEEDS_SEGV=1)
endif()
-set(ASAN_LINK_FLAGS)
-if(ASAN_TESTS_USE_ZERO_BASE_SHADOW)
- list(APPEND ASAN_LINK_FLAGS -pie)
-endif()
-# 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_LINK_FLAGS -fsanitize=address)
-endif()
-# Unit tests on Mac depend on Foundation.
-if(APPLE)
- list(APPEND ASAN_LINK_FLAGS -framework Foundation)
-endif()
-# Unit tests require libstdc++.
-list(APPEND ASAN_LINK_FLAGS -lstdc++)
-
set(ASAN_BLACKLIST_FILE "${CMAKE_CURRENT_SOURCE_DIR}/asan_test.ignore")
-
set(ASAN_UNITTEST_INSTRUMENTED_CFLAGS
${ASAN_UNITTEST_COMMON_CFLAGS}
-fsanitize=address
@@ -88,35 +67,65 @@ set(ASAN_UNITTEST_INSTRUMENTED_CFLAGS
-mllvm -asan-globals=1
-mllvm -asan-mapping-scale=0 # default will be used
-mllvm -asan-mapping-offset-log=-1 # default will be used
- -mllvm -asan-use-after-return=0
)
if(ASAN_TESTS_USE_ZERO_BASE_SHADOW)
list(APPEND ASAN_UNITTEST_INSTRUMENTED_CFLAGS
-fsanitize-address-zero-base-shadow)
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)
+ 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()
+
+set(ASAN_UNITTEST_NOINST_LINKFLAGS
+ ${ASAN_UNITTEST_COMMON_LINKFLAGS}
+ -ldl -lm)
+if(NOT ANDROID)
+ list(APPEND ASAN_UNITTEST_NOINST_LINKFLAGS -lpthread)
+endif()
+
# 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)
get_filename_component(basename ${source} NAME)
- set(output_obj "${basename}.${arch}.o")
+ set(output_obj "${obj_list}.${basename}.${arch}.o")
get_target_flags_for_arch(${arch} TARGET_CFLAGS)
clang_compile(${output_obj} ${source}
CFLAGS ${ARGN} ${TARGET_CFLAGS}
- DEPS gtest ${ASAN_RUNTIME_LIBRARIES}
+ DEPS gtest asan_runtime_libraries
${ASAN_UNITTEST_HEADERS}
${ASAN_BLACKLIST_FILE})
list(APPEND ${obj_list} ${output_obj})
endmacro()
# Link ASan unit test for a given architecture from a set
-# of objects in ${ARGN}.
+# of objects in with given linker flags.
macro(add_asan_test test_suite test_name arch)
+ 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})
+ if(TEST_WITH_TEST_RUNTIME)
+ list(APPEND TEST_DEPS ${ASAN_TEST_RUNTIME})
+ list(APPEND TEST_OBJECTS lib${ASAN_TEST_RUNTIME}.a)
+ endif()
add_compiler_rt_test(${test_suite} ${test_name}
- OBJECTS ${ARGN}
- DEPS ${ASAN_RUNTIME_LIBRARIES} ${ARGN}
- LINK_FLAGS ${ASAN_LINK_FLAGS}
+ OBJECTS ${TEST_OBJECTS}
+ DEPS ${TEST_DEPS}
+ LINK_FLAGS ${TEST_LINKFLAGS}
${TARGET_LINK_FLAGS})
endmacro()
@@ -128,52 +137,84 @@ add_custom_target(AsanBenchmarks)
set_target_properties(AsanBenchmarks PROPERTIES FOLDER "Asan benchmarks")
set(ASAN_NOINST_TEST_SOURCES
+ ${COMPILER_RT_GTEST_SOURCE}
+ asan_fake_stack_test.cc
asan_noinst_test.cc
asan_test_main.cc)
+
set(ASAN_INST_TEST_SOURCES
+ ${COMPILER_RT_GTEST_SOURCE}
asan_globals_test.cc
+ asan_interface_test.cc
asan_test.cc
asan_oob_test.cc
asan_mem_test.cc
- asan_str_test.cc)
+ asan_str_test.cc
+ asan_test_main.cc)
+if(APPLE)
+ list(APPEND ASAN_INST_TEST_SOURCES asan_mac_test.cc)
+endif()
+
+set(ASAN_BENCHMARKS_SOURCES
+ ${COMPILER_RT_GTEST_SOURCE}
+ asan_benchmarks_test.cc)
# Adds ASan unit tests and benchmarks for architecture.
macro(add_asan_tests_for_arch arch)
- # Build gtest instrumented with ASan.
- set(ASAN_INST_GTEST)
- asan_compile(ASAN_INST_GTEST ${COMPILER_RT_GTEST_SOURCE} ${arch}
- ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS})
# 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})
endforeach()
- # Add Mac-specific tests.
if (APPLE)
- asan_compile(ASAN_INST_TEST_OBJECTS asan_mac_test.cc ${arch}
- ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS})
+ # Add Mac-specific helper.
asan_compile(ASAN_INST_TEST_OBJECTS asan_mac_test_helpers.mm ${arch}
${ASAN_UNITTEST_INSTRUMENTED_CFLAGS} -ObjC)
endif()
+ add_asan_test(AsanUnitTests "Asan-${arch}-Test" ${arch}
+ OBJECTS ${ASAN_INST_TEST_OBJECTS}
+ LINKFLAGS ${ASAN_UNITTEST_INSTRUMENTED_LINKFLAGS})
+
+ # Add static ASan runtime that will be linked with uninstrumented tests.
+ set(ASAN_TEST_RUNTIME RTAsanTest.${arch})
+ if(APPLE)
+ set(ASAN_TEST_RUNTIME_OBJECTS
+ $<TARGET_OBJECTS:RTAsan.osx>
+ $<TARGET_OBJECTS:RTInterception.osx>
+ $<TARGET_OBJECTS:RTSanitizerCommon.osx>
+ $<TARGET_OBJECTS:RTLSanCommon.osx>)
+ else()
+ set(ASAN_TEST_RUNTIME_OBJECTS
+ $<TARGET_OBJECTS:RTAsan.${arch}>
+ $<TARGET_OBJECTS:RTInterception.${arch}>
+ $<TARGET_OBJECTS:RTLSanCommon.${arch}>
+ $<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
+ $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>)
+ endif()
+ add_library(${ASAN_TEST_RUNTIME} STATIC ${ASAN_TEST_RUNTIME_OBJECTS})
+ set_target_properties(${ASAN_TEST_RUNTIME} PROPERTIES
+ ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
# 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})
endforeach()
- # Link everything together.
- add_asan_test(AsanUnitTests "Asan-${arch}-Test" ${arch}
- ${ASAN_NOINST_TEST_OBJECTS}
- ${ASAN_INST_TEST_OBJECTS} ${ASAN_INST_GTEST})
+ add_asan_test(AsanUnitTests "Asan-${arch}-Noinst-Test" ${arch}
+ OBJECTS ${ASAN_NOINST_TEST_OBJECTS}
+ LINKFLAGS ${ASAN_UNITTEST_NOINST_LINKFLAGS}
+ WITH_TEST_RUNTIME)
- # Instrumented benchmarks.
+ # Benchmarks.
set(ASAN_BENCHMARKS_OBJECTS)
- asan_compile(ASAN_BENCHMARKS_OBJECTS asan_benchmarks_test.cc ${arch}
- ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS})
- # Link benchmarks.
+ foreach(src ${ASAN_BENCHMARKS_SOURCES})
+ asan_compile(ASAN_BENCHMARKS_OBJECTS ${src} ${arch}
+ ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS})
+ endforeach()
add_asan_test(AsanBenchmarks "Asan-${arch}-Benchmark" ${arch}
- ${ASAN_BENCHMARKS_OBJECTS} ${ASAN_INST_GTEST})
+ OBJECTS ${ASAN_BENCHMARKS_OBJECTS}
+ LINKFLAGS ${ASAN_UNITTEST_INSTRUMENTED_LINKFLAGS})
endmacro()
if(COMPILER_RT_CAN_EXECUTE_TESTS)
@@ -185,20 +226,28 @@ endif()
if(ANDROID)
# We assume that unit tests on Android are built in a build
# tree with fresh Clang as a host compiler.
- add_library(asan_noinst_test OBJECT ${ASAN_NOINST_TEST_SOURCES})
- set_target_compile_flags(asan_noinst_test ${ASAN_UNITTEST_COMMON_CFLAGS})
- add_library(asan_inst_test OBJECT
- ${ASAN_INST_TEST_SOURCES} ${COMPILER_RT_GTEST_SOURCE})
- set_target_compile_flags(asan_inst_test ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS})
+
+ # 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
- $<TARGET_OBJECTS:asan_noinst_test>
- $<TARGET_OBJECTS:asan_inst_test>
- )
+ ${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(AsanTest PROPERTIES
+ set_target_properties(AsanNoinstTest AsanTest PROPERTIES
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
- set_target_link_flags(AsanTest ${ASAN_LINK_FLAGS})
- target_link_libraries(AsanTest clang_rt.asan-arm-android)
# Add unit test to test suite.
- add_dependencies(AsanUnitTests AsanTest)
+ add_dependencies(AsanUnitTests AsanNoinstTest AsanTest)
endif()
diff --git a/lib/asan/tests/asan_fake_stack_test.cc b/lib/asan/tests/asan_fake_stack_test.cc
new file mode 100644
index 000000000000..1c98125eb45e
--- /dev/null
+++ b/lib/asan/tests/asan_fake_stack_test.cc
@@ -0,0 +1,150 @@
+//===-- asan_fake_stack_test.cc -------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Tests for FakeStack.
+// This test file should be compiled w/o asan instrumentation.
+//===----------------------------------------------------------------------===//
+
+#include "asan_fake_stack.h"
+#include "asan_test_utils.h"
+#include "sanitizer_common/sanitizer_common.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <map>
+
+namespace __asan {
+
+TEST(FakeStack, FlagsSize) {
+ EXPECT_EQ(FakeStack::SizeRequiredForFlags(10), 1U << 5);
+ EXPECT_EQ(FakeStack::SizeRequiredForFlags(11), 1U << 6);
+ EXPECT_EQ(FakeStack::SizeRequiredForFlags(20), 1U << 15);
+}
+
+TEST(FakeStack, RequiredSize) {
+ // for (int i = 15; i < 20; i++) {
+ // uptr alloc_size = FakeStack::RequiredSize(i);
+ // printf("%zdK ==> %zd\n", 1 << (i - 10), alloc_size);
+ // }
+ EXPECT_EQ(FakeStack::RequiredSize(15), 365568U);
+ EXPECT_EQ(FakeStack::RequiredSize(16), 727040U);
+ EXPECT_EQ(FakeStack::RequiredSize(17), 1449984U);
+ EXPECT_EQ(FakeStack::RequiredSize(18), 2895872U);
+ EXPECT_EQ(FakeStack::RequiredSize(19), 5787648U);
+}
+
+TEST(FakeStack, FlagsOffset) {
+ for (uptr stack_size_log = 15; stack_size_log <= 20; stack_size_log++) {
+ uptr stack_size = 1UL << stack_size_log;
+ uptr offset = 0;
+ for (uptr class_id = 0; class_id < FakeStack::kNumberOfSizeClasses;
+ class_id++) {
+ uptr frame_size = FakeStack::BytesInSizeClass(class_id);
+ uptr num_flags = stack_size / frame_size;
+ EXPECT_EQ(offset, FakeStack::FlagsOffset(stack_size_log, class_id));
+ // printf("%zd: %zd => %zd %zd\n", stack_size_log, class_id, offset,
+ // FakeStack::FlagsOffset(stack_size_log, class_id));
+ offset += num_flags;
+ }
+ }
+}
+
+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();
+ }
+ }
+}
+
+TEST(FakeStack, ModuloNumberOfFrames) {
+ EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 0, 0), 0U);
+ EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 0, (1<<15)), 0U);
+ EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 0, (1<<10)), 0U);
+ EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 0, (1<<9)), 0U);
+ EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 0, (1<<8)), 1U<<8);
+ EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 0, (1<<15) + 1), 1U);
+
+ EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 1, 0), 0U);
+ EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 1, 1<<9), 0U);
+ EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 1, 1<<8), 0U);
+ EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 1, 1<<7), 1U<<7);
+
+ EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 5, 0), 0U);
+ EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 5, 1), 1U);
+ EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 5, 15), 15U);
+ EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 5, 16), 0U);
+ EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 5, 17), 1U);
+}
+
+TEST(FakeStack, GetFrame) {
+ const uptr stack_size_log = 20;
+ const uptr stack_size = 1 << stack_size_log;
+ FakeStack *fs = FakeStack::Create(stack_size_log);
+ u8 *base = fs->GetFrame(stack_size_log, 0, 0);
+ EXPECT_EQ(base, reinterpret_cast<u8 *>(fs) +
+ fs->SizeRequiredForFlags(stack_size_log) + 4096);
+ EXPECT_EQ(base + 0*stack_size + 64 * 7, fs->GetFrame(stack_size_log, 0, 7U));
+ EXPECT_EQ(base + 1*stack_size + 128 * 3, fs->GetFrame(stack_size_log, 1, 3U));
+ EXPECT_EQ(base + 2*stack_size + 256 * 5, fs->GetFrame(stack_size_log, 2, 5U));
+ fs->Destroy();
+}
+
+TEST(FakeStack, Allocate) {
+ const uptr stack_size_log = 19;
+ FakeStack *fs = FakeStack::Create(stack_size_log);
+ std::map<FakeFrame *, uptr> s;
+ for (int iter = 0; iter < 2; iter++) {
+ s.clear();
+ for (uptr cid = 0; cid < FakeStack::kNumberOfSizeClasses; cid++) {
+ uptr n = FakeStack::NumberOfFrames(stack_size_log, cid);
+ uptr bytes_in_class = FakeStack::BytesInSizeClass(cid);
+ for (uptr j = 0; j < n; j++) {
+ FakeFrame *ff = fs->Allocate(stack_size_log, cid, 0);
+ uptr x = reinterpret_cast<uptr>(ff);
+ EXPECT_TRUE(s.insert(std::make_pair(ff, cid)).second);
+ EXPECT_EQ(x, fs->AddrIsInFakeStack(x));
+ EXPECT_EQ(x, fs->AddrIsInFakeStack(x + 1));
+ EXPECT_EQ(x, fs->AddrIsInFakeStack(x + bytes_in_class - 1));
+ EXPECT_NE(x, fs->AddrIsInFakeStack(x + bytes_in_class));
+ }
+ // We are out of fake stack, so Allocate should return 0.
+ EXPECT_EQ(0UL, fs->Allocate(stack_size_log, cid, 0));
+ }
+ for (std::map<FakeFrame *, uptr>::iterator it = s.begin(); it != s.end();
+ ++it) {
+ fs->Deallocate(reinterpret_cast<uptr>(it->first), it->second);
+ }
+ }
+ fs->Destroy();
+}
+
+static void RecursiveFunction(FakeStack *fs, int depth) {
+ uptr class_id = depth / 3;
+ FakeFrame *ff = fs->Allocate(fs->stack_size_log(), class_id, 0);
+ if (depth) {
+ RecursiveFunction(fs, depth - 1);
+ RecursiveFunction(fs, depth - 1);
+ }
+ fs->Deallocate(reinterpret_cast<uptr>(ff), class_id);
+}
+
+TEST(FakeStack, RecursiveStressTest) {
+ const uptr stack_size_log = 16;
+ FakeStack *fs = FakeStack::Create(stack_size_log);
+ RecursiveFunction(fs, 22); // with 26 runs for 2-3 seconds.
+ fs->Destroy();
+}
+
+} // namespace __asan
diff --git a/lib/asan/tests/asan_interface_test.cc b/lib/asan/tests/asan_interface_test.cc
new file mode 100644
index 000000000000..f36679012f27
--- /dev/null
+++ b/lib/asan/tests/asan_interface_test.cc
@@ -0,0 +1,426 @@
+//===-- asan_interface_test.cc --------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+//===----------------------------------------------------------------------===//
+#include "asan_test_utils.h"
+#include "sanitizer/asan_interface.h"
+
+TEST(AddressSanitizerInterface, GetEstimatedAllocatedSize) {
+ EXPECT_EQ(0U, __asan_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]));
+ }
+}
+
+static const char* kGetAllocatedSizeErrorMsg =
+ "attempting to call __asan_get_allocated_size()";
+
+TEST(AddressSanitizerInterface, GetAllocatedSizeAndOwnershipTest) {
+ const size_t kArraySize = 100;
+ char *array = Ident((char*)malloc(kArraySize));
+ int *int_ptr = Ident(new int);
+
+ // Allocated memory is owned by allocator. Allocated size should be
+ // equal to requested size.
+ EXPECT_EQ(true, __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));
+
+ // 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),
+ 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));
+
+ // 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);
+ 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));
+ // Allocated size is 0 or 1 depending on the allocator used.
+ EXPECT_LT(__asan_get_allocated_size(zero_alloc), 2U);
+ }
+ free(zero_alloc);
+}
+
+TEST(AddressSanitizerInterface, GetCurrentAllocatedBytesTest) {
+ size_t before_malloc, after_malloc, after_free;
+ char *array;
+ const size_t kMallocSize = 100;
+ before_malloc = __asan_get_current_allocated_bytes();
+
+ array = Ident((char*)malloc(kMallocSize));
+ after_malloc = __asan_get_current_allocated_bytes();
+ EXPECT_EQ(before_malloc + kMallocSize, after_malloc);
+
+ free(array);
+ after_free = __asan_get_current_allocated_bytes();
+ EXPECT_EQ(before_malloc, after_free);
+}
+
+TEST(AddressSanitizerInterface, GetHeapSizeTest) {
+ // asan_allocator2 does not keep huge chunks in free list, but unmaps them.
+ // The chunk should be greater than the quarantine size,
+ // otherwise it will be stuck in quarantine instead of being unmaped.
+ static const size_t kLargeMallocSize = (1 << 28) + 1; // 256M
+ free(Ident(malloc(kLargeMallocSize))); // Drain quarantine.
+ size_t old_heap_size = __asan_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());
+ }
+}
+
+static const size_t kManyThreadsMallocSizes[] = {5, 1UL<<10, 1UL<<14, 357};
+static const size_t kManyThreadsIterations = 250;
+static const size_t kManyThreadsNumThreads =
+ (SANITIZER_WORDSIZE == 32) ? 40 : 200;
+
+static void *ManyThreadsWithStatsWorker(void *arg) {
+ (void)arg;
+ for (size_t iter = 0; iter < kManyThreadsIterations; iter++) {
+ for (size_t size_index = 0; size_index < 4; size_index++) {
+ free(Ident(malloc(kManyThreadsMallocSizes[size_index])));
+ }
+ }
+ // Just one large allocation.
+ free(Ident(malloc(1 << 20)));
+ return 0;
+}
+
+TEST(AddressSanitizerInterface, ManyThreadsWithStatsStressTest) {
+ size_t before_test, after_test, i;
+ pthread_t threads[kManyThreadsNumThreads];
+ before_test = __asan_get_current_allocated_bytes();
+ for (i = 0; i < kManyThreadsNumThreads; i++) {
+ PTHREAD_CREATE(&threads[i], 0,
+ (void* (*)(void *x))ManyThreadsWithStatsWorker, (void*)i);
+ }
+ for (i = 0; i < kManyThreadsNumThreads; i++) {
+ PTHREAD_JOIN(threads[i], 0);
+ }
+ after_test = __asan_get_current_allocated_bytes();
+ // ASan stats also reflect memory usage of internal ASan RTL structs,
+ // so we can't check for equality here.
+ EXPECT_LT(after_test, before_test + (1UL<<20));
+}
+
+static void DoDoubleFree() {
+ int *x = Ident(new int);
+ delete Ident(x);
+ delete Ident(x);
+}
+
+TEST(AddressSanitizerInterface, ExitCode) {
+ int original_exit_code = __asan_set_error_exit_code(7);
+ EXPECT_EXIT(DoDoubleFree(), ::testing::ExitedWithCode(7), "");
+ EXPECT_EQ(7, __asan_set_error_exit_code(8));
+ EXPECT_EXIT(DoDoubleFree(), ::testing::ExitedWithCode(8), "");
+ EXPECT_EQ(8, __asan_set_error_exit_code(original_exit_code));
+ EXPECT_EXIT(DoDoubleFree(),
+ ::testing::ExitedWithCode(original_exit_code), "");
+}
+
+static void MyDeathCallback() {
+ fprintf(stderr, "MyDeathCallback\n");
+}
+
+TEST(AddressSanitizerInterface, DeathCallbackTest) {
+ __asan_set_death_callback(MyDeathCallback);
+ EXPECT_DEATH(DoDoubleFree(), "MyDeathCallback");
+ __asan_set_death_callback(NULL);
+}
+
+static const char* kUseAfterPoisonErrorMessage = "use-after-poison";
+
+#define GOOD_ACCESS(ptr, offset) \
+ EXPECT_FALSE(__asan_address_is_poisoned(ptr + offset))
+
+#define BAD_ACCESS(ptr, offset) \
+ EXPECT_TRUE(__asan_address_is_poisoned(ptr + offset))
+
+TEST(AddressSanitizerInterface, SimplePoisonMemoryRegionTest) {
+ char *array = Ident((char*)malloc(120));
+ // poison array[40..80)
+ __asan_poison_memory_region(array + 40, 40);
+ GOOD_ACCESS(array, 39);
+ GOOD_ACCESS(array, 80);
+ BAD_ACCESS(array, 40);
+ BAD_ACCESS(array, 60);
+ BAD_ACCESS(array, 79);
+ char value;
+ EXPECT_DEATH(value = Ident(array[40]), kUseAfterPoisonErrorMessage);
+ __asan_unpoison_memory_region(array + 40, 40);
+ // access previously poisoned memory.
+ GOOD_ACCESS(array, 40);
+ GOOD_ACCESS(array, 79);
+ free(array);
+}
+
+TEST(AddressSanitizerInterface, OverlappingPoisonMemoryRegionTest) {
+ char *array = Ident((char*)malloc(120));
+ // Poison [0..40) and [80..120)
+ __asan_poison_memory_region(array, 40);
+ __asan_poison_memory_region(array + 80, 40);
+ BAD_ACCESS(array, 20);
+ GOOD_ACCESS(array, 60);
+ BAD_ACCESS(array, 100);
+ // Poison whole array - [0..120)
+ __asan_poison_memory_region(array, 120);
+ BAD_ACCESS(array, 60);
+ // Unpoison [24..96)
+ __asan_unpoison_memory_region(array + 24, 72);
+ BAD_ACCESS(array, 23);
+ GOOD_ACCESS(array, 24);
+ GOOD_ACCESS(array, 60);
+ GOOD_ACCESS(array, 95);
+ BAD_ACCESS(array, 96);
+ free(array);
+}
+
+TEST(AddressSanitizerInterface, PushAndPopWithPoisoningTest) {
+ // Vector of capacity 20
+ char *vec = Ident((char*)malloc(20));
+ __asan_poison_memory_region(vec, 20);
+ for (size_t i = 0; i < 7; i++) {
+ // Simulate push_back.
+ __asan_unpoison_memory_region(vec + i, 1);
+ GOOD_ACCESS(vec, i);
+ BAD_ACCESS(vec, i + 1);
+ }
+ for (size_t i = 7; i > 0; i--) {
+ // Simulate pop_back.
+ __asan_poison_memory_region(vec + i - 1, 1);
+ BAD_ACCESS(vec, i - 1);
+ if (i > 1) GOOD_ACCESS(vec, i - 2);
+ }
+ free(vec);
+}
+
+// Make sure that each aligned block of size "2^granularity" doesn't have
+// "true" value before "false" value.
+static void MakeShadowValid(bool *shadow, int length, int granularity) {
+ bool can_be_poisoned = true;
+ for (int i = length - 1; i >= 0; i--) {
+ if (!shadow[i])
+ can_be_poisoned = false;
+ if (!can_be_poisoned)
+ shadow[i] = false;
+ if (i % (1 << granularity) == 0) {
+ can_be_poisoned = true;
+ }
+ }
+}
+
+TEST(AddressSanitizerInterface, PoisoningStressTest) {
+ const size_t kSize = 24;
+ bool expected[kSize];
+ char *arr = Ident((char*)malloc(kSize));
+ for (size_t l1 = 0; l1 < kSize; l1++) {
+ for (size_t s1 = 1; l1 + s1 <= kSize; s1++) {
+ for (size_t l2 = 0; l2 < kSize; l2++) {
+ for (size_t s2 = 1; l2 + s2 <= kSize; s2++) {
+ // Poison [l1, l1+s1), [l2, l2+s2) and check result.
+ __asan_unpoison_memory_region(arr, kSize);
+ __asan_poison_memory_region(arr + l1, s1);
+ __asan_poison_memory_region(arr + l2, s2);
+ memset(expected, false, kSize);
+ memset(expected + l1, true, s1);
+ MakeShadowValid(expected, kSize, /*granularity*/ 3);
+ memset(expected + l2, true, s2);
+ MakeShadowValid(expected, kSize, /*granularity*/ 3);
+ for (size_t i = 0; i < kSize; i++) {
+ ASSERT_EQ(expected[i], __asan_address_is_poisoned(arr + i));
+ }
+ // Unpoison [l1, l1+s1) and [l2, l2+s2) and check result.
+ __asan_poison_memory_region(arr, kSize);
+ __asan_unpoison_memory_region(arr + l1, s1);
+ __asan_unpoison_memory_region(arr + l2, s2);
+ memset(expected, true, kSize);
+ memset(expected + l1, false, s1);
+ MakeShadowValid(expected, kSize, /*granularity*/ 3);
+ memset(expected + l2, false, s2);
+ MakeShadowValid(expected, kSize, /*granularity*/ 3);
+ for (size_t i = 0; i < kSize; i++) {
+ ASSERT_EQ(expected[i], __asan_address_is_poisoned(arr + i));
+ }
+ }
+ }
+ }
+ }
+ free(arr);
+}
+
+TEST(AddressSanitizerInterface, GlobalRedzones) {
+ GOOD_ACCESS(glob1, 1 - 1);
+ GOOD_ACCESS(glob2, 2 - 1);
+ GOOD_ACCESS(glob3, 3 - 1);
+ GOOD_ACCESS(glob4, 4 - 1);
+ GOOD_ACCESS(glob5, 5 - 1);
+ GOOD_ACCESS(glob6, 6 - 1);
+ GOOD_ACCESS(glob7, 7 - 1);
+ GOOD_ACCESS(glob8, 8 - 1);
+ GOOD_ACCESS(glob9, 9 - 1);
+ GOOD_ACCESS(glob10, 10 - 1);
+ GOOD_ACCESS(glob11, 11 - 1);
+ GOOD_ACCESS(glob12, 12 - 1);
+ GOOD_ACCESS(glob13, 13 - 1);
+ GOOD_ACCESS(glob14, 14 - 1);
+ GOOD_ACCESS(glob15, 15 - 1);
+ GOOD_ACCESS(glob16, 16 - 1);
+ GOOD_ACCESS(glob17, 17 - 1);
+ GOOD_ACCESS(glob1000, 1000 - 1);
+ GOOD_ACCESS(glob10000, 10000 - 1);
+ GOOD_ACCESS(glob100000, 100000 - 1);
+
+ BAD_ACCESS(glob1, 1);
+ BAD_ACCESS(glob2, 2);
+ BAD_ACCESS(glob3, 3);
+ BAD_ACCESS(glob4, 4);
+ BAD_ACCESS(glob5, 5);
+ BAD_ACCESS(glob6, 6);
+ BAD_ACCESS(glob7, 7);
+ BAD_ACCESS(glob8, 8);
+ BAD_ACCESS(glob9, 9);
+ BAD_ACCESS(glob10, 10);
+ BAD_ACCESS(glob11, 11);
+ BAD_ACCESS(glob12, 12);
+ BAD_ACCESS(glob13, 13);
+ BAD_ACCESS(glob14, 14);
+ BAD_ACCESS(glob15, 15);
+ BAD_ACCESS(glob16, 16);
+ BAD_ACCESS(glob17, 17);
+ BAD_ACCESS(glob1000, 1000);
+ BAD_ACCESS(glob1000, 1100); // Redzone is at least 101 bytes.
+ BAD_ACCESS(glob10000, 10000);
+ BAD_ACCESS(glob10000, 11000); // Redzone is at least 1001 bytes.
+ BAD_ACCESS(glob100000, 100000);
+ BAD_ACCESS(glob100000, 110000); // Redzone is at least 10001 bytes.
+}
+
+TEST(AddressSanitizerInterface, PoisonedRegion) {
+ size_t rz = 16;
+ for (size_t size = 1; size <= 64; size++) {
+ char *p = new char[size];
+ for (size_t beg = 0; beg < size + rz; beg++) {
+ for (size_t end = beg; end < size + rz; end++) {
+ void *first_poisoned = __asan_region_is_poisoned(p + beg, end - beg);
+ if (beg == end) {
+ EXPECT_FALSE(first_poisoned);
+ } else if (beg < size && end <= size) {
+ EXPECT_FALSE(first_poisoned);
+ } else if (beg >= size) {
+ EXPECT_EQ(p + beg, first_poisoned);
+ } else {
+ EXPECT_GT(end, size);
+ EXPECT_EQ(p + size, first_poisoned);
+ }
+ }
+ }
+ delete [] p;
+ }
+}
+
+// This is a performance benchmark for manual runs.
+// asan's memset interceptor calls mem_is_zero for the entire shadow region.
+// the profile should look like this:
+// 89.10% [.] __memset_sse2
+// 10.50% [.] __sanitizer::mem_is_zero
+// I.e. mem_is_zero should consume ~ SHADOW_GRANULARITY less CPU cycles
+// than memset itself.
+TEST(AddressSanitizerInterface, DISABLED_StressLargeMemset) {
+ size_t size = 1 << 20;
+ char *x = new char[size];
+ for (int i = 0; i < 100000; i++)
+ Ident(memset)(x, 0, size);
+ delete [] x;
+}
+
+// Same here, but we run memset with small sizes.
+TEST(AddressSanitizerInterface, DISABLED_StressSmallMemset) {
+ size_t size = 32;
+ char *x = new char[size];
+ for (int i = 0; i < 100000000; i++)
+ Ident(memset)(x, 0, size);
+ delete [] x;
+}
+static const char *kInvalidPoisonMessage = "invalid-poison-memory-range";
+static const char *kInvalidUnpoisonMessage = "invalid-unpoison-memory-range";
+
+TEST(AddressSanitizerInterface, DISABLED_InvalidPoisonAndUnpoisonCallsTest) {
+ char *array = Ident((char*)malloc(120));
+ __asan_unpoison_memory_region(array, 120);
+ // Try to unpoison not owned memory
+ EXPECT_DEATH(__asan_unpoison_memory_region(array, 121),
+ kInvalidUnpoisonMessage);
+ EXPECT_DEATH(__asan_unpoison_memory_region(array - 1, 120),
+ kInvalidUnpoisonMessage);
+
+ __asan_poison_memory_region(array, 120);
+ // Try to poison not owned memory.
+ EXPECT_DEATH(__asan_poison_memory_region(array, 121), kInvalidPoisonMessage);
+ EXPECT_DEATH(__asan_poison_memory_region(array - 1, 120),
+ kInvalidPoisonMessage);
+ free(array);
+}
+
+static void ErrorReportCallbackOneToZ(const char *report) {
+ int report_len = strlen(report);
+ ASSERT_EQ(6, write(2, "ABCDEF", 6));
+ ASSERT_EQ(report_len, write(2, report, report_len));
+ ASSERT_EQ(6, write(2, "ABCDEF", 6));
+ _exit(1);
+}
+
+TEST(AddressSanitizerInterface, SetErrorReportCallbackTest) {
+ __asan_set_error_report_callback(ErrorReportCallbackOneToZ);
+ EXPECT_DEATH(__asan_report_error(0, 0, 0, 0, true, 1),
+ ASAN_PCRE_DOTALL "ABCDEF.*AddressSanitizer.*WRITE.*ABCDEF");
+ __asan_set_error_report_callback(NULL);
+}
+
+TEST(AddressSanitizerInterface, GetOwnershipStressTest) {
+ std::vector<char *> pointers;
+ std::vector<size_t> sizes;
+ const size_t kNumMallocs = 1 << 9;
+ for (size_t i = 0; i < kNumMallocs; i++) {
+ size_t size = i * 100 + 1;
+ pointers.push_back((char*)malloc(size));
+ sizes.push_back(size);
+ }
+ for (size_t i = 0; i < 4000000; i++) {
+ EXPECT_FALSE(__asan_get_ownership(&pointers));
+ EXPECT_FALSE(__asan_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]));
+ }
+ for (size_t i = 0, n = pointers.size(); i < n; i++)
+ free(pointers[i]);
+}
+
diff --git a/lib/asan/tests/asan_mac_test_helpers.mm b/lib/asan/tests/asan_mac_test_helpers.mm
index 4cbd2bb247fd..a7e4b9d1928b 100644
--- a/lib/asan/tests/asan_mac_test_helpers.mm
+++ b/lib/asan/tests/asan_mac_test_helpers.mm
@@ -1,5 +1,6 @@
// Mac OS X 10.6 or higher only.
#include <dispatch/dispatch.h>
+#include <pthread.h> // for pthread_yield_np()
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -11,26 +12,26 @@
// This is a (void*)(void*) function so it can be passed to pthread_create.
void *CFAllocatorDefaultDoubleFree(void *unused) {
- void *mem = CFAllocatorAllocate(kCFAllocatorDefault, 5, 0);
+ void *mem = CFAllocatorAllocate(kCFAllocatorDefault, 5, 0);
CFAllocatorDeallocate(kCFAllocatorDefault, mem);
CFAllocatorDeallocate(kCFAllocatorDefault, mem);
return 0;
}
void CFAllocatorSystemDefaultDoubleFree() {
- void *mem = CFAllocatorAllocate(kCFAllocatorSystemDefault, 5, 0);
+ void *mem = CFAllocatorAllocate(kCFAllocatorSystemDefault, 5, 0);
CFAllocatorDeallocate(kCFAllocatorSystemDefault, mem);
CFAllocatorDeallocate(kCFAllocatorSystemDefault, mem);
}
void CFAllocatorMallocDoubleFree() {
- void *mem = CFAllocatorAllocate(kCFAllocatorMalloc, 5, 0);
+ void *mem = CFAllocatorAllocate(kCFAllocatorMalloc, 5, 0);
CFAllocatorDeallocate(kCFAllocatorMalloc, mem);
CFAllocatorDeallocate(kCFAllocatorMalloc, mem);
}
void CFAllocatorMallocZoneDoubleFree() {
- void *mem = CFAllocatorAllocate(kCFAllocatorMallocZone, 5, 0);
+ void *mem = CFAllocatorAllocate(kCFAllocatorMallocZone, 5, 0);
CFAllocatorDeallocate(kCFAllocatorMallocZone, mem);
CFAllocatorDeallocate(kCFAllocatorMallocZone, mem);
}
@@ -77,10 +78,17 @@ void worker_do_crash(int size) {
free(mem);
}
+// Used by the GCD tests to avoid a race between the worker thread reporting a
+// memory error and the main thread which may exit with exit code 0 before
+// that.
+void wait_forever() {
+ volatile bool infinite = true;
+ while (infinite) pthread_yield_np();
+}
+
// Tests for the Grand Central Dispatch. See
// http://developer.apple.com/library/mac/#documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html
// for the reference.
-
void TestGCDDispatchAsync() {
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_block_t block = ^{ worker_do_crash(1024); };
@@ -88,8 +96,7 @@ void TestGCDDispatchAsync() {
// pthread_create(). We need to verify that AddressSanitizer notices that the
// thread has started.
dispatch_async(queue, block);
- // TODO(glider): this is hacky. Need to wait for the worker instead.
- sleep(1);
+ wait_forever();
}
void TestGCDDispatchSync() {
@@ -99,8 +106,7 @@ void TestGCDDispatchSync() {
// pthread_create(). We need to verify that AddressSanitizer notices that the
// thread has started.
dispatch_sync(queue, block);
- // TODO(glider): this is hacky. Need to wait for the worker instead.
- sleep(1);
+ wait_forever();
}
// libdispatch spawns a rather small number of threads and reuses them. We need
@@ -113,8 +119,7 @@ void TestGCDReuseWqthreadsAsync() {
dispatch_async(queue, block_alloc);
}
dispatch_async(queue, block_crash);
- // TODO(glider): this is hacky. Need to wait for the workers instead.
- sleep(1);
+ wait_forever();
}
// Try to trigger abnormal behaviour of dispatch_sync() being unhandled by us.
@@ -130,8 +135,7 @@ void TestGCDReuseWqthreadsSync() {
dispatch_sync(queue[i % 4], block_alloc);
}
dispatch_sync(queue[3], block_crash);
- // TODO(glider): this is hacky. Need to wait for the workers instead.
- sleep(1);
+ wait_forever();
}
void TestGCDDispatchAfter() {
@@ -141,9 +145,7 @@ void TestGCDDispatchAfter() {
dispatch_time_t milestone =
dispatch_time(DISPATCH_TIME_NOW, 1LL * NSEC_PER_SEC);
dispatch_after(milestone, queue, block_crash);
- // Let's wait for a bit longer now.
- // TODO(glider): this is still hacky.
- sleep(2);
+ wait_forever();
}
void worker_do_deallocate(void *ptr) {
@@ -172,7 +174,7 @@ void TestGCDSourceEvent() {
access_memory(&mem[10]);
});
dispatch_resume(timer);
- sleep(2);
+ wait_forever();
}
void TestGCDSourceCancel() {
@@ -196,7 +198,7 @@ void TestGCDSourceCancel() {
access_memory(&mem[10]);
});
dispatch_resume(timer);
- sleep(2);
+ wait_forever();
}
void TestGCDGroupAsync() {
@@ -207,6 +209,7 @@ void TestGCDGroupAsync() {
access_memory(&mem[10]);
});
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
+ wait_forever();
}
@interface FixedArray : NSObject {
diff --git a/lib/asan/tests/asan_noinst_test.cc b/lib/asan/tests/asan_noinst_test.cc
index 54fdd1979b8e..cb6223c09a46 100644
--- a/lib/asan/tests/asan_noinst_test.cc
+++ b/lib/asan/tests/asan_noinst_test.cc
@@ -25,6 +25,46 @@
#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
+
+extern "C" {
+// Set specific ASan options for uninstrumented unittest.
+const char* __asan_default_options() {
+ return "allow_reexec=0";
+}
+} // extern "C"
+
+// Make sure __asan_init is called before any test case is run.
+struct AsanInitCaller {
+ AsanInitCaller() { __asan_init(); }
+};
+static AsanInitCaller asan_init_caller;
TEST(AddressSanitizer, InternalSimpleDeathTest) {
EXPECT_DEATH(exit(1), "");
@@ -66,6 +106,7 @@ static void MallocStress(size_t n) {
size_t alignment = 1 << (my_rand_r(&seed) % 10 + 1);
char *ptr = (char*)__asan::asan_memalign(alignment, size,
&stack2, __asan::FROM_MALLOC);
+ EXPECT_EQ(size, __asan::asan_malloc_usable_size(ptr, 0, 0));
vec.push_back(ptr);
ptr[0] = 0;
ptr[size-1] = 0;
@@ -118,144 +159,6 @@ TEST(AddressSanitizer, DISABLED_InternalPrintShadow) {
}
}
-static uptr pc_array[] = {
-#if SANITIZER_WORDSIZE == 64
- 0x7effbf756068ULL,
- 0x7effbf75e5abULL,
- 0x7effc0625b7cULL,
- 0x7effc05b8997ULL,
- 0x7effbf990577ULL,
- 0x7effbf990c56ULL,
- 0x7effbf992f3cULL,
- 0x7effbf950c22ULL,
- 0x7effc036dba0ULL,
- 0x7effc03638a3ULL,
- 0x7effc035be4aULL,
- 0x7effc0539c45ULL,
- 0x7effc0539a65ULL,
- 0x7effc03db9b3ULL,
- 0x7effc03db100ULL,
- 0x7effc037c7b8ULL,
- 0x7effc037bfffULL,
- 0x7effc038b777ULL,
- 0x7effc038021cULL,
- 0x7effc037c7d1ULL,
- 0x7effc037bfffULL,
- 0x7effc038b777ULL,
- 0x7effc038021cULL,
- 0x7effc037c7d1ULL,
- 0x7effc037bfffULL,
- 0x7effc038b777ULL,
- 0x7effc038021cULL,
- 0x7effc037c7d1ULL,
- 0x7effc037bfffULL,
- 0x7effc0520d26ULL,
- 0x7effc009ddffULL,
- 0x7effbf90bb50ULL,
- 0x7effbdddfa69ULL,
- 0x7effbdde1fe2ULL,
- 0x7effbdde2424ULL,
- 0x7effbdde27b3ULL,
- 0x7effbddee53bULL,
- 0x7effbdde1988ULL,
- 0x7effbdde0904ULL,
- 0x7effc106ce0dULL,
- 0x7effbcc3fa04ULL,
- 0x7effbcc3f6a4ULL,
- 0x7effbcc3e726ULL,
- 0x7effbcc40852ULL,
- 0x7effb681ec4dULL,
-#endif // SANITIZER_WORDSIZE
- 0xB0B5E768,
- 0x7B682EC1,
- 0x367F9918,
- 0xAE34E13,
- 0xBA0C6C6,
- 0x13250F46,
- 0xA0D6A8AB,
- 0x2B07C1A8,
- 0x6C844F4A,
- 0x2321B53,
- 0x1F3D4F8F,
- 0x3FE2924B,
- 0xB7A2F568,
- 0xBD23950A,
- 0x61020930,
- 0x33E7970C,
- 0x405998A1,
- 0x59F3551D,
- 0x350E3028,
- 0xBC55A28D,
- 0x361F3AED,
- 0xBEAD0F73,
- 0xAEF28479,
- 0x757E971F,
- 0xAEBA450,
- 0x43AD22F5,
- 0x8C2C50C4,
- 0x7AD8A2E1,
- 0x69EE4EE8,
- 0xC08DFF,
- 0x4BA6538,
- 0x3708AB2,
- 0xC24B6475,
- 0x7C8890D7,
- 0x6662495F,
- 0x9B641689,
- 0xD3596B,
- 0xA1049569,
- 0x44CBC16,
- 0x4D39C39F
-};
-
-void CompressStackTraceTest(size_t n_iter) {
- u32 seed = my_rand();
- const size_t kNumPcs = ARRAY_SIZE(pc_array);
- u32 compressed[2 * kNumPcs];
-
- for (size_t iter = 0; iter < n_iter; iter++) {
- std::random_shuffle(pc_array, pc_array + kNumPcs);
- StackTrace stack0, stack1;
- stack0.CopyFrom(pc_array, kNumPcs);
- stack0.size = std::max((size_t)1, (size_t)(my_rand_r(&seed) % stack0.size));
- size_t compress_size =
- std::max((size_t)2, (size_t)my_rand_r(&seed) % (2 * kNumPcs));
- size_t n_frames =
- StackTrace::CompressStack(&stack0, compressed, compress_size);
- Ident(n_frames);
- assert(n_frames <= stack0.size);
- StackTrace::UncompressStack(&stack1, compressed, compress_size);
- assert(stack1.size == n_frames);
- for (size_t i = 0; i < stack1.size; i++) {
- assert(stack0.trace[i] == stack1.trace[i]);
- }
- }
-}
-
-TEST(AddressSanitizer, CompressStackTraceTest) {
- CompressStackTraceTest(10000);
-}
-
-void CompressStackTraceBenchmark(size_t n_iter) {
- const size_t kNumPcs = ARRAY_SIZE(pc_array);
- u32 compressed[2 * kNumPcs];
- std::random_shuffle(pc_array, pc_array + kNumPcs);
-
- StackTrace stack0;
- stack0.CopyFrom(pc_array, kNumPcs);
- stack0.size = kNumPcs;
- for (size_t iter = 0; iter < n_iter; iter++) {
- size_t compress_size = kNumPcs;
- size_t n_frames =
- StackTrace::CompressStack(&stack0, compressed, compress_size);
- Ident(n_frames);
- }
-}
-
-TEST(AddressSanitizer, CompressStackTraceBenchmark) {
- CompressStackTraceBenchmark(1 << 24);
-}
-
TEST(AddressSanitizer, QuarantineTest) {
StackTrace stack;
stack.trace[0] = 0x890;
@@ -332,463 +235,13 @@ TEST(AddressSanitizer, ThreadedOneSizeMallocStressTest) {
}
}
-TEST(AddressSanitizer, MemsetWildAddressTest) {
+TEST(AddressSanitizer, ShadowRegionIsPoisonedTest) {
using __asan::kHighMemEnd;
- typedef void*(*memset_p)(void*, int, size_t);
- // Prevent inlining of memset().
- volatile memset_p libc_memset = (memset_p)memset;
- EXPECT_DEATH(libc_memset((void*)(kLowShadowBeg + 200), 0, 100),
- (kLowShadowEnd == 0) ? "unknown-crash.*shadow gap"
- : "unknown-crash.*low shadow");
- EXPECT_DEATH(libc_memset((void*)(kShadowGapBeg + 200), 0, 100),
- "unknown-crash.*shadow gap");
- EXPECT_DEATH(libc_memset((void*)(kHighShadowBeg + 200), 0, 100),
- "unknown-crash.*high shadow");
-}
-
-TEST(AddressSanitizerInterface, GetEstimatedAllocatedSize) {
- EXPECT_EQ(0U, __asan_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]));
- }
-}
-
-static const char* kGetAllocatedSizeErrorMsg =
- "attempting to call __asan_get_allocated_size()";
-
-TEST(AddressSanitizerInterface, GetAllocatedSizeAndOwnershipTest) {
- const size_t kArraySize = 100;
- char *array = Ident((char*)malloc(kArraySize));
- int *int_ptr = Ident(new int);
-
- // Allocated memory is owned by allocator. Allocated size should be
- // equal to requested size.
- EXPECT_EQ(true, __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));
-
- // 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),
- 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));
-
- // 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);
- 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));
- // Allocated size is 0 or 1 depending on the allocator used.
- EXPECT_LT(__asan_get_allocated_size(zero_alloc), 2U);
- }
- free(zero_alloc);
-}
-
-TEST(AddressSanitizerInterface, GetCurrentAllocatedBytesTest) {
- size_t before_malloc, after_malloc, after_free;
- char *array;
- const size_t kMallocSize = 100;
- before_malloc = __asan_get_current_allocated_bytes();
-
- array = Ident((char*)malloc(kMallocSize));
- after_malloc = __asan_get_current_allocated_bytes();
- EXPECT_EQ(before_malloc + kMallocSize, after_malloc);
-
- free(array);
- after_free = __asan_get_current_allocated_bytes();
- EXPECT_EQ(before_malloc, after_free);
-}
-
-static void DoDoubleFree() {
- int *x = Ident(new int);
- delete Ident(x);
- delete Ident(x);
-}
-
-TEST(AddressSanitizerInterface, GetHeapSizeTest) {
- // asan_allocator2 does not keep huge chunks in free list, but unmaps them.
- // The chunk should be greater than the quarantine size,
- // otherwise it will be stuck in quarantine instead of being unmaped.
- static const size_t kLargeMallocSize = (1 << 28) + 1; // 256M
- free(Ident(malloc(kLargeMallocSize))); // Drain quarantine.
- uptr old_heap_size = __asan_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());
- }
-}
-
-static const size_t kManyThreadsMallocSizes[] = {5, 1UL<<10, 1UL<<14, 357};
-static const size_t kManyThreadsIterations = 250;
-static const size_t kManyThreadsNumThreads =
- (SANITIZER_WORDSIZE == 32) ? 40 : 200;
-
-void *ManyThreadsWithStatsWorker(void *arg) {
- (void)arg;
- for (size_t iter = 0; iter < kManyThreadsIterations; iter++) {
- for (size_t size_index = 0; size_index < 4; size_index++) {
- free(Ident(malloc(kManyThreadsMallocSizes[size_index])));
- }
- }
- // Just one large allocation.
- free(Ident(malloc(1 << 20)));
- return 0;
-}
-
-TEST(AddressSanitizerInterface, ManyThreadsWithStatsStressTest) {
- size_t before_test, after_test, i;
- pthread_t threads[kManyThreadsNumThreads];
- before_test = __asan_get_current_allocated_bytes();
- for (i = 0; i < kManyThreadsNumThreads; i++) {
- PTHREAD_CREATE(&threads[i], 0,
- (void* (*)(void *x))ManyThreadsWithStatsWorker, (void*)i);
- }
- for (i = 0; i < kManyThreadsNumThreads; i++) {
- PTHREAD_JOIN(threads[i], 0);
- }
- after_test = __asan_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));
-}
-
-TEST(AddressSanitizerInterface, ExitCode) {
- int original_exit_code = __asan_set_error_exit_code(7);
- EXPECT_EXIT(DoDoubleFree(), ::testing::ExitedWithCode(7), "");
- EXPECT_EQ(7, __asan_set_error_exit_code(8));
- EXPECT_EXIT(DoDoubleFree(), ::testing::ExitedWithCode(8), "");
- EXPECT_EQ(8, __asan_set_error_exit_code(original_exit_code));
- EXPECT_EXIT(DoDoubleFree(),
- ::testing::ExitedWithCode(original_exit_code), "");
-}
-
-static void MyDeathCallback() {
- fprintf(stderr, "MyDeathCallback\n");
-}
-
-TEST(AddressSanitizerInterface, DeathCallbackTest) {
- __asan_set_death_callback(MyDeathCallback);
- EXPECT_DEATH(DoDoubleFree(), "MyDeathCallback");
- __asan_set_death_callback(NULL);
-}
-
-static const char* kUseAfterPoisonErrorMessage = "use-after-poison";
-
-#define GOOD_ACCESS(ptr, offset) \
- EXPECT_FALSE(__asan::AddressIsPoisoned((uptr)(ptr + offset)))
-
-#define BAD_ACCESS(ptr, offset) \
- EXPECT_TRUE(__asan::AddressIsPoisoned((uptr)(ptr + offset)))
-
-TEST(AddressSanitizerInterface, SimplePoisonMemoryRegionTest) {
- char *array = Ident((char*)malloc(120));
- // poison array[40..80)
- __asan_poison_memory_region(array + 40, 40);
- GOOD_ACCESS(array, 39);
- GOOD_ACCESS(array, 80);
- BAD_ACCESS(array, 40);
- BAD_ACCESS(array, 60);
- BAD_ACCESS(array, 79);
- EXPECT_DEATH(__asan_report_error(0, 0, 0, (uptr)(array + 40), true, 1),
- kUseAfterPoisonErrorMessage);
- __asan_unpoison_memory_region(array + 40, 40);
- // access previously poisoned memory.
- GOOD_ACCESS(array, 40);
- GOOD_ACCESS(array, 79);
- free(array);
-}
-
-TEST(AddressSanitizerInterface, OverlappingPoisonMemoryRegionTest) {
- char *array = Ident((char*)malloc(120));
- // Poison [0..40) and [80..120)
- __asan_poison_memory_region(array, 40);
- __asan_poison_memory_region(array + 80, 40);
- BAD_ACCESS(array, 20);
- GOOD_ACCESS(array, 60);
- BAD_ACCESS(array, 100);
- // Poison whole array - [0..120)
- __asan_poison_memory_region(array, 120);
- BAD_ACCESS(array, 60);
- // Unpoison [24..96)
- __asan_unpoison_memory_region(array + 24, 72);
- BAD_ACCESS(array, 23);
- GOOD_ACCESS(array, 24);
- GOOD_ACCESS(array, 60);
- GOOD_ACCESS(array, 95);
- BAD_ACCESS(array, 96);
- free(array);
-}
-
-TEST(AddressSanitizerInterface, PushAndPopWithPoisoningTest) {
- // Vector of capacity 20
- char *vec = Ident((char*)malloc(20));
- __asan_poison_memory_region(vec, 20);
- for (size_t i = 0; i < 7; i++) {
- // Simulate push_back.
- __asan_unpoison_memory_region(vec + i, 1);
- GOOD_ACCESS(vec, i);
- BAD_ACCESS(vec, i + 1);
- }
- for (size_t i = 7; i > 0; i--) {
- // Simulate pop_back.
- __asan_poison_memory_region(vec + i - 1, 1);
- BAD_ACCESS(vec, i - 1);
- if (i > 1) GOOD_ACCESS(vec, i - 2);
- }
- free(vec);
-}
-
-TEST(AddressSanitizerInterface, GlobalRedzones) {
- GOOD_ACCESS(glob1, 1 - 1);
- GOOD_ACCESS(glob2, 2 - 1);
- GOOD_ACCESS(glob3, 3 - 1);
- GOOD_ACCESS(glob4, 4 - 1);
- GOOD_ACCESS(glob5, 5 - 1);
- GOOD_ACCESS(glob6, 6 - 1);
- GOOD_ACCESS(glob7, 7 - 1);
- GOOD_ACCESS(glob8, 8 - 1);
- GOOD_ACCESS(glob9, 9 - 1);
- GOOD_ACCESS(glob10, 10 - 1);
- GOOD_ACCESS(glob11, 11 - 1);
- GOOD_ACCESS(glob12, 12 - 1);
- GOOD_ACCESS(glob13, 13 - 1);
- GOOD_ACCESS(glob14, 14 - 1);
- GOOD_ACCESS(glob15, 15 - 1);
- GOOD_ACCESS(glob16, 16 - 1);
- GOOD_ACCESS(glob17, 17 - 1);
- GOOD_ACCESS(glob1000, 1000 - 1);
- GOOD_ACCESS(glob10000, 10000 - 1);
- GOOD_ACCESS(glob100000, 100000 - 1);
-
- BAD_ACCESS(glob1, 1);
- BAD_ACCESS(glob2, 2);
- BAD_ACCESS(glob3, 3);
- BAD_ACCESS(glob4, 4);
- BAD_ACCESS(glob5, 5);
- BAD_ACCESS(glob6, 6);
- BAD_ACCESS(glob7, 7);
- BAD_ACCESS(glob8, 8);
- BAD_ACCESS(glob9, 9);
- BAD_ACCESS(glob10, 10);
- BAD_ACCESS(glob11, 11);
- BAD_ACCESS(glob12, 12);
- BAD_ACCESS(glob13, 13);
- BAD_ACCESS(glob14, 14);
- BAD_ACCESS(glob15, 15);
- BAD_ACCESS(glob16, 16);
- BAD_ACCESS(glob17, 17);
- BAD_ACCESS(glob1000, 1000);
- BAD_ACCESS(glob1000, 1100); // Redzone is at least 101 bytes.
- BAD_ACCESS(glob10000, 10000);
- BAD_ACCESS(glob10000, 11000); // Redzone is at least 1001 bytes.
- BAD_ACCESS(glob100000, 100000);
- BAD_ACCESS(glob100000, 110000); // Redzone is at least 10001 bytes.
-}
-
-// Make sure that each aligned block of size "2^granularity" doesn't have
-// "true" value before "false" value.
-static void MakeShadowValid(bool *shadow, int length, int granularity) {
- bool can_be_poisoned = true;
- for (int i = length - 1; i >= 0; i--) {
- if (!shadow[i])
- can_be_poisoned = false;
- if (!can_be_poisoned)
- shadow[i] = false;
- if (i % (1 << granularity) == 0) {
- can_be_poisoned = true;
- }
- }
-}
-
-TEST(AddressSanitizerInterface, PoisoningStressTest) {
- const size_t kSize = 24;
- bool expected[kSize];
- char *arr = Ident((char*)malloc(kSize));
- for (size_t l1 = 0; l1 < kSize; l1++) {
- for (size_t s1 = 1; l1 + s1 <= kSize; s1++) {
- for (size_t l2 = 0; l2 < kSize; l2++) {
- for (size_t s2 = 1; l2 + s2 <= kSize; s2++) {
- // Poison [l1, l1+s1), [l2, l2+s2) and check result.
- __asan_unpoison_memory_region(arr, kSize);
- __asan_poison_memory_region(arr + l1, s1);
- __asan_poison_memory_region(arr + l2, s2);
- memset(expected, false, kSize);
- memset(expected + l1, true, s1);
- MakeShadowValid(expected, kSize, /*granularity*/ 3);
- memset(expected + l2, true, s2);
- MakeShadowValid(expected, kSize, /*granularity*/ 3);
- for (size_t i = 0; i < kSize; i++) {
- ASSERT_EQ(expected[i], __asan_address_is_poisoned(arr + i));
- }
- // Unpoison [l1, l1+s1) and [l2, l2+s2) and check result.
- __asan_poison_memory_region(arr, kSize);
- __asan_unpoison_memory_region(arr + l1, s1);
- __asan_unpoison_memory_region(arr + l2, s2);
- memset(expected, true, kSize);
- memset(expected + l1, false, s1);
- MakeShadowValid(expected, kSize, /*granularity*/ 3);
- memset(expected + l2, false, s2);
- MakeShadowValid(expected, kSize, /*granularity*/ 3);
- for (size_t i = 0; i < kSize; i++) {
- ASSERT_EQ(expected[i], __asan_address_is_poisoned(arr + i));
- }
- }
- }
- }
- }
-}
-
-TEST(AddressSanitizerInterface, PoisonedRegion) {
- size_t rz = 16;
- for (size_t size = 1; size <= 64; size++) {
- char *p = new char[size];
- uptr x = reinterpret_cast<uptr>(p);
- for (size_t beg = 0; beg < size + rz; beg++) {
- for (size_t end = beg; end < size + rz; end++) {
- uptr first_poisoned = __asan_region_is_poisoned(x + beg, end - beg);
- if (beg == end) {
- EXPECT_FALSE(first_poisoned);
- } else if (beg < size && end <= size) {
- EXPECT_FALSE(first_poisoned);
- } else if (beg >= size) {
- EXPECT_EQ(x + beg, first_poisoned);
- } else {
- EXPECT_GT(end, size);
- EXPECT_EQ(x + size, first_poisoned);
- }
- }
- }
- delete [] p;
- }
-}
-
-// This is a performance benchmark for manual runs.
-// asan's memset interceptor calls mem_is_zero for the entire shadow region.
-// the profile should look like this:
-// 89.10% [.] __memset_sse2
-// 10.50% [.] __sanitizer::mem_is_zero
-// I.e. mem_is_zero should consume ~ SHADOW_GRANULARITY less CPU cycles
-// than memset itself.
-TEST(AddressSanitizerInterface, DISABLED_StressLargeMemset) {
- size_t size = 1 << 20;
- char *x = new char[size];
- for (int i = 0; i < 100000; i++)
- Ident(memset)(x, 0, size);
- delete [] x;
-}
-
-// Same here, but we run memset with small sizes.
-TEST(AddressSanitizerInterface, DISABLED_StressSmallMemset) {
- size_t size = 32;
- char *x = new char[size];
- for (int i = 0; i < 100000000; i++)
- Ident(memset)(x, 0, size);
- delete [] x;
-}
-
-static const char *kInvalidPoisonMessage = "invalid-poison-memory-range";
-static const char *kInvalidUnpoisonMessage = "invalid-unpoison-memory-range";
-
-TEST(AddressSanitizerInterface, DISABLED_InvalidPoisonAndUnpoisonCallsTest) {
- char *array = Ident((char*)malloc(120));
- __asan_unpoison_memory_region(array, 120);
- // Try to unpoison not owned memory
- EXPECT_DEATH(__asan_unpoison_memory_region(array, 121),
- kInvalidUnpoisonMessage);
- EXPECT_DEATH(__asan_unpoison_memory_region(array - 1, 120),
- kInvalidUnpoisonMessage);
-
- __asan_poison_memory_region(array, 120);
- // Try to poison not owned memory.
- EXPECT_DEATH(__asan_poison_memory_region(array, 121), kInvalidPoisonMessage);
- EXPECT_DEATH(__asan_poison_memory_region(array - 1, 120),
- kInvalidPoisonMessage);
- free(array);
-}
-
-static void ErrorReportCallbackOneToZ(const char *report) {
- int report_len = strlen(report);
- ASSERT_EQ(6, write(2, "ABCDEF", 6));
- ASSERT_EQ(report_len, write(2, report, report_len));
- ASSERT_EQ(6, write(2, "ABCDEF", 6));
- _exit(1);
-}
-
-TEST(AddressSanitizerInterface, SetErrorReportCallbackTest) {
- __asan_set_error_report_callback(ErrorReportCallbackOneToZ);
- EXPECT_DEATH(__asan_report_error(0, 0, 0, 0, true, 1),
- ASAN_PCRE_DOTALL "ABCDEF.*AddressSanitizer.*WRITE.*ABCDEF");
- __asan_set_error_report_callback(NULL);
-}
-
-TEST(AddressSanitizerInterface, GetOwnershipStressTest) {
- std::vector<char *> pointers;
- std::vector<size_t> sizes;
- const size_t kNumMallocs = 1 << 9;
- for (size_t i = 0; i < kNumMallocs; i++) {
- size_t size = i * 100 + 1;
- pointers.push_back((char*)malloc(size));
- sizes.push_back(size);
- }
- for (size_t i = 0; i < 4000000; i++) {
- EXPECT_FALSE(__asan_get_ownership(&pointers));
- EXPECT_FALSE(__asan_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]));
- }
- for (size_t i = 0, n = pointers.size(); i < n; i++)
- free(pointers[i]);
-}
-
-TEST(AddressSanitizerInterface, CallocOverflow) {
- size_t kArraySize = 4096;
- volatile size_t kMaxSizeT = std::numeric_limits<size_t>::max();
- volatile size_t kArraySize2 = kMaxSizeT / kArraySize + 10;
- void *p = calloc(kArraySize, kArraySize2); // Should return 0.
- EXPECT_EQ(0L, Ident(p));
-}
-
-TEST(AddressSanitizerInterface, CallocOverflow2) {
-#if SANITIZER_WORDSIZE == 32
- size_t kArraySize = 112;
- volatile size_t kArraySize2 = 43878406;
- void *p = calloc(kArraySize, kArraySize2); // Should return 0.
- EXPECT_EQ(0L, Ident(p));
-#endif
-}
-
-TEST(AddressSanitizerInterface, CallocReturnsZeroMem) {
- size_t sizes[] = {16, 1000, 10000, 100000, 2100000};
- for (size_t s = 0; s < ARRAY_SIZE(sizes); 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));
- free(Ident(malloc(Ident(1 << 27)))); // Try to drain the quarantine.
- }
- }
+ // Check that __asan_region_is_poisoned works for shadow regions.
+ uptr ptr = kLowShadowBeg + 200;
+ EXPECT_EQ(ptr, __asan_region_is_poisoned(ptr, 100));
+ ptr = kShadowGapBeg + 200;
+ EXPECT_EQ(ptr, __asan_region_is_poisoned(ptr, 100));
+ ptr = kHighShadowBeg + 200;
+ EXPECT_EQ(ptr, __asan_region_is_poisoned(ptr, 100));
}
diff --git a/lib/asan/tests/asan_str_test.cc b/lib/asan/tests/asan_str_test.cc
index 128fb61c25a9..178d00d4da86 100644
--- a/lib/asan/tests/asan_str_test.cc
+++ b/lib/asan/tests/asan_str_test.cc
@@ -12,6 +12,10 @@
//===----------------------------------------------------------------------===//
#include "asan_test_utils.h"
+#if defined(__APPLE__)
+#include <AvailabilityMacros.h> // For MAC_OS_X_VERSION_*
+#endif
+
// Used for string functions tests
static char global_string[] = "global";
static size_t global_string_length = 6;
@@ -61,6 +65,18 @@ TEST(AddressSanitizer, StrLenOOBTest) {
free(heap_string);
}
+TEST(AddressSanitizer, WcsLenTest) {
+ EXPECT_EQ(0U, wcslen(Ident(L"")));
+ size_t hello_len = 13;
+ size_t hello_size = (hello_len + 1) * sizeof(wchar_t);
+ EXPECT_EQ(hello_len, wcslen(Ident(L"Hello, World!")));
+ wchar_t *heap_string = Ident((wchar_t*)malloc(hello_size));
+ memcpy(heap_string, L"Hello, World!", hello_size);
+ EXPECT_EQ(hello_len, Ident(wcslen(heap_string)));
+ EXPECT_DEATH(Ident(wcslen(heap_string + 14)), RightOOBReadMessage(0));
+ free(heap_string);
+}
+
#ifndef __APPLE__
TEST(AddressSanitizer, StrNLenOOBTest) {
size_t size = Ident(123);
diff --git a/lib/asan/tests/asan_test.cc b/lib/asan/tests/asan_test.cc
index 5ae525de9876..6539ae8af4ea 100644
--- a/lib/asan/tests/asan_test.cc
+++ b/lib/asan/tests/asan_test.cc
@@ -111,6 +111,24 @@ TEST(AddressSanitizer, CallocTest) {
free(a);
}
+TEST(AddressSanitizer, CallocReturnsZeroMem) {
+ size_t sizes[] = {16, 1000, 10000, 100000, 2100000};
+ for (size_t s = 0; s < sizeof(sizes)/sizeof(sizes[0]); s++) {
+ size_t size = sizes[s];
+ for (size_t iter = 0; iter < 5; iter++) {
+ char *x = Ident((char*)calloc(1, size));
+ EXPECT_EQ(x[0], 0);
+ EXPECT_EQ(x[size - 1], 0);
+ EXPECT_EQ(x[size / 2], 0);
+ EXPECT_EQ(x[size / 3], 0);
+ EXPECT_EQ(x[size / 4], 0);
+ memset(x, 0x42, size);
+ free(Ident(x));
+ free(Ident(malloc(Ident(1 << 27)))); // Try to drain the quarantine.
+ }
+ }
+}
+
TEST(AddressSanitizer, VallocTest) {
void *a = valloc(100);
EXPECT_EQ(0U, (uintptr_t)a % kPageSize);
@@ -227,16 +245,6 @@ TEST(AddressSanitizer, BitFieldNegativeTest) {
delete Ident(x);
}
-TEST(AddressSanitizer, OutOfMemoryTest) {
- size_t size = SANITIZER_WORDSIZE == 64 ? (size_t)(1ULL << 48) : (0xf0000000);
- EXPECT_EQ(0, realloc(0, size));
- EXPECT_EQ(0, realloc(0, ~Ident(0)));
- EXPECT_EQ(0, malloc(size));
- EXPECT_EQ(0, malloc(~Ident(0)));
- EXPECT_EQ(0, calloc(1, size));
- EXPECT_EQ(0, calloc(1, ~Ident(0)));
-}
-
#if ASAN_NEEDS_SEGV
namespace {
@@ -363,6 +371,7 @@ TEST(AddressSanitizer, ReallocFreedPointerTest) {
TEST(AddressSanitizer, ReallocInvalidPointerTest) {
void *ptr = Ident(malloc(42));
EXPECT_DEATH(ptr = realloc((int*)ptr + 1, 77), "attempting free.*not malloc");
+ free(ptr);
}
TEST(AddressSanitizer, ZeroSizeMallocTest) {
@@ -401,6 +410,7 @@ TEST(AddressSanitizer, MallocUsableSizeTest) {
kMallocUsableSizeErrorMsg);
free(array);
EXPECT_DEATH(malloc_usable_size(array), kMallocUsableSizeErrorMsg);
+ delete int_ptr;
}
#endif
@@ -659,7 +669,8 @@ TEST(AddressSanitizer, ThreadStackReuseTest) {
PTHREAD_JOIN(t, 0);
}
-#if defined(__i386__) || defined(__x86_64__)
+#if defined(__i686__) || defined(__x86_64__)
+#include <emmintrin.h>
TEST(AddressSanitizer, Store128Test) {
char *a = Ident((char*)malloc(Ident(12)));
char *p = a;
@@ -1089,15 +1100,15 @@ TEST(AddressSanitizer, LargeStructCopyTest) {
*Ident(&a) = *Ident(&a);
}
-ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS
-static void NoAddressSafety() {
+ATTRIBUTE_NO_SANITIZE_ADDRESS
+static void NoSanitizeAddress() {
char *foo = new char[10];
Ident(foo)[10] = 0;
delete [] foo;
}
-TEST(AddressSanitizer, AttributeNoAddressSafetyTest) {
- Ident(NoAddressSafety)();
+TEST(AddressSanitizer, AttributeNoSanitizeAddressTest) {
+ Ident(NoSanitizeAddress)();
}
// It doesn't work on Android, as calls to new/delete go through malloc/free.
@@ -1223,10 +1234,10 @@ TEST(AddressSanitizer, pthread_getschedparam) {
struct sched_param param;
EXPECT_DEATH(
pthread_getschedparam(pthread_self(), &policy, Ident(&param) + 2),
- "AddressSanitizer: stack-buffer-overflow");
+ "AddressSanitizer: stack-buffer-.*flow");
EXPECT_DEATH(
pthread_getschedparam(pthread_self(), Ident(&policy) - 1, &param),
- "AddressSanitizer: stack-buffer-overflow");
+ "AddressSanitizer: stack-buffer-.*flow");
int res = pthread_getschedparam(pthread_self(), &policy, &param);
ASSERT_EQ(0, res);
}
diff --git a/lib/asan/tests/asan_test_utils.h b/lib/asan/tests/asan_test_utils.h
index 403773180c2f..b6bf6b82066d 100644
--- a/lib/asan/tests/asan_test_utils.h
+++ b/lib/asan/tests/asan_test_utils.h
@@ -41,10 +41,6 @@
#include <unistd.h>
#endif
-#if defined(__i386__) || defined(__x86_64__)
-#include <emmintrin.h>
-#endif
-
#ifndef __APPLE__
#include <malloc.h>
#endif
diff --git a/lib/dfsan/CMakeLists.txt b/lib/dfsan/CMakeLists.txt
new file mode 100644
index 000000000000..b952799ffb5b
--- /dev/null
+++ b/lib/dfsan/CMakeLists.txt
@@ -0,0 +1,44 @@
+include_directories(..)
+
+# Runtime library sources and build flags.
+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)
+
+# 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}
+ 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}
+ SOURCES ${DFSAN_RTL_SOURCES}
+ $<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
+ CFLAGS ${DFSAN_RTL_CFLAGS} -fPIC -DDFSAN_NOLIBC)
+ 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_custom_target(dfsan_abilist ALL
+ SOURCES ${CLANG_RESOURCE_DIR}/dfsan_abilist.txt)
+add_custom_command(OUTPUT ${CLANG_RESOURCE_DIR}/dfsan_abilist.txt
+ 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})
+
+add_subdirectory(lit_tests)
diff --git a/lib/dfsan/Makefile.mk b/lib/dfsan/Makefile.mk
new file mode 100644
index 000000000000..4aeaac42dea2
--- /dev/null
+++ b/lib/dfsan/Makefile.mk
@@ -0,0 +1,23 @@
+#===- lib/dfsan/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 := dfsan
+SubDirs :=
+
+Sources := $(foreach file,$(wildcard $(Dir)/*.cc),$(notdir $(file)))
+ObjNames := $(Sources:%.cc=%.o)
+
+Implementation := Generic
+
+# FIXME: use automatic dependencies?
+Dependencies := $(wildcard $(Dir)/*.h)
+Dependencies += $(wildcard $(Dir)/../sanitizer_common/*.h)
+
+# Define a convenience variable for all the dfsan functions.
+DfsanFunctions := $(Sources:%.cc=%)
diff --git a/lib/dfsan/dfsan.cc b/lib/dfsan/dfsan.cc
new file mode 100644
index 000000000000..72d05c68604b
--- /dev/null
+++ b/lib/dfsan/dfsan.cc
@@ -0,0 +1,265 @@
+//===-- dfsan.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 DataFlowSanitizer.
+//
+// DataFlowSanitizer runtime. This file defines the public interface to
+// DataFlowSanitizer as well as the definition of certain runtime functions
+// called automatically by the compiler (specifically the instrumentation pass
+// in llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp).
+//
+// The public interface is defined in include/sanitizer/dfsan_interface.h whose
+// functions are prefixed dfsan_ while the compiler interface functions are
+// prefixed __dfsan_.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_atomic.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_flags.h"
+#include "sanitizer_common/sanitizer_libc.h"
+
+#include "dfsan/dfsan.h"
+
+using namespace __dfsan;
+
+typedef atomic_uint16_t atomic_dfsan_label;
+static const dfsan_label kInitializingLabel = -1;
+
+static const uptr kNumLabels = 1 << (sizeof(dfsan_label) * 8);
+
+static atomic_dfsan_label __dfsan_last_label;
+static dfsan_label_info __dfsan_label_info[kNumLabels];
+
+Flags __dfsan::flags_data;
+
+SANITIZER_INTERFACE_ATTRIBUTE THREADLOCAL dfsan_label __dfsan_retval_tls;
+SANITIZER_INTERFACE_ATTRIBUTE THREADLOCAL dfsan_label __dfsan_arg_tls[64];
+
+// On Linux/x86_64, memory is laid out as follows:
+//
+// +--------------------+ 0x800000000000 (top of memory)
+// | application memory |
+// +--------------------+ 0x700000008000 (kAppAddr)
+// | |
+// | unused |
+// | |
+// +--------------------+ 0x200200000000 (kUnusedAddr)
+// | union table |
+// +--------------------+ 0x200000000000 (kUnionTableAddr)
+// | shadow memory |
+// +--------------------+ 0x000000010000 (kShadowAddr)
+// | reserved by kernel |
+// +--------------------+ 0x000000000000
+//
+// To derive a shadow memory address from an application memory address,
+// bits 44-46 are cleared to bring the address into the range
+// [0x000000008000,0x100000000000). Then the address is shifted left by 1 to
+// account for the double byte representation of shadow labels and move the
+// address into the shadow memory range. See the function shadow_for below.
+
+typedef atomic_dfsan_label dfsan_union_table_t[kNumLabels][kNumLabels];
+
+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;
+
+static atomic_dfsan_label *union_table(dfsan_label l1, dfsan_label l2) {
+ return &(*(dfsan_union_table_t *) kUnionTableAddr)[l1][l2];
+}
+
+// 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
+dfsan_label __dfsan_union(dfsan_label l1, dfsan_label l2) {
+ DCHECK_NE(l1, l2);
+
+ if (l1 == 0)
+ return l2;
+ if (l2 == 0)
+ return l1;
+
+ if (l1 > l2)
+ Swap(l1, l2);
+
+ atomic_dfsan_label *table_ent = union_table(l1, l2);
+ // We need to deal with the case where two threads concurrently request
+ // a union of the same pair of labels. If the table entry is uninitialized,
+ // (i.e. 0) use a compare-exchange to set the entry to kInitializingLabel
+ // (i.e. -1) to mark that we are initializing it.
+ dfsan_label label = 0;
+ if (atomic_compare_exchange_strong(table_ent, &label, kInitializingLabel,
+ memory_order_acquire)) {
+ // Check whether l2 subsumes l1. We don't need to check whether l1
+ // subsumes l2 because we are guaranteed here that l1 < l2, and (at least
+ // in the cases we are interested in) a label may only subsume labels
+ // created earlier (i.e. with a lower numerical value).
+ if (__dfsan_label_info[l2].l1 == l1 ||
+ __dfsan_label_info[l2].l2 == l1) {
+ label = l2;
+ } else {
+ label =
+ atomic_fetch_add(&__dfsan_last_label, 1, memory_order_relaxed) + 1;
+ CHECK_NE(label, kInitializingLabel);
+ __dfsan_label_info[label].l1 = l1;
+ __dfsan_label_info[label].l2 = l2;
+ }
+ atomic_store(table_ent, label, memory_order_release);
+ } else if (label == kInitializingLabel) {
+ // Another thread is initializing the entry. Wait until it is finished.
+ do {
+ internal_sched_yield();
+ label = atomic_load(table_ent, memory_order_acquire);
+ } while (label == kInitializingLabel);
+ }
+ return label;
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+dfsan_label __dfsan_union_load(const dfsan_label *ls, uptr n) {
+ dfsan_label label = ls[0];
+ for (uptr i = 1; i != n; ++i) {
+ dfsan_label next_label = ls[i];
+ if (label != next_label)
+ label = __dfsan_union(label, next_label);
+ }
+ return label;
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+void __dfsan_unimplemented(char *fname) {
+ if (flags().warn_unimplemented)
+ Report("WARNING: DataFlowSanitizer: call to uninstrumented function %s\n",
+ fname);
+}
+
+// Use '-mllvm -dfsan-debug-nonzero-labels' and break on this function
+// to try to figure out where labels are being introduced in a nominally
+// label-free program.
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __dfsan_nonzero_label() {
+ if (flags().warn_nonzero_labels)
+ Report("WARNING: DataFlowSanitizer: saw nonzero label\n");
+}
+
+// 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
+dfsan_union(dfsan_label l1, dfsan_label l2) {
+ if (l1 == l2)
+ return l1;
+ return __dfsan_union(l1, l2);
+}
+
+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_label_info[label].l1 = __dfsan_label_info[label].l2 = 0;
+ __dfsan_label_info[label].desc = desc;
+ __dfsan_label_info[label].userdata = userdata;
+ return label;
+}
+
+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)
+ *labelp = label;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void dfsan_set_label(dfsan_label label, void *addr, uptr size) {
+ __dfsan_set_label(label, addr, size);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void dfsan_add_label(dfsan_label label, void *addr, uptr size) {
+ for (dfsan_label *labelp = shadow_for(addr); size != 0; --size, ++labelp)
+ if (*labelp != label)
+ *labelp = __dfsan_union(*labelp, label);
+}
+
+// Unlike the other dfsan interface functions the behavior of this function
+// depends on the label of one of its arguments. Hence it is implemented as a
+// custom function.
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE dfsan_label
+__dfsw_dfsan_get_label(long data, dfsan_label data_label,
+ dfsan_label *ret_label) {
+ *ret_label = 0;
+ return data_label;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE dfsan_label
+dfsan_read_label(const void *addr, uptr size) {
+ if (size == 0)
+ return 0;
+ return __dfsan_union_load(shadow_for(addr), size);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+const struct dfsan_label_info *dfsan_get_label_info(dfsan_label label) {
+ return &__dfsan_label_info[label];
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE int
+dfsan_has_label(dfsan_label label, dfsan_label elem) {
+ if (label == elem)
+ return true;
+ const dfsan_label_info *info = dfsan_get_label_info(label);
+ if (info->l1 != 0) {
+ return dfsan_has_label(info->l1, elem) || dfsan_has_label(info->l2, elem);
+ } else {
+ return false;
+ }
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE dfsan_label
+dfsan_has_label_with_desc(dfsan_label label, const char *desc) {
+ const dfsan_label_info *info = dfsan_get_label_info(label);
+ if (info->l1 != 0) {
+ return dfsan_has_label_with_desc(info->l1, desc) ||
+ dfsan_has_label_with_desc(info->l2, desc);
+ } else {
+ return internal_strcmp(desc, info->desc) == 0;
+ }
+}
+
+static void InitializeFlags(Flags &f, const char *env) {
+ f.warn_unimplemented = true;
+ f.warn_nonzero_labels = false;
+
+ ParseFlag(env, &f.warn_unimplemented, "warn_unimplemented");
+ ParseFlag(env, &f.warn_nonzero_labels, "warn_nonzero_labels");
+}
+
+#ifdef DFSAN_NOLIBC
+extern "C" void dfsan_init() {
+#else
+static void dfsan_init(int argc, char **argv, char **envp) {
+#endif
+ MmapFixedNoReserve(kShadowAddr, kUnusedAddr - kShadowAddr);
+
+ // Protect the region of memory we don't use, to preserve the one-to-one
+ // mapping from application to shadow memory. But if ASLR is disabled, Linux
+ // will load our executable in the middle of our unused region. This mostly
+ // works so long as the program doesn't use too much memory. We support this
+ // case by disabling memory protection when ASLR is disabled.
+ uptr init_addr = (uptr)&dfsan_init;
+ if (!(init_addr >= kUnusedAddr && init_addr < kAppAddr))
+ Mprotect(kUnusedAddr, kAppAddr - kUnusedAddr);
+
+ InitializeFlags(flags(), GetEnv("DFSAN_OPTIONS"));
+
+ InitializeInterceptors();
+}
+
+#ifndef DFSAN_NOLIBC
+__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
new file mode 100644
index 000000000000..693e0c5efe04
--- /dev/null
+++ b/lib/dfsan/dfsan.h
@@ -0,0 +1,67 @@
+//===-- dfsan.h -------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of DataFlowSanitizer.
+//
+// Private DFSan header.
+//===----------------------------------------------------------------------===//
+
+#ifndef DFSAN_H
+#define DFSAN_H
+
+#include "sanitizer_common/sanitizer_internal_defs.h"
+
+// Copy declarations from public sanitizer/dfsan_interface.h header here.
+typedef u16 dfsan_label;
+
+struct dfsan_label_info {
+ dfsan_label l1;
+ dfsan_label l2;
+ const char *desc;
+ void *userdata;
+};
+
+extern "C" {
+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);
+} // extern "C"
+
+template <typename T>
+void dfsan_set_label(dfsan_label label, T &data) { // NOLINT
+ dfsan_set_label(label, (void *)&data, sizeof(T));
+}
+
+namespace __dfsan {
+
+void InitializeInterceptors();
+
+inline dfsan_label *shadow_for(void *ptr) {
+ return (dfsan_label *) ((((uptr) ptr) & ~0x700000000000) << 1);
+}
+
+inline const dfsan_label *shadow_for(const void *ptr) {
+ return shadow_for(const_cast<void *>(ptr));
+}
+
+struct Flags {
+ // Whether to warn on unimplemented functions.
+ bool warn_unimplemented;
+ // Whether to warn on non-zero labels.
+ bool warn_nonzero_labels;
+};
+
+extern Flags flags_data;
+inline Flags &flags() {
+ return flags_data;
+}
+
+} // namespace __dfsan
+
+#endif // DFSAN_H
diff --git a/lib/dfsan/dfsan.syms.extra b/lib/dfsan/dfsan.syms.extra
new file mode 100644
index 000000000000..0d507eef0814
--- /dev/null
+++ b/lib/dfsan/dfsan.syms.extra
@@ -0,0 +1,3 @@
+dfsan_*
+__dfsan_*
+__dfsw_*
diff --git a/lib/dfsan/dfsan_custom.cc b/lib/dfsan/dfsan_custom.cc
new file mode 100644
index 000000000000..6a132db062b3
--- /dev/null
+++ b/lib/dfsan/dfsan_custom.cc
@@ -0,0 +1,341 @@
+//===-- dfsan.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 DataFlowSanitizer.
+//
+// This file defines the custom functions listed in done_abilist.txt.
+//===----------------------------------------------------------------------===//
+#include "sanitizer_common/sanitizer_internal_defs.h"
+#include "sanitizer_common/sanitizer_linux.h"
+
+#include "dfsan/dfsan.h"
+
+#include <ctype.h>
+#include <dlfcn.h>
+#include <link.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.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) {
+ int ret = stat(path, buf);
+ if (ret == 0)
+ dfsan_set_label(0, buf, sizeof(struct stat));
+ *ret_label = 0;
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_fstat(int fd, struct stat *buf,
+ dfsan_label fd_label,
+ dfsan_label buf_label,
+ dfsan_label *ret_label) {
+ int ret = fstat(fd, buf);
+ if (ret == 0)
+ dfsan_set_label(0, buf, sizeof(struct stat));
+ *ret_label = 0;
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strchr(const char *s, int c,
+ dfsan_label s_label,
+ dfsan_label c_label,
+ 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);
+ return s[i] == 0 ? 0 : const_cast<char *>(s+i);
+ }
+ }
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_memcmp(const void *s1, const void *s2,
+ size_t n, dfsan_label s1_label,
+ dfsan_label s2_label,
+ dfsan_label n_label,
+ dfsan_label *ret_label) {
+ 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));
+ return cs1[i] - cs2[i];
+ }
+ }
+ *ret_label = dfsan_union(dfsan_read_label(cs1, n),
+ dfsan_read_label(cs2, n));
+ return 0;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_strcmp(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 (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));
+ return s1[i] - s2[i];
+ }
+ }
+ return 0;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE int
+__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));
+ return s1[i] - s2[i];
+ }
+ }
+ return 0;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_strncmp(const char *s1, const char *s2,
+ size_t n, dfsan_label s1_label,
+ dfsan_label s2_label,
+ dfsan_label n_label,
+ dfsan_label *ret_label) {
+ if (n == 0) {
+ *ret_label = 0;
+ return 0;
+ }
+
+ 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));
+ return s1[i] - s2[i];
+ }
+ }
+ return 0;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE int
+__dfsw_strncasecmp(const char *s1, const char *s2, size_t n,
+ dfsan_label s1_label, dfsan_label s2_label,
+ dfsan_label n_label, dfsan_label *ret_label) {
+ if (n == 0) {
+ *ret_label = 0;
+ return 0;
+ }
+
+ 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));
+ return s1[i] - s2[i];
+ }
+ }
+ return 0;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE void *__dfsw_calloc(size_t nmemb, size_t size,
+ dfsan_label nmemb_label,
+ dfsan_label size_label,
+ dfsan_label *ret_label) {
+ void *p = calloc(nmemb, size);
+ dfsan_set_label(0, p, nmemb * size);
+ *ret_label = 0;
+ return p;
+}
+
+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);
+ 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));
+ return internal_memcpy(dest, src, n);
+}
+
+static void dfsan_memset(void *s, int c, dfsan_label c_label, size_t n) {
+ internal_memset(s, c, n);
+ dfsan_set_label(c_label, s, n);
+}
+
+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;
+ return dfsan_memcpy(dest, src, n);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+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;
+ return s;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE char *
+__dfsw_strdup(const char *s, dfsan_label s_label, dfsan_label *ret_label) {
+ size_t len = strlen(s);
+ void *p = malloc(len+1);
+ dfsan_memcpy(p, s, len+1);
+ *ret_label = 0;
+ return static_cast<char *>(p);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE char *
+__dfsw_strncpy(char *s1, const char *s2, size_t n, dfsan_label s1_label,
+ dfsan_label s2_label, dfsan_label n_label,
+ dfsan_label *ret_label) {
+ size_t len = strlen(s2);
+ if (len < n) {
+ dfsan_memcpy(s1, s2, len+1);
+ dfsan_memset(s1+len+1, 0, 0, n-len-1);
+ } else {
+ dfsan_memcpy(s1, s2, n);
+ }
+
+ *ret_label = 0;
+ return s1;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE ssize_t
+__dfsw_pread(int fd, void *buf, size_t count, off_t offset,
+ dfsan_label fd_label, dfsan_label buf_label,
+ dfsan_label count_label, dfsan_label offset_label,
+ dfsan_label *ret_label) {
+ ssize_t ret = pread(fd, buf, count, offset);
+ if (ret > 0)
+ dfsan_set_label(0, buf, ret);
+ *ret_label = 0;
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE ssize_t
+__dfsw_read(int fd, void *buf, size_t count,
+ dfsan_label fd_label, dfsan_label buf_label,
+ dfsan_label count_label,
+ dfsan_label *ret_label) {
+ ssize_t ret = read(fd, buf, count);
+ if (ret > 0)
+ dfsan_set_label(0, buf, ret);
+ *ret_label = 0;
+ return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_clock_gettime(clockid_t clk_id,
+ struct timespec *tp,
+ dfsan_label clk_id_label,
+ dfsan_label tp_label,
+ dfsan_label *ret_label) {
+ int ret = clock_gettime(clk_id, tp);
+ if (ret == 0)
+ dfsan_set_label(0, tp, sizeof(struct timespec));
+ *ret_label = 0;
+ return ret;
+}
+
+static void unpoison(const void *ptr, uptr size) {
+ dfsan_set_label(0, const_cast<void *>(ptr), size);
+}
+
+// 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.
+SANITIZER_INTERFACE_ATTRIBUTE void *
+__dfsw_dlopen(const char *filename, int flag, dfsan_label filename_label,
+ dfsan_label flag_label, dfsan_label *ret_label) {
+ link_map *map = (link_map *)dlopen(filename, flag);
+ if (map)
+ ForEachMappedRegion(map, unpoison);
+ *ret_label = 0;
+ return (void *)map;
+}
+
+struct pthread_create_info {
+ void *(*start_routine_trampoline)(void *, void *, dfsan_label, dfsan_label *);
+ void *start_routine;
+ void *arg;
+};
+
+static void *pthread_create_cb(void *p) {
+ pthread_create_info pci(*(pthread_create_info *)p);
+ free(p);
+ dfsan_label ret_label;
+ return pci.start_routine_trampoline(pci.start_routine, pci.arg, 0,
+ &ret_label);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_pthread_create(
+ pthread_t *thread, const pthread_attr_t *attr,
+ void *(*start_routine_trampoline)(void *, void *, dfsan_label,
+ dfsan_label *),
+ void *start_routine, void *arg, dfsan_label thread_label,
+ dfsan_label attr_label, dfsan_label start_routine_label,
+ dfsan_label arg_label, dfsan_label *ret_label) {
+ pthread_create_info *pci =
+ (pthread_create_info *)malloc(sizeof(pthread_create_info));
+ pci->start_routine_trampoline = start_routine_trampoline;
+ pci->start_routine = start_routine;
+ pci->arg = arg;
+ int rv = pthread_create(thread, attr, pthread_create_cb, (void *)pci);
+ if (rv != 0)
+ free(pci);
+ *ret_label = 0;
+ return rv;
+}
+
+struct dl_iterate_phdr_info {
+ int (*callback_trampoline)(void *callback, struct dl_phdr_info *info,
+ size_t size, void *data, dfsan_label info_label,
+ dfsan_label size_label, dfsan_label data_label,
+ dfsan_label *ret_label);
+ void *callback;
+ void *data;
+};
+
+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_label ret_label;
+ return dipi->callback_trampoline(dipi->callback, info, size, dipi->data, 0, 0,
+ 0, &ret_label);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_dl_iterate_phdr(
+ int (*callback_trampoline)(void *callback, struct dl_phdr_info *info,
+ size_t size, void *data, dfsan_label info_label,
+ dfsan_label size_label, dfsan_label data_label,
+ dfsan_label *ret_label),
+ void *callback, void *data, dfsan_label callback_label,
+ dfsan_label data_label, dfsan_label *ret_label) {
+ dl_iterate_phdr_info dipi = { callback_trampoline, callback, data };
+ *ret_label = 0;
+ return dl_iterate_phdr(dl_iterate_phdr_cb, &dipi);
+}
+
+}
diff --git a/lib/dfsan/dfsan_interceptors.cc b/lib/dfsan/dfsan_interceptors.cc
new file mode 100644
index 000000000000..8b7d64e25a39
--- /dev/null
+++ b/lib/dfsan/dfsan_interceptors.cc
@@ -0,0 +1,44 @@
+//===-- dfsan_interceptors.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 DataFlowSanitizer.
+//
+// Interceptors for standard library functions.
+//===----------------------------------------------------------------------===//
+
+#include "dfsan/dfsan.h"
+#include "interception/interception.h"
+#include "sanitizer_common/sanitizer_common.h"
+
+INTERCEPTOR(void *, mmap, void *addr, SIZE_T length, int prot, int flags,
+ int fd, OFF_T offset) {
+ void *res = REAL(mmap)(addr, length, prot, flags, fd, offset);
+ if (res != (void*)-1)
+ dfsan_set_label(0, res, RoundUpTo(length, GetPageSize()));
+ return res;
+}
+
+INTERCEPTOR(void *, mmap64, void *addr, SIZE_T length, int prot, int flags,
+ int fd, OFF64_T offset) {
+ void *res = REAL(mmap64)(addr, length, prot, flags, fd, offset);
+ if (res != (void*)-1)
+ dfsan_set_label(0, res, RoundUpTo(length, GetPageSize()));
+ return res;
+}
+
+namespace __dfsan {
+void InitializeInterceptors() {
+ static int inited = 0;
+ CHECK_EQ(inited, 0);
+
+ INTERCEPT_FUNCTION(mmap);
+ INTERCEPT_FUNCTION(mmap64);
+ inited = 1;
+}
+} // namespace __dfsan
diff --git a/lib/dfsan/done_abilist.txt b/lib/dfsan/done_abilist.txt
new file mode 100644
index 000000000000..27df3e9b707c
--- /dev/null
+++ b/lib/dfsan/done_abilist.txt
@@ -0,0 +1,127 @@
+fun:main=uninstrumented
+fun:main=discard
+
+# 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_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
+
+# glibc functions.
+fun:malloc=discard
+fun:realloc=discard
+fun:free=discard
+fun:isalpha=functional
+fun:isdigit=functional
+fun:isprint=functional
+fun:isxdigit=functional
+fun:isalnum=functional
+fun:ispunct=functional
+fun:isspace=functional
+fun:tolower=functional
+fun:toupper=functional
+fun:exp=functional
+fun:exp2=functional
+fun:log=functional
+fun:sqrt=functional
+fun:__cxa_atexit=discard
+fun:open=discard
+fun:pthread_key_create=discard
+fun:getenv=discard
+fun:__ctype_b_loc=discard
+fun:__errno_location=discard
+fun:mmap=discard
+fun:munmap=discard
+fun:write=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:fprintf=discard
+fun:fputs=discard
+fun:fputc=discard
+fun:fopen=discard
+fun:fseek=discard
+fun:lseek=discard
+fun:ftell=discard
+fun:fclose=discard
+fun:dladdr=discard
+fun:getpagesize=discard
+fun:sched_getcpu=discard
+fun:sched_getaffinity=discard
+fun:sched_setaffinity=discard
+fun:syscall=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:sleep=discard
+
+fun:stat=custom
+fun:fstat=custom
+fun:memcmp=custom
+fun:memcpy=custom
+fun:memset=custom
+fun:strcmp=custom
+fun:strdup=custom
+fun:strncmp=custom
+fun:strncpy=custom
+fun:strcasecmp=custom
+fun:strncasecmp=custom
+fun:strchr=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:dl_iterate_phdr=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
diff --git a/lib/dfsan/libc_ubuntu1204_abilist.txt b/lib/dfsan/libc_ubuntu1204_abilist.txt
new file mode 100644
index 000000000000..5fc8194c8f16
--- /dev/null
+++ b/lib/dfsan/libc_ubuntu1204_abilist.txt
@@ -0,0 +1,3685 @@
+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/lit_tests/CMakeLists.txt b/lib/dfsan/lit_tests/CMakeLists.txt
new file mode 100644
index 000000000000..d7c5c82ac3c0
--- /dev/null
+++ b/lib/dfsan/lit_tests/CMakeLists.txt
@@ -0,0 +1,21 @@
+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
new file mode 100644
index 000000000000..94b1fa298259
--- /dev/null
+++ b/lib/dfsan/lit_tests/Inputs/flags_abilist.txt
@@ -0,0 +1,10 @@
+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
new file mode 100644
index 000000000000..b566c9271d0b
--- /dev/null
+++ b/lib/dfsan/lit_tests/basic.c
@@ -0,0 +1,21 @@
+// 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
new file mode 100644
index 000000000000..c9fa9356154d
--- /dev/null
+++ b/lib/dfsan/lit_tests/custom.c
@@ -0,0 +1,154 @@
+// 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
new file mode 100644
index 000000000000..5cf970dce90d
--- /dev/null
+++ b/lib/dfsan/lit_tests/flags.c
@@ -0,0 +1,24 @@
+// 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
new file mode 100644
index 000000000000..15b77bd67902
--- /dev/null
+++ b/lib/dfsan/lit_tests/fncall.c
@@ -0,0 +1,26 @@
+// 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
new file mode 100644
index 000000000000..19bc97690a86
--- /dev/null
+++ b/lib/dfsan/lit_tests/lit.cfg
@@ -0,0 +1,69 @@
+# -*- 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
new file mode 100644
index 000000000000..0cf6d6b5580f
--- /dev/null
+++ b/lib/dfsan/lit_tests/lit.site.cfg.in
@@ -0,0 +1,5 @@
+# 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
new file mode 100644
index 000000000000..86d182b8a7fc
--- /dev/null
+++ b/lib/dfsan/lit_tests/propagate.c
@@ -0,0 +1,47 @@
+// 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
new file mode 100755
index 000000000000..8f6b8d513631
--- /dev/null
+++ b/lib/dfsan/scripts/build-libc-list.py
@@ -0,0 +1,84 @@
+#!/usr/bin/env python
+#===- lib/dfsan/scripts/build-libc-list.py ---------------------------------===#
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+# The purpose of this script is to identify every function symbol in a set of
+# libraries (in this case, libc and libgcc) so that they can be marked as
+# uninstrumented, thus allowing the instrumentation pass to treat calls to those
+# functions correctly.
+
+import os
+import subprocess
+import sys
+from optparse import OptionParser
+
+def defined_function_list(object):
+ functions = []
+ readelf_proc = subprocess.Popen(['readelf', '-s', '-W', object],
+ stdout=subprocess.PIPE)
+ readelf = readelf_proc.communicate()[0].split('\n')
+ if readelf_proc.returncode != 0:
+ raise subprocess.CalledProcessError(readelf_proc.returncode, 'readelf')
+ for line in readelf:
+ if (line[31:35] == 'FUNC' or line[31:36] == 'IFUNC') and \
+ line[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',
+ default='/lib/x86_64-linux-gnu')
+p.add_option('--usrlib', metavar='PATH',
+ help='path to usr/lib directory to use',
+ default='/usr/lib/x86_64-linux-gnu')
+p.add_option('--gcclib', metavar='PATH',
+ help='path to gcc lib directory to use',
+ 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)')
+(options, args) = p.parse_args()
+
+libs = [os.path.join(options.lib, name) for name in
+ ['ld-linux-x86-64.so.2',
+ 'libanl.so.1',
+ 'libBrokenLocale.so.1',
+ 'libcidn.so.1',
+ 'libcrypt.so.1',
+ 'libc.so.6',
+ 'libdl.so.2',
+ 'libm.so.6',
+ 'libnsl.so.1',
+ 'libpthread.so.0',
+ 'libresolv.so.2',
+ 'librt.so.1',
+ 'libthread_db.so.1',
+ 'libutil.so.1']]
+libs += [os.path.join(options.usrlib, name) for name in
+ ['libc_nonshared.a',
+ 'libpthread_nonshared.a']]
+gcclibs = ['libgcc.a',
+ 'libgcc_s.so']
+if options.with_libstdcxx:
+ gcclibs += ['libstdc++.so']
+libs += [os.path.join(options.gcclib, name) for name in gcclibs]
+
+functions = []
+for l in libs:
+ if os.path.exists(l):
+ functions += defined_function_list(l)
+ else:
+ print >> sys.stderr, 'warning: library %s not found' % l
+
+functions = list(set(functions))
+functions.sort()
+
+for f in functions:
+ print 'fun:%s=uninstrumented' % f
diff --git a/lib/eprintf.c b/lib/eprintf.c
index b07d624b50f9..3626dbf8b0c4 100644
--- a/lib/eprintf.c
+++ b/lib/eprintf.c
@@ -22,7 +22,9 @@
* 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)
{
diff --git a/lib/int_endianness.h b/lib/int_endianness.h
index edb58c810e21..a64f926478ca 100644
--- a/lib/int_endianness.h
+++ b/lib/int_endianness.h
@@ -19,13 +19,15 @@
#if defined(__SVR4) && defined(__sun)
#include <sys/byteorder.h>
-#if _BYTE_ORDER == _BIG_ENDIAN
+#if defined(_BIG_ENDIAN)
#define _YUGA_LITTLE_ENDIAN 0
#define _YUGA_BIG_ENDIAN 1
-#elif _BYTE_ORDER == _LITTLE_ENDIAN
+#elif defined(_LITTLE_ENDIAN)
#define _YUGA_LITTLE_ENDIAN 1
#define _YUGA_BIG_ENDIAN 0
-#endif /* _BYTE_ORDER */
+#else /* !_LITTLE_ENDIAN */
+#error "unknown endianness"
+#endif /* !_LITTLE_ENDIAN */
#endif /* Solaris and AuroraUX. */
diff --git a/lib/int_util.c b/lib/int_util.c
index 871d191658cb..323e46179e6c 100644
--- a/lib/int_util.c
+++ b/lib/int_util.c
@@ -24,31 +24,36 @@
#ifdef KERNEL_USE
extern void panic(const char *, ...) __attribute__((noreturn));
+#ifndef _WIN32
__attribute__((visibility("hidden")))
+#endif
void compilerrt_abort_impl(const char *file, int line, const char *function) {
panic("%s:%d: abort in %s", file, line, function);
}
-#elif __APPLE__ && !__STATIC__
+#elif __APPLE__
/* from libSystem.dylib */
extern void __assert_rtn(const char *func, const char *file,
int line, const char * message) __attribute__((noreturn));
+#ifndef _WIN32
__attribute__((weak))
__attribute__((visibility("hidden")))
+#endif
void compilerrt_abort_impl(const char *file, int line, const char *function) {
__assert_rtn(function, file, line, "libcompiler_rt abort");
}
-
#else
/* Get the system definition of abort() */
#include <stdlib.h>
+#ifndef _WIN32
__attribute__((weak))
__attribute__((visibility("hidden")))
+#endif
void compilerrt_abort_impl(const char *file, int line, const char *function) {
abort();
}
diff --git a/lib/interception/CMakeLists.txt b/lib/interception/CMakeLists.txt
index cd9e6e75504f..1dfdaffb6dc1 100644
--- a/lib/interception/CMakeLists.txt
+++ b/lib/interception/CMakeLists.txt
@@ -13,10 +13,12 @@ set(INTERCEPTION_CFLAGS ${SANITIZER_COMMON_CFLAGS})
if(APPLE)
# Build universal binary on APPLE.
- add_compiler_rt_osx_object_library(RTInterception
- ARCH ${SANITIZER_COMMON_SUPPORTED_ARCH}
- SOURCES ${INTERCEPTION_SOURCES}
- CFLAGS ${INTERCEPTION_CFLAGS})
+ foreach(os ${SANITIZER_COMMON_SUPPORTED_DARWIN_OS})
+ add_compiler_rt_darwin_object_library(RTInterception ${os}
+ ARCH ${SANITIZER_COMMON_SUPPORTED_ARCH}
+ SOURCES ${INTERCEPTION_SOURCES}
+ CFLAGS ${INTERCEPTION_CFLAGS})
+ endforeach()
elseif(ANDROID)
add_library(RTInterception.arm.android OBJECT ${INTERCEPTION_SOURCES})
set_target_compile_flags(RTInterception.arm.android
diff --git a/lib/interception/interception.h b/lib/interception/interception.h
index d50af35415d6..baddd6c132c9 100644
--- a/lib/interception/interception.h
+++ b/lib/interception/interception.h
@@ -130,7 +130,10 @@ const interpose_substitution substitution_##func_name[] \
# define WRAPPER_NAME(x) "wrap_"#x
# define INTERCEPTOR_ATTRIBUTE
# endif
-# define DECLARE_WRAPPER(ret_type, func, ...)
+# 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__);
#else
# define WRAP(x) __interceptor_ ## x
# define WRAPPER_NAME(x) "__interceptor_" #x
@@ -211,7 +214,7 @@ const interpose_substitution substitution_##func_name[] \
namespace __interception { \
FUNC_TYPE(func) PTR_TO_REAL(func); \
} \
- DECLARE_WRAPPER(ret_type, func, __VA_ARGS__) \
+ DECLARE_WRAPPER_WINAPI(ret_type, func, __VA_ARGS__) \
extern "C" \
INTERCEPTOR_ATTRIBUTE \
ret_type __stdcall WRAP(func)(__VA_ARGS__)
@@ -235,12 +238,18 @@ typedef unsigned long uptr; // NOLINT
#if defined(__linux__)
# include "interception_linux.h"
# define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_LINUX(func)
+# define INTERCEPT_FUNCTION_VER(func, symver) \
+ INTERCEPT_FUNCTION_VER_LINUX(func, symver)
#elif defined(__APPLE__)
# include "interception_mac.h"
# define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_MAC(func)
+# define INTERCEPT_FUNCTION_VER(func, symver) \
+ INTERCEPT_FUNCTION_VER_MAC(func, symver)
#else // defined(_WIN32)
# include "interception_win.h"
# define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_WIN(func)
+# define INTERCEPT_FUNCTION_VER(func, symver) \
+ INTERCEPT_FUNCTION_VER_WIN(func, symver)
#endif
#undef INCLUDED_FROM_INTERCEPTION_LIB
diff --git a/lib/interception/interception_linux.cc b/lib/interception/interception_linux.cc
index 009098fbd657..53f42881016c 100644
--- a/lib/interception/interception_linux.cc
+++ b/lib/interception/interception_linux.cc
@@ -15,7 +15,6 @@
#ifdef __linux__
#include "interception.h"
-#include <stddef.h> // for NULL
#include <dlfcn.h> // for dlsym
namespace __interception {
@@ -24,6 +23,13 @@ bool GetRealFunctionAddress(const char *func_name, uptr *func_addr,
*func_addr = (uptr)dlsym(RTLD_NEXT, func_name);
return real == wrapper;
}
+
+#if !defined(__ANDROID__) // android does not have dlvsym
+void *GetFuncAddrVer(const char *func_name, const char *ver) {
+ return dlvsym(RTLD_NEXT, func_name, ver);
+}
+#endif // !defined(__ANDROID__)
+
} // namespace __interception
diff --git a/lib/interception/interception_linux.h b/lib/interception/interception_linux.h
index dba60bf7315e..cea957320d05 100644
--- a/lib/interception/interception_linux.h
+++ b/lib/interception/interception_linux.h
@@ -25,6 +25,7 @@ namespace __interception {
// returns true if a function with the given name was found.
bool GetRealFunctionAddress(const char *func_name, uptr *func_addr,
uptr real, uptr wrapper);
+void *GetFuncAddrVer(const char *func_name, const char *ver);
} // namespace __interception
#define INTERCEPT_FUNCTION_LINUX(func) \
@@ -33,5 +34,14 @@ bool GetRealFunctionAddress(const char *func_name, uptr *func_addr,
(::__interception::uptr)&(func), \
(::__interception::uptr)&WRAP(func))
+#if !defined(__ANDROID__) // android does not have dlvsym
+# define INTERCEPT_FUNCTION_VER_LINUX(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)
+#endif // !defined(__ANDROID__)
+
#endif // INTERCEPTION_LINUX_H
#endif // __linux__
diff --git a/lib/interception/interception_mac.h b/lib/interception/interception_mac.h
index 5059489831ec..e5a35c6971cd 100644
--- a/lib/interception/interception_mac.h
+++ b/lib/interception/interception_mac.h
@@ -22,6 +22,7 @@
#define INTERCEPTION_MAC_H
#define INTERCEPT_FUNCTION_MAC(func)
+#define INTERCEPT_FUNCTION_VER_MAC(func, symver)
#endif // INTERCEPTION_MAC_H
#endif // __APPLE__
diff --git a/lib/interception/interception_win.h b/lib/interception/interception_win.h
index c64af1baffe7..f2727c9241d3 100644
--- a/lib/interception/interception_win.h
+++ b/lib/interception/interception_win.h
@@ -41,5 +41,8 @@ bool OverrideFunction(uptr old_func, uptr new_func, uptr *orig_old_func);
(::__interception::uptr*)&REAL(func))
#endif
+#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
index b410259a9e71..6c2b4cca4546 100644
--- a/lib/lit.common.cfg
+++ b/lib/lit.common.cfg
@@ -6,17 +6,17 @@
import os
import platform
+import lit.formats
+
# Setup test format
execute_external = (platform.system() != 'Windows'
- or lit.getBashPath() not in [None, ""])
+ 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.fatal("Can't find Clang on path %r" % clang_path)
-if not lit.quiet:
- lit.note("using clang: %r" % 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',
@@ -38,14 +38,12 @@ for name in possibly_dangerous_env_vars:
# 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.fatal("Invalid llvm_tools_dir config attribute: %r" % 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 %clang and %clangxx substitutions to use in test RUN lines.
-config.substitutions.append( ("%clang ", (" " + config.clang + " ")) )
-config.substitutions.append( ("%clangxx ", (" " + config.clang +
- " -ccc-cxx ")) )
+# 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.
@@ -58,3 +56,7 @@ 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/asan/lit_tests/lit.site.cfg.in b/lib/lit.common.configured.in
index 08546cdabe02..558655cbbee8 100644
--- a/lib/asan/lit_tests/lit.site.cfg.in
+++ b/lib/lit.common.configured.in
@@ -1,22 +1,27 @@
## 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.params
+ config.llvm_tools_dir = config.llvm_tools_dir % lit_config.params
except KeyError,e:
key, = e.args
- lit.fatal("unable to find %r parameter, use '--param=%s=VALUE'" % (key, key))
+ lit_config.fatal("unable to find %r parameter, use '--param=%s=VALUE'" % (key, key))
-# Let the main config do the real work.
-lit.load_config(config, "@ASAN_SOURCE_DIR@/lit_tests/lit.cfg")
+# 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
index ca00abb65e9f..2bd8f376f00e 100644
--- a/lib/lit.common.unit.cfg
+++ b/lib/lit.common.unit.cfg
@@ -6,6 +6,8 @@
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")
@@ -13,6 +15,13 @@ 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:
diff --git a/lib/lit.common.unit.configured.in b/lib/lit.common.unit.configured.in
new file mode 100644
index 000000000000..430816b24280
--- /dev/null
+++ b/lib/lit.common.unit.configured.in
@@ -0,0 +1,23 @@
+## 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 378f08199218..3018a06622ee 100644
--- a/lib/lsan/CMakeLists.txt
+++ b/lib/lsan/CMakeLists.txt
@@ -1,24 +1,26 @@
include_directories(..)
set(LSAN_CFLAGS
- ${SANITIZER_COMMON_CFLAGS})
+ ${SANITIZER_COMMON_CFLAGS}
+ -fno-rtti)
set(LSAN_COMMON_SOURCES
lsan_common.cc
lsan_common_linux.cc)
set(LSAN_SOURCES
- lsan_interceptors.cc
+ lsan.cc
lsan_allocator.cc
- lsan_thread.cc
- lsan.cc)
+ lsan_interceptors.cc
+ lsan_preinit.cc
+ lsan_thread.cc)
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 powerpc)
+ x86_64 i386 powerpc64)
# Architectures supported by the standalone LSan.
filter_available_targets(LSAN_SUPPORTED_ARCH
@@ -26,7 +28,14 @@ filter_available_targets(LSAN_SUPPORTED_ARCH
set(LSAN_RUNTIME_LIBRARIES)
-if (NOT APPLE AND NOT ANDROID)
+if(APPLE)
+ foreach(os ${SANITIZER_COMMON_SUPPORTED_DARWIN_OS})
+ add_compiler_rt_darwin_object_library(RTLSanCommon ${os}
+ ARCH ${LSAN_COMMON_SUPPORTED_ARCH}
+ SOURCES ${LSAN_COMMON_SOURCES}
+ CFLAGS ${LSAN_CFLAGS})
+ endforeach()
+elseif(NOT ANDROID)
foreach(arch ${LSAN_COMMON_SUPPORTED_ARCH})
add_compiler_rt_object_library(RTLSanCommon ${arch}
SOURCES ${LSAN_COMMON_SOURCES}
diff --git a/lib/lsan/Makefile.mk b/lib/lsan/Makefile.mk
index aae5c32fd32f..2a6b41c98e2c 100644
--- a/lib/lsan/Makefile.mk
+++ b/lib/lsan/Makefile.mk
@@ -7,17 +7,22 @@
#
#===------------------------------------------------------------------------===#
-ModuleName := lsan_common
+ModuleName := lsan
SubDirs :=
-Sources := $(foreach file,$(wildcard $(Dir)/lsan_common*.cc),$(notdir $(file)))
+Sources := $(foreach file,$(wildcard $(Dir)/*.cc),$(notdir $(file)))
ObjNames := $(Sources:%.cc=%.o)
Implementation := Generic
# FIXME: use automatic dependencies?
Dependencies := $(wildcard $(Dir)/*.h)
+Dependencies += $(wildcard $(Dir)/../interception/*.h)
Dependencies += $(wildcard $(Dir)/../sanitizer_common/*.h)
-# Define a convenience variable for all the asan functions.
-LsanCommonFunctions := $(Sources:%.cc=%)
+# Define a convenience variable for all the lsan functions.
+LsanFunctions := $(Sources:%.cc=%)
+
+# lsan functions used in another sanitizers.
+LsanCommonSources := $(foreach file,$(wildcard $(Dir)/lsan_common*.cc),$(notdir $(file)))
+LsanCommonFunctions := $(LsanCommonSources:%.cc=%)
diff --git a/lib/lsan/lit_tests/AsanConfig/lit.cfg b/lib/lsan/lit_tests/AsanConfig/lit.cfg
new file mode 100644
index 000000000000..ae9198173ffc
--- /dev/null
+++ b/lib/lsan/lit_tests/AsanConfig/lit.cfg
@@ -0,0 +1,32 @@
+# -*- 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
new file mode 100644
index 000000000000..9cf6572c54b7
--- /dev/null
+++ b/lib/lsan/lit_tests/AsanConfig/lit.site.cfg.in
@@ -0,0 +1,8 @@
+# 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
index e1be508202b8..526d71bf3418 100644
--- a/lib/lsan/lit_tests/CMakeLists.txt
+++ b/lib/lsan/lit_tests/CMakeLists.txt
@@ -1,9 +1,16 @@
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}/lit.site.cfg.in
- ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg
+ ${CMAKE_CURRENT_SOURCE_DIR}/AsanConfig/lit.site.cfg.in
+ ${CMAKE_CURRENT_BINARY_DIR}/AsanConfig/lit.site.cfg
)
configure_lit_site_cfg(
@@ -11,18 +18,20 @@ configure_lit_site_cfg(
${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg
)
-if(COMPILER_RT_CAN_EXECUTE_TESTS)
+if(COMPILER_RT_CAN_EXECUTE_TESTS AND NOT APPLE AND NOT ANDROID)
set(LSAN_TEST_DEPS
${SANITIZER_COMMON_LIT_TEST_DEPS}
${LSAN_RUNTIME_LIBRARIES})
- set(LSAN_TEST_PARAMS
- lsan_site_config=${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg)
+ foreach(arch ${LSAN_SUPPORTED_ARCH})
+ list(APPEND LSAN_TEST_DEPS clang_rt.asan-${arch})
+ endforeach()
if(LLVM_INCLUDE_TESTS)
- list(APPEND LSAN_TEST_DEPS LsanTests)
+ list(APPEND LSAN_TEST_DEPS LsanUnitTests)
endif()
add_lit_testsuite(check-lsan "Running the LeakSanitizer tests"
- ${CMAKE_CURRENT_BINARY_DIR}
- PARAMS ${LSAN_TEST_PARAMS}
+ ${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
new file mode 100644
index 000000000000..84faf9167a78
--- /dev/null
+++ b/lib/lsan/lit_tests/LsanConfig/lit.cfg
@@ -0,0 +1,30 @@
+# -*- 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
new file mode 100644
index 000000000000..2a6d724c0436
--- /dev/null
+++ b/lib/lsan/lit_tests/LsanConfig/lit.site.cfg.in
@@ -0,0 +1,8 @@
+# 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
new file mode 100644
index 000000000000..475a66ec12a4
--- /dev/null
+++ b/lib/lsan/lit_tests/TestCases/SharedLibs/huge_tls_lib_so.cc
@@ -0,0 +1,12 @@
+// 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/SharedLibs/lit.local.cfg b/lib/lsan/lit_tests/TestCases/SharedLibs/lit.local.cfg
index b3677c17a0f2..b3677c17a0f2 100644
--- a/lib/lsan/lit_tests/SharedLibs/lit.local.cfg
+++ b/lib/lsan/lit_tests/TestCases/SharedLibs/lit.local.cfg
diff --git a/lib/lsan/lit_tests/TestCases/cleanup_in_tsd_destructor.cc b/lib/lsan/lit_tests/TestCases/cleanup_in_tsd_destructor.cc
new file mode 100644
index 000000000000..ab368245317c
--- /dev/null
+++ b/lib/lsan/lit_tests/TestCases/cleanup_in_tsd_destructor.cc
@@ -0,0 +1,45 @@
+// 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
new file mode 100644
index 000000000000..db0cd8fabe4d
--- /dev/null
+++ b/lib/lsan/lit_tests/TestCases/disabler.cc
@@ -0,0 +1,23 @@
+// 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
new file mode 100644
index 000000000000..94e4fc390b3b
--- /dev/null
+++ b/lib/lsan/lit_tests/TestCases/disabler_in_tsd_destructor.cc
@@ -0,0 +1,38 @@
+// 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
new file mode 100644
index 000000000000..be0ed0a6d48f
--- /dev/null
+++ b/lib/lsan/lit_tests/TestCases/do_leak_check_override.cc
@@ -0,0 +1,36 @@
+// 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
new file mode 100644
index 000000000000..69258d9a0c72
--- /dev/null
+++ b/lib/lsan/lit_tests/TestCases/fork.cc
@@ -0,0 +1,24 @@
+// 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
new file mode 100644
index 000000000000..24a586109e28
--- /dev/null
+++ b/lib/lsan/lit_tests/TestCases/fork_threaded.cc
@@ -0,0 +1,43 @@
+// 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
new file mode 100644
index 000000000000..1cecb2a550a1
--- /dev/null
+++ b/lib/lsan/lit_tests/TestCases/high_allocator_contention.cc
@@ -0,0 +1,48 @@
+// 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
new file mode 100644
index 000000000000..cbc743b75497
--- /dev/null
+++ b/lib/lsan/lit_tests/TestCases/ignore_object.cc
@@ -0,0 +1,30 @@
+// 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
new file mode 100644
index 000000000000..2a6c72551772
--- /dev/null
+++ b/lib/lsan/lit_tests/TestCases/ignore_object_errors.cc
@@ -0,0 +1,22 @@
+// 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
new file mode 100644
index 000000000000..57d056597ee2
--- /dev/null
+++ b/lib/lsan/lit_tests/TestCases/large_allocation_leak.cc
@@ -0,0 +1,18 @@
+// 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
new file mode 100644
index 000000000000..38c1063b6ebb
--- /dev/null
+++ b/lib/lsan/lit_tests/TestCases/leak_check_at_exit.cc
@@ -0,0 +1,19 @@
+// 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
new file mode 100644
index 000000000000..93628a1d15ee
--- /dev/null
+++ b/lib/lsan/lit_tests/TestCases/link_turned_off.cc
@@ -0,0 +1,24 @@
+// 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
new file mode 100644
index 000000000000..0d2818d2fa1d
--- /dev/null
+++ b/lib/lsan/lit_tests/TestCases/pointer_to_self.cc
@@ -0,0 +1,18 @@
+// 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
new file mode 100644
index 000000000000..085412b47d55
--- /dev/null
+++ b/lib/lsan/lit_tests/TestCases/sanity_check_pure_c.c
@@ -0,0 +1,10 @@
+// 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
new file mode 100644
index 000000000000..fabfb4ff21a9
--- /dev/null
+++ b/lib/lsan/lit_tests/TestCases/stale_stack_leak.cc
@@ -0,0 +1,42 @@
+// 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
new file mode 100644
index 000000000000..9a165f8770f9
--- /dev/null
+++ b/lib/lsan/lit_tests/TestCases/suppressions_default.cc
@@ -0,0 +1,29 @@
+// 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
new file mode 100644
index 000000000000..9a165f8770f9
--- /dev/null
+++ b/lib/lsan/lit_tests/TestCases/suppressions_file.cc
@@ -0,0 +1,29 @@
+// 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
new file mode 100644
index 000000000000..8d8e560cba4c
--- /dev/null
+++ b/lib/lsan/lit_tests/TestCases/suppressions_file.cc.supp
@@ -0,0 +1 @@
+leak:*LSanTestLeakingFunc*
diff --git a/lib/lsan/lit_tests/TestCases/swapcontext.cc b/lib/lsan/lit_tests/TestCases/swapcontext.cc
new file mode 100644
index 000000000000..a06685ca2f03
--- /dev/null
+++ b/lib/lsan/lit_tests/TestCases/swapcontext.cc
@@ -0,0 +1,42 @@
+// 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
new file mode 100644
index 000000000000..93b0ea6068ef
--- /dev/null
+++ b/lib/lsan/lit_tests/TestCases/use_after_return.cc
@@ -0,0 +1,23 @@
+// 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/use_globals_initialized.cc b/lib/lsan/lit_tests/TestCases/use_globals_initialized.cc
index 53c22c8ac057..5a7c48bdf49a 100644
--- a/lib/lsan/lit_tests/use_globals_initialized.cc
+++ b/lib/lsan/lit_tests/TestCases/use_globals_initialized.cc
@@ -1,7 +1,7 @@
-// Test that initialized globals are included in the root set.
-// RUN: LSAN_BASE="report_blocks=1:use_stacks=0:use_registers=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" %t 2>&1 | FileCheck %s
+// 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
@@ -16,6 +16,6 @@ int main() {
return 0;
}
// CHECK: Test alloc: [[ADDR:.*]].
+// CHECK: Directly leaked 1337 byte object at [[ADDR]]
// CHECK: LeakSanitizer: detected memory leaks
-// CHECK: Directly leaked 1337 byte block at [[ADDR]]
-// CHECK: SUMMARY: LeakSanitizer:
+// 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
new file mode 100644
index 000000000000..e1d045e3f79f
--- /dev/null
+++ b/lib/lsan/lit_tests/TestCases/use_globals_uninitialized.cc
@@ -0,0 +1,21 @@
+// 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
new file mode 100644
index 000000000000..a7d8a69d7173
--- /dev/null
+++ b/lib/lsan/lit_tests/TestCases/use_registers.cc
@@ -0,0 +1,51 @@
+// 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
new file mode 100644
index 000000000000..4287a96b2285
--- /dev/null
+++ b/lib/lsan/lit_tests/TestCases/use_stacks.cc
@@ -0,0 +1,20 @@
+// 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
new file mode 100644
index 000000000000..c7dfaf8abad6
--- /dev/null
+++ b/lib/lsan/lit_tests/TestCases/use_stacks_threaded.cc
@@ -0,0 +1,36 @@
+// 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
new file mode 100644
index 000000000000..2570b63f0c5e
--- /dev/null
+++ b/lib/lsan/lit_tests/TestCases/use_tls_dynamic.cc
@@ -0,0 +1,33 @@
+// 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
new file mode 100644
index 000000000000..3dea41edddd4
--- /dev/null
+++ b/lib/lsan/lit_tests/TestCases/use_tls_pthread_specific_dynamic.cc
@@ -0,0 +1,37 @@
+// 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
new file mode 100644
index 000000000000..b75f15153863
--- /dev/null
+++ b/lib/lsan/lit_tests/TestCases/use_tls_pthread_specific_static.cc
@@ -0,0 +1,31 @@
+// 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
new file mode 100644
index 000000000000..9ccb2b2b7fb1
--- /dev/null
+++ b/lib/lsan/lit_tests/TestCases/use_tls_static.cc
@@ -0,0 +1,21 @@
+// 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
new file mode 100644
index 000000000000..bc75f11b99f0
--- /dev/null
+++ b/lib/lsan/lit_tests/TestCases/use_unaligned.cc
@@ -0,0 +1,23 @@
+// 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.cfg b/lib/lsan/lit_tests/Unit/lit.cfg
deleted file mode 100644
index bcd1de4477f1..000000000000
--- a/lib/lsan/lit_tests/Unit/lit.cfg
+++ /dev/null
@@ -1,26 +0,0 @@
-# -*- Python -*-
-
-import os
-
-def get_required_attr(config, attr_name):
- attr_value = getattr(config, attr_name, None)
- if not attr_value:
- lit.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 attributes common for all compiler-rt projects.
-compiler_rt_src_root = get_required_attr(config, 'compiler_rt_src_root')
-compiler_rt_lit_unit_cfg = os.path.join(compiler_rt_src_root, "lib",
- "lit.common.unit.cfg")
-lit.load_config(config, compiler_rt_lit_unit_cfg)
-
-# 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.
-lsan_binary_dir = get_required_attr(config, "lsan_binary_dir")
-config.test_exec_root = os.path.join(lsan_binary_dir, "tests")
-config.test_source_root = config.test_exec_root
diff --git a/lib/lsan/lit_tests/Unit/lit.site.cfg.in b/lib/lsan/lit_tests/Unit/lit.site.cfg.in
index 90c88c952156..a3a4e9ad0b13 100644
--- a/lib/lsan/lit_tests/Unit/lit.site.cfg.in
+++ b/lib/lsan/lit_tests/Unit/lit.site.cfg.in
@@ -1,17 +1,12 @@
## Autogenerated by LLVM/Clang configuration.
# Do not edit!
-config.target_triple = "@TARGET_TRIPLE@"
-config.llvm_src_root = "@LLVM_SOURCE_DIR@"
-config.compiler_rt_src_root = "@COMPILER_RT_SOURCE_DIR@"
-config.llvm_build_mode = "@LLVM_BUILD_MODE@"
-config.lsan_binary_dir = "@LSAN_BINARY_DIR@"
+# Load common config for all compiler-rt unit tests.
+lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/lib/lit.common.unit.configured")
-try:
- config.llvm_build_mode = config.llvm_build_mode % lit.params
-except KeyError,e:
- key, = e.args
- lit.fatal("unable to find %r parameter, use '--param=%s=VALUE'" % (key, key))
-
-# Let the main config do the real work.
-lit.load_config(config, "@LSAN_SOURCE_DIR@/lit_tests/Unit/lit.cfg")
+# 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.cfg b/lib/lsan/lit_tests/lit.cfg
deleted file mode 100644
index 48e1453334d0..000000000000
--- a/lib/lsan/lit_tests/lit.cfg
+++ /dev/null
@@ -1,50 +0,0 @@
-# -*- Python -*-
-
-import os
-
-def get_required_attr(config, attr_name):
- attr_value = getattr(config, attr_name, None)
- if not attr_value:
- lit.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 attributes common for all compiler-rt projects.
-compiler_rt_src_root = get_required_attr(config, 'compiler_rt_src_root')
-compiler_rt_lit_unit_cfg = os.path.join(compiler_rt_src_root, "lib",
- "lit.common.unit.cfg")
-lit.load_config(config, compiler_rt_lit_unit_cfg)
-
-# Setup config name.
-config.name = 'LeakSanitizer'
-
-# Setup source root.
-config.test_source_root = os.path.dirname(__file__)
-
-# Setup attributes common for all compiler-rt projects.
-compiler_rt_lit_cfg = os.path.join(compiler_rt_src_root, "lib",
- "lit.common.cfg")
-if (not compiler_rt_lit_cfg) or (not os.path.exists(compiler_rt_lit_cfg)):
- lit.fatal("Can't find common compiler-rt lit config at: %r"
- % compiler_rt_lit_cfg)
-lit.load_config(config, compiler_rt_lit_cfg)
-
-clang_cxxflags = ("-ccc-cxx "
- + "-g "
- + "-O0 "
- + "-m64 ")
-
-clang_lsan_cxxflags = clang_cxxflags + "-fsanitize=leak "
-
-config.substitutions.append( ("%clangxx ", (" " + config.clang + " " +
- clang_cxxflags + " ")) )
-config.substitutions.append( ("%clangxx_lsan ", (" " + config.clang + " " +
- clang_lsan_cxxflags + " ")) )
-
-# Default test suffixes.
-config.suffixes = ['.c', '.cc', '.cpp']
-
-# 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
diff --git a/lib/lsan/lit_tests/lit.common.cfg b/lib/lsan/lit_tests/lit.common.cfg
new file mode 100644
index 000000000000..96dc1b1f55fc
--- /dev/null
+++ b/lib/lsan/lit_tests/lit.common.cfg
@@ -0,0 +1,43 @@
+# -*- 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/lit_tests/lit.site.cfg.in b/lib/lsan/lit_tests/lit.site.cfg.in
deleted file mode 100644
index 3de98a9811f8..000000000000
--- a/lib/lsan/lit_tests/lit.site.cfg.in
+++ /dev/null
@@ -1,20 +0,0 @@
-config.host_os = "@HOST_OS@"
-config.host_arch = "@HOST_ARCH@"
-config.llvm_build_mode = "@LLVM_BUILD_MODE@"
-config.llvm_src_root = "@LLVM_SOURCE_DIR@"
-config.compiler_rt_src_root = "@COMPILER_RT_SOURCE_DIR@"
-config.llvm_obj_root = "@LLVM_BINARY_DIR@"
-config.llvm_tools_dir = "@LLVM_TOOLS_DIR@"
-config.clang = "@LLVM_BINARY_DIR@/bin/clang"
-config.compiler_rt_arch = "@COMPILER_RT_SUPPORTED_ARCH@"
-
-# LLVM tools dir can be passed in lit parameters, so try to
-# apply substitution.
-try:
- config.llvm_tools_dir = config.llvm_tools_dir % lit.params
-except KeyError,e:
- key, = e.args
- lit.fatal("unable to find %r parameter, use '--param=%s=VALUE'" % (key, key))
-
-# Let the main config do the real work.
-lit.load_config(config, "@CMAKE_CURRENT_SOURCE_DIR@/lit.cfg")
diff --git a/lib/lsan/lsan.cc b/lib/lsan/lsan.cc
index 9b83b411f843..058bbdba3907 100644
--- a/lib/lsan/lsan.cc
+++ b/lib/lsan/lsan.cc
@@ -20,25 +20,30 @@
#include "lsan_common.h"
#include "lsan_thread.h"
+bool lsan_inited;
+bool lsan_init_is_running;
+
namespace __lsan {
static void InitializeCommonFlags() {
CommonFlags *cf = common_flags();
+ SetCommonFlagDefaults();
cf->external_symbolizer_path = GetEnv("LSAN_SYMBOLIZER_PATH");
- cf->symbolize = (cf->external_symbolizer_path &&
- cf->external_symbolizer_path[0]);
- cf->strip_path_prefix = "";
- cf->fast_unwind_on_malloc = true;
cf->malloc_context_size = 30;
+ cf->detect_leaks = true;
ParseCommonFlagsFromString(GetEnv("LSAN_OPTIONS"));
}
-void Init() {
- static bool inited;
- if (inited)
+} // namespace __lsan
+
+using namespace __lsan; // NOLINT
+
+extern "C" void __lsan_init() {
+ CHECK(!lsan_init_is_running);
+ if (lsan_inited)
return;
- inited = true;
+ lsan_init_is_running = true;
SanitizerToolName = "LeakSanitizer";
InitializeCommonFlags();
InitializeAllocator();
@@ -48,16 +53,19 @@ void Init() {
u32 tid = ThreadCreate(0, 0, true);
CHECK_EQ(tid, 0);
ThreadStart(tid, GetTid());
+ SetCurrentThread(tid);
// Start symbolizer process if necessary.
- const char* external_symbolizer = common_flags()->external_symbolizer_path;
- if (common_flags()->symbolize && external_symbolizer &&
- external_symbolizer[0]) {
- InitializeExternalSymbolizer(external_symbolizer);
+ if (common_flags()->symbolize) {
+ Symbolizer::Init(common_flags()->external_symbolizer_path);
+ } else {
+ Symbolizer::Disable();
}
InitCommonLsan();
- Atexit(DoLeakCheck);
+ if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit)
+ Atexit(DoLeakCheck);
+ lsan_inited = true;
+ lsan_init_is_running = false;
}
-} // namespace __lsan
diff --git a/lib/lsan/lsan.h b/lib/lsan/lsan.h
index d89a6ab8f983..3e7f76b08193 100644
--- a/lib/lsan/lsan.h
+++ b/lib/lsan/lsan.h
@@ -17,7 +17,11 @@
namespace __lsan {
-void Init();
void InitializeInterceptors();
} // namespace __lsan
+
+extern bool lsan_inited;
+extern bool lsan_init_is_running;
+
+extern "C" void __lsan_init();
diff --git a/lib/lsan/lsan_allocator.cc b/lib/lsan/lsan_allocator.cc
index 49b5a9fa4c5d..f7eee1314bf0 100644
--- a/lib/lsan/lsan_allocator.cc
+++ b/lib/lsan/lsan_allocator.cc
@@ -20,13 +20,13 @@
#include "sanitizer_common/sanitizer_stacktrace.h"
#include "lsan_common.h"
-namespace __lsan {
+extern "C" void *memset(void *ptr, int value, uptr num);
-static const uptr kMaxAllowedMallocSize =
- FIRST_32_SECOND_64(3UL << 30, 8UL << 30);
+namespace __lsan {
+static const uptr kMaxAllowedMallocSize = 8UL << 30;
static const uptr kAllocatorSpace = 0x600000000000ULL;
-static const uptr kAllocatorSize = 0x10000000000ULL; // 1T.
+static const uptr kAllocatorSize = 0x40000000000ULL; // 4T.
struct ChunkMetadata {
bool allocated : 8; // Must be first.
@@ -36,7 +36,7 @@ struct ChunkMetadata {
};
typedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize,
- sizeof(ChunkMetadata), CompactSizeClassMap> PrimaryAllocator;
+ sizeof(ChunkMetadata), DefaultSizeClassMap> PrimaryAllocator;
typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache;
typedef LargeMmapAllocator<> SecondaryAllocator;
typedef CombinedAllocator<PrimaryAllocator, AllocatorCache,
@@ -54,23 +54,24 @@ void AllocatorThreadFinish() {
}
static ChunkMetadata *Metadata(void *p) {
- return (ChunkMetadata *)allocator.GetMetaData(p);
+ return reinterpret_cast<ChunkMetadata *>(allocator.GetMetaData(p));
}
static void RegisterAllocation(const StackTrace &stack, void *p, uptr size) {
if (!p) return;
ChunkMetadata *m = Metadata(p);
CHECK(m);
+ m->tag = DisabledInThisThread() ? kIgnored : kDirectlyLeaked;
m->stack_trace_id = StackDepotPut(stack.trace, stack.size);
m->requested_size = size;
- atomic_store((atomic_uint8_t*)m, 1, memory_order_relaxed);
+ atomic_store(reinterpret_cast<atomic_uint8_t *>(m), 1, memory_order_relaxed);
}
static void RegisterDeallocation(void *p) {
if (!p) return;
ChunkMetadata *m = Metadata(p);
CHECK(m);
- atomic_store((atomic_uint8_t*)m, 0, memory_order_relaxed);
+ atomic_store(reinterpret_cast<atomic_uint8_t *>(m), 0, memory_order_relaxed);
}
void *Allocate(const StackTrace &stack, uptr size, uptr alignment,
@@ -78,11 +79,13 @@ void *Allocate(const StackTrace &stack, uptr size, uptr alignment,
if (size == 0)
size = 1;
if (size > kMaxAllowedMallocSize) {
- Report("WARNING: LeakSanitizer failed to allocate %p bytes\n",
- (void*)size);
- return 0;
+ Report("WARNING: LeakSanitizer failed to allocate %zu bytes\n", size);
+ return 0;
}
- void *p = allocator.Allocate(&cache, size, alignment, cleared);
+ void *p = allocator.Allocate(&cache, size, alignment, false);
+ // Do not rely on the allocator to clear the memory (it's slow).
+ if (cleared && allocator.FromPrimary(p))
+ memset(p, 0, size);
RegisterAllocation(stack, p, size);
return p;
}
@@ -96,10 +99,9 @@ void *Reallocate(const StackTrace &stack, void *p, uptr new_size,
uptr alignment) {
RegisterDeallocation(p);
if (new_size > kMaxAllowedMallocSize) {
- Report("WARNING: LeakSanitizer failed to allocate %p bytes\n",
- (void*)new_size);
- allocator.Deallocate(&cache, p);
- return 0;
+ Report("WARNING: LeakSanitizer failed to allocate %zu bytes\n", new_size);
+ allocator.Deallocate(&cache, p);
+ return 0;
}
p = allocator.Reallocate(&cache, p, new_size, alignment);
RegisterAllocation(stack, p, new_size);
@@ -132,26 +134,26 @@ void GetAllocatorGlobalRange(uptr *begin, uptr *end) {
*end = *begin + sizeof(allocator);
}
-void *PointsIntoChunk(void* p) {
- if (!allocator.PointerIsMine(p)) return 0;
- void *chunk = allocator.GetBlockBegin(p);
+uptr PointsIntoChunk(void* p) {
+ uptr addr = reinterpret_cast<uptr>(p);
+ uptr chunk = reinterpret_cast<uptr>(allocator.GetBlockBeginFastLocked(p));
if (!chunk) return 0;
// LargeMmapAllocator considers pointers to the meta-region of a chunk to be
// valid, but we don't want that.
- if (p < chunk) return 0;
- ChunkMetadata *m = Metadata(chunk);
+ if (addr < chunk) return 0;
+ ChunkMetadata *m = Metadata(reinterpret_cast<void *>(chunk));
CHECK(m);
- if (m->allocated && (uptr)p < (uptr)chunk + m->requested_size)
+ if (m->allocated && addr < chunk + m->requested_size)
return chunk;
return 0;
}
-void *GetUserBegin(void *p) {
- return p;
+uptr GetUserBegin(uptr chunk) {
+ return chunk;
}
-LsanMetadata::LsanMetadata(void *chunk) {
- metadata_ = Metadata(chunk);
+LsanMetadata::LsanMetadata(uptr chunk) {
+ metadata_ = Metadata(reinterpret_cast<void *>(chunk));
CHECK(metadata_);
}
@@ -175,16 +177,22 @@ u32 LsanMetadata::stack_trace_id() const {
return reinterpret_cast<ChunkMetadata *>(metadata_)->stack_trace_id;
}
-template<typename Callable>
-void ForEachChunk(Callable const &callback) {
- allocator.ForEachChunk(callback);
+void ForEachChunk(ForEachChunkCallback callback, void *arg) {
+ allocator.ForEachChunk(callback, arg);
}
-template void ForEachChunk<ProcessPlatformSpecificAllocationsCb>(
- ProcessPlatformSpecificAllocationsCb const &callback);
-template void ForEachChunk<PrintLeakedCb>(PrintLeakedCb const &callback);
-template void ForEachChunk<CollectLeaksCb>(CollectLeaksCb const &callback);
-template void ForEachChunk<MarkIndirectlyLeakedCb>(
- MarkIndirectlyLeakedCb const &callback);
-template void ForEachChunk<ClearTagCb>(ClearTagCb const &callback);
+IgnoreObjectResult IgnoreObjectLocked(const void *p) {
+ void *chunk = allocator.GetBlockBegin(p);
+ if (!chunk || p < chunk) return kIgnoreObjectInvalid;
+ ChunkMetadata *m = Metadata(chunk);
+ CHECK(m);
+ if (m->allocated && (uptr)p < (uptr)chunk + m->requested_size) {
+ if (m->tag == kIgnored)
+ return kIgnoreObjectAlreadyIgnored;
+ m->tag = kIgnored;
+ return kIgnoreObjectSuccess;
+ } else {
+ return kIgnoreObjectInvalid;
+ }
+}
} // namespace __lsan
diff --git a/lib/lsan/lsan_common.cc b/lib/lsan/lsan_common.cc
index e2971e999aa6..152588411e2f 100644
--- a/lib/lsan/lsan_common.cc
+++ b/lib/lsan/lsan_common.cc
@@ -16,27 +16,38 @@
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_flags.h"
+#include "sanitizer_common/sanitizer_placement_new.h"
#include "sanitizer_common/sanitizer_stackdepot.h"
#include "sanitizer_common/sanitizer_stacktrace.h"
#include "sanitizer_common/sanitizer_stoptheworld.h"
+#include "sanitizer_common/sanitizer_suppressions.h"
+#include "sanitizer_common/sanitizer_report_decorator.h"
#if CAN_SANITIZE_LEAKS
namespace __lsan {
+// This mutex is used to prevent races between DoLeakCheck and IgnoreObject.
+BlockingMutex global_mutex(LINKER_INITIALIZED);
+
+THREADLOCAL int disable_counter;
+bool DisabledInThisThread() { return disable_counter > 0; }
+
Flags lsan_flags;
static void InitializeFlags() {
Flags *f = flags();
// Default values.
- f->report_blocks = false;
+ 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_unaligned = false;
+ f->verbosity = 0;
f->log_pointers = false;
f->log_threads = false;
@@ -47,25 +58,60 @@ static void InitializeFlags() {
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_blocks, "report_blocks");
+ ParseFlag(options, &f->report_objects, "report_objects");
ParseFlag(options, &f->resolution, "resolution");
CHECK_GE(&f->resolution, 0);
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");
+ }
+}
+
+SuppressionContext *suppression_ctx;
+
+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();
}
+ if (&__lsan_default_suppressions)
+ suppression_ctx->Parse(__lsan_default_suppressions());
}
void InitCommonLsan() {
InitializeFlags();
- InitializePlatformSpecificModules();
+ if (common_flags()->detect_leaks) {
+ // Initialization which can fail or print warnings should only be done if
+ // LSan is actually enabled.
+ InitializeSuppressions();
+ InitializePlatformSpecificModules();
+ }
}
+class Decorator: private __sanitizer::AnsiColorDecorator {
+ public:
+ Decorator() : __sanitizer::AnsiColorDecorator(PrintsToTtyCached()) { }
+ const char *Error() { return Red(); }
+ const char *Leak() { return Blue(); }
+ const char *End() { return Default(); }
+};
+
static inline bool CanBeAHeapPointer(uptr p) {
// Since our heap is located in mmap-ed memory, we can assume a sensible lower
- // boundary on heap addresses.
+ // bound on heap addresses.
const uptr kMinAddress = 4 * 4096;
if (p < kMinAddress) return false;
#ifdef __x86_64__
@@ -76,13 +122,14 @@ static inline bool CanBeAHeapPointer(uptr p) {
#endif
}
-// Scan the memory range, looking for byte patterns that point into allocator
-// chunks. Mark those chunks with tag and add them to the frontier.
-// There are two usage modes for this function: finding non-leaked chunks
-// (tag = kReachable) and finding indirectly leaked chunks
-// (tag = kIndirectlyLeaked). In the second case, there's no flood fill,
-// so frontier = 0.
-void ScanRangeForPointers(uptr begin, uptr end, InternalVector<uptr> *frontier,
+// Scans the memory range, looking for byte patterns that point into allocator
+// chunks. Marks those chunks with |tag| and adds them to |frontier|.
+// There are two usage modes for this function: finding reachable or ignored
+// chunks (|tag| = kReachable or kIgnored) and finding indirectly leaked chunks
+// (|tag| = kIndirectlyLeaked). In the second case, there's no flood fill,
+// so |frontier| = 0.
+void ScanRangeForPointers(uptr begin, uptr end,
+ Frontier *frontier,
const char *region_type, ChunkTag tag) {
const uptr alignment = flags()->pointer_alignment();
if (flags()->log_pointers)
@@ -90,28 +137,34 @@ void ScanRangeForPointers(uptr begin, uptr end, InternalVector<uptr> *frontier,
uptr pp = begin;
if (pp % alignment)
pp = pp + alignment - pp % alignment;
- for (; pp + sizeof(uptr) <= end; pp += alignment) {
- void *p = *reinterpret_cast<void**>(pp);
+ for (; pp + sizeof(void *) <= end; pp += alignment) { // NOLINT
+ void *p = *reinterpret_cast<void **>(pp);
if (!CanBeAHeapPointer(reinterpret_cast<uptr>(p))) continue;
- // FIXME: PointsIntoChunk is SLOW because GetBlockBegin() in
- // LargeMmapAllocator involves a lock and a linear search.
- void *chunk = PointsIntoChunk(p);
+ uptr chunk = PointsIntoChunk(p);
if (!chunk) continue;
+ // Pointers to self don't count. This matters when tag == kIndirectlyLeaked.
+ if (chunk == begin) continue;
LsanMetadata m(chunk);
+ // Reachable beats ignored beats leaked.
if (m.tag() == kReachable) continue;
+ if (m.tag() == kIgnored && tag != kReachable) continue;
m.set_tag(tag);
if (flags()->log_pointers)
- Report("%p: found %p pointing into chunk %p-%p of size %llu.\n", pp, p,
- chunk, reinterpret_cast<uptr>(chunk) + m.requested_size(),
- m.requested_size());
+ Report("%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(reinterpret_cast<uptr>(chunk));
+ frontier->push_back(chunk);
}
}
-// Scan thread data (stacks and TLS) for heap pointers.
+void ForEachExtraStackRangeCb(uptr begin, uptr end, void* arg) {
+ Frontier *frontier = reinterpret_cast<Frontier *>(arg);
+ ScanRangeForPointers(begin, end, frontier, "FAKE STACK", kReachable);
+}
+
+// Scans thread data (stacks and TLS) for heap pointers.
static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
- InternalVector<uptr> *frontier) {
+ Frontier *frontier) {
InternalScopedBuffer<uptr> registers(SuspendedThreadsList::RegisterCount());
uptr registers_begin = reinterpret_cast<uptr>(registers.data());
uptr registers_end = registers_begin + registers.size();
@@ -150,13 +203,14 @@ static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
// 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");
+ Report("WARNING: stack pointer not in stack range.\n");
} else {
// Shrink the stack range to ignore out-of-scope values.
stack_begin = sp;
}
ScanRangeForPointers(stack_begin, stack_end, frontier, "STACK",
kReachable);
+ ForEachExtraStackRange(os_id, ForEachExtraStackRangeCb, frontier);
}
if (flags()->use_tls) {
@@ -178,152 +232,210 @@ static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
}
}
-static void FloodFillReachable(InternalVector<uptr> *frontier) {
+static void FloodFillTag(Frontier *frontier, ChunkTag tag) {
while (frontier->size()) {
uptr next_chunk = frontier->back();
frontier->pop_back();
- LsanMetadata m(reinterpret_cast<void *>(next_chunk));
+ LsanMetadata m(next_chunk);
ScanRangeForPointers(next_chunk, next_chunk + m.requested_size(), frontier,
- "HEAP", kReachable);
+ "HEAP", tag);
}
}
-// Mark leaked chunks which are reachable from other leaked chunks.
-void MarkIndirectlyLeakedCb::operator()(void *p) const {
- p = GetUserBegin(p);
- LsanMetadata m(p);
+// ForEachChunk callback. If the chunk is marked as leaked, marks all chunks
+// which are reachable from it as indirectly leaked.
+static void MarkIndirectlyLeakedCb(uptr chunk, void *arg) {
+ chunk = GetUserBegin(chunk);
+ LsanMetadata m(chunk);
if (m.allocated() && m.tag() != kReachable) {
- ScanRangeForPointers(reinterpret_cast<uptr>(p),
- reinterpret_cast<uptr>(p) + m.requested_size(),
+ ScanRangeForPointers(chunk, chunk + m.requested_size(),
/* frontier */ 0, "HEAP", kIndirectlyLeaked);
}
}
-// Set the appropriate tag on each chunk.
+// ForEachChunk callback. If chunk is marked as ignored, adds its address to
+// frontier.
+static void CollectIgnoredCb(uptr chunk, void *arg) {
+ CHECK(arg);
+ chunk = GetUserBegin(chunk);
+ LsanMetadata m(chunk);
+ if (m.allocated() && m.tag() == kIgnored)
+ reinterpret_cast<Frontier *>(arg)->push_back(chunk);
+}
+
+// Sets the appropriate tag on each chunk.
static void ClassifyAllChunks(SuspendedThreadsList const &suspended_threads) {
// Holds the flood fill frontier.
- InternalVector<uptr> frontier(GetPageSizeCached());
+ Frontier frontier(GetPageSizeCached());
if (flags()->use_globals)
ProcessGlobalRegions(&frontier);
ProcessThreads(suspended_threads, &frontier);
- FloodFillReachable(&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");
ProcessPlatformSpecificAllocations(&frontier);
- FloodFillReachable(&frontier);
+ FloodFillTag(&frontier, kReachable);
- // Now all reachable chunks are marked. Iterate over leaked chunks and mark
- // those that are reachable from other leaked chunks.
if (flags()->log_pointers)
- Report("Now scanning leaked blocks for pointers.\n");
- ForEachChunk(MarkIndirectlyLeakedCb());
-}
+ Report("Scanning ignored chunks.\n");
+ CHECK_EQ(0, frontier.size());
+ ForEachChunk(CollectIgnoredCb, &frontier);
+ FloodFillTag(&frontier, kIgnored);
-void ClearTagCb::operator()(void *p) const {
- p = GetUserBegin(p);
- LsanMetadata m(p);
- m.set_tag(kDirectlyLeaked);
+ // Iterate over leaked chunks and mark those that are reachable from other
+ // leaked chunks.
+ if (flags()->log_pointers)
+ Report("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, common_flags()->symbolize,
- common_flags()->strip_path_prefix, 0);
-}
-
-static void LockAndSuspendThreads(StopTheWorldCallback callback, void *arg) {
- LockThreadRegistry();
- LockAllocator();
- StopTheWorld(callback, arg);
- // Allocator must be unlocked by the callback.
- UnlockThreadRegistry();
+ StackTrace::PrintStack(trace, size);
}
-///// Normal leak checking. /////
-
-void CollectLeaksCb::operator()(void *p) const {
- p = GetUserBegin(p);
- LsanMetadata m(p);
+// ForEachChunk callback. Aggregates unreachable chunks into a LeakReport.
+static void CollectLeaksCb(uptr chunk, void *arg) {
+ CHECK(arg);
+ LeakReport *leak_report = reinterpret_cast<LeakReport *>(arg);
+ chunk = GetUserBegin(chunk);
+ LsanMetadata m(chunk);
if (!m.allocated()) return;
- if (m.tag() != kReachable) {
+ if (m.tag() == kDirectlyLeaked || m.tag() == kIndirectlyLeaked) {
uptr resolution = flags()->resolution;
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());
+ leak_report->Add(StackDepotPut(trace, size), m.requested_size(), m.tag());
} else {
- leak_report_->Add(m.stack_trace_id(), m.requested_size(), m.tag());
+ leak_report->Add(m.stack_trace_id(), m.requested_size(), m.tag());
}
}
}
-static void CollectLeaks(LeakReport *leak_report) {
- ForEachChunk(CollectLeaksCb(leak_report));
-}
-
-void PrintLeakedCb::operator()(void *p) const {
- p = GetUserBegin(p);
- LsanMetadata m(p);
+// 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() != kReachable) {
- CHECK(m.tag() == kDirectlyLeaked || m.tag() == kIndirectlyLeaked);
- Printf("%s leaked %llu byte block at %p\n",
+ if (m.tag() == kDirectlyLeaked || m.tag() == kIndirectlyLeaked) {
+ Printf("%s leaked %zu byte object at %p.\n",
m.tag() == kDirectlyLeaked ? "Directly" : "Indirectly",
- m.requested_size(), p);
+ m.requested_size(), chunk);
}
}
+static void PrintMatchedSuppressions() {
+ InternalMmapVector<Suppression *> matched(1);
+ suppression_ctx->GetMatched(&matched);
+ if (!matched.size())
+ return;
+ const char *line = "-----------------------------------------------------";
+ Printf("%s\n", line);
+ Printf("Suppressions used:\n");
+ Printf(" count bytes template\n");
+ for (uptr i = 0; i < matched.size(); i++)
+ Printf("%7zu %10zu %s\n", static_cast<uptr>(matched[i]->hit_count),
+ matched[i]->weight, matched[i]->templ);
+ Printf("%s\n\n", line);
+}
+
static void PrintLeaked() {
- Printf("Reporting individual blocks:\n");
- Printf("============================\n");
- ForEachChunk(PrintLeakedCb());
Printf("\n");
+ Printf("Reporting individual objects:\n");
+ ForEachChunk(PrintLeakedCb, 0 /* arg */);
}
-enum LeakCheckResult {
- kFatalError,
- kLeaksFound,
- kNoLeaks
+struct DoLeakCheckParam {
+ bool success;
+ LeakReport leak_report;
};
static void DoLeakCheckCallback(const SuspendedThreadsList &suspended_threads,
void *arg) {
- LeakCheckResult *result = reinterpret_cast<LeakCheckResult *>(arg);
- CHECK_EQ(*result, kFatalError);
- // Allocator must not be locked when we call GetRegionBegin().
- UnlockAllocator();
+ DoLeakCheckParam *param = reinterpret_cast<DoLeakCheckParam *>(arg);
+ CHECK(param);
+ CHECK(!param->success);
+ CHECK(param->leak_report.IsEmpty());
ClassifyAllChunks(suspended_threads);
- LeakReport leak_report;
- CollectLeaks(&leak_report);
- if (leak_report.IsEmpty()) {
- *result = kNoLeaks;
- return;
- }
- Printf("\n");
- Printf("=================================================================\n");
- Report("ERROR: LeakSanitizer: detected memory leaks\n");
- leak_report.PrintLargest(flags()->max_leaks);
- if (flags()->report_blocks)
+ ForEachChunk(CollectLeaksCb, &param->leak_report);
+ if (!param->leak_report.IsEmpty() && flags()->report_objects)
PrintLeaked();
- leak_report.PrintSummary();
- Printf("\n");
- ForEachChunk(ClearTagCb());
- *result = kLeaksFound;
+ param->success = true;
}
void DoLeakCheck() {
- LeakCheckResult result = kFatalError;
- LockAndSuspendThreads(DoLeakCheckCallback, &result);
- if (result == kFatalError) {
+ EnsureMainThreadIDIsCorrect();
+ BlockingMutexLock l(&global_mutex);
+ static bool already_done;
+ if (already_done) return;
+ already_done = true;
+ if (&__lsan_is_turned_off && __lsan_is_turned_off())
+ return;
+
+ DoLeakCheckParam param;
+ param.success = false;
+ LockThreadRegistry();
+ LockAllocator();
+ StopTheWorld(DoLeakCheckCallback, &param);
+ UnlockAllocator();
+ UnlockThreadRegistry();
+
+ if (!param.success) {
Report("LeakSanitizer has encountered a fatal error.\n");
Die();
- } else if (result == kLeaksFound) {
- if (flags()->exitcode)
- internal__exit(flags()->exitcode);
}
+ uptr have_unsuppressed = param.leak_report.ApplySuppressions();
+ if (have_unsuppressed) {
+ Decorator d;
+ Printf("\n"
+ "================================================================="
+ "\n");
+ Printf("%s", d.Error());
+ Report("ERROR: LeakSanitizer: detected memory leaks\n");
+ Printf("%s", d.End());
+ param.leak_report.PrintLargest(flags()->max_leaks);
+ }
+ if (have_unsuppressed || (flags()->verbosity >= 1)) {
+ PrintMatchedSuppressions();
+ param.leak_report.PrintSummary();
+ }
+ 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;
+ }
+ return 0;
+}
+
+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]));
+ if (s) return s;
+ }
+ return 0;
}
///// LeakReport implementation. /////
@@ -333,7 +445,7 @@ void DoLeakCheck() {
// real-world applications.
// FIXME: Get rid of this limit by changing the implementation of LeakReport to
// use a hash table.
-const uptr kMaxLeaksConsidered = 1000;
+const uptr kMaxLeaksConsidered = 5000;
void LeakReport::Add(u32 stack_trace_id, uptr leaked_size, ChunkTag tag) {
CHECK(tag == kDirectlyLeaked || tag == kIndirectlyLeaked);
@@ -347,35 +459,47 @@ void LeakReport::Add(u32 stack_trace_id, uptr leaked_size, ChunkTag tag) {
}
if (leaks_.size() == kMaxLeaksConsidered) return;
Leak leak = { /* hit_count */ 1, leaked_size, stack_trace_id,
- is_directly_leaked };
+ is_directly_leaked, /* is_suppressed */ false };
leaks_.push_back(leak);
}
-static bool IsLarger(const Leak &leak1, const Leak &leak2) {
- return leak1.total_size > leak2.total_size;
+static bool LeakComparator(const Leak &leak1, const Leak &leak2) {
+ if (leak1.is_directly_leaked == leak2.is_directly_leaked)
+ return leak1.total_size > leak2.total_size;
+ else
+ return leak1.is_directly_leaked;
}
-void LeakReport::PrintLargest(uptr max_leaks) {
+void LeakReport::PrintLargest(uptr num_leaks_to_print) {
CHECK(leaks_.size() <= kMaxLeaksConsidered);
Printf("\n");
if (leaks_.size() == kMaxLeaksConsidered)
- Printf("Too many leaks! Only the first %llu leaks encountered will be "
+ Printf("Too many leaks! Only the first %zu leaks encountered will be "
"reported.\n",
kMaxLeaksConsidered);
- if (max_leaks > 0 && max_leaks < leaks_.size())
- Printf("The %llu largest leak(s):\n", max_leaks);
- InternalSort(&leaks_, leaks_.size(), IsLarger);
- max_leaks = max_leaks > 0 ? Min(max_leaks, leaks_.size()) : leaks_.size();
- for (uptr i = 0; i < max_leaks; i++) {
- Printf("%s leak of %llu byte(s) in %llu object(s) allocated from:\n",
+
+ 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);
+ InternalSort(&leaks_, leaks_.size(), LeakComparator);
+ uptr leaks_printed = 0;
+ Decorator d;
+ 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);
- Printf("\n");
+ leaks_printed++;
+ if (leaks_printed == num_leaks_to_print) break;
}
- if (max_leaks < leaks_.size()) {
- uptr remaining = leaks_.size() - max_leaks;
- Printf("Omitting %llu more leak(s).\n", remaining);
+ if (leaks_printed < unsuppressed_count) {
+ uptr remaining = unsuppressed_count - leaks_printed;
+ Printf("Omitting %zu more leak(s).\n", remaining);
}
}
@@ -383,11 +507,86 @@ void LeakReport::PrintSummary() {
CHECK(leaks_.size() <= kMaxLeaksConsidered);
uptr bytes = 0, allocations = 0;
for (uptr i = 0; i < leaks_.size(); i++) {
+ if (leaks_[i].is_suppressed) continue;
bytes += leaks_[i].total_size;
allocations += leaks_[i].hit_count;
}
- Printf("SUMMARY: LeakSanitizer: %llu byte(s) leaked in %llu allocation(s).\n",
- bytes, allocations);
+ InternalScopedBuffer<char> summary(kMaxSummaryLength);
+ internal_snprintf(summary.data(), summary.size(),
+ "%zu byte(s) leaked in %zu allocation(s).", bytes,
+ allocations);
+ ReportErrorSummary(summary.data());
+}
+
+uptr LeakReport::ApplySuppressions() {
+ uptr unsuppressed_count = 0;
+ 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;
}
} // namespace __lsan
#endif // CAN_SANITIZE_LEAKS
+
+using namespace __lsan; // NOLINT
+
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE
+void __lsan_ignore_object(const void *p) {
+#if CAN_SANITIZE_LEAKS
+ if (!common_flags()->detect_leaks)
+ return;
+ // Cannot use PointsIntoChunk or LsanMetadata here, since the allocator is not
+ // 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(): "
+ "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);
+#endif // CAN_SANITIZE_LEAKS
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __lsan_disable() {
+#if CAN_SANITIZE_LEAKS
+ __lsan::disable_counter++;
+#endif
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __lsan_enable() {
+#if CAN_SANITIZE_LEAKS
+ if (!__lsan::disable_counter && common_flags()->detect_leaks) {
+ Report("Unmatched call to __lsan_enable().\n");
+ Die();
+ }
+ __lsan::disable_counter--;
+#endif
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __lsan_do_leak_check() {
+#if CAN_SANITIZE_LEAKS
+ if (common_flags()->detect_leaks)
+ __lsan::DoLeakCheck();
+#endif // CAN_SANITIZE_LEAKS
+}
+
+#if !SANITIZER_SUPPORTS_WEAK_HOOKS
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+int __lsan_is_turned_off() {
+ return 0;
+}
+#endif
+} // extern "C"
diff --git a/lib/lsan/lsan_common.h b/lib/lsan/lsan_common.h
index 8cb4b2753cd9..d490f8bafd9e 100644
--- a/lib/lsan/lsan_common.h
+++ b/lib/lsan/lsan_common.h
@@ -15,6 +15,7 @@
#ifndef LSAN_COMMON_H
#define LSAN_COMMON_H
+#include "sanitizer_common/sanitizer_allocator.h"
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_internal_defs.h"
#include "sanitizer_common/sanitizer_platform.h"
@@ -32,7 +33,8 @@ namespace __lsan {
enum ChunkTag {
kDirectlyLeaked = 0, // default
kIndirectlyLeaked = 1,
- kReachable = 2
+ kReachable = 2,
+ kIgnored = 3
};
struct Flags {
@@ -40,15 +42,17 @@ struct Flags {
return use_unaligned ? 1 : sizeof(uptr);
}
- // Print addresses of leaked blocks after main leak report.
- bool report_blocks;
- // Aggregate two blocks into one leak if this many stack frames match. If
+ // Print addresses of leaked objects after main leak report.
+ bool report_objects;
+ // Aggregate two objects into one leak if this many stack frames match. If
// zero, the entire stack trace must match.
int resolution;
// The number of leaks reported.
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,6 +67,9 @@ struct Flags {
// Consider unaligned pointers valid.
bool use_unaligned;
+ // User-visible verbosity.
+ int verbosity;
+
// Debug logging.
bool log_pointers;
bool log_threads;
@@ -71,17 +78,12 @@ struct Flags {
extern Flags lsan_flags;
inline Flags *flags() { return &lsan_flags; }
-void InitCommonLsan();
-// Testing interface. Find leaked chunks and dump their addresses to vector.
-void ReportLeaked(InternalVector<void *> *leaked, uptr sources);
-// Normal leak check. Find leaks and print a report according to flags.
-void DoLeakCheck();
-
struct Leak {
uptr hit_count;
uptr total_size;
u32 stack_trace_id;
bool is_directly_leaked;
+ bool is_suppressed;
};
// Aggregates leaks by stack trace prefix.
@@ -92,66 +94,37 @@ class LeakReport {
void PrintLargest(uptr max_leaks);
void PrintSummary();
bool IsEmpty() { return leaks_.size() == 0; }
+ uptr ApplySuppressions();
private:
- InternalVector<Leak> leaks_;
+ InternalMmapVector<Leak> leaks_;
};
+typedef InternalMmapVector<uptr> Frontier;
+
// Platform-specific functions.
void InitializePlatformSpecificModules();
-void ProcessGlobalRegions(InternalVector<uptr> *frontier);
-void ProcessPlatformSpecificAllocations(InternalVector<uptr> *frontier);
+void ProcessGlobalRegions(Frontier *frontier);
+void ProcessPlatformSpecificAllocations(Frontier *frontier);
-void ScanRangeForPointers(uptr begin, uptr end, InternalVector<uptr> *frontier,
+void ScanRangeForPointers(uptr begin, uptr end,
+ Frontier *frontier,
const char *region_type, ChunkTag tag);
-// Callables for iterating over chunks. Those classes are used as template
-// parameters in ForEachChunk, so we must expose them here to allow for explicit
-// template instantiation.
-
-// Identifies unreachable chunks which must be treated as reachable. Marks them
-// as reachable and adds them to the frontier.
-class ProcessPlatformSpecificAllocationsCb {
- public:
- explicit ProcessPlatformSpecificAllocationsCb(InternalVector<uptr> *frontier)
- : frontier_(frontier) {}
- void operator()(void *p) const;
- private:
- InternalVector<uptr> *frontier_;
-};
-
-// Prints addresses of unreachable chunks.
-class PrintLeakedCb {
- public:
- void operator()(void *p) const;
-};
-
-// Aggregates unreachable chunks into a LeakReport.
-class CollectLeaksCb {
- public:
- explicit CollectLeaksCb(LeakReport *leak_report)
- : leak_report_(leak_report) {}
- void operator()(void *p) const;
- private:
- LeakReport *leak_report_;
-};
-
-// Resets each chunk's tag to default (kDirectlyLeaked).
-class ClearTagCb {
- public:
- void operator()(void *p) const;
+enum IgnoreObjectResult {
+ kIgnoreObjectSuccess,
+ kIgnoreObjectAlreadyIgnored,
+ kIgnoreObjectInvalid
};
-// Scans each leaked chunk for pointers to other leaked chunks, and marks each
-// of them as indirectly leaked.
-class MarkIndirectlyLeakedCb {
- public:
- void operator()(void *p) const;
-};
+// Functions called from the parent tool.
+void InitCommonLsan();
+void DoLeakCheck();
+bool DisabledInThisThread();
// The following must be implemented in the parent tool.
-template<typename Callable> void ForEachChunk(Callable const &callback);
-// The address range occupied by the global allocator object.
+void ForEachChunk(ForEachChunkCallback callback, void *arg);
+// Returns the address range occupied by the global allocator object.
void GetAllocatorGlobalRange(uptr *begin, uptr *end);
// Wrappers for allocator's ForceLock()/ForceUnlock().
void LockAllocator();
@@ -162,16 +135,27 @@ void UnlockThreadRegistry();
bool GetThreadRangesLocked(uptr os_id, uptr *stack_begin, uptr *stack_end,
uptr *tls_begin, uptr *tls_end,
uptr *cache_begin, uptr *cache_end);
-// If p points into a chunk that has been allocated to the user, return its
-// user-visible address. Otherwise, return 0.
-void *PointsIntoChunk(void *p);
-// Return address of user-visible chunk contained in this allocator chunk.
-void *GetUserBegin(void *p);
+void ForEachExtraStackRange(uptr os_id, RangeIteratorCallback callback,
+ void *arg);
+// If called from the main thread, updates the main thread's TID in the thread
+// registry. We need this to handle processes that fork() without a subsequent
+// exec(), which invalidates the recorded TID. To update it, we must call
+// gettid() from the main thread. Our solution is to call this function before
+// leak checking and also before every call to pthread_create() (to handle cases
+// where leak checking is initiated from a non-main thread).
+void EnsureMainThreadIDIsCorrect();
+// If p points into a chunk that has been allocated to the user, returns its
+// user-visible address. Otherwise, returns 0.
+uptr PointsIntoChunk(void *p);
+// Returns address of user-visible chunk contained in this allocator chunk.
+uptr GetUserBegin(uptr chunk);
+// Helper for __lsan_ignore_object().
+IgnoreObjectResult IgnoreObjectLocked(const void *p);
// Wrapper for chunk metadata operations.
class LsanMetadata {
public:
- // Constructor accepts pointer to user-visible chunk.
- explicit LsanMetadata(void *chunk);
+ // Constructor accepts address of user-visible chunk.
+ explicit LsanMetadata(uptr chunk);
bool allocated() const;
ChunkTag tag() const;
void set_tag(ChunkTag value);
@@ -183,4 +167,12 @@ class LsanMetadata {
} // namespace __lsan
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+int __lsan_is_turned_off();
+
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+const char *__lsan_default_suppressions();
+} // extern "C"
+
#endif // LSAN_COMMON_H
diff --git a/lib/lsan/lsan_common_linux.cc b/lib/lsan/lsan_common_linux.cc
index 10a434b5f851..ef8857fe8dbb 100644
--- a/lib/lsan/lsan_common_linux.cc
+++ b/lib/lsan/lsan_common_linux.cc
@@ -53,8 +53,7 @@ void InitializePlatformSpecificModules() {
static int ProcessGlobalRegionsCallback(struct dl_phdr_info *info, size_t size,
void *data) {
- InternalVector<uptr> *frontier =
- reinterpret_cast<InternalVector<uptr> *>(data);
+ Frontier *frontier = reinterpret_cast<Frontier *>(data);
for (uptr j = 0; j < info->dlpi_phnum; j++) {
const ElfW(Phdr) *phdr = &(info->dlpi_phdr[j]);
// We're looking for .data and .bss sections, which reside in writeable,
@@ -82,8 +81,8 @@ static int ProcessGlobalRegionsCallback(struct dl_phdr_info *info, size_t size,
return 0;
}
-// Scan global variables for heap pointers.
-void ProcessGlobalRegions(InternalVector<uptr> *frontier) {
+// Scans global variables for heap pointers.
+void ProcessGlobalRegions(Frontier *frontier) {
// 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
@@ -91,32 +90,51 @@ void ProcessGlobalRegions(InternalVector<uptr> *frontier) {
dl_iterate_phdr(ProcessGlobalRegionsCallback, frontier);
}
-static uptr GetCallerPC(u32 stack_id) {
+static uptr GetCallerPC(u32 stack_id, StackDepotReverseMap *map) {
CHECK(stack_id);
uptr size = 0;
- const uptr *trace = StackDepotGet(stack_id, &size);
+ const uptr *trace = map->Get(stack_id, &size);
// The top frame is our malloc/calloc/etc. The next frame is the caller.
- CHECK_GE(size, 2);
- return trace[1];
+ if (size >= 2)
+ return trace[1];
+ return 0;
}
-void ProcessPlatformSpecificAllocationsCb::operator()(void *p) const {
- p = GetUserBegin(p);
- LsanMetadata m(p);
+struct ProcessPlatformAllocParam {
+ Frontier *frontier;
+ StackDepotReverseMap *stack_depot_reverse_map;
+};
+
+// ForEachChunk callback. Identifies unreachable chunks which must be treated as
+// reachable. Marks them as reachable and adds them to the frontier.
+static void ProcessPlatformSpecificAllocationsCb(uptr chunk, void *arg) {
+ CHECK(arg);
+ ProcessPlatformAllocParam *param =
+ reinterpret_cast<ProcessPlatformAllocParam *>(arg);
+ chunk = GetUserBegin(chunk);
+ LsanMetadata m(chunk);
if (m.allocated() && m.tag() != kReachable) {
- if (linker->containsAddress(GetCallerPC(m.stack_trace_id()))) {
+ u32 stack_id = m.stack_trace_id();
+ uptr caller_pc = 0;
+ if (stack_id > 0)
+ caller_pc = GetCallerPC(stack_id, param->stack_depot_reverse_map);
+ // If caller_pc is unknown, this chunk may be allocated in a coroutine. Mark
+ // it as reachable, as we can't properly report its allocation stack anyway.
+ if (caller_pc == 0 || linker->containsAddress(caller_pc)) {
m.set_tag(kReachable);
- frontier_->push_back(reinterpret_cast<uptr>(p));
+ param->frontier->push_back(chunk);
}
}
}
-// Handle dynamically allocated TLS blocks by treating all chunks allocated from
-// ld-linux.so as reachable.
-void ProcessPlatformSpecificAllocations(InternalVector<uptr> *frontier) {
+// Handles dynamically allocated TLS blocks by treating all chunks allocated
+// from ld-linux.so as reachable.
+void ProcessPlatformSpecificAllocations(Frontier *frontier) {
if (!flags()->use_tls) return;
if (!linker) return;
- ForEachChunk(ProcessPlatformSpecificAllocationsCb(frontier));
+ StackDepotReverseMap stack_depot_reverse_map;
+ ProcessPlatformAllocParam arg = {frontier, &stack_depot_reverse_map};
+ ForEachChunk(ProcessPlatformSpecificAllocationsCb, &arg);
}
} // namespace __lsan
diff --git a/lib/lsan/lsan_interceptors.cc b/lib/lsan/lsan_interceptors.cc
index b2eb6e310229..400230b885ff 100644
--- a/lib/lsan/lsan_interceptors.cc
+++ b/lib/lsan/lsan_interceptors.cc
@@ -44,66 +44,85 @@ int pthread_setspecific(unsigned key, const void *v);
stack_top = t->stack_end(); \
stack_bottom = t->stack_begin(); \
} \
- GetStackTrace(&stack, __sanitizer::common_flags()->malloc_context_size, \
- StackTrace::GetCurrentPc(), \
- GET_CURRENT_FRAME(), stack_top, stack_bottom, fast); \
+ 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) \
+ __lsan_init(); \
+} while (0)
+
///// Malloc/free interceptors. /////
+const bool kAlwaysClearMemory = true;
+
namespace std {
struct nothrow_t;
}
INTERCEPTOR(void*, malloc, uptr size) {
- Init();
+ ENSURE_LSAN_INITED;
GET_STACK_TRACE;
- return Allocate(stack, size, 1, false);
+ return Allocate(stack, size, 1, kAlwaysClearMemory);
}
INTERCEPTOR(void, free, void *p) {
- Init();
+ ENSURE_LSAN_INITED;
Deallocate(p);
}
INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) {
+ if (lsan_init_is_running) {
+ // Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym.
+ const uptr kCallocPoolSize = 1024;
+ static uptr calloc_memory_for_dlsym[kCallocPoolSize];
+ static uptr allocated;
+ uptr size_in_words = ((nmemb * size) + kWordSize - 1) / kWordSize;
+ void *mem = (void*)&calloc_memory_for_dlsym[allocated];
+ allocated += size_in_words;
+ CHECK(allocated < kCallocPoolSize);
+ return mem;
+ }
if (CallocShouldReturnNullDueToOverflow(size, nmemb)) return 0;
- Init();
+ ENSURE_LSAN_INITED;
GET_STACK_TRACE;
size *= nmemb;
return Allocate(stack, size, 1, true);
}
INTERCEPTOR(void*, realloc, void *q, uptr size) {
- Init();
+ ENSURE_LSAN_INITED;
GET_STACK_TRACE;
return Reallocate(stack, q, size, 1);
}
INTERCEPTOR(void*, memalign, uptr alignment, uptr size) {
- Init();
+ ENSURE_LSAN_INITED;
GET_STACK_TRACE;
- return Allocate(stack, size, alignment, false);
+ return Allocate(stack, size, alignment, kAlwaysClearMemory);
}
INTERCEPTOR(int, posix_memalign, void **memptr, uptr alignment, uptr size) {
- Init();
+ ENSURE_LSAN_INITED;
GET_STACK_TRACE;
- *memptr = Allocate(stack, size, alignment, false);
+ *memptr = Allocate(stack, size, alignment, kAlwaysClearMemory);
// FIXME: Return ENOMEM if user requested more than max alloc size.
return 0;
}
INTERCEPTOR(void*, valloc, uptr size) {
- Init();
+ ENSURE_LSAN_INITED;
GET_STACK_TRACE;
if (size == 0)
size = GetPageSizeCached();
- return Allocate(stack, size, GetPageSizeCached(), false);
+ return Allocate(stack, size, GetPageSizeCached(), kAlwaysClearMemory);
}
INTERCEPTOR(uptr, malloc_usable_size, void *ptr) {
- Init();
+ ENSURE_LSAN_INITED;
return GetMallocUsableSize(ptr);
}
@@ -121,28 +140,52 @@ INTERCEPTOR(int, mallopt, int cmd, int value) {
return -1;
}
-void *operator new(uptr size) ALIAS("malloc") SANITIZER_INTERFACE_ATTRIBUTE;
-void *operator new[](uptr size) ALIAS("malloc") SANITIZER_INTERFACE_ATTRIBUTE;
-void *operator new(uptr size, std::nothrow_t const&) ALIAS("malloc")
- SANITIZER_INTERFACE_ATTRIBUTE;
-void *operator new[](uptr size, std::nothrow_t const&) ALIAS("malloc")
- SANITIZER_INTERFACE_ATTRIBUTE;
-void operator delete(void *ptr) ALIAS("free") SANITIZER_INTERFACE_ATTRIBUTE;
-void operator delete[](void *ptr) ALIAS("free") SANITIZER_INTERFACE_ATTRIBUTE;
-void operator delete(void *ptr, std::nothrow_t const&) ALIAS("free")
- SANITIZER_INTERFACE_ATTRIBUTE;
-void operator delete[](void *ptr, std::nothrow_t const&) ALIAS("free")
- SANITIZER_INTERFACE_ATTRIBUTE;
+INTERCEPTOR(void*, pvalloc, uptr size) {
+ ENSURE_LSAN_INITED;
+ GET_STACK_TRACE;
+ uptr PageSize = GetPageSizeCached();
+ size = RoundUpTo(size, PageSize);
+ if (size == 0) {
+ // pvalloc(0) should allocate one page.
+ size = PageSize;
+ }
+ return Allocate(stack, size, GetPageSizeCached(), kAlwaysClearMemory);
+}
+
+INTERCEPTOR(void, cfree, void *p) ALIAS("free");
+
+#define OPERATOR_NEW_BODY \
+ ENSURE_LSAN_INITED; \
+ GET_STACK_TRACE; \
+ return Allocate(stack, size, 1, kAlwaysClearMemory);
+
+INTERCEPTOR_ATTRIBUTE
+void *operator new(uptr size) { OPERATOR_NEW_BODY; }
+INTERCEPTOR_ATTRIBUTE
+void *operator new[](uptr size) { OPERATOR_NEW_BODY; }
+INTERCEPTOR_ATTRIBUTE
+void *operator new(uptr size, std::nothrow_t const&) { OPERATOR_NEW_BODY; }
+INTERCEPTOR_ATTRIBUTE
+void *operator new[](uptr size, std::nothrow_t const&) { OPERATOR_NEW_BODY; }
+
+#define OPERATOR_DELETE_BODY \
+ ENSURE_LSAN_INITED; \
+ Deallocate(ptr);
+
+INTERCEPTOR_ATTRIBUTE
+void operator delete(void *ptr) { OPERATOR_DELETE_BODY; }
+INTERCEPTOR_ATTRIBUTE
+void operator delete[](void *ptr) { 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;
+}
-extern "C" {
-void cfree(void *p) ALIAS("free") SANITIZER_INTERFACE_ATTRIBUTE;
-void *pvalloc(uptr size) ALIAS("valloc")
- SANITIZER_INTERFACE_ATTRIBUTE;
// We need this to intercept the __libc_memalign calls that are used to
// allocate dynamic TLS space in ld-linux.so.
-void *__libc_memalign(uptr alignment, uptr size)
- ALIAS("memalign") SANITIZER_INTERFACE_ATTRIBUTE;
-}
+INTERCEPTOR(void *, __libc_memalign, uptr align, uptr s) ALIAS("memalign");
///// Thread initialization and finalization. /////
@@ -166,9 +209,6 @@ struct ThreadParam {
atomic_uintptr_t tid;
};
-// PTHREAD_DESTRUCTOR_ITERATIONS from glibc.
-const uptr kPthreadDestructorIterations = 4;
-
extern "C" void *__lsan_thread_start_func(void *arg) {
ThreadParam *p = (ThreadParam*)arg;
void* (*callback)(void *arg) = p->callback;
@@ -191,13 +231,14 @@ extern "C" void *__lsan_thread_start_func(void *arg) {
INTERCEPTOR(int, pthread_create, void *th, void *attr,
void *(*callback)(void *), void *param) {
- Init();
+ ENSURE_LSAN_INITED;
+ EnsureMainThreadIDIsCorrect();
__sanitizer_pthread_attr_t myattr;
if (attr == 0) {
pthread_attr_init(&myattr);
attr = &myattr;
}
- AdjustStackSizeLinux(attr, 0);
+ AdjustStackSizeLinux(attr);
int detached = 0;
pthread_attr_getdetachstate(attr, &detached);
ThreadParam p;
@@ -218,7 +259,7 @@ INTERCEPTOR(int, pthread_create, void *th, void *attr,
}
INTERCEPTOR(int, pthread_join, void *th, void **ret) {
- Init();
+ ENSURE_LSAN_INITED;
int tid = ThreadTid((uptr)th);
int res = REAL(pthread_join)(th, ret);
if (res == 0)
@@ -231,12 +272,14 @@ namespace __lsan {
void InitializeInterceptors() {
INTERCEPT_FUNCTION(malloc);
INTERCEPT_FUNCTION(free);
+ INTERCEPT_FUNCTION(cfree);
INTERCEPT_FUNCTION(calloc);
INTERCEPT_FUNCTION(realloc);
INTERCEPT_FUNCTION(memalign);
INTERCEPT_FUNCTION(posix_memalign);
- INTERCEPT_FUNCTION(memalign);
+ INTERCEPT_FUNCTION(__libc_memalign);
INTERCEPT_FUNCTION(valloc);
+ INTERCEPT_FUNCTION(pvalloc);
INTERCEPT_FUNCTION(malloc_usable_size);
INTERCEPT_FUNCTION(mallinfo);
INTERCEPT_FUNCTION(mallopt);
diff --git a/lib/lsan/lsan_preinit.cc b/lib/lsan/lsan_preinit.cc
new file mode 100644
index 000000000000..e6639516dc81
--- /dev/null
+++ b/lib/lsan/lsan_preinit.cc
@@ -0,0 +1,26 @@
+//===-- lsan_preinit.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.
+//
+// Call __lsan_init at the very early stage of process startup.
+//===----------------------------------------------------------------------===//
+
+#include "lsan.h"
+
+#ifndef LSAN_USE_PREINIT_ARRAY
+#define LSAN_USE_PREINIT_ARRAY 1
+#endif
+
+#if LSAN_USE_PREINIT_ARRAY && !defined(PIC)
+ // We force __lsan_init to be called before anyone else by placing it into
+ // .preinit_array section.
+ __attribute__((section(".preinit_array"), used))
+ void (*__local_lsan_preinit)(void) = __lsan_init;
+#endif
diff --git a/lib/lsan/lsan_thread.cc b/lib/lsan/lsan_thread.cc
index 3e28dee1325a..0f8efc093b56 100644
--- a/lib/lsan/lsan_thread.cc
+++ b/lib/lsan/lsan_thread.cc
@@ -123,6 +123,11 @@ void ThreadJoin(u32 tid) {
thread_registry->JoinThread(tid, /* arg */0);
}
+void EnsureMainThreadIDIsCorrect() {
+ if (GetCurrentThread() == 0)
+ CurrentThreadContext()->os_id = GetTid();
+}
+
///// Interface to the common LSan module. /////
bool GetThreadRangesLocked(uptr os_id, uptr *stack_begin, uptr *stack_end,
@@ -140,6 +145,10 @@ bool GetThreadRangesLocked(uptr os_id, uptr *stack_begin, uptr *stack_end,
return true;
}
+void ForEachExtraStackRange(uptr os_id, RangeIteratorCallback callback,
+ void *arg) {
+}
+
void LockThreadRegistry() {
thread_registry->Lock();
}
diff --git a/lib/lsan/lsan_thread.h b/lib/lsan/lsan_thread.h
index b62f04b8eb74..4641b32ed6e6 100644
--- a/lib/lsan/lsan_thread.h
+++ b/lib/lsan/lsan_thread.h
@@ -47,7 +47,7 @@ u32 ThreadTid(uptr uid);
u32 GetCurrentThread();
void SetCurrentThread(u32 tid);
ThreadContext *CurrentThreadContext();
-
+void EnsureMainThreadIDIsCorrect();
} // namespace __lsan
#endif // LSAN_THREAD_H
diff --git a/lib/lsan/tests/CMakeLists.txt b/lib/lsan/tests/CMakeLists.txt
index 3d97ae96f650..2221e0650237 100644
--- a/lib/lsan/tests/CMakeLists.txt
+++ b/lib/lsan/tests/CMakeLists.txt
@@ -9,13 +9,17 @@ set(LSAN_TESTS_SRC
lsan_dummy_unittest.cc)
set(LSAN_TESTS_CFLAGS
- ${LSAN_CFLAGS}
+ ${SANITIZER_COMMON_CFLAGS}
${COMPILER_RT_GTEST_INCLUDE_CFLAGS}
- -I${COMPILER_RT_SOURCE_DIR}/lib)
+ -I${COMPILER_RT_SOURCE_DIR}/lib
+ -I${LSAN_SRC_DIR})
-add_custom_target(LsanTests)
-set_target_properties(LsanTests PROPERTIES
- FOLDER "LSan unittests")
+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.
@@ -25,24 +29,27 @@ macro(lsan_compile obj_list source arch)
get_target_flags_for_arch(${arch} TARGET_CFLAGS)
clang_compile(${output_obj} ${source}
CFLAGS ${ARGN} ${TARGET_CFLAGS}
- DEPS gtest)
+ DEPS gtest ${LSAN_RUNTIME_LIBRARIES})
list(APPEND ${obj_list} ${output_obj})
endmacro()
-function(add_lsan_test testname arch)
- set(testname_arch ${testname}-${arch}-Test)
- get_target_flags_for_arch(${arch} TARGET_LINKFLAGS)
- add_unittest(LsanTests ${testname_arch} ${ARGN})
- target_link_libraries(${testname_arch} "clang_rt.lsan-${arch}")
- set_target_compile_flags(${testname_arch} ${LSAN_TESTS_CFLAGS})
- set_target_link_flags(${testname_arch} ${TARGET_LINKFLAGS})
+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)
- lsan_compile(LSAN_TESTS_OBJ ${LSAN_TESTS_SRC} ${arch} ${LSAN_TESTS_CFLAGS}
- -I${LSAN_SRC_DIR})
- add_lsan_test(Lsan ${arch} ${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.
diff --git a/lib/lsan/tests/lsan_dummy_unittest.cc b/lib/lsan/tests/lsan_dummy_unittest.cc
index e69de29bb2d1..5468400775a0 100644
--- a/lib/lsan/tests/lsan_dummy_unittest.cc
+++ b/lib/lsan/tests/lsan_dummy_unittest.cc
@@ -0,0 +1,22 @@
+//===-- 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
index 363cc14f1941..8db6cf1e2f8c 100644
--- a/lib/lsan/tests/lsan_testlib.cc
+++ b/lib/lsan/tests/lsan_testlib.cc
@@ -14,12 +14,12 @@
/* Usage:
clang++ ../sanitizer_common/sanitizer_*.cc ../interception/interception_*.cc \
lsan*.cc tests/lsan_testlib.cc -I. -I.. -g -ldl -lpthread -fPIC -shared -O2 \
- -o lsan.so
+ -DLSAN_USE_PREINIT_ARRAY=0 -o lsan.so
LD_PRELOAD=./lsan.so /your/app
*/
#include "lsan.h"
__attribute__((constructor))
void constructor() {
- __lsan::Init();
+ __lsan_init();
}
diff --git a/lib/msan/CMakeLists.txt b/lib/msan/CMakeLists.txt
index 0671b59c0025..06f3f65d8e38 100644
--- a/lib/msan/CMakeLists.txt
+++ b/lib/msan/CMakeLists.txt
@@ -25,13 +25,24 @@ if(CAN_TARGET_${arch})
$<TARGET_OBJECTS:RTInterception.${arch}>
$<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
$<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>
- CFLAGS ${MSAN_RTL_CFLAGS}
- SYMS msan.syms)
+ CFLAGS ${MSAN_RTL_CFLAGS})
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)
+ endif()
endif()
add_compiler_rt_resource_file(msan_blacklist msan_blacklist.txt)
+# 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)
add_subdirectory(tests)
endif()
diff --git a/lib/msan/lit_tests/CMakeLists.txt b/lib/msan/lit_tests/CMakeLists.txt
index ed2da6b839f5..38d1e59e709e 100644
--- a/lib/msan/lit_tests/CMakeLists.txt
+++ b/lib/msan/lit_tests/CMakeLists.txt
@@ -3,24 +3,23 @@ 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
- )
+ ${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(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)
+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)
+ 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"
diff --git a/lib/msan/lit_tests/Linux/glob.cc b/lib/msan/lit_tests/Linux/glob.cc
index 513679c6d3d7..387ce3cf5f1a 100644
--- a/lib/msan/lit_tests/Linux/glob.cc
+++ b/lib/msan/lit_tests/Linux/glob.cc
@@ -1,4 +1,5 @@
// 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>
diff --git a/lib/msan/lit_tests/Linux/glob_altdirfunc.cc b/lib/msan/lit_tests/Linux/glob_altdirfunc.cc
new file mode 100644
index 000000000000..b8200c3ee899
--- /dev/null
+++ b/lib/msan/lit_tests/Linux/glob_altdirfunc.cc
@@ -0,0 +1,78 @@
+// 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
new file mode 100644
index 000000000000..0262034aec5b
--- /dev/null
+++ b/lib/msan/lit_tests/Linux/glob_nomatch.cc
@@ -0,0 +1,21 @@
+// 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/syscalls.cc b/lib/msan/lit_tests/Linux/syscalls.cc
index c12eda39189e..ec308bfe30ca 100644
--- a/lib/msan/lit_tests/Linux/syscalls.cc
+++ b/lib/msan/lit_tests/Linux/syscalls.cc
@@ -7,6 +7,10 @@
#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>
@@ -16,6 +20,7 @@
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);
@@ -46,5 +51,50 @@ int main(int argc, char *argv[]) {
__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
new file mode 100644
index 000000000000..e6e101db884f
--- /dev/null
+++ b/lib/msan/lit_tests/Linux/tcgetattr.cc
@@ -0,0 +1,21 @@
+// 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
new file mode 100644
index 000000000000..8930a7159246
--- /dev/null
+++ b/lib/msan/lit_tests/SharedLibs/dso-origin-so.cc
@@ -0,0 +1,14 @@
+#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
new file mode 100644
index 000000000000..ff926b3f61c8
--- /dev/null
+++ b/lib/msan/lit_tests/SharedLibs/dso-origin.h
@@ -0,0 +1,4 @@
+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
new file mode 100644
index 000000000000..b3677c17a0f2
--- /dev/null
+++ b/lib/msan/lit_tests/SharedLibs/lit.local.cfg
@@ -0,0 +1,4 @@
+# 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.cfg b/lib/msan/lit_tests/Unit/lit.cfg
deleted file mode 100644
index ee379d0deaed..000000000000
--- a/lib/msan/lit_tests/Unit/lit.cfg
+++ /dev/null
@@ -1,26 +0,0 @@
-# -*- Python -*-
-
-import os
-
-def get_required_attr(config, attr_name):
- attr_value = getattr(config, attr_name, None)
- if not attr_value:
- lit.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 attributes common for all compiler-rt projects.
-compiler_rt_src_root = get_required_attr(config, 'compiler_rt_src_root')
-compiler_rt_lit_unit_cfg = os.path.join(compiler_rt_src_root, "lib",
- "lit.common.unit.cfg")
-lit.load_config(config, compiler_rt_lit_unit_cfg)
-
-# 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.
-msan_binary_dir = get_required_attr(config, "msan_binary_dir")
-config.test_exec_root = os.path.join(msan_binary_dir, "tests")
-config.test_source_root = config.test_exec_root
diff --git a/lib/msan/lit_tests/Unit/lit.site.cfg.in b/lib/msan/lit_tests/Unit/lit.site.cfg.in
index a91f6713303a..8e67f557d7fd 100644
--- a/lib/msan/lit_tests/Unit/lit.site.cfg.in
+++ b/lib/msan/lit_tests/Unit/lit.site.cfg.in
@@ -1,17 +1,13 @@
## Autogenerated by LLVM/Clang configuration.
# Do not edit!
-config.target_triple = "@TARGET_TRIPLE@"
-config.llvm_src_root = "@LLVM_SOURCE_DIR@"
-config.compiler_rt_src_root = "@COMPILER_RT_SOURCE_DIR@"
-config.llvm_build_mode = "@LLVM_BUILD_MODE@"
-config.msan_binary_dir = "@MSAN_BINARY_DIR@"
+# Load common config for all compiler-rt unit tests.
+lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/lib/lit.common.unit.configured")
-try:
- config.llvm_build_mode = config.llvm_build_mode % lit.params
-except KeyError,e:
- key, = e.args
- lit.fatal("unable to find %r parameter, use '--param=%s=VALUE'" % (key, key))
+# Setup config name.
+config.name = 'MemorySanitizer-Unit'
-# Let the main config do the real work.
-lit.load_config(config, "@MSAN_SOURCE_DIR@/lit_tests/Unit/lit.cfg")
+# 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
new file mode 100644
index 000000000000..aaa85cce7113
--- /dev/null
+++ b/lib/msan/lit_tests/allocator_returns_null.cc
@@ -0,0 +1,81 @@
+// 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
new file mode 100644
index 000000000000..48684c29c60d
--- /dev/null
+++ b/lib/msan/lit_tests/backtrace.cc
@@ -0,0 +1,26 @@
+// 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/cxa_atexit.cc b/lib/msan/lit_tests/cxa_atexit.cc
new file mode 100644
index 000000000000..f3641aadce03
--- /dev/null
+++ b/lib/msan/lit_tests/cxa_atexit.cc
@@ -0,0 +1,28 @@
+// 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/dlerror.cc b/lib/msan/lit_tests/dlerror.cc
new file mode 100644
index 000000000000..281b3164fd7e
--- /dev/null
+++ b/lib/msan/lit_tests/dlerror.cc
@@ -0,0 +1,14 @@
+// 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
new file mode 100644
index 000000000000..13661c65e744
--- /dev/null
+++ b/lib/msan/lit_tests/dso-origin.cc
@@ -0,0 +1,25 @@
+// 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
new file mode 100644
index 000000000000..af27ad0b0329
--- /dev/null
+++ b/lib/msan/lit_tests/errno.cc
@@ -0,0 +1,17 @@
+// 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
index f16679cc2aa2..7fde1fdfab93 100644
--- a/lib/msan/lit_tests/getaddrinfo-positive.cc
+++ b/lib/msan/lit_tests/getaddrinfo-positive.cc
@@ -8,12 +8,16 @@
#include <netdb.h>
#include <stdlib.h>
+volatile int z;
+
int main(void) {
struct addrinfo *ai;
struct addrinfo hint;
- int res = getaddrinfo("localhost", NULL, &hint, &ai);
+ 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: Use of uninitialized value
+ // 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/getline.cc b/lib/msan/lit_tests/getline.cc
new file mode 100644
index 000000000000..27168a885606
--- /dev/null
+++ b/lib/msan/lit_tests/getline.cc
@@ -0,0 +1,30 @@
+// 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
new file mode 100644
index 000000000000..5ba1d4cec0dd
--- /dev/null
+++ b/lib/msan/lit_tests/getline_test_data
@@ -0,0 +1,2 @@
+abcde
+12345
diff --git a/lib/msan/lit_tests/heap-origin.cc b/lib/msan/lit_tests/heap-origin.cc
index 54e2c31438ff..dfe7edd27e82 100644
--- a/lib/msan/lit_tests/heap-origin.cc
+++ b/lib/msan/lit_tests/heap-origin.cc
@@ -19,15 +19,13 @@
#include <stdlib.h>
int main(int argc, char **argv) {
char *volatile x = (char*)malloc(5 * sizeof(char));
- if (*x)
- exit(0);
- // CHECK: WARNING: Use of uninitialized value
- // CHECK: {{#0 0x.* in main .*heap-origin.cc:}}[[@LINE-3]]
+ 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-8]]
+ // CHECK-ORIGINS: {{#1 0x.* in main .*heap-origin.cc:}}[[@LINE-7]]
// CHECK: SUMMARY: MemorySanitizer: use-of-uninitialized-value {{.*heap-origin.cc:.* main}}
- return 0;
}
diff --git a/lib/msan/lit_tests/initgroups.cc b/lib/msan/lit_tests/initgroups.cc
new file mode 100644
index 000000000000..adba5369579a
--- /dev/null
+++ b/lib/msan/lit_tests/initgroups.cc
@@ -0,0 +1,11 @@
+// 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
new file mode 100644
index 000000000000..4aeb15583f84
--- /dev/null
+++ b/lib/msan/lit_tests/inline.cc
@@ -0,0 +1,20 @@
+// 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
new file mode 100644
index 000000000000..769ea45f8c4d
--- /dev/null
+++ b/lib/msan/lit_tests/insertvalue_origin.cc
@@ -0,0 +1,35 @@
+// 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
new file mode 100644
index 000000000000..caff80c2e5d7
--- /dev/null
+++ b/lib/msan/lit_tests/ioctl.cc
@@ -0,0 +1,20 @@
+// 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
new file mode 100644
index 000000000000..94ed528c70b9
--- /dev/null
+++ b/lib/msan/lit_tests/ioctl_custom.cc
@@ -0,0 +1,33 @@
+// 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
new file mode 100644
index 000000000000..6d006756a110
--- /dev/null
+++ b/lib/msan/lit_tests/keep-going-dso.cc
@@ -0,0 +1,33 @@
+// 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
new file mode 100644
index 000000000000..e33b137c76f7
--- /dev/null
+++ b/lib/msan/lit_tests/keep-going.cc
@@ -0,0 +1,34 @@
+// 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
index 42381885fe8e..da1bde6dd04a 100644
--- a/lib/msan/lit_tests/lit.cfg
+++ b/lib/msan/lit_tests/lit.cfg
@@ -2,12 +2,15 @@
import os
+import lit.util
+
def get_required_attr(config, attr_name):
attr_value = getattr(config, attr_name, None)
if not attr_value:
- lit.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)
+ 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.
@@ -17,9 +20,9 @@ config.name = 'MemorySanitizer'
config.test_source_root = os.path.dirname(__file__)
def DisplayNoConfigMessage():
- lit.fatal("No site specific configuration available! " +
- "Try running your test from the build tree or running " +
- "make check-msan")
+ 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)
@@ -27,9 +30,9 @@ 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.params.get('msan_site_config', None)
+ msan_site_cfg = lit_config.params.get('msan_site_config', None)
if (msan_site_cfg) and (os.path.exists(msan_site_cfg)):
- lit.load_config(config, 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
@@ -45,25 +48,17 @@ if llvm_src_root is None:
if (not msan_site_cfg) or (not os.path.exists(msan_site_cfg)):
DisplayNoConfigMessage()
- lit.load_config(config, msan_site_cfg)
+ lit_config.load_config(config, msan_site_cfg)
raise SystemExit
-# Setup attributes common for all compiler-rt projects.
-compiler_rt_src_root = get_required_attr(config, "compiler_rt_src_root")
-compiler_rt_lit_cfg = os.path.join(compiler_rt_src_root, "lib",
- "lit.common.cfg")
-if (not compiler_rt_lit_cfg) or (not os.path.exists(compiler_rt_lit_cfg)):
- lit.fatal("Can't find common compiler-rt lit config at: %r"
- % compiler_rt_lit_cfg)
-lit.load_config(config, compiler_rt_lit_cfg)
-
# 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"]
-clang_msan_cxxflags = ["-ccc-cxx "] + clang_msan_cflags
+ "-g",
+ "-m64"]
+clang_msan_cxxflags = ["--driver-mode=g++ "] + clang_msan_cflags
config.substitutions.append( ("%clang_msan ",
" ".join([config.clang] + clang_msan_cflags) +
" ") )
@@ -71,12 +66,6 @@ config.substitutions.append( ("%clangxx_msan ",
" ".join([config.clang] + clang_msan_cxxflags) +
" ") )
-# Setup path to external LLVM symbolizer to run MemorySanitizer output tests.
-llvm_tools_dir = getattr(config, 'llvm_tools_dir', None)
-if llvm_tools_dir:
- llvm_symbolizer_path = os.path.join(llvm_tools_dir, "llvm-symbolizer")
- config.environment['MSAN_SYMBOLIZER_PATH'] = llvm_symbolizer_path
-
# Default test suffixes.
config.suffixes = ['.c', '.cc', '.cpp']
diff --git a/lib/msan/lit_tests/lit.site.cfg.in b/lib/msan/lit_tests/lit.site.cfg.in
index 3b969e0b0614..946df778f3d3 100644
--- a/lib/msan/lit_tests/lit.site.cfg.in
+++ b/lib/msan/lit_tests/lit.site.cfg.in
@@ -1,18 +1,5 @@
-config.target_triple = "@TARGET_TRIPLE@"
-config.host_os = "@HOST_OS@"
-config.llvm_src_root = "@LLVM_SOURCE_DIR@"
-config.compiler_rt_src_root = "@COMPILER_RT_SOURCE_DIR@"
-config.llvm_obj_root = "@LLVM_BINARY_DIR@"
-config.llvm_tools_dir = "@LLVM_TOOLS_DIR@"
-config.clang = "@LLVM_BINARY_DIR@/bin/clang"
+# Load common config for all compiler-rt lit tests.
+lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/lib/lit.common.configured")
-# LLVM tools dir can be passed in lit parameters, so try to
-# apply substitution.
-try:
- config.llvm_tools_dir = config.llvm_tools_dir % lit.params
-except KeyError,e:
- key, = e.args
- lit.fatal("unable to find %r parameter, use '--param=%s=VALUE'" % (key, key))
-
-# Let the main config do the real work.
-lit.load_config(config, "@MSAN_SOURCE_DIR@/lit_tests/lit.cfg")
+# 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
new file mode 100644
index 000000000000..fc68fbc35fbb
--- /dev/null
+++ b/lib/msan/lit_tests/malloc_hook.cc
@@ -0,0 +1,36 @@
+// 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_prop.cc b/lib/msan/lit_tests/no_sanitize_memory_prop.cc
index c74ca6b89db9..355152478852 100644
--- a/lib/msan/lit_tests/no_sanitize_memory_prop.cc
+++ b/lib/msan/lit_tests/no_sanitize_memory_prop.cc
@@ -25,7 +25,7 @@ int main(void) {
int x;
int * volatile p = &x;
int y = f(*p);
- // CHECK: WARNING: Use of uninitialized value
+ // CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value
// CHECK: {{#0 0x.* in main .*no_sanitize_memory_prop.cc:}}[[@LINE+1]]
if (y)
exit(0);
diff --git a/lib/msan/lit_tests/poison_in_free.cc b/lib/msan/lit_tests/poison_in_free.cc
new file mode 100644
index 000000000000..f134d05abb1e
--- /dev/null
+++ b/lib/msan/lit_tests/poison_in_free.cc
@@ -0,0 +1,16 @@
+// 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
new file mode 100644
index 000000000000..d0e83eabd6a4
--- /dev/null
+++ b/lib/msan/lit_tests/ptrace.cc
@@ -0,0 +1,36 @@
+// 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/scandir.cc b/lib/msan/lit_tests/scandir.cc
new file mode 100644
index 000000000000..94672e1adbee
--- /dev/null
+++ b/lib/msan/lit_tests/scandir.cc
@@ -0,0 +1,56 @@
+// 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
new file mode 100644
index 000000000000..84af7f418d21
--- /dev/null
+++ b/lib/msan/lit_tests/scandir_null.cc
@@ -0,0 +1,34 @@
+// 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
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/lib/msan/lit_tests/scandir_test_root/aaa
diff --git a/lib/msan/lit_tests/scandir_test_root/aab b/lib/msan/lit_tests/scandir_test_root/aab
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/lib/msan/lit_tests/scandir_test_root/aab
diff --git a/lib/msan/lit_tests/scandir_test_root/bbb b/lib/msan/lit_tests/scandir_test_root/bbb
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/lib/msan/lit_tests/scandir_test_root/bbb
diff --git a/lib/msan/lit_tests/select.cc b/lib/msan/lit_tests/select.cc
new file mode 100644
index 000000000000..a169a2dd9118
--- /dev/null
+++ b/lib/msan/lit_tests/select.cc
@@ -0,0 +1,22 @@
+// 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
new file mode 100644
index 000000000000..a22b744d74db
--- /dev/null
+++ b/lib/msan/lit_tests/setlocale.cc
@@ -0,0 +1,13 @@
+// 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
new file mode 100644
index 000000000000..ea75eae1bdaa
--- /dev/null
+++ b/lib/msan/lit_tests/signal_stress_test.cc
@@ -0,0 +1,71 @@
+// 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
new file mode 100644
index 000000000000..29aa86c938f2
--- /dev/null
+++ b/lib/msan/lit_tests/sigwait.cc
@@ -0,0 +1,30 @@
+// 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
new file mode 100644
index 000000000000..d4f004598a62
--- /dev/null
+++ b/lib/msan/lit_tests/sigwaitinfo.cc
@@ -0,0 +1,31 @@
+// 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
index 90f527309224..b0b05d9658bf 100644
--- a/lib/msan/lit_tests/stack-origin.cc
+++ b/lib/msan/lit_tests/stack-origin.cc
@@ -20,13 +20,12 @@
int main(int argc, char **argv) {
int x;
int *volatile p = &x;
- if (*p)
- exit(0);
- // CHECK: WARNING: Use of uninitialized value
- // CHECK: {{#0 0x.* in main .*stack-origin.cc:}}[[@LINE-3]]
+ 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}}
- return 0;
}
diff --git a/lib/msan/lit_tests/sync_lock_set_and_test.cc b/lib/msan/lit_tests/sync_lock_set_and_test.cc
new file mode 100644
index 000000000000..1023b3e54368
--- /dev/null
+++ b/lib/msan/lit_tests/sync_lock_set_and_test.cc
@@ -0,0 +1,7 @@
+// 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
new file mode 100644
index 000000000000..7e1c2cfad566
--- /dev/null
+++ b/lib/msan/lit_tests/tzset.cc
@@ -0,0 +1,16 @@
+// 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
new file mode 100644
index 000000000000..fa29ab69de1b
--- /dev/null
+++ b/lib/msan/lit_tests/unaligned_read_origin.cc
@@ -0,0 +1,16 @@
+// 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
new file mode 100644
index 000000000000..ac47c0233a10
--- /dev/null
+++ b/lib/msan/lit_tests/use-after-free.cc
@@ -0,0 +1,34 @@
+// 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
new file mode 100644
index 000000000000..c200c77de96a
--- /dev/null
+++ b/lib/msan/lit_tests/vector_cvt.cc
@@ -0,0 +1,23 @@
+// 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
new file mode 100644
index 000000000000..e8d55423293c
--- /dev/null
+++ b/lib/msan/lit_tests/vector_select.cc
@@ -0,0 +1,13 @@
+// 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
new file mode 100644
index 000000000000..b4bac1ecbd22
--- /dev/null
+++ b/lib/msan/lit_tests/wrap_indirect_calls.cc
@@ -0,0 +1,64 @@
+// 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
new file mode 100644
index 000000000000..a0af8b7bb0c5
--- /dev/null
+++ b/lib/msan/lit_tests/wrap_indirect_calls/caller.cc
@@ -0,0 +1,51 @@
+// 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
new file mode 100644
index 000000000000..5e01230c0986
--- /dev/null
+++ b/lib/msan/lit_tests/wrap_indirect_calls/lit.local.cfg
@@ -0,0 +1,3 @@
+# 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
new file mode 100644
index 000000000000..ab7bf4125c0a
--- /dev/null
+++ b/lib/msan/lit_tests/wrap_indirect_calls/one.cc
@@ -0,0 +1,3 @@
+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
new file mode 100644
index 000000000000..c939a993bc9a
--- /dev/null
+++ b/lib/msan/lit_tests/wrap_indirect_calls/two.cc
@@ -0,0 +1,11 @@
+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
new file mode 100644
index 000000000000..8fcd0c635d96
--- /dev/null
+++ b/lib/msan/lit_tests/wrap_indirect_calls/wrapper.cc
@@ -0,0 +1,11 @@
+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 aa79b31be2e0..83b11e5c2ff3 100644
--- a/lib/msan/msan.cc
+++ b/lib/msan/msan.cc
@@ -58,14 +58,17 @@ static THREADLOCAL struct {
uptr stack_top, stack_bottom;
} __msan_stack_bounds;
-static THREADLOCAL bool is_in_symbolizer;
-static THREADLOCAL bool is_in_loader;
+static THREADLOCAL int is_in_symbolizer;
+static THREADLOCAL int is_in_loader;
+
+extern "C" SANITIZER_WEAK_ATTRIBUTE const int __msan_track_origins;
-extern "C" const int __msan_track_origins;
int __msan_get_track_origins() {
- return __msan_track_origins;
+ return &__msan_track_origins ? __msan_track_origins : 0;
}
+extern "C" SANITIZER_WEAK_ATTRIBUTE const int __msan_keep_going;
+
namespace __msan {
static bool IsRunningUnderDr() {
@@ -84,12 +87,12 @@ static bool IsRunningUnderDr() {
return result;
}
-void EnterSymbolizer() { is_in_symbolizer = true; }
-void ExitSymbolizer() { is_in_symbolizer = false; }
+void EnterSymbolizer() { ++is_in_symbolizer; }
+void ExitSymbolizer() { --is_in_symbolizer; }
bool IsInSymbolizer() { return is_in_symbolizer; }
-void EnterLoader() { is_in_loader = true; }
-void ExitLoader() { is_in_loader = false; }
+void EnterLoader() { ++is_in_loader; }
+void ExitLoader() { --is_in_loader; }
extern "C" {
SANITIZER_INTERFACE_ATTRIBUTE
@@ -111,6 +114,7 @@ int msan_report_count = 0;
// FIXME: make it resizable.
static const uptr kNumStackOriginDescrs = 1024 * 1024;
static const char *StackOriginDescr[kNumStackOriginDescrs];
+static uptr StackOriginPC[kNumStackOriginDescrs];
static atomic_uint32_t NumStackOriginDescrs;
static void ParseFlagsFromString(Flags *f, const char *str) {
@@ -118,33 +122,39 @@ static void ParseFlagsFromString(Flags *f, const char *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);
- f->exit_code = 1;
Die();
}
ParseFlag(str, &f->report_umrs, "report_umrs");
- ParseFlag(str, &f->verbosity, "verbosity");
ParseFlag(str, &f->wrap_signals, "wrap_signals");
+
+ // 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");
+ f->halt_on_error = !f->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();
cf->external_symbolizer_path = GetEnv("MSAN_SYMBOLIZER_PATH");
- cf->strip_path_prefix = "";
- cf->fast_unwind_on_fatal = false;
- cf->fast_unwind_on_malloc = true;
cf->malloc_context_size = 20;
+ cf->handle_ioctl = true;
internal_memset(f, 0, sizeof(*f));
f->poison_heap_with_zeroes = false;
f->poison_stack_with_zeroes = false;
f->poison_in_malloc = true;
+ f->poison_in_free = true;
f->exit_code = 77;
f->report_umrs = true;
- f->verbosity = 0;
f->wrap_signals = true;
+ f->halt_on_error = !&__msan_keep_going;
// Override from user-specified string.
if (__msan_default_options)
@@ -166,19 +176,15 @@ static void GetCurrentStackBounds(uptr *stack_top, uptr *stack_bottom) {
}
void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp,
- bool fast) {
- if (!fast) {
+ bool request_fast_unwind) {
+ if (!StackTrace::WillUseFastUnwind(request_fast_unwind)) {
// Block reports from our interceptors during _Unwind_Backtrace.
SymbolizerScope sym_scope;
- return stack->SlowUnwindStack(pc, max_s);
+ return stack->Unwind(max_s, pc, bp, 0, 0, request_fast_unwind);
}
-
uptr stack_top, stack_bottom;
GetCurrentStackBounds(&stack_top, &stack_bottom);
- stack->size = 0;
- stack->trace[0] = pc;
- stack->max_size = max_s;
- stack->FastUnwindStack(pc, bp, stack_top, stack_bottom);
+ stack->Unwind(max_s, pc, bp, stack_top, stack_bottom, request_fast_unwind);
}
void PrintWarning(uptr pc, uptr bp) {
@@ -204,16 +210,55 @@ void PrintWarningWithOrigin(uptr pc, uptr bp, u32 origin) {
common_flags()->fast_unwind_on_fatal);
u32 report_origin =
- (__msan_track_origins && OriginIsValid(origin)) ? origin : 0;
+ (__msan_get_track_origins() && OriginIsValid(origin)) ? origin : 0;
ReportUMR(&stack, report_origin);
- if (__msan_track_origins && !OriginIsValid(origin)) {
- Printf(" ORIGIN: invalid (%x). Might be a bug in MemorySanitizer, "
- "please report to MemorySanitizer developers.\n",
- origin);
+ if (__msan_get_track_origins() && !OriginIsValid(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",
+ origin);
+ }
+}
+
+void UnpoisonParam(uptr n) {
+ internal_memset(__msan_param_tls, 0, n * sizeof(*__msan_param_tls));
+}
+
+// Backup MSan runtime TLS state.
+// Implementation must be async-signal-safe.
+// Instances of this class may live on the signal handler stack, and data size
+// may be an issue.
+void ScopedThreadLocalStateBackup::Backup() {
+ va_arg_overflow_size_tls = __msan_va_arg_overflow_size_tls;
+}
+
+void ScopedThreadLocalStateBackup::Restore() {
+ // A lame implementation that only keeps essential state and resets the rest.
+ __msan_va_arg_overflow_size_tls = va_arg_overflow_size_tls;
+
+ internal_memset(__msan_param_tls, 0, sizeof(__msan_param_tls));
+ internal_memset(__msan_retval_tls, 0, sizeof(__msan_retval_tls));
+ internal_memset(__msan_va_arg_tls, 0, sizeof(__msan_va_arg_tls));
+
+ if (__msan_get_track_origins()) {
+ internal_memset(&__msan_retval_origin_tls, 0, sizeof(__msan_retval_tls));
+ internal_memset(__msan_param_origin_tls, 0,
+ sizeof(__msan_param_origin_tls));
}
}
+void UnpoisonThreadLocalState() {
+}
+
+const char *GetOriginDescrIfStack(u32 id, uptr *pc) {
+ if ((id >> 31) == 0) return 0;
+ id &= (1U << 31) - 1;
+ CHECK_LT(id, kNumStackOriginDescrs);
+ if (pc) *pc = StackOriginPC[id];
+ return StackOriginDescr[id];
+}
+
} // namespace __msan
// Interface.
@@ -224,6 +269,10 @@ void __msan_warning() {
GET_CALLER_PC_BP_SP;
(void)sp;
PrintWarning(pc, bp);
+ if (__msan::flags()->halt_on_error) {
+ Printf("Exiting\n");
+ Die();
+ }
}
void __msan_warning_noreturn() {
@@ -239,17 +288,20 @@ void __msan_init() {
msan_init_is_running = 1;
SanitizerToolName = "MemorySanitizer";
- InstallAtExitHandler();
SetDieCallback(MsanDie);
InitTlsSize();
+
+ const char *msan_options = GetEnv("MSAN_OPTIONS");
+ InitializeFlags(&msan_flags, msan_options);
+ __sanitizer_set_report_path(common_flags()->log_path);
+
InitializeInterceptors();
+ InstallAtExitHandler(); // Needs __cxa_atexit interceptor.
if (MSAN_REPLACE_OPERATORS_NEW_AND_DELETE)
ReplaceOperatorsNewAndDelete();
- const char *msan_options = GetEnv("MSAN_OPTIONS");
- InitializeFlags(&msan_flags, msan_options);
if (StackSizeIsUnlimited()) {
- if (flags()->verbosity)
+ if (common_flags()->verbosity)
Printf("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.
@@ -257,15 +309,15 @@ void __msan_init() {
ReExec();
}
- if (flags()->verbosity)
+ if (common_flags()->verbosity)
Printf("MSAN_OPTIONS: %s\n", msan_options ? msan_options : "<empty>");
msan_running_under_dr = IsRunningUnderDr();
__msan_clear_on_return();
- if (__msan_track_origins && flags()->verbosity > 0)
+ if (__msan_get_track_origins() && common_flags()->verbosity > 0)
Printf("msan_track_origins\n");
- if (!InitShadow(/* prot1 */false, /* prot2 */true, /* map_shadow */true,
- __msan_track_origins)) {
+ if (!InitShadow(/* prot1 */ false, /* prot2 */ true, /* map_shadow */ true,
+ __msan_get_track_origins())) {
// FIXME: prot1 = false is only required when running under DR.
Printf("FATAL: MemorySanitizer can not mmap the shadow memory.\n");
Printf("FATAL: Make sure to compile with -fPIE and to link with -pie.\n");
@@ -277,14 +329,17 @@ void __msan_init() {
}
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(InitializeExternalSymbolizer(external_symbolizer));
+ CHECK(external_symbolizer_started);
}
+ Symbolizer::Get()->AddHooks(EnterSymbolizer, ExitSymbolizer);
GetThreadStackTopAndBottom(/* at_initialization */true,
&__msan_stack_bounds.stack_top,
&__msan_stack_bounds.stack_bottom);
- if (flags()->verbosity)
+ if (common_flags()->verbosity)
Printf("MemorySanitizer init done\n");
msan_init_is_running = 0;
msan_inited = 1;
@@ -294,6 +349,10 @@ void __msan_set_exit_code(int exit_code) {
flags()->exit_code = exit_code;
}
+void __msan_set_keep_going(int keep_going) {
+ flags()->halt_on_error = !keep_going;
+}
+
void __msan_set_expect_umr(int expect_umr) {
if (expect_umr) {
msan_expected_umr_found = 0;
@@ -310,13 +369,17 @@ void __msan_set_expect_umr(int expect_umr) {
}
void __msan_print_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++) {
Printf("%x%x ", s[i] >> 4, s[i] & 0xf);
}
Printf("\n");
- if (__msan_track_origins) {
+ if (__msan_get_track_origins()) {
for (uptr i = 0; i < size / 4; i++) {
Printf(" o: %x ", o[i]);
}
@@ -331,10 +394,6 @@ void __msan_print_param_shadow() {
Printf("\n");
}
-void __msan_unpoison_param(uptr n) {
- internal_memset(__msan_param_tls, 0, n * sizeof(*__msan_param_tls));
-}
-
sptr __msan_test_shadow(const void *x, uptr size) {
unsigned char *s = (unsigned char*)MEM_TO_SHADOW((uptr)x);
for (uptr i = 0; i < size; ++i)
@@ -396,7 +455,7 @@ void __msan_set_origin(const void *a, uptr size, u32 origin) {
// Origin mapping is 4 bytes per 4 bytes of application memory.
// Here we extend the range such that its left and right bounds are both
// 4 byte aligned.
- if (!__msan_track_origins) return;
+ if (!__msan_get_track_origins()) return;
uptr x = MEM_TO_ORIGIN((uptr)a);
uptr beg = x & ~3UL; // align down.
uptr end = (x + size + 3) & ~3UL; // align up.
@@ -417,6 +476,10 @@ void __msan_set_origin(const void *a, uptr size, u32 origin) {
// 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) {
+ __msan_set_alloca_origin4(a, size, descr, 0);
+}
+
+void __msan_set_alloca_origin4(void *a, uptr size, const char *descr, uptr pc) {
static const u32 dash = '-';
static const u32 first_timer =
dash + (dash << 8) + (dash << 16) + (dash << 24);
@@ -429,8 +492,9 @@ void __msan_set_alloca_origin(void *a, uptr size, const char *descr) {
*id_ptr = id;
CHECK_LT(id, kNumStackOriginDescrs);
StackOriginDescr[id] = descr + 4;
+ StackOriginPC[id] = pc;
if (print)
- Printf("First time: id=%d %s \n", id, descr + 4);
+ Printf("First time: id=%d %s %p \n", id, descr + 4, pc);
}
id |= 1U << 31;
if (print)
@@ -439,15 +503,11 @@ void __msan_set_alloca_origin(void *a, uptr size, const char *descr) {
}
const char *__msan_get_origin_descr_if_stack(u32 id) {
- if ((id >> 31) == 0) return 0;
- id &= (1U << 31) - 1;
- CHECK_LT(id, kNumStackOriginDescrs);
- return StackOriginDescr[id];
+ return GetOriginDescrIfStack(id, 0);
}
-
u32 __msan_get_origin(const void *a) {
- if (!__msan_track_origins) return 0;
+ if (!__msan_get_track_origins()) return 0;
uptr x = (uptr)a;
uptr aligned = x & ~3ULL;
uptr origin_ptr = MEM_TO_ORIGIN(aligned);
@@ -458,9 +518,46 @@ u32 __msan_get_umr_origin() {
return __msan_origin_tls;
}
+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);
+ 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);
+ 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);
+ 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];
+ *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];
+ *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];
+ *p = x;
+}
+
#if !SANITIZER_SUPPORTS_WEAK_HOOKS
extern "C" {
-SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
const char* __msan_default_options() { return ""; }
} // extern "C"
#endif
diff --git a/lib/msan/msan.h b/lib/msan/msan.h
index baaba49f4187..4e6c6194505e 100644
--- a/lib/msan/msan.h
+++ b/lib/msan/msan.h
@@ -25,13 +25,12 @@
# define MSAN_REPLACE_OPERATORS_NEW_AND_DELETE 1
#endif
-#define MEM_TO_SHADOW(mem) (((uptr)mem) & ~0x400000000000ULL)
-#define MEM_TO_ORIGIN(mem) (MEM_TO_SHADOW(mem) + 0x200000000000ULL)
-#define MEM_IS_APP(mem) ((uptr)mem >= 0x600000000000ULL)
-#define MEM_IS_SHADOW(mem) ((uptr)mem >= 0x200000000000ULL && \
- (uptr)mem <= 0x400000000000ULL)
-
-struct link_map; // Opaque type returned by dlopen().
+#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)
+#define MEM_IS_SHADOW(mem) \
+ ((uptr)mem >= 0x200000000000ULL && (uptr)mem <= 0x400000000000ULL)
const int kMsanParamTlsSizeInWords = 100;
const int kMsanRetvalTlsSizeInWords = 100;
@@ -46,13 +45,16 @@ bool InitShadow(bool prot1, bool prot2, bool map_shadow, bool init_origins);
char *GetProcSelfMaps();
void InitializeInterceptors();
+void MsanAllocatorThreadFinish();
void *MsanReallocate(StackTrace *stack, void *oldp, uptr size,
uptr alignment, bool zeroise);
-void MsanDeallocate(void *ptr);
+void MsanDeallocate(StackTrace *stack, void *ptr);
void InstallTrapHandler();
void InstallAtExitHandler();
void ReplaceOperatorsNewAndDelete();
+const char *GetOriginDescrIfStack(u32 id, uptr *pc);
+
void EnterSymbolizer();
void ExitSymbolizer();
bool IsInSymbolizer();
@@ -70,13 +72,15 @@ 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,
- bool fast);
+ bool request_fast_unwind);
void ReportUMR(StackTrace *stack, u32 origin);
void ReportExpectedUMRNotFound(StackTrace *stack);
void ReportAtExitStatistics();
-void UnpoisonMappedDSO(struct link_map *map);
+// Unpoison first n function arguments.
+void UnpoisonParam(uptr n);
+void UnpoisonThreadLocalState();
#define GET_MALLOC_STACK_TRACE \
StackTrace stack; \
@@ -86,6 +90,20 @@ void UnpoisonMappedDSO(struct link_map *map);
StackTrace::GetCurrentPc(), GET_CURRENT_FRAME(), \
common_flags()->fast_unwind_on_malloc)
+class ScopedThreadLocalStateBackup {
+ public:
+ ScopedThreadLocalStateBackup() { Backup(); }
+ ~ScopedThreadLocalStateBackup() { Restore(); }
+ void Backup();
+ void Restore();
+ private:
+ u64 va_arg_overflow_size_tls;
+};
} // namespace __msan
+#define MSAN_MALLOC_HOOK(ptr, size) \
+ if (&__msan_malloc_hook) __msan_malloc_hook(ptr, size)
+#define MSAN_FREE_HOOK(ptr) \
+ if (&__msan_free_hook) __msan_free_hook(ptr)
+
#endif // MSAN_H
diff --git a/lib/msan/msan.syms b/lib/msan/msan.syms
deleted file mode 100644
index 24bbaba478b7..000000000000
--- a/lib/msan/msan.syms
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- __msan_*;
- __sanitizer_syscall_pre_*;
- __sanitizer_syscall_post_*;
-};
diff --git a/lib/msan/msan.syms.extra b/lib/msan/msan.syms.extra
new file mode 100644
index 000000000000..aad41cf1124e
--- /dev/null
+++ b/lib/msan/msan.syms.extra
@@ -0,0 +1 @@
+__msan_*
diff --git a/lib/msan/msan_allocator.cc b/lib/msan/msan_allocator.cc
index 7435843ce61e..2badf712188b 100644
--- a/lib/msan/msan_allocator.cc
+++ b/lib/msan/msan_allocator.cc
@@ -25,6 +25,7 @@ struct Metadata {
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> PrimaryAllocator;
@@ -45,35 +46,56 @@ static inline void Init() {
allocator.Init();
}
+void MsanAllocatorThreadFinish() {
+ allocator.SwallowCache(&cache);
+}
+
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));
meta->requested_size = size;
- if (zeroise)
+ if (zeroise) {
__msan_clear_and_unpoison(res, size);
- else if (flags()->poison_in_malloc)
+ } else if (flags()->poison_in_malloc) {
__msan_poison(res, 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);
+ 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);
+ }
}
+ MSAN_MALLOC_HOOK(res, size);
return res;
}
-void MsanDeallocate(void *p) {
+void MsanDeallocate(StackTrace *stack, void *p) {
CHECK(p);
Init();
+ MSAN_FREE_HOOK(p);
Metadata *meta = reinterpret_cast<Metadata*>(allocator.GetMetaData(p));
uptr size = meta->requested_size;
+ meta->requested_size = 0;
// This memory will not be reused by anyone else, so we are free to keep it
// poisoned.
- __msan_poison(p, size);
- if (__msan_get_track_origins())
- __msan_set_origin(p, size, -1);
+ 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);
+ }
+ }
allocator.Deallocate(&cache, p);
}
@@ -82,7 +104,7 @@ void *MsanReallocate(StackTrace *stack, void *old_p, uptr new_size,
if (!old_p)
return MsanAllocate(stack, new_size, alignment, zeroise);
if (!new_size) {
- MsanDeallocate(old_p);
+ MsanDeallocate(stack, old_p);
return 0;
}
Metadata *meta = reinterpret_cast<Metadata*>(allocator.GetMetaData(old_p));
@@ -98,10 +120,59 @@ void *MsanReallocate(StackTrace *stack, void *old_p, uptr new_size,
uptr memcpy_size = Min(new_size, old_size);
void *new_p = MsanAllocate(stack, new_size, alignment, zeroise);
// Printf("realloc: old_size %zd new_size %zd\n", old_size, new_size);
- if (new_p)
+ if (new_p) {
__msan_memcpy(new_p, old_p, memcpy_size);
- MsanDeallocate(old_p);
+ MsanDeallocate(stack, old_p);
+ }
return new_p;
}
+static uptr AllocationSize(const void *p) {
+ if (p == 0)
+ return 0;
+ const void *beg = allocator.GetBlockBegin(p);
+ if (beg != p)
+ return 0;
+ Metadata *b = (Metadata*)allocator.GetMetaData(p);
+ return b->requested_size;
+}
+
} // namespace __msan
+
+using namespace __msan;
+
+uptr __msan_get_current_allocated_bytes() {
+ u64 stats[AllocatorStatCount];
+ allocator.GetStats(stats);
+ u64 m = stats[AllocatorStatMalloced];
+ u64 f = stats[AllocatorStatFreed];
+ return m >= f ? m - f : 1;
+}
+
+uptr __msan_get_heap_size() {
+ u64 stats[AllocatorStatCount];
+ allocator.GetStats(stats);
+ u64 m = stats[AllocatorStatMmapped];
+ u64 f = stats[AllocatorStatUnmapped];
+ return m >= f ? m - f : 1;
+}
+
+uptr __msan_get_free_bytes() {
+ return 1;
+}
+
+uptr __msan_get_unmapped_bytes() {
+ return 1;
+}
+
+uptr __msan_get_estimated_allocated_size(uptr size) {
+ return size;
+}
+
+int __msan_get_ownership(const void *p) {
+ return AllocationSize(p) != 0;
+}
+
+uptr __msan_get_allocated_size(const void *p) {
+ return AllocationSize(p);
+}
diff --git a/lib/msan/msan_flags.h b/lib/msan/msan_flags.h
index 64ef84509888..93fa8a60dba0 100644
--- a/lib/msan/msan_flags.h
+++ b/lib/msan/msan_flags.h
@@ -19,12 +19,13 @@ namespace __msan {
// Flags.
struct Flags {
int exit_code;
- int verbosity;
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 halt_on_error;
};
Flags *flags();
diff --git a/lib/msan/msan_interceptors.cc b/lib/msan/msan_interceptors.cc
index 1bcf93db9440..15a8bec12f31 100644
--- a/lib/msan/msan_interceptors.cc
+++ b/lib/msan/msan_interceptors.cc
@@ -19,6 +19,8 @@
#include "msan.h"
#include "sanitizer_common/sanitizer_platform_limits_posix.h"
#include "sanitizer_common/sanitizer_allocator.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"
@@ -28,10 +30,15 @@
// ACHTUNG! No other system header includes in this file.
// Ideally, we should get rid of stdarg.h as well.
-extern "C" const int __msan_keep_going;
-
using namespace __msan;
+using __sanitizer::memory_order;
+using __sanitizer::atomic_load;
+using __sanitizer::atomic_store;
+using __sanitizer::atomic_uintptr_t;
+
+static unsigned g_thread_finalize_key;
+
// True if this is a nested interceptor.
static THREADLOCAL int in_interceptor_scope;
@@ -52,28 +59,30 @@ 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_keep_going) { \
- 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; \
+ 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(); \
+ } \
+ } \
} while (0)
// Check that [x, x+n) range is unpoisoned unless we are in a nested
// interceptor.
-#define CHECK_UNPOISONED(x, n) \
- if (!IsInInterceptorScope()) CHECK_UNPOISONED_0(x, n);
+#define CHECK_UNPOISONED(x, n) \
+ do { \
+ 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);
@@ -103,22 +112,22 @@ INTERCEPTOR(SSIZE_T, readlink, const char *path, char *buf, SIZE_T bufsiz) {
return res;
}
-INTERCEPTOR(void *, readdir, void *a) {
- ENSURE_MSAN_INITED();
- void *res = REAL(readdir)(a);
- __msan_unpoison(res, __sanitizer::struct_dirent_sz);
- return res;
+INTERCEPTOR(void *, memcpy, void *dest, const void *src, SIZE_T n) {
+ return __msan_memcpy(dest, src, n);
}
-INTERCEPTOR(void *, readdir64, void *a) {
- ENSURE_MSAN_INITED();
- void *res = REAL(readdir)(a);
- __msan_unpoison(res, __sanitizer::struct_dirent64_sz);
- return res;
+INTERCEPTOR(void *, mempcpy, void *dest, const void *src, SIZE_T n) {
+ return (char *)__msan_memcpy(dest, src, n) + n;
}
-INTERCEPTOR(void *, memcpy, void *dest, const void *src, SIZE_T n) {
- return __msan_memcpy(dest, src, n);
+INTERCEPTOR(void *, memccpy, void *dest, const void *src, int c, SIZE_T n) {
+ ENSURE_MSAN_INITED();
+ void *res = REAL(memccpy)(dest, src, c, n);
+ CHECK(!res || (res >= dest && res <= (char *)dest + n));
+ SIZE_T sz = res ? (char *)res - (char *)dest : n;
+ CHECK_UNPOISONED(src, sz);
+ __msan_unpoison(dest, sz);
+ return res;
}
INTERCEPTOR(void *, memmove, void *dest, const void *src, SIZE_T n) {
@@ -129,6 +138,10 @@ INTERCEPTOR(void *, memset, void *s, int c, SIZE_T n) {
return __msan_memset(s, c, n);
}
+INTERCEPTOR(void *, bcopy, const void *src, void *dest, SIZE_T n) {
+ return __msan_memmove(dest, src, n);
+}
+
INTERCEPTOR(int, posix_memalign, void **memptr, SIZE_T alignment, SIZE_T size) {
GET_MALLOC_STACK_TRACE;
CHECK_EQ(alignment & (alignment - 1), 0);
@@ -139,10 +152,35 @@ INTERCEPTOR(int, posix_memalign, void **memptr, SIZE_T alignment, SIZE_T size) {
return 0;
}
+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;
+}
+
+INTERCEPTOR(void *, valloc, SIZE_T size) {
+ GET_MALLOC_STACK_TRACE;
+ void *ptr = MsanReallocate(&stack, 0, size, GetPageSizeCached(), false);
+ return ptr;
+}
+
+INTERCEPTOR(void *, pvalloc, SIZE_T size) {
+ GET_MALLOC_STACK_TRACE;
+ uptr PageSize = GetPageSizeCached();
+ size = RoundUpTo(size, PageSize);
+ if (size == 0) {
+ // pvalloc(0) should allocate one page.
+ size = PageSize;
+ }
+ void *ptr = MsanReallocate(&stack, 0, size, PageSize, false);
+ return ptr;
+}
+
INTERCEPTOR(void, free, void *ptr) {
- ENSURE_MSAN_INITED();
+ GET_MALLOC_STACK_TRACE;
if (ptr == 0) return;
- MsanDeallocate(ptr);
+ MsanDeallocate(&stack, ptr);
}
INTERCEPTOR(SIZE_T, strlen, const char *s) {
@@ -181,6 +219,14 @@ INTERCEPTOR(char *, strncpy, char *dest, const char *src, SIZE_T n) { // NOLINT
return res;
}
+INTERCEPTOR(char *, stpcpy, char *dest, const char *src) { // NOLINT
+ ENSURE_MSAN_INITED();
+ SIZE_T n = REAL(strlen)(src);
+ char *res = REAL(stpcpy)(dest, src); // NOLINT
+ __msan_copy_poison(dest, src, n + 1);
+ return res;
+}
+
INTERCEPTOR(char *, strdup, char *src) {
ENSURE_MSAN_INITED();
SIZE_T n = REAL(strlen)(src);
@@ -295,6 +341,26 @@ INTERCEPTOR(double, strtod, const char *nptr, char **endptr) { // NOLINT
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
@@ -304,6 +370,26 @@ INTERCEPTOR(float, strtof, const char *nptr, char **endptr) { // NOLINT
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));
+ }
+ 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));
+ }
+ return res;
+}
+
INTERCEPTOR(long double, strtold, const char *nptr, char **endptr) { // NOLINT
ENSURE_MSAN_INITED();
long double res = REAL(strtold)(nptr, endptr); // NOLINT
@@ -313,11 +399,50 @@ INTERCEPTOR(long double, strtold, const char *nptr, char **endptr) { // NOLINT
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));
+ }
+ 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));
+ }
+ return res;
+}
+
+INTERCEPTOR(int, vasprintf, char **strp, const char *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);
+ }
+ return res;
+}
+
+INTERCEPTOR(int, asprintf, char **strp, const char *format, ...) { // NOLINT
+ ENSURE_MSAN_INITED();
+ va_list ap;
+ va_start(ap, format);
+ int res = vasprintf(strp, format, ap); // NOLINT
+ va_end(ap);
+ return res;
+}
+
INTERCEPTOR(int, vsnprintf, char *str, uptr size,
const char *format, va_list ap) {
ENSURE_MSAN_INITED();
int res = REAL(vsnprintf)(str, size, format, ap);
- if (!__msan_has_dynamic_component()) {
+ if (res >= 0 && !__msan_has_dynamic_component()) {
__msan_unpoison(str, res + 1);
}
return res;
@@ -326,7 +451,7 @@ INTERCEPTOR(int, vsnprintf, char *str, uptr size,
INTERCEPTOR(int, vsprintf, char *str, const char *format, va_list ap) {
ENSURE_MSAN_INITED();
int res = REAL(vsprintf)(str, format, ap);
- if (!__msan_has_dynamic_component()) {
+ if (res >= 0 && !__msan_has_dynamic_component()) {
__msan_unpoison(str, res + 1);
}
return res;
@@ -335,7 +460,7 @@ INTERCEPTOR(int, vsprintf, char *str, const char *format, va_list ap) {
INTERCEPTOR(int, vswprintf, void *str, uptr size, void *format, va_list ap) {
ENSURE_MSAN_INITED();
int res = REAL(vswprintf)(str, size, format, ap);
- if (!__msan_has_dynamic_component()) {
+ if (res >= 0 && !__msan_has_dynamic_component()) {
__msan_unpoison(str, 4 * (res + 1));
}
return res;
@@ -370,25 +495,24 @@ INTERCEPTOR(int, swprintf, void *str, uptr size, void *format, ...) {
// 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,
- void *tm) {
+ __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(SIZE_T, wcstombs, void *dest, void *src, SIZE_T size) {
+INTERCEPTOR(int, mbtowc, wchar_t *dest, const char *src, SIZE_T n) {
ENSURE_MSAN_INITED();
- SIZE_T res = REAL(wcstombs)(dest, src, size);
- if (res != (SIZE_T)-1) __msan_unpoison(dest, res + 1);
+ int res = REAL(mbtowc)(dest, src, n);
+ if (res != -1 && dest) __msan_unpoison(dest, sizeof(wchar_t));
return res;
}
-// SIZE_T mbstowcs(wchar_t *dest, const char *src, SIZE_T n);
-INTERCEPTOR(SIZE_T, mbstowcs, wchar_t *dest, const char *src, SIZE_T n) {
+INTERCEPTOR(int, mbrtowc, wchar_t *dest, const char *src, SIZE_T n, void *ps) {
ENSURE_MSAN_INITED();
- SIZE_T res = REAL(mbstowcs)(dest, src, n);
- if (res != (SIZE_T)-1) __msan_unpoison(dest, (res + 1) * sizeof(wchar_t));
+ SIZE_T res = REAL(mbrtowc)(dest, src, n, ps);
+ if (res != (SIZE_T)-1 && dest) __msan_unpoison(dest, sizeof(wchar_t));
return res;
}
@@ -422,6 +546,13 @@ INTERCEPTOR(wchar_t *, wmemcpy, wchar_t *dest, const wchar_t *src, SIZE_T n) {
return res;
}
+INTERCEPTOR(wchar_t *, wmempcpy, wchar_t *dest, const wchar_t *src, SIZE_T n) {
+ ENSURE_MSAN_INITED();
+ wchar_t *res = REAL(wmempcpy)(dest, src, n);
+ __msan_copy_poison(dest, src, n * sizeof(wchar_t));
+ return res;
+}
+
INTERCEPTOR(wchar_t *, wmemset, wchar_t *s, wchar_t c, SIZE_T n) {
CHECK(MEM_IS_APP(s));
ENSURE_MSAN_INITED();
@@ -450,28 +581,6 @@ INTERCEPTOR(double, wcstod, const wchar_t *nptr, wchar_t **endptr) {
return res;
}
-// #define UNSUPPORTED(name) \
-// INTERCEPTOR(void, name, void) { \
-// Printf("MSAN: Unsupported %s\n", __FUNCTION__); \
-// Die(); \
-// }
-
-// FIXME: intercept the following functions:
-// Note, they only matter when running without a dynamic tool.
-// UNSUPPORTED(wcscoll_l)
-// UNSUPPORTED(wcsnrtombs)
-// UNSUPPORTED(wcstol)
-// UNSUPPORTED(wcstoll)
-// UNSUPPORTED(wcstold)
-// UNSUPPORTED(wcstoul)
-// UNSUPPORTED(wcstoull)
-// UNSUPPORTED(wcsxfrm_l)
-// UNSUPPORTED(wcsdup)
-// UNSUPPORTED(wcsftime)
-// UNSUPPORTED(wcsstr)
-// UNSUPPORTED(wcsrchr)
-// UNSUPPORTED(wctob)
-
INTERCEPTOR(int, gettimeofday, void *tv, void *tz) {
ENSURE_MSAN_INITED();
int res = REAL(gettimeofday)(tv, tz);
@@ -502,6 +611,32 @@ INTERCEPTOR(char *, getenv, char *name) {
return res;
}
+extern char **environ;
+
+static void UnpoisonEnviron() {
+ char **envp = environ;
+ for (; *envp; ++envp) {
+ __msan_unpoison(envp, sizeof(*envp));
+ __msan_unpoison(*envp, REAL(strlen)(*envp) + 1);
+ }
+ // Trailing NULL pointer.
+ __msan_unpoison(envp, sizeof(*envp));
+}
+
+INTERCEPTOR(int, setenv, const char *name, const char *value, int overwrite) {
+ ENSURE_MSAN_INITED();
+ int res = REAL(setenv)(name, value, overwrite);
+ if (!res) UnpoisonEnviron();
+ return res;
+}
+
+INTERCEPTOR(int, putenv, char *string) {
+ ENSURE_MSAN_INITED();
+ int res = REAL(putenv)(string);
+ if (!res) UnpoisonEnviron();
+ return res;
+}
+
INTERCEPTOR(int, __fxstat, int magic, int fd, void *buf) {
ENSURE_MSAN_INITED();
int res = REAL(__fxstat)(magic, fd, buf);
@@ -518,6 +653,22 @@ INTERCEPTOR(int, __fxstat64, int magic, int fd, void *buf) {
return res;
}
+INTERCEPTOR(int, __fxstatat, int magic, int fd, char *pathname, void *buf,
+ int flags) {
+ ENSURE_MSAN_INITED();
+ int res = REAL(__fxstatat)(magic, fd, pathname, buf, flags);
+ if (!res) __msan_unpoison(buf, __sanitizer::struct_stat_sz);
+ return res;
+}
+
+INTERCEPTOR(int, __fxstatat64, int magic, int fd, char *pathname, void *buf,
+ int flags) {
+ ENSURE_MSAN_INITED();
+ int res = REAL(__fxstatat64)(magic, fd, pathname, buf, flags);
+ if (!res) __msan_unpoison(buf, __sanitizer::struct_stat64_sz);
+ return res;
+}
+
INTERCEPTOR(int, __xstat, int magic, char *path, void *buf) {
ENSURE_MSAN_INITED();
int res = REAL(__xstat)(magic, path, buf);
@@ -592,22 +743,6 @@ INTERCEPTOR(char *, fgets_unlocked, char *s, int size, void *stream) {
return res;
}
-INTERCEPTOR(char *, getcwd, char *buf, SIZE_T size) {
- ENSURE_MSAN_INITED();
- char *res = REAL(getcwd)(buf, size);
- if (res)
- __msan_unpoison(res, REAL(strlen)(res) + 1);
- return res;
-}
-
-INTERCEPTOR(char *, realpath, char *path, char *abspath) {
- ENSURE_MSAN_INITED();
- char *res = REAL(realpath)(path, abspath);
- if (res)
- __msan_unpoison(abspath, REAL(strlen)(abspath) + 1);
- return res;
-}
-
INTERCEPTOR(int, getrlimit, int resource, void *rlim) {
if (msan_init_is_running)
return REAL(getrlimit)(resource, rlim);
@@ -628,38 +763,6 @@ INTERCEPTOR(int, getrlimit64, int resource, void *rlim) {
return res;
}
-INTERCEPTOR(int, statfs, const char *s, void *buf) {
- ENSURE_MSAN_INITED();
- int res = REAL(statfs)(s, buf);
- if (!res)
- __msan_unpoison(buf, __sanitizer::struct_statfs_sz);
- return res;
-}
-
-INTERCEPTOR(int, fstatfs, int fd, void *buf) {
- ENSURE_MSAN_INITED();
- int res = REAL(fstatfs)(fd, buf);
- if (!res)
- __msan_unpoison(buf, __sanitizer::struct_statfs_sz);
- return res;
-}
-
-INTERCEPTOR(int, statfs64, const char *s, void *buf) {
- ENSURE_MSAN_INITED();
- int res = REAL(statfs64)(s, buf);
- if (!res)
- __msan_unpoison(buf, __sanitizer::struct_statfs64_sz);
- return res;
-}
-
-INTERCEPTOR(int, fstatfs64, int fd, void *buf) {
- ENSURE_MSAN_INITED();
- int res = REAL(fstatfs64)(fd, buf);
- if (!res)
- __msan_unpoison(buf, __sanitizer::struct_statfs64_sz);
- return res;
-}
-
INTERCEPTOR(int, uname, void *utsname) {
ENSURE_MSAN_INITED();
int res = REAL(uname)(utsname);
@@ -710,35 +813,24 @@ INTERCEPTOR(SSIZE_T, recv, int fd, void *buf, SIZE_T len, int flags) {
}
INTERCEPTOR(SSIZE_T, recvfrom, int fd, void *buf, SIZE_T len, int flags,
- void *srcaddr, void *addrlen) {
+ void *srcaddr, int *addrlen) {
ENSURE_MSAN_INITED();
SIZE_T srcaddr_sz;
- if (srcaddr)
- srcaddr_sz = __sanitizer_get_socklen_t(addrlen);
+ if (srcaddr) srcaddr_sz = *addrlen;
SSIZE_T res = REAL(recvfrom)(fd, buf, len, flags, srcaddr, addrlen);
if (res > 0) {
__msan_unpoison(buf, res);
if (srcaddr) {
- SIZE_T sz = __sanitizer_get_socklen_t(addrlen);
+ SIZE_T sz = *addrlen;
__msan_unpoison(srcaddr, (sz < srcaddr_sz) ? sz : srcaddr_sz);
}
}
return res;
}
-INTERCEPTOR(SSIZE_T, recvmsg, int fd, struct msghdr *msg, int flags) {
- ENSURE_MSAN_INITED();
- SSIZE_T res = REAL(recvmsg)(fd, msg, flags);
- if (res > 0) {
- for (SIZE_T i = 0; i < __sanitizer_get_msghdr_iovlen(msg); ++i)
- __msan_unpoison(__sanitizer_get_msghdr_iov_iov_base(msg, i),
- __sanitizer_get_msghdr_iov_iov_len(msg, i));
- }
- return res;
-}
-
INTERCEPTOR(void *, calloc, SIZE_T nmemb, SIZE_T size) {
- if (CallocShouldReturnNullDueToOverflow(size, nmemb)) return 0;
+ if (CallocShouldReturnNullDueToOverflow(size, nmemb))
+ return AllocatorReturnNull();
GET_MALLOC_STACK_TRACE;
if (!msan_inited) {
// Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym.
@@ -814,6 +906,13 @@ INTERCEPTOR(int, dladdr, void *addr, dlinfo *info) {
return res;
}
+INTERCEPTOR(char *, dlerror) {
+ ENSURE_MSAN_INITED();
+ char *res = REAL(dlerror)();
+ 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
@@ -828,7 +927,7 @@ INTERCEPTOR(void *, dlopen, const char *filename, int flag) {
if (!__msan_has_dynamic_component() && map) {
// If msandr didn't clear the shadow before the initializers ran, we do it
// ourselves afterwards.
- UnpoisonMappedDSO(map);
+ ForEachMappedRegion(map, __msan_unpoison);
}
return (void *)map;
}
@@ -848,7 +947,7 @@ static int msan_dl_iterate_phdr_cb(__sanitizer_dl_phdr_info *info, SIZE_T size,
__msan_unpoison(info->dlpi_name, REAL(strlen)(info->dlpi_name) + 1);
}
dl_iterate_phdr_data *cbdata = (dl_iterate_phdr_data *)data;
- __msan_unpoison_param(3);
+ UnpoisonParam(3);
return cbdata->callback(info, size, cbdata->data);
}
@@ -872,22 +971,32 @@ INTERCEPTOR(int, getrusage, int who, void *usage) {
return res;
}
+// 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.
const int kMaxSignals = 1024;
-static uptr sigactions[kMaxSignals];
+static atomic_uintptr_t sigactions[kMaxSignals];
static StaticSpinMutex sigactions_mu;
static void SignalHandler(int signo) {
+ ScopedThreadLocalStateBackup stlsb;
+ UnpoisonParam(1);
+
typedef void (*signal_cb)(int x);
- signal_cb cb = (signal_cb)sigactions[signo];
+ signal_cb cb =
+ (signal_cb)atomic_load(&sigactions[signo], memory_order_relaxed);
cb(signo);
}
static void SignalAction(int signo, void *si, void *uc) {
- __msan_unpoison(si, __sanitizer::struct_sigaction_sz);
+ ScopedThreadLocalStateBackup stlsb;
+ UnpoisonParam(3);
+ __msan_unpoison(si, sizeof(__sanitizer_sigaction));
__msan_unpoison(uc, __sanitizer::ucontext_t_sz);
typedef void (*sigaction_cb)(int, void *, void *);
- sigaction_cb cb = (sigaction_cb)sigactions[signo];
+ sigaction_cb cb =
+ (sigaction_cb)atomic_load(&sigactions[signo], memory_order_relaxed);
cb(signo, si, uc);
}
@@ -900,25 +1009,25 @@ INTERCEPTOR(int, sigaction, int signo, const __sanitizer_sigaction *act,
if (flags()->wrap_signals) {
SpinMutexLock lock(&sigactions_mu);
CHECK_LT(signo, kMaxSignals);
- uptr old_cb = sigactions[signo];
+ uptr old_cb = atomic_load(&sigactions[signo], memory_order_relaxed);
__sanitizer_sigaction new_act;
__sanitizer_sigaction *pnew_act = act ? &new_act : 0;
if (act) {
- internal_memcpy(pnew_act, act, __sanitizer::struct_sigaction_sz);
- uptr cb = __sanitizer::__sanitizer_get_sigaction_sa_sigaction(pnew_act);
- uptr new_cb =
- __sanitizer::__sanitizer_get_sigaction_sa_siginfo(pnew_act) ?
- (uptr)SignalAction : (uptr)SignalHandler;
+ internal_memcpy(pnew_act, act, sizeof(__sanitizer_sigaction));
+ uptr cb = (uptr)pnew_act->sa_sigaction;
+ uptr new_cb = (pnew_act->sa_flags & __sanitizer::sa_siginfo)
+ ? (uptr)SignalAction
+ : (uptr)SignalHandler;
if (cb != __sanitizer::sig_ign && cb != __sanitizer::sig_dfl) {
- sigactions[signo] = cb;
- __sanitizer::__sanitizer_set_sigaction_sa_sigaction(pnew_act, new_cb);
+ atomic_store(&sigactions[signo], cb, memory_order_relaxed);
+ pnew_act->sa_sigaction = (void (*)(int, void *, void *))new_cb;
}
}
res = REAL(sigaction)(signo, pnew_act, oldact);
if (res == 0 && oldact) {
- uptr cb = __sanitizer::__sanitizer_get_sigaction_sa_sigaction(oldact);
+ uptr cb = (uptr)oldact->sa_sigaction;
if (cb != __sanitizer::sig_ign && cb != __sanitizer::sig_dfl) {
- __sanitizer::__sanitizer_set_sigaction_sa_sigaction(oldact, old_cb);
+ oldact->sa_sigaction = (void (*)(int, void *, void *))old_cb;
}
}
} else {
@@ -926,7 +1035,7 @@ INTERCEPTOR(int, sigaction, int signo, const __sanitizer_sigaction *act,
}
if (res == 0 && oldact) {
- __msan_unpoison(oldact, __sanitizer::struct_sigaction_sz);
+ __msan_unpoison(oldact, sizeof(__sanitizer_sigaction));
}
return res;
}
@@ -937,7 +1046,7 @@ INTERCEPTOR(int, signal, int signo, uptr cb) {
CHECK_LT(signo, kMaxSignals);
SpinMutexLock lock(&sigactions_mu);
if (cb != __sanitizer::sig_ign && cb != __sanitizer::sig_dfl) {
- sigactions[signo] = cb;
+ atomic_store(&sigactions[signo], cb, memory_order_relaxed);
cb = (uptr) SignalHandler;
}
return REAL(signal)(signo, cb);
@@ -948,8 +1057,39 @@ 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_attr_setstacksize(void *attr, uptr stacksize);
-extern "C" int pthread_attr_getstack(void *attr, uptr *stack, uptr *stacksize);
+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);
+}
INTERCEPTOR(int, pthread_create, void *th, void *attr, void *(*callback)(void*),
void * param) {
@@ -960,9 +1100,19 @@ INTERCEPTOR(int, pthread_create, void *th, void *attr, void *(*callback)(void*),
attr = &myattr;
}
- AdjustStackSizeLinux(attr, flags()->verbosity);
+ AdjustStackSizeLinux(attr);
+
+ ThreadParam p;
+ p.callback = callback;
+ p.param = param;
+ atomic_store(&p.done, 0, memory_order_relaxed);
+
+ 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, callback, param);
if (attr == &myattr)
pthread_attr_destroy(&myattr);
if (!res) {
@@ -971,37 +1121,177 @@ INTERCEPTOR(int, pthread_create, void *th, void *attr, void *(*callback)(void*),
return res;
}
+INTERCEPTOR(int, pthread_key_create, __sanitizer_pthread_key_t *key,
+ void (*dtor)(void *value)) {
+ ENSURE_MSAN_INITED();
+ int res = REAL(pthread_key_create)(key, dtor);
+ if (!res && key)
+ __msan_unpoison(key, sizeof(*key));
+ return res;
+}
+
+INTERCEPTOR(int, pthread_join, void *th, void **retval) {
+ ENSURE_MSAN_INITED();
+ int res = REAL(pthread_join)(th, retval);
+ if (!res && retval)
+ __msan_unpoison(retval, sizeof(*retval));
+ return res;
+}
+
+extern char *tzname[2];
+
+INTERCEPTOR(void, tzset) {
+ ENSURE_MSAN_INITED();
+ REAL(tzset)();
+ if (tzname[0])
+ __msan_unpoison(tzname[0], REAL(strlen)(tzname[0]) + 1);
+ if (tzname[1])
+ __msan_unpoison(tzname[1], REAL(strlen)(tzname[1]) + 1);
+ return;
+}
+
+struct MSanAtExitRecord {
+ void (*func)(void *arg);
+ void *arg;
+};
+
+void MSanAtExitWrapper(void *arg) {
+ UnpoisonParam(1);
+ MSanAtExitRecord *r = (MSanAtExitRecord *)arg;
+ r->func(r->arg);
+ InternalFree(r);
+}
+
+// Unpoison argument shadow for C++ module destructors.
+INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg,
+ void *dso_handle) {
+ if (msan_init_is_running) return REAL(__cxa_atexit)(func, arg, dso_handle);
+ ENSURE_MSAN_INITED();
+ MSanAtExitRecord *r =
+ (MSanAtExitRecord *)InternalAlloc(sizeof(MSanAtExitRecord));
+ r->func = func;
+ r->arg = arg;
+ return REAL(__cxa_atexit)(MSanAtExitWrapper, r, dso_handle);
+}
+
+DECLARE_REAL(int, shmctl, int shmid, int cmd, void *buf)
+
+INTERCEPTOR(void *, shmat, int shmid, const void *shmaddr, int shmflg) {
+ ENSURE_MSAN_INITED();
+ void *p = REAL(shmat)(shmid, shmaddr, shmflg);
+ if (p != (void *)-1) {
+ __sanitizer_shmid_ds ds;
+ int res = REAL(shmctl)(shmid, shmctl_ipc_stat, &ds);
+ if (!res) {
+ __msan_unpoison(p, ds.shm_segsz);
+ }
+ }
+ 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;
+}
+
+INTERCEPTOR(int, mlockall, int flags) {
+ MlockIsUnsupported();
+ return 0;
+}
+
+INTERCEPTOR(int, munlockall, void) {
+ MlockIsUnsupported();
+ return 0;
+}
+
struct MSanInterceptorContext {
bool in_interceptor_scope;
};
-// A version of CHECK_UNPOISED using a saved scope value. Used in common
+namespace __msan {
+
+int OnExit() {
+ // FIXME: ask frontend whether we need to return failure.
+ return 0;
+}
+
+} // 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) \
- if (!((MSanInterceptorContext *) ctx)->in_interceptor_scope) \
- CHECK_UNPOISONED_0(x, n);
+#define CHECK_UNPOISONED_CTX(ctx, x, n) \
+ do { \
+ if (!((MSanInterceptorContext *)ctx)->in_interceptor_scope) \
+ 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"); \
+ } while (0)
+
+#define COMMON_INTERCEPT_FUNCTION(name) MSAN_INTERCEPT_FUNC(name)
+#define COMMON_INTERCEPTOR_UNPOISON_PARAM(ctx, 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_ENTER(ctx, func, ...) \
- if (msan_init_is_running) return REAL(func)(__VA_ARGS__); \
- MSanInterceptorContext msan_ctx = { IsInInterceptorScope() }; \
- ctx = (void *)&msan_ctx; \
- InterceptorScope interceptor_scope; \
+ CHECK_UNPOISONED_CTX(ctx, ptr, size)
+#define COMMON_INTERCEPTOR_INITIALIZE_RANGE(ctx, ptr, size) \
+ __msan_unpoison(ptr, size)
+#define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \
+ if (msan_init_is_running) return REAL(func)(__VA_ARGS__); \
+ MSanInterceptorContext msan_ctx = {IsInInterceptorScope()}; \
+ ctx = (void *)&msan_ctx; \
+ (void)ctx; \
+ InterceptorScope interceptor_scope; \
+ __msan_unpoison(__errno_location(), sizeof(int)); /* NOLINT */ \
ENSURE_MSAN_INITED();
#define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd) \
do { \
} while (false)
-#define COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd) do { } while (false)
+#define COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd) \
+ do { \
+ } while (false)
+#define COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, newfd) \
+ do { \
+ } while (false)
#define COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, name) \
- do { } while (false) // FIXME
+ do { \
+ } while (false) // FIXME
+#define COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name) \
+ do { \
+ } while (false) // FIXME
+#define COMMON_INTERCEPTOR_BLOCK_REAL(name) REAL(name)
+#define COMMON_INTERCEPTOR_ON_EXIT(ctx) OnExit()
#include "sanitizer_common/sanitizer_common_interceptors.inc"
#define COMMON_SYSCALL_PRE_READ_RANGE(p, s) CHECK_UNPOISONED(p, s)
-#define COMMON_SYSCALL_PRE_WRITE_RANGE(p, s)
-#define COMMON_SYSCALL_POST_READ_RANGE(p, s)
+#define COMMON_SYSCALL_PRE_WRITE_RANGE(p, s) \
+ do { \
+ } while (false)
+#define COMMON_SYSCALL_POST_READ_RANGE(p, s) \
+ do { \
+ } while (false)
#define COMMON_SYSCALL_POST_WRITE_RANGE(p, s) __msan_unpoison(p, s)
#include "sanitizer_common/sanitizer_common_syscalls.inc"
@@ -1062,15 +1352,41 @@ void __msan_clear_and_unpoison(void *a, uptr size) {
fast_memset((void*)MEM_TO_SHADOW((uptr)a), 0, size);
}
+u32 get_origin_if_poisoned(uptr a, uptr size) {
+ unsigned char *s = (unsigned char *)MEM_TO_SHADOW(a);
+ for (uptr i = 0; i < size; ++i)
+ if (s[i])
+ return *(u32 *)SHADOW_TO_ORIGIN((s + i) & ~3UL);
+ return 0;
+}
+
void __msan_copy_origin(void *dst, const void *src, uptr size) {
if (!__msan_get_track_origins()) return;
if (!MEM_IS_APP(dst) || !MEM_IS_APP(src)) return;
- uptr d = MEM_TO_ORIGIN(dst);
- uptr s = MEM_TO_ORIGIN(src);
- uptr beg = d & ~3UL; // align down.
- uptr end = (d + size + 3) & ~3UL; // align up.
- s = s & ~3UL; // align down.
- fast_memcpy((void*)beg, (void*)s, end - beg);
+ 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 *)MEM_TO_ORIGIN(beg) = o;
+ beg += 4;
+ }
+
+ uptr end = (d + size + 3) & ~3UL;
+ // 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 (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);
+ }
}
void __msan_copy_poison(void *dst, const void *src, uptr size) {
@@ -1119,6 +1435,9 @@ void InitializeInterceptors() {
INTERCEPT_FUNCTION(mmap);
INTERCEPT_FUNCTION(mmap64);
INTERCEPT_FUNCTION(posix_memalign);
+ INTERCEPT_FUNCTION(memalign);
+ INTERCEPT_FUNCTION(valloc);
+ INTERCEPT_FUNCTION(pvalloc);
INTERCEPT_FUNCTION(malloc);
INTERCEPT_FUNCTION(calloc);
INTERCEPT_FUNCTION(realloc);
@@ -1126,15 +1445,18 @@ void InitializeInterceptors() {
INTERCEPT_FUNCTION(fread);
INTERCEPT_FUNCTION(fread_unlocked);
INTERCEPT_FUNCTION(readlink);
- INTERCEPT_FUNCTION(readdir);
- INTERCEPT_FUNCTION(readdir64);
INTERCEPT_FUNCTION(memcpy);
+ INTERCEPT_FUNCTION(memccpy);
+ INTERCEPT_FUNCTION(mempcpy);
INTERCEPT_FUNCTION(memset);
INTERCEPT_FUNCTION(memmove);
+ INTERCEPT_FUNCTION(bcopy);
INTERCEPT_FUNCTION(wmemset);
INTERCEPT_FUNCTION(wmemcpy);
+ INTERCEPT_FUNCTION(wmempcpy);
INTERCEPT_FUNCTION(wmemmove);
INTERCEPT_FUNCTION(strcpy); // NOLINT
+ INTERCEPT_FUNCTION(stpcpy); // NOLINT
INTERCEPT_FUNCTION(strdup);
INTERCEPT_FUNCTION(__strdup);
INTERCEPT_FUNCTION(strndup);
@@ -1150,8 +1472,16 @@ void InitializeInterceptors() {
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_FUNCTION(vswprintf);
@@ -1159,20 +1489,24 @@ void InitializeInterceptors() {
INTERCEPT_FUNCTION(snprintf);
INTERCEPT_FUNCTION(swprintf);
INTERCEPT_FUNCTION(strftime);
- INTERCEPT_FUNCTION(wcstombs);
- INTERCEPT_FUNCTION(mbstowcs);
+ 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);
INTERCEPT_FUNCTION(pipe);
@@ -1180,28 +1514,33 @@ void InitializeInterceptors() {
INTERCEPT_FUNCTION(socketpair);
INTERCEPT_FUNCTION(fgets);
INTERCEPT_FUNCTION(fgets_unlocked);
- INTERCEPT_FUNCTION(getcwd);
- INTERCEPT_FUNCTION(realpath);
INTERCEPT_FUNCTION(getrlimit);
INTERCEPT_FUNCTION(getrlimit64);
- INTERCEPT_FUNCTION(statfs);
- INTERCEPT_FUNCTION(fstatfs);
- INTERCEPT_FUNCTION(statfs64);
- INTERCEPT_FUNCTION(fstatfs64);
INTERCEPT_FUNCTION(uname);
INTERCEPT_FUNCTION(gethostname);
INTERCEPT_FUNCTION(epoll_wait);
INTERCEPT_FUNCTION(epoll_pwait);
INTERCEPT_FUNCTION(recv);
INTERCEPT_FUNCTION(recvfrom);
- INTERCEPT_FUNCTION(recvmsg);
INTERCEPT_FUNCTION(dladdr);
+ INTERCEPT_FUNCTION(dlerror);
INTERCEPT_FUNCTION(dlopen);
INTERCEPT_FUNCTION(dl_iterate_phdr);
INTERCEPT_FUNCTION(getrusage);
INTERCEPT_FUNCTION(sigaction);
INTERCEPT_FUNCTION(signal);
INTERCEPT_FUNCTION(pthread_create);
+ INTERCEPT_FUNCTION(pthread_key_create);
+ INTERCEPT_FUNCTION(pthread_join);
+ 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();
+ }
+
inited = 1;
}
} // namespace __msan
diff --git a/lib/msan/msan_interface_internal.h b/lib/msan/msan_interface_internal.h
index fb57f67c42ed..794b3540f931 100644
--- a/lib/msan/msan_interface_internal.h
+++ b/lib/msan/msan_interface_internal.h
@@ -73,6 +73,8 @@ 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);
SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_set_alloca_origin4(void *a, uptr size, const char *descr, uptr pc);
+SANITIZER_INTERFACE_ATTRIBUTE
u32 __msan_get_origin(const void *a);
SANITIZER_INTERFACE_ATTRIBUTE
@@ -83,9 +85,12 @@ SANITIZER_INTERFACE_ATTRIBUTE
void __msan_set_exit_code(int exit_code);
SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_set_keep_going(int keep_going);
+
+SANITIZER_INTERFACE_ATTRIBUTE
int __msan_set_poison_in_malloc(int do_poison);
-SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
/* OPTIONAL */ const char* __msan_default_options();
// For testing.
@@ -120,9 +125,51 @@ void __msan_partial_poison(const void* data, void* shadow, uptr size);
// Memory will be marked uninitialized, with origin at the call site.
SANITIZER_INTERFACE_ATTRIBUTE
void __msan_allocated_memory(const void* data, uptr size);
-} // extern "C"
-// Unpoison first n function arguments.
-void __msan_unpoison_param(uptr n);
+SANITIZER_INTERFACE_ATTRIBUTE
+u16 __sanitizer_unaligned_load16(const uu16 *p);
+
+SANITIZER_INTERFACE_ATTRIBUTE
+u32 __sanitizer_unaligned_load32(const uu32 *p);
+
+SANITIZER_INTERFACE_ATTRIBUTE
+u64 __sanitizer_unaligned_load64(const uu64 *p);
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_unaligned_store16(uu16 *p, u16 x);
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_unaligned_store32(uu32 *p, u32 x);
+
+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);
+} // extern "C"
#endif // MSAN_INTERFACE_INTERNAL_H
diff --git a/lib/msan/msan_linux.cc b/lib/msan/msan_linux.cc
index 367dc904d05d..46f501e488c5 100644
--- a/lib/msan/msan_linux.cc
+++ b/lib/msan/msan_linux.cc
@@ -17,7 +17,6 @@
#include "msan.h"
-#include <algorithm>
#include <elf.h>
#include <link.h>
#include <stdio.h>
@@ -46,7 +45,13 @@ static const uptr kOriginsBeg = kBad2Beg;
static const uptr kOriginsEnd = kBad2End;
bool InitShadow(bool prot1, bool prot2, bool map_shadow, bool init_origins) {
- if (flags()->verbosity) {
+ if ((uptr) & InitShadow < kMemBeg) {
+ Printf("FATAL: Code below application range: %p < %p. Non-PIE build?\n",
+ &InitShadow, (void *)kMemBeg);
+ return false;
+ }
+
+ 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);
@@ -92,41 +97,6 @@ void InstallAtExitHandler() {
atexit(MsanAtExit);
}
-void UnpoisonMappedDSO(link_map *map) {
- typedef ElfW(Phdr) Elf_Phdr;
- typedef ElfW(Ehdr) Elf_Ehdr;
- char *base = (char *)map->l_addr;
- Elf_Ehdr *ehdr = (Elf_Ehdr *)base;
- char *phdrs = base + ehdr->e_phoff;
- char *phdrs_end = phdrs + ehdr->e_phnum * ehdr->e_phentsize;
-
- // Find the segment with the minimum base so we can "relocate" the p_vaddr
- // fields. Typically ET_DYN objects (DSOs) have base of zero and ET_EXEC
- // objects have a non-zero base.
- uptr preferred_base = ~0ULL;
- for (char *iter = phdrs; iter != phdrs_end; iter += ehdr->e_phentsize) {
- Elf_Phdr *phdr = (Elf_Phdr *)iter;
- if (phdr->p_type == PT_LOAD)
- preferred_base = std::min(preferred_base, (uptr)phdr->p_vaddr);
- }
-
- // Compute the delta from the real base to get a relocation delta.
- sptr delta = (uptr)base - preferred_base;
- // Now we can figure out what the loader really mapped.
- for (char *iter = phdrs; iter != phdrs_end; iter += ehdr->e_phentsize) {
- Elf_Phdr *phdr = (Elf_Phdr *)iter;
- if (phdr->p_type == PT_LOAD) {
- uptr seg_start = phdr->p_vaddr + delta;
- uptr seg_end = seg_start + phdr->p_memsz;
- // None of these values are aligned. We consider the ragged edges of the
- // load command as defined, since they are mapped from the file.
- seg_start = RoundDownTo(seg_start, GetPageSizeCached());
- seg_end = RoundUpTo(seg_end, GetPageSizeCached());
- __msan_unpoison((void *)seg_start, seg_end - seg_start);
- }
- }
-}
-
} // namespace __msan
#endif // __linux__
diff --git a/lib/msan/msan_new_delete.cc b/lib/msan/msan_new_delete.cc
index 88d4364f6562..17687ddfc213 100644
--- a/lib/msan/msan_new_delete.cc
+++ b/lib/msan/msan_new_delete.cc
@@ -43,7 +43,8 @@ void *operator new(size_t size, std::nothrow_t const&) { OPERATOR_NEW_BODY; }
void *operator new[](size_t size, std::nothrow_t const&) { OPERATOR_NEW_BODY; }
#define OPERATOR_DELETE_BODY \
- if (ptr) MsanDeallocate(ptr)
+ 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; }
diff --git a/lib/msan/msan_report.cc b/lib/msan/msan_report.cc
index 734fc96fe69f..e3ef99307940 100644
--- a/lib/msan/msan_report.cc
+++ b/lib/msan/msan_report.cc
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "msan.h"
+#include "sanitizer_common/sanitizer_allocator_internal.h"
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_flags.h"
#include "sanitizer_common/sanitizer_mutex.h"
@@ -24,16 +25,6 @@ using namespace __sanitizer;
namespace __msan {
-static bool PrintsToTtyCached() {
- static int cached = 0;
- static bool prints_to_tty;
- if (!cached) { // Ok wrt threads since we are printing only from one thread.
- prints_to_tty = PrintsToTty();
- cached = 1;
- }
- return prints_to_tty;
-}
-
class Decorator: private __sanitizer::AnsiColorDecorator {
public:
Decorator() : __sanitizer::AnsiColorDecorator(PrintsToTtyCached()) { }
@@ -43,17 +34,12 @@ class Decorator: private __sanitizer::AnsiColorDecorator {
const char *End() { return Default(); }
};
-static void PrintStack(const uptr *trace, uptr size) {
- SymbolizerScope sym_scope;
- StackTrace::PrintStack(trace, size, true,
- common_flags()->strip_path_prefix, 0);
-}
-
static void DescribeOrigin(u32 origin) {
Decorator d;
- if (flags()->verbosity)
+ if (common_flags()->verbosity)
Printf(" raw origin id: %d\n", origin);
- if (const char *so = __msan_get_origin_descr_if_stack(origin)) {
+ uptr pc;
+ if (const char *so = GetOriginDescrIfStack(origin, &pc)) {
char* s = internal_strdup(so);
char* sep = internal_strchr(s, '@');
CHECK(sep);
@@ -61,32 +47,25 @@ static void DescribeOrigin(u32 origin) {
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(), Demangle(sep + 1),
- d.Origin(), d.End());
+ 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);
+ }
} else {
uptr size = 0;
const uptr *trace = StackDepotGet(origin, &size);
Printf(" %sUninitialized value was created by a heap allocation%s\n",
d.Origin(), d.End());
- PrintStack(trace, size);
+ StackTrace::PrintStack(trace, size);
}
}
-static void ReportSummary(const char *error_type, StackTrace *stack) {
- if (!stack->size || !IsSymbolizerAvailable()) return;
- AddressInfo ai;
- uptr pc = StackTrace::GetPreviousInstructionPc(stack->trace[0]);
- {
- SymbolizerScope sym_scope;
- SymbolizeCode(pc, &ai, 1);
- }
- ReportErrorSummary(error_type,
- StripPathPrefix(ai.file,
- common_flags()->strip_path_prefix),
- ai.line, ai.function);
-}
-
void ReportUMR(StackTrace *stack, u32 origin) {
if (!__msan::flags()->report_umrs) return;
@@ -94,20 +73,20 @@ void ReportUMR(StackTrace *stack, u32 origin) {
Decorator d;
Printf("%s", d.Warning());
- Report(" WARNING: Use of uninitialized value\n");
+ Report(" WARNING: MemorySanitizer: use-of-uninitialized-value\n");
Printf("%s", d.End());
- PrintStack(stack->trace, stack->size);
+ StackTrace::PrintStack(stack->trace, stack->size);
if (origin) {
DescribeOrigin(origin);
}
- ReportSummary("use-of-uninitialized-value", stack);
+ ReportErrorSummary("use-of-uninitialized-value", stack);
}
void ReportExpectedUMRNotFound(StackTrace *stack) {
SpinMutexLock l(&CommonSanitizerReportMutex);
Printf(" WARNING: Expected use of uninitialized value not found\n");
- PrintStack(stack->trace, stack->size);
+ StackTrace::PrintStack(stack->trace, stack->size);
}
void ReportAtExitStatistics() {
@@ -119,5 +98,4 @@ void ReportAtExitStatistics() {
Printf("%s", d.End());
}
-
} // namespace __msan
diff --git a/lib/msan/tests/CMakeLists.txt b/lib/msan/tests/CMakeLists.txt
index 7a784023d2db..9c49f167fa19 100644
--- a/lib/msan/tests/CMakeLists.txt
+++ b/lib/msan/tests/CMakeLists.txt
@@ -6,7 +6,6 @@ include_directories(..)
include_directories(../..)
# Instrumented libcxx sources and build flags.
-set(MSAN_LIBCXX_PATH ${LLVM_MAIN_SRC_DIR}/projects/libcxx)
file(GLOB MSAN_LIBCXX_SOURCES ${MSAN_LIBCXX_PATH}/src/*.cpp)
set(MSAN_LIBCXX_CFLAGS
-I${MSAN_LIBCXX_PATH}/include
@@ -52,6 +51,7 @@ set(MSAN_UNITTEST_COMMON_CFLAGS
-fno-exceptions
-fno-omit-frame-pointer
-mno-omit-leaf-frame-pointer
+ -Wno-deprecated-declarations
)
set(MSAN_UNITTEST_INSTRUMENTED_CFLAGS
${MSAN_UNITTEST_COMMON_CFLAGS}
@@ -165,7 +165,7 @@ macro(add_msan_tests_for_arch arch)
${MSAN_INST_LIBCXX} ${MSANDR_TEST_SO})
endmacro()
-if(COMPILER_RT_CAN_EXECUTE_TESTS AND EXISTS ${MSAN_LIBCXX_PATH}/)
+if(COMPILER_RT_CAN_EXECUTE_TESTS AND MSAN_CAN_INSTRUMENT_LIBCXX)
if(CAN_TARGET_x86_64)
add_msan_tests_for_arch(x86_64)
endif()
diff --git a/lib/msan/tests/msan_test.cc b/lib/msan/tests/msan_test.cc
index 1e05382e4b9f..f95bb4e7c618 100644
--- a/lib/msan/tests/msan_test.cc
+++ b/lib/msan/tests/msan_test.cc
@@ -19,12 +19,14 @@
#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>
#include <arpa/inet.h>
#include <dlfcn.h>
@@ -33,11 +35,14 @@
#include <link.h>
#include <limits.h>
#include <sys/time.h>
+#include <poll.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/resource.h>
#include <sys/ioctl.h>
+#include <sys/statvfs.h>
+#include <sys/sysinfo.h>
#include <sys/utsname.h>
#include <sys/mman.h>
#include <sys/vfs.h>
@@ -45,6 +50,11 @@
#include <pwd.h>
#include <sys/socket.h>
#include <netdb.h>
+#include <wordexp.h>
+#include <mntent.h>
+#include <netinet/ether.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
#if defined(__i386__) || defined(__x86_64__)
# include <emmintrin.h>
@@ -53,6 +63,8 @@
# define MSAN_HAS_M128 0
#endif
+static const int kPageSize = 4096;
+
typedef unsigned char U1;
typedef unsigned short U2; // NOLINT
typedef unsigned int U4;
@@ -522,12 +534,42 @@ LargeStruct LargeRetTest() {
return res;
}
+TEST(MemorySanitizer, strcmp) {
+ char s1[10];
+ char s2[10];
+ strncpy(s1, "foo", 10);
+ s2[0] = 'f';
+ s2[1] = 'n';
+ EXPECT_GT(strcmp(s1, s2), 0);
+ s2[1] = 'o';
+ int res;
+ EXPECT_UMR(res = strcmp(s1, s2));
+ EXPECT_NOT_POISONED(res);
+ EXPECT_EQ(strncmp(s1, s2, 1), 0);
+}
+
TEST(MemorySanitizer, LargeRet) {
LargeStruct a = LargeRetTest();
EXPECT_POISONED(a.x[0]);
EXPECT_POISONED(a.x[9]);
}
+TEST(MemorySanitizer, strerror) {
+ char *buf = strerror(EINVAL);
+ EXPECT_NOT_POISONED(strlen(buf));
+ buf = strerror(123456);
+ EXPECT_NOT_POISONED(strlen(buf));
+}
+
+TEST(MemorySanitizer, strerror_r) {
+ errno = 0;
+ char buf[1000];
+ char *res = strerror_r(EINVAL, buf, sizeof(buf));
+ ASSERT_EQ(0, errno);
+ if (!res) res = buf; // POSIX version success.
+ EXPECT_NOT_POISONED(strlen(res));
+}
+
TEST(MemorySanitizer, fread) {
char *x = new char[32];
FILE *f = fopen("/proc/self/stat", "r");
@@ -566,6 +608,52 @@ TEST(MemorySanitizer, pread) {
delete x;
}
+TEST(MemorySanitizer, readv) {
+ char buf[2011];
+ struct iovec iov[2];
+ iov[0].iov_base = buf + 1;
+ iov[0].iov_len = 5;
+ iov[1].iov_base = buf + 10;
+ iov[1].iov_len = 2000;
+ int fd = open("/proc/self/stat", O_RDONLY);
+ assert(fd > 0);
+ int sz = readv(fd, iov, 2);
+ ASSERT_LT(sz, 5 + 2000);
+ ASSERT_GT(sz, iov[0].iov_len);
+ EXPECT_POISONED(buf[0]);
+ EXPECT_NOT_POISONED(buf[1]);
+ EXPECT_NOT_POISONED(buf[5]);
+ EXPECT_POISONED(buf[6]);
+ EXPECT_POISONED(buf[9]);
+ EXPECT_NOT_POISONED(buf[10]);
+ EXPECT_NOT_POISONED(buf[10 + (sz - 1) - 5]);
+ EXPECT_POISONED(buf[11 + (sz - 1) - 5]);
+ close(fd);
+}
+
+TEST(MemorySanitizer, preadv) {
+ char buf[2011];
+ struct iovec iov[2];
+ iov[0].iov_base = buf + 1;
+ iov[0].iov_len = 5;
+ iov[1].iov_base = buf + 10;
+ iov[1].iov_len = 2000;
+ int fd = open("/proc/self/stat", O_RDONLY);
+ assert(fd > 0);
+ int sz = preadv(fd, iov, 2, 3);
+ ASSERT_LT(sz, 5 + 2000);
+ ASSERT_GT(sz, iov[0].iov_len);
+ EXPECT_POISONED(buf[0]);
+ EXPECT_NOT_POISONED(buf[1]);
+ EXPECT_NOT_POISONED(buf[5]);
+ EXPECT_POISONED(buf[6]);
+ EXPECT_POISONED(buf[9]);
+ EXPECT_NOT_POISONED(buf[10]);
+ EXPECT_NOT_POISONED(buf[10 + (sz - 1) - 5]);
+ EXPECT_POISONED(buf[11 + (sz - 1) - 5]);
+ close(fd);
+}
+
// FIXME: fails now.
TEST(MemorySanitizer, DISABLED_ioctl) {
struct winsize ws;
@@ -590,13 +678,47 @@ TEST(MemorySanitizer, stat) {
EXPECT_NOT_POISONED(st->st_size);
}
+TEST(MemorySanitizer, fstatat) {
+ struct stat* st = new struct stat;
+ int dirfd = open("/proc/self", O_RDONLY);
+ assert(dirfd > 0);
+ int res = fstatat(dirfd, "stat", st, 0);
+ assert(!res);
+ EXPECT_NOT_POISONED(st->st_dev);
+ EXPECT_NOT_POISONED(st->st_mode);
+ EXPECT_NOT_POISONED(st->st_size);
+ close(dirfd);
+}
+
TEST(MemorySanitizer, statfs) {
- struct statfs* st = new struct statfs;
- int res = statfs("/", st);
+ struct statfs st;
+ int res = statfs("/", &st);
assert(!res);
- EXPECT_NOT_POISONED(st->f_type);
- EXPECT_NOT_POISONED(st->f_bfree);
- EXPECT_NOT_POISONED(st->f_namelen);
+ EXPECT_NOT_POISONED(st.f_type);
+ EXPECT_NOT_POISONED(st.f_bfree);
+ EXPECT_NOT_POISONED(st.f_namelen);
+}
+
+TEST(MemorySanitizer, statvfs) {
+ struct statvfs st;
+ int res = statvfs("/", &st);
+ assert(!res);
+ EXPECT_NOT_POISONED(st.f_bsize);
+ EXPECT_NOT_POISONED(st.f_blocks);
+ EXPECT_NOT_POISONED(st.f_bfree);
+ EXPECT_NOT_POISONED(st.f_namemax);
+}
+
+TEST(MemorySanitizer, fstatvfs) {
+ struct statvfs st;
+ int fd = open("/", O_RDONLY | O_DIRECTORY);
+ int res = fstatvfs(fd, &st);
+ assert(!res);
+ EXPECT_NOT_POISONED(st.f_bsize);
+ EXPECT_NOT_POISONED(st.f_blocks);
+ EXPECT_NOT_POISONED(st.f_bfree);
+ EXPECT_NOT_POISONED(st.f_namemax);
+ close(fd);
}
TEST(MemorySanitizer, pipe) {
@@ -629,6 +751,70 @@ TEST(MemorySanitizer, socketpair) {
close(sv[1]);
}
+TEST(MemorySanitizer, poll) {
+ int* pipefd = new int[2];
+ int res = pipe(pipefd);
+ ASSERT_EQ(0, res);
+
+ char data = 42;
+ res = write(pipefd[1], &data, 1);
+ ASSERT_EQ(1, res);
+
+ pollfd fds[2];
+ fds[0].fd = pipefd[0];
+ fds[0].events = POLLIN;
+ fds[1].fd = pipefd[1];
+ fds[1].events = POLLIN;
+ res = poll(fds, 2, 500);
+ ASSERT_EQ(1, res);
+ EXPECT_NOT_POISONED(fds[0].revents);
+ EXPECT_NOT_POISONED(fds[1].revents);
+
+ close(pipefd[0]);
+ close(pipefd[1]);
+}
+
+TEST(MemorySanitizer, ppoll) {
+ int* pipefd = new int[2];
+ int res = pipe(pipefd);
+ ASSERT_EQ(0, res);
+
+ char data = 42;
+ res = write(pipefd[1], &data, 1);
+ ASSERT_EQ(1, res);
+
+ pollfd fds[2];
+ fds[0].fd = pipefd[0];
+ fds[0].events = POLLIN;
+ fds[1].fd = pipefd[1];
+ fds[1].events = POLLIN;
+ sigset_t ss;
+ sigemptyset(&ss);
+ res = ppoll(fds, 2, NULL, &ss);
+ ASSERT_EQ(1, res);
+ EXPECT_NOT_POISONED(fds[0].revents);
+ EXPECT_NOT_POISONED(fds[1].revents);
+
+ close(pipefd[0]);
+ close(pipefd[1]);
+}
+
+TEST(MemorySanitizer, poll_positive) {
+ int* pipefd = new int[2];
+ int res = pipe(pipefd);
+ ASSERT_EQ(0, res);
+
+ pollfd fds[2];
+ fds[0].fd = pipefd[0];
+ fds[0].events = POLLIN;
+ // fds[1].fd uninitialized
+ fds[1].events = POLLIN;
+ EXPECT_UMR(poll(fds, 2, 0));
+
+ close(pipefd[0]);
+ close(pipefd[1]);
+}
+
TEST(MemorySanitizer, bind_getsockname) {
int sock = socket(AF_UNIX, SOCK_STREAM, 0);
@@ -651,6 +837,83 @@ TEST(MemorySanitizer, bind_getsockname) {
close(sock);
}
+TEST(MemorySanitizer, accept) {
+ int listen_socket = socket(AF_INET, SOCK_STREAM, 0);
+ ASSERT_LT(0, listen_socket);
+
+ struct sockaddr_in sai;
+ memset(&sai, 0, sizeof(sai));
+ sai.sin_family = AF_INET;
+ sai.sin_port = 0;
+ sai.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ int res = bind(listen_socket, (struct sockaddr *)&sai, sizeof(sai));
+ ASSERT_EQ(0, res);
+
+ res = listen(listen_socket, 1);
+ ASSERT_EQ(0, res);
+
+ socklen_t sz = sizeof(sai);
+ res = getsockname(listen_socket, (struct sockaddr *)&sai, &sz);
+ ASSERT_EQ(0, res);
+ ASSERT_EQ(sizeof(sai), sz);
+
+ int connect_socket = socket(AF_INET, SOCK_STREAM, 0);
+ ASSERT_LT(0, connect_socket);
+ res = fcntl(connect_socket, F_SETFL, O_NONBLOCK);
+ ASSERT_EQ(0, res);
+ res = connect(connect_socket, (struct sockaddr *)&sai, sizeof(sai));
+ ASSERT_EQ(-1, res);
+ ASSERT_EQ(EINPROGRESS, errno);
+
+ __msan_poison(&sai, sizeof(sai));
+ int new_sock = accept(listen_socket, (struct sockaddr *)&sai, &sz);
+ ASSERT_LT(0, new_sock);
+ ASSERT_EQ(sizeof(sai), sz);
+ EXPECT_NOT_POISONED(sai);
+
+ __msan_poison(&sai, sizeof(sai));
+ res = getpeername(new_sock, (struct sockaddr *)&sai, &sz);
+ ASSERT_EQ(0, res);
+ ASSERT_EQ(sizeof(sai), sz);
+ EXPECT_NOT_POISONED(sai);
+
+ close(new_sock);
+ close(connect_socket);
+ close(listen_socket);
+}
+
+TEST(MemorySanitizer, getaddrinfo) {
+ struct addrinfo *ai;
+ struct addrinfo hints;
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_INET;
+ int res = getaddrinfo("localhost", NULL, &hints, &ai);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(*ai);
+ ASSERT_EQ(sizeof(sockaddr_in), ai->ai_addrlen);
+ EXPECT_NOT_POISONED(*(sockaddr_in*)ai->ai_addr);
+}
+
+TEST(MemorySanitizer, getnameinfo) {
+ struct sockaddr_in sai;
+ memset(&sai, 0, sizeof(sai));
+ sai.sin_family = AF_INET;
+ sai.sin_port = 80;
+ sai.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ char host[500];
+ char serv[500];
+ int res = getnameinfo((struct sockaddr *)&sai, sizeof(sai), host,
+ sizeof(host), serv, sizeof(serv), 0);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(host[0]);
+ EXPECT_POISONED(host[sizeof(host) - 1]);
+
+ ASSERT_NE(0, strlen(host));
+ EXPECT_NOT_POISONED(serv[0]);
+ EXPECT_POISONED(serv[sizeof(serv) - 1]);
+ ASSERT_NE(0, strlen(serv));
+}
+
#define EXPECT_HOSTENT_NOT_POISONED(he) \
do { \
EXPECT_NOT_POISONED(*(he)); \
@@ -677,12 +940,87 @@ TEST(MemorySanitizer, gethostent) {
EXPECT_HOSTENT_NOT_POISONED(he);
}
+#ifndef MSAN_TEST_DISABLE_GETHOSTBYNAME
+
TEST(MemorySanitizer, gethostbyname) {
struct hostent *he = gethostbyname("localhost");
ASSERT_NE((void *)NULL, he);
EXPECT_HOSTENT_NOT_POISONED(he);
}
+#endif // MSAN_TEST_DISABLE_GETHOSTBYNAME
+
+TEST(MemorySanitizer, recvmsg) {
+ int server_socket = socket(AF_INET, SOCK_DGRAM, 0);
+ ASSERT_LT(0, server_socket);
+
+ struct sockaddr_in sai;
+ memset(&sai, 0, sizeof(sai));
+ sai.sin_family = AF_INET;
+ sai.sin_port = 0;
+ sai.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ int res = bind(server_socket, (struct sockaddr *)&sai, sizeof(sai));
+ ASSERT_EQ(0, res);
+
+ socklen_t sz = sizeof(sai);
+ res = getsockname(server_socket, (struct sockaddr *)&sai, &sz);
+ ASSERT_EQ(0, res);
+ ASSERT_EQ(sizeof(sai), sz);
+
+
+ int client_socket = socket(AF_INET, SOCK_DGRAM, 0);
+ ASSERT_LT(0, client_socket);
+
+ struct sockaddr_in client_sai;
+ memset(&client_sai, 0, sizeof(client_sai));
+ client_sai.sin_family = AF_INET;
+ client_sai.sin_port = 0;
+ client_sai.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ res = bind(client_socket, (struct sockaddr *)&client_sai, sizeof(client_sai));
+ ASSERT_EQ(0, res);
+
+ sz = sizeof(client_sai);
+ res = getsockname(client_socket, (struct sockaddr *)&client_sai, &sz);
+ ASSERT_EQ(0, res);
+ ASSERT_EQ(sizeof(client_sai), sz);
+
+
+ const char *s = "message text";
+ struct iovec iov;
+ iov.iov_base = (void *)s;
+ iov.iov_len = strlen(s) + 1;
+ struct msghdr msg;
+ memset(&msg, 0, sizeof(msg));
+ msg.msg_name = &sai;
+ msg.msg_namelen = sizeof(sai);
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ res = sendmsg(client_socket, &msg, 0);
+ ASSERT_LT(0, res);
+
+
+ char buf[1000];
+ struct iovec recv_iov;
+ recv_iov.iov_base = (void *)&buf;
+ recv_iov.iov_len = sizeof(buf);
+ struct sockaddr_in recv_sai;
+ struct msghdr recv_msg;
+ memset(&recv_msg, 0, sizeof(recv_msg));
+ recv_msg.msg_name = &recv_sai;
+ recv_msg.msg_namelen = sizeof(recv_sai);
+ recv_msg.msg_iov = &recv_iov;
+ recv_msg.msg_iovlen = 1;
+ res = recvmsg(server_socket, &recv_msg, 0);
+ ASSERT_LT(0, res);
+
+ ASSERT_EQ(sizeof(recv_sai), recv_msg.msg_namelen);
+ EXPECT_NOT_POISONED(*(struct sockaddr_in *)recv_msg.msg_name);
+ EXPECT_STREQ(s, buf);
+
+ close(server_socket);
+ close(client_socket);
+}
+
TEST(MemorySanitizer, gethostbyname2) {
struct hostent *he = gethostbyname2("localhost", AF_INET);
ASSERT_NE((void *)NULL, he);
@@ -778,6 +1116,96 @@ TEST(MemorySanitizer, getcwd_gnu) {
free(res);
}
+TEST(MemorySanitizer, get_current_dir_name) {
+ char* res = get_current_dir_name();
+ assert(res);
+ EXPECT_NOT_POISONED(res[0]);
+ free(res);
+}
+
+TEST(MemorySanitizer, shmctl) {
+ int id = shmget(IPC_PRIVATE, 4096, 0644 | IPC_CREAT);
+ ASSERT_GT(id, -1);
+
+ struct shmid_ds ds;
+ int res = shmctl(id, IPC_STAT, &ds);
+ ASSERT_GT(res, -1);
+ EXPECT_NOT_POISONED(ds);
+
+ struct shminfo si;
+ res = shmctl(id, IPC_INFO, (struct shmid_ds *)&si);
+ ASSERT_GT(res, -1);
+ EXPECT_NOT_POISONED(si);
+
+ struct shm_info s_i;
+ res = shmctl(id, SHM_INFO, (struct shmid_ds *)&s_i);
+ ASSERT_GT(res, -1);
+ EXPECT_NOT_POISONED(s_i);
+
+ res = shmctl(id, IPC_RMID, 0);
+ ASSERT_GT(res, -1);
+}
+
+TEST(MemorySanitizer, shmat) {
+ void *p = mmap(NULL, 4096, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
+ ASSERT_NE(MAP_FAILED, p);
+
+ ((char *)p)[10] = *GetPoisoned<U1>();
+ ((char *)p)[4095] = *GetPoisoned<U1>();
+
+ int res = munmap(p, 4096);
+ ASSERT_EQ(0, res);
+
+ int id = shmget(IPC_PRIVATE, 4096, 0644 | IPC_CREAT);
+ ASSERT_GT(id, -1);
+
+ void *q = shmat(id, p, 0);
+ ASSERT_EQ(p, q);
+
+ EXPECT_NOT_POISONED(((char *)q)[0]);
+ EXPECT_NOT_POISONED(((char *)q)[10]);
+ EXPECT_NOT_POISONED(((char *)q)[4095]);
+
+ res = shmdt(q);
+ ASSERT_EQ(0, res);
+
+ res = shmctl(id, IPC_RMID, 0);
+ ASSERT_GT(res, -1);
+}
+
+TEST(MemorySanitizer, random_r) {
+ int32_t x;
+ char z[64];
+ memset(z, 0, sizeof(z));
+
+ struct random_data buf;
+ memset(&buf, 0, sizeof(buf));
+
+ int res = initstate_r(0, z, sizeof(z), &buf);
+ ASSERT_EQ(0, res);
+
+ res = random_r(&buf, &x);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(x);
+}
+
+TEST(MemorySanitizer, confstr) {
+ char buf[3];
+ size_t res = confstr(_CS_PATH, buf, sizeof(buf));
+ ASSERT_GT(res, sizeof(buf));
+ EXPECT_NOT_POISONED(buf[0]);
+ EXPECT_NOT_POISONED(buf[sizeof(buf) - 1]);
+
+ char buf2[1000];
+ res = confstr(_CS_PATH, buf2, sizeof(buf2));
+ ASSERT_LT(res, sizeof(buf2));
+ EXPECT_NOT_POISONED(buf2[0]);
+ EXPECT_NOT_POISONED(buf2[res - 1]);
+ EXPECT_POISONED(buf2[res]);
+ ASSERT_EQ(res, strlen(buf2) + 1);
+}
+
TEST(MemorySanitizer, readdir) {
DIR *dir = opendir(".");
struct dirent *d = readdir(dir);
@@ -786,6 +1214,17 @@ TEST(MemorySanitizer, readdir) {
closedir(dir);
}
+TEST(MemorySanitizer, readdir_r) {
+ DIR *dir = opendir(".");
+ struct dirent d;
+ struct dirent *pd;
+ int res = readdir_r(dir, &d, &pd);
+ assert(!res);
+ EXPECT_NOT_POISONED(pd);
+ EXPECT_NOT_POISONED(d.d_name[0]);
+ closedir(dir);
+}
+
TEST(MemorySanitizer, realpath) {
const char* relpath = ".";
char path[PATH_MAX + 1];
@@ -794,6 +1233,42 @@ TEST(MemorySanitizer, realpath) {
EXPECT_NOT_POISONED(path[0]);
}
+TEST(MemorySanitizer, realpath_null) {
+ const char* relpath = ".";
+ char* res = realpath(relpath, NULL);
+ printf("%d, %s\n", errno, strerror(errno));
+ assert(res);
+ EXPECT_NOT_POISONED(res[0]);
+ free(res);
+}
+
+TEST(MemorySanitizer, canonicalize_file_name) {
+ const char* relpath = ".";
+ char* res = canonicalize_file_name(relpath);
+ assert(res);
+ EXPECT_NOT_POISONED(res[0]);
+ free(res);
+}
+
+extern char **environ;
+
+TEST(MemorySanitizer, setenv) {
+ setenv("AAA", "BBB", 1);
+ for (char **envp = environ; *envp; ++envp) {
+ EXPECT_NOT_POISONED(*envp);
+ EXPECT_NOT_POISONED(*envp[0]);
+ }
+}
+
+TEST(MemorySanitizer, putenv) {
+ char s[] = "AAA=BBB";
+ putenv(s);
+ for (char **envp = environ; *envp; ++envp) {
+ EXPECT_NOT_POISONED(*envp);
+ EXPECT_NOT_POISONED(*envp[0]);
+ }
+}
+
TEST(MemorySanitizer, memcpy) {
char* x = new char[2];
char* y = new char[2];
@@ -804,6 +1279,35 @@ TEST(MemorySanitizer, memcpy) {
EXPECT_POISONED(y[1]);
}
+void TestUnalignedMemcpy(int left, int right, bool src_is_aligned) {
+ const int sz = 20;
+ char *dst = (char *)malloc(sz);
+ U4 origin = __msan_get_origin(dst);
+
+ char *src = (char *)malloc(sz);
+ 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]);
+
+ 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);
+ }
+ }
+}
+
TEST(MemorySanitizer, memmove) {
char* x = new char[2];
char* y = new char[2];
@@ -814,6 +1318,63 @@ TEST(MemorySanitizer, memmove) {
EXPECT_POISONED(y[1]);
}
+TEST(MemorySanitizer, memccpy_nomatch) {
+ char* x = new char[5];
+ char* y = new char[5];
+ strcpy(x, "abc");
+ memccpy(y, x, 'd', 4);
+ EXPECT_NOT_POISONED(y[0]);
+ EXPECT_NOT_POISONED(y[1]);
+ EXPECT_NOT_POISONED(y[2]);
+ EXPECT_NOT_POISONED(y[3]);
+ EXPECT_POISONED(y[4]);
+ delete[] x;
+ delete[] y;
+}
+
+TEST(MemorySanitizer, memccpy_match) {
+ char* x = new char[5];
+ char* y = new char[5];
+ strcpy(x, "abc");
+ memccpy(y, x, 'b', 4);
+ EXPECT_NOT_POISONED(y[0]);
+ EXPECT_NOT_POISONED(y[1]);
+ EXPECT_POISONED(y[2]);
+ EXPECT_POISONED(y[3]);
+ EXPECT_POISONED(y[4]);
+ delete[] x;
+ delete[] y;
+}
+
+TEST(MemorySanitizer, memccpy_nomatch_positive) {
+ char* x = new char[5];
+ char* y = new char[5];
+ strcpy(x, "abc");
+ EXPECT_UMR(memccpy(y, x, 'd', 5));
+ delete[] x;
+ delete[] y;
+}
+
+TEST(MemorySanitizer, memccpy_match_positive) {
+ char* x = new char[5];
+ char* y = new char[5];
+ x[0] = 'a';
+ x[2] = 'b';
+ EXPECT_UMR(memccpy(y, x, 'b', 5));
+ delete[] x;
+ delete[] y;
+}
+
+TEST(MemorySanitizer, bcopy) {
+ char* x = new char[2];
+ char* y = new char[2];
+ x[0] = 1;
+ x[1] = *GetPoisoned<char>();
+ bcopy(x, y, 2);
+ EXPECT_NOT_POISONED(y[0]);
+ EXPECT_POISONED(y[1]);
+}
+
TEST(MemorySanitizer, strdup) {
char buf[4] = "abc";
__msan_poison(buf + 2, sizeof(*buf));
@@ -896,6 +1457,19 @@ TEST(MemorySanitizer, strncpy) { // NOLINT
EXPECT_POISONED(y[2]);
}
+TEST(MemorySanitizer, stpcpy) { // NOLINT
+ char* x = new char[3];
+ char* y = new char[3];
+ x[0] = 'a';
+ x[1] = *GetPoisoned<char>(1, 1);
+ x[2] = 0;
+ char *res = stpcpy(y, x); // NOLINT
+ ASSERT_EQ(res, y + 2);
+ EXPECT_NOT_POISONED(y[0]);
+ EXPECT_POISONED(y[1]);
+ EXPECT_NOT_POISONED(y[2]);
+}
+
TEST(MemorySanitizer, strtol) {
char *e;
assert(1 == strtol("1", &e, 10));
@@ -920,12 +1494,35 @@ TEST(MemorySanitizer, strtoull) {
EXPECT_NOT_POISONED((S8) e);
}
+TEST(MemorySanitizer, strtoimax) {
+ char *e;
+ assert(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));
EXPECT_NOT_POISONED((S8) e);
}
+#ifdef __GLIBC__
+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);
+}
+#endif // __GLIBC__
+
TEST(MemorySanitizer, strtof) {
char *e;
assert(0 != strtof("1.5", &e));
@@ -938,6 +1535,121 @@ TEST(MemorySanitizer, strtold) {
EXPECT_NOT_POISONED((S8) e);
}
+TEST(MemorySanitizer, modf) {
+ double x, y;
+ x = modf(2.1, &y);
+ EXPECT_NOT_POISONED(y);
+}
+
+TEST(MemorySanitizer, modff) {
+ float x, y;
+ x = modff(2.1, &y);
+ EXPECT_NOT_POISONED(y);
+}
+
+TEST(MemorySanitizer, modfl) {
+ long double x, y;
+ x = modfl(2.1, &y);
+ EXPECT_NOT_POISONED(y);
+}
+
+TEST(MemorySanitizer, sincos) {
+ double s, c;
+ sincos(0.2, &s, &c);
+ EXPECT_NOT_POISONED(s);
+ EXPECT_NOT_POISONED(c);
+}
+
+TEST(MemorySanitizer, sincosf) {
+ float s, c;
+ sincosf(0.2, &s, &c);
+ EXPECT_NOT_POISONED(s);
+ EXPECT_NOT_POISONED(c);
+}
+
+TEST(MemorySanitizer, sincosl) {
+ long double s, c;
+ sincosl(0.2, &s, &c);
+ EXPECT_NOT_POISONED(s);
+ EXPECT_NOT_POISONED(c);
+}
+
+TEST(MemorySanitizer, remquo) {
+ int quo;
+ double res = remquo(29.0, 3.0, &quo);
+ ASSERT_NE(0.0, res);
+ EXPECT_NOT_POISONED(quo);
+}
+
+TEST(MemorySanitizer, remquof) {
+ int quo;
+ float res = remquof(29.0, 3.0, &quo);
+ ASSERT_NE(0.0, res);
+ EXPECT_NOT_POISONED(quo);
+}
+
+TEST(MemorySanitizer, remquol) {
+ int quo;
+ long double res = remquof(29.0, 3.0, &quo);
+ ASSERT_NE(0.0, res);
+ EXPECT_NOT_POISONED(quo);
+}
+
+TEST(MemorySanitizer, lgamma) {
+ double res = lgamma(1.1);
+ ASSERT_NE(0.0, res);
+ EXPECT_NOT_POISONED(signgam);
+}
+
+TEST(MemorySanitizer, lgammaf) {
+ float res = lgammaf(1.1);
+ ASSERT_NE(0.0, res);
+ EXPECT_NOT_POISONED(signgam);
+}
+
+TEST(MemorySanitizer, lgammal) {
+ long double res = lgammal(1.1);
+ ASSERT_NE(0.0, res);
+ EXPECT_NOT_POISONED(signgam);
+}
+
+TEST(MemorySanitizer, lgamma_r) {
+ int sgn;
+ double res = lgamma_r(1.1, &sgn);
+ ASSERT_NE(0.0, res);
+ EXPECT_NOT_POISONED(sgn);
+}
+
+TEST(MemorySanitizer, lgammaf_r) {
+ int sgn;
+ float res = lgammaf_r(1.1, &sgn);
+ ASSERT_NE(0.0, res);
+ EXPECT_NOT_POISONED(sgn);
+}
+
+TEST(MemorySanitizer, lgammal_r) {
+ int sgn;
+ long double res = lgammal_r(1.1, &sgn);
+ ASSERT_NE(0.0, res);
+ EXPECT_NOT_POISONED(sgn);
+}
+
+TEST(MemorySanitizer, drand48_r) {
+ struct drand48_data buf;
+ srand48_r(0, &buf);
+ double d;
+ drand48_r(&buf, &d);
+ EXPECT_NOT_POISONED(d);
+}
+
+TEST(MemorySanitizer, lrand48_r) {
+ struct drand48_data buf;
+ srand48_r(0, &buf);
+ long d;
+ lrand48_r(&buf, &d);
+ EXPECT_NOT_POISONED(d);
+}
+
TEST(MemorySanitizer, sprintf) { // NOLINT
char buff[10];
break_optimization(buff);
@@ -981,6 +1693,33 @@ TEST(MemorySanitizer, swprintf) {
EXPECT_POISONED(buff[8]);
}
+TEST(MemorySanitizer, asprintf) { // NOLINT
+ char *pbuf;
+ EXPECT_POISONED(pbuf);
+ int res = asprintf(&pbuf, "%d", 1234567); // NOLINT
+ assert(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);
+ free(pbuf);
+}
+
+TEST(MemorySanitizer, mbstowcs) {
+ const char *x = "abc";
+ wchar_t buff[10];
+ int res = mbstowcs(buff, x, 2);
+ EXPECT_EQ(2, res);
+ EXPECT_EQ(L'a', buff[0]);
+ EXPECT_EQ(L'b', buff[1]);
+ EXPECT_POISONED(buff[2]);
+ res = mbstowcs(buff, x, 10);
+ EXPECT_EQ(3, res);
+ EXPECT_NOT_POISONED(buff[3]);
+}
+
TEST(MemorySanitizer, wcstombs) {
const wchar_t *x = L"abc";
char buff[10];
@@ -991,6 +1730,52 @@ TEST(MemorySanitizer, wcstombs) {
EXPECT_EQ(buff[2], 'c');
}
+TEST(MemorySanitizer, wcsrtombs) {
+ const wchar_t *x = L"abc";
+ const wchar_t *p = x;
+ char buff[10];
+ mbstate_t mbs;
+ memset(&mbs, 0, sizeof(mbs));
+ int res = wcsrtombs(buff, &p, 4, &mbs);
+ EXPECT_EQ(res, 3);
+ EXPECT_EQ(buff[0], 'a');
+ EXPECT_EQ(buff[1], 'b');
+ EXPECT_EQ(buff[2], 'c');
+ EXPECT_EQ(buff[3], '\0');
+ EXPECT_POISONED(buff[4]);
+}
+
+TEST(MemorySanitizer, wcsnrtombs) {
+ const wchar_t *x = L"abc";
+ const wchar_t *p = x;
+ char buff[10];
+ mbstate_t mbs;
+ memset(&mbs, 0, sizeof(mbs));
+ int res = wcsnrtombs(buff, &p, 2, 4, &mbs);
+ EXPECT_EQ(res, 2);
+ EXPECT_EQ(buff[0], 'a');
+ EXPECT_EQ(buff[1], 'b');
+ EXPECT_POISONED(buff[2]);
+}
+
+TEST(MemorySanitizer, mbtowc) {
+ const char *x = "abc";
+ wchar_t wx;
+ int res = mbtowc(&wx, x, 3);
+ EXPECT_GT(res, 0);
+ EXPECT_NOT_POISONED(wx);
+}
+
+TEST(MemorySanitizer, mbrtowc) {
+ const char *x = "abc";
+ wchar_t wx;
+ mbstate_t mbs;
+ memset(&mbs, 0, sizeof(mbs));
+ int res = mbrtowc(&wx, x, 3, &mbs);
+ EXPECT_GT(res, 0);
+ EXPECT_NOT_POISONED(wx);
+}
+
TEST(MemorySanitizer, gettimeofday) {
struct timeval tv;
struct timezone tz;
@@ -1060,6 +1845,13 @@ TEST(MemorySanitizer, getitimer) {
assert(!res);
}
+TEST(MemorySanitizer, setitimer_null) {
+ setitimer(ITIMER_VIRTUAL, 0, 0);
+ // Not testing the return value, since it the behaviour seems to differ
+ // between libc implementations and POSIX.
+ // Should never crash, though.
+}
+
TEST(MemorySanitizer, time) {
time_t t;
EXPECT_POISONED(t);
@@ -1068,6 +1860,15 @@ TEST(MemorySanitizer, time) {
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);
+ EXPECT_NOT_POISONED(time.tm_sec);
+ EXPECT_NOT_POISONED(time.tm_hour);
+ EXPECT_NOT_POISONED(time.tm_year);
+}
+
TEST(MemorySanitizer, localtime) {
time_t t = 123;
struct tm *time = localtime(&t);
@@ -1076,6 +1877,7 @@ TEST(MemorySanitizer, localtime) {
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));
}
TEST(MemorySanitizer, localtime_r) {
@@ -1087,6 +1889,54 @@ TEST(MemorySanitizer, localtime_r) {
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));
+}
+
+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));
+ EXPECT_NOT_POISONED(mnt->mnt_freq);
+ EXPECT_NOT_POISONED(mnt->mnt_passno);
+ fclose(fp);
+}
+
+TEST(MemorySanitizer, getmntent_r) {
+ FILE *fp = setmntent("/etc/fstab", "r");
+ struct mntent mntbuf;
+ char buf[1000];
+ struct mntent *mnt = getmntent_r(fp, &mntbuf, buf, sizeof(buf));
+ ASSERT_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));
+ EXPECT_NOT_POISONED(mnt->mnt_freq);
+ EXPECT_NOT_POISONED(mnt->mnt_passno);
+ fclose(fp);
+}
+
+TEST(MemorySanitizer, ether) {
+ const char *asc = "11:22:33:44:55:66";
+ struct ether_addr *paddr = ether_aton(asc);
+ EXPECT_NOT_POISONED(*paddr);
+
+ struct ether_addr addr;
+ paddr = ether_aton_r(asc, &addr);
+ ASSERT_EQ(paddr, &addr);
+ EXPECT_NOT_POISONED(addr);
+
+ char *s = ether_ntoa(&addr);
+ ASSERT_NE(0, strlen(s));
+
+ char buf[100];
+ s = ether_ntoa_r(&addr, buf);
+ ASSERT_EQ(s, buf);
+ ASSERT_NE(0, strlen(buf));
}
TEST(MemorySanitizer, mmap) {
@@ -1201,6 +2051,39 @@ TEST(MemorySanitizer, sigaction) {
} // namespace
+
+TEST(MemorySanitizer, sigemptyset) {
+ sigset_t s;
+ EXPECT_POISONED(s);
+ int res = sigemptyset(&s);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(s);
+}
+
+TEST(MemorySanitizer, sigfillset) {
+ sigset_t s;
+ EXPECT_POISONED(s);
+ int res = sigfillset(&s);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(s);
+}
+
+TEST(MemorySanitizer, sigpending) {
+ sigset_t s;
+ EXPECT_POISONED(s);
+ int res = sigpending(&s);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(s);
+}
+
+TEST(MemorySanitizer, sigprocmask) {
+ sigset_t s;
+ EXPECT_POISONED(s);
+ int res = sigprocmask(SIG_BLOCK, 0, &s);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(s);
+}
+
struct StructWithDtor {
~StructWithDtor();
};
@@ -1392,22 +2275,33 @@ TEST(MemorySanitizer, VAArgOverflow) {
static void vaargsfn_tlsoverwrite2(int guard, ...) {
va_list vl;
va_start(vl, guard);
- EXPECT_NOT_POISONED(va_arg(vl, int));
+ for (int i = 0; i < 20; ++i)
+ EXPECT_NOT_POISONED(va_arg(vl, int));
va_end(vl);
}
static void vaargsfn_tlsoverwrite(int guard, ...) {
// This call will overwrite TLS contents unless it's backed up somewhere.
- vaargsfn_tlsoverwrite2(2, 42);
+ vaargsfn_tlsoverwrite2(2,
+ 42, 42, 42, 42, 42,
+ 42, 42, 42, 42, 42,
+ 42, 42, 42, 42, 42,
+ 42, 42, 42, 42, 42); // 20x
va_list vl;
va_start(vl, guard);
- EXPECT_POISONED(va_arg(vl, int));
+ for (int i = 0; i < 20; ++i)
+ EXPECT_POISONED(va_arg(vl, int));
va_end(vl);
}
TEST(MemorySanitizer, VAArgTLSOverwrite) {
int* x = GetPoisoned<int>();
- vaargsfn_tlsoverwrite(1, *x);
+ vaargsfn_tlsoverwrite(1,
+ *x, *x, *x, *x, *x,
+ *x, *x, *x, *x, *x,
+ *x, *x, *x, *x, *x,
+ *x, *x, *x, *x, *x); // 20x
+
}
struct StructByVal {
@@ -1616,18 +2510,6 @@ extern char *program_invocation_name;
# error "TODO: port this"
#endif
-// Compute the path to our loadable DSO. We assume it's in the same
-// directory. Only use string routines that we intercept so far to do this.
-static int PathToLoadable(char *buf, size_t sz) {
- const char *basename = "libmsan_loadable.x86_64.so";
- char *argv0 = program_invocation_name;
- char *last_slash = strrchr(argv0, '/');
- assert(last_slash);
- int res =
- snprintf(buf, sz, "%.*s/%s", int(last_slash - argv0), argv0, basename);
- return res < sz ? 0 : res;
-}
-
static void dladdr_testfn() {}
TEST(MemorySanitizer, dladdr) {
@@ -1645,6 +2527,8 @@ TEST(MemorySanitizer, dladdr) {
EXPECT_NOT_POISONED((unsigned long)info.dli_saddr);
}
+#ifndef MSAN_TEST_DISABLE_DLOPEN
+
static int dl_phdr_callback(struct dl_phdr_info *info, size_t size, void *data) {
(*(int *)data)++;
EXPECT_NOT_POISONED(info->dlpi_addr);
@@ -1655,6 +2539,18 @@ static int dl_phdr_callback(struct dl_phdr_info *info, size_t size, void *data)
return 0;
}
+// Compute the path to our loadable DSO. We assume it's in the same
+// directory. Only use string routines that we intercept so far to do this.
+static int PathToLoadable(char *buf, size_t sz) {
+ const char *basename = "libmsan_loadable.x86_64.so";
+ char *argv0 = program_invocation_name;
+ char *last_slash = strrchr(argv0, '/');
+ assert(last_slash);
+ int res =
+ snprintf(buf, sz, "%.*s/%s", int(last_slash - argv0), argv0, basename);
+ return res < sz ? 0 : res;
+}
+
TEST(MemorySanitizer, dl_iterate_phdr) {
char path[4096];
int res = PathToLoadable(path, sizeof(path));
@@ -1706,6 +2602,15 @@ TEST(MemorySanitizer, dlopenFailed) {
ASSERT_EQ(0, lib);
}
+#endif // MSAN_TEST_DISABLE_DLOPEN
+
+TEST(MemorySanitizer, sched_getaffinity) {
+ cpu_set_t mask;
+ int res = sched_getaffinity(getpid(), sizeof(mask), &mask);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(mask);
+}
+
TEST(MemorySanitizer, scanf) {
const char *input = "42 hello";
int* d = new int;
@@ -1737,8 +2642,7 @@ TEST(MemorySanitizer, SimpleThread) {
EXPECT_NOT_POISONED(t);
res = pthread_join(t, &p);
assert(!res);
- if (!__msan_has_dynamic_component()) // FIXME: intercept pthread_join (?).
- __msan_unpoison(&p, sizeof(p));
+ EXPECT_NOT_POISONED(p);
delete (int*)p;
}
@@ -1783,6 +2687,71 @@ TEST(MemorySanitizer, PreAllocatedStackThread) {
ASSERT_EQ(0, res);
}
+TEST(MemorySanitizer, pthread_attr_get) {
+ pthread_attr_t attr;
+ int res;
+ res = pthread_attr_init(&attr);
+ ASSERT_EQ(0, res);
+ {
+ int v;
+ res = pthread_attr_getdetachstate(&attr, &v);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(v);
+ }
+ {
+ size_t v;
+ res = pthread_attr_getguardsize(&attr, &v);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(v);
+ }
+ {
+ struct sched_param v;
+ res = pthread_attr_getschedparam(&attr, &v);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(v);
+ }
+ {
+ int v;
+ res = pthread_attr_getschedpolicy(&attr, &v);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(v);
+ }
+ {
+ int v;
+ res = pthread_attr_getinheritsched(&attr, &v);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(v);
+ }
+ {
+ int v;
+ res = pthread_attr_getscope(&attr, &v);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(v);
+ }
+ {
+ size_t v;
+ res = pthread_attr_getstacksize(&attr, &v);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(v);
+ }
+ {
+ void *v;
+ size_t w;
+ res = pthread_attr_getstack(&attr, &v, &w);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(v);
+ EXPECT_NOT_POISONED(w);
+ }
+ {
+ cpu_set_t v;
+ res = pthread_attr_getaffinity_np(&attr, sizeof(v), &v);
+ ASSERT_EQ(0, res);
+ EXPECT_NOT_POISONED(v);
+ }
+ res = pthread_attr_destroy(&attr);
+ ASSERT_EQ(0, res);
+}
+
TEST(MemorySanitizer, pthread_getschedparam) {
int policy;
struct sched_param param;
@@ -1792,12 +2761,105 @@ TEST(MemorySanitizer, pthread_getschedparam) {
EXPECT_NOT_POISONED(param.sched_priority);
}
+TEST(MemorySanitizer, pthread_key_create) {
+ pthread_key_t key;
+ int res = pthread_key_create(&key, NULL);
+ assert(!res);
+ EXPECT_NOT_POISONED(key);
+ res = pthread_key_delete(key);
+ assert(!res);
+}
+
+namespace {
+struct SignalCondArg {
+ pthread_cond_t* cond;
+ pthread_mutex_t* mu;
+ bool broadcast;
+};
+
+void *SignalCond(void *param) {
+ SignalCondArg *arg = reinterpret_cast<SignalCondArg *>(param);
+ pthread_mutex_lock(arg->mu);
+ if (arg->broadcast)
+ pthread_cond_broadcast(arg->cond);
+ else
+ pthread_cond_signal(arg->cond);
+ pthread_mutex_unlock(arg->mu);
+ return 0;
+}
+} // namespace
+
+TEST(MemorySanitizer, pthread_cond_wait) {
+ pthread_cond_t cond;
+ pthread_mutex_t mu;
+ SignalCondArg args = {&cond, &mu, false};
+ pthread_cond_init(&cond, 0);
+ pthread_mutex_init(&mu, 0);
+ pthread_mutex_lock(&mu);
+
+ // signal
+ pthread_t thr;
+ pthread_create(&thr, 0, SignalCond, &args);
+ int res = pthread_cond_wait(&cond, &mu);
+ assert(!res);
+ pthread_join(thr, 0);
+
+ // broadcast
+ args.broadcast = true;
+ pthread_create(&thr, 0, SignalCond, &args);
+ res = pthread_cond_wait(&cond, &mu);
+ assert(!res);
+ pthread_join(thr, 0);
+
+ pthread_mutex_unlock(&mu);
+ pthread_mutex_destroy(&mu);
+ pthread_cond_destroy(&cond);
+}
+
+TEST(MemorySanitizer, tmpnam) {
+ char s[L_tmpnam];
+ char *res = tmpnam(s);
+ ASSERT_EQ(s, res);
+ EXPECT_NOT_POISONED(strlen(res));
+}
+
+TEST(MemorySanitizer, tempnam) {
+ char *res = tempnam(NULL, "zzz");
+ EXPECT_NOT_POISONED(strlen(res));
+ free(res);
+}
+
TEST(MemorySanitizer, posix_memalign) {
void *p;
EXPECT_POISONED(p);
int res = posix_memalign(&p, 4096, 13);
ASSERT_EQ(0, res);
EXPECT_NOT_POISONED(p);
+ EXPECT_EQ(0U, (uintptr_t)p % 4096);
+ free(p);
+}
+
+TEST(MemorySanitizer, memalign) {
+ void *p = memalign(4096, 13);
+ EXPECT_EQ(0U, (uintptr_t)p % kPageSize);
+ free(p);
+}
+
+TEST(MemorySanitizer, valloc) {
+ void *a = valloc(100);
+ EXPECT_EQ(0U, (uintptr_t)a % kPageSize);
+ free(a);
+}
+
+TEST(MemorySanitizer, pvalloc) {
+ void *p = pvalloc(kPageSize + 100);
+ EXPECT_EQ(0U, (uintptr_t)p % kPageSize);
+ EXPECT_EQ(2 * kPageSize, __msan_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));
free(p);
}
@@ -1816,6 +2878,15 @@ TEST(MemorySanitizer, inet_pton) {
EXPECT_NOT_POISONED(s_out[3]);
}
+TEST(MemorySanitizer, inet_aton) {
+ const char *s = "127.0.0.1";
+ struct in_addr in[2];
+ int res = inet_aton(s, in);
+ ASSERT_NE(0, res);
+ EXPECT_NOT_POISONED(in[0]);
+ EXPECT_POISONED(*(char *)(in + 1));
+}
+
TEST(MemorySanitizer, uname) {
struct utsname u;
int res = uname(&u);
@@ -1834,6 +2905,13 @@ TEST(MemorySanitizer, gethostname) {
EXPECT_NOT_POISONED(strlen(buf));
}
+TEST(MemorySanitizer, sysinfo) {
+ struct sysinfo info;
+ int res = sysinfo(&info);
+ assert(!res);
+ EXPECT_NOT_POISONED(info);
+}
+
TEST(MemorySanitizer, getpwuid) {
struct passwd *p = getpwuid(0); // root
assert(p);
@@ -1880,6 +2958,25 @@ TEST(MemorySanitizer, getgrnam_r) {
EXPECT_NOT_POISONED(grp.gr_gid);
}
+TEST(MemorySanitizer, getgroups) {
+ int n = getgroups(0, 0);
+ gid_t *gids = new gid_t[n];
+ int res = getgroups(n, gids);
+ ASSERT_EQ(n, res);
+ for (int i = 0; i < n; ++i)
+ EXPECT_NOT_POISONED(gids[i]);
+}
+
+TEST(MemorySanitizer, wordexp) {
+ wordexp_t w;
+ int res = wordexp("a b c", &w, 0);
+ ASSERT_EQ(0, res);
+ ASSERT_EQ(3, w.we_wordc);
+ ASSERT_STREQ("a", w.we_wordv[0]);
+ ASSERT_STREQ("b", w.we_wordv[1]);
+ ASSERT_STREQ("c", w.we_wordv[2]);
+}
+
template<class T>
static bool applySlt(T value, T shadow) {
__msan_partial_poison(&value, &shadow, sizeof(T));
@@ -1986,6 +3083,83 @@ TEST(MemorySanitizer, VolatileBitfield) {
EXPECT_POISONED((unsigned)S->y);
}
+TEST(MemorySanitizer, UnalignedLoad) {
+ char x[32];
+ 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));
+}
+
+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]);
+ EXPECT_NOT_POISONED(x[2]);
+ EXPECT_POISONED(x[3]);
+ EXPECT_POISONED(x[4]);
+}
+
+TEST(MemorySanitizer, UnalignedStore32) {
+ char x[8];
+ U4 y4 = 0;
+ __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]);
+ EXPECT_NOT_POISONED(x[5]);
+ EXPECT_NOT_POISONED(x[6]);
+ EXPECT_POISONED(x[7]);
+}
+
+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]);
+ EXPECT_NOT_POISONED(x[6]);
+ EXPECT_NOT_POISONED(x[7]);
+ EXPECT_NOT_POISONED(x[8]);
+ EXPECT_POISONED(x[9]);
+ EXPECT_NOT_POISONED(x[10]);
+ EXPECT_POISONED(x[11]);
+}
+
TEST(MemorySanitizerDr, StoreInDSOTest) {
if (!__msan_has_dynamic_component()) return;
char* s = new char[10];
@@ -2181,6 +3355,7 @@ void MemCpyTest() {
T *x = new T[N];
T *y = new T[N];
T *z = new T[N];
+ T *q = new T[N];
__msan_poison(x, N * sizeof(T));
__msan_set_origin(x, N * sizeof(T), ox);
__msan_set_origin(y, N * sizeof(T), 777777);
@@ -2191,6 +3366,12 @@ void MemCpyTest() {
EXPECT_POISONED_O(y[N/2], ox);
EXPECT_POISONED_O(y[N-1], ox);
EXPECT_NOT_POISONED(x);
+ void *res = mempcpy(q, x, N * sizeof(T));
+ ASSERT_EQ(q + N, res);
+ EXPECT_POISONED_O(q[0], ox);
+ EXPECT_POISONED_O(q[N/2], ox);
+ EXPECT_POISONED_O(q[N-1], ox);
+ EXPECT_NOT_POISONED(x);
memmove(z, x, N * sizeof(T));
EXPECT_POISONED_O(z[0], ox);
EXPECT_POISONED_O(z[N/2], ox);
@@ -2325,14 +3506,56 @@ NOINLINE void RecursiveMalloc(int depth) {
delete x2;
}
-TEST(MemorySanitizer, CallocOverflow) {
- size_t kArraySize = 4096;
- volatile size_t kMaxSizeT = std::numeric_limits<size_t>::max();
- volatile size_t kArraySize2 = kMaxSizeT / kArraySize + 10;
- void *p = calloc(kArraySize, kArraySize2); // Should return 0.
- EXPECT_EQ(0L, Ident(p));
+TEST(MemorySanitizer, Select) {
+ int x;
+ int volatile* p = &x;
+ int z = *p ? 1 : 0;
+ EXPECT_POISONED(z);
}
TEST(MemorySanitizerStress, DISABLED_MallocStackTrace) {
RecursiveMalloc(22);
}
+
+TEST(MemorySanitizerAllocator, get_estimated_allocated_size) {
+ size_t sizes[] = {0, 20, 5000, 1<<20};
+ for (size_t i = 0; i < sizeof(sizes) / sizeof(*sizes); ++i) {
+ size_t alloc_size = __msan_get_estimated_allocated_size(sizes[i]);
+ EXPECT_EQ(alloc_size, sizes[i]);
+ }
+}
+
+TEST(MemorySanitizerAllocator, get_allocated_size_and_ownership) {
+ char *array = reinterpret_cast<char*>(malloc(100));
+ int *int_ptr = new int;
+
+ EXPECT_TRUE(__msan_get_ownership(array));
+ EXPECT_EQ(100, __msan_get_allocated_size(array));
+
+ EXPECT_TRUE(__msan_get_ownership(int_ptr));
+ EXPECT_EQ(sizeof(*int_ptr), __msan_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(__msan_get_ownership(array + 50));
+ EXPECT_EQ(0, __msan_get_allocated_size(array + 50));
+
+ // 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));
+
+ delete int_ptr;
+}
+
+TEST(MemorySanitizer, MlockTest) {
+ EXPECT_EQ(0, mlockall(MCL_CURRENT));
+ EXPECT_EQ(0, mlock((void*)0x12345, 0x5678));
+ EXPECT_EQ(0, munlockall());
+ EXPECT_EQ(0, munlock((void*)0x987, 0x654));
+}
diff --git a/lib/msandr/README.txt b/lib/msandr/README.txt
index b328910c53ba..81a87c694083 100644
--- a/lib/msandr/README.txt
+++ b/lib/msandr/README.txt
@@ -6,7 +6,8 @@ Building:
(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_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)
@@ -31,3 +32,9 @@ 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
index 27b1c9427d9d..6c9d7c675aca 100644
--- a/lib/msandr/msandr.cc
+++ b/lib/msandr/msandr.cc
@@ -60,8 +60,43 @@
#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();
@@ -78,11 +113,6 @@ public:
bool executed_;
};
-std::string g_app_path;
-
-int msan_retval_tls_offset;
-int msan_param_tls_offset;
-
// 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.
@@ -99,19 +129,54 @@ ModuleData::ModuleData(const module_data_t *info)
// 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() {
@@ -217,21 +282,14 @@ void InstrumentMops(void *drcontext, instrlist_t *bb, instr_t *instr, opnd_t op,
}
CHECK(reg_is_pointer_sized(R1)); // otherwise R2 may be wrong.
- // Pick R2 that's not R1 or used by the operand. It's OK if the instr uses
- // R2 elsewhere, since we'll restore it before instr.
- reg_id_t GPR_TO_USE_FOR_R2[] = {
- DR_REG_XAX, DR_REG_XBX, DR_REG_XCX, DR_REG_XDX
- // Don't forget to update the +4 below if you add anything else!
- };
- std::set<reg_id_t> unused_registers(GPR_TO_USE_FOR_R2, GPR_TO_USE_FOR_R2 + 4);
- unused_registers.erase(R1);
- for (int j = 0; j < opnd_num_regs_used(op); j++) {
- unused_registers.erase(opnd_get_reg_used(op, j));
+ // 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(unused_registers.size() > 0);
- reg_id_t R2 = *unused_registers.begin();
- CHECK(R1 != R2);
+ 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);
@@ -241,21 +299,41 @@ void InstrumentMops(void *drcontext, instrlist_t *bb, instr_t *instr, opnd_t op,
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(0xffffbfffffffffff)));
+ 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) {
- PRE(instr,
- mov_st(drcontext, opnd_create_base_disp(R1, DR_REG_NULL, 0, 0, op_size),
- opnd_create_immed_int((ptr_int_t) 0, 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) {
- PRE(instr,
- mov_st(drcontext, OPND_CREATE_MEM32(R1, ofs), OPND_CREATE_INT32(0)));
+ 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)
}
}
@@ -263,6 +341,7 @@ void InstrumentMops(void *drcontext, instrlist_t *bb, instr_t *instr, opnd_t op,
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");
@@ -278,6 +357,18 @@ void InstrumentMops(void *drcontext, instrlist_t *bb, instr_t *instr, opnd_t op,
}
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.
@@ -294,10 +385,27 @@ void InstrumentReturn(void *drcontext, instrlist_t *bb, instr_t *instr) {
// 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.
@@ -306,7 +414,7 @@ void InstrumentIndirectBranch(void *drcontext, instrlist_t *bb,
CHECK(res);
// TODO: unpoison more bytes?
- for (int i = 0; i < 6; ++i) {
+ 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 *)),
@@ -317,8 +425,10 @@ void InstrumentIndirectBranch(void *drcontext, instrlist_t *bb,
// 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) {
@@ -373,22 +483,26 @@ bool ShouldInstrumentPc(app_pc pc, ModuleData **pmod_data) {
}
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))
@@ -411,6 +525,8 @@ dr_emit_flags_t event_basic_block(void *drcontext, void *tag, instrlist_t *bb,
pc - mod_data->start_);
}
}
+#endif /* !MSANDR_NATIVE_EXEC */
+
if (VERBOSITY > 1) {
instrlist_disassemble(drcontext, pc, bb, STDOUT);
instr_t *instr;
@@ -474,6 +590,7 @@ dr_emit_flags_t event_basic_block(void *drcontext, void *tag, instrlist_t *bb,
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.
@@ -507,6 +624,7 @@ void event_module_unload(void *drcontext, const module_data_t *info) {
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.
@@ -514,6 +632,15 @@ void event_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");
}
@@ -551,6 +678,7 @@ bool drsys_iter_memarg_cb(drsys_arg_t *arg, void *user_data) {
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);
@@ -689,6 +817,21 @@ DR_EXPORT void dr_init(client_id_t id) {
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
@@ -719,8 +862,10 @@ DR_EXPORT void dr_init(client_id_t id) {
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/profile/CMakeLists.txt b/lib/profile/CMakeLists.txt
index 641f085c883f..bb4fd9e23a7e 100644
--- a/lib/profile/CMakeLists.txt
+++ b/lib/profile/CMakeLists.txt
@@ -6,11 +6,11 @@ filter_available_targets(PROFILE_SUPPORTED_ARCH x86_64 i386)
if(APPLE)
add_compiler_rt_osx_static_runtime(clang_rt.profile_osx
ARCH ${PROFILE_SUPPORTED_ARCH}
- SOURCES ${PROFILE_SOURCES}
- CFLAGS --sysroot=${COMPILER_RT_DARWIN_SDK_SYSROOT})
+ SOURCES ${PROFILE_SOURCES})
else()
foreach(arch ${PROFILE_SUPPORTED_ARCH})
- add_compiler_rt_static_runtime(clang_rt.profile-${arch} ${arch}
+ add_compiler_rt_static_runtime(clang_rt.profile-${arch}
+ ${arch}
SOURCES ${PROFILE_SOURCES})
endforeach()
endif()
diff --git a/lib/profile/GCDAProfiling.c b/lib/profile/GCDAProfiling.c
index ce1b03c14de7..7edf6829b4a5 100644
--- a/lib/profile/GCDAProfiling.c
+++ b/lib/profile/GCDAProfiling.c
@@ -20,6 +20,7 @@
|*
\*===----------------------------------------------------------------------===*/
+#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
@@ -45,6 +46,11 @@ typedef unsigned int uint64_t;
*/
/*
+ * The current file name we're outputting. Used primarily for error logging.
+ */
+static char *filename = NULL;
+
+/*
* The current file we're outputting.
*/
static FILE *output_file = NULL;
@@ -196,17 +202,37 @@ static void recursive_mkdir(char *filename) {
}
}
-static void map_file() {
+static int map_file() {
fseek(output_file, 0L, SEEK_END);
file_size = ftell(output_file);
+ /* A size of 0 is invalid to `mmap'. Return a fail here, but don't issue an
+ * error message because it should "just work" for the user. */
+ if (file_size == 0)
+ return -1;
+
write_buffer = mmap(0, file_size, PROT_READ | PROT_WRITE,
MAP_FILE | MAP_SHARED, fd, 0);
+ if (write_buffer == (void *)-1) {
+ int errnum = errno;
+ fprintf(stderr, "profiling: %s: cannot map: %s\n", filename,
+ strerror(errnum));
+ return -1;
+ }
+ return 0;
}
static void unmap_file() {
- msync(write_buffer, file_size, MS_SYNC);
- munmap(write_buffer, file_size);
+ if (msync(write_buffer, file_size, MS_SYNC) == -1) {
+ int errnum = errno;
+ fprintf(stderr, "profiling: %s: cannot msync: %s\n", filename,
+ strerror(errnum));
+ }
+
+ /* We explicitly ignore errors from unmapping because at this point the data
+ * is written and we don't care.
+ */
+ (void)munmap(write_buffer, file_size);
write_buffer = NULL;
file_size = 0;
}
@@ -220,8 +246,8 @@ static void unmap_file() {
* started at a time.
*/
void llvm_gcda_start_file(const char *orig_filename, const char version[4]) {
- char *filename = mangle_filename(orig_filename);
const char *mode = "r+b";
+ filename = mangle_filename(orig_filename);
/* Try just opening the file. */
new_file = 0;
@@ -236,10 +262,11 @@ void llvm_gcda_start_file(const char *orig_filename, const char version[4]) {
/* Try creating the directories first then opening the file. */
recursive_mkdir(filename);
fd = open(filename, O_RDWR | O_CREAT, 0644);
- if (!output_file) {
+ if (fd == -1) {
/* Bah! It's hopeless. */
- fprintf(stderr, "profiling:%s: cannot open\n", filename);
- free(filename);
+ int errnum = errno;
+ fprintf(stderr, "profiling: %s: cannot open: %s\n", filename,
+ strerror(errnum));
return;
}
}
@@ -256,7 +283,14 @@ void llvm_gcda_start_file(const char *orig_filename, const char version[4]) {
resize_write_buffer(WRITE_BUFFER_SIZE);
memset(write_buffer, 0, WRITE_BUFFER_SIZE);
} else {
- map_file();
+ if (map_file() == -1) {
+ /* mmap failed, try to recover by clobbering */
+ new_file = 1;
+ write_buffer = NULL;
+ cur_buffer_size = 0;
+ resize_write_buffer(WRITE_BUFFER_SIZE);
+ memset(write_buffer, 0, WRITE_BUFFER_SIZE);
+ }
}
/* gcda file, version, stamp LLVM. */
@@ -264,8 +298,6 @@ void llvm_gcda_start_file(const char *orig_filename, const char version[4]) {
write_bytes(version, 4);
write_bytes("MVLL", 4);
- free(filename);
-
#ifdef DEBUG_GCDAPROFILING
fprintf(stderr, "llvmgcda: [%s]\n", orig_filename);
#endif
@@ -334,7 +366,7 @@ 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 magic number (0x%08x)\n", val);
+ fprintf(stderr, "profiling:invalid arc tag (0x%08x)\n", val);
return;
}
@@ -368,21 +400,72 @@ void llvm_gcda_emit_arcs(uint32_t num_counters, uint64_t *counters) {
#endif
}
-void llvm_gcda_end_file() {
- /* Write out EOF record. */
+void llvm_gcda_summary_info() {
+ const int obj_summary_len = 9; // length for gcov compatibility
+ uint32_t i;
+ uint32_t runs = 1;
+ uint32_t val = 0;
+ uint64_t save_cur_pos = cur_pos;
+
if (!output_file) return;
- write_bytes("\0\0\0\0\0\0\0\0", 8);
- if (new_file) {
- fwrite(write_buffer, cur_pos, 1, output_file);
- free(write_buffer);
- } else {
- unmap_file();
+ val = read_32bit_value();
+
+ 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);
+ return;
+ }
+
+ val = read_32bit_value(); // length
+ if (val != obj_summary_len) {
+ fprintf(stderr, "profiling:invalid object length (%d)\n", val); // length
+ return;
+ }
+
+ read_32bit_value(); // checksum, unused
+ read_32bit_value(); // num, unused
+ runs += read_32bit_value(); // add previous run count to new counter
}
- fclose(output_file);
- output_file = NULL;
- write_buffer = NULL;
+ cur_pos = save_cur_pos;
+
+ /* 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(runs);
+ 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
+
+#ifdef DEBUG_GCDAPROFILING
+ fprintf(stderr, "llvmgcda: %u runs\n", runs);
+#endif
+}
+
+void llvm_gcda_end_file() {
+ /* Write out EOF record. */
+ if (output_file) {
+ write_bytes("\0\0\0\0\0\0\0\0", 8);
+
+ if (new_file) {
+ fwrite(write_buffer, cur_pos, 1, output_file);
+ free(write_buffer);
+ } else {
+ unmap_file();
+ }
+
+ fclose(output_file);
+ output_file = NULL;
+ write_buffer = NULL;
+ }
+ free(filename);
#ifdef DEBUG_GCDAPROFILING
fprintf(stderr, "llvmgcda: -----\n");
diff --git a/lib/sanitizer_common/CMakeLists.txt b/lib/sanitizer_common/CMakeLists.txt
index 2683a37a32ca..84c1e67dc806 100644
--- a/lib/sanitizer_common/CMakeLists.txt
+++ b/lib/sanitizer_common/CMakeLists.txt
@@ -4,47 +4,52 @@
set(SANITIZER_SOURCES
sanitizer_allocator.cc
sanitizer_common.cc
+ sanitizer_coverage.cc
sanitizer_flags.cc
sanitizer_libc.cc
+ sanitizer_libignore.cc
sanitizer_linux.cc
sanitizer_mac.cc
+ sanitizer_platform_limits_linux.cc
sanitizer_platform_limits_posix.cc
sanitizer_posix.cc
sanitizer_printf.cc
sanitizer_stackdepot.cc
sanitizer_stacktrace.cc
- sanitizer_symbolizer_itanium.cc
- sanitizer_symbolizer_mac.cc
+ sanitizer_suppressions.cc
+ sanitizer_symbolizer.cc
sanitizer_symbolizer_win.cc
sanitizer_thread_registry.cc
- sanitizer_win.cc
- )
+ sanitizer_win.cc)
set(SANITIZER_LIBCDEP_SOURCES
sanitizer_common_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_linux_libcdep.cc
- )
+ sanitizer_symbolizer_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_allocator.h
+ sanitizer_allocator_internal.h
sanitizer_atomic_clang.h
sanitizer_atomic_msvc.h
sanitizer_atomic.h
sanitizer_common.h
sanitizer_common_interceptors.inc
+ sanitizer_common_interceptors_ioctl.inc
sanitizer_common_interceptors_scanf.inc
sanitizer_common_syscalls.inc
sanitizer_flags.h
sanitizer_internal_defs.h
sanitizer_lfstack.h
sanitizer_libc.h
+ sanitizer_libignore.h
sanitizer_linux.h
sanitizer_list.h
sanitizer_mutex.h
@@ -56,21 +61,32 @@ set(SANITIZER_HEADERS
sanitizer_stackdepot.h
sanitizer_stacktrace.h
sanitizer_symbolizer.h
- sanitizer_thread_registry.h
- )
+ sanitizer_thread_registry.h)
-set(SANITIZER_CFLAGS
- ${SANITIZER_COMMON_CFLAGS}
- -fno-rtti)
+if (NOT MSVC)
+ set(SANITIZER_CFLAGS
+ ${SANITIZER_COMMON_CFLAGS}
+ -fno-rtti)
+else()
+ set(SANITIZER_CFLAGS
+ ${SANITIZER_COMMON_CFLAGS}
+ /GR-)
+endif()
+
+if(SUPPORTS_GLOBAL_CONSTRUCTORS_FLAG)
+ list(APPEND SANITIZER_CFLAGS -Wglobal-constructors)
+endif()
set(SANITIZER_RUNTIME_LIBRARIES)
if(APPLE)
# Build universal binary on APPLE.
- add_compiler_rt_osx_object_library(RTSanitizerCommon
- ARCH ${SANITIZER_COMMON_SUPPORTED_ARCH}
- SOURCES ${SANITIZER_SOURCES} ${SANITIZER_LIBCDEP_SOURCES}
- CFLAGS ${SANITIZER_CFLAGS})
- list(APPEND SANITIZER_RUNTIME_LIBRARIES RTSanitizerCommon.osx)
+ foreach(os ${SANITIZER_COMMON_SUPPORTED_DARWIN_OS})
+ add_compiler_rt_darwin_object_library(RTSanitizerCommon ${os}
+ ARCH ${SANITIZER_COMMON_SUPPORTED_ARCH}
+ SOURCES ${SANITIZER_SOURCES} ${SANITIZER_LIBCDEP_SOURCES}
+ CFLAGS ${SANITIZER_CFLAGS})
+ list(APPEND SANITIZER_RUNTIME_LIBRARIES RTSanitizerCommon.${os})
+ endforeach()
elseif(ANDROID)
add_library(RTSanitizerCommon.arm.android OBJECT
${SANITIZER_SOURCES} ${SANITIZER_LIBCDEP_SOURCES})
@@ -88,7 +104,8 @@ else()
SOURCES $<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
$<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>
CFLAGS ${SANITIZER_CFLAGS})
- list(APPEND SANITIZER_RUNTIME_LIBRARIES RTSanitizerCommon.${arch})
+ list(APPEND SANITIZER_RUNTIME_LIBRARIES RTSanitizerCommon.${arch}
+ RTSanitizerCommonLibc.${arch})
endforeach()
endif()
diff --git a/lib/sanitizer_common/sanitizer_allocator.cc b/lib/sanitizer_common/sanitizer_allocator.cc
index a97a70937a43..daaf7e1ce055 100644
--- a/lib/sanitizer_common/sanitizer_allocator.cc
+++ b/lib/sanitizer_common/sanitizer_allocator.cc
@@ -9,44 +9,103 @@
//
// This file is shared between AddressSanitizer and ThreadSanitizer
// run-time libraries.
-// This allocator that is used inside run-times.
+// This allocator is used inside run-times.
//===----------------------------------------------------------------------===//
+#include "sanitizer_allocator.h"
+#include "sanitizer_allocator_internal.h"
#include "sanitizer_common.h"
+#include "sanitizer_flags.h"
-// FIXME: We should probably use more low-level allocator that would
-// mmap some pages and split them into chunks to fulfill requests.
-#if SANITIZER_LINUX && !SANITIZER_ANDROID
-extern "C" void *__libc_malloc(__sanitizer::uptr size);
+namespace __sanitizer {
+
+// ThreadSanitizer for Go uses libc malloc/free.
+#if defined(SANITIZER_GO)
+# if SANITIZER_LINUX && !SANITIZER_ANDROID
+extern "C" void *__libc_malloc(uptr size);
extern "C" void __libc_free(void *ptr);
-# define LIBC_MALLOC __libc_malloc
-# define LIBC_FREE __libc_free
-#else // SANITIZER_LINUX && !SANITIZER_ANDROID
-# include <stdlib.h>
-# define LIBC_MALLOC malloc
-# define LIBC_FREE free
-#endif // SANITIZER_LINUX && !SANITIZER_ANDROID
+# define LIBC_MALLOC __libc_malloc
+# define LIBC_FREE __libc_free
+# else
+# include <stdlib.h>
+# define LIBC_MALLOC malloc
+# define LIBC_FREE free
+# endif
-namespace __sanitizer {
+static void *RawInternalAlloc(uptr size, InternalAllocatorCache *cache) {
+ (void)cache;
+ return LIBC_MALLOC(size);
+}
+
+static void RawInternalFree(void *ptr, InternalAllocatorCache *cache) {
+ (void)cache;
+ LIBC_FREE(ptr);
+}
+
+InternalAllocator *internal_allocator() {
+ return 0;
+}
+
+#else // SANITIZER_GO
+
+static ALIGNED(64) char internal_alloc_placeholder[sizeof(InternalAllocator)];
+static atomic_uint8_t internal_allocator_initialized;
+static StaticSpinMutex internal_alloc_init_mu;
+
+static InternalAllocatorCache internal_allocator_cache;
+static StaticSpinMutex internal_allocator_cache_mu;
+
+InternalAllocator *internal_allocator() {
+ InternalAllocator *internal_allocator_instance =
+ reinterpret_cast<InternalAllocator *>(&internal_alloc_placeholder);
+ if (atomic_load(&internal_allocator_initialized, memory_order_acquire) == 0) {
+ SpinMutexLock l(&internal_alloc_init_mu);
+ if (atomic_load(&internal_allocator_initialized, memory_order_relaxed) ==
+ 0) {
+ internal_allocator_instance->Init();
+ atomic_store(&internal_allocator_initialized, 1, memory_order_release);
+ }
+ }
+ return internal_allocator_instance;
+}
+
+static void *RawInternalAlloc(uptr size, InternalAllocatorCache *cache) {
+ if (cache == 0) {
+ SpinMutexLock l(&internal_allocator_cache_mu);
+ return internal_allocator()->Allocate(&internal_allocator_cache, size, 8,
+ false);
+ }
+ return internal_allocator()->Allocate(cache, size, 8, false);
+}
+
+static void RawInternalFree(void *ptr, InternalAllocatorCache *cache) {
+ if (cache == 0) {
+ SpinMutexLock l(&internal_allocator_cache_mu);
+ return internal_allocator()->Deallocate(&internal_allocator_cache, ptr);
+ }
+ internal_allocator()->Deallocate(cache, ptr);
+}
+
+#endif // SANITIZER_GO
const u64 kBlockMagic = 0x6A6CB03ABCEBC041ull;
-void *InternalAlloc(uptr size) {
+void *InternalAlloc(uptr size, InternalAllocatorCache *cache) {
if (size + sizeof(u64) < size)
return 0;
- void *p = LIBC_MALLOC(size + sizeof(u64));
+ void *p = RawInternalAlloc(size + sizeof(u64), cache);
if (p == 0)
return 0;
((u64*)p)[0] = kBlockMagic;
return (char*)p + sizeof(u64);
}
-void InternalFree(void *addr) {
+void InternalFree(void *addr, InternalAllocatorCache *cache) {
if (addr == 0)
return;
addr = (char*)addr - sizeof(u64);
- CHECK_EQ(((u64*)addr)[0], kBlockMagic);
+ CHECK_EQ(kBlockMagic, ((u64*)addr)[0]);
((u64*)addr)[0] = 0;
- LIBC_FREE(addr);
+ RawInternalFree(addr, cache);
}
// LowLevelAllocator
@@ -81,4 +140,14 @@ bool CallocShouldReturnNullDueToOverflow(uptr size, uptr n) {
return (max / size) < n;
}
+void *AllocatorReturnNull() {
+ if (common_flags()->allocator_may_return_null)
+ return 0;
+ Report("%s's allocator is terminating the process instead of returning 0\n",
+ SanitizerToolName);
+ Report("If you don't like this behavior set allocator_may_return_null=1\n");
+ CHECK(0);
+ return 0;
+}
+
} // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_allocator.h b/lib/sanitizer_common/sanitizer_allocator.h
index 0542addb7f37..6075cfe92aac 100644
--- a/lib/sanitizer_common/sanitizer_allocator.h
+++ b/lib/sanitizer_common/sanitizer_allocator.h
@@ -23,6 +23,9 @@
namespace __sanitizer {
+// Depending on allocator_may_return_null either return 0 or crash.
+void *AllocatorReturnNull();
+
// SizeClassMap maps allocation sizes into size classes and back.
// Class 0 corresponds to size 0.
// Classes 1 - 16 correspond to sizes 16 to 256 (size = class_id * 16).
@@ -279,6 +282,9 @@ struct NoOpMapUnmapCallback {
void OnUnmap(uptr p, uptr size) const { }
};
+// Callback type for iterating over chunks.
+typedef void (*ForEachChunkCallback)(uptr chunk, void *arg);
+
// SizeClassAllocator64 -- allocator for 64-bit address space.
//
// Space: a portion of address space of kSpaceSize bytes starting at
@@ -344,15 +350,15 @@ class SizeClassAllocator64 {
region->n_freed += b->count;
}
- static bool PointerIsMine(void *p) {
+ static bool PointerIsMine(const void *p) {
return reinterpret_cast<uptr>(p) / kSpaceSize == kSpaceBeg / kSpaceSize;
}
- static uptr GetSizeClass(void *p) {
+ static uptr GetSizeClass(const void *p) {
return (reinterpret_cast<uptr>(p) / kRegionSize) % kNumClassesRounded;
}
- void *GetBlockBegin(void *p) {
+ void *GetBlockBegin(const void *p) {
uptr class_id = GetSizeClass(p);
uptr size = SizeClassMap::Size(class_id);
if (!size) return 0;
@@ -374,7 +380,7 @@ class SizeClassAllocator64 {
uptr ClassID(uptr size) { return SizeClassMap::ClassID(size); }
- void *GetMetaData(void *p) {
+ void *GetMetaData(const void *p) {
uptr class_id = GetSizeClass(p);
uptr size = SizeClassMap::Size(class_id);
uptr chunk_idx = GetChunkIdx(reinterpret_cast<uptr>(p), size);
@@ -433,20 +439,18 @@ class SizeClassAllocator64 {
}
}
- // Iterate over existing chunks. May include chunks that are not currently
- // allocated to the user (e.g. freed).
- // The caller is expected to call ForceLock() before calling this function.
- template<typename Callable>
- void ForEachChunk(const Callable &callback) {
+ // Iterate over all existing chunks.
+ // The allocator must be locked when calling this function.
+ void ForEachChunk(ForEachChunkCallback callback, void *arg) {
for (uptr class_id = 1; class_id < kNumClasses; class_id++) {
RegionInfo *region = GetRegionInfo(class_id);
uptr chunk_size = SizeClassMap::Size(class_id);
uptr region_beg = kSpaceBeg + class_id * kRegionSize;
- for (uptr p = region_beg;
- p < region_beg + region->allocated_user;
- p += chunk_size) {
- // Too slow: CHECK_EQ((void *)p, GetBlockBegin((void *)p));
- callback((void *)p);
+ for (uptr chunk = region_beg;
+ chunk < region_beg + region->allocated_user;
+ chunk += chunk_size) {
+ // Too slow: CHECK_EQ((void *)chunk, GetBlockBegin((void *)chunk));
+ callback(chunk, arg);
}
}
}
@@ -639,7 +643,7 @@ class SizeClassAllocator32 {
alignment <= SizeClassMap::kMaxSize;
}
- void *GetMetaData(void *p) {
+ void *GetMetaData(const void *p) {
CHECK(PointerIsMine(p));
uptr mem = reinterpret_cast<uptr>(p);
uptr beg = ComputeRegionBeg(mem);
@@ -671,15 +675,15 @@ class SizeClassAllocator32 {
sci->free_list.push_front(b);
}
- bool PointerIsMine(void *p) {
+ bool PointerIsMine(const void *p) {
return GetSizeClass(p) != 0;
}
- uptr GetSizeClass(void *p) {
+ uptr GetSizeClass(const void *p) {
return possible_regions[ComputeRegionId(reinterpret_cast<uptr>(p))];
}
- void *GetBlockBegin(void *p) {
+ void *GetBlockBegin(const void *p) {
CHECK(PointerIsMine(p));
uptr mem = reinterpret_cast<uptr>(p);
uptr beg = ComputeRegionBeg(mem);
@@ -726,21 +730,19 @@ class SizeClassAllocator32 {
}
}
- // Iterate over existing chunks. May include chunks that are not currently
- // allocated to the user (e.g. freed).
- // The caller is expected to call ForceLock() before calling this function.
- template<typename Callable>
- void ForEachChunk(const Callable &callback) {
+ // Iterate over all existing chunks.
+ // The allocator must be locked when calling this function.
+ void ForEachChunk(ForEachChunkCallback callback, void *arg) {
for (uptr region = 0; region < kNumPossibleRegions; region++)
if (possible_regions[region]) {
uptr chunk_size = SizeClassMap::Size(possible_regions[region]);
uptr max_chunks_in_region = kRegionSize / (chunk_size + kMetadataSize);
uptr region_beg = region * kRegionSize;
- for (uptr p = region_beg;
- p < region_beg + max_chunks_in_region * chunk_size;
- p += chunk_size) {
- // Too slow: CHECK_EQ((void *)p, GetBlockBegin((void *)p));
- callback((void *)p);
+ for (uptr chunk = region_beg;
+ chunk < region_beg + max_chunks_in_region * chunk_size;
+ chunk += chunk_size) {
+ // Too slow: CHECK_EQ((void *)chunk, GetBlockBegin((void *)chunk));
+ callback(chunk, arg);
}
}
}
@@ -779,7 +781,7 @@ class SizeClassAllocator32 {
MapUnmapCallback().OnMap(res, kRegionSize);
stat->Add(AllocatorStatMmapped, kRegionSize);
CHECK_EQ(0U, (res & (kRegionSize - 1)));
- possible_regions.set(ComputeRegionId(res), class_id);
+ possible_regions.set(ComputeRegionId(res), static_cast<u8>(class_id));
return res;
}
@@ -942,7 +944,7 @@ class LargeMmapAllocator {
uptr map_size = RoundUpMapSize(size);
if (alignment > page_size_)
map_size += alignment;
- if (map_size < size) return 0; // Overflow.
+ if (map_size < size) return AllocatorReturnNull(); // Overflow.
uptr map_beg = reinterpret_cast<uptr>(
MmapOrDie(map_size, "LargeMmapAllocator"));
MapUnmapCallback().OnMap(map_beg, map_size);
@@ -961,6 +963,7 @@ class LargeMmapAllocator {
{
SpinMutexLock l(&mutex_);
uptr idx = n_chunks_++;
+ chunks_sorted_ = false;
CHECK_LT(idx, kMaxNumChunks);
h->chunk_idx = idx;
chunks_[idx] = h;
@@ -984,6 +987,7 @@ class LargeMmapAllocator {
chunks_[idx] = chunks_[n_chunks_ - 1];
chunks_[idx]->chunk_idx = idx;
n_chunks_--;
+ chunks_sorted_ = false;
stats.n_frees++;
stats.currently_allocated -= h->map_size;
stat->Add(AllocatorStatFreed, h->map_size);
@@ -1004,7 +1008,7 @@ class LargeMmapAllocator {
return res;
}
- bool PointerIsMine(void *p) {
+ bool PointerIsMine(const void *p) {
return GetBlockBegin(p) != 0;
}
@@ -1013,13 +1017,16 @@ class LargeMmapAllocator {
}
// At least page_size_/2 metadata bytes is available.
- void *GetMetaData(void *p) {
+ void *GetMetaData(const void *p) {
// Too slow: CHECK_EQ(p, GetBlockBegin(p));
- CHECK(IsAligned(reinterpret_cast<uptr>(p), page_size_));
+ if (!IsAligned(reinterpret_cast<uptr>(p), page_size_)) {
+ Printf("%s: bad pointer %p\n", SanitizerToolName, p);
+ CHECK(IsAligned(reinterpret_cast<uptr>(p), page_size_));
+ }
return GetHeader(p) + 1;
}
- void *GetBlockBegin(void *ptr) {
+ void *GetBlockBegin(const void *ptr) {
uptr p = reinterpret_cast<uptr>(ptr);
SpinMutexLock l(&mutex_);
uptr nearest_chunk = 0;
@@ -1041,6 +1048,49 @@ class LargeMmapAllocator {
return GetUser(h);
}
+ // This function does the same as GetBlockBegin, but is much faster.
+ // Must be called with the allocator locked.
+ void *GetBlockBeginFastLocked(void *ptr) {
+ mutex_.CheckLocked();
+ uptr p = reinterpret_cast<uptr>(ptr);
+ uptr n = n_chunks_;
+ if (!n) return 0;
+ if (!chunks_sorted_) {
+ // Do one-time sort. chunks_sorted_ is reset in Allocate/Deallocate.
+ SortArray(reinterpret_cast<uptr*>(chunks_), n);
+ for (uptr i = 0; i < n; i++)
+ chunks_[i]->chunk_idx = i;
+ chunks_sorted_ = true;
+ min_mmap_ = reinterpret_cast<uptr>(chunks_[0]);
+ max_mmap_ = reinterpret_cast<uptr>(chunks_[n - 1]) +
+ chunks_[n - 1]->map_size;
+ }
+ if (p < min_mmap_ || p >= max_mmap_)
+ return 0;
+ uptr beg = 0, end = n - 1;
+ // This loop is a log(n) lower_bound. It does not check for the exact match
+ // to avoid expensive cache-thrashing loads.
+ while (end - beg >= 2) {
+ uptr mid = (beg + end) / 2; // Invariant: mid >= beg + 1
+ if (p < reinterpret_cast<uptr>(chunks_[mid]))
+ end = mid - 1; // We are not interested in chunks_[mid].
+ else
+ beg = mid; // chunks_[mid] may still be what we want.
+ }
+
+ if (beg < end) {
+ CHECK_EQ(beg + 1, end);
+ // There are 2 chunks left, choose one.
+ if (p >= reinterpret_cast<uptr>(chunks_[end]))
+ beg = end;
+ }
+
+ Header *h = chunks_[beg];
+ if (h->map_beg + h->map_size <= p || p < h->map_beg)
+ return 0;
+ return GetUser(h);
+ }
+
void PrintStats() {
Printf("Stats: LargeMmapAllocator: allocated %zd times, "
"remains %zd (%zd K) max %zd M; by size logs: ",
@@ -1064,13 +1114,11 @@ class LargeMmapAllocator {
mutex_.Unlock();
}
- // Iterate over existing chunks. May include chunks that are not currently
- // allocated to the user (e.g. freed).
- // The caller is expected to call ForceLock() before calling this function.
- template<typename Callable>
- void ForEachChunk(const Callable &callback) {
+ // Iterate over all existing chunks.
+ // The allocator must be locked when calling this function.
+ void ForEachChunk(ForEachChunkCallback callback, void *arg) {
for (uptr i = 0; i < n_chunks_; i++)
- callback(GetUser(chunks_[i]));
+ callback(reinterpret_cast<uptr>(GetUser(chunks_[i])), arg);
}
private:
@@ -1083,13 +1131,15 @@ class LargeMmapAllocator {
};
Header *GetHeader(uptr p) {
- CHECK_EQ(p % page_size_, 0);
+ CHECK(IsAligned(p, page_size_));
return reinterpret_cast<Header*>(p - page_size_);
}
- Header *GetHeader(void *p) { return GetHeader(reinterpret_cast<uptr>(p)); }
+ Header *GetHeader(const void *p) {
+ return GetHeader(reinterpret_cast<uptr>(p));
+ }
void *GetUser(Header *h) {
- CHECK_EQ((uptr)h % page_size_, 0);
+ CHECK(IsAligned((uptr)h, page_size_));
return reinterpret_cast<void*>(reinterpret_cast<uptr>(h) + page_size_);
}
@@ -1100,6 +1150,8 @@ class LargeMmapAllocator {
uptr page_size_;
Header *chunks_[kMaxNumChunks];
uptr n_chunks_;
+ uptr min_mmap_, max_mmap_;
+ bool chunks_sorted_;
struct Stats {
uptr n_allocs, n_frees, currently_allocated, max_allocated, by_size_log[64];
} stats;
@@ -1128,7 +1180,7 @@ class CombinedAllocator {
if (size == 0)
size = 1;
if (size + alignment < size)
- return 0;
+ return AllocatorReturnNull();
if (alignment > 8)
size = RoundUpTo(size, alignment);
void *res;
@@ -1179,18 +1231,26 @@ class CombinedAllocator {
return primary_.PointerIsMine(p);
}
- void *GetMetaData(void *p) {
+ void *GetMetaData(const void *p) {
if (primary_.PointerIsMine(p))
return primary_.GetMetaData(p);
return secondary_.GetMetaData(p);
}
- void *GetBlockBegin(void *p) {
+ void *GetBlockBegin(const void *p) {
if (primary_.PointerIsMine(p))
return primary_.GetBlockBegin(p);
return secondary_.GetBlockBegin(p);
}
+ // This function does the same as GetBlockBegin, but is much faster.
+ // Must be called with the allocator locked.
+ void *GetBlockBeginFastLocked(void *p) {
+ if (primary_.PointerIsMine(p))
+ return primary_.GetBlockBegin(p);
+ return secondary_.GetBlockBeginFastLocked(p);
+ }
+
uptr GetActuallyAllocatedSize(void *p) {
if (primary_.PointerIsMine(p))
return primary_.GetActuallyAllocatedSize(p);
@@ -1236,13 +1296,11 @@ class CombinedAllocator {
primary_.ForceUnlock();
}
- // Iterate over existing chunks. May include chunks that are not currently
- // allocated to the user (e.g. freed).
- // The caller is expected to call ForceLock() before calling this function.
- template<typename Callable>
- void ForEachChunk(const Callable &callback) {
- primary_.ForEachChunk(callback);
- secondary_.ForEachChunk(callback);
+ // Iterate over all existing chunks.
+ // The allocator must be locked when calling this function.
+ void ForEachChunk(ForEachChunkCallback callback, void *arg) {
+ primary_.ForEachChunk(callback, arg);
+ secondary_.ForEachChunk(callback, arg);
}
private:
diff --git a/lib/sanitizer_common/sanitizer_allocator_internal.h b/lib/sanitizer_common/sanitizer_allocator_internal.h
new file mode 100644
index 000000000000..5b24bfdafa36
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_allocator_internal.h
@@ -0,0 +1,64 @@
+//===-- sanitizer_allocator_internal.h -------------------------- C++ -----===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This allocator is used inside run-times.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_ALLOCATOR_INTERNAL_H
+#define SANITIZER_ALLOCATOR_INTERNAL_H
+
+#include "sanitizer_allocator.h"
+#include "sanitizer_internal_defs.h"
+
+namespace __sanitizer {
+
+// FIXME: Check if we may use even more compact size class map for internal
+// purposes.
+typedef CompactSizeClassMap InternalSizeClassMap;
+
+static const uptr kInternalAllocatorSpace = 0;
+#if SANITIZER_WORDSIZE == 32
+static const u64 kInternalAllocatorSize = (1ULL << 32);
+static const uptr kInternalAllocatorRegionSizeLog = 20;
+#else
+static const u64 kInternalAllocatorSize = (1ULL << 47);
+static const uptr kInternalAllocatorRegionSizeLog = 24;
+#endif
+static const uptr kInternalAllocatorFlatByteMapSize =
+ kInternalAllocatorSize >> kInternalAllocatorRegionSizeLog;
+typedef SizeClassAllocator32<
+ kInternalAllocatorSpace, kInternalAllocatorSize, 16, InternalSizeClassMap,
+ kInternalAllocatorRegionSizeLog,
+ FlatByteMap<kInternalAllocatorFlatByteMapSize> > 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;
+
+void *InternalAlloc(uptr size, InternalAllocatorCache *cache = 0);
+void InternalFree(void *p, InternalAllocatorCache *cache = 0);
+InternalAllocator *internal_allocator();
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_ALLOCATOR_INTERNAL_H
diff --git a/lib/sanitizer_common/sanitizer_atomic_clang.h b/lib/sanitizer_common/sanitizer_atomic_clang.h
index 30158b49683c..c5aa939b58c4 100644
--- a/lib/sanitizer_common/sanitizer_atomic_clang.h
+++ b/lib/sanitizer_common/sanitizer_atomic_clang.h
@@ -41,7 +41,17 @@ INLINE typename T::Type atomic_load(
| memory_order_acquire | memory_order_seq_cst));
DCHECK(!((uptr)a % sizeof(*a)));
typename T::Type v;
- // FIXME(dvyukov): 64-bit load is not atomic on 32-bits.
+ // 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 {
@@ -57,7 +67,6 @@ 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)));
- // FIXME(dvyukov): 64-bit store is not atomic on 32-bits.
if (mo == memory_order_relaxed) {
a->val_dont_use = v;
} else {
@@ -121,4 +130,6 @@ INLINE bool atomic_compare_exchange_weak(volatile T *a,
} // namespace __sanitizer
+#undef ATOMIC_ORDER
+
#endif // SANITIZER_ATOMIC_CLANG_H
diff --git a/lib/sanitizer_common/sanitizer_common.cc b/lib/sanitizer_common/sanitizer_common.cc
index abbe5f92d1a9..7e870ff65455 100644
--- a/lib/sanitizer_common/sanitizer_common.cc
+++ b/lib/sanitizer_common/sanitizer_common.cc
@@ -12,12 +12,14 @@
//===----------------------------------------------------------------------===//
#include "sanitizer_common.h"
+#include "sanitizer_flags.h"
#include "sanitizer_libc.h"
+#include "sanitizer_stacktrace.h"
+#include "sanitizer_symbolizer.h"
namespace __sanitizer {
const char *SanitizerToolName = "SanitizerTool";
-uptr SanitizerVerbosity = 0;
uptr GetPageSizeCached() {
static uptr PageSize;
@@ -26,22 +28,29 @@ uptr GetPageSizeCached() {
return PageSize;
}
-static bool log_to_file = false; // Set to true by __sanitizer_set_report_path
// 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;
-static char report_path_prefix[4096]; // Set via __sanitizer_set_report_path.
+
+// Set via __sanitizer_set_report_path.
+bool log_to_file = false;
+char report_path_prefix[sizeof(report_path_prefix)];
+
// PID of process that opened |report_fd|. If a fork() occurs, the PID of the
// child thread will be different from |report_fd_pid|.
-static uptr report_fd_pid = 0;
+uptr report_fd_pid = 0;
-static void (*DieCallback)(void);
-void SetDieCallback(void (*callback)(void)) {
+static DieCallbackType DieCallback;
+void SetDieCallback(DieCallbackType callback) {
DieCallback = callback;
}
+DieCallbackType GetDieCallback() {
+ return DieCallback;
+}
+
void NORETURN Die() {
if (DieCallback) {
DieCallback();
@@ -64,36 +73,6 @@ void NORETURN CheckFailed(const char *file, int line, const char *cond,
Die();
}
-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!";
- uptr length = (uptr)internal_strlen(buffer);
- MaybeOpenReportFile();
- if (length != internal_write(report_fd, buffer, length)) {
- internal_write(report_fd, kRawWriteError, internal_strlen(kRawWriteError));
- Die();
- }
-}
-
uptr ReadFileToBuffer(const char *file_name, char **buff,
uptr *buff_size, uptr max_len) {
uptr PageSize = GetPageSizeCached();
@@ -159,14 +138,103 @@ void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type) {
return (void*)res;
}
+const char *StripPathPrefix(const char *filepath,
+ const char *strip_path_prefix) {
+ if (filepath == 0) return 0;
+ if (strip_path_prefix == 0) return filepath;
+ const char *pos = internal_strstr(filepath, strip_path_prefix);
+ if (pos == 0) return filepath;
+ pos += internal_strlen(strip_path_prefix);
+ if (pos[0] == '.' && pos[1] == '/')
+ pos += 2;
+ 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);
+}
+
+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);
+ __sanitizer_report_error_summary(buff.data());
+}
+
void ReportErrorSummary(const char *error_type, const char *file,
int line, const char *function) {
- const int kMaxSize = 1024; // We don't want a summary too long.
- InternalScopedBuffer<char> buff(kMaxSize);
- internal_snprintf(buff.data(), kMaxSize, "%s: %s %s:%d %s",
- SanitizerToolName, error_type,
- file ? file : "??", line, function ? function : "??");
- __sanitizer_report_error_summary(buff.data());
+ 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 : "??");
+ 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) {
+ CHECK_LT(n_ranges_, kMaxNumberOfAddressRanges);
+ ranges_[n_ranges_].beg = beg;
+ ranges_[n_ranges_].end = end;
+ n_ranges_++;
+}
+
+bool LoadedModule::containsAddress(uptr address) const {
+ for (uptr i = 0; i < n_ranges_; i++) {
+ if (ranges_[i].beg <= address && address < ranges_[i].end)
+ return true;
+ }
+ 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);
}
} // namespace __sanitizer
@@ -175,7 +243,8 @@ using namespace __sanitizer; // NOLINT
extern "C" {
void __sanitizer_set_report_path(const char *path) {
- if (!path) return;
+ 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",
@@ -183,18 +252,21 @@ void __sanitizer_set_report_path(const char *path) {
path[4], path[5], path[6], path[7]);
Die();
}
- internal_strncpy(report_path_prefix, path, sizeof(report_path_prefix));
- report_path_prefix[len] = '\0';
- report_fd = kInvalidFd;
- log_to_file = true;
-}
-
-void __sanitizer_set_report_fd(int fd) {
if (report_fd != kStdoutFd &&
report_fd != kStderrFd &&
report_fd != kInvalidFd)
internal_close(report_fd);
- report_fd = 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) {
@@ -203,6 +275,6 @@ void NOINLINE __sanitizer_sandbox_on_notify(void *reserved) {
}
void __sanitizer_report_error_summary(const char *error_summary) {
- Printf("SUMMARY: %s\n", error_summary);
+ Printf("%s\n", error_summary);
}
} // extern "C"
diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h
index d800360169fb..cf8a12d65a09 100644
--- a/lib/sanitizer_common/sanitizer_common.h
+++ b/lib/sanitizer_common/sanitizer_common.h
@@ -33,12 +33,14 @@ const uptr kCacheLineSize = 128;
const uptr kCacheLineSize = 64;
#endif
+const uptr kMaxPathLength = 512;
+
extern const char *SanitizerToolName; // Can be changed by the tool.
-extern uptr SanitizerVerbosity;
uptr GetPageSize();
uptr GetPageSizeCached();
uptr GetMmapGranularity();
+uptr GetMaxVirtualAddress();
// Threads
uptr GetTid();
uptr GetThreadSelf();
@@ -59,10 +61,6 @@ void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type);
bool MemoryRangeIsAvailable(uptr range_start, uptr range_end);
void FlushUnneededShadowMemory(uptr addr, uptr size);
-// Internal allocator
-void *InternalAlloc(uptr size);
-void InternalFree(void *p);
-
// InternalScopedBuffer can be used instead of large stack arrays to
// keep frame size low.
// FIXME: use InternalAlloc instead of MmapOrDie once
@@ -89,6 +87,23 @@ class InternalScopedBuffer {
void operator=(const InternalScopedBuffer&);
};
+class InternalScopedString : public InternalScopedBuffer<char> {
+ public:
+ explicit InternalScopedString(uptr max_length)
+ : InternalScopedBuffer<char>(max_length), length_(0) {
+ (*this)[0] = '\0';
+ }
+ uptr length() { return length_; }
+ void clear() {
+ (*this)[0] = '\0';
+ length_ = 0;
+ }
+ void append(const char *format, ...);
+
+ private:
+ uptr length_;
+};
+
// Simple low-level (mmap-based) allocator for internal use. Doesn't have
// constructor, so all instances of LowLevelAllocator should be
// linker initialized.
@@ -108,13 +123,19 @@ void SetLowLevelAllocateCallback(LowLevelAllocateCallback callback);
// IO
void RawWrite(const char *buffer);
bool PrintsToTty();
+// Caching version of PrintsToTty(). Not thread-safe.
+bool PrintsToTtyCached();
void Printf(const char *format, ...);
void Report(const char *format, ...);
void SetPrintfAndReportCallback(void (*callback)(const char *));
+
// 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;
uptr OpenFile(const char *filename, bool write);
// Opens the file 'file_name" and reads up to 'max_len' bytes.
@@ -128,6 +149,14 @@ uptr ReadFileToBuffer(const char *file_name, char **buff,
// in '*buff_size'.
void *MapFileToMemory(const char *file_name, uptr *buff_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);
+
// OS
void DisableCoreDumper();
void DumpProcessMap();
@@ -135,6 +164,7 @@ bool FileExists(const char *filename);
const char *GetEnv(const char *name);
bool SetEnv(const char *name, const char *value);
const char *GetPwd();
+char *FindPathToBinary(const char *name);
u32 GetUid();
void ReExec();
bool StackSizeIsUnlimited();
@@ -150,11 +180,14 @@ 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();
void NORETURN Die();
-void NORETURN SANITIZER_INTERFACE_ATTRIBUTE
+void NORETURN
CheckFailed(const char *file, int line, const char *cond, u64 v1, u64 v2);
// Set the name of the current thread to 'name', return true on succees.
@@ -166,19 +199,27 @@ bool SanitizerGetThreadName(char *name, int max_len);
// Specific tools may override behavior of "Die" and "CheckFailed" functions
// to do tool-specific job.
-void SetDieCallback(void (*callback)(void));
+typedef void (*DieCallbackType)(void);
+void SetDieCallback(DieCallbackType);
+DieCallbackType GetDieCallback();
typedef void (*CheckFailedCallbackType)(const char *, int, const char *,
u64, u64);
void SetCheckFailedCallback(CheckFailedCallbackType callback);
-// Construct a one-line string like
-// SanitizerToolName: error_type file:line function
-// and call __sanitizer_report_error_summary on it.
+// We don't want a summary too long.
+const int kMaxSummaryLength = 1024;
+// Construct a one-line string:
+// SUMMARY: SanitizerToolName: error_message
+// 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
void ReportErrorSummary(const char *error_type, const char *file,
int line, const char *function);
+void ReportErrorSummary(const char *error_type, StackTrace *trace);
// Math
-#if SANITIZER_WINDOWS && !defined(__clang__)
+#if SANITIZER_WINDOWS && !defined(__clang__) && !defined(__GNUC__)
extern "C" {
unsigned char _BitScanForward(unsigned long *index, unsigned long mask); // NOLINT
unsigned char _BitScanReverse(unsigned long *index, unsigned long mask); // NOLINT
@@ -192,7 +233,7 @@ unsigned char _BitScanReverse64(unsigned long *index, unsigned __int64 mask); /
INLINE uptr MostSignificantSetBitIndex(uptr x) {
CHECK_NE(x, 0U);
unsigned long up; // NOLINT
-#if !SANITIZER_WINDOWS || defined(__clang__)
+#if !SANITIZER_WINDOWS || defined(__clang__) || defined(__GNUC__)
up = SANITIZER_WORDSIZE - 1 - __builtin_clzl(x);
#elif defined(_WIN64)
_BitScanReverse64(&up, x);
@@ -231,7 +272,7 @@ INLINE bool IsAligned(uptr a, uptr alignment) {
INLINE uptr Log2(uptr x) {
CHECK(IsPowerOfTwo(x));
-#if !SANITIZER_WINDOWS || defined(__clang__)
+#if !SANITIZER_WINDOWS || defined(__clang__) || defined(__GNUC__)
return __builtin_ctzl(x);
#elif defined(_WIN64)
unsigned long ret; // NOLINT
@@ -276,15 +317,15 @@ INLINE int ToLower(int c) {
// small vectors.
// WARNING: The current implementation supports only POD types.
template<typename T>
-class InternalVector {
+class InternalMmapVector {
public:
- explicit InternalVector(uptr initial_capacity) {
+ explicit InternalMmapVector(uptr initial_capacity) {
CHECK_GT(initial_capacity, 0);
capacity_ = initial_capacity;
size_ = 0;
- data_ = (T *)MmapOrDie(capacity_ * sizeof(T), "InternalVector");
+ data_ = (T *)MmapOrDie(capacity_ * sizeof(T), "InternalMmapVector");
}
- ~InternalVector() {
+ ~InternalMmapVector() {
UnmapOrDie(data_, capacity_ * sizeof(T));
}
T &operator[](uptr i) {
@@ -321,12 +362,14 @@ class InternalVector {
return capacity_;
}
+ void clear() { size_ = 0; }
+
private:
void Resize(uptr new_capacity) {
CHECK_GT(new_capacity, 0);
CHECK_LE(size_, new_capacity);
T *new_data = (T *)MmapOrDie(new_capacity * sizeof(T),
- "InternalVector");
+ "InternalMmapVector");
internal_memcpy(new_data, data_, size_ * sizeof(T));
T *old_data = data_;
data_ = new_data;
@@ -334,15 +377,15 @@ class InternalVector {
capacity_ = new_capacity;
}
// Disallow evil constructors.
- InternalVector(const InternalVector&);
- void operator=(const InternalVector&);
+ InternalMmapVector(const InternalMmapVector&);
+ void operator=(const InternalMmapVector&);
T *data_;
uptr capacity_;
uptr size_;
};
-// HeapSort for arrays and InternalVector.
+// HeapSort for arrays and InternalMmapVector.
template<class Container, class Compare>
void InternalSort(Container *v, uptr size, Compare comp) {
if (size < 2)
@@ -379,6 +422,67 @@ void InternalSort(Container *v, uptr size, Compare comp) {
}
}
+template<class Container, class Value, class Compare>
+uptr InternalBinarySearch(const Container &v, uptr first, uptr last,
+ const Value &val, Compare comp) {
+ uptr not_found = last + 1;
+ while (last >= first) {
+ uptr mid = (first + last) / 2;
+ if (comp(v[mid], val))
+ first = mid + 1;
+ else if (comp(val, v[mid]))
+ last = mid - 1;
+ else
+ return mid;
+ }
+ return not_found;
+}
+
+// Represents a binary loaded into virtual memory (e.g. this can be an
+// executable or a shared object).
+class LoadedModule {
+ public:
+ LoadedModule(const char *module_name, uptr base_address);
+ void addAddressRange(uptr beg, uptr end);
+ bool containsAddress(uptr address) const;
+
+ const char *full_name() const { return full_name_; }
+ uptr base_address() const { return base_address_; }
+
+ private:
+ struct AddressRange {
+ uptr beg;
+ uptr end;
+ };
+ char *full_name_;
+ uptr base_address_;
+ static const uptr kMaxNumberOfAddressRanges = 6;
+ AddressRange ranges_[kMaxNumberOfAddressRanges];
+ uptr n_ranges_;
+};
+
+// OS-dependent function that fills array with descriptions of at most
+// "max_modules" currently loaded modules. Returns the number of
+// initialized modules. If filter is nonzero, ignores modules for which
+// filter(full_name) is false.
+typedef bool (*string_predicate_t)(const char *);
+uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
+ string_predicate_t filter);
+
+#if SANITIZER_POSIX
+const uptr kPthreadDestructorIterations = 4;
+#else
+// Unused on Windows.
+const uptr kPthreadDestructorIterations = 0;
+#endif
+
+// Callback type for iterating over a set of memory ranges.
+typedef void (*RangeIteratorCallback)(uptr begin, uptr end, void *arg);
} // namespace __sanitizer
+inline void *operator new(__sanitizer::operator_new_size_type size,
+ __sanitizer::LowLevelAllocator &alloc) {
+ return alloc.Allocate(size);
+}
+
#endif // SANITIZER_COMMON_H
diff --git a/lib/sanitizer_common/sanitizer_common_interceptors.inc b/lib/sanitizer_common/sanitizer_common_interceptors.inc
index 8c0fb55f3ce9..d1c8976781c7 100644
--- a/lib/sanitizer_common/sanitizer_common_interceptors.inc
+++ b/lib/sanitizer_common/sanitizer_common_interceptors.inc
@@ -15,9 +15,16 @@
// COMMON_INTERCEPTOR_ENTER
// COMMON_INTERCEPTOR_READ_RANGE
// COMMON_INTERCEPTOR_WRITE_RANGE
+// COMMON_INTERCEPTOR_INITIALIZE_RANGE
// COMMON_INTERCEPTOR_FD_ACQUIRE
// COMMON_INTERCEPTOR_FD_RELEASE
+// COMMON_INTERCEPTOR_FD_ACCESS
// COMMON_INTERCEPTOR_SET_THREAD_NAME
+// COMMON_INTERCEPTOR_ON_EXIT
+// COMMON_INTERCEPTOR_MUTEX_LOCK
+// COMMON_INTERCEPTOR_MUTEX_UNLOCK
+// COMMON_INTERCEPTOR_MUTEX_REPAIR
+// COMMON_INTERCEPTOR_SET_PTHREAD_NAME
//===----------------------------------------------------------------------===//
#include "interception/interception.h"
#include "sanitizer_platform_interceptors.h"
@@ -28,6 +35,68 @@
#define va_copy(dst, src) ((dst) = (src))
#endif // _WIN32
+#ifndef COMMON_INTERCEPTOR_INITIALIZE_RANGE
+#define COMMON_INTERCEPTOR_INITIALIZE_RANGE(ctx, p, size) {}
+#endif
+
+#ifndef COMMON_INTERCEPTOR_FD_ACCESS
+#define COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd) {}
+#endif
+
+#ifndef COMMON_INTERCEPTOR_MUTEX_LOCK
+#define COMMON_INTERCEPTOR_MUTEX_LOCK(ctx, m) {}
+#endif
+
+#ifndef COMMON_INTERCEPTOR_MUTEX_UNLOCK
+#define COMMON_INTERCEPTOR_MUTEX_UNLOCK(ctx, m) {}
+#endif
+
+#ifndef COMMON_INTERCEPTOR_MUTEX_REPAIR
+#define COMMON_INTERCEPTOR_MUTEX_REPAIR(ctx, m) {}
+#endif
+
+#if SANITIZER_INTERCEPT_STRCMP
+static inline int CharCmpX(unsigned char c1, unsigned char c2) {
+ return (c1 == c2) ? 0 : (c1 < c2) ? -1 : 1;
+}
+
+INTERCEPTOR(int, strcmp, const char *s1, const char *s2) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, strcmp, s1, s2);
+ unsigned char c1, c2;
+ uptr i;
+ for (i = 0;; i++) {
+ c1 = (unsigned char)s1[i];
+ c2 = (unsigned char)s2[i];
+ if (c1 != c2 || c1 == '\0') break;
+ }
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, s1, i + 1);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, i + 1);
+ return CharCmpX(c1, c2);
+}
+
+INTERCEPTOR(int, strncmp, const char *s1, const char *s2, uptr size) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, strncmp, s1, s2, size);
+ unsigned char c1 = 0, c2 = 0;
+ uptr i;
+ for (i = 0; i < size; i++) {
+ c1 = (unsigned char)s1[i];
+ c2 = (unsigned char)s2[i];
+ if (c1 != c2 || c1 == '\0') break;
+ }
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, s1, Min(i + 1, size));
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, Min(i + 1, size));
+ return CharCmpX(c1, c2);
+}
+
+#define INIT_STRCMP COMMON_INTERCEPT_FUNCTION(strcmp)
+#define INIT_STRNCMP COMMON_INTERCEPT_FUNCTION(strncmp)
+#else
+#define INIT_STRCMP
+#define INIT_STRNCMP
+#endif
+
#if SANITIZER_INTERCEPT_STRCASECMP
static inline int CharCaseCmp(unsigned char c1, unsigned char c2) {
int c1_low = ToLower(c1);
@@ -40,11 +109,10 @@ INTERCEPTOR(int, strcasecmp, const char *s1, const char *s2) {
COMMON_INTERCEPTOR_ENTER(ctx, strcasecmp, s1, s2);
unsigned char c1 = 0, c2 = 0;
uptr i;
- for (i = 0; ; i++) {
+ for (i = 0;; i++) {
c1 = (unsigned char)s1[i];
c2 = (unsigned char)s2[i];
- if (CharCaseCmp(c1, c2) != 0 || c1 == '\0')
- break;
+ if (CharCaseCmp(c1, c2) != 0 || c1 == '\0') break;
}
COMMON_INTERCEPTOR_READ_RANGE(ctx, s1, i + 1);
COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, i + 1);
@@ -59,16 +127,15 @@ INTERCEPTOR(int, strncasecmp, const char *s1, const char *s2, SIZE_T n) {
for (i = 0; i < n; i++) {
c1 = (unsigned char)s1[i];
c2 = (unsigned char)s2[i];
- if (CharCaseCmp(c1, c2) != 0 || c1 == '\0')
- break;
+ if (CharCaseCmp(c1, c2) != 0 || c1 == '\0') break;
}
COMMON_INTERCEPTOR_READ_RANGE(ctx, s1, Min(i + 1, n));
COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, Min(i + 1, n));
return CharCaseCmp(c1, c2);
}
-#define INIT_STRCASECMP INTERCEPT_FUNCTION(strcasecmp)
-#define INIT_STRNCASECMP INTERCEPT_FUNCTION(strncasecmp)
+#define INIT_STRCASECMP COMMON_INTERCEPT_FUNCTION(strcasecmp)
+#define INIT_STRNCASECMP COMMON_INTERCEPT_FUNCTION(strncasecmp)
#else
#define INIT_STRCASECMP
#define INIT_STRNCASECMP
@@ -83,10 +150,10 @@ INTERCEPTOR(double, frexp, double x, int *exp) {
return res;
}
-#define INIT_FREXP INTERCEPT_FUNCTION(frexp);
+#define INIT_FREXP COMMON_INTERCEPT_FUNCTION(frexp);
#else
#define INIT_FREXP
-#endif // SANITIZER_INTERCEPT_FREXP
+#endif // SANITIZER_INTERCEPT_FREXP
#if SANITIZER_INTERCEPT_FREXPF_FREXPL
INTERCEPTOR(float, frexpf, float x, int *exp) {
@@ -105,25 +172,45 @@ INTERCEPTOR(long double, frexpl, long double x, int *exp) {
return res;
}
-#define INIT_FREXPF_FREXPL \
- INTERCEPT_FUNCTION(frexpf); \
- INTERCEPT_FUNCTION(frexpl)
+#define INIT_FREXPF_FREXPL \
+ COMMON_INTERCEPT_FUNCTION(frexpf); \
+ COMMON_INTERCEPT_FUNCTION(frexpl)
#else
#define INIT_FREXPF_FREXPL
-#endif // SANITIZER_INTERCEPT_FREXPF_FREXPL
+#endif // SANITIZER_INTERCEPT_FREXPF_FREXPL
+
+#if SI_NOT_WINDOWS
+static void write_iovec(void *ctx, struct __sanitizer_iovec *iovec,
+ SIZE_T iovlen, SIZE_T maxlen) {
+ for (SIZE_T i = 0; i < iovlen && maxlen; ++i) {
+ SSIZE_T sz = Min(iovec[i].iov_len, maxlen);
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, iovec[i].iov_base, sz);
+ maxlen -= sz;
+ }
+}
+
+static void read_iovec(void *ctx, struct __sanitizer_iovec *iovec,
+ SIZE_T iovlen, SIZE_T maxlen) {
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, iovec, sizeof(*iovec) * iovlen);
+ for (SIZE_T i = 0; i < iovlen && maxlen; ++i) {
+ SSIZE_T sz = Min(iovec[i].iov_len, maxlen);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, iovec[i].iov_base, sz);
+ maxlen -= sz;
+ }
+}
+#endif
#if SANITIZER_INTERCEPT_READ
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);
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);
+ if (res > 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, res);
+ if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
return res;
}
-#define INIT_READ INTERCEPT_FUNCTION(read)
+#define INIT_READ COMMON_INTERCEPT_FUNCTION(read)
#else
#define INIT_READ
#endif
@@ -132,14 +219,13 @@ INTERCEPTOR(SSIZE_T, read, int fd, void *ptr, SIZE_T count) {
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);
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);
+ if (res > 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, res);
+ if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
return res;
}
-#define INIT_PREAD INTERCEPT_FUNCTION(pread)
+#define INIT_PREAD COMMON_INTERCEPT_FUNCTION(pread)
#else
#define INIT_PREAD
#endif
@@ -148,30 +234,77 @@ INTERCEPTOR(SSIZE_T, pread, int fd, void *ptr, SIZE_T count, OFF_T offset) {
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);
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);
+ if (res > 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, res);
+ if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
return res;
}
-#define INIT_PREAD64 INTERCEPT_FUNCTION(pread64)
+#define INIT_PREAD64 COMMON_INTERCEPT_FUNCTION(pread64)
#else
#define INIT_PREAD64
#endif
+#if SANITIZER_INTERCEPT_READV
+INTERCEPTOR_WITH_SUFFIX(SSIZE_T, readv, int fd, __sanitizer_iovec *iov,
+ int iovcnt) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, readv, fd, iov, iovcnt);
+ COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
+ SSIZE_T res = REAL(readv)(fd, iov, iovcnt);
+ if (res > 0) write_iovec(ctx, iov, iovcnt, res);
+ if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
+ return res;
+}
+#define INIT_READV COMMON_INTERCEPT_FUNCTION(readv)
+#else
+#define INIT_READV
+#endif
+
+#if SANITIZER_INTERCEPT_PREADV
+INTERCEPTOR(SSIZE_T, preadv, int fd, __sanitizer_iovec *iov, int iovcnt,
+ OFF_T offset) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, preadv, fd, iov, iovcnt, offset);
+ COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
+ SSIZE_T res = REAL(preadv)(fd, iov, iovcnt, offset);
+ if (res > 0) write_iovec(ctx, iov, iovcnt, res);
+ if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
+ return res;
+}
+#define INIT_PREADV COMMON_INTERCEPT_FUNCTION(preadv)
+#else
+#define INIT_PREADV
+#endif
+
+#if SANITIZER_INTERCEPT_PREADV64
+INTERCEPTOR(SSIZE_T, preadv64, int fd, __sanitizer_iovec *iov, int iovcnt,
+ OFF64_T offset) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, preadv64, fd, iov, iovcnt, offset);
+ COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
+ SSIZE_T res = REAL(preadv64)(fd, iov, iovcnt, offset);
+ if (res > 0) write_iovec(ctx, iov, iovcnt, res);
+ if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
+ return res;
+}
+#define INIT_PREADV64 COMMON_INTERCEPT_FUNCTION(preadv64)
+#else
+#define INIT_PREADV64
+#endif
+
#if SANITIZER_INTERCEPT_WRITE
INTERCEPTOR(SSIZE_T, write, int fd, void *ptr, SIZE_T count) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, write, fd, ptr, count);
- if (fd >= 0)
- COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd);
+ COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
+ if (fd >= 0) COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd);
SSIZE_T res = REAL(write)(fd, ptr, count);
- if (res > 0)
- COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, res);
+ // FIXME: this check should be _before_ the call to REAL(write), not after
+ if (res > 0) COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, res);
return res;
}
-#define INIT_WRITE INTERCEPT_FUNCTION(write)
+#define INIT_WRITE COMMON_INTERCEPT_FUNCTION(write)
#else
#define INIT_WRITE
#endif
@@ -180,14 +313,13 @@ INTERCEPTOR(SSIZE_T, write, int fd, void *ptr, SIZE_T count) {
INTERCEPTOR(SSIZE_T, pwrite, int fd, void *ptr, SIZE_T count, OFF_T offset) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, pwrite, fd, ptr, count, offset);
- if (fd >= 0)
- COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd);
+ COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
+ if (fd >= 0) COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd);
SSIZE_T res = REAL(pwrite)(fd, ptr, count, offset);
- if (res > 0)
- COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, res);
+ if (res > 0) COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, res);
return res;
}
-#define INIT_PWRITE INTERCEPT_FUNCTION(pwrite)
+#define INIT_PWRITE COMMON_INTERCEPT_FUNCTION(pwrite)
#else
#define INIT_PWRITE
#endif
@@ -197,22 +329,69 @@ INTERCEPTOR(SSIZE_T, pwrite64, int fd, void *ptr, OFF64_T count,
OFF64_T offset) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, pwrite64, fd, ptr, count, offset);
- if (fd >= 0)
- COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd);
+ COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
+ if (fd >= 0) COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd);
SSIZE_T res = REAL(pwrite64)(fd, ptr, count, offset);
- if (res > 0)
- COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, res);
+ if (res > 0) COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, res);
return res;
}
-#define INIT_PWRITE64 INTERCEPT_FUNCTION(pwrite64)
+#define INIT_PWRITE64 COMMON_INTERCEPT_FUNCTION(pwrite64)
#else
#define INIT_PWRITE64
#endif
+#if SANITIZER_INTERCEPT_WRITEV
+INTERCEPTOR_WITH_SUFFIX(SSIZE_T, writev, int fd, __sanitizer_iovec *iov,
+ int iovcnt) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, writev, fd, iov, iovcnt);
+ COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
+ if (fd >= 0) COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd);
+ SSIZE_T res = REAL(writev)(fd, iov, iovcnt);
+ if (res > 0) read_iovec(ctx, iov, iovcnt, res);
+ return res;
+}
+#define INIT_WRITEV COMMON_INTERCEPT_FUNCTION(writev)
+#else
+#define INIT_WRITEV
+#endif
+
+#if SANITIZER_INTERCEPT_PWRITEV
+INTERCEPTOR(SSIZE_T, pwritev, int fd, __sanitizer_iovec *iov, int iovcnt,
+ OFF_T offset) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, pwritev, fd, iov, iovcnt, offset);
+ COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
+ if (fd >= 0) COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd);
+ SSIZE_T res = REAL(pwritev)(fd, iov, iovcnt, offset);
+ if (res > 0) read_iovec(ctx, iov, iovcnt, res);
+ return res;
+}
+#define INIT_PWRITEV COMMON_INTERCEPT_FUNCTION(pwritev)
+#else
+#define INIT_PWRITEV
+#endif
+
+#if SANITIZER_INTERCEPT_PWRITEV64
+INTERCEPTOR(SSIZE_T, pwritev64, int fd, __sanitizer_iovec *iov, int iovcnt,
+ OFF64_T offset) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, pwritev64, fd, iov, iovcnt, offset);
+ COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
+ if (fd >= 0) COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd);
+ SSIZE_T res = REAL(pwritev64)(fd, iov, iovcnt, offset);
+ if (res > 0) read_iovec(ctx, iov, iovcnt, res);
+ return res;
+}
+#define INIT_PWRITEV64 COMMON_INTERCEPT_FUNCTION(pwritev64)
+#else
+#define INIT_PWRITEV64
+#endif
+
#if SANITIZER_INTERCEPT_PRCTL
-INTERCEPTOR(int, prctl, int option,
- unsigned long arg2, unsigned long arg3, // NOLINT
- unsigned long arg4, unsigned long arg5) { // NOLINT
+INTERCEPTOR(int, prctl, int option, unsigned long arg2,
+ unsigned long arg3, // NOLINT
+ unsigned long arg4, unsigned long arg5) { // NOLINT
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, prctl, option, arg2, arg3, arg4, arg5);
static const int PR_SET_NAME = 15;
@@ -225,11 +404,10 @@ INTERCEPTOR(int, prctl, int option,
}
return res;
}
-#define INIT_PRCTL INTERCEPT_FUNCTION(prctl)
+#define INIT_PRCTL COMMON_INTERCEPT_FUNCTION(prctl)
#else
#define INIT_PRCTL
-#endif // SANITIZER_INTERCEPT_PRCTL
-
+#endif // SANITIZER_INTERCEPT_PRCTL
#if SANITIZER_INTERCEPT_TIME
INTERCEPTOR(unsigned long, time, unsigned long *t) {
@@ -241,51 +419,58 @@ INTERCEPTOR(unsigned long, time, unsigned long *t) {
}
return res;
}
-#define INIT_TIME \
- INTERCEPT_FUNCTION(time);
+#define INIT_TIME COMMON_INTERCEPT_FUNCTION(time);
#else
#define INIT_TIME
-#endif // SANITIZER_INTERCEPT_TIME
-
+#endif // SANITIZER_INTERCEPT_TIME
#if SANITIZER_INTERCEPT_LOCALTIME_AND_FRIENDS
-INTERCEPTOR(void *, localtime, unsigned long *timep) {
+static void unpoison_tm(void *ctx, __sanitizer_tm *tm) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tm, sizeof(*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,
+ REAL(strlen(tm->tm_zone)) + 1);
+ }
+}
+INTERCEPTOR(__sanitizer_tm *, localtime, unsigned long *timep) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, localtime, timep);
- void *res = REAL(localtime)(timep);
+ __sanitizer_tm *res = REAL(localtime)(timep);
if (res) {
COMMON_INTERCEPTOR_READ_RANGE(ctx, timep, sizeof(*timep));
- COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_tm_sz);
+ unpoison_tm(ctx, res);
}
return res;
}
-INTERCEPTOR(void *, localtime_r, unsigned long *timep, void *result) {
+INTERCEPTOR(__sanitizer_tm *, localtime_r, unsigned long *timep, void *result) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, localtime_r, timep, result);
- void *res = REAL(localtime_r)(timep, result);
+ __sanitizer_tm *res = REAL(localtime_r)(timep, result);
if (res) {
COMMON_INTERCEPTOR_READ_RANGE(ctx, timep, sizeof(*timep));
- COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_tm_sz);
+ unpoison_tm(ctx, res);
}
return res;
}
-INTERCEPTOR(void *, gmtime, unsigned long *timep) {
+INTERCEPTOR(__sanitizer_tm *, gmtime, unsigned long *timep) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, gmtime, timep);
- void *res = REAL(gmtime)(timep);
+ __sanitizer_tm *res = REAL(gmtime)(timep);
if (res) {
COMMON_INTERCEPTOR_READ_RANGE(ctx, timep, sizeof(*timep));
- COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_tm_sz);
+ unpoison_tm(ctx, res);
}
return res;
}
-INTERCEPTOR(void *, gmtime_r, unsigned long *timep, void *result) {
+INTERCEPTOR(__sanitizer_tm *, gmtime_r, unsigned long *timep, void *result) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, gmtime_r, timep, result);
- void *res = REAL(gmtime_r)(timep, result);
+ __sanitizer_tm *res = REAL(gmtime_r)(timep, result);
if (res) {
COMMON_INTERCEPTOR_READ_RANGE(ctx, timep, sizeof(*timep));
- COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_tm_sz);
+ unpoison_tm(ctx, res);
}
return res;
}
@@ -309,38 +494,59 @@ INTERCEPTOR(char *, ctime_r, unsigned long *timep, char *result) {
}
return res;
}
-INTERCEPTOR(char *, asctime, void *tm) {
+INTERCEPTOR(char *, asctime, __sanitizer_tm *tm) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, asctime, tm);
char *res = REAL(asctime)(tm);
if (res) {
- COMMON_INTERCEPTOR_READ_RANGE(ctx, tm, struct_tm_sz);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, tm, sizeof(*tm));
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
}
return res;
}
-INTERCEPTOR(char *, asctime_r, void *tm, char *result) {
+INTERCEPTOR(char *, asctime_r, __sanitizer_tm *tm, char *result) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, asctime_r, tm, result);
char *res = REAL(asctime_r)(tm, result);
if (res) {
- COMMON_INTERCEPTOR_READ_RANGE(ctx, tm, struct_tm_sz);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, tm, sizeof(*tm));
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
}
return res;
}
-#define INIT_LOCALTIME_AND_FRIENDS \
- INTERCEPT_FUNCTION(localtime); \
- INTERCEPT_FUNCTION(localtime_r); \
- INTERCEPT_FUNCTION(gmtime); \
- INTERCEPT_FUNCTION(gmtime_r); \
- INTERCEPT_FUNCTION(ctime); \
- INTERCEPT_FUNCTION(ctime_r); \
- INTERCEPT_FUNCTION(asctime); \
- INTERCEPT_FUNCTION(asctime_r);
+#define INIT_LOCALTIME_AND_FRIENDS \
+ COMMON_INTERCEPT_FUNCTION(localtime); \
+ COMMON_INTERCEPT_FUNCTION(localtime_r); \
+ COMMON_INTERCEPT_FUNCTION(gmtime); \
+ COMMON_INTERCEPT_FUNCTION(gmtime_r); \
+ COMMON_INTERCEPT_FUNCTION(ctime); \
+ COMMON_INTERCEPT_FUNCTION(ctime_r); \
+ COMMON_INTERCEPT_FUNCTION(asctime); \
+ COMMON_INTERCEPT_FUNCTION(asctime_r);
#else
#define INIT_LOCALTIME_AND_FRIENDS
-#endif // SANITIZER_INTERCEPT_LOCALTIME_AND_FRIENDS
+#endif // SANITIZER_INTERCEPT_LOCALTIME_AND_FRIENDS
+
+#if SANITIZER_INTERCEPT_STRPTIME
+INTERCEPTOR(char *, strptime, char *s, char *format, __sanitizer_tm *tm) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, strptime, s, format, tm);
+ if (format)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, format, REAL(strlen)(format) + 1);
+ char *res = REAL(strptime)(s, format, tm);
+ if (res) {
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, s, res - s);
+ // Do not call unpoison_tm here, because strptime does not, in fact,
+ // initialize the entire struct tm. For example, tm_zone pointer is left
+ // uninitialized.
+ if (tm) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tm, sizeof(*tm));
+ }
+ return res;
+}
+#define INIT_STRPTIME COMMON_INTERCEPT_FUNCTION(strptime);
+#else
+#define INIT_STRPTIME
+#endif
#if SANITIZER_INTERCEPT_SCANF
@@ -383,9 +589,9 @@ VSCANF_INTERCEPTOR_IMPL(__isoc99_vfscanf, false, stream, format, ap)
#define SCANF_INTERCEPTOR_IMPL(name, vname, ...) \
{ \
void *ctx; \
- COMMON_INTERCEPTOR_ENTER(ctx, name, __VA_ARGS__); \
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; \
@@ -411,40 +617,74 @@ INTERCEPTOR(int, __isoc99_sscanf, const char *str, const char *format, ...)
SCANF_INTERCEPTOR_IMPL(__isoc99_sscanf, __isoc99_vsscanf, str, format)
#endif
-#define INIT_SCANF \
- INTERCEPT_FUNCTION(scanf); \
- INTERCEPT_FUNCTION(sscanf); \
- INTERCEPT_FUNCTION(fscanf); \
- INTERCEPT_FUNCTION(vscanf); \
- INTERCEPT_FUNCTION(vsscanf); \
- INTERCEPT_FUNCTION(vfscanf); \
- INTERCEPT_FUNCTION(__isoc99_scanf); \
- INTERCEPT_FUNCTION(__isoc99_sscanf); \
- INTERCEPT_FUNCTION(__isoc99_fscanf); \
- INTERCEPT_FUNCTION(__isoc99_vscanf); \
- INTERCEPT_FUNCTION(__isoc99_vsscanf); \
- INTERCEPT_FUNCTION(__isoc99_vfscanf);
+#endif
+#if SANITIZER_INTERCEPT_SCANF
+#define INIT_SCANF \
+ COMMON_INTERCEPT_FUNCTION(scanf); \
+ COMMON_INTERCEPT_FUNCTION(sscanf); \
+ COMMON_INTERCEPT_FUNCTION(fscanf); \
+ COMMON_INTERCEPT_FUNCTION(vscanf); \
+ COMMON_INTERCEPT_FUNCTION(vsscanf); \
+ COMMON_INTERCEPT_FUNCTION(vfscanf);
#else
#define INIT_SCANF
#endif
+#if SANITIZER_INTERCEPT_ISOC99_SCANF
+#define INIT_ISOC99_SCANF \
+ COMMON_INTERCEPT_FUNCTION(__isoc99_scanf); \
+ COMMON_INTERCEPT_FUNCTION(__isoc99_sscanf); \
+ COMMON_INTERCEPT_FUNCTION(__isoc99_fscanf); \
+ COMMON_INTERCEPT_FUNCTION(__isoc99_vscanf); \
+ COMMON_INTERCEPT_FUNCTION(__isoc99_vsscanf); \
+ COMMON_INTERCEPT_FUNCTION(__isoc99_vfscanf);
+#else
+#define INIT_ISOC99_SCANF
+#endif
+
+#if SANITIZER_INTERCEPT_IOCTL
+#include "sanitizer_common_interceptors_ioctl.inc"
+INTERCEPTOR(int, ioctl, int d, unsigned request, void *arg) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, ioctl, d, request, arg);
+
+ CHECK(ioctl_initialized);
+
+ // Note: TSan does not use common flags, and they are zero-initialized.
+ // This effectively disables ioctl handling in TSan.
+ 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);
+
+ if (desc) ioctl_common_pre(ctx, desc, d, request, arg);
+ int res = REAL(ioctl)(d, request, arg);
+ // FIXME: some ioctls have different return values for success and failure.
+ if (desc && res != -1) ioctl_common_post(ctx, desc, res, d, request, arg);
+ return res;
+}
+#define INIT_IOCTL \
+ ioctl_init(); \
+ COMMON_INTERCEPT_FUNCTION(ioctl);
+#else
+#define INIT_IOCTL
+#endif
+
#if SANITIZER_INTERCEPT_GETPWNAM_AND_FRIENDS
INTERCEPTOR(void *, 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);
+ if (res != 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_passwd_sz);
return res;
}
INTERCEPTOR(void *, 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);
+ if (res != 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_passwd_sz);
return res;
}
INTERCEPTOR(void *, getgrnam, const char *name) {
@@ -452,31 +692,28 @@ INTERCEPTOR(void *, getgrnam, const char *name) {
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);
+ if (res != 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_group_sz);
return res;
}
INTERCEPTOR(void *, 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);
+ if (res != 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_group_sz);
return res;
}
-#define INIT_GETPWNAM_AND_FRIENDS \
- INTERCEPT_FUNCTION(getpwnam); \
- INTERCEPT_FUNCTION(getpwuid); \
- INTERCEPT_FUNCTION(getgrnam); \
- INTERCEPT_FUNCTION(getgrgid);
+#define INIT_GETPWNAM_AND_FRIENDS \
+ COMMON_INTERCEPT_FUNCTION(getpwnam); \
+ COMMON_INTERCEPT_FUNCTION(getpwuid); \
+ COMMON_INTERCEPT_FUNCTION(getgrnam); \
+ COMMON_INTERCEPT_FUNCTION(getgrgid);
#else
#define INIT_GETPWNAM_AND_FRIENDS
#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, void *pwd, char *buf,
+ SIZE_T buflen, void **result) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, getpwnam_r, name, pwd, buf, buflen, result);
COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1);
@@ -487,8 +724,8 @@ INTERCEPTOR(int, getpwnam_r, const char *name, void *pwd,
}
return res;
}
-INTERCEPTOR(int, getpwuid_r, u32 uid, void *pwd,
- char *buf, SIZE_T buflen, void **result) {
+INTERCEPTOR(int, getpwuid_r, u32 uid, void *pwd, char *buf, SIZE_T buflen,
+ void **result) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, getpwuid_r, uid, pwd, buf, buflen, result);
int res = REAL(getpwuid_r)(uid, pwd, buf, buflen, result);
@@ -498,8 +735,8 @@ INTERCEPTOR(int, getpwuid_r, u32 uid, void *pwd,
}
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, void *grp, char *buf,
+ SIZE_T buflen, void **result) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, getgrnam_r, name, grp, buf, buflen, result);
COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1);
@@ -510,8 +747,8 @@ INTERCEPTOR(int, getgrnam_r, const char *name, void *grp,
}
return res;
}
-INTERCEPTOR(int, getgrgid_r, u32 gid, void *grp,
- char *buf, SIZE_T buflen, void **result) {
+INTERCEPTOR(int, getgrgid_r, u32 gid, void *grp, char *buf, SIZE_T buflen,
+ void **result) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, getgrgid_r, gid, grp, buf, buflen, result);
int res = REAL(getgrgid_r)(gid, grp, buf, buflen, result);
@@ -521,16 +758,15 @@ INTERCEPTOR(int, getgrgid_r, u32 gid, void *grp,
}
return res;
}
-#define INIT_GETPWNAM_R_AND_FRIENDS \
- INTERCEPT_FUNCTION(getpwnam_r); \
- INTERCEPT_FUNCTION(getpwuid_r); \
- INTERCEPT_FUNCTION(getgrnam_r); \
- INTERCEPT_FUNCTION(getgrgid_r);
+#define INIT_GETPWNAM_R_AND_FRIENDS \
+ COMMON_INTERCEPT_FUNCTION(getpwnam_r); \
+ COMMON_INTERCEPT_FUNCTION(getpwuid_r); \
+ COMMON_INTERCEPT_FUNCTION(getgrnam_r); \
+ COMMON_INTERCEPT_FUNCTION(getgrgid_r);
#else
#define INIT_GETPWNAM_R_AND_FRIENDS
#endif
-
#if SANITIZER_INTERCEPT_CLOCK_GETTIME
INTERCEPTOR(int, clock_getres, u32 clk_id, void *tp) {
void *ctx;
@@ -556,21 +792,20 @@ INTERCEPTOR(int, clock_settime, u32 clk_id, const void *tp) {
COMMON_INTERCEPTOR_READ_RANGE(ctx, tp, struct_timespec_sz);
return REAL(clock_settime)(clk_id, tp);
}
-#define INIT_CLOCK_GETTIME \
- INTERCEPT_FUNCTION(clock_getres); \
- INTERCEPT_FUNCTION(clock_gettime); \
- INTERCEPT_FUNCTION(clock_settime);
+#define INIT_CLOCK_GETTIME \
+ COMMON_INTERCEPT_FUNCTION(clock_getres); \
+ COMMON_INTERCEPT_FUNCTION(clock_gettime); \
+ COMMON_INTERCEPT_FUNCTION(clock_settime);
#else
#define INIT_CLOCK_GETTIME
#endif
-
#if SANITIZER_INTERCEPT_GETITIMER
INTERCEPTOR(int, getitimer, int which, void *curr_value) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, getitimer, which, curr_value);
int res = REAL(getitimer)(which, curr_value);
- if (!res) {
+ if (!res && curr_value) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, curr_value, struct_itimerval_sz);
}
return res;
@@ -578,66 +813,134 @@ INTERCEPTOR(int, getitimer, int which, void *curr_value) {
INTERCEPTOR(int, setitimer, int which, const void *new_value, void *old_value) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, setitimer, which, new_value, old_value);
- COMMON_INTERCEPTOR_READ_RANGE(ctx, new_value, struct_itimerval_sz);
+ if (new_value)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, new_value, struct_itimerval_sz);
int res = REAL(setitimer)(which, new_value, old_value);
if (!res && old_value) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, old_value, struct_itimerval_sz);
}
return res;
}
-#define INIT_GETITIMER \
- INTERCEPT_FUNCTION(getitimer); \
- INTERCEPT_FUNCTION(setitimer);
+#define INIT_GETITIMER \
+ COMMON_INTERCEPT_FUNCTION(getitimer); \
+ COMMON_INTERCEPT_FUNCTION(setitimer);
#else
#define INIT_GETITIMER
#endif
-
#if SANITIZER_INTERCEPT_GLOB
-struct sanitizer_glob_t {
- SIZE_T gl_pathc;
- char **gl_pathv;
-};
-
-static void unpoison_glob_t(void *ctx, sanitizer_glob_t *pglob) {
+static void unpoison_glob_t(void *ctx, __sanitizer_glob_t *pglob) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pglob, sizeof(*pglob));
// +1 for NULL pointer at the end.
- COMMON_INTERCEPTOR_WRITE_RANGE(
- ctx, pglob->gl_pathv, (pglob->gl_pathc + 1) * sizeof(*pglob->gl_pathv));
+ if (pglob->gl_pathv)
+ COMMON_INTERCEPTOR_WRITE_RANGE(
+ ctx, pglob->gl_pathv, (pglob->gl_pathc + 1) * sizeof(*pglob->gl_pathv));
for (SIZE_T i = 0; i < pglob->gl_pathc; ++i) {
char *p = pglob->gl_pathv[i];
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, REAL(strlen)(p) + 1);
}
}
+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);
+ pglob_copy->gl_closedir(dir);
+}
+
+static void *wrapped_gl_readdir(void *dir) {
+ COMMON_INTERCEPTOR_UNPOISON_PARAM(glob_ctx, 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);
+ 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);
+ 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);
+ return pglob_copy->gl_stat(s, st);
+}
+
INTERCEPTOR(int, glob, const char *pattern, int flags,
int (*errfunc)(const char *epath, int eerrno),
- sanitizer_glob_t *pglob) {
+ __sanitizer_glob_t *pglob) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, glob, pattern, flags, errfunc, pglob);
+ __sanitizer_glob_t glob_copy = {
+ 0, 0, 0,
+ 0, wrapped_gl_closedir, wrapped_gl_readdir,
+ wrapped_gl_opendir, wrapped_gl_lstat, wrapped_gl_stat};
+ if (flags & glob_altdirfunc) {
+ Swap(pglob->gl_closedir, glob_copy.gl_closedir);
+ Swap(pglob->gl_readdir, glob_copy.gl_readdir);
+ Swap(pglob->gl_opendir, glob_copy.gl_opendir);
+ 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 (res == 0)
- unpoison_glob_t(ctx, pglob);
+ if (flags & glob_altdirfunc) {
+ Swap(pglob->gl_closedir, glob_copy.gl_closedir);
+ Swap(pglob->gl_readdir, glob_copy.gl_readdir);
+ Swap(pglob->gl_opendir, glob_copy.gl_opendir);
+ Swap(pglob->gl_lstat, glob_copy.gl_lstat);
+ 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;
}
INTERCEPTOR(int, glob64, const char *pattern, int flags,
int (*errfunc)(const char *epath, int eerrno),
- sanitizer_glob_t *pglob) {
+ __sanitizer_glob_t *pglob) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, glob64, pattern, flags, errfunc, pglob);
+ __sanitizer_glob_t glob_copy = {
+ 0, 0, 0,
+ 0, wrapped_gl_closedir, wrapped_gl_readdir,
+ wrapped_gl_opendir, wrapped_gl_lstat, wrapped_gl_stat};
+ if (flags & glob_altdirfunc) {
+ Swap(pglob->gl_closedir, glob_copy.gl_closedir);
+ Swap(pglob->gl_readdir, glob_copy.gl_readdir);
+ Swap(pglob->gl_opendir, glob_copy.gl_opendir);
+ 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 (res == 0)
- unpoison_glob_t(ctx, pglob);
+ if (flags & glob_altdirfunc) {
+ Swap(pglob->gl_closedir, glob_copy.gl_closedir);
+ Swap(pglob->gl_readdir, glob_copy.gl_readdir);
+ Swap(pglob->gl_opendir, glob_copy.gl_opendir);
+ Swap(pglob->gl_lstat, glob_copy.gl_lstat);
+ 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;
}
-#define INIT_GLOB \
- INTERCEPT_FUNCTION(glob); \
- INTERCEPT_FUNCTION(glob64);
-#else // SANITIZER_INTERCEPT_GLOB
+#define INIT_GLOB \
+ COMMON_INTERCEPT_FUNCTION(glob); \
+ COMMON_INTERCEPT_FUNCTION(glob64);
+#else // SANITIZER_INTERCEPT_GLOB
#define INIT_GLOB
-#endif // SANITIZER_INTERCEPT_GLOB
-
+#endif // SANITIZER_INTERCEPT_GLOB
#if SANITIZER_INTERCEPT_WAIT
// According to sys/wait.h, wait(), waitid(), waitpid() may have symbol version
@@ -652,7 +955,7 @@ INTERCEPTOR_WITH_SUFFIX(int, wait, int *status) {
return res;
}
INTERCEPTOR_WITH_SUFFIX(int, waitid, int idtype, int id, void *infop,
- int options) {
+ int options) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, waitid, idtype, id, infop, options);
int res = REAL(waitid)(idtype, id, infop, options);
@@ -673,10 +976,8 @@ INTERCEPTOR(int, wait3, int *status, int options, void *rusage) {
COMMON_INTERCEPTOR_ENTER(ctx, wait3, status, options, rusage);
int res = REAL(wait3)(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);
+ if (status) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status));
+ if (rusage) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, rusage, struct_rusage_sz);
}
return res;
}
@@ -685,19 +986,17 @@ INTERCEPTOR(int, wait4, int pid, int *status, int options, void *rusage) {
COMMON_INTERCEPTOR_ENTER(ctx, wait4, pid, status, options, rusage);
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);
+ 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_WAIT \
- INTERCEPT_FUNCTION(wait); \
- INTERCEPT_FUNCTION(waitid); \
- INTERCEPT_FUNCTION(waitpid); \
- INTERCEPT_FUNCTION(wait3); \
- INTERCEPT_FUNCTION(wait4);
+#define INIT_WAIT \
+ COMMON_INTERCEPT_FUNCTION(wait); \
+ COMMON_INTERCEPT_FUNCTION(waitid); \
+ COMMON_INTERCEPT_FUNCTION(waitpid); \
+ COMMON_INTERCEPT_FUNCTION(wait3); \
+ COMMON_INTERCEPT_FUNCTION(wait4);
#else
#define INIT_WAIT
#endif
@@ -710,8 +1009,7 @@ INTERCEPTOR(char *, inet_ntop, int af, const void *src, char *dst, u32 size) {
if (sz) COMMON_INTERCEPTOR_READ_RANGE(ctx, src, sz);
// FIXME: figure out read size based on the address family.
char *res = REAL(inet_ntop)(af, src, dst, size);
- if (res)
- COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
+ if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
return res;
}
INTERCEPTOR(int, inet_pton, int af, const char *src, void *dst) {
@@ -725,13 +1023,30 @@ INTERCEPTOR(int, inet_pton, int af, const char *src, void *dst) {
}
return res;
}
-#define INIT_INET \
- INTERCEPT_FUNCTION(inet_ntop); \
- INTERCEPT_FUNCTION(inet_pton);
+#define INIT_INET \
+ COMMON_INTERCEPT_FUNCTION(inet_ntop); \
+ COMMON_INTERCEPT_FUNCTION(inet_pton);
#else
#define INIT_INET
#endif
+#if SANITIZER_INTERCEPT_INET
+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);
+ int res = REAL(inet_aton)(cp, dst);
+ if (res != 0) {
+ uptr sz = __sanitizer_in_addr_sz(af_inet);
+ if (sz) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, sz);
+ }
+ return res;
+}
+#define INIT_INET_ATON COMMON_INTERCEPT_FUNCTION(inet_aton);
+#else
+#define INIT_INET_ATON
+#endif
+
#if SANITIZER_INTERCEPT_PTHREAD_GETSCHEDPARAM
INTERCEPTOR(int, pthread_getschedparam, uptr thread, int *policy, int *param) {
void *ctx;
@@ -743,7 +1058,8 @@ INTERCEPTOR(int, pthread_getschedparam, uptr thread, int *policy, int *param) {
}
return res;
}
-#define INIT_PTHREAD_GETSCHEDPARAM INTERCEPT_FUNCTION(pthread_getschedparam);
+#define INIT_PTHREAD_GETSCHEDPARAM \
+ COMMON_INTERCEPT_FUNCTION(pthread_getschedparam);
#else
#define INIT_PTHREAD_GETSCHEDPARAM
#endif
@@ -760,12 +1076,13 @@ INTERCEPTOR(int, getaddrinfo, char *node, char *service,
if (hints)
COMMON_INTERCEPTOR_READ_RANGE(ctx, hints, sizeof(__sanitizer_addrinfo));
int res = REAL(getaddrinfo)(node, service, hints, out);
- if (res == 0) {
+ if (res == 0 && out) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, out, sizeof(*out));
struct __sanitizer_addrinfo *p = *out;
while (p) {
- COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, sizeof(__sanitizer_addrinfo));
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, sizeof(*p));
if (p->ai_addr)
- COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->ai_addr, struct_sockaddr_sz);
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->ai_addr, p->ai_addrlen);
if (p->ai_canonname)
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->ai_canonname,
REAL(strlen)(p->ai_canonname) + 1);
@@ -774,11 +1091,34 @@ INTERCEPTOR(int, getaddrinfo, char *node, char *service,
}
return res;
}
-#define INIT_GETADDRINFO INTERCEPT_FUNCTION(getaddrinfo);
+#define INIT_GETADDRINFO COMMON_INTERCEPT_FUNCTION(getaddrinfo);
#else
#define INIT_GETADDRINFO
#endif
+#if SANITIZER_INTERCEPT_GETNAMEINFO
+INTERCEPTOR(int, getnameinfo, void *sockaddr, unsigned salen, char *host,
+ unsigned hostlen, char *serv, unsigned servlen, int flags) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getnameinfo, sockaddr, salen, host, hostlen,
+ serv, servlen, flags);
+ // FIXME: consider adding READ_RANGE(sockaddr, salen)
+ // There is padding in in_addr that may make this too noisy
+ int res =
+ REAL(getnameinfo)(sockaddr, salen, host, hostlen, serv, servlen, flags);
+ if (res == 0) {
+ if (host && hostlen)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, host, REAL(strlen)(host) + 1);
+ if (serv && servlen)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, serv, REAL(strlen)(serv) + 1);
+ }
+ return res;
+}
+#define INIT_GETNAMEINFO COMMON_INTERCEPT_FUNCTION(getnameinfo);
+#else
+#define INIT_GETNAMEINFO
+#endif
+
#if SANITIZER_INTERCEPT_GETSOCKNAME
INTERCEPTOR(int, getsockname, int sock_fd, void *addr, int *addrlen) {
void *ctx;
@@ -791,7 +1131,7 @@ INTERCEPTOR(int, getsockname, int sock_fd, void *addr, int *addrlen) {
}
return res;
}
-#define INIT_GETSOCKNAME INTERCEPT_FUNCTION(getsockname);
+#define INIT_GETSOCKNAME COMMON_INTERCEPT_FUNCTION(getsockname);
#else
#define INIT_GETSOCKNAME
#endif
@@ -837,10 +1177,10 @@ INTERCEPTOR(struct __sanitizer_hostent *, gethostbyaddr, void *addr, int len,
return res;
}
-INTERCEPTOR(struct __sanitizer_hostent *, gethostent) {
+INTERCEPTOR(struct __sanitizer_hostent *, gethostent, int fake) {
void *ctx;
- COMMON_INTERCEPTOR_ENTER(ctx, gethostent);
- struct __sanitizer_hostent *res = REAL(gethostent)();
+ COMMON_INTERCEPTOR_ENTER(ctx, gethostent, fake);
+ struct __sanitizer_hostent *res = REAL(gethostent)(fake);
if (res) write_hostent(ctx, res);
return res;
}
@@ -852,11 +1192,11 @@ INTERCEPTOR(struct __sanitizer_hostent *, gethostbyname2, char *name, int af) {
if (res) write_hostent(ctx, res);
return res;
}
-#define INIT_GETHOSTBYNAME \
- INTERCEPT_FUNCTION(gethostent); \
- INTERCEPT_FUNCTION(gethostbyaddr); \
- INTERCEPT_FUNCTION(gethostbyname); \
- INTERCEPT_FUNCTION(gethostbyname2);
+#define INIT_GETHOSTBYNAME \
+ COMMON_INTERCEPT_FUNCTION(gethostent); \
+ COMMON_INTERCEPT_FUNCTION(gethostbyaddr); \
+ COMMON_INTERCEPT_FUNCTION(gethostbyname); \
+ COMMON_INTERCEPT_FUNCTION(gethostbyname2);
#else
#define INIT_GETHOSTBYNAME
#endif
@@ -935,11 +1275,11 @@ INTERCEPTOR(int, gethostbyname2_r, char *name, int af,
}
return res;
}
-#define INIT_GETHOSTBYNAME_R \
- INTERCEPT_FUNCTION(gethostent_r); \
- INTERCEPT_FUNCTION(gethostbyaddr_r); \
- INTERCEPT_FUNCTION(gethostbyname_r); \
- INTERCEPT_FUNCTION(gethostbyname2_r);
+#define INIT_GETHOSTBYNAME_R \
+ COMMON_INTERCEPT_FUNCTION(gethostent_r); \
+ COMMON_INTERCEPT_FUNCTION(gethostbyaddr_r); \
+ COMMON_INTERCEPT_FUNCTION(gethostbyname_r); \
+ COMMON_INTERCEPT_FUNCTION(gethostbyname2_r);
#else
#define INIT_GETHOSTBYNAME_R
#endif
@@ -956,23 +1296,1555 @@ INTERCEPTOR(int, getsockopt, int sockfd, int level, int optname, void *optval,
if (optval && optlen) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, optval, *optlen);
return res;
}
-#define INIT_GETSOCKOPT INTERCEPT_FUNCTION(getsockopt);
+#define INIT_GETSOCKOPT COMMON_INTERCEPT_FUNCTION(getsockopt);
#else
#define INIT_GETSOCKOPT
#endif
+#if SANITIZER_INTERCEPT_ACCEPT
+INTERCEPTOR(int, accept, int fd, void *addr, unsigned *addrlen) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, accept, fd, addr, addrlen);
+ unsigned addrlen0;
+ if (addrlen) {
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, addrlen, sizeof(*addrlen));
+ addrlen0 = *addrlen;
+ }
+ int fd2 = REAL(accept)(fd, addr, addrlen);
+ if (fd2 >= 0) {
+ if (fd >= 0) COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, fd2);
+ if (addr && addrlen)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, Min(*addrlen, addrlen0));
+ }
+ return fd2;
+}
+#define INIT_ACCEPT COMMON_INTERCEPT_FUNCTION(accept);
+#else
+#define INIT_ACCEPT
+#endif
+
+#if SANITIZER_INTERCEPT_ACCEPT4
+INTERCEPTOR(int, accept4, int fd, void *addr, unsigned *addrlen, int f) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, accept4, fd, addr, addrlen, f);
+ unsigned addrlen0;
+ if (addrlen) {
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, addrlen, sizeof(*addrlen));
+ addrlen0 = *addrlen;
+ }
+ int fd2 = REAL(accept4)(fd, addr, addrlen, f);
+ if (fd2 >= 0) {
+ if (fd >= 0) COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, fd2);
+ if (addr && addrlen)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, Min(*addrlen, addrlen0));
+ }
+ return fd2;
+}
+#define INIT_ACCEPT4 COMMON_INTERCEPT_FUNCTION(accept4);
+#else
+#define INIT_ACCEPT4
+#endif
+
+#if SANITIZER_INTERCEPT_MODF
+INTERCEPTOR(double, modf, double x, double *iptr) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, modf, x, iptr);
+ double res = REAL(modf)(x, iptr);
+ if (iptr) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, iptr, sizeof(*iptr));
+ }
+ return res;
+}
+INTERCEPTOR(float, modff, float x, float *iptr) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, modff, x, iptr);
+ float res = REAL(modff)(x, iptr);
+ if (iptr) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, iptr, sizeof(*iptr));
+ }
+ return res;
+}
+INTERCEPTOR(long double, modfl, long double x, long double *iptr) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, modfl, x, iptr);
+ long double res = REAL(modfl)(x, iptr);
+ if (iptr) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, iptr, sizeof(*iptr));
+ }
+ return res;
+}
+#define INIT_MODF \
+ COMMON_INTERCEPT_FUNCTION(modf); \
+ COMMON_INTERCEPT_FUNCTION(modff); \
+ COMMON_INTERCEPT_FUNCTION(modfl);
+#else
+#define INIT_MODF
+#endif
+
+#if SANITIZER_INTERCEPT_RECVMSG
+static void write_msghdr(void *ctx, struct __sanitizer_msghdr *msg,
+ SSIZE_T maxlen) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, msg, sizeof(*msg));
+ if (msg->msg_name && msg->msg_namelen)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, msg->msg_name, msg->msg_namelen);
+ if (msg->msg_iov && msg->msg_iovlen)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, msg->msg_iov,
+ sizeof(*msg->msg_iov) * msg->msg_iovlen);
+ write_iovec(ctx, msg->msg_iov, msg->msg_iovlen, maxlen);
+ if (msg->msg_control && msg->msg_controllen)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, msg->msg_control, msg->msg_controllen);
+}
+
+INTERCEPTOR(SSIZE_T, recvmsg, int fd, struct __sanitizer_msghdr *msg,
+ int flags) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, recvmsg, fd, msg, flags);
+ 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);
+ }
+ return res;
+}
+#define INIT_RECVMSG COMMON_INTERCEPT_FUNCTION(recvmsg);
+#else
+#define INIT_RECVMSG
+#endif
+
+#if SANITIZER_INTERCEPT_GETPEERNAME
+INTERCEPTOR(int, getpeername, int sockfd, void *addr, unsigned *addrlen) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getpeername, sockfd, addr, addrlen);
+ unsigned addr_sz;
+ if (addrlen) addr_sz = *addrlen;
+ int res = REAL(getpeername)(sockfd, addr, addrlen);
+ if (!res && addr && addrlen)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, Min(addr_sz, *addrlen));
+ return res;
+}
+#define INIT_GETPEERNAME COMMON_INTERCEPT_FUNCTION(getpeername);
+#else
+#define INIT_GETPEERNAME
+#endif
+
+#if SANITIZER_INTERCEPT_SYSINFO
+INTERCEPTOR(int, sysinfo, void *info) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, sysinfo, info);
+ int res = REAL(sysinfo)(info);
+ if (!res && info)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, info, struct_sysinfo_sz);
+ return res;
+}
+#define INIT_SYSINFO COMMON_INTERCEPT_FUNCTION(sysinfo);
+#else
+#define INIT_SYSINFO
+#endif
+
+#if SANITIZER_INTERCEPT_READDIR
+INTERCEPTOR(__sanitizer_dirent *, readdir, void *dirp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, readdir, dirp);
+ __sanitizer_dirent *res = REAL(readdir)(dirp);
+ if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, res->d_reclen);
+ return res;
+}
+
+INTERCEPTOR(int, readdir_r, void *dirp, __sanitizer_dirent *entry,
+ __sanitizer_dirent **result) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, readdir_r, dirp, entry, result);
+ int res = REAL(readdir_r)(dirp, entry, result);
+ if (!res) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
+ if (*result)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *result, (*result)->d_reclen);
+ }
+ return res;
+}
+
+#define INIT_READDIR \
+ COMMON_INTERCEPT_FUNCTION(readdir); \
+ COMMON_INTERCEPT_FUNCTION(readdir_r);
+#else
+#define INIT_READDIR
+#endif
+
+#if SANITIZER_INTERCEPT_READDIR64
+INTERCEPTOR(__sanitizer_dirent64 *, readdir64, void *dirp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, readdir64, dirp);
+ __sanitizer_dirent64 *res = REAL(readdir64)(dirp);
+ if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, res->d_reclen);
+ return res;
+}
+
+INTERCEPTOR(int, readdir64_r, void *dirp, __sanitizer_dirent64 *entry,
+ __sanitizer_dirent64 **result) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, readdir64_r, dirp, entry, result);
+ int res = REAL(readdir64_r)(dirp, entry, result);
+ if (!res) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
+ if (*result)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *result, (*result)->d_reclen);
+ }
+ return res;
+}
+#define INIT_READDIR64 \
+ COMMON_INTERCEPT_FUNCTION(readdir64); \
+ COMMON_INTERCEPT_FUNCTION(readdir64_r);
+#else
+#define INIT_READDIR64
+#endif
+
+#if SANITIZER_INTERCEPT_PTRACE
+INTERCEPTOR(uptr, ptrace, int request, int pid, void *addr, void *data) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, ptrace, request, pid, addr, data);
+
+ if (data) {
+ if (request == ptrace_setregs)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, data, struct_user_regs_struct_sz);
+ else if (request == ptrace_setfpregs)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, data, struct_user_fpregs_struct_sz);
+ else if (request == ptrace_setfpxregs)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, data, struct_user_fpxregs_struct_sz);
+ else if (request == ptrace_setsiginfo)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, data, siginfo_t_sz);
+ else if (request == ptrace_setregset) {
+ __sanitizer_iovec *iov = (__sanitizer_iovec *)data;
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, iov->iov_base, iov->iov_len);
+ }
+ }
+
+ uptr res = REAL(ptrace)(request, pid, addr, data);
+
+ if (!res && data) {
+ // Note that PEEK* requests assing 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);
+ else if (request == ptrace_getfpregs)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, struct_user_fpregs_struct_sz);
+ else if (request == ptrace_getfpxregs)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, struct_user_fpxregs_struct_sz);
+ else if (request == ptrace_getsiginfo)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, siginfo_t_sz);
+ else if (request == ptrace_getregset) {
+ __sanitizer_iovec *iov = (__sanitizer_iovec *)data;
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, iov->iov_base, iov->iov_len);
+ }
+ }
+ return res;
+}
+
+#define INIT_PTRACE COMMON_INTERCEPT_FUNCTION(ptrace);
+#else
+#define INIT_PTRACE
+#endif
+
+#if SANITIZER_INTERCEPT_SETLOCALE
+INTERCEPTOR(char *, setlocale, int category, char *locale) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, setlocale, category, locale);
+ if (locale)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, locale, REAL(strlen)(locale) + 1);
+ char *res = REAL(setlocale)(category, locale);
+ if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
+ return res;
+}
+
+#define INIT_SETLOCALE COMMON_INTERCEPT_FUNCTION(setlocale);
+#else
+#define INIT_SETLOCALE
+#endif
+
+#if SANITIZER_INTERCEPT_GETCWD
+INTERCEPTOR(char *, getcwd, char *buf, SIZE_T size) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getcwd, buf, size);
+ char *res = REAL(getcwd)(buf, size);
+ if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
+ return res;
+}
+#define INIT_GETCWD COMMON_INTERCEPT_FUNCTION(getcwd);
+#else
+#define INIT_GETCWD
+#endif
+
+#if SANITIZER_INTERCEPT_GET_CURRENT_DIR_NAME
+INTERCEPTOR(char *, get_current_dir_name, int fake) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, get_current_dir_name, fake);
+ char *res = REAL(get_current_dir_name)(fake);
+ if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
+ return res;
+}
+
+#define INIT_GET_CURRENT_DIR_NAME \
+ COMMON_INTERCEPT_FUNCTION(get_current_dir_name);
+#else
+#define INIT_GET_CURRENT_DIR_NAME
+#endif
+
+#if SANITIZER_INTERCEPT_STRTOIMAX
+INTERCEPTOR(INTMAX_T, strtoimax, const char *nptr, char **endptr, int base) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, strtoimax, nptr, endptr, base);
+ INTMAX_T res = REAL(strtoimax)(nptr, endptr, base);
+ if (endptr) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, endptr, sizeof(*endptr));
+ return res;
+}
+
+INTERCEPTOR(INTMAX_T, strtoumax, const char *nptr, char **endptr, int base) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, strtoumax, nptr, endptr, base);
+ INTMAX_T res = REAL(strtoumax)(nptr, endptr, base);
+ if (endptr) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, endptr, sizeof(*endptr));
+ return res;
+}
+
+#define INIT_STRTOIMAX \
+ COMMON_INTERCEPT_FUNCTION(strtoimax); \
+ COMMON_INTERCEPT_FUNCTION(strtoumax);
+#else
+#define INIT_STRTOIMAX
+#endif
+
+#if SANITIZER_INTERCEPT_MBSTOWCS
+INTERCEPTOR(SIZE_T, mbstowcs, wchar_t *dest, const char *src, SIZE_T len) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, mbstowcs, dest, src, len);
+ SIZE_T res = REAL(mbstowcs)(dest, src, len);
+ if (res != (SIZE_T) - 1 && dest) {
+ SIZE_T write_cnt = res + (res < len);
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, write_cnt * sizeof(wchar_t));
+ }
+ return res;
+}
+
+INTERCEPTOR(SIZE_T, mbsrtowcs, wchar_t *dest, const char **src, SIZE_T len,
+ void *ps) {
+ void *ctx;
+ 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);
+ 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
+ // \0 character. They write it iff they clear *src.
+ SIZE_T write_cnt = res + !*src;
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, write_cnt * sizeof(wchar_t));
+ }
+ return res;
+}
+
+#define INIT_MBSTOWCS \
+ COMMON_INTERCEPT_FUNCTION(mbstowcs); \
+ COMMON_INTERCEPT_FUNCTION(mbsrtowcs);
+#else
+#define INIT_MBSTOWCS
+#endif
+
+#if SANITIZER_INTERCEPT_MBSNRTOWCS
+INTERCEPTOR(SIZE_T, mbsnrtowcs, wchar_t *dest, const char **src, SIZE_T nms,
+ SIZE_T len, void *ps) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, mbsnrtowcs, dest, src, nms, len, ps);
+ if (src) {
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, src, sizeof(*src));
+ if (nms) COMMON_INTERCEPTOR_READ_RANGE(ctx, *src, nms);
+ }
+ if (ps) COMMON_INTERCEPTOR_READ_RANGE(ctx, ps, mbstate_t_sz);
+ SIZE_T res = REAL(mbsnrtowcs)(dest, src, nms, len, ps);
+ if (res != (SIZE_T)(-1) && dest && src) {
+ SIZE_T write_cnt = res + !*src;
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, write_cnt * sizeof(wchar_t));
+ }
+ return res;
+}
+
+#define INIT_MBSNRTOWCS COMMON_INTERCEPT_FUNCTION(mbsnrtowcs);
+#else
+#define INIT_MBSNRTOWCS
+#endif
+
+#if SANITIZER_INTERCEPT_WCSTOMBS
+INTERCEPTOR(SIZE_T, wcstombs, char *dest, const wchar_t *src, SIZE_T len) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, wcstombs, dest, src, len);
+ SIZE_T res = REAL(wcstombs)(dest, src, len);
+ if (res != (SIZE_T) - 1 && dest) {
+ SIZE_T write_cnt = res + (res < len);
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, write_cnt);
+ }
+ return res;
+}
+
+INTERCEPTOR(SIZE_T, wcsrtombs, char *dest, const wchar_t **src, SIZE_T len,
+ void *ps) {
+ void *ctx;
+ 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);
+ SIZE_T res = REAL(wcsrtombs)(dest, src, len, ps);
+ if (res != (SIZE_T) - 1 && dest && src) {
+ SIZE_T write_cnt = res + !*src;
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, write_cnt);
+ }
+ return res;
+}
+
+#define INIT_WCSTOMBS \
+ COMMON_INTERCEPT_FUNCTION(wcstombs); \
+ COMMON_INTERCEPT_FUNCTION(wcsrtombs);
+#else
+#define INIT_WCSTOMBS
+#endif
+
+#if SANITIZER_INTERCEPT_WCSNRTOMBS
+INTERCEPTOR(SIZE_T, wcsnrtombs, char *dest, const wchar_t **src, SIZE_T nms,
+ SIZE_T len, void *ps) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, wcsnrtombs, dest, src, nms, len, ps);
+ if (src) {
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, src, sizeof(*src));
+ if (nms) COMMON_INTERCEPTOR_READ_RANGE(ctx, *src, nms);
+ }
+ if (ps) COMMON_INTERCEPTOR_READ_RANGE(ctx, ps, mbstate_t_sz);
+ SIZE_T res = REAL(wcsnrtombs)(dest, src, nms, len, ps);
+ if (res != (SIZE_T) - 1 && dest && src) {
+ SIZE_T write_cnt = res + !*src;
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, write_cnt);
+ }
+ return res;
+}
+
+#define INIT_WCSNRTOMBS COMMON_INTERCEPT_FUNCTION(wcsnrtombs);
+#else
+#define INIT_WCSNRTOMBS
+#endif
+
+#if SANITIZER_INTERCEPT_TCGETATTR
+INTERCEPTOR(int, tcgetattr, int fd, void *termios_p) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, tcgetattr, fd, termios_p);
+ int res = REAL(tcgetattr)(fd, termios_p);
+ if (!res && termios_p)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, termios_p, struct_termios_sz);
+ return res;
+}
+
+#define INIT_TCGETATTR COMMON_INTERCEPT_FUNCTION(tcgetattr);
+#else
+#define INIT_TCGETATTR
+#endif
+
+#if SANITIZER_INTERCEPT_REALPATH
+INTERCEPTOR(char *, realpath, const char *path, char *resolved_path) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, realpath, path, resolved_path);
+ if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
+
+ // Workaround a bug in glibc where dlsym(RTLD_NEXT, ...) returns the oldest
+ // version of a versioned symbol. For realpath(), this gives us something
+ // (called __old_realpath) that does not handle NULL in the second argument.
+ // Handle it as part of the interceptor.
+ char *allocated_path = 0;
+ if (!resolved_path)
+ allocated_path = resolved_path = (char *)WRAP(malloc)(path_max + 1);
+
+ char *res = REAL(realpath)(path, resolved_path);
+ if (allocated_path && !res) WRAP(free)(allocated_path);
+ if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
+ return res;
+}
+#define INIT_REALPATH COMMON_INTERCEPT_FUNCTION(realpath);
+#else
+#define INIT_REALPATH
+#endif
+
+#if SANITIZER_INTERCEPT_CANONICALIZE_FILE_NAME
+INTERCEPTOR(char *, canonicalize_file_name, const char *path) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, canonicalize_file_name, path);
+ if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
+ char *res = REAL(canonicalize_file_name)(path);
+ if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
+ return res;
+}
+#define INIT_CANONICALIZE_FILE_NAME \
+ COMMON_INTERCEPT_FUNCTION(canonicalize_file_name);
+#else
+#define INIT_CANONICALIZE_FILE_NAME
+#endif
+
+#if SANITIZER_INTERCEPT_CONFSTR
+INTERCEPTOR(SIZE_T, confstr, int name, char *buf, SIZE_T len) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, confstr, name, buf, len);
+ SIZE_T res = REAL(confstr)(name, buf, len);
+ if (buf && res)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, res < len ? res : len);
+ return res;
+}
+#define INIT_CONFSTR COMMON_INTERCEPT_FUNCTION(confstr);
+#else
+#define INIT_CONFSTR
+#endif
+
+#if SANITIZER_INTERCEPT_SCHED_GETAFFINITY
+INTERCEPTOR(int, sched_getaffinity, int pid, SIZE_T cpusetsize, void *mask) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, sched_getaffinity, pid, cpusetsize, mask);
+ int res = REAL(sched_getaffinity)(pid, cpusetsize, mask);
+ if (mask && !res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, mask, cpusetsize);
+ return res;
+}
+#define INIT_SCHED_GETAFFINITY COMMON_INTERCEPT_FUNCTION(sched_getaffinity);
+#else
+#define INIT_SCHED_GETAFFINITY
+#endif
+
+#if SANITIZER_INTERCEPT_STRERROR
+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);
+ return res;
+}
+#define INIT_STRERROR COMMON_INTERCEPT_FUNCTION(strerror);
+#else
+#define INIT_STRERROR
+#endif
+
+#if SANITIZER_INTERCEPT_STRERROR_R
+INTERCEPTOR(char *, strerror_r, int errnum, char *buf, SIZE_T buflen) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, strerror_r, errnum, buf, buflen);
+ 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,
+ // writes message to buf.
+ // * GNU version returns message pointer, which points to either buf or some
+ // static storage.
+ SIZE_T posix_res = (SIZE_T)res;
+ if (posix_res < 1024 || posix_res > (SIZE_T) - 1024) {
+ // POSIX version. Spec is not clear on whether buf is NULL-terminated.
+ // At least on OSX, buf contents are valid even when the call fails.
+ SIZE_T sz = internal_strnlen(buf, buflen);
+ if (sz < buflen) ++sz;
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, sz);
+ } else {
+ // GNU version.
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
+ }
+ return res;
+}
+#define INIT_STRERROR_R COMMON_INTERCEPT_FUNCTION(strerror_r);
+#else
+#define INIT_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);
+ 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);
+ return scandir_compar(a, b);
+}
+
+INTERCEPTOR(int, scandir, char *dirp, __sanitizer_dirent ***namelist,
+ scandir_filter_f filter, scandir_compar_f compar) {
+ 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;
+ 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) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, namelist, sizeof(*namelist));
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *namelist, sizeof(**namelist) * res);
+ for (int i = 0; i < res; ++i)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, (*namelist)[i],
+ (*namelist)[i]->d_reclen);
+ }
+ return res;
+}
+#define INIT_SCANDIR COMMON_INTERCEPT_FUNCTION(scandir);
+#else
+#define INIT_SCANDIR
+#endif
+
+#if SANITIZER_INTERCEPT_SCANDIR64
+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);
+ 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);
+ return scandir64_compar(a, b);
+}
+
+INTERCEPTOR(int, scandir64, char *dirp, __sanitizer_dirent64 ***namelist,
+ scandir64_filter_f filter, scandir64_compar_f compar) {
+ 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;
+ 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) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, namelist, sizeof(*namelist));
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *namelist, sizeof(**namelist) * res);
+ for (int i = 0; i < res; ++i)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, (*namelist)[i],
+ (*namelist)[i]->d_reclen);
+ }
+ return res;
+}
+#define INIT_SCANDIR64 COMMON_INTERCEPT_FUNCTION(scandir64);
+#else
+#define INIT_SCANDIR64
+#endif
+
+#if SANITIZER_INTERCEPT_GETGROUPS
+INTERCEPTOR(int, getgroups, int size, u32 *lst) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getgroups, size, lst);
+ int res = REAL(getgroups)(size, lst);
+ if (res && lst) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, lst, res * sizeof(*lst));
+ return res;
+}
+#define INIT_GETGROUPS COMMON_INTERCEPT_FUNCTION(getgroups);
+#else
+#define INIT_GETGROUPS
+#endif
+
+#if SANITIZER_INTERCEPT_POLL
+static void read_pollfd(void *ctx, __sanitizer_pollfd *fds,
+ __sanitizer_nfds_t nfds) {
+ for (unsigned i = 0; i < nfds; ++i) {
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, &fds[i].fd, sizeof(fds[i].fd));
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, &fds[i].events, sizeof(fds[i].events));
+ }
+}
+
+static void write_pollfd(void *ctx, __sanitizer_pollfd *fds,
+ __sanitizer_nfds_t nfds) {
+ for (unsigned i = 0; i < nfds; ++i)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, &fds[i].revents,
+ sizeof(fds[i].revents));
+}
+
+INTERCEPTOR(int, poll, __sanitizer_pollfd *fds, __sanitizer_nfds_t nfds,
+ int timeout) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, poll, fds, nfds, timeout);
+ if (fds && nfds) read_pollfd(ctx, fds, nfds);
+ int res = COMMON_INTERCEPTOR_BLOCK_REAL(poll)(fds, nfds, timeout);
+ if (fds && nfds) write_pollfd(ctx, fds, nfds);
+ return res;
+}
+#define INIT_POLL COMMON_INTERCEPT_FUNCTION(poll);
+#else
+#define INIT_POLL
+#endif
+
+#if SANITIZER_INTERCEPT_PPOLL
+INTERCEPTOR(int, ppoll, __sanitizer_pollfd *fds, __sanitizer_nfds_t nfds,
+ void *timeout_ts, __sanitizer_sigset_t *sigmask) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, ppoll, fds, nfds, timeout_ts, sigmask);
+ if (fds && nfds) read_pollfd(ctx, fds, nfds);
+ if (timeout_ts)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, timeout_ts, struct_timespec_sz);
+ // FIXME: read sigmask when all of sigemptyset, etc are intercepted.
+ int res =
+ COMMON_INTERCEPTOR_BLOCK_REAL(ppoll)(fds, nfds, timeout_ts, sigmask);
+ if (fds && nfds) write_pollfd(ctx, fds, nfds);
+ return res;
+}
+#define INIT_PPOLL COMMON_INTERCEPT_FUNCTION(ppoll);
+#else
+#define INIT_PPOLL
+#endif
+
+#if SANITIZER_INTERCEPT_WORDEXP
+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);
+ int res = REAL(wordexp)(s, p, flags);
+ if (!res && p) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, sizeof(*p));
+ if (p->we_wordc)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->we_wordv,
+ sizeof(*p->we_wordv) * p->we_wordc);
+ for (uptr i = 0; i < p->we_wordc; ++i) {
+ char *w = p->we_wordv[i];
+ if (w) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, w, REAL(strlen)(w) + 1);
+ }
+ }
+ return res;
+}
+#define INIT_WORDEXP COMMON_INTERCEPT_FUNCTION(wordexp);
+#else
+#define INIT_WORDEXP
+#endif
+
+#if SANITIZER_INTERCEPT_SIGWAIT
+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
+ int res = REAL(sigwait)(set, sig);
+ if (!res && sig) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sig, sizeof(*sig));
+ return res;
+}
+#define INIT_SIGWAIT COMMON_INTERCEPT_FUNCTION(sigwait);
+#else
+#define INIT_SIGWAIT
+#endif
+
+#if SANITIZER_INTERCEPT_SIGWAITINFO
+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
+ int res = REAL(sigwaitinfo)(set, info);
+ if (res > 0 && info) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, info, siginfo_t_sz);
+ return res;
+}
+#define INIT_SIGWAITINFO COMMON_INTERCEPT_FUNCTION(sigwaitinfo);
+#else
+#define INIT_SIGWAITINFO
+#endif
+
+#if SANITIZER_INTERCEPT_SIGTIMEDWAIT
+INTERCEPTOR(int, sigtimedwait, __sanitizer_sigset_t *set, void *info,
+ void *timeout) {
+ void *ctx;
+ 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
+ int res = REAL(sigtimedwait)(set, info, timeout);
+ if (res > 0 && info) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, info, siginfo_t_sz);
+ return res;
+}
+#define INIT_SIGTIMEDWAIT COMMON_INTERCEPT_FUNCTION(sigtimedwait);
+#else
+#define INIT_SIGTIMEDWAIT
+#endif
+
+#if SANITIZER_INTERCEPT_SIGSETOPS
+INTERCEPTOR(int, sigemptyset, __sanitizer_sigset_t *set) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, sigemptyset, set);
+ int res = REAL(sigemptyset)(set);
+ if (!res && set) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, set, sizeof(*set));
+ return res;
+}
+
+INTERCEPTOR(int, sigfillset, __sanitizer_sigset_t *set) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, sigfillset, set);
+ int res = REAL(sigfillset)(set);
+ if (!res && set) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, set, sizeof(*set));
+ return res;
+}
+#define INIT_SIGSETOPS \
+ COMMON_INTERCEPT_FUNCTION(sigemptyset); \
+ COMMON_INTERCEPT_FUNCTION(sigfillset);
+#else
+#define INIT_SIGSETOPS
+#endif
+
+#if SANITIZER_INTERCEPT_SIGPENDING
+INTERCEPTOR(int, sigpending, __sanitizer_sigset_t *set) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, sigpending, set);
+ int res = REAL(sigpending)(set);
+ if (!res && set) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, set, sizeof(*set));
+ return res;
+}
+#define INIT_SIGPENDING COMMON_INTERCEPT_FUNCTION(sigpending);
+#else
+#define INIT_SIGPENDING
+#endif
+
+#if SANITIZER_INTERCEPT_SIGPROCMASK
+INTERCEPTOR(int, sigprocmask, int how, __sanitizer_sigset_t *set,
+ __sanitizer_sigset_t *oldset) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, sigprocmask, how, set, oldset);
+ // FIXME: read sigset_t when all of sigemptyset, etc are intercepted
+ int res = REAL(sigprocmask)(how, set, oldset);
+ if (!res && oldset)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, oldset, sizeof(*oldset));
+ return res;
+}
+#define INIT_SIGPROCMASK COMMON_INTERCEPT_FUNCTION(sigprocmask);
+#else
+#define INIT_SIGPROCMASK
+#endif
+
+#if SANITIZER_INTERCEPT_BACKTRACE
+INTERCEPTOR(int, backtrace, void **buffer, int size) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, backtrace, buffer, size);
+ int res = REAL(backtrace)(buffer, size);
+ if (res && buffer)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buffer, res * sizeof(*buffer));
+ return res;
+}
+
+INTERCEPTOR(char **, backtrace_symbols, void **buffer, int size) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, backtrace_symbols, buffer, size);
+ if (buffer && size)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, buffer, size * sizeof(*buffer));
+ char **res = REAL(backtrace_symbols)(buffer, size);
+ if (res && size) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, size * sizeof(*res));
+ for (int i = 0; i < size; ++i)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res[i], REAL(strlen(res[i])) + 1);
+ }
+ return res;
+}
+#define INIT_BACKTRACE \
+ COMMON_INTERCEPT_FUNCTION(backtrace); \
+ COMMON_INTERCEPT_FUNCTION(backtrace_symbols);
+#else
+#define INIT_BACKTRACE
+#endif
+
+#if SANITIZER_INTERCEPT__EXIT
+INTERCEPTOR(void, _exit, int status) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, _exit, status);
+ int status1 = COMMON_INTERCEPTOR_ON_EXIT(ctx);
+ if (status == 0) status = status1;
+ REAL(_exit)(status);
+}
+#define INIT__EXIT COMMON_INTERCEPT_FUNCTION(_exit);
+#else
+#define INIT__EXIT
+#endif
+
+#if SANITIZER_INTERCEPT_PHTREAD_MUTEX
+INTERCEPTOR(int, pthread_mutex_lock, void *m) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, pthread_mutex_lock, m);
+ int res = REAL(pthread_mutex_lock)(m);
+ if (res == errno_EOWNERDEAD)
+ COMMON_INTERCEPTOR_MUTEX_REPAIR(ctx, m);
+ if (res == 0 || res == errno_EOWNERDEAD)
+ COMMON_INTERCEPTOR_MUTEX_LOCK(ctx, m);
+ return res;
+}
+
+INTERCEPTOR(int, pthread_mutex_unlock, void *m) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, pthread_mutex_unlock, m);
+ COMMON_INTERCEPTOR_MUTEX_UNLOCK(ctx, m);
+ return REAL(pthread_mutex_unlock)(m);
+}
+
+#define INIT_PTHREAD_MUTEX_LOCK COMMON_INTERCEPT_FUNCTION(pthread_mutex_lock)
+#define INIT_PTHREAD_MUTEX_UNLOCK \
+ COMMON_INTERCEPT_FUNCTION(pthread_mutex_unlock)
+#else
+#define INIT_PTHREAD_MUTEX_LOCK
+#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));
+ if (mnt->mnt_fsname)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, mnt->mnt_fsname,
+ REAL(strlen)(mnt->mnt_fsname) + 1);
+ if (mnt->mnt_dir)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, mnt->mnt_dir,
+ REAL(strlen)(mnt->mnt_dir) + 1);
+ if (mnt->mnt_type)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, mnt->mnt_type,
+ REAL(strlen)(mnt->mnt_type) + 1);
+ if (mnt->mnt_opts)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, mnt->mnt_opts,
+ REAL(strlen)(mnt->mnt_opts) + 1);
+}
+#endif
+
+#if SANITIZER_INTERCEPT_GETMNTENT
+INTERCEPTOR(__sanitizer_mntent *, getmntent, void *fp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getmntent, fp);
+ __sanitizer_mntent *res = REAL(getmntent)(fp);
+ if (res) write_mntent(ctx, res);
+ return res;
+}
+#define INIT_GETMNTENT COMMON_INTERCEPT_FUNCTION(getmntent);
+#else
+#define INIT_GETMNTENT
+#endif
+
+#if SANITIZER_INTERCEPT_GETMNTENT_R
+INTERCEPTOR(__sanitizer_mntent *, getmntent_r, void *fp,
+ __sanitizer_mntent *mntbuf, char *buf, int buflen) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getmntent_r, fp, mntbuf, buf, buflen);
+ __sanitizer_mntent *res = REAL(getmntent_r)(fp, mntbuf, buf, buflen);
+ if (res) write_mntent(ctx, res);
+ return res;
+}
+#define INIT_GETMNTENT_R COMMON_INTERCEPT_FUNCTION(getmntent_r);
+#else
+#define INIT_GETMNTENT_R
+#endif
+
+#if SANITIZER_INTERCEPT_STATFS
+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);
+ int res = REAL(statfs)(path, buf);
+ if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statfs_sz);
+ return res;
+}
+INTERCEPTOR(int, fstatfs, int fd, void *buf) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, fstatfs, fd, buf);
+ int res = REAL(fstatfs)(fd, buf);
+ if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statfs_sz);
+ return res;
+}
+#define INIT_STATFS \
+ COMMON_INTERCEPT_FUNCTION(statfs); \
+ COMMON_INTERCEPT_FUNCTION(fstatfs);
+#else
+#define INIT_STATFS
+#endif
+
+#if SANITIZER_INTERCEPT_STATFS64
+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);
+ int res = REAL(statfs64)(path, buf);
+ if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statfs64_sz);
+ return res;
+}
+INTERCEPTOR(int, fstatfs64, int fd, void *buf) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, fstatfs64, fd, buf);
+ int res = REAL(fstatfs64)(fd, buf);
+ if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statfs64_sz);
+ return res;
+}
+#define INIT_STATFS64 \
+ COMMON_INTERCEPT_FUNCTION(statfs64); \
+ COMMON_INTERCEPT_FUNCTION(fstatfs64);
+#else
+#define INIT_STATFS64
+#endif
+
+#if SANITIZER_INTERCEPT_STATVFS
+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);
+ int res = REAL(statvfs)(path, buf);
+ if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs_sz);
+ return res;
+}
+INTERCEPTOR(int, fstatvfs, int fd, void *buf) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, fstatvfs, fd, buf);
+ int res = REAL(fstatvfs)(fd, buf);
+ if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs_sz);
+ return res;
+}
+#define INIT_STATVFS \
+ COMMON_INTERCEPT_FUNCTION(statvfs); \
+ COMMON_INTERCEPT_FUNCTION(fstatvfs);
+#else
+#define INIT_STATVFS
+#endif
+
+#if SANITIZER_INTERCEPT_STATVFS64
+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);
+ int res = REAL(statvfs64)(path, buf);
+ if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs64_sz);
+ return res;
+}
+INTERCEPTOR(int, fstatvfs64, int fd, void *buf) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, fstatvfs64, fd, buf);
+ int res = REAL(fstatvfs64)(fd, buf);
+ if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs64_sz);
+ return res;
+}
+#define INIT_STATVFS64 \
+ COMMON_INTERCEPT_FUNCTION(statvfs64); \
+ COMMON_INTERCEPT_FUNCTION(fstatvfs64);
+#else
+#define INIT_STATVFS64
+#endif
+
+#if SANITIZER_INTERCEPT_INITGROUPS
+INTERCEPTOR(int, initgroups, char *user, u32 group) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, initgroups, user, group);
+ if (user) COMMON_INTERCEPTOR_READ_RANGE(ctx, user, REAL(strlen)(user) + 1);
+ int res = REAL(initgroups)(user, group);
+ return res;
+}
+#define INIT_INITGROUPS COMMON_INTERCEPT_FUNCTION(initgroups);
+#else
+#define INIT_INITGROUPS
+#endif
+
+#if SANITIZER_INTERCEPT_ETHER
+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);
+ return res;
+}
+INTERCEPTOR(__sanitizer_ether_addr *, ether_aton, char *buf) {
+ void *ctx;
+ 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));
+ return res;
+}
+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));
+ int res = REAL(ether_ntohost)(hostname, addr);
+ if (!res && hostname)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, hostname, REAL(strlen)(hostname) + 1);
+ return res;
+}
+INTERCEPTOR(int, ether_hostton, char *hostname, __sanitizer_ether_addr *addr) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, ether_hostton, hostname, addr);
+ if (hostname)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, hostname, REAL(strlen)(hostname) + 1);
+ int res = REAL(ether_hostton)(hostname, addr);
+ if (!res && addr) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, sizeof(*addr));
+ return res;
+}
+INTERCEPTOR(int, ether_line, char *line, __sanitizer_ether_addr *addr,
+ char *hostname) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, ether_line, line, addr, hostname);
+ if (line) COMMON_INTERCEPTOR_READ_RANGE(ctx, line, REAL(strlen)(line) + 1);
+ int res = REAL(ether_line)(line, addr, hostname);
+ if (!res) {
+ if (addr) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, sizeof(*addr));
+ if (hostname)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, hostname, REAL(strlen)(hostname) + 1);
+ }
+ return res;
+}
+#define INIT_ETHER \
+ COMMON_INTERCEPT_FUNCTION(ether_ntoa); \
+ COMMON_INTERCEPT_FUNCTION(ether_aton); \
+ COMMON_INTERCEPT_FUNCTION(ether_ntohost); \
+ COMMON_INTERCEPT_FUNCTION(ether_hostton); \
+ COMMON_INTERCEPT_FUNCTION(ether_line);
+#else
+#define INIT_ETHER
+#endif
+
+#if SANITIZER_INTERCEPT_ETHER_R
+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));
+ char *res = REAL(ether_ntoa_r)(addr, buf);
+ if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
+ return res;
+}
+INTERCEPTOR(__sanitizer_ether_addr *, ether_aton_r, char *buf,
+ __sanitizer_ether_addr *addr) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, ether_aton_r, buf, addr);
+ if (buf) COMMON_INTERCEPTOR_READ_RANGE(ctx, buf, REAL(strlen)(buf) + 1);
+ __sanitizer_ether_addr *res = REAL(ether_aton_r)(buf, addr);
+ if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, sizeof(*res));
+ return res;
+}
+#define INIT_ETHER_R \
+ COMMON_INTERCEPT_FUNCTION(ether_ntoa_r); \
+ COMMON_INTERCEPT_FUNCTION(ether_aton_r);
+#else
+#define INIT_ETHER_R
+#endif
+
+#if SANITIZER_INTERCEPT_SHMCTL
+INTERCEPTOR(int, shmctl, int shmid, int cmd, void *buf) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, shmctl, shmid, cmd, buf);
+ int res = REAL(shmctl)(shmid, cmd, buf);
+ if (res >= 0) {
+ unsigned sz = 0;
+ if (cmd == shmctl_ipc_stat || cmd == shmctl_shm_stat)
+ sz = sizeof(__sanitizer_shmid_ds);
+ else if (cmd == shmctl_ipc_info)
+ sz = struct_shminfo_sz;
+ else if (cmd == shmctl_shm_info)
+ sz = struct_shm_info_sz;
+ if (sz) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, sz);
+ }
+ return res;
+}
+#define INIT_SHMCTL COMMON_INTERCEPT_FUNCTION(shmctl);
+#else
+#define INIT_SHMCTL
+#endif
+
+#if SANITIZER_INTERCEPT_RANDOM_R
+INTERCEPTOR(int, random_r, void *buf, u32 *result) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, random_r, buf, result);
+ int res = REAL(random_r)(buf, result);
+ if (!res && result)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
+ return res;
+}
+#define INIT_RANDOM_R COMMON_INTERCEPT_FUNCTION(random_r);
+#else
+#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; \
+ }
+#endif
+
+#if SANITIZER_INTERCEPT_PTHREAD_ATTR_GET
+INTERCEPTOR_PTHREAD_ATTR_GET(detachstate, sizeof(int))
+INTERCEPTOR_PTHREAD_ATTR_GET(guardsize, sizeof(SIZE_T))
+INTERCEPTOR_PTHREAD_ATTR_GET(schedparam, struct_sched_param_sz)
+INTERCEPTOR_PTHREAD_ATTR_GET(schedpolicy, sizeof(int))
+INTERCEPTOR_PTHREAD_ATTR_GET(scope, sizeof(int))
+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);
+ int res = REAL(pthread_attr_getstack)(attr, addr, size);
+ if (!res) {
+ if (addr) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, sizeof(*addr));
+ if (size) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, size, sizeof(*size));
+ }
+ return res;
+}
+
+#define INIT_PTHREAD_ATTR_GET \
+ COMMON_INTERCEPT_FUNCTION(pthread_attr_getdetachstate); \
+ COMMON_INTERCEPT_FUNCTION(pthread_attr_getguardsize); \
+ COMMON_INTERCEPT_FUNCTION(pthread_attr_getschedparam); \
+ COMMON_INTERCEPT_FUNCTION(pthread_attr_getschedpolicy); \
+ COMMON_INTERCEPT_FUNCTION(pthread_attr_getscope); \
+ COMMON_INTERCEPT_FUNCTION(pthread_attr_getstacksize); \
+ COMMON_INTERCEPT_FUNCTION(pthread_attr_getstack);
+#else
+#define INIT_PTHREAD_ATTR_GET
+#endif
+
+#if SANITIZER_INTERCEPT_PTHREAD_ATTR_GETINHERITSCHED
+INTERCEPTOR_PTHREAD_ATTR_GET(inheritsched, sizeof(int))
+
+#define INIT_PTHREAD_ATTR_GETINHERITSCHED \
+ COMMON_INTERCEPT_FUNCTION(pthread_attr_getinheritsched);
+#else
+#define INIT_PTHREAD_ATTR_GETINHERITSCHED
+#endif
+
+#if SANITIZER_INTERCEPT_PTHREAD_ATTR_GETAFFINITY_NP
+INTERCEPTOR(int, pthread_attr_getaffinity_np, void *attr, SIZE_T cpusetsize,
+ void *cpuset) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, pthread_attr_getaffinity_np, attr, cpusetsize,
+ cpuset);
+ int res = REAL(pthread_attr_getaffinity_np)(attr, cpusetsize, cpuset);
+ if (!res && cpusetsize && cpuset)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cpuset, cpusetsize);
+ return res;
+}
+
+#define INIT_PTHREAD_ATTR_GETAFFINITY_NP \
+ COMMON_INTERCEPT_FUNCTION(pthread_attr_getaffinity_np);
+#else
+#define INIT_PTHREAD_ATTR_GETAFFINITY_NP
+#endif
+
+#if SANITIZER_INTERCEPT_TMPNAM
+INTERCEPTOR(char *, tmpnam, char *s) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, tmpnam, s);
+ char *res = REAL(tmpnam)(s);
+ if (res) {
+ if (s)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, s, REAL(strlen)(s) + 1);
+ else
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(ctx, res, REAL(strlen)(res) + 1);
+ }
+ return res;
+}
+#define INIT_TMPNAM COMMON_INTERCEPT_FUNCTION(tmpnam);
+#else
+#define INIT_TMPNAM
+#endif
+
+#if SANITIZER_INTERCEPT_TMPNAM_R
+INTERCEPTOR(char *, tmpnam_r, char *s) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, tmpnam_r, s);
+ char *res = REAL(tmpnam_r)(s);
+ if (res && s) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, s, REAL(strlen)(s) + 1);
+ return res;
+}
+#define INIT_TMPNAM_R COMMON_INTERCEPT_FUNCTION(tmpnam_r);
+#else
+#define INIT_TMPNAM_R
+#endif
+
+#if SANITIZER_INTERCEPT_TEMPNAM
+INTERCEPTOR(char *, tempnam, char *dir, char *pfx) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, tempnam, dir, 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);
+ return res;
+}
+#define INIT_TEMPNAM COMMON_INTERCEPT_FUNCTION(tempnam);
+#else
+#define INIT_TEMPNAM
+#endif
+
+#if SANITIZER_INTERCEPT_PTHREAD_SETNAME_NP
+INTERCEPTOR(int, pthread_setname_np, uptr thread, const char *name) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, pthread_setname_np, thread, name);
+ COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name);
+ return REAL(pthread_setname_np)(thread, name);
+}
+#define INIT_PTHREAD_SETNAME_NP COMMON_INTERCEPT_FUNCTION(pthread_setname_np);
+#else
+#define INIT_PTHREAD_SETNAME_NP
+#endif
+
+#if SANITIZER_INTERCEPT_SINCOS
+INTERCEPTOR(void, sincos, double x, double *sin, double *cos) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, sincos, x, sin, cos);
+ 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));
+}
+INTERCEPTOR(void, sincosf, float x, float *sin, float *cos) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, sincosf, x, sin, cos);
+ 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));
+}
+INTERCEPTOR(void, sincosl, long double x, long double *sin, long double *cos) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, sincosl, x, sin, cos);
+ 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));
+}
+#define INIT_SINCOS \
+ COMMON_INTERCEPT_FUNCTION(sincos); \
+ COMMON_INTERCEPT_FUNCTION(sincosf); \
+ COMMON_INTERCEPT_FUNCTION(sincosl);
+#else
+#define INIT_SINCOS
+#endif
+
+#if SANITIZER_INTERCEPT_REMQUO
+INTERCEPTOR(double, remquo, double x, double y, int *quo) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, remquo, x, y, quo);
+ double res = REAL(remquo)(x, y, quo);
+ if (quo) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, quo, sizeof(*quo));
+ return res;
+}
+INTERCEPTOR(float, remquof, float x, float y, int *quo) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, remquof, x, y, quo);
+ float res = REAL(remquof)(x, y, quo);
+ if (quo) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, quo, sizeof(*quo));
+ return res;
+}
+INTERCEPTOR(long double, remquol, long double x, long double y, int *quo) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, remquol, x, y, quo);
+ long double res = REAL(remquol)(x, y, quo);
+ if (quo) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, quo, sizeof(*quo));
+ return res;
+}
+#define INIT_REMQUO \
+ COMMON_INTERCEPT_FUNCTION(remquo); \
+ COMMON_INTERCEPT_FUNCTION(remquof); \
+ COMMON_INTERCEPT_FUNCTION(remquol);
+#else
+#define INIT_REMQUO
+#endif
+
+#if SANITIZER_INTERCEPT_LGAMMA
+extern int signgam;
+INTERCEPTOR(double, lgamma, double x) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, lgamma, x);
+ double res = REAL(lgamma)(x);
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, &signgam, sizeof(signgam));
+ return res;
+}
+INTERCEPTOR(float, lgammaf, float x) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, lgammaf, x);
+ float res = REAL(lgammaf)(x);
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, &signgam, sizeof(signgam));
+ return res;
+}
+INTERCEPTOR(long double, lgammal, long double x) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, lgammal, x);
+ long double res = REAL(lgammal)(x);
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, &signgam, sizeof(signgam));
+ return res;
+}
+#define INIT_LGAMMA \
+ COMMON_INTERCEPT_FUNCTION(lgamma); \
+ COMMON_INTERCEPT_FUNCTION(lgammaf); \
+ COMMON_INTERCEPT_FUNCTION(lgammal);
+#else
+#define INIT_LGAMMA
+#endif
+
+#if SANITIZER_INTERCEPT_LGAMMA_R
+INTERCEPTOR(double, lgamma_r, double x, int *signp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, lgamma_r, x, signp);
+ double res = REAL(lgamma_r)(x, signp);
+ if (signp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, signp, sizeof(*signp));
+ return res;
+}
+INTERCEPTOR(float, lgammaf_r, float x, int *signp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, lgammaf_r, x, signp);
+ float res = REAL(lgammaf_r)(x, signp);
+ if (signp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, signp, sizeof(*signp));
+ return res;
+}
+INTERCEPTOR(long double, lgammal_r, long double x, int *signp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, lgammal_r, x, signp);
+ 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);
+#else
+#define INIT_LGAMMA_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);
+ int res = REAL(drand48_r)(buffer, result);
+ if (result) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
+ return res;
+}
+INTERCEPTOR(int, lrand48_r, void *buffer, long *result) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, lrand48_r, buffer, result);
+ int res = REAL(lrand48_r)(buffer, result);
+ if (result) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
+ return res;
+}
+#define INIT_DRAND48_R \
+ COMMON_INTERCEPT_FUNCTION(drand48_r); \
+ COMMON_INTERCEPT_FUNCTION(lrand48_r);
+#else
+#define INIT_DRAND48_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);
+ SSIZE_T res = REAL(getline)(lineptr, n, stream);
+ if (res > 0) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, lineptr, sizeof(*lineptr));
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, n, sizeof(*n));
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *lineptr, res + 1);
+ }
+ return res;
+}
+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);
+ if (res > 0) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, lineptr, sizeof(*lineptr));
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, n, sizeof(*n));
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *lineptr, res + 1);
+ }
+ return res;
+}
+#define INIT_GETLINE \
+ COMMON_INTERCEPT_FUNCTION(getline); \
+ 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_PRCTL; \
+ 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; \
@@ -985,7 +2857,79 @@ INTERCEPTOR(int, getsockopt, int sockfd, int level, int optname, void *optval,
INIT_INET; \
INIT_PTHREAD_GETSCHEDPARAM; \
INIT_GETADDRINFO; \
+ INIT_GETNAMEINFO; \
INIT_GETSOCKNAME; \
INIT_GETHOSTBYNAME; \
INIT_GETHOSTBYNAME_R; \
- INIT_GETSOCKOPT;
+ 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; \
+/**/
diff --git a/lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc b/lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc
new file mode 100755
index 000000000000..4b90f8ca8a36
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc
@@ -0,0 +1,568 @@
+//===-- sanitizer_common_interceptors_ioctl.inc -----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Ioctl handling in common sanitizer interceptors.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_flags.h"
+
+struct ioctl_desc {
+ unsigned req;
+ // FIXME: support read+write arguments. Those are currently marked as WRITE.
+ enum {
+ NONE,
+ READ,
+ WRITE,
+ CUSTOM
+ } type : 2;
+ unsigned size : 30;
+ const char* name;
+};
+
+const unsigned ioctl_table_max = 500;
+static ioctl_desc ioctl_table[ioctl_table_max];
+static unsigned ioctl_table_size = 0;
+
+// This can not be declared as a global, because references to struct_*_sz
+// require a global initializer. And this table must be available before global
+// initializers are run.
+static void ioctl_table_fill() {
+#define _(rq, tp, sz) \
+ if (IOCTL_##rq != IOCTL_NOT_PRESENT) { \
+ CHECK(ioctl_table_size < ioctl_table_max); \
+ ioctl_table[ioctl_table_size].req = IOCTL_##rq; \
+ ioctl_table[ioctl_table_size].type = ioctl_desc::tp; \
+ ioctl_table[ioctl_table_size].size = sz; \
+ ioctl_table[ioctl_table_size].name = #rq; \
+ ++ioctl_table_size; \
+ }
+
+ _(FIOASYNC, READ, sizeof(int));
+ _(FIOCLEX, NONE, 0);
+ _(FIOGETOWN, WRITE, sizeof(int));
+ _(FIONBIO, READ, sizeof(int));
+ _(FIONCLEX, NONE, 0);
+ _(FIOSETOWN, READ, sizeof(int));
+ _(SIOCADDMULTI, READ, struct_ifreq_sz);
+ _(SIOCATMARK, WRITE, sizeof(int));
+ _(SIOCDELMULTI, READ, struct_ifreq_sz);
+ _(SIOCGIFADDR, WRITE, struct_ifreq_sz);
+ _(SIOCGIFBRDADDR, WRITE, struct_ifreq_sz);
+ _(SIOCGIFCONF, CUSTOM, 0);
+ _(SIOCGIFDSTADDR, WRITE, struct_ifreq_sz);
+ _(SIOCGIFFLAGS, WRITE, struct_ifreq_sz);
+ _(SIOCGIFMETRIC, WRITE, struct_ifreq_sz);
+ _(SIOCGIFMTU, WRITE, struct_ifreq_sz);
+ _(SIOCGIFNETMASK, WRITE, struct_ifreq_sz);
+ _(SIOCGPGRP, WRITE, sizeof(int));
+ _(SIOCSIFADDR, READ, struct_ifreq_sz);
+ _(SIOCSIFBRDADDR, READ, struct_ifreq_sz);
+ _(SIOCSIFDSTADDR, READ, struct_ifreq_sz);
+ _(SIOCSIFFLAGS, READ, struct_ifreq_sz);
+ _(SIOCSIFMETRIC, READ, struct_ifreq_sz);
+ _(SIOCSIFMTU, READ, struct_ifreq_sz);
+ _(SIOCSIFNETMASK, READ, struct_ifreq_sz);
+ _(SIOCSPGRP, READ, sizeof(int));
+ _(TIOCCONS, NONE, 0);
+ _(TIOCEXCL, NONE, 0);
+ _(TIOCGETD, WRITE, sizeof(int));
+ _(TIOCGPGRP, WRITE, pid_t_sz);
+ _(TIOCGWINSZ, WRITE, struct_winsize_sz);
+ _(TIOCMBIC, READ, sizeof(int));
+ _(TIOCMBIS, READ, sizeof(int));
+ _(TIOCMGET, WRITE, sizeof(int));
+ _(TIOCMSET, READ, sizeof(int));
+ _(TIOCNOTTY, NONE, 0);
+ _(TIOCNXCL, NONE, 0);
+ _(TIOCOUTQ, WRITE, sizeof(int));
+ _(TIOCPKT, READ, sizeof(int));
+ _(TIOCSCTTY, NONE, 0);
+ _(TIOCSETD, READ, sizeof(int));
+ _(TIOCSPGRP, READ, pid_t_sz);
+ _(TIOCSTI, READ, sizeof(char));
+ _(TIOCSWINSZ, READ, struct_winsize_sz);
+
+#if (SANITIZER_LINUX && !SANITIZER_ANDROID)
+ _(SIOCGETSGCNT, WRITE, struct_sioc_sg_req_sz);
+ _(SIOCGETVIFCNT, WRITE, struct_sioc_vif_req_sz);
+#endif
+
+#if SANITIZER_LINUX
+ // Conflicting request ids.
+ // _(CDROMAUDIOBUFSIZ, NONE, 0);
+ // _(SNDCTL_TMR_CONTINUE, NONE, 0);
+ // _(SNDCTL_TMR_START, NONE, 0);
+ // _(SNDCTL_TMR_STOP, NONE, 0);
+ // _(SOUND_MIXER_READ_LOUD, WRITE, sizeof(int)); // same as ...READ_ENHANCE
+ // _(SOUND_MIXER_READ_MUTE, WRITE, sizeof(int)); // same as ...READ_ENHANCE
+ // _(SOUND_MIXER_WRITE_LOUD, WRITE, sizeof(int)); // same as ...WRITE_ENHANCE
+ // _(SOUND_MIXER_WRITE_MUTE, WRITE, sizeof(int)); // same as ...WRITE_ENHANCE
+ _(BLKFLSBUF, NONE, 0);
+ _(BLKGETSIZE, WRITE, sizeof(uptr));
+ _(BLKRAGET, WRITE, sizeof(int));
+ _(BLKRASET, NONE, 0);
+ _(BLKROGET, WRITE, sizeof(int));
+ _(BLKROSET, READ, sizeof(int));
+ _(BLKRRPART, NONE, 0);
+ _(CDROMEJECT, NONE, 0);
+ _(CDROMEJECT_SW, NONE, 0);
+ _(CDROMMULTISESSION, WRITE, struct_cdrom_multisession_sz);
+ _(CDROMPAUSE, NONE, 0);
+ _(CDROMPLAYMSF, READ, struct_cdrom_msf_sz);
+ _(CDROMPLAYTRKIND, READ, struct_cdrom_ti_sz);
+ _(CDROMREADAUDIO, READ, struct_cdrom_read_audio_sz);
+ _(CDROMREADCOOKED, READ, struct_cdrom_msf_sz);
+ _(CDROMREADMODE1, READ, struct_cdrom_msf_sz);
+ _(CDROMREADMODE2, READ, struct_cdrom_msf_sz);
+ _(CDROMREADRAW, READ, struct_cdrom_msf_sz);
+ _(CDROMREADTOCENTRY, WRITE, struct_cdrom_tocentry_sz);
+ _(CDROMREADTOCHDR, WRITE, struct_cdrom_tochdr_sz);
+ _(CDROMRESET, NONE, 0);
+ _(CDROMRESUME, NONE, 0);
+ _(CDROMSEEK, READ, struct_cdrom_msf_sz);
+ _(CDROMSTART, NONE, 0);
+ _(CDROMSTOP, NONE, 0);
+ _(CDROMSUBCHNL, WRITE, struct_cdrom_subchnl_sz);
+ _(CDROMVOLCTRL, READ, struct_cdrom_volctrl_sz);
+ _(CDROMVOLREAD, WRITE, struct_cdrom_volctrl_sz);
+ _(CDROM_GET_UPC, WRITE, 8);
+ _(EVIOCGABS, WRITE, struct_input_absinfo_sz); // fixup
+ _(EVIOCGBIT, WRITE, struct_input_id_sz); // fixup
+ _(EVIOCGEFFECTS, WRITE, sizeof(int));
+ _(EVIOCGID, WRITE, struct_input_id_sz);
+ _(EVIOCGKEY, WRITE, 0);
+ _(EVIOCGKEYCODE, WRITE, sizeof(int) * 2);
+ _(EVIOCGLED, WRITE, 0);
+ _(EVIOCGNAME, WRITE, 0);
+ _(EVIOCGPHYS, WRITE, 0);
+ _(EVIOCGRAB, READ, sizeof(int));
+ _(EVIOCGREP, WRITE, sizeof(int) * 2);
+ _(EVIOCGSND, WRITE, 0);
+ _(EVIOCGSW, WRITE, 0);
+ _(EVIOCGUNIQ, WRITE, 0);
+ _(EVIOCGVERSION, WRITE, sizeof(int));
+ _(EVIOCRMFF, READ, sizeof(int));
+ _(EVIOCSABS, READ, struct_input_absinfo_sz); // fixup
+ _(EVIOCSFF, READ, struct_ff_effect_sz);
+ _(EVIOCSKEYCODE, READ, sizeof(int) * 2);
+ _(EVIOCSREP, READ, sizeof(int) * 2);
+ _(FDCLRPRM, NONE, 0);
+ _(FDDEFPRM, READ, struct_floppy_struct_sz);
+ _(FDFLUSH, NONE, 0);
+ _(FDFMTBEG, NONE, 0);
+ _(FDFMTEND, NONE, 0);
+ _(FDFMTTRK, READ, struct_format_descr_sz);
+ _(FDGETDRVPRM, WRITE, struct_floppy_drive_params_sz);
+ _(FDGETDRVSTAT, WRITE, struct_floppy_drive_struct_sz);
+ _(FDGETDRVTYP, WRITE, 16);
+ _(FDGETFDCSTAT, WRITE, struct_floppy_fdc_state_sz);
+ _(FDGETMAXERRS, WRITE, struct_floppy_max_errors_sz);
+ _(FDGETPRM, WRITE, struct_floppy_struct_sz);
+ _(FDMSGOFF, NONE, 0);
+ _(FDMSGON, NONE, 0);
+ _(FDPOLLDRVSTAT, WRITE, struct_floppy_drive_struct_sz);
+ _(FDRAWCMD, WRITE, struct_floppy_raw_cmd_sz);
+ _(FDRESET, NONE, 0);
+ _(FDSETDRVPRM, READ, struct_floppy_drive_params_sz);
+ _(FDSETEMSGTRESH, NONE, 0);
+ _(FDSETMAXERRS, READ, struct_floppy_max_errors_sz);
+ _(FDSETPRM, READ, struct_floppy_struct_sz);
+ _(FDTWADDLE, NONE, 0);
+ _(FDWERRORCLR, NONE, 0);
+ _(FDWERRORGET, WRITE, struct_floppy_write_errors_sz);
+ _(HDIO_DRIVE_CMD, WRITE, sizeof(int));
+ _(HDIO_GETGEO, WRITE, struct_hd_geometry_sz);
+ _(HDIO_GET_32BIT, WRITE, sizeof(int));
+ _(HDIO_GET_DMA, WRITE, sizeof(int));
+ _(HDIO_GET_IDENTITY, WRITE, struct_hd_driveid_sz);
+ _(HDIO_GET_KEEPSETTINGS, WRITE, sizeof(int));
+ _(HDIO_GET_MULTCOUNT, WRITE, sizeof(int));
+ _(HDIO_GET_NOWERR, WRITE, sizeof(int));
+ _(HDIO_GET_UNMASKINTR, WRITE, sizeof(int));
+ _(HDIO_SET_32BIT, NONE, 0);
+ _(HDIO_SET_DMA, NONE, 0);
+ _(HDIO_SET_KEEPSETTINGS, NONE, 0);
+ _(HDIO_SET_MULTCOUNT, NONE, 0);
+ _(HDIO_SET_NOWERR, NONE, 0);
+ _(HDIO_SET_UNMASKINTR, NONE, 0);
+ _(MTIOCGET, WRITE, struct_mtget_sz);
+ _(MTIOCPOS, WRITE, struct_mtpos_sz);
+ _(MTIOCTOP, READ, struct_mtop_sz);
+ _(PPPIOCGASYNCMAP, WRITE, sizeof(int));
+ _(PPPIOCGDEBUG, WRITE, sizeof(int));
+ _(PPPIOCGFLAGS, WRITE, sizeof(int));
+ _(PPPIOCGUNIT, WRITE, sizeof(int));
+ _(PPPIOCGXASYNCMAP, WRITE, sizeof(int) * 8);
+ _(PPPIOCSASYNCMAP, READ, sizeof(int));
+ _(PPPIOCSDEBUG, READ, sizeof(int));
+ _(PPPIOCSFLAGS, READ, sizeof(int));
+ _(PPPIOCSMAXCID, READ, sizeof(int));
+ _(PPPIOCSMRU, READ, sizeof(int));
+ _(PPPIOCSXASYNCMAP, READ, sizeof(int) * 8);
+ _(SIOCADDRT, READ, struct_rtentry_sz);
+ _(SIOCDARP, READ, struct_arpreq_sz);
+ _(SIOCDELRT, READ, struct_rtentry_sz);
+ _(SIOCDRARP, READ, struct_arpreq_sz);
+ _(SIOCGARP, WRITE, struct_arpreq_sz);
+ _(SIOCGIFENCAP, WRITE, sizeof(int));
+ _(SIOCGIFHWADDR, WRITE, struct_ifreq_sz);
+ _(SIOCGIFMAP, WRITE, struct_ifreq_sz);
+ _(SIOCGIFMEM, WRITE, struct_ifreq_sz);
+ _(SIOCGIFNAME, NONE, 0);
+ _(SIOCGIFSLAVE, NONE, 0);
+ _(SIOCGRARP, WRITE, struct_arpreq_sz);
+ _(SIOCGSTAMP, WRITE, timeval_sz);
+ _(SIOCSARP, READ, struct_arpreq_sz);
+ _(SIOCSIFENCAP, READ, sizeof(int));
+ _(SIOCSIFHWADDR, READ, struct_ifreq_sz);
+ _(SIOCSIFLINK, NONE, 0);
+ _(SIOCSIFMAP, READ, struct_ifreq_sz);
+ _(SIOCSIFMEM, READ, struct_ifreq_sz);
+ _(SIOCSIFSLAVE, NONE, 0);
+ _(SIOCSRARP, READ, struct_arpreq_sz);
+ _(SNDCTL_COPR_HALT, WRITE, struct_copr_debug_buf_sz);
+ _(SNDCTL_COPR_LOAD, READ, struct_copr_buffer_sz);
+ _(SNDCTL_COPR_RCODE, WRITE, struct_copr_debug_buf_sz);
+ _(SNDCTL_COPR_RCVMSG, WRITE, struct_copr_msg_sz);
+ _(SNDCTL_COPR_RDATA, WRITE, struct_copr_debug_buf_sz);
+ _(SNDCTL_COPR_RESET, NONE, 0);
+ _(SNDCTL_COPR_RUN, WRITE, struct_copr_debug_buf_sz);
+ _(SNDCTL_COPR_SENDMSG, READ, struct_copr_msg_sz);
+ _(SNDCTL_COPR_WCODE, READ, struct_copr_debug_buf_sz);
+ _(SNDCTL_COPR_WDATA, READ, struct_copr_debug_buf_sz);
+ _(SNDCTL_DSP_GETBLKSIZE, WRITE, sizeof(int));
+ _(SNDCTL_DSP_GETFMTS, WRITE, sizeof(int));
+ _(SNDCTL_DSP_NONBLOCK, NONE, 0);
+ _(SNDCTL_DSP_POST, NONE, 0);
+ _(SNDCTL_DSP_RESET, NONE, 0);
+ _(SNDCTL_DSP_SETFMT, WRITE, sizeof(int));
+ _(SNDCTL_DSP_SETFRAGMENT, WRITE, sizeof(int));
+ _(SNDCTL_DSP_SPEED, WRITE, sizeof(int));
+ _(SNDCTL_DSP_STEREO, WRITE, sizeof(int));
+ _(SNDCTL_DSP_SUBDIVIDE, WRITE, sizeof(int));
+ _(SNDCTL_DSP_SYNC, NONE, 0);
+ _(SNDCTL_FM_4OP_ENABLE, READ, sizeof(int));
+ _(SNDCTL_FM_LOAD_INSTR, READ, struct_sbi_instrument_sz);
+ _(SNDCTL_MIDI_INFO, WRITE, struct_midi_info_sz);
+ _(SNDCTL_MIDI_PRETIME, WRITE, sizeof(int));
+ _(SNDCTL_SEQ_CTRLRATE, WRITE, sizeof(int));
+ _(SNDCTL_SEQ_GETINCOUNT, WRITE, sizeof(int));
+ _(SNDCTL_SEQ_GETOUTCOUNT, WRITE, sizeof(int));
+ _(SNDCTL_SEQ_NRMIDIS, WRITE, sizeof(int));
+ _(SNDCTL_SEQ_NRSYNTHS, WRITE, sizeof(int));
+ _(SNDCTL_SEQ_OUTOFBAND, READ, struct_seq_event_rec_sz);
+ _(SNDCTL_SEQ_PANIC, NONE, 0);
+ _(SNDCTL_SEQ_PERCMODE, NONE, 0);
+ _(SNDCTL_SEQ_RESET, NONE, 0);
+ _(SNDCTL_SEQ_RESETSAMPLES, READ, sizeof(int));
+ _(SNDCTL_SEQ_SYNC, NONE, 0);
+ _(SNDCTL_SEQ_TESTMIDI, READ, sizeof(int));
+ _(SNDCTL_SEQ_THRESHOLD, READ, sizeof(int));
+ _(SNDCTL_SYNTH_INFO, WRITE, struct_synth_info_sz);
+ _(SNDCTL_SYNTH_MEMAVL, WRITE, sizeof(int));
+ _(SNDCTL_TMR_METRONOME, READ, sizeof(int));
+ _(SNDCTL_TMR_SELECT, WRITE, sizeof(int));
+ _(SNDCTL_TMR_SOURCE, WRITE, sizeof(int));
+ _(SNDCTL_TMR_TEMPO, WRITE, sizeof(int));
+ _(SNDCTL_TMR_TIMEBASE, WRITE, sizeof(int));
+ _(SOUND_MIXER_READ_ALTPCM, WRITE, sizeof(int));
+ _(SOUND_MIXER_READ_BASS, WRITE, sizeof(int));
+ _(SOUND_MIXER_READ_CAPS, WRITE, sizeof(int));
+ _(SOUND_MIXER_READ_CD, WRITE, sizeof(int));
+ _(SOUND_MIXER_READ_DEVMASK, WRITE, sizeof(int));
+ _(SOUND_MIXER_READ_ENHANCE, WRITE, sizeof(int));
+ _(SOUND_MIXER_READ_IGAIN, WRITE, sizeof(int));
+ _(SOUND_MIXER_READ_IMIX, WRITE, sizeof(int));
+ _(SOUND_MIXER_READ_LINE, WRITE, sizeof(int));
+ _(SOUND_MIXER_READ_LINE1, WRITE, sizeof(int));
+ _(SOUND_MIXER_READ_LINE2, WRITE, sizeof(int));
+ _(SOUND_MIXER_READ_LINE3, WRITE, sizeof(int));
+ _(SOUND_MIXER_READ_MIC, WRITE, sizeof(int));
+ _(SOUND_MIXER_READ_OGAIN, WRITE, sizeof(int));
+ _(SOUND_MIXER_READ_PCM, WRITE, sizeof(int));
+ _(SOUND_MIXER_READ_RECLEV, WRITE, sizeof(int));
+ _(SOUND_MIXER_READ_RECMASK, WRITE, sizeof(int));
+ _(SOUND_MIXER_READ_RECSRC, WRITE, sizeof(int));
+ _(SOUND_MIXER_READ_SPEAKER, WRITE, sizeof(int));
+ _(SOUND_MIXER_READ_STEREODEVS, WRITE, sizeof(int));
+ _(SOUND_MIXER_READ_SYNTH, WRITE, sizeof(int));
+ _(SOUND_MIXER_READ_TREBLE, WRITE, sizeof(int));
+ _(SOUND_MIXER_READ_VOLUME, WRITE, sizeof(int));
+ _(SOUND_MIXER_WRITE_ALTPCM, WRITE, sizeof(int));
+ _(SOUND_MIXER_WRITE_BASS, WRITE, sizeof(int));
+ _(SOUND_MIXER_WRITE_CD, WRITE, sizeof(int));
+ _(SOUND_MIXER_WRITE_ENHANCE, WRITE, sizeof(int));
+ _(SOUND_MIXER_WRITE_IGAIN, WRITE, sizeof(int));
+ _(SOUND_MIXER_WRITE_IMIX, WRITE, sizeof(int));
+ _(SOUND_MIXER_WRITE_LINE, WRITE, sizeof(int));
+ _(SOUND_MIXER_WRITE_LINE1, WRITE, sizeof(int));
+ _(SOUND_MIXER_WRITE_LINE2, WRITE, sizeof(int));
+ _(SOUND_MIXER_WRITE_LINE3, WRITE, sizeof(int));
+ _(SOUND_MIXER_WRITE_MIC, WRITE, sizeof(int));
+ _(SOUND_MIXER_WRITE_OGAIN, WRITE, sizeof(int));
+ _(SOUND_MIXER_WRITE_PCM, WRITE, sizeof(int));
+ _(SOUND_MIXER_WRITE_RECLEV, WRITE, sizeof(int));
+ _(SOUND_MIXER_WRITE_RECSRC, WRITE, sizeof(int));
+ _(SOUND_MIXER_WRITE_SPEAKER, WRITE, sizeof(int));
+ _(SOUND_MIXER_WRITE_SYNTH, WRITE, sizeof(int));
+ _(SOUND_MIXER_WRITE_TREBLE, WRITE, sizeof(int));
+ _(SOUND_MIXER_WRITE_VOLUME, WRITE, sizeof(int));
+ _(SOUND_PCM_READ_BITS, WRITE, sizeof(int));
+ _(SOUND_PCM_READ_CHANNELS, WRITE, sizeof(int));
+ _(SOUND_PCM_READ_FILTER, WRITE, sizeof(int));
+ _(SOUND_PCM_READ_RATE, WRITE, sizeof(int));
+ _(SOUND_PCM_WRITE_CHANNELS, WRITE, sizeof(int));
+ _(SOUND_PCM_WRITE_FILTER, WRITE, sizeof(int));
+ _(TCFLSH, NONE, 0);
+ _(TCGETA, WRITE, struct_termio_sz);
+ _(TCGETS, WRITE, struct_termios_sz);
+ _(TCSBRK, NONE, 0);
+ _(TCSBRKP, NONE, 0);
+ _(TCSETA, READ, struct_termio_sz);
+ _(TCSETAF, READ, struct_termio_sz);
+ _(TCSETAW, READ, struct_termio_sz);
+ _(TCSETS, READ, struct_termios_sz);
+ _(TCSETSF, READ, struct_termios_sz);
+ _(TCSETSW, READ, struct_termios_sz);
+ _(TCXONC, NONE, 0);
+ _(TIOCGLCKTRMIOS, WRITE, struct_termios_sz);
+ _(TIOCGSOFTCAR, WRITE, sizeof(int));
+ _(TIOCINQ, WRITE, sizeof(int));
+ _(TIOCLINUX, READ, sizeof(char));
+ _(TIOCSERCONFIG, NONE, 0);
+ _(TIOCSERGETLSR, WRITE, sizeof(int));
+ _(TIOCSERGWILD, WRITE, sizeof(int));
+ _(TIOCSERSWILD, READ, sizeof(int));
+ _(TIOCSLCKTRMIOS, READ, struct_termios_sz);
+ _(TIOCSSOFTCAR, READ, sizeof(int));
+ _(VT_ACTIVATE, NONE, 0);
+ _(VT_DISALLOCATE, NONE, 0);
+ _(VT_GETMODE, WRITE, struct_vt_mode_sz);
+ _(VT_GETSTATE, WRITE, struct_vt_stat_sz);
+ _(VT_OPENQRY, WRITE, sizeof(int));
+ _(VT_RELDISP, NONE, 0);
+ _(VT_RESIZE, READ, struct_vt_sizes_sz);
+ _(VT_RESIZEX, READ, struct_vt_consize_sz);
+ _(VT_SENDSIG, NONE, 0);
+ _(VT_SETMODE, READ, struct_vt_mode_sz);
+ _(VT_WAITACTIVE, NONE, 0);
+#endif
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+ // _(SIOCDEVPLIP, WRITE, struct_ifreq_sz); // the same as EQL_ENSLAVE
+ _(CYGETDEFTHRESH, WRITE, sizeof(int));
+ _(CYGETDEFTIMEOUT, WRITE, sizeof(int));
+ _(CYGETMON, WRITE, struct_cyclades_monitor_sz);
+ _(CYGETTHRESH, WRITE, sizeof(int));
+ _(CYGETTIMEOUT, WRITE, sizeof(int));
+ _(CYSETDEFTHRESH, NONE, 0);
+ _(CYSETDEFTIMEOUT, NONE, 0);
+ _(CYSETTHRESH, NONE, 0);
+ _(CYSETTIMEOUT, NONE, 0);
+ _(EQL_EMANCIPATE, WRITE, struct_ifreq_sz);
+ _(EQL_ENSLAVE, WRITE, struct_ifreq_sz);
+ _(EQL_GETMASTRCFG, WRITE, struct_ifreq_sz);
+ _(EQL_GETSLAVECFG, WRITE, struct_ifreq_sz);
+ _(EQL_SETMASTRCFG, WRITE, struct_ifreq_sz);
+ _(EQL_SETSLAVECFG, WRITE, struct_ifreq_sz);
+ _(EVIOCGKEYCODE_V2, WRITE, struct_input_keymap_entry_sz);
+ _(EVIOCGPROP, WRITE, 0);
+ _(EVIOCSKEYCODE_V2, READ, struct_input_keymap_entry_sz);
+ _(FS_IOC_GETFLAGS, WRITE, sizeof(int));
+ _(FS_IOC_GETVERSION, WRITE, sizeof(int));
+ _(FS_IOC_SETFLAGS, READ, sizeof(int));
+ _(FS_IOC_SETVERSION, READ, sizeof(int));
+ _(GIO_CMAP, WRITE, 48);
+ _(GIO_FONT, WRITE, 8192);
+ _(GIO_SCRNMAP, WRITE, e_tabsz);
+ _(GIO_UNIMAP, WRITE, struct_unimapdesc_sz);
+ _(GIO_UNISCRNMAP, WRITE, sizeof(short) * e_tabsz);
+ _(KDADDIO, NONE, 0);
+ _(KDDELIO, NONE, 0);
+ _(KDDISABIO, NONE, 0);
+ _(KDENABIO, NONE, 0);
+ _(KDGETKEYCODE, WRITE, struct_kbkeycode_sz);
+ _(KDGETLED, WRITE, 1);
+ _(KDGETMODE, WRITE, sizeof(int));
+ _(KDGKBDIACR, WRITE, struct_kbdiacrs_sz);
+ _(KDGKBENT, WRITE, struct_kbentry_sz);
+ _(KDGKBLED, WRITE, sizeof(int));
+ _(KDGKBMETA, WRITE, sizeof(int));
+ _(KDGKBMODE, WRITE, sizeof(int));
+ _(KDGKBSENT, WRITE, struct_kbsentry_sz);
+ _(KDGKBTYPE, WRITE, 1);
+ _(KDMAPDISP, NONE, 0);
+ _(KDMKTONE, NONE, 0);
+ _(KDSETKEYCODE, READ, struct_kbkeycode_sz);
+ _(KDSETLED, NONE, 0);
+ _(KDSETMODE, NONE, 0);
+ _(KDSIGACCEPT, NONE, 0);
+ _(KDSKBDIACR, READ, struct_kbdiacrs_sz);
+ _(KDSKBENT, READ, struct_kbentry_sz);
+ _(KDSKBLED, NONE, 0);
+ _(KDSKBMETA, NONE, 0);
+ _(KDSKBMODE, NONE, 0);
+ _(KDSKBSENT, READ, struct_kbsentry_sz);
+ _(KDUNMAPDISP, NONE, 0);
+ _(KIOCSOUND, NONE, 0);
+ _(LPABORT, NONE, 0);
+ _(LPABORTOPEN, NONE, 0);
+ _(LPCAREFUL, NONE, 0);
+ _(LPCHAR, NONE, 0);
+ _(LPGETIRQ, WRITE, sizeof(int));
+ _(LPGETSTATUS, WRITE, sizeof(int));
+ _(LPRESET, NONE, 0);
+ _(LPSETIRQ, NONE, 0);
+ _(LPTIME, NONE, 0);
+ _(LPWAIT, NONE, 0);
+ _(MTIOCGETCONFIG, WRITE, struct_mtconfiginfo_sz);
+ _(MTIOCSETCONFIG, READ, struct_mtconfiginfo_sz);
+ _(PIO_CMAP, NONE, 0);
+ _(PIO_FONT, READ, 8192);
+ _(PIO_SCRNMAP, READ, e_tabsz);
+ _(PIO_UNIMAP, READ, struct_unimapdesc_sz);
+ _(PIO_UNIMAPCLR, READ, struct_unimapinit_sz);
+ _(PIO_UNISCRNMAP, READ, sizeof(short) * e_tabsz);
+ _(SCSI_IOCTL_PROBE_HOST, READ, sizeof(int));
+ _(SCSI_IOCTL_TAGGED_DISABLE, NONE, 0);
+ _(SCSI_IOCTL_TAGGED_ENABLE, NONE, 0);
+ _(SNDCTL_DSP_GETISPACE, WRITE, struct_audio_buf_info_sz);
+ _(SNDCTL_DSP_GETOSPACE, WRITE, struct_audio_buf_info_sz);
+ _(TIOCGSERIAL, WRITE, struct_serial_struct_sz);
+ _(TIOCSERGETMULTI, WRITE, struct_serial_multiport_struct_sz);
+ _(TIOCSERSETMULTI, READ, struct_serial_multiport_struct_sz);
+ _(TIOCSSERIAL, READ, struct_serial_struct_sz);
+
+ // The following ioctl requests are shared between AX25, IPX, netrom and
+ // mrouted.
+ // _(SIOCAIPXITFCRT, READ, sizeof(char));
+ // _(SIOCAX25GETUID, READ, struct_sockaddr_ax25_sz);
+ // _(SIOCNRGETPARMS, WRITE, struct_nr_parms_struct_sz);
+ // _(SIOCAIPXPRISLT, READ, sizeof(char));
+ // _(SIOCNRSETPARMS, READ, struct_nr_parms_struct_sz);
+ // _(SIOCAX25ADDUID, READ, struct_sockaddr_ax25_sz);
+ // _(SIOCNRDECOBS, NONE, 0);
+ // _(SIOCAX25DELUID, READ, struct_sockaddr_ax25_sz);
+ // _(SIOCIPXCFGDATA, WRITE, struct_ipx_config_data_sz);
+ // _(SIOCAX25NOUID, READ, sizeof(int));
+ // _(SIOCNRRTCTL, READ, sizeof(int));
+ // _(SIOCAX25DIGCTL, READ, sizeof(int));
+ // _(SIOCAX25GETPARMS, WRITE, struct_ax25_parms_struct_sz);
+ // _(SIOCAX25SETPARMS, READ, struct_ax25_parms_struct_sz);
+#endif
+#undef _
+}
+
+static bool ioctl_initialized = false;
+
+struct ioctl_desc_compare {
+ bool operator()(const ioctl_desc& left, const ioctl_desc& right) const {
+ return left.req < right.req;
+ }
+};
+
+static void ioctl_init() {
+ ioctl_table_fill();
+ InternalSort(&ioctl_table, ioctl_table_size, ioctl_desc_compare());
+
+ bool bad = false;
+ for (unsigned i = 0; i < ioctl_table_size - 1; ++i) {
+ if (ioctl_table[i].req >= ioctl_table[i + 1].req) {
+ Printf("Duplicate or unsorted ioctl request id %x >= %x (%s vs %s)\n",
+ ioctl_table[i].req, ioctl_table[i + 1].req, ioctl_table[i].name,
+ ioctl_table[i + 1].name);
+ bad = true;
+ }
+ }
+
+ if (bad) Die();
+
+ ioctl_initialized = true;
+}
+
+// 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)
+ return IOCTL_EVIOCGBIT;
+ if ((req & ~0x3fU) == IOCTL_EVIOCGABS)
+ return IOCTL_EVIOCGABS;
+ if ((req & ~0x3fU) == IOCTL_EVIOCSABS)
+ return IOCTL_EVIOCSABS;
+#endif
+ return req;
+}
+
+static const ioctl_desc *ioctl_table_lookup(unsigned req) {
+ int left = 0;
+ int right = ioctl_table_size;
+ while (left < right) {
+ int mid = (left + right) / 2;
+ if (ioctl_table[mid].req < req)
+ left = mid + 1;
+ else
+ right = mid;
+ }
+ if (left == right && ioctl_table[left].req == req)
+ return ioctl_table + left;
+ else
+ return 0;
+}
+
+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);
+ // 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))
+ 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) {
+ unsigned size = desc->size ? desc->size : IOC_SIZE(request);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, arg, size);
+ }
+ if (desc->type != ioctl_desc::CUSTOM)
+ return;
+ switch (request) {
+ case 0x00008912: { // SIOCGIFCONF
+ struct __sanitizer_ifconf *ifc = (__sanitizer_ifconf *)arg;
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, &ifc->ifc_len, sizeof(ifc->ifc_len));
+ break;
+ }
+ }
+ return;
+}
+
+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) {
+ // FIXME: add verbose output
+ unsigned size = desc->size ? desc->size : IOC_SIZE(request);
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, arg, size);
+ }
+ if (desc->type != ioctl_desc::CUSTOM)
+ return;
+ switch (request) {
+ case 0x00008912: { // SIOCGIFCONF
+ struct __sanitizer_ifconf *ifc = (__sanitizer_ifconf *)arg;
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ifc->ifc_ifcu.ifcu_req, ifc->ifc_len);
+ break;
+ }
+ }
+ return;
+}
diff --git a/lib/sanitizer_common/sanitizer_common_interceptors_scanf.inc b/lib/sanitizer_common/sanitizer_common_interceptors_scanf.inc
index 8bb5cd818ac2..08752e6a3b88 100644
--- a/lib/sanitizer_common/sanitizer_common_interceptors_scanf.inc
+++ b/lib/sanitizer_common/sanitizer_common_interceptors_scanf.inc
@@ -278,7 +278,7 @@ static void scanf_common(void *ctx, int n_inputs, bool allowGnuMalloc,
CHECK_GT(n_inputs, 0);
const char *p = format;
- while (*p && n_inputs) {
+ while (*p) {
ScanfDirective dir;
p = scanf_parse_next(p, allowGnuMalloc, &dir);
if (!p)
@@ -301,6 +301,8 @@ static void scanf_common(void *ctx, int n_inputs, bool allowGnuMalloc,
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;
}
diff --git a/lib/sanitizer_common/sanitizer_common_libcdep.cc b/lib/sanitizer_common/sanitizer_common_libcdep.cc
index 36f6cf0bc0db..f3430074eb0f 100644
--- a/lib/sanitizer_common/sanitizer_common_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_common_libcdep.cc
@@ -17,7 +17,21 @@ namespace __sanitizer {
bool PrintsToTty() {
MaybeOpenReportFile();
- return internal_isatty(report_fd);
+ return internal_isatty(report_fd) != 0;
}
+bool PrintsToTtyCached() {
+ // FIXME: Add proper Windows support to AnsiColorDecorator and re-enable color
+ // printing on Windows.
+ if (SANITIZER_WINDOWS)
+ return 0;
+
+ static int cached = 0;
+ static bool prints_to_tty;
+ if (!cached) { // Not thread-safe.
+ prints_to_tty = PrintsToTty();
+ cached = 1;
+ }
+ return prints_to_tty;
+}
} // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_common_syscalls.inc b/lib/sanitizer_common/sanitizer_common_syscalls.inc
index da25e6b6ad2c..958f12f84393 100644
--- a/lib/sanitizer_common/sanitizer_common_syscalls.inc
+++ b/lib/sanitizer_common/sanitizer_common_syscalls.inc
@@ -25,18 +25,41 @@
// COMMON_SYSCALL_POST_WRITE_RANGE
// Called in posthook for regions that were written to by the kernel
// and are now initialized.
+// COMMON_SYSCALL_FD_CLOSE(fd)
+// Called before closing file descriptor fd.
+// COMMON_SYSCALL_PRE_FORK()
+// Called before fork syscall.
+// COMMON_SYSCALL_POST_FORK(long res)
+// Called after fork syscall.
//===----------------------------------------------------------------------===//
+#include "sanitizer_platform.h"
+#if SANITIZER_LINUX
+
+#include "sanitizer_libc.h"
+
#define PRE_SYSCALL(name) \
- SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_syscall_pre_##name
+ SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_syscall_pre_impl_##name
#define PRE_READ(p, s) COMMON_SYSCALL_PRE_READ_RANGE(p, s)
#define PRE_WRITE(p, s) COMMON_SYSCALL_PRE_WRITE_RANGE(p, s)
#define POST_SYSCALL(name) \
- SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_syscall_post_##name
+ SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_syscall_post_impl_##name
#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_FD_CLOSE
+# define COMMON_SYSCALL_FD_CLOSE(fd)
+#endif
+
+#ifndef COMMON_SYSCALL_PRE_FORK
+# define COMMON_SYSCALL_PRE_FORK()
+#endif
+
+#ifndef COMMON_SYSCALL_POST_FORK
+# define COMMON_SYSCALL_POST_FORK(res)
+#endif
+
// FIXME: do some kind of PRE_READ for all syscall arguments (int(s) and such).
extern "C" {
@@ -55,6 +78,16 @@ struct sanitizer_kernel_msghdr {
unsigned msg_flags;
};
+struct sanitizer_kernel_mmsghdr {
+ struct sanitizer_kernel_msghdr msg_hdr;
+ unsigned msg_len;
+};
+
+struct sanitizer_kernel_timespec {
+ long tv_sec;
+ long tv_nsec;
+};
+
struct sanitizer_kernel_timeval {
long tv_sec;
long tv_usec;
@@ -65,79 +98,2683 @@ struct sanitizer_kernel_rusage {
long ru_long[14];
};
-PRE_SYSCALL(recvmsg)(int sockfd, struct sanitizer_kernel_msghdr *msg,
- int flags) {
+struct sanitizer_kernel_sockaddr {
+ unsigned short sa_family;
+ char sa_data[14];
+};
+
+// Real sigset size is always passed as a syscall argument.
+// Declare it "void" to catch sizeof(kernel_sigset_t).
+typedef void kernel_sigset_t;
+
+static void kernel_write_iovec(const __sanitizer_iovec *iovec,
+ SIZE_T iovlen, SIZE_T maxlen) {
+ for (SIZE_T i = 0; i < iovlen && maxlen; ++i) {
+ SSIZE_T sz = Min(iovec[i].iov_len, maxlen);
+ POST_WRITE(iovec[i].iov_base, sz);
+ maxlen -= sz;
+ }
+}
+
+// This functions uses POST_READ, because it needs to run after syscall to know
+// the real read range.
+static void kernel_read_iovec(const __sanitizer_iovec *iovec,
+ SIZE_T iovlen, SIZE_T maxlen) {
+ POST_READ(iovec, sizeof(*iovec) * iovlen);
+ for (SIZE_T i = 0; i < iovlen && maxlen; ++i) {
+ SSIZE_T sz = Min(iovec[i].iov_len, maxlen);
+ POST_READ(iovec[i].iov_base, sz);
+ maxlen -= sz;
+ }
+}
+
+PRE_SYSCALL(recvmsg)(long sockfd, sanitizer_kernel_msghdr *msg, long flags) {
PRE_READ(msg, sizeof(*msg));
}
-POST_SYSCALL(recvmsg)(long res, int sockfd, struct sanitizer_kernel_msghdr *msg,
- int flags) {
- if (res > 0)
- for (unsigned long i = 0; i < msg->msg_iovlen; ++i) {
- POST_WRITE(msg->msg_iov[i].iov_base, msg->msg_iov[i].iov_len);
+POST_SYSCALL(recvmsg)(long res, long sockfd, sanitizer_kernel_msghdr *msg,
+ long flags) {
+ if (res >= 0) {
+ if (msg) {
+ for (unsigned long i = 0; i < msg->msg_iovlen; ++i) {
+ POST_WRITE(msg->msg_iov[i].iov_base, msg->msg_iov[i].iov_len);
+ }
+ POST_WRITE(msg->msg_control, msg->msg_controllen);
}
- POST_WRITE(msg->msg_control, msg->msg_controllen);
+ }
+}
+
+PRE_SYSCALL(recvmmsg)(long fd, sanitizer_kernel_mmsghdr *msg, long vlen,
+ long flags, void *timeout) {
+ PRE_READ(msg, vlen * sizeof(*msg));
+}
+
+POST_SYSCALL(recvmmsg)(long res, long fd, sanitizer_kernel_mmsghdr *msg,
+ long vlen, long flags, void *timeout) {
+ if (res >= 0) {
+ if (msg) {
+ for (unsigned long i = 0; i < msg->msg_hdr.msg_iovlen; ++i) {
+ POST_WRITE(msg->msg_hdr.msg_iov[i].iov_base,
+ msg->msg_hdr.msg_iov[i].iov_len);
+ }
+ POST_WRITE(msg->msg_hdr.msg_control, msg->msg_hdr.msg_controllen);
+ POST_WRITE(&msg->msg_len, sizeof(msg->msg_len));
+ }
+ if (timeout) POST_WRITE(timeout, struct_timespec_sz);
+ }
+}
+
+PRE_SYSCALL(read)(long fd, void *buf, uptr count) {
+ if (buf) {
+ PRE_WRITE(buf, count);
+ }
+}
+
+POST_SYSCALL(read)(long res, long fd, void *buf, uptr count) {
+ if (res > 0 && buf) {
+ POST_WRITE(buf, res);
+ }
+}
+
+PRE_SYSCALL(time)(void *tloc) {}
+
+POST_SYSCALL(time)(long res, void *tloc) {
+ if (res >= 0) {
+ if (tloc) POST_WRITE(tloc, sizeof(long));
+ }
+}
+
+PRE_SYSCALL(stime)(void *tptr) {}
+
+POST_SYSCALL(stime)(long res, void *tptr) {
+ if (res >= 0) {
+ if (tptr) POST_WRITE(tptr, sizeof(long));
+ }
+}
+
+PRE_SYSCALL(gettimeofday)(void *tv, void *tz) {}
+
+POST_SYSCALL(gettimeofday)(long res, void *tv, void *tz) {
+ if (res >= 0) {
+ if (tv) POST_WRITE(tv, timeval_sz);
+ if (tz) POST_WRITE(tz, struct_timezone_sz);
+ }
+}
+
+PRE_SYSCALL(settimeofday)(void *tv, void *tz) {}
+
+POST_SYSCALL(settimeofday)(long res, void *tv, void *tz) {
+ if (res >= 0) {
+ if (tv) POST_WRITE(tv, timeval_sz);
+ if (tz) POST_WRITE(tz, struct_timezone_sz);
+ }
+}
+
+PRE_SYSCALL(adjtimex)(void *txc_p) {}
+
+POST_SYSCALL(adjtimex)(long res, void *txc_p) {
+ if (res >= 0) {
+ if (txc_p) POST_WRITE(txc_p, struct_timex_sz);
+ }
+}
+
+PRE_SYSCALL(times)(void *tbuf) {}
+
+POST_SYSCALL(times)(long res, void *tbuf) {
+ if (res >= 0) {
+ if (tbuf) POST_WRITE(tbuf, struct_tms_sz);
+ }
+}
+
+PRE_SYSCALL(gettid)() {}
+
+POST_SYSCALL(gettid)(long res) {}
+
+PRE_SYSCALL(nanosleep)(void *rqtp, void *rmtp) {}
+
+POST_SYSCALL(nanosleep)(long res, void *rqtp, void *rmtp) {
+ if (res >= 0) {
+ if (rqtp) POST_WRITE(rqtp, struct_timespec_sz);
+ if (rmtp) POST_WRITE(rmtp, struct_timespec_sz);
+ }
+}
+
+PRE_SYSCALL(alarm)(long seconds) {}
+
+POST_SYSCALL(alarm)(long res, long seconds) {}
+
+PRE_SYSCALL(getpid)() {}
+
+POST_SYSCALL(getpid)(long res) {}
+
+PRE_SYSCALL(getppid)() {}
+
+POST_SYSCALL(getppid)(long res) {}
+
+PRE_SYSCALL(getuid)() {}
+
+POST_SYSCALL(getuid)(long res) {}
+
+PRE_SYSCALL(geteuid)() {}
+
+POST_SYSCALL(geteuid)(long res) {}
+
+PRE_SYSCALL(getgid)() {}
+
+POST_SYSCALL(getgid)(long res) {}
+
+PRE_SYSCALL(getegid)() {}
+
+POST_SYSCALL(getegid)(long res) {}
+
+PRE_SYSCALL(getresuid)(void *ruid, void *euid, void *suid) {}
+
+POST_SYSCALL(getresuid)(long res, void *ruid, void *euid, void *suid) {
+ if (res >= 0) {
+ if (ruid) POST_WRITE(ruid, sizeof(unsigned));
+ if (euid) POST_WRITE(euid, sizeof(unsigned));
+ if (suid) POST_WRITE(suid, sizeof(unsigned));
+ }
+}
+
+PRE_SYSCALL(getresgid)(void *rgid, void *egid, void *sgid) {}
+
+POST_SYSCALL(getresgid)(long res, void *rgid, void *egid, void *sgid) {
+ if (res >= 0) {
+ if (rgid) POST_WRITE(rgid, sizeof(unsigned));
+ if (egid) POST_WRITE(egid, sizeof(unsigned));
+ if (sgid) POST_WRITE(sgid, sizeof(unsigned));
+ }
+}
+
+PRE_SYSCALL(getpgid)(long pid) {}
+
+POST_SYSCALL(getpgid)(long res, long pid) {}
+
+PRE_SYSCALL(getpgrp)() {}
+
+POST_SYSCALL(getpgrp)(long res) {}
+
+PRE_SYSCALL(getsid)(long pid) {}
+
+POST_SYSCALL(getsid)(long res, long pid) {}
+
+PRE_SYSCALL(getgroups)(long gidsetsize, void *grouplist) {}
+
+POST_SYSCALL(getgroups)(long res, long gidsetsize,
+ __sanitizer___kernel_gid_t *grouplist) {
+ if (res >= 0) {
+ if (grouplist) POST_WRITE(grouplist, res * sizeof(*grouplist));
+ }
+}
+
+PRE_SYSCALL(setregid)(long rgid, long egid) {}
+
+POST_SYSCALL(setregid)(long res, long rgid, long egid) {}
+
+PRE_SYSCALL(setgid)(long gid) {}
+
+POST_SYSCALL(setgid)(long res, long gid) {}
+
+PRE_SYSCALL(setreuid)(long ruid, long euid) {}
+
+POST_SYSCALL(setreuid)(long res, long ruid, long euid) {}
+
+PRE_SYSCALL(setuid)(long uid) {}
+
+POST_SYSCALL(setuid)(long res, long uid) {}
+
+PRE_SYSCALL(setresuid)(long ruid, long euid, long suid) {}
+
+POST_SYSCALL(setresuid)(long res, long ruid, long euid, long suid) {}
+
+PRE_SYSCALL(setresgid)(long rgid, long egid, long sgid) {}
+
+POST_SYSCALL(setresgid)(long res, long rgid, long egid, long sgid) {}
+
+PRE_SYSCALL(setfsuid)(long uid) {}
+
+POST_SYSCALL(setfsuid)(long res, long uid) {}
+
+PRE_SYSCALL(setfsgid)(long gid) {}
+
+POST_SYSCALL(setfsgid)(long res, long gid) {}
+
+PRE_SYSCALL(setpgid)(long pid, long pgid) {}
+
+POST_SYSCALL(setpgid)(long res, long pid, long pgid) {}
+
+PRE_SYSCALL(setsid)() {}
+
+POST_SYSCALL(setsid)(long res) {}
+
+PRE_SYSCALL(setgroups)(long gidsetsize, __sanitizer___kernel_gid_t *grouplist) {
+ if (grouplist) POST_WRITE(grouplist, gidsetsize * sizeof(*grouplist));
+}
+
+POST_SYSCALL(setgroups)(long res, long gidsetsize,
+ __sanitizer___kernel_gid_t *grouplist) {}
+
+PRE_SYSCALL(acct)(const void *name) {
+ if (name)
+ PRE_READ(name, __sanitizer::internal_strlen((const char *)name) + 1);
+}
+
+POST_SYSCALL(acct)(long res, const void *name) {}
+
+PRE_SYSCALL(capget)(void *header, void *dataptr) {}
+
+POST_SYSCALL(capget)(long res, void *header, void *dataptr) {
+ if (res >= 0) {
+ if (header) POST_WRITE(header, __user_cap_header_struct_sz);
+ if (dataptr) POST_WRITE(dataptr, __user_cap_data_struct_sz);
+ }
+}
+
+PRE_SYSCALL(capset)(void *header, const void *data) {
+ 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);
+ }
+}
+
+PRE_SYSCALL(personality)(long personality) {}
+
+POST_SYSCALL(personality)(long res, long personality) {}
+
+PRE_SYSCALL(sigpending)(void *set) {}
+
+POST_SYSCALL(sigpending)(long res, void *set) {
+ if (res >= 0) {
+ if (set) POST_WRITE(set, old_sigset_t_sz);
+ }
+}
+
+PRE_SYSCALL(sigprocmask)(long how, void *set, void *oset) {}
+
+POST_SYSCALL(sigprocmask)(long res, long how, void *set, void *oset) {
+ if (res >= 0) {
+ if (set) POST_WRITE(set, old_sigset_t_sz);
+ if (oset) POST_WRITE(oset, old_sigset_t_sz);
+ }
}
-PRE_SYSCALL(rt_sigpending)(void *p, unsigned long s) { PRE_WRITE(p, s); }
+PRE_SYSCALL(getitimer)(long which, void *value) {}
-POST_SYSCALL(rt_sigpending)(long res, void *p, unsigned long s) {
- if (res == 0) {
- POST_WRITE(p, s);
+POST_SYSCALL(getitimer)(long res, long which, void *value) {
+ if (res >= 0) {
+ if (value) POST_WRITE(value, struct_itimerval_sz);
}
}
-PRE_SYSCALL(getdents)(int fd, void *dirp, int count) { PRE_WRITE(dirp, count); }
+PRE_SYSCALL(setitimer)(long which, void *value, void *ovalue) {}
-POST_SYSCALL(getdents)(long res, int fd, void *dirp, int count) {
- if (res > 0) {
- POST_WRITE(dirp, res);
+POST_SYSCALL(setitimer)(long res, long which, void *value, void *ovalue) {
+ if (res >= 0) {
+ if (value) POST_WRITE(value, struct_itimerval_sz);
+ if (ovalue) POST_WRITE(ovalue, struct_itimerval_sz);
}
}
-PRE_SYSCALL(getdents64)(int fd, void *dirp, int count) {
- PRE_WRITE(dirp, count);
+PRE_SYSCALL(timer_create)(long which_clock, void *timer_event_spec,
+ void *created_timer_id) {}
+
+POST_SYSCALL(timer_create)(long res, long which_clock, void *timer_event_spec,
+ void *created_timer_id) {
+ if (res >= 0) {
+ if (timer_event_spec) POST_WRITE(timer_event_spec, struct_sigevent_sz);
+ if (created_timer_id) POST_WRITE(created_timer_id, sizeof(long));
+ }
}
-POST_SYSCALL(getdents64)(long res, int fd, void *dirp, int count) {
- if (res > 0) {
- POST_WRITE(dirp, res);
+PRE_SYSCALL(timer_gettime)(long timer_id, void *setting) {}
+
+POST_SYSCALL(timer_gettime)(long res, long timer_id, void *setting) {
+ if (res >= 0) {
+ if (setting) POST_WRITE(setting, struct_itimerspec_sz);
}
}
-PRE_SYSCALL(wait4)(int pid, int *status, int options,
- struct sanitizer_kernel_rusage *r) {
- if (status) {
- PRE_WRITE(status, sizeof(*status));
+PRE_SYSCALL(timer_getoverrun)(long timer_id) {}
+
+POST_SYSCALL(timer_getoverrun)(long res, long timer_id) {}
+
+PRE_SYSCALL(timer_settime)(long timer_id, long flags, const void *new_setting,
+ void *old_setting) {
+ if (new_setting) PRE_READ(new_setting, struct_itimerspec_sz);
+}
+
+POST_SYSCALL(timer_settime)(long res, long timer_id, long flags,
+ const void *new_setting, void *old_setting) {
+ if (res >= 0) {
+ if (old_setting) POST_WRITE(old_setting, struct_itimerspec_sz);
}
- if (r) {
- PRE_WRITE(r, sizeof(*r));
+}
+
+PRE_SYSCALL(timer_delete)(long timer_id) {}
+
+POST_SYSCALL(timer_delete)(long res, long timer_id) {}
+
+PRE_SYSCALL(clock_settime)(long which_clock, const void *tp) {
+ if (tp) PRE_READ(tp, struct_timespec_sz);
+}
+
+POST_SYSCALL(clock_settime)(long res, long which_clock, const void *tp) {}
+
+PRE_SYSCALL(clock_gettime)(long which_clock, void *tp) {}
+
+POST_SYSCALL(clock_gettime)(long res, long which_clock, void *tp) {
+ if (res >= 0) {
+ if (tp) POST_WRITE(tp, struct_timespec_sz);
}
}
-POST_SYSCALL(wait4)(long res, int pid, int *status, int options,
- struct sanitizer_kernel_rusage *r) {
- if (res > 0) {
- if (status) {
- POST_WRITE(status, sizeof(*status));
+PRE_SYSCALL(clock_adjtime)(long which_clock, void *tx) {}
+
+POST_SYSCALL(clock_adjtime)(long res, long which_clock, void *tx) {
+ if (res >= 0) {
+ if (tx) POST_WRITE(tx, struct_timex_sz);
+ }
+}
+
+PRE_SYSCALL(clock_getres)(long which_clock, void *tp) {}
+
+POST_SYSCALL(clock_getres)(long res, long which_clock, void *tp) {
+ if (res >= 0) {
+ if (tp) POST_WRITE(tp, struct_timespec_sz);
+ }
+}
+
+PRE_SYSCALL(clock_nanosleep)(long which_clock, long flags, const void *rqtp,
+ void *rmtp) {
+ if (rqtp) PRE_READ(rqtp, struct_timespec_sz);
+}
+
+POST_SYSCALL(clock_nanosleep)(long res, long which_clock, long flags,
+ const void *rqtp, void *rmtp) {
+ if (res >= 0) {
+ if (rmtp) POST_WRITE(rmtp, struct_timespec_sz);
+ }
+}
+
+PRE_SYSCALL(nice)(long increment) {}
+
+POST_SYSCALL(nice)(long res, long increment) {}
+
+PRE_SYSCALL(sched_setscheduler)(long pid, long policy, void *param) {}
+
+POST_SYSCALL(sched_setscheduler)(long res, long pid, long policy, void *param) {
+ if (res >= 0) {
+ if (param) POST_WRITE(param, struct_sched_param_sz);
+ }
+}
+
+PRE_SYSCALL(sched_setparam)(long pid, void *param) {
+ if (param) PRE_READ(param, struct_sched_param_sz);
+}
+
+POST_SYSCALL(sched_setparam)(long res, long pid, void *param) {}
+
+PRE_SYSCALL(sched_getscheduler)(long pid) {}
+
+POST_SYSCALL(sched_getscheduler)(long res, long pid) {}
+
+PRE_SYSCALL(sched_getparam)(long pid, void *param) {}
+
+POST_SYSCALL(sched_getparam)(long res, long pid, void *param) {
+ if (res >= 0) {
+ if (param) POST_WRITE(param, struct_sched_param_sz);
+ }
+}
+
+PRE_SYSCALL(sched_setaffinity)(long pid, long len, void *user_mask_ptr) {
+ if (user_mask_ptr) PRE_READ(user_mask_ptr, len);
+}
+
+POST_SYSCALL(sched_setaffinity)(long res, long pid, long len,
+ void *user_mask_ptr) {}
+
+PRE_SYSCALL(sched_getaffinity)(long pid, long len, void *user_mask_ptr) {}
+
+POST_SYSCALL(sched_getaffinity)(long res, long pid, long len,
+ void *user_mask_ptr) {
+ if (res >= 0) {
+ if (user_mask_ptr) POST_WRITE(user_mask_ptr, len);
+ }
+}
+
+PRE_SYSCALL(sched_yield)() {}
+
+POST_SYSCALL(sched_yield)(long res) {}
+
+PRE_SYSCALL(sched_get_priority_max)(long policy) {}
+
+POST_SYSCALL(sched_get_priority_max)(long res, long policy) {}
+
+PRE_SYSCALL(sched_get_priority_min)(long policy) {}
+
+POST_SYSCALL(sched_get_priority_min)(long res, long policy) {}
+
+PRE_SYSCALL(sched_rr_get_interval)(long pid, void *interval) {}
+
+POST_SYSCALL(sched_rr_get_interval)(long res, long pid, void *interval) {
+ if (res >= 0) {
+ if (interval) POST_WRITE(interval, struct_timespec_sz);
+ }
+}
+
+PRE_SYSCALL(setpriority)(long which, long who, long niceval) {}
+
+POST_SYSCALL(setpriority)(long res, long which, long who, long niceval) {}
+
+PRE_SYSCALL(getpriority)(long which, long who) {}
+
+POST_SYSCALL(getpriority)(long res, long which, long who) {}
+
+PRE_SYSCALL(shutdown)(long arg0, long arg1) {}
+
+POST_SYSCALL(shutdown)(long res, long arg0, long arg1) {}
+
+PRE_SYSCALL(reboot)(long magic1, long magic2, long cmd, void *arg) {}
+
+POST_SYSCALL(reboot)(long res, long magic1, long magic2, long cmd, void *arg) {}
+
+PRE_SYSCALL(restart_syscall)() {}
+
+POST_SYSCALL(restart_syscall)(long res) {}
+
+PRE_SYSCALL(kexec_load)(long entry, long nr_segments, void *segments,
+ long flags) {}
+
+POST_SYSCALL(kexec_load)(long res, long entry, long nr_segments, void *segments,
+ long flags) {
+ if (res >= 0) {
+ if (segments) POST_WRITE(segments, struct_kexec_segment_sz);
+ }
+}
+
+PRE_SYSCALL(exit)(long error_code) {}
+
+POST_SYSCALL(exit)(long res, long error_code) {}
+
+PRE_SYSCALL(exit_group)(long error_code) {}
+
+POST_SYSCALL(exit_group)(long res, long error_code) {}
+
+PRE_SYSCALL(wait4)(long pid, void *stat_addr, long options, void *ru) {}
+
+POST_SYSCALL(wait4)(long res, long pid, void *stat_addr, long options,
+ void *ru) {
+ if (res >= 0) {
+ if (stat_addr) POST_WRITE(stat_addr, sizeof(int));
+ if (ru) POST_WRITE(ru, struct_rusage_sz);
+ }
+}
+
+PRE_SYSCALL(waitid)(long which, long pid, void *infop, long options, void *ru) {
+}
+
+POST_SYSCALL(waitid)(long res, long which, long pid, void *infop, long options,
+ void *ru) {
+ if (res >= 0) {
+ if (infop) POST_WRITE(infop, siginfo_t_sz);
+ if (ru) POST_WRITE(ru, struct_rusage_sz);
+ }
+}
+
+PRE_SYSCALL(waitpid)(long pid, void *stat_addr, long options) {}
+
+POST_SYSCALL(waitpid)(long res, long pid, void *stat_addr, long options) {
+ if (res >= 0) {
+ if (stat_addr) POST_WRITE(stat_addr, sizeof(int));
+ }
+}
+
+PRE_SYSCALL(set_tid_address)(void *tidptr) {}
+
+POST_SYSCALL(set_tid_address)(long res, void *tidptr) {
+ if (res >= 0) {
+ if (tidptr) POST_WRITE(tidptr, sizeof(int));
+ }
+}
+
+PRE_SYSCALL(init_module)(void *umod, long len, const void *uargs) {
+ if (uargs)
+ PRE_READ(uargs, __sanitizer::internal_strlen((const char *)uargs) + 1);
+}
+
+POST_SYSCALL(init_module)(long res, void *umod, long len, const void *uargs) {}
+
+PRE_SYSCALL(delete_module)(const void *name_user, long flags) {
+ if (name_user)
+ PRE_READ(name_user,
+ __sanitizer::internal_strlen((const char *)name_user) + 1);
+}
+
+POST_SYSCALL(delete_module)(long res, const void *name_user, long flags) {}
+
+PRE_SYSCALL(rt_sigprocmask)(long how, void *set, void *oset, long sigsetsize) {}
+
+POST_SYSCALL(rt_sigprocmask)(long res, long how, kernel_sigset_t *set,
+ kernel_sigset_t *oset, long sigsetsize) {
+ if (res >= 0) {
+ if (set) POST_WRITE(set, sigsetsize);
+ if (oset) POST_WRITE(oset, sigsetsize);
+ }
+}
+
+PRE_SYSCALL(rt_sigpending)(void *set, long sigsetsize) {}
+
+POST_SYSCALL(rt_sigpending)(long res, kernel_sigset_t *set, long sigsetsize) {
+ if (res >= 0) {
+ if (set) POST_WRITE(set, sigsetsize);
+ }
+}
+
+PRE_SYSCALL(rt_sigtimedwait)(const kernel_sigset_t *uthese, void *uinfo,
+ const void *uts, long sigsetsize) {
+ if (uthese) PRE_READ(uthese, sigsetsize);
+ if (uts) PRE_READ(uts, struct_timespec_sz);
+}
+
+POST_SYSCALL(rt_sigtimedwait)(long res, const void *uthese, void *uinfo,
+ const void *uts, long sigsetsize) {
+ if (res >= 0) {
+ if (uinfo) POST_WRITE(uinfo, siginfo_t_sz);
+ }
+}
+
+PRE_SYSCALL(rt_tgsigqueueinfo)(long tgid, long pid, long sig, void *uinfo) {}
+
+POST_SYSCALL(rt_tgsigqueueinfo)(long res, long tgid, long pid, long sig,
+ void *uinfo) {
+ if (res >= 0) {
+ if (uinfo) POST_WRITE(uinfo, siginfo_t_sz);
+ }
+}
+
+PRE_SYSCALL(kill)(long pid, long sig) {}
+
+POST_SYSCALL(kill)(long res, long pid, long sig) {}
+
+PRE_SYSCALL(tgkill)(long tgid, long pid, long sig) {}
+
+POST_SYSCALL(tgkill)(long res, long tgid, long pid, long sig) {}
+
+PRE_SYSCALL(tkill)(long pid, long sig) {}
+
+POST_SYSCALL(tkill)(long res, long pid, long sig) {}
+
+PRE_SYSCALL(rt_sigqueueinfo)(long pid, long sig, void *uinfo) {}
+
+POST_SYSCALL(rt_sigqueueinfo)(long res, long pid, long sig, void *uinfo) {
+ if (res >= 0) {
+ if (uinfo) POST_WRITE(uinfo, siginfo_t_sz);
+ }
+}
+
+PRE_SYSCALL(sgetmask)() {}
+
+POST_SYSCALL(sgetmask)(long res) {}
+
+PRE_SYSCALL(ssetmask)(long newmask) {}
+
+POST_SYSCALL(ssetmask)(long res, long newmask) {}
+
+PRE_SYSCALL(signal)(long sig, long handler) {}
+
+POST_SYSCALL(signal)(long res, long sig, long handler) {}
+
+PRE_SYSCALL(pause)() {}
+
+POST_SYSCALL(pause)(long res) {}
+
+PRE_SYSCALL(sync)() {}
+
+POST_SYSCALL(sync)(long res) {}
+
+PRE_SYSCALL(fsync)(long fd) {}
+
+POST_SYSCALL(fsync)(long res, long fd) {}
+
+PRE_SYSCALL(fdatasync)(long fd) {}
+
+POST_SYSCALL(fdatasync)(long res, long fd) {}
+
+PRE_SYSCALL(bdflush)(long func, long data) {}
+
+POST_SYSCALL(bdflush)(long res, long func, long data) {}
+
+PRE_SYSCALL(mount)(void *dev_name, void *dir_name, void *type, long flags,
+ void *data) {}
+
+POST_SYSCALL(mount)(long res, void *dev_name, void *dir_name, void *type,
+ long flags, void *data) {
+ if (res >= 0) {
+ if (dev_name)
+ POST_WRITE(dev_name,
+ __sanitizer::internal_strlen((const char *)dev_name) + 1);
+ if (dir_name)
+ POST_WRITE(dir_name,
+ __sanitizer::internal_strlen((const char *)dir_name) + 1);
+ if (type)
+ POST_WRITE(type, __sanitizer::internal_strlen((const char *)type) + 1);
+ }
+}
+
+PRE_SYSCALL(umount)(void *name, long flags) {}
+
+POST_SYSCALL(umount)(long res, void *name, long flags) {
+ if (res >= 0) {
+ if (name)
+ POST_WRITE(name, __sanitizer::internal_strlen((const char *)name) + 1);
+ }
+}
+
+PRE_SYSCALL(oldumount)(void *name) {}
+
+POST_SYSCALL(oldumount)(long res, void *name) {
+ if (res >= 0) {
+ if (name)
+ POST_WRITE(name, __sanitizer::internal_strlen((const char *)name) + 1);
+ }
+}
+
+PRE_SYSCALL(truncate)(const void *path, long length) {
+ if (path)
+ PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1);
+}
+
+POST_SYSCALL(truncate)(long res, const void *path, long length) {}
+
+PRE_SYSCALL(ftruncate)(long fd, long length) {}
+
+POST_SYSCALL(ftruncate)(long res, long fd, long length) {}
+
+PRE_SYSCALL(stat)(const void *filename, void *statbuf) {
+ if (filename)
+ PRE_READ(filename,
+ __sanitizer::internal_strlen((const char *)filename) + 1);
+}
+
+POST_SYSCALL(stat)(long res, const void *filename, void *statbuf) {
+ if (res >= 0) {
+ if (statbuf) POST_WRITE(statbuf, struct___old_kernel_stat_sz);
+ }
+}
+
+PRE_SYSCALL(statfs)(const void *path, void *buf) {
+ if (path)
+ PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1);
+}
+
+POST_SYSCALL(statfs)(long res, const void *path, void *buf) {
+ if (res >= 0) {
+ if (buf) POST_WRITE(buf, struct_statfs_sz);
+ }
+}
+
+PRE_SYSCALL(statfs64)(const void *path, long sz, void *buf) {
+ if (path)
+ PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1);
+}
+
+POST_SYSCALL(statfs64)(long res, const void *path, long sz, void *buf) {
+ if (res >= 0) {
+ if (buf) POST_WRITE(buf, struct_statfs64_sz);
+ }
+}
+
+PRE_SYSCALL(fstatfs)(long fd, void *buf) {}
+
+POST_SYSCALL(fstatfs)(long res, long fd, void *buf) {
+ if (res >= 0) {
+ if (buf) POST_WRITE(buf, struct_statfs_sz);
+ }
+}
+
+PRE_SYSCALL(fstatfs64)(long fd, long sz, void *buf) {}
+
+POST_SYSCALL(fstatfs64)(long res, long fd, long sz, void *buf) {
+ if (res >= 0) {
+ if (buf) POST_WRITE(buf, struct_statfs64_sz);
+ }
+}
+
+PRE_SYSCALL(lstat)(const void *filename, void *statbuf) {
+ if (filename)
+ PRE_READ(filename,
+ __sanitizer::internal_strlen((const char *)filename) + 1);
+}
+
+POST_SYSCALL(lstat)(long res, const void *filename, void *statbuf) {
+ if (res >= 0) {
+ if (statbuf) POST_WRITE(statbuf, struct___old_kernel_stat_sz);
+ }
+}
+
+PRE_SYSCALL(fstat)(long fd, void *statbuf) {}
+
+POST_SYSCALL(fstat)(long res, long fd, void *statbuf) {
+ if (res >= 0) {
+ if (statbuf) POST_WRITE(statbuf, struct___old_kernel_stat_sz);
+ }
+}
+
+PRE_SYSCALL(newstat)(const void *filename, void *statbuf) {
+ if (filename)
+ PRE_READ(filename,
+ __sanitizer::internal_strlen((const char *)filename) + 1);
+}
+
+POST_SYSCALL(newstat)(long res, const void *filename, void *statbuf) {
+ if (res >= 0) {
+ if (statbuf) POST_WRITE(statbuf, struct_kernel_stat_sz);
+ }
+}
+
+PRE_SYSCALL(newlstat)(const void *filename, void *statbuf) {
+ if (filename)
+ PRE_READ(filename,
+ __sanitizer::internal_strlen((const char *)filename) + 1);
+}
+
+POST_SYSCALL(newlstat)(long res, const void *filename, void *statbuf) {
+ if (res >= 0) {
+ if (statbuf) POST_WRITE(statbuf, struct_kernel_stat_sz);
+ }
+}
+
+PRE_SYSCALL(newfstat)(long fd, void *statbuf) {}
+
+POST_SYSCALL(newfstat)(long res, long fd, void *statbuf) {
+ if (res >= 0) {
+ if (statbuf) POST_WRITE(statbuf, struct_kernel_stat_sz);
+ }
+}
+
+PRE_SYSCALL(ustat)(long dev, void *ubuf) {}
+
+POST_SYSCALL(ustat)(long res, long dev, void *ubuf) {
+ if (res >= 0) {
+ if (ubuf) POST_WRITE(ubuf, struct_ustat_sz);
+ }
+}
+
+PRE_SYSCALL(stat64)(const void *filename, void *statbuf) {
+ if (filename)
+ PRE_READ(filename,
+ __sanitizer::internal_strlen((const char *)filename) + 1);
+}
+
+POST_SYSCALL(stat64)(long res, const void *filename, void *statbuf) {
+ if (res >= 0) {
+ if (statbuf) POST_WRITE(statbuf, struct_kernel_stat64_sz);
+ }
+}
+
+PRE_SYSCALL(fstat64)(long fd, void *statbuf) {}
+
+POST_SYSCALL(fstat64)(long res, long fd, void *statbuf) {
+ if (res >= 0) {
+ if (statbuf) POST_WRITE(statbuf, struct_kernel_stat64_sz);
+ }
+}
+
+PRE_SYSCALL(lstat64)(const void *filename, void *statbuf) {
+ if (filename)
+ PRE_READ(filename,
+ __sanitizer::internal_strlen((const char *)filename) + 1);
+}
+
+POST_SYSCALL(lstat64)(long res, const void *filename, void *statbuf) {
+ if (res >= 0) {
+ if (statbuf) POST_WRITE(statbuf, struct_kernel_stat64_sz);
+ }
+}
+
+PRE_SYSCALL(setxattr)(const void *path, const void *name, const void *value,
+ long size, long flags) {
+ if (path)
+ PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1);
+ if (name)
+ PRE_READ(name, __sanitizer::internal_strlen((const char *)name) + 1);
+ if (value) PRE_READ(value, size);
+}
+
+POST_SYSCALL(setxattr)(long res, const void *path, const void *name,
+ const void *value, long size, long flags) {}
+
+PRE_SYSCALL(lsetxattr)(const void *path, const void *name, const void *value,
+ long size, long flags) {
+ if (path)
+ PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1);
+ if (name)
+ PRE_READ(name, __sanitizer::internal_strlen((const char *)name) + 1);
+ if (value) PRE_READ(value, size);
+}
+
+POST_SYSCALL(lsetxattr)(long res, const void *path, const void *name,
+ const void *value, long size, long flags) {}
+
+PRE_SYSCALL(fsetxattr)(long fd, const void *name, const void *value, long size,
+ long flags) {
+ if (name)
+ PRE_READ(name, __sanitizer::internal_strlen((const char *)name) + 1);
+ if (value) PRE_READ(value, size);
+}
+
+POST_SYSCALL(fsetxattr)(long res, long fd, const void *name, const void *value,
+ long size, long flags) {}
+
+PRE_SYSCALL(getxattr)(const void *path, const void *name, void *value,
+ long size) {
+ if (path)
+ PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1);
+ if (name)
+ PRE_READ(name, __sanitizer::internal_strlen((const char *)name) + 1);
+}
+
+POST_SYSCALL(getxattr)(long res, const void *path, const void *name,
+ void *value, long size) {
+ if (res >= 0) {
+ if (value) POST_WRITE(value, size);
+ }
+}
+
+PRE_SYSCALL(lgetxattr)(const void *path, const void *name, void *value,
+ long size) {
+ if (path)
+ PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1);
+ if (name)
+ PRE_READ(name, __sanitizer::internal_strlen((const char *)name) + 1);
+}
+
+POST_SYSCALL(lgetxattr)(long res, const void *path, const void *name,
+ void *value, long size) {
+ if (res >= 0) {
+ if (value) POST_WRITE(value, size);
+ }
+}
+
+PRE_SYSCALL(fgetxattr)(long fd, const void *name, void *value, long size) {
+ if (name)
+ PRE_READ(name, __sanitizer::internal_strlen((const char *)name) + 1);
+}
+
+POST_SYSCALL(fgetxattr)(long res, long fd, const void *name, void *value,
+ long size) {
+ if (res >= 0) {
+ if (value) POST_WRITE(value, size);
+ }
+}
+
+PRE_SYSCALL(listxattr)(const void *path, void *list, long size) {
+ if (path)
+ PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1);
+}
+
+POST_SYSCALL(listxattr)(long res, const void *path, void *list, long size) {
+ if (res >= 0) {
+ if (list) POST_WRITE(list, size);
+ }
+}
+
+PRE_SYSCALL(llistxattr)(const void *path, void *list, long size) {
+ if (path)
+ PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1);
+}
+
+POST_SYSCALL(llistxattr)(long res, const void *path, void *list, long size) {
+ if (res >= 0) {
+ if (list) POST_WRITE(list, size);
+ }
+}
+
+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);
+ }
+}
+
+PRE_SYSCALL(removexattr)(const void *path, const void *name) {
+ if (path)
+ PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1);
+ if (name)
+ PRE_READ(name, __sanitizer::internal_strlen((const char *)name) + 1);
+}
+
+POST_SYSCALL(removexattr)(long res, const void *path, const void *name) {}
+
+PRE_SYSCALL(lremovexattr)(const void *path, const void *name) {
+ if (path)
+ PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1);
+ if (name)
+ PRE_READ(name, __sanitizer::internal_strlen((const char *)name) + 1);
+}
+
+POST_SYSCALL(lremovexattr)(long res, const void *path, const void *name) {}
+
+PRE_SYSCALL(fremovexattr)(long fd, const void *name) {
+ if (name)
+ PRE_READ(name, __sanitizer::internal_strlen((const char *)name) + 1);
+}
+
+POST_SYSCALL(fremovexattr)(long res, long fd, const void *name) {}
+
+PRE_SYSCALL(brk)(long brk) {}
+
+POST_SYSCALL(brk)(long res, long brk) {}
+
+PRE_SYSCALL(mprotect)(long start, long len, long prot) {}
+
+POST_SYSCALL(mprotect)(long res, long start, long len, long prot) {}
+
+PRE_SYSCALL(mremap)(long addr, long old_len, long new_len, long flags,
+ long new_addr) {}
+
+POST_SYSCALL(mremap)(long res, long addr, long old_len, long new_len,
+ long flags, long new_addr) {}
+
+PRE_SYSCALL(remap_file_pages)(long start, long size, long prot, long pgoff,
+ long flags) {}
+
+POST_SYSCALL(remap_file_pages)(long res, long start, long size, long prot,
+ long pgoff, long flags) {}
+
+PRE_SYSCALL(msync)(long start, long len, long flags) {}
+
+POST_SYSCALL(msync)(long res, long start, long len, long flags) {}
+
+PRE_SYSCALL(munmap)(long addr, long len) {}
+
+POST_SYSCALL(munmap)(long res, long addr, long len) {}
+
+PRE_SYSCALL(mlock)(long start, long len) {}
+
+POST_SYSCALL(mlock)(long res, long start, long len) {}
+
+PRE_SYSCALL(munlock)(long start, long len) {}
+
+POST_SYSCALL(munlock)(long res, long start, long len) {}
+
+PRE_SYSCALL(mlockall)(long flags) {}
+
+POST_SYSCALL(mlockall)(long res, long flags) {}
+
+PRE_SYSCALL(munlockall)() {}
+
+POST_SYSCALL(munlockall)(long res) {}
+
+PRE_SYSCALL(madvise)(long start, long len, long behavior) {}
+
+POST_SYSCALL(madvise)(long res, long start, long len, long behavior) {}
+
+PRE_SYSCALL(mincore)(long start, long len, void *vec) {}
+
+POST_SYSCALL(mincore)(long res, long start, long len, void *vec) {
+ if (res >= 0) {
+ if (vec) {
+ POST_WRITE(vec, (len + GetPageSizeCached() - 1) / GetPageSizeCached());
}
- if (r) {
- POST_WRITE(r, sizeof(*r));
+ }
+}
+
+PRE_SYSCALL(pivot_root)(const void *new_root, const void *put_old) {
+ if (new_root)
+ PRE_READ(new_root,
+ __sanitizer::internal_strlen((const char *)new_root) + 1);
+ if (put_old)
+ PRE_READ(put_old, __sanitizer::internal_strlen((const char *)put_old) + 1);
+}
+
+POST_SYSCALL(pivot_root)(long res, const void *new_root, const void *put_old) {}
+
+PRE_SYSCALL(chroot)(const void *filename) {
+ if (filename)
+ PRE_READ(filename,
+ __sanitizer::internal_strlen((const char *)filename) + 1);
+}
+
+POST_SYSCALL(chroot)(long res, const void *filename) {}
+
+PRE_SYSCALL(mknod)(const void *filename, long mode, long dev) {
+ if (filename)
+ PRE_READ(filename,
+ __sanitizer::internal_strlen((const char *)filename) + 1);
+}
+
+POST_SYSCALL(mknod)(long res, const void *filename, long mode, long dev) {}
+
+PRE_SYSCALL(link)(const void *oldname, const void *newname) {
+ if (oldname)
+ PRE_READ(oldname, __sanitizer::internal_strlen((const char *)oldname) + 1);
+ if (newname)
+ PRE_READ(newname, __sanitizer::internal_strlen((const char *)newname) + 1);
+}
+
+POST_SYSCALL(link)(long res, const void *oldname, const void *newname) {}
+
+PRE_SYSCALL(symlink)(const void *old, const void *new_) {
+ if (old) PRE_READ(old, __sanitizer::internal_strlen((const char *)old) + 1);
+ if (new_)
+ PRE_READ(new_, __sanitizer::internal_strlen((const char *)new_) + 1);
+}
+
+POST_SYSCALL(symlink)(long res, const void *old, const void *new_) {}
+
+PRE_SYSCALL(unlink)(const void *pathname) {
+ if (pathname)
+ PRE_READ(pathname,
+ __sanitizer::internal_strlen((const char *)pathname) + 1);
+}
+
+POST_SYSCALL(unlink)(long res, const void *pathname) {}
+
+PRE_SYSCALL(rename)(const void *oldname, const void *newname) {
+ if (oldname)
+ PRE_READ(oldname, __sanitizer::internal_strlen((const char *)oldname) + 1);
+ if (newname)
+ PRE_READ(newname, __sanitizer::internal_strlen((const char *)newname) + 1);
+}
+
+POST_SYSCALL(rename)(long res, const void *oldname, const void *newname) {}
+
+PRE_SYSCALL(chmod)(const void *filename, long mode) {
+ if (filename)
+ PRE_READ(filename,
+ __sanitizer::internal_strlen((const char *)filename) + 1);
+}
+
+POST_SYSCALL(chmod)(long res, const void *filename, long mode) {}
+
+PRE_SYSCALL(fchmod)(long fd, long mode) {}
+
+POST_SYSCALL(fchmod)(long res, long fd, long mode) {}
+
+PRE_SYSCALL(fcntl)(long fd, long cmd, long arg) {}
+
+POST_SYSCALL(fcntl)(long res, long fd, long cmd, long arg) {}
+
+PRE_SYSCALL(fcntl64)(long fd, long cmd, long arg) {}
+
+POST_SYSCALL(fcntl64)(long res, long fd, long cmd, long arg) {}
+
+PRE_SYSCALL(pipe)(void *fildes) {}
+
+POST_SYSCALL(pipe)(long res, void *fildes) {
+ if (res >= 0) {
+ if (fildes) POST_WRITE(fildes, sizeof(int));
+ }
+}
+
+PRE_SYSCALL(pipe2)(void *fildes, long flags) {}
+
+POST_SYSCALL(pipe2)(long res, void *fildes, long flags) {
+ if (res >= 0) {
+ if (fildes) POST_WRITE(fildes, sizeof(int));
+ }
+}
+
+PRE_SYSCALL(dup)(long fildes) {}
+
+POST_SYSCALL(dup)(long res, long fildes) {}
+
+PRE_SYSCALL(dup2)(long oldfd, long newfd) {}
+
+POST_SYSCALL(dup2)(long res, long oldfd, long newfd) {}
+
+PRE_SYSCALL(dup3)(long oldfd, long newfd, long flags) {}
+
+POST_SYSCALL(dup3)(long res, long oldfd, long newfd, long flags) {}
+
+PRE_SYSCALL(ioperm)(long from, long num, long on) {}
+
+POST_SYSCALL(ioperm)(long res, long from, long num, long on) {}
+
+PRE_SYSCALL(ioctl)(long fd, long cmd, long arg) {}
+
+POST_SYSCALL(ioctl)(long res, long fd, long cmd, long arg) {}
+
+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) {}
+
+POST_SYSCALL(io_setup)(long res, long nr_reqs, void *ctx) {
+ if (res >= 0) {
+ if (ctx) POST_WRITE(ctx, sizeof(long));
+ }
+}
+
+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) {
+ 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) {
+ if (res >= 0) {
+ if (events) POST_WRITE(events, res * struct_io_event_sz);
+ if (timeout) POST_WRITE(timeout, struct_timespec_sz);
+ }
+}
+
+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);
+ }
+}
+
+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);
}
}
}
-PRE_SYSCALL(waitpid)(int pid, int *status, int options) {
- if (status) {
- PRE_WRITE(status, sizeof(*status));
+PRE_SYSCALL(io_cancel)(long ctx_id, void *iocb, void *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(waitpid)(long res, int pid, int *status, int options) {
- if (res > 0 && status) {
- POST_WRITE(status, sizeof(*status));
+PRE_SYSCALL(sendfile)(long out_fd, long in_fd, void *offset, long count) {}
+
+POST_SYSCALL(sendfile)(long res, long out_fd, long in_fd,
+ __sanitizer___kernel_off_t *offset, long count) {
+ if (res >= 0) {
+ if (offset) POST_WRITE(offset, sizeof(*offset));
}
}
+
+PRE_SYSCALL(sendfile64)(long out_fd, long in_fd, void *offset, long count) {}
+
+POST_SYSCALL(sendfile64)(long res, long out_fd, long in_fd,
+ __sanitizer___kernel_loff_t *offset, long count) {
+ if (res >= 0) {
+ if (offset) POST_WRITE(offset, sizeof(*offset));
+ }
+}
+
+PRE_SYSCALL(readlink)(const void *path, void *buf, long bufsiz) {
+ if (path)
+ PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1);
+}
+
+POST_SYSCALL(readlink)(long res, const void *path, void *buf, long bufsiz) {
+ if (res >= 0) {
+ if (buf)
+ POST_WRITE(buf, __sanitizer::internal_strlen((const char *)buf) + 1);
+ }
+}
+
+PRE_SYSCALL(creat)(const void *pathname, long mode) {
+ if (pathname)
+ PRE_READ(pathname,
+ __sanitizer::internal_strlen((const char *)pathname) + 1);
+}
+
+POST_SYSCALL(creat)(long res, const void *pathname, long mode) {}
+
+PRE_SYSCALL(open)(const void *filename, long flags, long mode) {
+ if (filename)
+ PRE_READ(filename,
+ __sanitizer::internal_strlen((const char *)filename) + 1);
+}
+
+POST_SYSCALL(open)(long res, const void *filename, long flags, long mode) {}
+
+PRE_SYSCALL(close)(long fd) {
+ COMMON_SYSCALL_FD_CLOSE((int)fd);
+}
+
+POST_SYSCALL(close)(long res, long fd) {}
+
+PRE_SYSCALL(access)(const void *filename, long mode) {
+ if (filename)
+ PRE_READ(filename,
+ __sanitizer::internal_strlen((const char *)filename) + 1);
+}
+
+POST_SYSCALL(access)(long res, const void *filename, long mode) {}
+
+PRE_SYSCALL(vhangup)() {}
+
+POST_SYSCALL(vhangup)(long res) {}
+
+PRE_SYSCALL(chown)(const void *filename, long user, long group) {
+ if (filename)
+ PRE_READ(filename,
+ __sanitizer::internal_strlen((const char *)filename) + 1);
+}
+
+POST_SYSCALL(chown)(long res, const void *filename, long user, long group) {}
+
+PRE_SYSCALL(lchown)(const void *filename, long user, long group) {
+ if (filename)
+ PRE_READ(filename,
+ __sanitizer::internal_strlen((const char *)filename) + 1);
+}
+
+POST_SYSCALL(lchown)(long res, const void *filename, long user, long group) {}
+
+PRE_SYSCALL(fchown)(long fd, long user, long group) {}
+
+POST_SYSCALL(fchown)(long res, long fd, long user, long group) {}
+
+PRE_SYSCALL(chown16)(const void *filename, long user, long group) {
+ if (filename)
+ PRE_READ(filename,
+ __sanitizer::internal_strlen((const char *)filename) + 1);
+}
+
+POST_SYSCALL(chown16)(long res, const void *filename, long user, long group) {}
+
+PRE_SYSCALL(lchown16)(const void *filename, long user, long group) {
+ if (filename)
+ PRE_READ(filename,
+ __sanitizer::internal_strlen((const char *)filename) + 1);
+}
+
+POST_SYSCALL(lchown16)(long res, const void *filename, long user, long group) {}
+
+PRE_SYSCALL(fchown16)(long fd, long user, long group) {}
+
+POST_SYSCALL(fchown16)(long res, long fd, long user, long group) {}
+
+PRE_SYSCALL(setregid16)(long rgid, long egid) {}
+
+POST_SYSCALL(setregid16)(long res, long rgid, long egid) {}
+
+PRE_SYSCALL(setgid16)(long gid) {}
+
+POST_SYSCALL(setgid16)(long res, long gid) {}
+
+PRE_SYSCALL(setreuid16)(long ruid, long euid) {}
+
+POST_SYSCALL(setreuid16)(long res, long ruid, long euid) {}
+
+PRE_SYSCALL(setuid16)(long uid) {}
+
+POST_SYSCALL(setuid16)(long res, long uid) {}
+
+PRE_SYSCALL(setresuid16)(long ruid, long euid, long suid) {}
+
+POST_SYSCALL(setresuid16)(long res, long ruid, long euid, long suid) {}
+
+PRE_SYSCALL(getresuid16)(void *ruid, void *euid, void *suid) {}
+
+POST_SYSCALL(getresuid16)(long res, __sanitizer___kernel_old_uid_t *ruid,
+ __sanitizer___kernel_old_uid_t *euid,
+ __sanitizer___kernel_old_uid_t *suid) {
+ if (res >= 0) {
+ if (ruid) POST_WRITE(ruid, sizeof(*ruid));
+ if (euid) POST_WRITE(euid, sizeof(*euid));
+ if (suid) POST_WRITE(suid, sizeof(*suid));
+ }
+}
+
+PRE_SYSCALL(setresgid16)(long rgid, long egid, long sgid) {}
+
+POST_SYSCALL(setresgid16)(long res, long rgid, long egid, long sgid) {}
+
+PRE_SYSCALL(getresgid16)(void *rgid, void *egid, void *sgid) {}
+
+POST_SYSCALL(getresgid16)(long res, __sanitizer___kernel_old_gid_t *rgid,
+ __sanitizer___kernel_old_gid_t *egid,
+ __sanitizer___kernel_old_gid_t *sgid) {
+ if (res >= 0) {
+ if (rgid) POST_WRITE(rgid, sizeof(*rgid));
+ if (egid) POST_WRITE(egid, sizeof(*egid));
+ if (sgid) POST_WRITE(sgid, sizeof(*sgid));
+ }
+}
+
+PRE_SYSCALL(setfsuid16)(long uid) {}
+
+POST_SYSCALL(setfsuid16)(long res, long uid) {}
+
+PRE_SYSCALL(setfsgid16)(long gid) {}
+
+POST_SYSCALL(setfsgid16)(long res, long gid) {}
+
+PRE_SYSCALL(getgroups16)(long gidsetsize,
+ __sanitizer___kernel_old_gid_t *grouplist) {}
+
+POST_SYSCALL(getgroups16)(long res, long gidsetsize,
+ __sanitizer___kernel_old_gid_t *grouplist) {
+ if (res >= 0) {
+ if (grouplist) POST_WRITE(grouplist, res * sizeof(*grouplist));
+ }
+}
+
+PRE_SYSCALL(setgroups16)(long gidsetsize,
+ __sanitizer___kernel_old_gid_t *grouplist) {
+ if (grouplist) POST_WRITE(grouplist, gidsetsize * sizeof(*grouplist));
+}
+
+POST_SYSCALL(setgroups16)(long res, long gidsetsize,
+ __sanitizer___kernel_old_gid_t *grouplist) {}
+
+PRE_SYSCALL(getuid16)() {}
+
+POST_SYSCALL(getuid16)(long res) {}
+
+PRE_SYSCALL(geteuid16)() {}
+
+POST_SYSCALL(geteuid16)(long res) {}
+
+PRE_SYSCALL(getgid16)() {}
+
+POST_SYSCALL(getgid16)(long res) {}
+
+PRE_SYSCALL(getegid16)() {}
+
+POST_SYSCALL(getegid16)(long res) {}
+
+PRE_SYSCALL(utime)(void *filename, void *times) {}
+
+POST_SYSCALL(utime)(long res, void *filename, void *times) {
+ if (res >= 0) {
+ if (filename)
+ POST_WRITE(filename,
+ __sanitizer::internal_strlen((const char *)filename) + 1);
+ if (times) POST_WRITE(times, struct_utimbuf_sz);
+ }
+}
+
+PRE_SYSCALL(utimes)(void *filename, void *utimes) {}
+
+POST_SYSCALL(utimes)(long res, void *filename, void *utimes) {
+ if (res >= 0) {
+ if (filename)
+ POST_WRITE(filename,
+ __sanitizer::internal_strlen((const char *)filename) + 1);
+ if (utimes) POST_WRITE(utimes, timeval_sz);
+ }
+}
+
+PRE_SYSCALL(lseek)(long fd, long offset, long origin) {}
+
+POST_SYSCALL(lseek)(long res, long fd, long offset, long origin) {}
+
+PRE_SYSCALL(llseek)(long fd, long offset_high, long offset_low, void *result,
+ long origin) {}
+
+POST_SYSCALL(llseek)(long res, long fd, long offset_high, long offset_low,
+ void *result, long origin) {
+ if (res >= 0) {
+ if (result) POST_WRITE(result, sizeof(long long));
+ }
+}
+
+PRE_SYSCALL(readv)(long fd, const __sanitizer_iovec *vec, long vlen) {}
+
+POST_SYSCALL(readv)(long res, long fd, const __sanitizer_iovec *vec,
+ long vlen) {
+ if (res >= 0) {
+ if (vec) kernel_write_iovec(vec, vlen, res);
+ }
+}
+
+PRE_SYSCALL(write)(long fd, const void *buf, long count) {
+ if (buf) PRE_READ(buf, count);
+}
+
+POST_SYSCALL(write)(long res, long fd, const void *buf, long count) {}
+
+PRE_SYSCALL(writev)(long fd, const __sanitizer_iovec *vec, long vlen) {}
+
+POST_SYSCALL(writev)(long res, long fd, const __sanitizer_iovec *vec,
+ long vlen) {
+ if (res >= 0) {
+ if (vec) kernel_read_iovec(vec, vlen, res);
+ }
+}
+
+#ifdef _LP64
+PRE_SYSCALL(pread64)(long fd, void *buf, long count, long pos) {}
+
+POST_SYSCALL(pread64)(long res, long fd, void *buf, long count, long pos) {
+ if (res >= 0) {
+ if (buf) POST_WRITE(buf, res);
+ }
+}
+
+PRE_SYSCALL(pwrite64)(long fd, const void *buf, long count, long pos) {
+ if (buf) PRE_READ(buf, count);
+}
+
+POST_SYSCALL(pwrite64)(long res, long fd, const void *buf, long count,
+ long pos) {}
+#else
+PRE_SYSCALL(pread64)(long fd, void *buf, long count, long pos0, long pos1) {}
+
+POST_SYSCALL(pread64)(long res, long fd, void *buf, long count, long pos0,
+ long pos1) {
+ if (res >= 0) {
+ if (buf) POST_WRITE(buf, res);
+ }
+}
+
+PRE_SYSCALL(pwrite64)(long fd, const void *buf, long count, long pos0,
+ long pos1) {
+ if (buf) PRE_READ(buf, count);
+}
+
+POST_SYSCALL(pwrite64)(long res, long fd, const void *buf, long count,
+ long pos0, long pos1) {}
+#endif
+
+PRE_SYSCALL(preadv)(long fd, const __sanitizer_iovec *vec, long vlen,
+ long pos_l, long pos_h) {}
+
+POST_SYSCALL(preadv)(long res, long fd, const __sanitizer_iovec *vec, long vlen,
+ long pos_l, long pos_h) {
+ if (res >= 0) {
+ if (vec) kernel_write_iovec(vec, vlen, res);
+ }
+}
+
+PRE_SYSCALL(pwritev)(long fd, const __sanitizer_iovec *vec, long vlen,
+ long pos_l, long pos_h) {}
+
+POST_SYSCALL(pwritev)(long res, long fd, const __sanitizer_iovec *vec,
+ long vlen, long pos_l, long pos_h) {
+ if (res >= 0) {
+ if (vec) kernel_read_iovec(vec, vlen, res);
+ }
+}
+
+PRE_SYSCALL(getcwd)(void *buf, long size) {}
+
+POST_SYSCALL(getcwd)(long res, void *buf, long size) {
+ if (res >= 0) {
+ if (buf)
+ POST_WRITE(buf, __sanitizer::internal_strlen((const char *)buf) + 1);
+ }
+}
+
+PRE_SYSCALL(mkdir)(const void *pathname, long mode) {
+ if (pathname)
+ PRE_READ(pathname,
+ __sanitizer::internal_strlen((const char *)pathname) + 1);
+}
+
+POST_SYSCALL(mkdir)(long res, const void *pathname, long mode) {}
+
+PRE_SYSCALL(chdir)(const void *filename) {
+ if (filename)
+ PRE_READ(filename,
+ __sanitizer::internal_strlen((const char *)filename) + 1);
+}
+
+POST_SYSCALL(chdir)(long res, const void *filename) {}
+
+PRE_SYSCALL(fchdir)(long fd) {}
+
+POST_SYSCALL(fchdir)(long res, long fd) {}
+
+PRE_SYSCALL(rmdir)(const void *pathname) {
+ if (pathname)
+ PRE_READ(pathname,
+ __sanitizer::internal_strlen((const char *)pathname) + 1);
+}
+
+POST_SYSCALL(rmdir)(long res, const void *pathname) {}
+
+PRE_SYSCALL(lookup_dcookie)(u64 cookie64, void *buf, long len) {}
+
+POST_SYSCALL(lookup_dcookie)(long res, u64 cookie64, void *buf, long len) {
+ if (res >= 0) {
+ if (buf)
+ POST_WRITE(buf, __sanitizer::internal_strlen((const char *)buf) + 1);
+ }
+}
+
+PRE_SYSCALL(quotactl)(long cmd, const void *special, long id, void *addr) {
+ if (special)
+ PRE_READ(special, __sanitizer::internal_strlen((const char *)special) + 1);
+}
+
+POST_SYSCALL(quotactl)(long res, long cmd, const void *special, long id,
+ void *addr) {}
+
+PRE_SYSCALL(getdents)(long fd, void *dirent, long count) {}
+
+POST_SYSCALL(getdents)(long res, long fd, void *dirent, long count) {
+ if (res >= 0) {
+ if (dirent) POST_WRITE(dirent, res);
+ }
+}
+
+PRE_SYSCALL(getdents64)(long fd, void *dirent, long count) {}
+
+POST_SYSCALL(getdents64)(long res, long fd, void *dirent, long count) {
+ if (res >= 0) {
+ if (dirent) POST_WRITE(dirent, res);
+ }
+}
+
+PRE_SYSCALL(setsockopt)(long fd, long level, long optname, void *optval,
+ long optlen) {}
+
+POST_SYSCALL(setsockopt)(long res, long fd, long level, long optname,
+ void *optval, long optlen) {
+ if (res >= 0) {
+ if (optval)
+ POST_WRITE(optval,
+ __sanitizer::internal_strlen((const char *)optval) + 1);
+ }
+}
+
+PRE_SYSCALL(getsockopt)(long fd, long level, long optname, void *optval,
+ void *optlen) {}
+
+POST_SYSCALL(getsockopt)(long res, long fd, long level, long optname,
+ void *optval, void *optlen) {
+ if (res >= 0) {
+ if (optval)
+ POST_WRITE(optval,
+ __sanitizer::internal_strlen((const char *)optval) + 1);
+ if (optlen) POST_WRITE(optlen, sizeof(int));
+ }
+}
+
+PRE_SYSCALL(bind)(long arg0, sanitizer_kernel_sockaddr *arg1, long arg2) {}
+
+POST_SYSCALL(bind)(long res, long arg0, sanitizer_kernel_sockaddr *arg1,
+ long arg2) {
+ if (res >= 0) {
+ if (arg1) POST_WRITE(arg1, sizeof(*arg1));
+ }
+}
+
+PRE_SYSCALL(connect)(long arg0, sanitizer_kernel_sockaddr *arg1, long arg2) {}
+
+POST_SYSCALL(connect)(long res, long arg0, sanitizer_kernel_sockaddr *arg1,
+ long arg2) {
+ if (res >= 0) {
+ if (arg1) POST_WRITE(arg1, sizeof(*arg1));
+ }
+}
+
+PRE_SYSCALL(accept)(long arg0, sanitizer_kernel_sockaddr *arg1, void *arg2) {}
+
+POST_SYSCALL(accept)(long res, long arg0, sanitizer_kernel_sockaddr *arg1,
+ void *arg2) {
+ if (res >= 0) {
+ if (arg1) POST_WRITE(arg1, sizeof(*arg1));
+ if (arg2) POST_WRITE(arg2, sizeof(unsigned));
+ }
+}
+
+PRE_SYSCALL(accept4)(long arg0, sanitizer_kernel_sockaddr *arg1, void *arg2,
+ long arg3) {}
+
+POST_SYSCALL(accept4)(long res, long arg0, sanitizer_kernel_sockaddr *arg1,
+ void *arg2, long arg3) {
+ if (res >= 0) {
+ if (arg1) POST_WRITE(arg1, sizeof(*arg1));
+ if (arg2) POST_WRITE(arg2, sizeof(unsigned));
+ }
+}
+
+PRE_SYSCALL(getsockname)(long arg0, sanitizer_kernel_sockaddr *arg1,
+ void *arg2) {}
+
+POST_SYSCALL(getsockname)(long res, long arg0, sanitizer_kernel_sockaddr *arg1,
+ void *arg2) {
+ if (res >= 0) {
+ if (arg1) POST_WRITE(arg1, sizeof(*arg1));
+ if (arg2) POST_WRITE(arg2, sizeof(unsigned));
+ }
+}
+
+PRE_SYSCALL(getpeername)(long arg0, sanitizer_kernel_sockaddr *arg1,
+ void *arg2) {}
+
+POST_SYSCALL(getpeername)(long res, long arg0, sanitizer_kernel_sockaddr *arg1,
+ void *arg2) {
+ if (res >= 0) {
+ if (arg1) POST_WRITE(arg1, sizeof(*arg1));
+ if (arg2) POST_WRITE(arg2, sizeof(unsigned));
+ }
+}
+
+PRE_SYSCALL(send)(long arg0, void *arg1, long arg2, long arg3) {}
+
+POST_SYSCALL(send)(long res, long arg0, void *arg1, long arg2, long arg3) {
+ if (res) {
+ if (arg1) POST_READ(arg1, res);
+ }
+}
+
+PRE_SYSCALL(sendto)(long arg0, void *arg1, long arg2, long arg3,
+ sanitizer_kernel_sockaddr *arg4, long arg5) {}
+
+POST_SYSCALL(sendto)(long res, long arg0, void *arg1, long arg2, long arg3,
+ sanitizer_kernel_sockaddr *arg4, long arg5) {
+ if (res >= 0) {
+ if (arg1) POST_READ(arg1, res);
+ if (arg4) POST_WRITE(arg4, sizeof(*arg4));
+ }
+}
+
+PRE_SYSCALL(sendmsg)(long fd, void *msg, long flags) {}
+
+POST_SYSCALL(sendmsg)(long res, long fd, void *msg, long flags) {
+ // FIXME: POST_READ
+}
+
+PRE_SYSCALL(sendmmsg)(long fd, void *msg, long vlen, long flags) {}
+
+POST_SYSCALL(sendmmsg)(long res, long fd, void *msg, long vlen, long flags) {
+ // FIXME: POST_READ
+}
+
+PRE_SYSCALL(recv)(long arg0, void *buf, long len, long flags) {}
+
+POST_SYSCALL(recv)(long res, void *buf, long len, long flags) {
+ if (res >= 0) {
+ if (buf) POST_WRITE(buf, res);
+ }
+}
+
+PRE_SYSCALL(recvfrom)(long arg0, void *buf, long len, long flags,
+ sanitizer_kernel_sockaddr *arg4, void *arg5) {}
+
+POST_SYSCALL(recvfrom)(long res, long arg0, void *buf, long len, long flags,
+ sanitizer_kernel_sockaddr *arg4, void *arg5) {
+ if (res >= 0) {
+ if (buf) POST_WRITE(buf, res);
+ if (arg4) POST_WRITE(arg4, sizeof(*arg4));
+ if (arg5) POST_WRITE(arg5, sizeof(int));
+ }
+}
+
+PRE_SYSCALL(socket)(long arg0, long arg1, long arg2) {}
+
+POST_SYSCALL(socket)(long res, long arg0, long arg1, long arg2) {}
+
+PRE_SYSCALL(socketpair)(long arg0, long arg1, long arg2, void *arg3) {}
+
+POST_SYSCALL(socketpair)(long res, long arg0, long arg1, long arg2,
+ void *arg3) {
+ if (res >= 0) {
+ if (arg3) POST_WRITE(arg3, sizeof(int));
+ }
+}
+
+PRE_SYSCALL(socketcall)(long call, void *args) {}
+
+POST_SYSCALL(socketcall)(long res, long call, void *args) {
+ if (res >= 0) {
+ if (args) POST_WRITE(args, sizeof(long));
+ }
+}
+
+PRE_SYSCALL(listen)(long arg0, long arg1) {}
+
+POST_SYSCALL(listen)(long res, long arg0, long arg1) {}
+
+PRE_SYSCALL(poll)(void *ufds, long nfds, long timeout) {}
+
+POST_SYSCALL(poll)(long res, __sanitizer_pollfd *ufds, long nfds,
+ long timeout) {
+ if (res >= 0) {
+ if (ufds) POST_WRITE(ufds, nfds * sizeof(*ufds));
+ }
+}
+
+PRE_SYSCALL(select)(long n, __sanitizer___kernel_fd_set *inp,
+ __sanitizer___kernel_fd_set *outp,
+ __sanitizer___kernel_fd_set *exp, void *tvp) {}
+
+POST_SYSCALL(select)(long res, long n, __sanitizer___kernel_fd_set *inp,
+ __sanitizer___kernel_fd_set *outp,
+ __sanitizer___kernel_fd_set *exp, void *tvp) {
+ if (res >= 0) {
+ if (inp) POST_WRITE(inp, sizeof(*inp));
+ if (outp) POST_WRITE(outp, sizeof(*outp));
+ if (exp) POST_WRITE(exp, sizeof(*exp));
+ if (tvp) POST_WRITE(tvp, timeval_sz);
+ }
+}
+
+PRE_SYSCALL(old_select)(void *arg) {}
+
+POST_SYSCALL(old_select)(long res, void *arg) {}
+
+PRE_SYSCALL(epoll_create)(long size) {}
+
+POST_SYSCALL(epoll_create)(long res, long size) {}
+
+PRE_SYSCALL(epoll_create1)(long flags) {}
+
+POST_SYSCALL(epoll_create1)(long res, long flags) {}
+
+PRE_SYSCALL(epoll_ctl)(long epfd, long op, long fd, void *event) {}
+
+POST_SYSCALL(epoll_ctl)(long res, long epfd, long op, long fd, void *event) {
+ if (res >= 0) {
+ if (event) POST_WRITE(event, struct_epoll_event_sz);
+ }
+}
+
+PRE_SYSCALL(epoll_wait)(long epfd, void *events, long maxevents, long timeout) {
+}
+
+POST_SYSCALL(epoll_wait)(long res, long epfd, void *events, long maxevents,
+ long timeout) {
+ if (res >= 0) {
+ if (events) POST_WRITE(events, struct_epoll_event_sz);
+ }
+}
+
+PRE_SYSCALL(epoll_pwait)(long epfd, void *events, long maxevents, long timeout,
+ const kernel_sigset_t *sigmask, long sigsetsize) {
+ if (sigmask) PRE_READ(sigmask, sigsetsize);
+}
+
+POST_SYSCALL(epoll_pwait)(long res, long epfd, void *events, long maxevents,
+ long timeout, const void *sigmask, long sigsetsize) {
+ if (res >= 0) {
+ if (events) POST_WRITE(events, struct_epoll_event_sz);
+ }
+}
+
+PRE_SYSCALL(gethostname)(void *name, long len) {}
+
+POST_SYSCALL(gethostname)(long res, void *name, long len) {
+ if (res >= 0) {
+ if (name)
+ POST_WRITE(name, __sanitizer::internal_strlen((const char *)name) + 1);
+ }
+}
+
+PRE_SYSCALL(sethostname)(void *name, long len) {}
+
+POST_SYSCALL(sethostname)(long res, void *name, long len) {
+ if (res >= 0) {
+ if (name)
+ POST_WRITE(name, __sanitizer::internal_strlen((const char *)name) + 1);
+ }
+}
+
+PRE_SYSCALL(setdomainname)(void *name, long len) {}
+
+POST_SYSCALL(setdomainname)(long res, void *name, long len) {
+ if (res >= 0) {
+ if (name)
+ POST_WRITE(name, __sanitizer::internal_strlen((const char *)name) + 1);
+ }
+}
+
+PRE_SYSCALL(newuname)(void *name) {}
+
+POST_SYSCALL(newuname)(long res, void *name) {
+ if (res >= 0) {
+ if (name) POST_WRITE(name, struct_new_utsname_sz);
+ }
+}
+
+PRE_SYSCALL(uname)(void *arg0) {}
+
+POST_SYSCALL(uname)(long res, void *arg0) {
+ if (res >= 0) {
+ if (arg0) POST_WRITE(arg0, struct_old_utsname_sz);
+ }
+}
+
+PRE_SYSCALL(olduname)(void *arg0) {}
+
+POST_SYSCALL(olduname)(long res, void *arg0) {
+ if (res >= 0) {
+ if (arg0) POST_WRITE(arg0, struct_oldold_utsname_sz);
+ }
+}
+
+PRE_SYSCALL(getrlimit)(long resource, void *rlim) {}
+
+POST_SYSCALL(getrlimit)(long res, long resource, void *rlim) {
+ if (res >= 0) {
+ if (rlim) POST_WRITE(rlim, struct_rlimit_sz);
+ }
+}
+
+PRE_SYSCALL(old_getrlimit)(long resource, void *rlim) {}
+
+POST_SYSCALL(old_getrlimit)(long res, long resource, void *rlim) {
+ if (res >= 0) {
+ if (rlim) POST_WRITE(rlim, struct_rlimit_sz);
+ }
+}
+
+PRE_SYSCALL(setrlimit)(long resource, void *rlim) {}
+
+POST_SYSCALL(setrlimit)(long res, long resource, void *rlim) {
+ if (res >= 0) {
+ if (rlim) POST_WRITE(rlim, struct_rlimit_sz);
+ }
+}
+
+#if !SANITIZER_ANDROID
+PRE_SYSCALL(prlimit64)(long pid, long resource, const void *new_rlim,
+ void *old_rlim) {
+ if (new_rlim) PRE_READ(new_rlim, struct_rlimit64_sz);
+}
+
+POST_SYSCALL(prlimit64)(long res, long pid, long resource, const void *new_rlim,
+ void *old_rlim) {
+ if (res >= 0) {
+ if (old_rlim) POST_WRITE(old_rlim, struct_rlimit64_sz);
+ }
+}
+#endif
+
+PRE_SYSCALL(getrusage)(long who, void *ru) {}
+
+POST_SYSCALL(getrusage)(long res, long who, void *ru) {
+ if (res >= 0) {
+ if (ru) POST_WRITE(ru, struct_rusage_sz);
+ }
+}
+
+PRE_SYSCALL(umask)(long mask) {}
+
+POST_SYSCALL(umask)(long res, long mask) {}
+
+PRE_SYSCALL(msgget)(long key, long msgflg) {}
+
+POST_SYSCALL(msgget)(long res, long key, long msgflg) {}
+
+PRE_SYSCALL(msgsnd)(long msqid, void *msgp, long msgsz, long msgflg) {
+ if (msgp) PRE_READ(msgp, msgsz);
+}
+
+POST_SYSCALL(msgsnd)(long res, long msqid, void *msgp, long msgsz,
+ long msgflg) {}
+
+PRE_SYSCALL(msgrcv)(long msqid, void *msgp, long msgsz, long msgtyp,
+ long msgflg) {}
+
+POST_SYSCALL(msgrcv)(long res, long msqid, void *msgp, long msgsz, long msgtyp,
+ long msgflg) {
+ if (res >= 0) {
+ if (msgp) POST_WRITE(msgp, res);
+ }
+}
+
+PRE_SYSCALL(msgctl)(long msqid, long cmd, void *buf) {}
+
+POST_SYSCALL(msgctl)(long res, long msqid, long cmd, void *buf) {
+ if (res >= 0) {
+ if (buf) POST_WRITE(buf, struct_msqid_ds_sz);
+ }
+}
+
+PRE_SYSCALL(semget)(long key, long nsems, long semflg) {}
+
+POST_SYSCALL(semget)(long res, long key, long nsems, long semflg) {}
+
+PRE_SYSCALL(semop)(long semid, void *sops, long nsops) {}
+
+POST_SYSCALL(semop)(long res, long semid, void *sops, long nsops) {}
+
+PRE_SYSCALL(semctl)(long semid, long semnum, long cmd, void *arg) {}
+
+POST_SYSCALL(semctl)(long res, long semid, long semnum, long cmd, void *arg) {}
+
+PRE_SYSCALL(semtimedop)(long semid, void *sops, long nsops,
+ const void *timeout) {
+ if (timeout) PRE_READ(timeout, struct_timespec_sz);
+}
+
+POST_SYSCALL(semtimedop)(long res, long semid, void *sops, long nsops,
+ const void *timeout) {}
+
+PRE_SYSCALL(shmat)(long shmid, void *shmaddr, long shmflg) {}
+
+POST_SYSCALL(shmat)(long res, long shmid, void *shmaddr, long shmflg) {
+ if (res >= 0) {
+ if (shmaddr)
+ POST_WRITE(shmaddr,
+ __sanitizer::internal_strlen((const char *)shmaddr) + 1);
+ }
+}
+
+PRE_SYSCALL(shmget)(long key, long size, long flag) {}
+
+POST_SYSCALL(shmget)(long res, long key, long size, long flag) {}
+
+PRE_SYSCALL(shmdt)(void *shmaddr) {}
+
+POST_SYSCALL(shmdt)(long res, void *shmaddr) {
+ if (res >= 0) {
+ if (shmaddr)
+ POST_WRITE(shmaddr,
+ __sanitizer::internal_strlen((const char *)shmaddr) + 1);
+ }
+}
+
+PRE_SYSCALL(ipc)(long call, long first, long second, long third, void *ptr,
+ long fifth) {}
+
+POST_SYSCALL(ipc)(long res, long call, long first, long second, long third,
+ void *ptr, long fifth) {}
+
+#if !SANITIZER_ANDROID
+PRE_SYSCALL(shmctl)(long shmid, long cmd, void *buf) {}
+
+POST_SYSCALL(shmctl)(long res, long shmid, long cmd, void *buf) {
+ if (res >= 0) {
+ if (buf) POST_WRITE(buf, sizeof(__sanitizer_shmid_ds));
+ }
+}
+
+PRE_SYSCALL(mq_open)(const void *name, long oflag, long mode, void *attr) {
+ if (name)
+ PRE_READ(name, __sanitizer::internal_strlen((const char *)name) + 1);
+}
+
+POST_SYSCALL(mq_open)(long res, const void *name, long oflag, long mode,
+ void *attr) {
+ if (res >= 0) {
+ if (attr) POST_WRITE(attr, struct_mq_attr_sz);
+ }
+}
+
+PRE_SYSCALL(mq_unlink)(const void *name) {
+ if (name)
+ PRE_READ(name, __sanitizer::internal_strlen((const char *)name) + 1);
+}
+
+POST_SYSCALL(mq_unlink)(long res, const void *name) {}
+
+PRE_SYSCALL(mq_timedsend)(long mqdes, const void *msg_ptr, long msg_len,
+ long msg_prio, const void *abs_timeout) {
+ if (msg_ptr) PRE_READ(msg_ptr, msg_len);
+ if (abs_timeout) PRE_READ(abs_timeout, struct_timespec_sz);
+}
+
+POST_SYSCALL(mq_timedsend)(long res, long mqdes, const void *msg_ptr,
+ long msg_len, long msg_prio,
+ const void *abs_timeout) {}
+
+PRE_SYSCALL(mq_timedreceive)(long mqdes, void *msg_ptr, long msg_len,
+ void *msg_prio, const void *abs_timeout) {
+ if (abs_timeout) PRE_READ(abs_timeout, struct_timespec_sz);
+}
+
+POST_SYSCALL(mq_timedreceive)(long res, long mqdes, void *msg_ptr, long msg_len,
+ int *msg_prio, const void *abs_timeout) {
+ if (res >= 0) {
+ if (msg_ptr) POST_WRITE(msg_ptr, res);
+ if (msg_prio) POST_WRITE(msg_prio, sizeof(*msg_prio));
+ }
+}
+
+PRE_SYSCALL(mq_notify)(long mqdes, const void *notification) {
+ if (notification) PRE_READ(notification, struct_sigevent_sz);
+}
+
+POST_SYSCALL(mq_notify)(long res, long mqdes, const void *notification) {}
+
+PRE_SYSCALL(mq_getsetattr)(long mqdes, const void *mqstat, void *omqstat) {
+ if (mqstat) PRE_READ(mqstat, struct_mq_attr_sz);
+}
+
+POST_SYSCALL(mq_getsetattr)(long res, long mqdes, const void *mqstat,
+ void *omqstat) {
+ if (res >= 0) {
+ if (omqstat) POST_WRITE(omqstat, struct_mq_attr_sz);
+ }
+}
+#endif // SANITIZER_ANDROID
+
+PRE_SYSCALL(pciconfig_iobase)(long which, long bus, long devfn) {}
+
+POST_SYSCALL(pciconfig_iobase)(long res, long which, long bus, long devfn) {}
+
+PRE_SYSCALL(pciconfig_read)(long bus, long dfn, long off, long len, void *buf) {
+}
+
+POST_SYSCALL(pciconfig_read)(long res, long bus, long dfn, long off, long len,
+ void *buf) {}
+
+PRE_SYSCALL(pciconfig_write)(long bus, long dfn, long off, long len,
+ void *buf) {}
+
+POST_SYSCALL(pciconfig_write)(long res, long bus, long dfn, long off, long len,
+ void *buf) {}
+
+PRE_SYSCALL(swapon)(const void *specialfile, long swap_flags) {
+ if (specialfile)
+ PRE_READ(specialfile,
+ __sanitizer::internal_strlen((const char *)specialfile) + 1);
+}
+
+POST_SYSCALL(swapon)(long res, const void *specialfile, long swap_flags) {}
+
+PRE_SYSCALL(swapoff)(const void *specialfile) {
+ if (specialfile)
+ PRE_READ(specialfile,
+ __sanitizer::internal_strlen((const char *)specialfile) + 1);
+}
+
+POST_SYSCALL(swapoff)(long res, const void *specialfile) {}
+
+PRE_SYSCALL(sysctl)(__sanitizer___sysctl_args *args) {
+ if (args) {
+ if (args->name) PRE_READ(args->name, args->nlen * sizeof(*args->name));
+ if (args->newval) PRE_READ(args->name, args->newlen);
+ }
+}
+
+POST_SYSCALL(sysctl)(long res, __sanitizer___sysctl_args *args) {
+ if (res >= 0) {
+ if (args && args->oldval && args->oldlenp) {
+ POST_WRITE(args->oldlenp, sizeof(*args->oldlenp));
+ POST_WRITE(args->oldval, *args->oldlenp);
+ }
+ }
+}
+
+PRE_SYSCALL(sysinfo)(void *info) {}
+
+POST_SYSCALL(sysinfo)(long res, void *info) {
+ if (res >= 0) {
+ if (info) POST_WRITE(info, struct_sysinfo_sz);
+ }
+}
+
+PRE_SYSCALL(sysfs)(long option, long arg1, long arg2) {}
+
+POST_SYSCALL(sysfs)(long res, long option, long arg1, long arg2) {}
+
+PRE_SYSCALL(syslog)(long type, void *buf, long len) {}
+
+POST_SYSCALL(syslog)(long res, long type, void *buf, long len) {
+ if (res >= 0) {
+ if (buf)
+ POST_WRITE(buf, __sanitizer::internal_strlen((const char *)buf) + 1);
+ }
+}
+
+PRE_SYSCALL(uselib)(const void *library) {
+ if (library)
+ PRE_READ(library, __sanitizer::internal_strlen((const char *)library) + 1);
+}
+
+POST_SYSCALL(uselib)(long res, const void *library) {}
+
+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 (data) {
+ if (request == ptrace_setregs) {
+ PRE_READ((void *)data, struct_user_regs_struct_sz);
+ } else if (request == ptrace_setfpregs) {
+ PRE_READ((void *)data, struct_user_fpregs_struct_sz);
+ } else if (request == ptrace_setfpxregs) {
+ PRE_READ((void *)data, struct_user_fpxregs_struct_sz);
+ } else if (request == ptrace_setsiginfo) {
+ PRE_READ((void *)data, siginfo_t_sz);
+ } else if (request == ptrace_setregset) {
+ __sanitizer_iovec *iov = (__sanitizer_iovec *)data;
+ PRE_READ(iov->iov_base, iov->iov_len);
+ }
+ }
+#endif
+}
+
+POST_SYSCALL(ptrace)(long res, long request, long pid, long addr, long data) {
+#if defined(__i386) || defined (__x86_64)
+ if (res >= 0 && data) {
+ // Note that this is different from the interceptor in
+ // sanitizer_common_interceptors.inc.
+ // PEEK* requests return resulting values through data pointer.
+ if (request == ptrace_getregs) {
+ POST_WRITE((void *)data, struct_user_regs_struct_sz);
+ } else if (request == ptrace_getfpregs) {
+ POST_WRITE((void *)data, struct_user_fpregs_struct_sz);
+ } else if (request == ptrace_getfpxregs) {
+ POST_WRITE((void *)data, struct_user_fpxregs_struct_sz);
+ } else if (request == ptrace_getsiginfo) {
+ POST_WRITE((void *)data, siginfo_t_sz);
+ } else if (request == ptrace_getregset) {
+ __sanitizer_iovec *iov = (__sanitizer_iovec *)data;
+ POST_WRITE(iov->iov_base, iov->iov_len);
+ } else if (request == ptrace_peekdata || request == ptrace_peektext ||
+ request == ptrace_peekuser) {
+ POST_WRITE((void *)data, sizeof(void *));
+ }
+ }
+#endif
+}
+
+PRE_SYSCALL(add_key)(const void *_type, const void *_description,
+ const void *_payload, long plen, long destringid) {
+ if (_type)
+ PRE_READ(_type, __sanitizer::internal_strlen((const char *)_type) + 1);
+ if (_description)
+ PRE_READ(_description,
+ __sanitizer::internal_strlen((const char *)_description) + 1);
+}
+
+POST_SYSCALL(add_key)(long res, const void *_type, const void *_description,
+ const void *_payload, long plen, long destringid) {}
+
+PRE_SYSCALL(request_key)(const void *_type, const void *_description,
+ const void *_callout_info, long destringid) {
+ if (_type)
+ PRE_READ(_type, __sanitizer::internal_strlen((const char *)_type) + 1);
+ if (_description)
+ PRE_READ(_description,
+ __sanitizer::internal_strlen((const char *)_description) + 1);
+ if (_callout_info)
+ PRE_READ(_callout_info,
+ __sanitizer::internal_strlen((const char *)_callout_info) + 1);
+}
+
+POST_SYSCALL(request_key)(long res, const void *_type, const void *_description,
+ const void *_callout_info, long destringid) {}
+
+PRE_SYSCALL(keyctl)(long cmd, long arg2, long arg3, long arg4, long arg5) {}
+
+POST_SYSCALL(keyctl)(long res, long cmd, long arg2, long arg3, long arg4,
+ long arg5) {}
+
+PRE_SYSCALL(ioprio_set)(long which, long who, long ioprio) {}
+
+POST_SYSCALL(ioprio_set)(long res, long which, long who, long ioprio) {}
+
+PRE_SYSCALL(ioprio_get)(long which, long who) {}
+
+POST_SYSCALL(ioprio_get)(long res, long which, long who) {}
+
+PRE_SYSCALL(set_mempolicy)(long mode, void *nmask, long maxnode) {}
+
+POST_SYSCALL(set_mempolicy)(long res, long mode, void *nmask, long maxnode) {
+ if (res >= 0) {
+ if (nmask) POST_WRITE(nmask, sizeof(long));
+ }
+}
+
+PRE_SYSCALL(migrate_pages)(long pid, long maxnode, const void *from,
+ const void *to) {
+ if (from) PRE_READ(from, sizeof(long));
+ if (to) PRE_READ(to, sizeof(long));
+}
+
+POST_SYSCALL(migrate_pages)(long res, long pid, long maxnode, const void *from,
+ const void *to) {}
+
+PRE_SYSCALL(move_pages)(long pid, long nr_pages, const void **pages,
+ const int *nodes, int *status, long flags) {
+ if (pages) PRE_READ(pages, nr_pages * sizeof(*pages));
+ if (nodes) PRE_READ(nodes, nr_pages * sizeof(*nodes));
+}
+
+POST_SYSCALL(move_pages)(long res, long pid, long nr_pages, const void **pages,
+ const int *nodes, int *status, long flags) {
+ if (res >= 0) {
+ if (status) POST_WRITE(status, nr_pages * sizeof(*status));
+ }
+}
+
+PRE_SYSCALL(mbind)(long start, long len, long mode, void *nmask, long maxnode,
+ long flags) {}
+
+POST_SYSCALL(mbind)(long res, long start, long len, long mode, void *nmask,
+ long maxnode, long flags) {
+ if (res >= 0) {
+ if (nmask) POST_WRITE(nmask, sizeof(long));
+ }
+}
+
+PRE_SYSCALL(get_mempolicy)(void *policy, void *nmask, long maxnode, long addr,
+ long flags) {}
+
+POST_SYSCALL(get_mempolicy)(long res, void *policy, void *nmask, long maxnode,
+ long addr, long flags) {
+ if (res >= 0) {
+ if (policy) POST_WRITE(policy, sizeof(int));
+ if (nmask) POST_WRITE(nmask, sizeof(long));
+ }
+}
+
+PRE_SYSCALL(inotify_init)() {}
+
+POST_SYSCALL(inotify_init)(long res) {}
+
+PRE_SYSCALL(inotify_init1)(long flags) {}
+
+POST_SYSCALL(inotify_init1)(long res, long flags) {}
+
+PRE_SYSCALL(inotify_add_watch)(long fd, const void *path, long mask) {
+ if (path)
+ PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1);
+}
+
+POST_SYSCALL(inotify_add_watch)(long res, long fd, const void *path,
+ long mask) {}
+
+PRE_SYSCALL(inotify_rm_watch)(long fd, long wd) {}
+
+POST_SYSCALL(inotify_rm_watch)(long res, long fd, long wd) {}
+
+PRE_SYSCALL(spu_run)(long fd, void *unpc, void *ustatus) {}
+
+POST_SYSCALL(spu_run)(long res, long fd, unsigned *unpc, unsigned *ustatus) {
+ if (res >= 0) {
+ if (unpc) POST_WRITE(unpc, sizeof(*unpc));
+ if (ustatus) POST_WRITE(ustatus, sizeof(*ustatus));
+ }
+}
+
+PRE_SYSCALL(spu_create)(const void *name, long flags, long mode, long fd) {
+ if (name)
+ PRE_READ(name, __sanitizer::internal_strlen((const char *)name) + 1);
+}
+
+POST_SYSCALL(spu_create)(long res, const void *name, long flags, long mode,
+ long fd) {}
+
+PRE_SYSCALL(mknodat)(long dfd, const void *filename, long mode, long dev) {
+ if (filename)
+ PRE_READ(filename,
+ __sanitizer::internal_strlen((const char *)filename) + 1);
+}
+
+POST_SYSCALL(mknodat)(long res, long dfd, const void *filename, long mode,
+ long dev) {}
+
+PRE_SYSCALL(mkdirat)(long dfd, const void *pathname, long mode) {
+ if (pathname)
+ PRE_READ(pathname,
+ __sanitizer::internal_strlen((const char *)pathname) + 1);
+}
+
+POST_SYSCALL(mkdirat)(long res, long dfd, const void *pathname, long mode) {}
+
+PRE_SYSCALL(unlinkat)(long dfd, const void *pathname, long flag) {
+ if (pathname)
+ PRE_READ(pathname,
+ __sanitizer::internal_strlen((const char *)pathname) + 1);
+}
+
+POST_SYSCALL(unlinkat)(long res, long dfd, const void *pathname, long flag) {}
+
+PRE_SYSCALL(symlinkat)(const void *oldname, long newdfd, const void *newname) {
+ if (oldname)
+ PRE_READ(oldname, __sanitizer::internal_strlen((const char *)oldname) + 1);
+ if (newname)
+ PRE_READ(newname, __sanitizer::internal_strlen((const char *)newname) + 1);
+}
+
+POST_SYSCALL(symlinkat)(long res, const void *oldname, long newdfd,
+ const void *newname) {}
+
+PRE_SYSCALL(linkat)(long olddfd, const void *oldname, long newdfd,
+ const void *newname, long flags) {
+ if (oldname)
+ PRE_READ(oldname, __sanitizer::internal_strlen((const char *)oldname) + 1);
+ if (newname)
+ PRE_READ(newname, __sanitizer::internal_strlen((const char *)newname) + 1);
+}
+
+POST_SYSCALL(linkat)(long res, long olddfd, const void *oldname, long newdfd,
+ const void *newname, long flags) {}
+
+PRE_SYSCALL(renameat)(long olddfd, const void *oldname, long newdfd,
+ const void *newname) {
+ if (oldname)
+ PRE_READ(oldname, __sanitizer::internal_strlen((const char *)oldname) + 1);
+ if (newname)
+ PRE_READ(newname, __sanitizer::internal_strlen((const char *)newname) + 1);
+}
+
+POST_SYSCALL(renameat)(long res, long olddfd, const void *oldname, long newdfd,
+ const void *newname) {}
+
+PRE_SYSCALL(futimesat)(long dfd, const void *filename, void *utimes) {
+ if (filename)
+ PRE_READ(filename,
+ __sanitizer::internal_strlen((const char *)filename) + 1);
+}
+
+POST_SYSCALL(futimesat)(long res, long dfd, const void *filename,
+ void *utimes) {
+ if (res >= 0) {
+ if (utimes) POST_WRITE(utimes, timeval_sz);
+ }
+}
+
+PRE_SYSCALL(faccessat)(long dfd, const void *filename, long mode) {
+ if (filename)
+ PRE_READ(filename,
+ __sanitizer::internal_strlen((const char *)filename) + 1);
+}
+
+POST_SYSCALL(faccessat)(long res, long dfd, const void *filename, long mode) {}
+
+PRE_SYSCALL(fchmodat)(long dfd, const void *filename, long mode) {
+ if (filename)
+ PRE_READ(filename,
+ __sanitizer::internal_strlen((const char *)filename) + 1);
+}
+
+POST_SYSCALL(fchmodat)(long res, long dfd, const void *filename, long mode) {}
+
+PRE_SYSCALL(fchownat)(long dfd, const void *filename, long user, long group,
+ long flag) {
+ if (filename)
+ PRE_READ(filename,
+ __sanitizer::internal_strlen((const char *)filename) + 1);
+}
+
+POST_SYSCALL(fchownat)(long res, long dfd, const void *filename, long user,
+ long group, long flag) {}
+
+PRE_SYSCALL(openat)(long dfd, const void *filename, long flags, long mode) {
+ if (filename)
+ PRE_READ(filename,
+ __sanitizer::internal_strlen((const char *)filename) + 1);
+}
+
+POST_SYSCALL(openat)(long res, long dfd, const void *filename, long flags,
+ long mode) {}
+
+PRE_SYSCALL(newfstatat)(long dfd, const void *filename, void *statbuf,
+ long flag) {
+ if (filename)
+ PRE_READ(filename,
+ __sanitizer::internal_strlen((const char *)filename) + 1);
+}
+
+POST_SYSCALL(newfstatat)(long res, long dfd, const void *filename,
+ void *statbuf, long flag) {
+ if (res >= 0) {
+ if (statbuf) POST_WRITE(statbuf, struct_kernel_stat_sz);
+ }
+}
+
+PRE_SYSCALL(fstatat64)(long dfd, const void *filename, void *statbuf,
+ long flag) {
+ if (filename)
+ PRE_READ(filename,
+ __sanitizer::internal_strlen((const char *)filename) + 1);
+}
+
+POST_SYSCALL(fstatat64)(long res, long dfd, const void *filename, void *statbuf,
+ long flag) {
+ if (res >= 0) {
+ if (statbuf) POST_WRITE(statbuf, struct_kernel_stat64_sz);
+ }
+}
+
+PRE_SYSCALL(readlinkat)(long dfd, const void *path, void *buf, long bufsiz) {
+ if (path)
+ PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1);
+}
+
+POST_SYSCALL(readlinkat)(long res, long dfd, const void *path, void *buf,
+ long bufsiz) {
+ if (res >= 0) {
+ if (buf)
+ POST_WRITE(buf, __sanitizer::internal_strlen((const char *)buf) + 1);
+ }
+}
+
+PRE_SYSCALL(utimensat)(long dfd, const void *filename, void *utimes,
+ long flags) {
+ if (filename)
+ PRE_READ(filename,
+ __sanitizer::internal_strlen((const char *)filename) + 1);
+}
+
+POST_SYSCALL(utimensat)(long res, long dfd, const void *filename, void *utimes,
+ long flags) {
+ if (res >= 0) {
+ if (utimes) POST_WRITE(utimes, struct_timespec_sz);
+ }
+}
+
+PRE_SYSCALL(unshare)(long unshare_flags) {}
+
+POST_SYSCALL(unshare)(long res, long unshare_flags) {}
+
+PRE_SYSCALL(splice)(long fd_in, void *off_in, long fd_out, void *off_out,
+ long len, long flags) {}
+
+POST_SYSCALL(splice)(long res, long fd_in, void *off_in, long fd_out,
+ void *off_out, long len, long flags) {
+ if (res >= 0) {
+ if (off_in) POST_WRITE(off_in, sizeof(long long));
+ if (off_out) POST_WRITE(off_out, sizeof(long long));
+ }
+}
+
+PRE_SYSCALL(vmsplice)(long fd, const __sanitizer_iovec *iov, long nr_segs,
+ long flags) {}
+
+POST_SYSCALL(vmsplice)(long res, long fd, const __sanitizer_iovec *iov,
+ long nr_segs, long flags) {
+ if (res >= 0) {
+ if (iov) kernel_read_iovec(iov, nr_segs, res);
+ }
+}
+
+PRE_SYSCALL(tee)(long fdin, long fdout, long len, long flags) {}
+
+POST_SYSCALL(tee)(long res, long fdin, long fdout, long len, long flags) {}
+
+PRE_SYSCALL(get_robust_list)(long pid, void *head_ptr, void *len_ptr) {}
+
+POST_SYSCALL(get_robust_list)(long res, long pid, void *head_ptr,
+ void *len_ptr) {}
+
+PRE_SYSCALL(set_robust_list)(void *head, long len) {}
+
+POST_SYSCALL(set_robust_list)(long res, void *head, long len) {}
+
+PRE_SYSCALL(getcpu)(void *cpu, void *node, void *cache) {}
+
+POST_SYSCALL(getcpu)(long res, void *cpu, void *node, void *cache) {
+ if (res >= 0) {
+ if (cpu) POST_WRITE(cpu, sizeof(unsigned));
+ if (node) POST_WRITE(node, sizeof(unsigned));
+ // The third argument to this system call is nowadays unused.
+ }
+}
+
+PRE_SYSCALL(signalfd)(long ufd, void *user_mask, long sizemask) {}
+
+POST_SYSCALL(signalfd)(long res, long ufd, kernel_sigset_t *user_mask,
+ long sizemask) {
+ if (res >= 0) {
+ if (user_mask) POST_WRITE(user_mask, sizemask);
+ }
+}
+
+PRE_SYSCALL(signalfd4)(long ufd, void *user_mask, long sizemask, long flags) {}
+
+POST_SYSCALL(signalfd4)(long res, long ufd, kernel_sigset_t *user_mask,
+ long sizemask, long flags) {
+ if (res >= 0) {
+ if (user_mask) POST_WRITE(user_mask, sizemask);
+ }
+}
+
+PRE_SYSCALL(timerfd_create)(long clockid, long flags) {}
+
+POST_SYSCALL(timerfd_create)(long res, long clockid, long flags) {}
+
+PRE_SYSCALL(timerfd_settime)(long ufd, long flags, const void *utmr,
+ void *otmr) {
+ if (utmr) PRE_READ(utmr, struct_itimerspec_sz);
+}
+
+POST_SYSCALL(timerfd_settime)(long res, long ufd, long flags, const void *utmr,
+ void *otmr) {
+ if (res >= 0) {
+ if (otmr) POST_WRITE(otmr, struct_itimerspec_sz);
+ }
+}
+
+PRE_SYSCALL(timerfd_gettime)(long ufd, void *otmr) {}
+
+POST_SYSCALL(timerfd_gettime)(long res, long ufd, void *otmr) {
+ if (res >= 0) {
+ if (otmr) POST_WRITE(otmr, struct_itimerspec_sz);
+ }
+}
+
+PRE_SYSCALL(eventfd)(long count) {}
+
+POST_SYSCALL(eventfd)(long res, long count) {}
+
+PRE_SYSCALL(eventfd2)(long count, long flags) {}
+
+POST_SYSCALL(eventfd2)(long res, long count, long flags) {}
+
+PRE_SYSCALL(old_readdir)(long arg0, void *arg1, long arg2) {}
+
+POST_SYSCALL(old_readdir)(long res, long arg0, void *arg1, long arg2) {
+ // Missing definition of 'struct old_linux_dirent'.
+}
+
+PRE_SYSCALL(pselect6)(long arg0, __sanitizer___kernel_fd_set *arg1,
+ __sanitizer___kernel_fd_set *arg2,
+ __sanitizer___kernel_fd_set *arg3, void *arg4,
+ void *arg5) {}
+
+POST_SYSCALL(pselect6)(long res, long arg0, __sanitizer___kernel_fd_set *arg1,
+ __sanitizer___kernel_fd_set *arg2,
+ __sanitizer___kernel_fd_set *arg3, void *arg4,
+ void *arg5) {
+ if (res >= 0) {
+ if (arg1) POST_WRITE(arg1, sizeof(*arg1));
+ if (arg2) POST_WRITE(arg2, sizeof(*arg2));
+ if (arg3) POST_WRITE(arg3, sizeof(*arg3));
+ if (arg4) POST_WRITE(arg4, struct_timespec_sz);
+ }
+}
+
+PRE_SYSCALL(ppoll)(__sanitizer_pollfd *arg0, long arg1, void *arg2,
+ const kernel_sigset_t *arg3, long arg4) {
+ if (arg3) PRE_READ(arg3, arg4);
+}
+
+POST_SYSCALL(ppoll)(long res, __sanitizer_pollfd *arg0, long arg1, void *arg2,
+ const void *arg3, long arg4) {
+ if (res >= 0) {
+ if (arg0) POST_WRITE(arg0, sizeof(*arg0));
+ if (arg2) POST_WRITE(arg2, struct_timespec_sz);
+ }
+}
+
+PRE_SYSCALL(syncfs)(long fd) {}
+
+POST_SYSCALL(syncfs)(long res, long fd) {}
+
+PRE_SYSCALL(perf_event_open)(__sanitizer_perf_event_attr *attr_uptr, long pid,
+ long cpu, long group_fd, long flags) {
+ if (attr_uptr) PRE_READ(attr_uptr, attr_uptr->size);
+}
+
+POST_SYSCALL(perf_event_open)(long res, __sanitizer_perf_event_attr *attr_uptr,
+ long pid, long cpu, long group_fd, long flags) {}
+
+PRE_SYSCALL(mmap_pgoff)(long addr, long len, long prot, long flags, long fd,
+ long pgoff) {}
+
+POST_SYSCALL(mmap_pgoff)(long res, long addr, long len, long prot, long flags,
+ long fd, long pgoff) {}
+
+PRE_SYSCALL(old_mmap)(void *arg) {}
+
+POST_SYSCALL(old_mmap)(long res, void *arg) {}
+
+PRE_SYSCALL(name_to_handle_at)(long dfd, const void *name, void *handle,
+ void *mnt_id, long flag) {}
+
+POST_SYSCALL(name_to_handle_at)(long res, long dfd, const void *name,
+ void *handle, void *mnt_id, long flag) {}
+
+PRE_SYSCALL(open_by_handle_at)(long mountdirfd, void *handle, long flags) {}
+
+POST_SYSCALL(open_by_handle_at)(long res, long mountdirfd, void *handle,
+ long flags) {}
+
+PRE_SYSCALL(setns)(long fd, long nstype) {}
+
+POST_SYSCALL(setns)(long res, long fd, long nstype) {}
+
+PRE_SYSCALL(process_vm_readv)(long pid, const __sanitizer_iovec *lvec,
+ long liovcnt, const void *rvec, long riovcnt,
+ long flags) {}
+
+POST_SYSCALL(process_vm_readv)(long res, long pid,
+ const __sanitizer_iovec *lvec, long liovcnt,
+ const void *rvec, long riovcnt, long flags) {
+ if (res >= 0) {
+ if (lvec) kernel_write_iovec(lvec, liovcnt, res);
+ }
+}
+
+PRE_SYSCALL(process_vm_writev)(long pid, const __sanitizer_iovec *lvec,
+ long liovcnt, const void *rvec, long riovcnt,
+ long flags) {}
+
+POST_SYSCALL(process_vm_writev)(long res, long pid,
+ const __sanitizer_iovec *lvec, long liovcnt,
+ const void *rvec, long riovcnt, long flags) {
+ if (res >= 0) {
+ if (lvec) kernel_read_iovec(lvec, liovcnt, res);
+ }
+}
+
+PRE_SYSCALL(fork)() {
+ COMMON_SYSCALL_PRE_FORK();
+}
+
+POST_SYSCALL(fork)(long res) {
+ COMMON_SYSCALL_POST_FORK(res);
+}
+
+PRE_SYSCALL(vfork)() {
+ COMMON_SYSCALL_PRE_FORK();
+}
+
+POST_SYSCALL(vfork)(long res) {
+ COMMON_SYSCALL_POST_FORK(res);
+}
} // extern "C"
#undef PRE_SYSCALL
@@ -146,3 +2783,5 @@ POST_SYSCALL(waitpid)(long res, int pid, int *status, int options) {
#undef POST_SYSCALL
#undef POST_READ
#undef POST_WRITE
+
+#endif // SANITIZER_LINUX
diff --git a/lib/sanitizer_common/sanitizer_coverage.cc b/lib/sanitizer_common/sanitizer_coverage.cc
new file mode 100644
index 000000000000..9e7a0f8b95fb
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_coverage.cc
@@ -0,0 +1,113 @@
+//===-- 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_flags.cc b/lib/sanitizer_common/sanitizer_flags.cc
index b7218e5ad212..924ed4bc014f 100644
--- a/lib/sanitizer_common/sanitizer_flags.cc
+++ b/lib/sanitizer_common/sanitizer_flags.cc
@@ -18,15 +18,42 @@
namespace __sanitizer {
-CommonFlags common_flags_dont_use_directly;
+void SetCommonFlagDefaults() {
+ CommonFlags *f = common_flags();
+ f->symbolize = true;
+ f->external_symbolizer_path = "";
+ f->strip_path_prefix = "";
+ 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->leak_check_at_exit = true;
+ f->allocator_may_return_null = false;
+ f->print_summary = true;
+}
void ParseCommonFlagsFromString(const char *str) {
CommonFlags *f = common_flags();
- ParseFlag(str, &f->malloc_context_size, "malloc_context_size");
+ 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->symbolize, "symbolize");
+ 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");
+
+ // Do a sanity check for certain flags.
+ if (f->malloc_context_size < 1)
+ f->malloc_context_size = 1;
}
static bool GetFlagValue(const char *env, const char *name,
@@ -97,7 +124,7 @@ void ParseFlag(const char *env, int *flag, const char *name) {
int value_length;
if (!GetFlagValue(env, name, &value, &value_length))
return;
- *flag = internal_atoll(value);
+ *flag = static_cast<int>(internal_atoll(value));
}
static LowLevelAllocator allocator_for_flags;
diff --git a/lib/sanitizer_common/sanitizer_flags.h b/lib/sanitizer_common/sanitizer_flags.h
index e97ce6a87188..9461dff80330 100644
--- a/lib/sanitizer_common/sanitizer_flags.h
+++ b/lib/sanitizer_common/sanitizer_flags.h
@@ -33,16 +33,34 @@ struct CommonFlags {
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;
};
-extern CommonFlags common_flags_dont_use_directly;
-
inline CommonFlags *common_flags() {
- return &common_flags_dont_use_directly;
+ static CommonFlags f;
+ return &f;
}
+void SetCommonFlagDefaults();
void ParseCommonFlagsFromString(const char *str);
} // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_internal_defs.h b/lib/sanitizer_common/sanitizer_internal_defs.h
index 9a7d374bf5ad..daa724be06f1 100644
--- a/lib/sanitizer_common/sanitizer_internal_defs.h
+++ b/lib/sanitizer_common/sanitizer_internal_defs.h
@@ -15,9 +15,10 @@
#include "sanitizer_platform.h"
+// Only use SANITIZER_*ATTRIBUTE* before the function return type!
#if SANITIZER_WINDOWS
-// FIXME find out what we need on Windows. __declspec(dllexport) ?
-# define SANITIZER_INTERFACE_ATTRIBUTE
+# define SANITIZER_INTERFACE_ATTRIBUTE __declspec(dllexport)
+// FIXME find out what we need on Windows, if anything.
# define SANITIZER_WEAK_ATTRIBUTE
#elif defined(SANITIZER_GO)
# define SANITIZER_INTERFACE_ATTRIBUTE
@@ -33,6 +34,12 @@
# define SANITIZER_SUPPORTS_WEAK_HOOKS 0
#endif
+#if __LP64__ || defined(_WIN64)
+# define SANITIZER_WORDSIZE 64
+#else
+# define SANITIZER_WORDSIZE 32
+#endif
+
// GCC does not understand __has_feature
#if !defined(__has_feature)
# define __has_feature(x) 0
@@ -78,29 +85,37 @@ typedef u64 OFF_T;
typedef uptr OFF_T;
#endif
typedef u64 OFF64_T;
+
+#if (SANITIZER_WORDSIZE == 64) || SANITIZER_MAC
+typedef uptr operator_new_size_type;
+#else
+typedef u32 operator_new_size_type;
+#endif
} // namespace __sanitizer
extern "C" {
// Tell the tools to write their reports to "path.<pid>" instead of stderr.
- void __sanitizer_set_report_path(const char *path)
- SANITIZER_INTERFACE_ATTRIBUTE;
-
- // Tell the tools to write their reports to given file descriptor instead of
- // stderr.
- void __sanitizer_set_report_fd(int fd)
- SANITIZER_INTERFACE_ATTRIBUTE;
+ // The special values are "stdout" and "stderr".
+ 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.
- void __sanitizer_sandbox_on_notify(void *reserved)
- SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
+ SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+ void __sanitizer_sandbox_on_notify(void *reserved);
// This function is called by the tool when it has just finished reporting
// an error. 'error_summary' is a one-line string that summarizes
// the error message. This function can be overridden by the client.
- void __sanitizer_report_error_summary(const char *error_summary)
- SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
+ SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+ 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_annotate_contiguous_container(void *beg, void *end,
+ void *old_mid, void *new_mid);
} // extern "C"
@@ -132,6 +147,8 @@ using namespace __sanitizer; // NOLINT
#else // _MSC_VER
# define ALWAYS_INLINE inline __attribute__((always_inline))
# define ALIAS(x) __attribute__((alias(x)))
+// Please only use the ALIGNED macro before the type.
+// Using ALIGNED after the variable declaration is not portable!
# define ALIGNED(x) __attribute__((aligned(x)))
# define FORMAT(f, a) __attribute__((format(printf, f, a)))
# define NOINLINE __attribute__((noinline))
@@ -150,6 +167,14 @@ using namespace __sanitizer; // NOLINT
# endif
#endif // _MSC_VER
+// Unaligned versions of basic types.
+typedef ALIGNED(1) u16 uu16;
+typedef ALIGNED(1) u32 uu32;
+typedef ALIGNED(1) u64 uu64;
+typedef ALIGNED(1) s16 us16;
+typedef ALIGNED(1) s32 us32;
+typedef ALIGNED(1) s64 us64;
+
#if SANITIZER_WINDOWS
typedef unsigned long DWORD; // NOLINT
typedef DWORD thread_return_t;
@@ -160,15 +185,12 @@ typedef void* thread_return_t;
#endif // _WIN32
typedef thread_return_t (THREAD_CALLING_CONV *thread_callback_t)(void* arg);
-#if __LP64__ || defined(_WIN64)
-# define SANITIZER_WORDSIZE 64
-#else
-# define SANITIZER_WORDSIZE 32
-#endif
-
// NOTE: Functions below must be defined in each run-time.
namespace __sanitizer {
void NORETURN Die();
+
+// FIXME: No, this shouldn't be in the sanitizer interface.
+SANITIZER_INTERFACE_ATTRIBUTE
void NORETURN CheckFailed(const char *file, int line, const char *cond,
u64 v1, u64 v2);
} // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_libc.cc b/lib/sanitizer_common/sanitizer_libc.cc
index 20c03c4474a1..72ddf0fd3fbe 100644
--- a/lib/sanitizer_common/sanitizer_libc.cc
+++ b/lib/sanitizer_common/sanitizer_libc.cc
@@ -10,6 +10,7 @@
// This file is shared between AddressSanitizer and ThreadSanitizer
// run-time libraries. See sanitizer_libc.h for details.
//===----------------------------------------------------------------------===//
+#include "sanitizer_allocator_internal.h"
#include "sanitizer_common.h"
#include "sanitizer_libc.h"
@@ -124,6 +125,13 @@ 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);
+ return res;
+}
+
char *internal_strrchr(const char *s, int c) {
const char *res = 0;
for (uptr i = 0; s[i]; i++) {
@@ -151,8 +159,7 @@ char *internal_strncpy(char *dst, const char *src, uptr n) {
uptr i;
for (i = 0; i < n && src[i]; i++)
dst[i] = src[i];
- for (; i < n; i++)
- dst[i] = '\0';
+ internal_memset(dst + i, '\0', n - i);
return dst;
}
diff --git a/lib/sanitizer_common/sanitizer_libc.h b/lib/sanitizer_common/sanitizer_libc.h
index 82d809a0305a..187a714a3b2b 100644
--- a/lib/sanitizer_common/sanitizer_libc.h
+++ b/lib/sanitizer_common/sanitizer_libc.h
@@ -32,6 +32,7 @@ void *internal_memmove(void *dest, const void *src, 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);
+char *internal_strchrnul(const char *s, int c);
int internal_strcmp(const char *s1, const char *s2);
uptr internal_strcspn(const char *s, const char *reject);
char *internal_strdup(const char *s);
diff --git a/lib/sanitizer_common/sanitizer_libignore.cc b/lib/sanitizer_common/sanitizer_libignore.cc
new file mode 100644
index 000000000000..0f193a130253
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_libignore.cc
@@ -0,0 +1,105 @@
+//===-- sanitizer_libignore.cc --------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_platform.h"
+#if SANITIZER_LINUX
+
+#include "sanitizer_libignore.h"
+#include "sanitizer_flags.h"
+#include "sanitizer_procmaps.h"
+
+namespace __sanitizer {
+
+LibIgnore::LibIgnore(LinkerInitialized) {
+}
+
+void LibIgnore::Init(const SuppressionContext &supp) {
+ BlockingMutexLock lock(&mutex_);
+ CHECK_EQ(count_, 0);
+ const uptr n = supp.SuppressionCount();
+ for (uptr i = 0; i < n; i++) {
+ const Suppression *s = supp.SuppressionAt(i);
+ if (s->type != SuppressionLib)
+ continue;
+ if (count_ >= kMaxLibs) {
+ Report("%s: too many called_from_lib suppressions (max: %d)\n",
+ SanitizerToolName, kMaxLibs);
+ Die();
+ }
+ Lib *lib = &libs_[count_++];
+ lib->templ = internal_strdup(s->templ);
+ lib->name = 0;
+ lib->loaded = false;
+ }
+}
+
+void LibIgnore::OnLibraryLoaded(const char *name) {
+ BlockingMutexLock lock(&mutex_);
+ // Try to match suppressions with symlink target.
+ InternalScopedBuffer<char> buf(4096);
+ if (name != 0 && internal_readlink(name, buf.data(), buf.size() - 1) > 0 &&
+ buf.data()[0]) {
+ for (uptr i = 0; i < count_; i++) {
+ Lib *lib = &libs_[i];
+ if (!lib->loaded && lib->real_name == 0 &&
+ TemplateMatch(lib->templ, name))
+ lib->real_name = internal_strdup(buf.data());
+ }
+ }
+
+ // Scan suppressions list and find newly loaded and unloaded libraries.
+ MemoryMappingLayout proc_maps(/*cache_enabled*/false);
+ InternalScopedBuffer<char> module(4096);
+ for (uptr i = 0; i < count_; i++) {
+ Lib *lib = &libs_[i];
+ bool loaded = false;
+ proc_maps.Reset();
+ uptr b, e, off, prot;
+ while (proc_maps.Next(&b, &e, &off, module.data(), module.size(), &prot)) {
+ if ((prot & MemoryMappingLayout::kProtectionExecute) == 0)
+ continue;
+ if (TemplateMatch(lib->templ, module.data()) ||
+ (lib->real_name != 0 &&
+ internal_strcmp(lib->real_name, module.data()) == 0)) {
+ if (loaded) {
+ Report("%s: called_from_lib suppression '%s' is matched against"
+ " 2 libraries: '%s' and '%s'\n",
+ SanitizerToolName, lib->templ, lib->name, module.data());
+ Die();
+ }
+ 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());
+ lib->loaded = true;
+ lib->name = internal_strdup(module.data());
+ const uptr idx = atomic_load(&loaded_count_, memory_order_relaxed);
+ code_ranges_[idx].begin = b;
+ code_ranges_[idx].end = e;
+ atomic_store(&loaded_count_, idx + 1, memory_order_release);
+ }
+ }
+ if (lib->loaded && !loaded) {
+ Report("%s: library '%s' that was matched against called_from_lib"
+ " suppression '%s' is unloaded\n",
+ SanitizerToolName, lib->name, lib->templ);
+ Die();
+ }
+ }
+}
+
+void LibIgnore::OnLibraryUnloaded() {
+ OnLibraryLoaded(0);
+}
+
+} // namespace __sanitizer
+
+#endif // #if SANITIZER_LINUX
diff --git a/lib/sanitizer_common/sanitizer_libignore.h b/lib/sanitizer_common/sanitizer_libignore.h
new file mode 100644
index 000000000000..8e1d584d8e3c
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_libignore.h
@@ -0,0 +1,84 @@
+//===-- sanitizer_libignore.h -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// LibIgnore allows to ignore all interceptors called from a particular set
+// of dynamic libraries. LibIgnore remembers all "called_from_lib" suppressions
+// from the provided SuppressionContext; finds code ranges for the libraries;
+// and checks whether the provided PC value belongs to the code ranges.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_LIBIGNORE_H
+#define SANITIZER_LIBIGNORE_H
+
+#include "sanitizer_internal_defs.h"
+#include "sanitizer_common.h"
+#include "sanitizer_suppressions.h"
+#include "sanitizer_atomic.h"
+#include "sanitizer_mutex.h"
+
+namespace __sanitizer {
+
+class LibIgnore {
+ public:
+ explicit LibIgnore(LinkerInitialized);
+
+ // Fetches all "called_from_lib" suppressions from the SuppressionContext.
+ void Init(const SuppressionContext &supp);
+
+ // Must be called after a new dynamic library is loaded.
+ void OnLibraryLoaded(const char *name);
+
+ // Must be called after a dynamic library is unloaded.
+ void OnLibraryUnloaded();
+
+ // Checks whether the provided PC belongs to one of the ignored libraries.
+ bool IsIgnored(uptr pc) const;
+
+ private:
+ struct Lib {
+ char *templ;
+ char *name;
+ char *real_name; // target of symlink
+ bool loaded;
+ };
+
+ struct LibCodeRange {
+ uptr begin;
+ uptr end;
+ };
+
+ static const uptr kMaxLibs = 128;
+
+ // Hot part:
+ atomic_uintptr_t loaded_count_;
+ LibCodeRange code_ranges_[kMaxLibs];
+
+ // Cold part:
+ BlockingMutex mutex_;
+ uptr count_;
+ Lib libs_[kMaxLibs];
+
+ // Disallow copying of LibIgnore objects.
+ LibIgnore(const LibIgnore&); // not implemented
+ void operator = (const LibIgnore&); // not implemented
+};
+
+inline bool LibIgnore::IsIgnored(uptr pc) const {
+ const uptr n = atomic_load(&loaded_count_, memory_order_acquire);
+ for (uptr i = 0; i < n; i++) {
+ if (pc >= code_ranges_[i].begin && pc < code_ranges_[i].end)
+ return true;
+ }
+ return false;
+}
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_LIBIGNORE_H
diff --git a/lib/sanitizer_common/sanitizer_linux.cc b/lib/sanitizer_common/sanitizer_linux.cc
index 6e234e5f1e1d..b98ad0ab4804 100644
--- a/lib/sanitizer_common/sanitizer_linux.cc
+++ b/lib/sanitizer_common/sanitizer_linux.cc
@@ -29,6 +29,9 @@
#include <dlfcn.h>
#include <errno.h>
#include <fcntl.h>
+#if !SANITIZER_ANDROID
+#include <link.h>
+#endif
#include <pthread.h>
#include <sched.h>
#include <sys/mman.h>
@@ -76,14 +79,15 @@ namespace __sanitizer {
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, addr, length, prot, flags, fd, offset);
+ return internal_syscall(__NR_mmap, (uptr)addr, length, prot, flags, fd,
+ offset);
#else
return internal_syscall(__NR_mmap2, addr, length, prot, flags, fd, offset);
#endif
}
uptr internal_munmap(void *addr, uptr length) {
- return internal_syscall(__NR_munmap, addr, length);
+ return internal_syscall(__NR_munmap, (uptr)addr, length);
}
uptr internal_close(fd_t fd) {
@@ -91,11 +95,11 @@ uptr internal_close(fd_t fd) {
}
uptr internal_open(const char *filename, int flags) {
- return internal_syscall(__NR_open, filename, flags);
+ return internal_syscall(__NR_open, (uptr)filename, flags);
}
uptr internal_open(const char *filename, int flags, u32 mode) {
- return internal_syscall(__NR_open, filename, flags, mode);
+ return internal_syscall(__NR_open, (uptr)filename, flags, mode);
}
uptr OpenFile(const char *filename, bool write) {
@@ -105,13 +109,13 @@ uptr OpenFile(const char *filename, bool write) {
uptr internal_read(fd_t fd, void *buf, uptr count) {
sptr res;
- HANDLE_EINTR(res, (sptr)internal_syscall(__NR_read, fd, buf, count));
+ HANDLE_EINTR(res, (sptr)internal_syscall(__NR_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, buf, count));
+ HANDLE_EINTR(res, (sptr)internal_syscall(__NR_write, fd, (uptr)buf, count));
return res;
}
@@ -137,7 +141,7 @@ static void stat64_to_stat(struct stat64 *in, struct stat *out) {
uptr internal_stat(const char *path, void *buf) {
#if SANITIZER_LINUX_USES_64BIT_SYSCALLS
- return internal_syscall(__NR_stat, path, buf);
+ return internal_syscall(__NR_stat, (uptr)path, (uptr)buf);
#else
struct stat64 buf64;
int res = internal_syscall(__NR_stat64, path, &buf64);
@@ -148,7 +152,7 @@ uptr internal_stat(const char *path, void *buf) {
uptr internal_lstat(const char *path, void *buf) {
#if SANITIZER_LINUX_USES_64BIT_SYSCALLS
- return internal_syscall(__NR_lstat, path, buf);
+ return internal_syscall(__NR_lstat, (uptr)path, (uptr)buf);
#else
struct stat64 buf64;
int res = internal_syscall(__NR_lstat64, path, &buf64);
@@ -159,7 +163,7 @@ uptr internal_lstat(const char *path, void *buf) {
uptr internal_fstat(fd_t fd, void *buf) {
#if SANITIZER_LINUX_USES_64BIT_SYSCALLS
- return internal_syscall(__NR_fstat, fd, buf);
+ return internal_syscall(__NR_fstat, fd, (uptr)buf);
#else
struct stat64 buf64;
int res = internal_syscall(__NR_fstat64, fd, &buf64);
@@ -180,11 +184,11 @@ uptr internal_dup2(int oldfd, int newfd) {
}
uptr internal_readlink(const char *path, char *buf, uptr bufsize) {
- return internal_syscall(__NR_readlink, path, buf, bufsize);
+ return internal_syscall(__NR_readlink, (uptr)path, (uptr)buf, bufsize);
}
uptr internal_unlink(const char *path) {
- return internal_syscall(__NR_unlink, path);
+ return internal_syscall(__NR_unlink, (uptr)path);
}
uptr internal_sched_yield() {
@@ -198,7 +202,7 @@ void internal__exit(int exitcode) {
uptr internal_execve(const char *filename, char *const argv[],
char *const envp[]) {
- return internal_syscall(__NR_execve, filename, argv, envp);
+ return internal_syscall(__NR_execve, (uptr)filename, (uptr)argv, (uptr)envp);
}
// ----------------- sanitizer_common.h
@@ -216,7 +220,8 @@ uptr GetTid() {
u64 NanoTime() {
kernel_timeval tv;
- internal_syscall(__NR_gettimeofday, &tv, 0);
+ internal_memset(&tv, 0, sizeof(tv));
+ internal_syscall(__NR_gettimeofday, (uptr)&tv, 0);
return (u64)tv.tv_sec * 1000*1000*1000 + tv.tv_usec * 1000;
}
@@ -249,7 +254,7 @@ const char *GetEnv(const char *name) {
}
extern "C" {
- extern void *__libc_stack_end SANITIZER_WEAK_ATTRIBUTE;
+ SANITIZER_WEAK_ATTRIBUTE extern void *__libc_stack_end;
}
#if !SANITIZER_GO
@@ -307,7 +312,10 @@ void PrepareForSandboxing() {
// cached mappings.
MemoryMappingLayout::CacheMemoryMappings();
// Same for /proc/self/exe in the symbolizer.
- SymbolizerPrepareForSandboxing();
+#if !SANITIZER_GO
+ if (Symbolizer *sym = Symbolizer::GetOrNull())
+ sym->PrepareForSandboxing();
+#endif
}
// ----------------- sanitizer_procmaps.h
@@ -400,6 +408,30 @@ 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) {
@@ -442,7 +474,9 @@ bool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset,
CHECK_EQ(*current_++, ' ');
while (IsDecimal(*current_))
current_++;
- CHECK_EQ(*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_++;
@@ -468,6 +502,29 @@ bool MemoryMappingLayout::GetObjectNameAndOffset(uptr addr, uptr *offset,
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);
+}
+
enum MutexState {
MtxUnlocked = 0,
MtxLocked = 1,
@@ -487,7 +544,7 @@ void BlockingMutex::Lock() {
if (atomic_exchange(m, MtxLocked, memory_order_acquire) == MtxUnlocked)
return;
while (atomic_exchange(m, MtxSleeping, memory_order_acquire) != MtxUnlocked)
- internal_syscall(__NR_futex, m, FUTEX_WAIT, MtxSleeping, 0, 0, 0);
+ internal_syscall(__NR_futex, (uptr)m, FUTEX_WAIT, MtxSleeping, 0, 0, 0);
}
void BlockingMutex::Unlock() {
@@ -495,7 +552,7 @@ void BlockingMutex::Unlock() {
u32 v = atomic_exchange(m, MtxUnlocked, memory_order_relaxed);
CHECK_NE(v, MtxUnlocked);
if (v == MtxSleeping)
- internal_syscall(__NR_futex, m, FUTEX_WAKE, 1, 0, 0, 0);
+ internal_syscall(__NR_futex, (uptr)m, FUTEX_WAKE, 1, 0, 0, 0);
}
void BlockingMutex::CheckLocked() {
@@ -516,11 +573,12 @@ struct linux_dirent {
// Syscall wrappers.
uptr internal_ptrace(int request, int pid, void *addr, void *data) {
- return internal_syscall(__NR_ptrace, request, pid, addr, data);
+ return internal_syscall(__NR_ptrace, request, pid, (uptr)addr, (uptr)data);
}
uptr internal_waitpid(int pid, int *status, int options) {
- return internal_syscall(__NR_wait4, pid, status, options, 0 /* rusage */);
+ return internal_syscall(__NR_wait4, pid, (uptr)status, options,
+ 0 /* rusage */);
}
uptr internal_getpid() {
@@ -532,7 +590,7 @@ uptr internal_getppid() {
}
uptr internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned int count) {
- return internal_syscall(__NR_getdents, fd, dirp, count);
+ return internal_syscall(__NR_getdents, fd, (uptr)dirp, count);
}
uptr internal_lseek(fd_t fd, OFF_T offset, int whence) {
@@ -545,7 +603,32 @@ uptr internal_prctl(int option, uptr arg2, uptr arg3, uptr arg4, uptr arg5) {
uptr internal_sigaltstack(const struct sigaltstack *ss,
struct sigaltstack *oss) {
- return internal_syscall(__NR_sigaltstack, ss, oss);
+ return internal_syscall(__NR_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));
+}
+
+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));
+}
+
+void internal_sigfillset(__sanitizer_kernel_sigset_t *set) {
+ internal_memset(set, 0xff, sizeof(*set));
+}
+
+void internal_sigdelset(__sanitizer_kernel_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);
}
// ThreadLister implementation.
@@ -624,6 +707,39 @@ uptr GetPageSize() {
#endif
}
+static char proc_self_exe_cache_str[kMaxPathLength];
+static uptr proc_self_exe_cache_len = 0;
+
+uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) {
+ 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");
+ }
+ CHECK_LT(module_name_len, buf_len);
+ buf[module_name_len] = '\0';
+ }
+ return module_name_len;
+}
+
+void CacheBinaryName() {
+ if (!proc_self_exe_cache_len) {
+ proc_self_exe_cache_len =
+ ReadBinaryName(proc_self_exe_cache_str, kMaxPathLength);
+ }
+}
+
// Match full names of the form /path/to/base_name{-,.}*
bool LibraryNameIs(const char *full_name, const char *base_name) {
const char *name = full_name;
@@ -636,6 +752,107 @@ bool LibraryNameIs(const char *full_name, const char *base_name) {
return (name[base_name_length] == '-' || name[base_name_length] == '.');
}
+#if !SANITIZER_ANDROID
+// Call cb for each region mapped by map.
+void ForEachMappedRegion(link_map *map, void (*cb)(const void *, uptr)) {
+ typedef ElfW(Phdr) Elf_Phdr;
+ typedef ElfW(Ehdr) Elf_Ehdr;
+ char *base = (char *)map->l_addr;
+ Elf_Ehdr *ehdr = (Elf_Ehdr *)base;
+ char *phdrs = base + ehdr->e_phoff;
+ char *phdrs_end = phdrs + ehdr->e_phnum * ehdr->e_phentsize;
+
+ // Find the segment with the minimum base so we can "relocate" the p_vaddr
+ // fields. Typically ET_DYN objects (DSOs) have base of zero and ET_EXEC
+ // objects have a non-zero base.
+ uptr preferred_base = (uptr)-1;
+ for (char *iter = phdrs; iter != phdrs_end; iter += ehdr->e_phentsize) {
+ Elf_Phdr *phdr = (Elf_Phdr *)iter;
+ if (phdr->p_type == PT_LOAD && preferred_base > (uptr)phdr->p_vaddr)
+ preferred_base = (uptr)phdr->p_vaddr;
+ }
+
+ // Compute the delta from the real base to get a relocation delta.
+ sptr delta = (uptr)base - preferred_base;
+ // Now we can figure out what the loader really mapped.
+ for (char *iter = phdrs; iter != phdrs_end; iter += ehdr->e_phentsize) {
+ Elf_Phdr *phdr = (Elf_Phdr *)iter;
+ if (phdr->p_type == PT_LOAD) {
+ uptr seg_start = phdr->p_vaddr + delta;
+ uptr seg_end = seg_start + phdr->p_memsz;
+ // None of these values are aligned. We consider the ragged edges of the
+ // load command as defined, since they are mapped from the file.
+ seg_start = RoundDownTo(seg_start, GetPageSizeCached());
+ seg_end = RoundUpTo(seg_end, GetPageSizeCached());
+ cb((void *)seg_start, seg_end - seg_start);
+ }
+ }
+}
+#endif
+
+#if defined(__x86_64__)
+// 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
+// the parent (because we don't know how to allocate a new thread
+// descriptor to keep glibc happy). So the stock version of clone(), when
+// used with CLONE_VM, would end up corrupting the parent's thread descriptor.
+uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
+ int *parent_tidptr, void *newtls, int *child_tidptr) {
+ long long res;
+ if (!fn || !child_stack)
+ return -EINVAL;
+ CHECK_EQ(0, (uptr)child_stack % 16);
+ child_stack = (char *)child_stack - 2 * sizeof(unsigned long long);
+ ((unsigned long long *)child_stack)[0] = (uptr)fn;
+ ((unsigned long long *)child_stack)[1] = (uptr)arg;
+ register void *r8 __asm__("r8") = newtls;
+ register int *r10 __asm__("r10") = child_tidptr;
+ __asm__ __volatile__(
+ /* %rax = syscall(%rax = __NR_clone,
+ * %rdi = flags,
+ * %rsi = child_stack,
+ * %rdx = parent_tidptr,
+ * %r8 = new_tls,
+ * %r10 = child_tidptr)
+ */
+ "syscall\n"
+
+ /* if (%rax != 0)
+ * return;
+ */
+ "testq %%rax,%%rax\n"
+ "jnz 1f\n"
+
+ /* In the child. Terminate unwind chain. */
+ // XXX: We should also terminate the CFI unwind chain
+ // here. Unfortunately clang 3.2 doesn't support the
+ // necessary CFI directives, so we skip that part.
+ "xorq %%rbp,%%rbp\n"
+
+ /* Call "fn(arg)". */
+ "popq %%rax\n"
+ "popq %%rdi\n"
+ "call *%%rax\n"
+
+ /* Call _exit(%rax). */
+ "movq %%rax,%%rdi\n"
+ "movq %2,%%rax\n"
+ "syscall\n"
+
+ /* Return to parent. */
+ "1:\n"
+ : "=a" (res)
+ : "a"(__NR_clone), "i"(__NR_exit),
+ "S"(child_stack),
+ "D"(flags),
+ "d"(parent_tidptr),
+ "r"(r8),
+ "r"(r10)
+ : "rsp", "memory", "r11", "rcx");
+ return res;
+}
+#endif // defined(__x86_64__)
} // namespace __sanitizer
#endif // SANITIZER_LINUX
diff --git a/lib/sanitizer_common/sanitizer_linux.h b/lib/sanitizer_common/sanitizer_linux.h
index ba68e6c2dd5a..a32e9bf08bad 100644
--- a/lib/sanitizer_common/sanitizer_linux.h
+++ b/lib/sanitizer_common/sanitizer_linux.h
@@ -13,9 +13,13 @@
#ifndef SANITIZER_LINUX_H
#define SANITIZER_LINUX_H
+#include "sanitizer_platform.h"
+#if SANITIZER_LINUX
#include "sanitizer_common.h"
#include "sanitizer_internal_defs.h"
+#include "sanitizer_platform_limits_posix.h"
+struct link_map; // Opaque type returned by dlopen().
struct sigaltstack;
namespace __sanitizer {
@@ -28,6 +32,17 @@ 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);
+
+#ifdef __x86_64__
+uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
+ int *parent_tidptr, void *newtls, int *child_tidptr);
+#endif
// This class reads thread IDs from /proc/<pid>/task using only syscalls.
class ThreadLister {
@@ -51,15 +66,25 @@ class ThreadLister {
int bytes_read_;
};
-void AdjustStackSizeLinux(void *attr, int verbosity);
+void AdjustStackSizeLinux(void *attr);
// Exposed for testing.
uptr ThreadDescriptorSize();
+uptr ThreadSelf();
+uptr ThreadSelfOffset();
// Matches a library's file name against a base name (stripping path and version
// information).
bool LibraryNameIs(const char *full_name, const char *base_name);
+// Read the name of the current binary from /proc/self/exe.
+uptr ReadBinaryName(/*out*/char *buf, uptr buf_len);
+// Cache the value of /proc/self/exe.
+void CacheBinaryName();
+
+// Call cb for each region mapped by map.
+void ForEachMappedRegion(link_map *map, void (*cb)(const void *, uptr));
} // namespace __sanitizer
+#endif // 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 d9e2f5389606..2940686f1275 100644
--- a/lib/sanitizer_common/sanitizer_linux_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_linux_libcdep.cc
@@ -16,27 +16,28 @@
#if SANITIZER_LINUX
#include "sanitizer_common.h"
+#include "sanitizer_flags.h"
+#include "sanitizer_linux.h"
+#include "sanitizer_placement_new.h"
#include "sanitizer_procmaps.h"
#include "sanitizer_stacktrace.h"
-#ifdef __x86_64__
-#include <asm/prctl.h>
-#endif
#include <dlfcn.h>
#include <pthread.h>
#include <sys/prctl.h>
#include <sys/resource.h>
#include <unwind.h>
-#ifdef __x86_64__
-extern "C" int arch_prctl(int code, __sanitizer::uptr *addr);
+#if !SANITIZER_ANDROID
+#include <elf.h>
+#include <link.h>
#endif
namespace __sanitizer {
void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
uptr *stack_bottom) {
- static const uptr kMaxThreadStackSize = 256 * (1 << 20); // 256M
+ static const uptr kMaxThreadStackSize = 1 << 30; // 1Gb
CHECK(stack_top);
CHECK(stack_bottom);
if (at_initialization) {
@@ -76,9 +77,9 @@ void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
pthread_attr_getstack(&attr, &stackaddr, (size_t*)&stacksize);
pthread_attr_destroy(&attr);
+ CHECK_LE(stacksize, kMaxThreadStackSize); // Sanity check.
*stack_top = (uptr)stackaddr + stacksize;
*stack_bottom = (uptr)stackaddr;
- CHECK(stacksize < kMaxThreadStackSize); // Sanity check.
}
// Does not compile for Go because dlsym() requires -ldl
@@ -139,35 +140,33 @@ uptr Unwind_GetIP(struct _Unwind_Context *ctx) {
#endif
}
+struct UnwindTraceArg {
+ StackTrace *stack;
+ uptr max_depth;
+};
+
_Unwind_Reason_Code Unwind_Trace(struct _Unwind_Context *ctx, void *param) {
- StackTrace *b = (StackTrace*)param;
- CHECK(b->size < b->max_size);
+ UnwindTraceArg *arg = (UnwindTraceArg*)param;
+ CHECK_LT(arg->stack->size, arg->max_depth);
uptr pc = Unwind_GetIP(ctx);
- b->trace[b->size++] = pc;
- if (b->size == b->max_size) return UNWIND_STOP;
+ arg->stack->trace[arg->stack->size++] = pc;
+ if (arg->stack->size == arg->max_depth) return UNWIND_STOP;
return UNWIND_CONTINUE;
}
-static bool MatchPc(uptr cur_pc, uptr trace_pc) {
- return cur_pc - trace_pc <= 64 || trace_pc - cur_pc <= 64;
-}
-
void StackTrace::SlowUnwindStack(uptr pc, uptr max_depth) {
- this->size = 0;
- this->max_size = max_depth;
- if (max_depth > 1) {
- _Unwind_Backtrace(Unwind_Trace, this);
- // We need to pop a few frames so that pc is on top.
- // trace[0] belongs to the current function so we always pop it.
- int to_pop = 1;
- /**/ if (size > 1 && MatchPc(pc, trace[1])) to_pop = 1;
- else if (size > 2 && MatchPc(pc, trace[2])) to_pop = 2;
- else if (size > 3 && MatchPc(pc, trace[3])) to_pop = 3;
- else if (size > 4 && MatchPc(pc, trace[4])) to_pop = 4;
- else if (size > 5 && MatchPc(pc, trace[5])) to_pop = 5;
- this->PopStackFrames(to_pop);
- }
- this->trace[0] = pc;
+ 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
@@ -200,20 +199,43 @@ uptr GetTlsSize() {
return g_tls_size;
}
+#if defined(__x86_64__) || defined(__i386__)
// sizeof(struct thread) from glibc.
-#ifdef __x86_64__
-const uptr kThreadDescriptorSize = 2304;
+// 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
uptr ThreadDescriptorSize() {
return kThreadDescriptorSize;
}
+
+// The offset at which pointer to self is located in the thread descriptor.
+const uptr kThreadSelfOffset = FIRST_32_SECOND_64(8, 16);
+
+uptr ThreadSelfOffset() {
+ return kThreadSelfOffset;
+}
+
+uptr ThreadSelf() {
+ uptr descr_addr;
+#ifdef __i386__
+ asm("mov %%gs:%c1,%0" : "=r"(descr_addr) : "i"(kThreadSelfOffset));
+#else
+ asm("mov %%fs:%c1,%0" : "=r"(descr_addr) : "i"(kThreadSelfOffset));
#endif
+ return descr_addr;
+}
+#endif // defined(__x86_64__) || defined(__i386__)
void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
uptr *tls_addr, uptr *tls_size) {
#ifndef SANITIZER_GO
-#ifdef __x86_64__
- arch_prctl(ARCH_GET_FS, tls_addr);
+#if defined(__x86_64__) || defined(__i386__)
+ *tls_addr = ThreadSelf();
*tls_size = GetTlsSize();
*tls_addr -= *tls_size;
*tls_addr += kThreadDescriptorSize;
@@ -244,7 +266,7 @@ void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
#endif // SANITIZER_GO
}
-void AdjustStackSizeLinux(void *attr_, int verbosity) {
+void AdjustStackSizeLinux(void *attr_) {
pthread_attr_t *attr = (pthread_attr_t *)attr_;
uptr stackaddr = 0;
size_t stacksize = 0;
@@ -256,7 +278,7 @@ void AdjustStackSizeLinux(void *attr_, int verbosity) {
const uptr minstacksize = GetTlsSize() + 128*1024;
if (stacksize < minstacksize) {
if (!stack_set) {
- if (verbosity && stacksize != 0)
+ if (common_flags()->verbosity && stacksize != 0)
Printf("Sanitizer: increasing stacksize %zu->%zu\n", stacksize,
minstacksize);
pthread_attr_setstacksize(attr, minstacksize);
@@ -268,6 +290,63 @@ void AdjustStackSizeLinux(void *attr_, int verbosity) {
}
}
+#if SANITIZER_ANDROID
+uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
+ string_predicate_t filter) {
+ return 0;
+}
+#else // SANITIZER_ANDROID
+typedef ElfW(Phdr) Elf_Phdr;
+
+struct DlIteratePhdrData {
+ LoadedModule *modules;
+ uptr current_n;
+ bool first;
+ uptr max_n;
+ string_predicate_t filter;
+};
+
+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';
+ 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());
+ }
+ if (module_name.data()[0] == '\0')
+ return 0;
+ if (data->filter && !data->filter(module_name.data()))
+ return 0;
+ void *mem = &data->modules[data->current_n];
+ LoadedModule *cur_module = new(mem) LoadedModule(module_name.data(),
+ info->dlpi_addr);
+ data->current_n++;
+ for (int i = 0; i < info->dlpi_phnum; i++) {
+ const Elf_Phdr *phdr = &info->dlpi_phdr[i];
+ 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);
+ }
+ }
+ return 0;
+}
+
+uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
+ string_predicate_t filter) {
+ CHECK(modules);
+ DlIteratePhdrData data = {modules, 0, true, max_modules, filter};
+ dl_iterate_phdr(dl_iterate_phdr_cb, &data);
+ return data.current_n;
+}
+#endif // SANITIZER_ANDROID
+
} // namespace __sanitizer
#endif // SANITIZER_LINUX
diff --git a/lib/sanitizer_common/sanitizer_mac.cc b/lib/sanitizer_common/sanitizer_mac.cc
index f97d1e39c5bf..87ad8b53c6c9 100644
--- a/lib/sanitizer_common/sanitizer_mac.cc
+++ b/lib/sanitizer_common/sanitizer_mac.cc
@@ -25,6 +25,7 @@
#include "sanitizer_common.h"
#include "sanitizer_internal_defs.h"
#include "sanitizer_libc.h"
+#include "sanitizer_placement_new.h"
#include "sanitizer_procmaps.h"
#include <crt_externs.h> // for _NSGetEnviron
@@ -144,7 +145,11 @@ void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
const char *GetEnv(const char *name) {
char ***env_ptr = _NSGetEnviron();
- CHECK(env_ptr);
+ if (!env_ptr) {
+ Report("_NSGetEnviron() returned NULL. Please make sure __asan_init() is "
+ "called after libSystem_initializer().\n");
+ CHECK(env_ptr);
+ }
char **environ = *env_ptr;
CHECK(environ);
uptr name_len = internal_strlen(name);
@@ -343,6 +348,10 @@ void BlockingMutex::CheckLocked() {
CHECK_EQ((uptr)pthread_self(), owner_);
}
+u64 NanoTime() {
+ return 0;
+}
+
uptr GetTlsSize() {
return 0;
}
@@ -352,12 +361,50 @@ void InitTlsSize() {
void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
uptr *tls_addr, uptr *tls_size) {
+#ifndef SANITIZER_GO
uptr stack_top, stack_bottom;
GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom);
*stk_addr = stack_bottom;
*stk_size = stack_top - stack_bottom;
*tls_addr = 0;
*tls_size = 0;
+#else
+ *stk_addr = 0;
+ *stk_size = 0;
+ *tls_addr = 0;
+ *tls_size = 0;
+#endif
+}
+
+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++;
+ }
+ cur_module->addAddressRange(cur_beg, cur_end);
+ }
+ return n_modules;
}
} // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_mutex.h b/lib/sanitizer_common/sanitizer_mutex.h
index 469981c35176..e812fce90598 100644
--- a/lib/sanitizer_common/sanitizer_mutex.h
+++ b/lib/sanitizer_common/sanitizer_mutex.h
@@ -40,6 +40,10 @@ class StaticSpinMutex {
atomic_store(&state_, 0, memory_order_release);
}
+ void CheckLocked() {
+ CHECK_EQ(atomic_load(&state_, memory_order_relaxed), 1);
+ }
+
private:
atomic_uint8_t state_;
diff --git a/lib/sanitizer_common/sanitizer_placement_new.h b/lib/sanitizer_common/sanitizer_placement_new.h
index a42301aedeac..8904d1040ea7 100644
--- a/lib/sanitizer_common/sanitizer_placement_new.h
+++ b/lib/sanitizer_common/sanitizer_placement_new.h
@@ -18,15 +18,7 @@
#include "sanitizer_internal_defs.h"
-namespace __sanitizer {
-#if (SANITIZER_WORDSIZE == 64) || SANITIZER_MAC
-typedef uptr operator_new_ptr_type;
-#else
-typedef u32 operator_new_ptr_type;
-#endif
-} // namespace __sanitizer
-
-inline void *operator new(__sanitizer::operator_new_ptr_type sz, void *p) {
+inline void *operator new(__sanitizer::operator_new_size_type sz, void *p) {
return p;
}
diff --git a/lib/sanitizer_common/sanitizer_platform.h b/lib/sanitizer_common/sanitizer_platform.h
index acb997180957..fce721e300fb 100644
--- a/lib/sanitizer_common/sanitizer_platform.h
+++ b/lib/sanitizer_common/sanitizer_platform.h
@@ -25,8 +25,15 @@
#if defined(__APPLE__)
# define SANITIZER_MAC 1
+# include <TargetConditionals.h>
+# if TARGET_OS_IPHONE
+# define SANITIZER_IOS 1
+# else
+# define SANITIZER_IOS 0
+# endif
#else
# define SANITIZER_MAC 0
+# define SANITIZER_IOS 0
#endif
#if defined(_WIN32)
diff --git a/lib/sanitizer_common/sanitizer_platform_interceptors.h b/lib/sanitizer_common/sanitizer_platform_interceptors.h
index 60c7145b611a..78d1f5adef7b 100644
--- a/lib/sanitizer_common/sanitizer_platform_interceptors.h
+++ b/lib/sanitizer_common/sanitizer_platform_interceptors.h
@@ -41,6 +41,13 @@
# define SI_MAC 0
#endif
+#if SANITIZER_IOS
+# define SI_IOS 1
+#else
+# define SI_IOS 0
+#endif
+
+# define SANITIZER_INTERCEPT_STRCMP 1
# define SANITIZER_INTERCEPT_STRCASECMP SI_NOT_WINDOWS
# define SANITIZER_INTERCEPT_READ SI_NOT_WINDOWS
@@ -48,11 +55,21 @@
# 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
+#define SANITIZER_INTERCEPT_PREAD64 SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_PWRITE64 SI_LINUX_NOT_ANDROID
+
+#define SANITIZER_INTERCEPT_READV SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_WRITEV SI_NOT_WINDOWS
+
+#define SANITIZER_INTERCEPT_PREADV SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_PWRITEV SI_LINUX_NOT_ANDROID
+#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
@@ -71,9 +88,83 @@
# 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
+
+// FIXME: getline seems to be available on OSX 10.7
+# define SANITIZER_INTERCEPT_GETLINE SI_LINUX_NOT_ANDROID
+
+# define SANITIZER_INTERCEPT__EXIT SI_LINUX
+
+# 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
#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
new file mode 100644
index 000000000000..4c9f12acd3b0
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_platform_limits_linux.cc
@@ -0,0 +1,95 @@
+//===-- sanitizer_platform_limits_linux.cc --------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of Sanitizer common code.
+//
+// Sizes and layouts of linux kernel data structures.
+//===----------------------------------------------------------------------===//
+
+// This is a separate compilation unit for linux headers that conflict with
+// userspace headers.
+// Most "normal" includes go in sanitizer_platform_limits_posix.cc
+
+#include "sanitizer_platform.h"
+#if SANITIZER_LINUX
+
+#include "sanitizer_internal_defs.h"
+#include "sanitizer_platform_limits_posix.h"
+
+// For offsetof -> __builtin_offsetof definition.
+#include <stddef.h>
+
+// With old kernels (and even new kernels on powerpc) asm/stat.h uses types that
+// are not defined anywhere in userspace headers. Fake them. This seems to work
+// fine with newer headers, too.
+#include <asm/posix_types.h>
+#define ino_t __kernel_ino_t
+#define mode_t __kernel_mode_t
+#define nlink_t __kernel_nlink_t
+#define uid_t __kernel_uid_t
+#define gid_t __kernel_gid_t
+#define off_t __kernel_off_t
+// This header seems to contain the definitions of _kernel_ stat* structs.
+#include <asm/stat.h>
+#undef ino_t
+#undef mode_t
+#undef nlink_t
+#undef uid_t
+#undef gid_t
+#undef off_t
+
+#include <linux/aio_abi.h>
+
+#if SANITIZER_ANDROID
+#include <asm/statfs.h>
+#else
+#include <sys/statfs.h>
+#endif
+
+#if !SANITIZER_ANDROID
+#include <linux/perf_event.h>
+#endif
+
+namespace __sanitizer {
+ unsigned struct_statfs64_sz = sizeof(struct statfs64);
+} // namespace __sanitizer
+
+#if !defined(__powerpc64__)
+COMPILER_CHECK(struct___old_kernel_stat_sz == sizeof(struct __old_kernel_stat));
+#endif
+
+COMPILER_CHECK(struct_kernel_stat_sz == sizeof(struct stat));
+
+#if defined(__i386__)
+COMPILER_CHECK(struct_kernel_stat64_sz == sizeof(struct stat64));
+#endif
+
+COMPILER_CHECK(struct_io_event_sz == sizeof(struct io_event));
+
+#if !SANITIZER_ANDROID
+COMPILER_CHECK(sizeof(struct __sanitizer_perf_event_attr) <=
+ sizeof(struct perf_event_attr));
+CHECK_SIZE_AND_OFFSET(perf_event_attr, type);
+CHECK_SIZE_AND_OFFSET(perf_event_attr, size);
+#endif
+
+COMPILER_CHECK(iocb_cmd_pread == IOCB_CMD_PREAD);
+COMPILER_CHECK(iocb_cmd_pwrite == IOCB_CMD_PWRITE);
+
+CHECK_TYPE_SIZE(iocb);
+CHECK_SIZE_AND_OFFSET(iocb, aio_data);
+// Skip aio_key, it's weird.
+CHECK_SIZE_AND_OFFSET(iocb, aio_lio_opcode);
+CHECK_SIZE_AND_OFFSET(iocb, aio_reqprio);
+CHECK_SIZE_AND_OFFSET(iocb, aio_fildes);
+CHECK_SIZE_AND_OFFSET(iocb, aio_buf);
+CHECK_SIZE_AND_OFFSET(iocb, aio_nbytes);
+CHECK_SIZE_AND_OFFSET(iocb, aio_offset);
+
+#endif // SANITIZER_LINUX
diff --git a/lib/sanitizer_common/sanitizer_platform_limits_posix.cc b/lib/sanitizer_common/sanitizer_platform_limits_posix.cc
index c269de65ca2c..e887751d60f0 100644
--- a/lib/sanitizer_common/sanitizer_platform_limits_posix.cc
+++ b/lib/sanitizer_common/sanitizer_platform_limits_posix.cc
@@ -21,35 +21,109 @@
#include <arpa/inet.h>
#include <dirent.h>
+#include <errno.h>
#include <grp.h>
+#include <limits.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/route.h>
+#include <netdb.h>
+#include <poll.h>
#include <pthread.h>
#include <pwd.h>
#include <signal.h>
#include <stddef.h>
-#include <sys/utsname.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/socket.h>
-#include <sys/time.h>
#include <sys/resource.h>
#include <sys/socket.h>
-#include <netdb.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/times.h>
+#include <sys/types.h>
+#include <sys/utsname.h>
+#include <termios.h>
#include <time.h>
+#include <wchar.h>
+
+#if SANITIZER_LINUX
+#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>
+#include <linux/fd.h>
+#include <linux/fs.h>
+#include <linux/hdreg.h>
+#include <linux/input.h>
+#include <linux/ioctl.h>
+#include <linux/soundcard.h>
+#include <linux/sysctl.h>
+#include <linux/utsname.h>
+#include <linux/posix_types.h>
+#endif
#if !SANITIZER_ANDROID
#include <sys/ucontext.h>
-#endif // !SANITIZER_ANDROID
+#include <wordexp.h>
+#endif
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+#include <glob.h>
+#include <mqueue.h>
+#include <net/if_ppp.h>
+#include <netax25/ax25.h>
+#include <netipx/ipx.h>
+#include <netrom/netrom.h>
+#include <scsi/scsi.h>
+#include <sys/mtio.h>
+#include <sys/kd.h>
+#include <sys/shm.h>
+#include <sys/statvfs.h>
+#include <sys/timex.h>
+#include <sys/user.h>
+#include <sys/ustat.h>
+#include <linux/cyclades.h>
+#include <linux/if_eql.h>
+#include <linux/if_plip.h>
+#include <linux/lp.h>
+#include <linux/mroute.h>
+#include <linux/mroute6.h>
+#include <linux/scc.h>
+#include <linux/serial.h>
+#include <sys/msg.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#endif // SANITIZER_LINUX && !SANITIZER_ANDROID
+
+#if SANITIZER_ANDROID
+#include <linux/kd.h>
+#include <linux/mtio.h>
+#include <linux/ppp_defs.h>
+#include <linux/if_ppp.h>
+#endif
#if SANITIZER_LINUX
#include <link.h>
#include <sys/vfs.h>
#include <sys/epoll.h>
+#include <linux/capability.h>
#endif // SANITIZER_LINUX
+#if SANITIZER_MAC
+#include <net/ethernet.h>
+#include <sys/filio.h>
+#include <sys/mount.h>
+#include <sys/sockio.h>
+#endif
+
namespace __sanitizer {
unsigned struct_utsname_sz = sizeof(struct utsname);
unsigned struct_stat_sz = sizeof(struct stat);
+#if !SANITIZER_IOS
unsigned struct_stat64_sz = sizeof(struct stat64);
+#endif // !SANITIZER_IOS
unsigned struct_rusage_sz = sizeof(struct rusage);
unsigned struct_tm_sz = sizeof(struct tm);
unsigned struct_passwd_sz = sizeof(struct passwd);
@@ -58,7 +132,21 @@ namespace __sanitizer {
unsigned struct_sigaction_sz = sizeof(struct sigaction);
unsigned struct_itimerval_sz = sizeof(struct itimerval);
unsigned pthread_t_sz = sizeof(pthread_t);
- unsigned struct_sockaddr_sz = sizeof(struct sockaddr);
+ unsigned pthread_cond_t_sz = sizeof(pthread_cond_t);
+ unsigned pid_t_sz = sizeof(pid_t);
+ unsigned timeval_sz = sizeof(timeval);
+ unsigned uid_t_sz = sizeof(uid_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 ucontext_t_sz = sizeof(ucontext_t);
@@ -66,51 +154,49 @@ namespace __sanitizer {
#if SANITIZER_LINUX
unsigned struct_rlimit_sz = sizeof(struct rlimit);
- unsigned struct_dirent_sz = sizeof(struct dirent);
- unsigned struct_statfs_sz = sizeof(struct statfs);
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);
+ unsigned struct_itimerspec_sz = sizeof(struct itimerspec);
+ unsigned struct_ustat_sz = sizeof(struct ustat);
#endif // SANITIZER_LINUX
#if SANITIZER_LINUX && !SANITIZER_ANDROID
- unsigned struct_dirent64_sz = sizeof(struct dirent64);
unsigned struct_rlimit64_sz = sizeof(struct rlimit64);
- unsigned struct_statfs64_sz = sizeof(struct statfs64);
+ 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
uptr sig_ign = (uptr)SIG_IGN;
uptr sig_dfl = (uptr)SIG_DFL;
+ uptr sa_siginfo = (uptr)SA_SIGINFO;
- void* __sanitizer_get_msghdr_iov_iov_base(void* msg, int idx) {
- return ((struct msghdr *)msg)->msg_iov[idx].iov_base;
- }
-
- uptr __sanitizer_get_msghdr_iov_iov_len(void* msg, int idx) {
- return ((struct msghdr *)msg)->msg_iov[idx].iov_len;
- }
+#if SANITIZER_LINUX
+ int e_tabsz = (int)E_TABSZ;
+#endif
- uptr __sanitizer_get_msghdr_iovlen(void* msg) {
- return ((struct msghdr *)msg)->msg_iovlen;
- }
- uptr __sanitizer_get_socklen_t(void* socklen_ptr) {
- return *(socklen_t*)socklen_ptr;
- }
+#if SANITIZER_LINUX && !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;
+#endif
- uptr __sanitizer_get_sigaction_sa_sigaction(void *act) {
- struct sigaction *a = (struct sigaction *)act;
- // Check that sa_sigaction and sa_handler are the same.
- CHECK((void *)&(a->sa_sigaction) == (void *)&(a->sa_handler));
- return (uptr) a->sa_sigaction;
- }
- void __sanitizer_set_sigaction_sa_sigaction(void *act, uptr cb) {
- struct sigaction *a = (struct sigaction *)act;
- a->sa_sigaction = (void (*)(int, siginfo_t *, void *))cb;
- }
- bool __sanitizer_get_sigaction_sa_siginfo(void *act) {
- struct sigaction *a = (struct sigaction *)act;
- return a->sa_flags & SA_SIGINFO;
- }
+ int af_inet = (int)AF_INET;
+ int af_inet6 = (int)AF_INET6;
uptr __sanitizer_in_addr_sz(int af) {
if (af == AF_INET)
@@ -120,36 +206,742 @@ namespace __sanitizer {
else
return 0;
}
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+ int glob_nomatch = GLOB_NOMATCH;
+ int glob_altdirfunc = GLOB_ALTDIRFUNC;
+#endif
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID && \
+ (defined(__i386) || defined (__x86_64)) // NOLINT
+ 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
+ unsigned struct_user_fpxregs_struct_sz = 0;
+#else
+ unsigned struct_user_fpxregs_struct_sz = sizeof(struct user_fpxregs_struct);
+#endif
+
+ int ptrace_peektext = PTRACE_PEEKTEXT;
+ int ptrace_peekdata = PTRACE_PEEKDATA;
+ int ptrace_peekuser = PTRACE_PEEKUSER;
+ int ptrace_getregs = PTRACE_GETREGS;
+ int ptrace_setregs = PTRACE_SETREGS;
+ int ptrace_getfpregs = PTRACE_GETFPREGS;
+ int ptrace_setfpregs = PTRACE_SETFPREGS;
+ int ptrace_getfpxregs = PTRACE_GETFPXREGS;
+ int ptrace_setfpxregs = PTRACE_SETFPXREGS;
+ int ptrace_getsiginfo = PTRACE_GETSIGINFO;
+ int ptrace_setsiginfo = 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
+
+ unsigned path_max = PATH_MAX;
+
+ // ioctl arguments
+ unsigned struct_arpreq_sz = sizeof(struct arpreq);
+ unsigned struct_ifreq_sz = sizeof(struct ifreq);
+ unsigned struct_termios_sz = sizeof(struct termios);
+ unsigned struct_winsize_sz = sizeof(struct winsize);
+
+#if SANITIZER_LINUX
+ unsigned struct_cdrom_msf_sz = sizeof(struct cdrom_msf);
+ unsigned struct_cdrom_multisession_sz = sizeof(struct cdrom_multisession);
+ unsigned struct_cdrom_read_audio_sz = sizeof(struct cdrom_read_audio);
+ unsigned struct_cdrom_subchnl_sz = sizeof(struct cdrom_subchnl);
+ unsigned struct_cdrom_ti_sz = sizeof(struct cdrom_ti);
+ 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);
+ unsigned struct_floppy_fdc_state_sz = sizeof(struct floppy_fdc_state);
+ unsigned struct_floppy_max_errors_sz = sizeof(struct floppy_max_errors);
+ unsigned struct_floppy_raw_cmd_sz = sizeof(struct floppy_raw_cmd);
+ unsigned struct_floppy_struct_sz = sizeof(struct floppy_struct);
+ unsigned struct_floppy_write_errors_sz = sizeof(struct floppy_write_errors);
+ unsigned struct_format_descr_sz = sizeof(struct format_descr);
+ unsigned struct_hd_driveid_sz = sizeof(struct hd_driveid);
+ 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_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
+
+#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)
+ unsigned struct_input_keymap_entry_sz = sizeof(struct input_keymap_entry);
+#else
+ unsigned struct_input_keymap_entry_sz = 0;
+#endif
+ unsigned struct_ipx_config_data_sz = sizeof(struct ipx_config_data);
+ unsigned struct_kbdiacrs_sz = sizeof(struct kbdiacrs);
+ unsigned struct_kbentry_sz = sizeof(struct kbentry);
+ unsigned struct_kbkeycode_sz = sizeof(struct kbkeycode);
+ 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
+ = sizeof(struct serial_multiport_struct);
+ unsigned struct_serial_struct_sz = sizeof(struct serial_struct);
+ unsigned struct_sockaddr_ax25_sz = sizeof(struct sockaddr_ax25);
+ unsigned struct_unimapdesc_sz = sizeof(struct unimapdesc);
+ unsigned struct_unimapinit_sz = sizeof(struct unimapinit);
+#endif
+
+#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;
+
+ unsigned IOCTL_FIOASYNC = FIOASYNC;
+ unsigned IOCTL_FIOCLEX = FIOCLEX;
+ unsigned IOCTL_FIOGETOWN = FIOGETOWN;
+ unsigned IOCTL_FIONBIO = FIONBIO;
+ unsigned IOCTL_FIONCLEX = FIONCLEX;
+ unsigned IOCTL_FIOSETOWN = FIOSETOWN;
+ unsigned IOCTL_SIOCADDMULTI = SIOCADDMULTI;
+ unsigned IOCTL_SIOCATMARK = SIOCATMARK;
+ unsigned IOCTL_SIOCDELMULTI = SIOCDELMULTI;
+ unsigned IOCTL_SIOCGIFADDR = SIOCGIFADDR;
+ unsigned IOCTL_SIOCGIFBRDADDR = SIOCGIFBRDADDR;
+ unsigned IOCTL_SIOCGIFCONF = SIOCGIFCONF;
+ unsigned IOCTL_SIOCGIFDSTADDR = SIOCGIFDSTADDR;
+ unsigned IOCTL_SIOCGIFFLAGS = SIOCGIFFLAGS;
+ unsigned IOCTL_SIOCGIFMETRIC = SIOCGIFMETRIC;
+ unsigned IOCTL_SIOCGIFMTU = SIOCGIFMTU;
+ unsigned IOCTL_SIOCGIFNETMASK = SIOCGIFNETMASK;
+ unsigned IOCTL_SIOCGPGRP = SIOCGPGRP;
+ unsigned IOCTL_SIOCSIFADDR = SIOCSIFADDR;
+ unsigned IOCTL_SIOCSIFBRDADDR = SIOCSIFBRDADDR;
+ unsigned IOCTL_SIOCSIFDSTADDR = SIOCSIFDSTADDR;
+ unsigned IOCTL_SIOCSIFFLAGS = SIOCSIFFLAGS;
+ unsigned IOCTL_SIOCSIFMETRIC = SIOCSIFMETRIC;
+ unsigned IOCTL_SIOCSIFMTU = SIOCSIFMTU;
+ unsigned IOCTL_SIOCSIFNETMASK = SIOCSIFNETMASK;
+ unsigned IOCTL_SIOCSPGRP = SIOCSPGRP;
+ unsigned IOCTL_TIOCCONS = TIOCCONS;
+ unsigned IOCTL_TIOCEXCL = TIOCEXCL;
+ unsigned IOCTL_TIOCGETD = TIOCGETD;
+ unsigned IOCTL_TIOCGPGRP = TIOCGPGRP;
+ unsigned IOCTL_TIOCGWINSZ = TIOCGWINSZ;
+ unsigned IOCTL_TIOCMBIC = TIOCMBIC;
+ unsigned IOCTL_TIOCMBIS = TIOCMBIS;
+ unsigned IOCTL_TIOCMGET = TIOCMGET;
+ unsigned IOCTL_TIOCMSET = TIOCMSET;
+ unsigned IOCTL_TIOCNOTTY = TIOCNOTTY;
+ unsigned IOCTL_TIOCNXCL = TIOCNXCL;
+ unsigned IOCTL_TIOCOUTQ = TIOCOUTQ;
+ unsigned IOCTL_TIOCPKT = TIOCPKT;
+ unsigned IOCTL_TIOCSCTTY = TIOCSCTTY;
+ unsigned IOCTL_TIOCSETD = TIOCSETD;
+ unsigned IOCTL_TIOCSPGRP = TIOCSPGRP;
+ unsigned IOCTL_TIOCSTI = TIOCSTI;
+ unsigned IOCTL_TIOCSWINSZ = TIOCSWINSZ;
+#if (SANITIZER_LINUX && !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);
+ unsigned IOCTL_EVIOCGEFFECTS = EVIOCGEFFECTS;
+ unsigned IOCTL_EVIOCGID = EVIOCGID;
+ unsigned IOCTL_EVIOCGKEY = EVIOCGKEY(0);
+ unsigned IOCTL_EVIOCGKEYCODE = EVIOCGKEYCODE;
+ unsigned IOCTL_EVIOCGLED = EVIOCGLED(0);
+ unsigned IOCTL_EVIOCGNAME = EVIOCGNAME(0);
+ unsigned IOCTL_EVIOCGPHYS = EVIOCGPHYS(0);
+ unsigned IOCTL_EVIOCGRAB = EVIOCGRAB;
+ unsigned IOCTL_EVIOCGREP = EVIOCGREP;
+ unsigned IOCTL_EVIOCGSND = EVIOCGSND(0);
+ unsigned IOCTL_EVIOCGSW = EVIOCGSW(0);
+ unsigned IOCTL_EVIOCGUNIQ = EVIOCGUNIQ(0);
+ unsigned IOCTL_EVIOCGVERSION = EVIOCGVERSION;
+ unsigned IOCTL_EVIOCRMFF = EVIOCRMFF;
+ unsigned IOCTL_EVIOCSABS = EVIOCSABS(0);
+ unsigned IOCTL_EVIOCSFF = EVIOCSFF;
+ unsigned IOCTL_EVIOCSKEYCODE = EVIOCSKEYCODE;
+ unsigned IOCTL_EVIOCSREP = EVIOCSREP;
+ unsigned IOCTL_BLKFLSBUF = BLKFLSBUF;
+ unsigned IOCTL_BLKGETSIZE = BLKGETSIZE;
+ unsigned IOCTL_BLKRAGET = BLKRAGET;
+ unsigned IOCTL_BLKRASET = BLKRASET;
+ unsigned IOCTL_BLKROGET = BLKROGET;
+ unsigned IOCTL_BLKROSET = BLKROSET;
+ unsigned IOCTL_BLKRRPART = BLKRRPART;
+ unsigned IOCTL_CDROMAUDIOBUFSIZ = CDROMAUDIOBUFSIZ;
+ unsigned IOCTL_CDROMEJECT = CDROMEJECT;
+ unsigned IOCTL_CDROMEJECT_SW = CDROMEJECT_SW;
+ unsigned IOCTL_CDROMMULTISESSION = CDROMMULTISESSION;
+ unsigned IOCTL_CDROMPAUSE = CDROMPAUSE;
+ unsigned IOCTL_CDROMPLAYMSF = CDROMPLAYMSF;
+ unsigned IOCTL_CDROMPLAYTRKIND = CDROMPLAYTRKIND;
+ unsigned IOCTL_CDROMREADAUDIO = CDROMREADAUDIO;
+ unsigned IOCTL_CDROMREADCOOKED = CDROMREADCOOKED;
+ unsigned IOCTL_CDROMREADMODE1 = CDROMREADMODE1;
+ unsigned IOCTL_CDROMREADMODE2 = CDROMREADMODE2;
+ unsigned IOCTL_CDROMREADRAW = CDROMREADRAW;
+ unsigned IOCTL_CDROMREADTOCENTRY = CDROMREADTOCENTRY;
+ unsigned IOCTL_CDROMREADTOCHDR = CDROMREADTOCHDR;
+ unsigned IOCTL_CDROMRESET = CDROMRESET;
+ unsigned IOCTL_CDROMRESUME = CDROMRESUME;
+ unsigned IOCTL_CDROMSEEK = CDROMSEEK;
+ unsigned IOCTL_CDROMSTART = CDROMSTART;
+ unsigned IOCTL_CDROMSTOP = CDROMSTOP;
+ unsigned IOCTL_CDROMSUBCHNL = CDROMSUBCHNL;
+ unsigned IOCTL_CDROMVOLCTRL = CDROMVOLCTRL;
+ unsigned IOCTL_CDROMVOLREAD = CDROMVOLREAD;
+ unsigned IOCTL_CDROM_GET_UPC = CDROM_GET_UPC;
+ unsigned IOCTL_FDCLRPRM = FDCLRPRM;
+ unsigned IOCTL_FDDEFPRM = FDDEFPRM;
+ unsigned IOCTL_FDFLUSH = FDFLUSH;
+ unsigned IOCTL_FDFMTBEG = FDFMTBEG;
+ unsigned IOCTL_FDFMTEND = FDFMTEND;
+ unsigned IOCTL_FDFMTTRK = FDFMTTRK;
+ unsigned IOCTL_FDGETDRVPRM = FDGETDRVPRM;
+ unsigned IOCTL_FDGETDRVSTAT = FDGETDRVSTAT;
+ unsigned IOCTL_FDGETDRVTYP = FDGETDRVTYP;
+ unsigned IOCTL_FDGETFDCSTAT = FDGETFDCSTAT;
+ unsigned IOCTL_FDGETMAXERRS = FDGETMAXERRS;
+ unsigned IOCTL_FDGETPRM = FDGETPRM;
+ unsigned IOCTL_FDMSGOFF = FDMSGOFF;
+ unsigned IOCTL_FDMSGON = FDMSGON;
+ unsigned IOCTL_FDPOLLDRVSTAT = FDPOLLDRVSTAT;
+ unsigned IOCTL_FDRAWCMD = FDRAWCMD;
+ unsigned IOCTL_FDRESET = FDRESET;
+ unsigned IOCTL_FDSETDRVPRM = FDSETDRVPRM;
+ unsigned IOCTL_FDSETEMSGTRESH = FDSETEMSGTRESH;
+ unsigned IOCTL_FDSETMAXERRS = FDSETMAXERRS;
+ unsigned IOCTL_FDSETPRM = FDSETPRM;
+ unsigned IOCTL_FDTWADDLE = FDTWADDLE;
+ unsigned IOCTL_FDWERRORCLR = FDWERRORCLR;
+ unsigned IOCTL_FDWERRORGET = FDWERRORGET;
+ unsigned IOCTL_HDIO_DRIVE_CMD = HDIO_DRIVE_CMD;
+ unsigned IOCTL_HDIO_GETGEO = HDIO_GETGEO;
+ unsigned IOCTL_HDIO_GET_32BIT = HDIO_GET_32BIT;
+ unsigned IOCTL_HDIO_GET_DMA = HDIO_GET_DMA;
+ unsigned IOCTL_HDIO_GET_IDENTITY = HDIO_GET_IDENTITY;
+ unsigned IOCTL_HDIO_GET_KEEPSETTINGS = HDIO_GET_KEEPSETTINGS;
+ unsigned IOCTL_HDIO_GET_MULTCOUNT = HDIO_GET_MULTCOUNT;
+ unsigned IOCTL_HDIO_GET_NOWERR = HDIO_GET_NOWERR;
+ unsigned IOCTL_HDIO_GET_UNMASKINTR = HDIO_GET_UNMASKINTR;
+ unsigned IOCTL_HDIO_SET_32BIT = HDIO_SET_32BIT;
+ unsigned IOCTL_HDIO_SET_DMA = HDIO_SET_DMA;
+ unsigned IOCTL_HDIO_SET_KEEPSETTINGS = HDIO_SET_KEEPSETTINGS;
+ 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;
+ unsigned IOCTL_PPPIOCGUNIT = PPPIOCGUNIT;
+ unsigned IOCTL_PPPIOCGXASYNCMAP = PPPIOCGXASYNCMAP;
+ unsigned IOCTL_PPPIOCSASYNCMAP = PPPIOCSASYNCMAP;
+ unsigned IOCTL_PPPIOCSDEBUG = PPPIOCSDEBUG;
+ unsigned IOCTL_PPPIOCSFLAGS = PPPIOCSFLAGS;
+ unsigned IOCTL_PPPIOCSMAXCID = PPPIOCSMAXCID;
+ unsigned IOCTL_PPPIOCSMRU = PPPIOCSMRU;
+ unsigned IOCTL_PPPIOCSXASYNCMAP = PPPIOCSXASYNCMAP;
+ unsigned IOCTL_SIOCADDRT = SIOCADDRT;
+ unsigned IOCTL_SIOCDARP = SIOCDARP;
+ unsigned IOCTL_SIOCDELRT = SIOCDELRT;
+ unsigned IOCTL_SIOCDRARP = SIOCDRARP;
+ unsigned IOCTL_SIOCGARP = SIOCGARP;
+ unsigned IOCTL_SIOCGIFENCAP = SIOCGIFENCAP;
+ unsigned IOCTL_SIOCGIFHWADDR = SIOCGIFHWADDR;
+ unsigned IOCTL_SIOCGIFMAP = SIOCGIFMAP;
+ unsigned IOCTL_SIOCGIFMEM = SIOCGIFMEM;
+ unsigned IOCTL_SIOCGIFNAME = SIOCGIFNAME;
+ unsigned IOCTL_SIOCGIFSLAVE = SIOCGIFSLAVE;
+ unsigned IOCTL_SIOCGRARP = SIOCGRARP;
+ unsigned IOCTL_SIOCGSTAMP = SIOCGSTAMP;
+ unsigned IOCTL_SIOCSARP = SIOCSARP;
+ unsigned IOCTL_SIOCSIFENCAP = SIOCSIFENCAP;
+ unsigned IOCTL_SIOCSIFHWADDR = SIOCSIFHWADDR;
+ unsigned IOCTL_SIOCSIFLINK = SIOCSIFLINK;
+ unsigned IOCTL_SIOCSIFMAP = SIOCSIFMAP;
+ unsigned IOCTL_SIOCSIFMEM = SIOCSIFMEM;
+ unsigned IOCTL_SIOCSIFSLAVE = SIOCSIFSLAVE;
+ unsigned IOCTL_SIOCSRARP = SIOCSRARP;
+#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;
+ unsigned IOCTL_SNDCTL_COPR_RCVMSG = IOCTL_NOT_PRESENT;
+ unsigned IOCTL_SNDCTL_COPR_RDATA = IOCTL_NOT_PRESENT;
+ unsigned IOCTL_SNDCTL_COPR_RESET = IOCTL_NOT_PRESENT;
+ unsigned IOCTL_SNDCTL_COPR_RUN = IOCTL_NOT_PRESENT;
+ unsigned IOCTL_SNDCTL_COPR_SENDMSG = IOCTL_NOT_PRESENT;
+ unsigned IOCTL_SNDCTL_COPR_WCODE = IOCTL_NOT_PRESENT;
+ unsigned IOCTL_SNDCTL_COPR_WDATA = IOCTL_NOT_PRESENT;
+ unsigned IOCTL_SOUND_PCM_READ_BITS = IOCTL_NOT_PRESENT;
+ unsigned IOCTL_SOUND_PCM_READ_CHANNELS = IOCTL_NOT_PRESENT;
+ unsigned IOCTL_SOUND_PCM_READ_FILTER = IOCTL_NOT_PRESENT;
+ 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
+ unsigned IOCTL_SNDCTL_COPR_HALT = SNDCTL_COPR_HALT;
+ unsigned IOCTL_SNDCTL_COPR_LOAD = SNDCTL_COPR_LOAD;
+ unsigned IOCTL_SNDCTL_COPR_RCODE = SNDCTL_COPR_RCODE;
+ unsigned IOCTL_SNDCTL_COPR_RCVMSG = SNDCTL_COPR_RCVMSG;
+ unsigned IOCTL_SNDCTL_COPR_RDATA = SNDCTL_COPR_RDATA;
+ unsigned IOCTL_SNDCTL_COPR_RESET = SNDCTL_COPR_RESET;
+ unsigned IOCTL_SNDCTL_COPR_RUN = SNDCTL_COPR_RUN;
+ unsigned IOCTL_SNDCTL_COPR_SENDMSG = SNDCTL_COPR_SENDMSG;
+ unsigned IOCTL_SNDCTL_COPR_WCODE = SNDCTL_COPR_WCODE;
+ unsigned IOCTL_SNDCTL_COPR_WDATA = SNDCTL_COPR_WDATA;
+ unsigned IOCTL_SOUND_PCM_READ_BITS = SOUND_PCM_READ_BITS;
+ unsigned IOCTL_SOUND_PCM_READ_CHANNELS = SOUND_PCM_READ_CHANNELS;
+ unsigned IOCTL_SOUND_PCM_READ_FILTER = SOUND_PCM_READ_FILTER;
+ 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
+ unsigned IOCTL_SNDCTL_DSP_GETBLKSIZE = SNDCTL_DSP_GETBLKSIZE;
+ unsigned IOCTL_SNDCTL_DSP_GETFMTS = SNDCTL_DSP_GETFMTS;
+ unsigned IOCTL_SNDCTL_DSP_NONBLOCK = SNDCTL_DSP_NONBLOCK;
+ unsigned IOCTL_SNDCTL_DSP_POST = SNDCTL_DSP_POST;
+ unsigned IOCTL_SNDCTL_DSP_RESET = SNDCTL_DSP_RESET;
+ unsigned IOCTL_SNDCTL_DSP_SETFMT = SNDCTL_DSP_SETFMT;
+ unsigned IOCTL_SNDCTL_DSP_SETFRAGMENT = SNDCTL_DSP_SETFRAGMENT;
+ unsigned IOCTL_SNDCTL_DSP_SPEED = SNDCTL_DSP_SPEED;
+ unsigned IOCTL_SNDCTL_DSP_STEREO = SNDCTL_DSP_STEREO;
+ unsigned IOCTL_SNDCTL_DSP_SUBDIVIDE = SNDCTL_DSP_SUBDIVIDE;
+ unsigned IOCTL_SNDCTL_DSP_SYNC = SNDCTL_DSP_SYNC;
+ unsigned IOCTL_SNDCTL_FM_4OP_ENABLE = SNDCTL_FM_4OP_ENABLE;
+ unsigned IOCTL_SNDCTL_FM_LOAD_INSTR = SNDCTL_FM_LOAD_INSTR;
+ unsigned IOCTL_SNDCTL_MIDI_INFO = SNDCTL_MIDI_INFO;
+ unsigned IOCTL_SNDCTL_MIDI_PRETIME = SNDCTL_MIDI_PRETIME;
+ unsigned IOCTL_SNDCTL_SEQ_CTRLRATE = SNDCTL_SEQ_CTRLRATE;
+ unsigned IOCTL_SNDCTL_SEQ_GETINCOUNT = SNDCTL_SEQ_GETINCOUNT;
+ unsigned IOCTL_SNDCTL_SEQ_GETOUTCOUNT = SNDCTL_SEQ_GETOUTCOUNT;
+ unsigned IOCTL_SNDCTL_SEQ_NRMIDIS = SNDCTL_SEQ_NRMIDIS;
+ unsigned IOCTL_SNDCTL_SEQ_NRSYNTHS = SNDCTL_SEQ_NRSYNTHS;
+ unsigned IOCTL_SNDCTL_SEQ_OUTOFBAND = SNDCTL_SEQ_OUTOFBAND;
+ unsigned IOCTL_SNDCTL_SEQ_PANIC = SNDCTL_SEQ_PANIC;
+ unsigned IOCTL_SNDCTL_SEQ_PERCMODE = SNDCTL_SEQ_PERCMODE;
+ unsigned IOCTL_SNDCTL_SEQ_RESET = SNDCTL_SEQ_RESET;
+ unsigned IOCTL_SNDCTL_SEQ_RESETSAMPLES = SNDCTL_SEQ_RESETSAMPLES;
+ unsigned IOCTL_SNDCTL_SEQ_SYNC = SNDCTL_SEQ_SYNC;
+ unsigned IOCTL_SNDCTL_SEQ_TESTMIDI = SNDCTL_SEQ_TESTMIDI;
+ unsigned IOCTL_SNDCTL_SEQ_THRESHOLD = SNDCTL_SEQ_THRESHOLD;
+ unsigned IOCTL_SNDCTL_SYNTH_INFO = SNDCTL_SYNTH_INFO;
+ unsigned IOCTL_SNDCTL_SYNTH_MEMAVL = SNDCTL_SYNTH_MEMAVL;
+ unsigned IOCTL_SNDCTL_TMR_CONTINUE = SNDCTL_TMR_CONTINUE;
+ unsigned IOCTL_SNDCTL_TMR_METRONOME = SNDCTL_TMR_METRONOME;
+ unsigned IOCTL_SNDCTL_TMR_SELECT = SNDCTL_TMR_SELECT;
+ unsigned IOCTL_SNDCTL_TMR_SOURCE = SNDCTL_TMR_SOURCE;
+ unsigned IOCTL_SNDCTL_TMR_START = SNDCTL_TMR_START;
+ unsigned IOCTL_SNDCTL_TMR_STOP = SNDCTL_TMR_STOP;
+ unsigned IOCTL_SNDCTL_TMR_TEMPO = SNDCTL_TMR_TEMPO;
+ unsigned IOCTL_SNDCTL_TMR_TIMEBASE = SNDCTL_TMR_TIMEBASE;
+ unsigned IOCTL_SOUND_MIXER_READ_ALTPCM = SOUND_MIXER_READ_ALTPCM;
+ unsigned IOCTL_SOUND_MIXER_READ_BASS = SOUND_MIXER_READ_BASS;
+ unsigned IOCTL_SOUND_MIXER_READ_CAPS = SOUND_MIXER_READ_CAPS;
+ unsigned IOCTL_SOUND_MIXER_READ_CD = SOUND_MIXER_READ_CD;
+ unsigned IOCTL_SOUND_MIXER_READ_DEVMASK = SOUND_MIXER_READ_DEVMASK;
+ unsigned IOCTL_SOUND_MIXER_READ_ENHANCE = SOUND_MIXER_READ_ENHANCE;
+ unsigned IOCTL_SOUND_MIXER_READ_IGAIN = SOUND_MIXER_READ_IGAIN;
+ unsigned IOCTL_SOUND_MIXER_READ_IMIX = SOUND_MIXER_READ_IMIX;
+ unsigned IOCTL_SOUND_MIXER_READ_LINE = SOUND_MIXER_READ_LINE;
+ unsigned IOCTL_SOUND_MIXER_READ_LINE1 = SOUND_MIXER_READ_LINE1;
+ unsigned IOCTL_SOUND_MIXER_READ_LINE2 = SOUND_MIXER_READ_LINE2;
+ unsigned IOCTL_SOUND_MIXER_READ_LINE3 = SOUND_MIXER_READ_LINE3;
+ unsigned IOCTL_SOUND_MIXER_READ_LOUD = SOUND_MIXER_READ_LOUD;
+ unsigned IOCTL_SOUND_MIXER_READ_MIC = SOUND_MIXER_READ_MIC;
+ unsigned IOCTL_SOUND_MIXER_READ_MUTE = SOUND_MIXER_READ_MUTE;
+ unsigned IOCTL_SOUND_MIXER_READ_OGAIN = SOUND_MIXER_READ_OGAIN;
+ unsigned IOCTL_SOUND_MIXER_READ_PCM = SOUND_MIXER_READ_PCM;
+ unsigned IOCTL_SOUND_MIXER_READ_RECLEV = SOUND_MIXER_READ_RECLEV;
+ unsigned IOCTL_SOUND_MIXER_READ_RECMASK = SOUND_MIXER_READ_RECMASK;
+ unsigned IOCTL_SOUND_MIXER_READ_RECSRC = SOUND_MIXER_READ_RECSRC;
+ unsigned IOCTL_SOUND_MIXER_READ_SPEAKER = SOUND_MIXER_READ_SPEAKER;
+ unsigned IOCTL_SOUND_MIXER_READ_STEREODEVS = SOUND_MIXER_READ_STEREODEVS;
+ unsigned IOCTL_SOUND_MIXER_READ_SYNTH = SOUND_MIXER_READ_SYNTH;
+ unsigned IOCTL_SOUND_MIXER_READ_TREBLE = SOUND_MIXER_READ_TREBLE;
+ unsigned IOCTL_SOUND_MIXER_READ_VOLUME = SOUND_MIXER_READ_VOLUME;
+ unsigned IOCTL_SOUND_MIXER_WRITE_ALTPCM = SOUND_MIXER_WRITE_ALTPCM;
+ unsigned IOCTL_SOUND_MIXER_WRITE_BASS = SOUND_MIXER_WRITE_BASS;
+ unsigned IOCTL_SOUND_MIXER_WRITE_CD = SOUND_MIXER_WRITE_CD;
+ unsigned IOCTL_SOUND_MIXER_WRITE_ENHANCE = SOUND_MIXER_WRITE_ENHANCE;
+ unsigned IOCTL_SOUND_MIXER_WRITE_IGAIN = SOUND_MIXER_WRITE_IGAIN;
+ unsigned IOCTL_SOUND_MIXER_WRITE_IMIX = SOUND_MIXER_WRITE_IMIX;
+ unsigned IOCTL_SOUND_MIXER_WRITE_LINE = SOUND_MIXER_WRITE_LINE;
+ unsigned IOCTL_SOUND_MIXER_WRITE_LINE1 = SOUND_MIXER_WRITE_LINE1;
+ unsigned IOCTL_SOUND_MIXER_WRITE_LINE2 = SOUND_MIXER_WRITE_LINE2;
+ unsigned IOCTL_SOUND_MIXER_WRITE_LINE3 = SOUND_MIXER_WRITE_LINE3;
+ unsigned IOCTL_SOUND_MIXER_WRITE_LOUD = SOUND_MIXER_WRITE_LOUD;
+ unsigned IOCTL_SOUND_MIXER_WRITE_MIC = SOUND_MIXER_WRITE_MIC;
+ unsigned IOCTL_SOUND_MIXER_WRITE_MUTE = SOUND_MIXER_WRITE_MUTE;
+ unsigned IOCTL_SOUND_MIXER_WRITE_OGAIN = SOUND_MIXER_WRITE_OGAIN;
+ unsigned IOCTL_SOUND_MIXER_WRITE_PCM = SOUND_MIXER_WRITE_PCM;
+ unsigned IOCTL_SOUND_MIXER_WRITE_RECLEV = SOUND_MIXER_WRITE_RECLEV;
+ unsigned IOCTL_SOUND_MIXER_WRITE_RECSRC = SOUND_MIXER_WRITE_RECSRC;
+ unsigned IOCTL_SOUND_MIXER_WRITE_SPEAKER = SOUND_MIXER_WRITE_SPEAKER;
+ 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
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+ unsigned IOCTL_CYGETDEFTHRESH = CYGETDEFTHRESH;
+ unsigned IOCTL_CYGETDEFTIMEOUT = CYGETDEFTIMEOUT;
+ unsigned IOCTL_CYGETMON = CYGETMON;
+ unsigned IOCTL_CYGETTHRESH = CYGETTHRESH;
+ unsigned IOCTL_CYGETTIMEOUT = CYGETTIMEOUT;
+ unsigned IOCTL_CYSETDEFTHRESH = CYSETDEFTHRESH;
+ unsigned IOCTL_CYSETDEFTIMEOUT = CYSETDEFTIMEOUT;
+ unsigned IOCTL_CYSETTHRESH = CYSETTHRESH;
+ unsigned IOCTL_CYSETTIMEOUT = CYSETTIMEOUT;
+ unsigned IOCTL_EQL_EMANCIPATE = EQL_EMANCIPATE;
+ unsigned IOCTL_EQL_ENSLAVE = EQL_ENSLAVE;
+ unsigned IOCTL_EQL_GETMASTRCFG = EQL_GETMASTRCFG;
+ unsigned IOCTL_EQL_GETSLAVECFG = EQL_GETSLAVECFG;
+ unsigned IOCTL_EQL_SETMASTRCFG = EQL_SETMASTRCFG;
+ unsigned IOCTL_EQL_SETSLAVECFG = EQL_SETSLAVECFG;
+#if EV_VERSION > (0x010000)
+ unsigned IOCTL_EVIOCGKEYCODE_V2 = EVIOCGKEYCODE_V2;
+ unsigned IOCTL_EVIOCGPROP = EVIOCGPROP(0);
+ unsigned IOCTL_EVIOCSKEYCODE_V2 = EVIOCSKEYCODE_V2;
+#else
+ unsigned IOCTL_EVIOCGKEYCODE_V2 = IOCTL_NOT_PRESENT;
+ unsigned IOCTL_EVIOCGPROP = IOCTL_NOT_PRESENT;
+ unsigned IOCTL_EVIOCSKEYCODE_V2 = IOCTL_NOT_PRESENT;
+#endif
+ unsigned IOCTL_FS_IOC_GETFLAGS = FS_IOC_GETFLAGS;
+ unsigned IOCTL_FS_IOC_GETVERSION = FS_IOC_GETVERSION;
+ unsigned IOCTL_FS_IOC_SETFLAGS = FS_IOC_SETFLAGS;
+ 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;
+ unsigned IOCTL_LPCHAR = LPCHAR;
+ unsigned IOCTL_LPGETIRQ = LPGETIRQ;
+ unsigned IOCTL_LPGETSTATUS = LPGETSTATUS;
+ unsigned IOCTL_LPRESET = LPRESET;
+ unsigned IOCTL_LPSETIRQ = LPSETIRQ;
+ unsigned IOCTL_LPTIME = LPTIME;
+ unsigned IOCTL_LPWAIT = LPWAIT;
+ unsigned IOCTL_MTIOCGETCONFIG = MTIOCGETCONFIG;
+ 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;
+ unsigned IOCTL_SCSI_IOCTL_GET_IDLUN = SCSI_IOCTL_GET_IDLUN;
+ unsigned IOCTL_SCSI_IOCTL_PROBE_HOST = SCSI_IOCTL_PROBE_HOST;
+ unsigned IOCTL_SCSI_IOCTL_TAGGED_DISABLE = SCSI_IOCTL_TAGGED_DISABLE;
+ unsigned IOCTL_SCSI_IOCTL_TAGGED_ENABLE = SCSI_IOCTL_TAGGED_ENABLE;
+ unsigned IOCTL_SIOCAIPXITFCRT = SIOCAIPXITFCRT;
+ unsigned IOCTL_SIOCAIPXPRISLT = SIOCAIPXPRISLT;
+ unsigned IOCTL_SIOCAX25ADDUID = SIOCAX25ADDUID;
+ unsigned IOCTL_SIOCAX25DELUID = SIOCAX25DELUID;
+ unsigned IOCTL_SIOCAX25GETPARMS = SIOCAX25GETPARMS;
+ unsigned IOCTL_SIOCAX25GETUID = SIOCAX25GETUID;
+ unsigned IOCTL_SIOCAX25NOUID = SIOCAX25NOUID;
+ unsigned IOCTL_SIOCAX25SETPARMS = SIOCAX25SETPARMS;
+ unsigned IOCTL_SIOCDEVPLIP = SIOCDEVPLIP;
+ unsigned IOCTL_SIOCIPXCFGDATA = SIOCIPXCFGDATA;
+ unsigned IOCTL_SIOCNRDECOBS = SIOCNRDECOBS;
+ 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
+
+// EOWNERDEAD is not present in some older platforms.
+#if defined(EOWNERDEAD)
+ extern const int errno_EOWNERDEAD = EOWNERDEAD;
+#else
+ extern const int errno_EOWNERDEAD = -1;
+#endif
} // namespace __sanitizer
COMPILER_CHECK(sizeof(__sanitizer_pthread_attr_t) >= sizeof(pthread_attr_t));
-COMPILER_CHECK(sizeof(__sanitizer::struct_sigaction_max_sz) >=
- sizeof(__sanitizer::struct_sigaction_sz));
+
+COMPILER_CHECK(sizeof(socklen_t) == sizeof(unsigned));
+CHECK_TYPE_SIZE(pthread_key_t);
+
#if SANITIZER_LINUX
-COMPILER_CHECK(offsetof(struct __sanitizer_dl_phdr_info, dlpi_addr) ==
- offsetof(struct dl_phdr_info, dlpi_addr));
-COMPILER_CHECK(offsetof(struct __sanitizer_dl_phdr_info, dlpi_name) ==
- offsetof(struct dl_phdr_info, dlpi_name));
-COMPILER_CHECK(offsetof(struct __sanitizer_dl_phdr_info, dlpi_phdr) ==
- offsetof(struct dl_phdr_info, dlpi_phdr));
-COMPILER_CHECK(offsetof(struct __sanitizer_dl_phdr_info, dlpi_phnum) ==
- offsetof(struct dl_phdr_info, dlpi_phnum));
-#endif
-
-COMPILER_CHECK(sizeof(struct __sanitizer_addrinfo) == sizeof(struct addrinfo));
-COMPILER_CHECK(offsetof(struct __sanitizer_addrinfo, ai_addr) ==
- offsetof(struct addrinfo, ai_addr));
-COMPILER_CHECK(offsetof(struct __sanitizer_addrinfo, ai_canonname) ==
- offsetof(struct addrinfo, ai_canonname));
-COMPILER_CHECK(offsetof(struct __sanitizer_addrinfo, ai_next) ==
- offsetof(struct addrinfo, ai_next));
-
-COMPILER_CHECK(sizeof(struct __sanitizer_hostent) == sizeof(struct hostent));
-COMPILER_CHECK(offsetof(struct __sanitizer_hostent, h_name) ==
- offsetof(struct hostent, h_name));
-COMPILER_CHECK(offsetof(struct __sanitizer_hostent, h_aliases) ==
- offsetof(struct hostent, h_aliases));
-COMPILER_CHECK(offsetof(struct __sanitizer_hostent, h_addr_list) ==
- offsetof(struct hostent, h_addr_list));
+// 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));
+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);
+
+COMPILER_CHECK(IOC_SIZE(0x12345678) == _IOC_SIZE(0x12345678));
+#endif
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+CHECK_TYPE_SIZE(glob_t);
+CHECK_SIZE_AND_OFFSET(glob_t, gl_pathc);
+CHECK_SIZE_AND_OFFSET(glob_t, gl_pathv);
+CHECK_SIZE_AND_OFFSET(glob_t, gl_offs);
+CHECK_SIZE_AND_OFFSET(glob_t, gl_flags);
+CHECK_SIZE_AND_OFFSET(glob_t, gl_closedir);
+CHECK_SIZE_AND_OFFSET(glob_t, gl_readdir);
+CHECK_SIZE_AND_OFFSET(glob_t, gl_opendir);
+CHECK_SIZE_AND_OFFSET(glob_t, gl_lstat);
+CHECK_SIZE_AND_OFFSET(glob_t, gl_stat);
+#endif
+
+CHECK_TYPE_SIZE(addrinfo);
+CHECK_SIZE_AND_OFFSET(addrinfo, ai_flags);
+CHECK_SIZE_AND_OFFSET(addrinfo, ai_family);
+CHECK_SIZE_AND_OFFSET(addrinfo, ai_socktype);
+CHECK_SIZE_AND_OFFSET(addrinfo, ai_protocol);
+CHECK_SIZE_AND_OFFSET(addrinfo, ai_protocol);
+CHECK_SIZE_AND_OFFSET(addrinfo, ai_addrlen);
+CHECK_SIZE_AND_OFFSET(addrinfo, ai_canonname);
+CHECK_SIZE_AND_OFFSET(addrinfo, ai_addr);
+
+CHECK_TYPE_SIZE(hostent);
+CHECK_SIZE_AND_OFFSET(hostent, h_name);
+CHECK_SIZE_AND_OFFSET(hostent, h_aliases);
+CHECK_SIZE_AND_OFFSET(hostent, h_addrtype);
+CHECK_SIZE_AND_OFFSET(hostent, h_length);
+CHECK_SIZE_AND_OFFSET(hostent, h_addr_list);
+
+CHECK_TYPE_SIZE(iovec);
+CHECK_SIZE_AND_OFFSET(iovec, iov_base);
+CHECK_SIZE_AND_OFFSET(iovec, iov_len);
+
+CHECK_TYPE_SIZE(msghdr);
+CHECK_SIZE_AND_OFFSET(msghdr, msg_name);
+CHECK_SIZE_AND_OFFSET(msghdr, msg_namelen);
+CHECK_SIZE_AND_OFFSET(msghdr, msg_iov);
+CHECK_SIZE_AND_OFFSET(msghdr, msg_iovlen);
+CHECK_SIZE_AND_OFFSET(msghdr, msg_control);
+CHECK_SIZE_AND_OFFSET(msghdr, msg_controllen);
+CHECK_SIZE_AND_OFFSET(msghdr, msg_flags);
+
+CHECK_TYPE_SIZE(cmsghdr);
+CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_len);
+CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_level);
+CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_type);
+
+COMPILER_CHECK(sizeof(__sanitizer_dirent) <= sizeof(dirent));
+CHECK_SIZE_AND_OFFSET(dirent, d_ino);
+#if SANITIZER_MAC
+CHECK_SIZE_AND_OFFSET(dirent, d_seekoff);
+#else
+CHECK_SIZE_AND_OFFSET(dirent, d_off);
+#endif
+CHECK_SIZE_AND_OFFSET(dirent, d_reclen);
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+COMPILER_CHECK(sizeof(__sanitizer_dirent64) <= sizeof(dirent64));
+CHECK_SIZE_AND_OFFSET(dirent64, d_ino);
+CHECK_SIZE_AND_OFFSET(dirent64, d_off);
+CHECK_SIZE_AND_OFFSET(dirent64, d_reclen);
+#endif
+
+CHECK_TYPE_SIZE(ifconf);
+CHECK_SIZE_AND_OFFSET(ifconf, ifc_len);
+CHECK_SIZE_AND_OFFSET(ifconf, ifc_ifcu);
+
+CHECK_TYPE_SIZE(pollfd);
+CHECK_SIZE_AND_OFFSET(pollfd, fd);
+CHECK_SIZE_AND_OFFSET(pollfd, events);
+CHECK_SIZE_AND_OFFSET(pollfd, revents);
+
+CHECK_TYPE_SIZE(nfds_t);
+
+CHECK_TYPE_SIZE(sigset_t);
+
+COMPILER_CHECK(sizeof(__sanitizer_sigaction) == sizeof(struct sigaction));
+// Can't write checks for sa_handler and sa_sigaction due to them being
+// preprocessor macros.
+CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_mask);
+CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_flags);
+#if SANITIZER_LINUX
+CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_restorer);
+#endif
+
+#if SANITIZER_LINUX
+CHECK_TYPE_SIZE(__sysctl_args);
+CHECK_SIZE_AND_OFFSET(__sysctl_args, name);
+CHECK_SIZE_AND_OFFSET(__sysctl_args, nlen);
+CHECK_SIZE_AND_OFFSET(__sysctl_args, oldval);
+CHECK_SIZE_AND_OFFSET(__sysctl_args, oldlenp);
+CHECK_SIZE_AND_OFFSET(__sysctl_args, newval);
+CHECK_SIZE_AND_OFFSET(__sysctl_args, newlen);
+
+CHECK_TYPE_SIZE(__kernel_uid_t);
+CHECK_TYPE_SIZE(__kernel_gid_t);
+CHECK_TYPE_SIZE(__kernel_old_uid_t);
+CHECK_TYPE_SIZE(__kernel_old_gid_t);
+CHECK_TYPE_SIZE(__kernel_off_t);
+CHECK_TYPE_SIZE(__kernel_loff_t);
+CHECK_TYPE_SIZE(__kernel_fd_set);
+#endif
+
+#if !SANITIZER_ANDROID
+CHECK_TYPE_SIZE(wordexp_t);
+CHECK_SIZE_AND_OFFSET(wordexp_t, we_wordc);
+CHECK_SIZE_AND_OFFSET(wordexp_t, we_wordv);
+CHECK_SIZE_AND_OFFSET(wordexp_t, we_offs);
+#endif
+
+CHECK_TYPE_SIZE(tm);
+CHECK_SIZE_AND_OFFSET(tm, tm_sec);
+CHECK_SIZE_AND_OFFSET(tm, tm_min);
+CHECK_SIZE_AND_OFFSET(tm, tm_hour);
+CHECK_SIZE_AND_OFFSET(tm, tm_mday);
+CHECK_SIZE_AND_OFFSET(tm, tm_mon);
+CHECK_SIZE_AND_OFFSET(tm, tm_year);
+CHECK_SIZE_AND_OFFSET(tm, tm_wday);
+CHECK_SIZE_AND_OFFSET(tm, tm_yday);
+CHECK_SIZE_AND_OFFSET(tm, tm_isdst);
+CHECK_SIZE_AND_OFFSET(tm, tm_gmtoff);
+CHECK_SIZE_AND_OFFSET(tm, tm_zone);
+
+#if SANITIZER_LINUX
+CHECK_TYPE_SIZE(mntent);
+CHECK_SIZE_AND_OFFSET(mntent, mnt_fsname);
+CHECK_SIZE_AND_OFFSET(mntent, mnt_dir);
+CHECK_SIZE_AND_OFFSET(mntent, mnt_type);
+CHECK_SIZE_AND_OFFSET(mntent, mnt_opts);
+CHECK_SIZE_AND_OFFSET(mntent, mnt_freq);
+CHECK_SIZE_AND_OFFSET(mntent, mnt_passno);
+#endif
+
+CHECK_TYPE_SIZE(ether_addr);
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+CHECK_TYPE_SIZE(ipc_perm);
+CHECK_SIZE_AND_OFFSET(ipc_perm, __key);
+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);
+CHECK_SIZE_AND_OFFSET(shmid_ds, shm_segsz);
+CHECK_SIZE_AND_OFFSET(shmid_ds, shm_atime);
+CHECK_SIZE_AND_OFFSET(shmid_ds, shm_dtime);
+CHECK_SIZE_AND_OFFSET(shmid_ds, shm_ctime);
+CHECK_SIZE_AND_OFFSET(shmid_ds, shm_cpid);
+CHECK_SIZE_AND_OFFSET(shmid_ds, shm_lpid);
+CHECK_SIZE_AND_OFFSET(shmid_ds, shm_nattch);
+#endif
#endif // SANITIZER_LINUX || SANITIZER_MAC
diff --git a/lib/sanitizer_common/sanitizer_platform_limits_posix.h b/lib/sanitizer_common/sanitizer_platform_limits_posix.h
index 37581953db24..b9a0fc98c017 100644
--- a/lib/sanitizer_common/sanitizer_platform_limits_posix.h
+++ b/lib/sanitizer_common/sanitizer_platform_limits_posix.h
@@ -15,44 +15,306 @@
#ifndef SANITIZER_PLATFORM_LIMITS_POSIX_H
#define SANITIZER_PLATFORM_LIMITS_POSIX_H
+#include "sanitizer_internal_defs.h"
#include "sanitizer_platform.h"
namespace __sanitizer {
extern unsigned struct_utsname_sz;
extern unsigned struct_stat_sz;
+#if !SANITIZER_IOS
extern unsigned struct_stat64_sz;
+#endif
extern unsigned struct_rusage_sz;
- extern unsigned struct_tm_sz;
extern unsigned struct_passwd_sz;
extern unsigned struct_group_sz;
- extern unsigned struct_sigaction_sz;
extern unsigned siginfo_t_sz;
extern unsigned struct_itimerval_sz;
extern unsigned pthread_t_sz;
- extern unsigned struct_sockaddr_sz;
+ extern unsigned pthread_cond_t_sz;
+ extern unsigned pid_t_sz;
+ extern unsigned timeval_sz;
+ extern unsigned uid_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 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(__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;
+#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_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;
+
extern unsigned struct_rlimit_sz;
- extern unsigned struct_dirent_sz;
- extern unsigned struct_statfs_sz;
extern unsigned struct_epoll_event_sz;
+ extern unsigned struct_sysinfo_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;
+ u32 aio_key_or_aio_reserved1; // Simply crazy.
+ u32 aio_reserved1_or_aio_key; // Luckily, we don't need these.
+ u16 aio_lio_opcode;
+ s16 aio_reqprio;
+ u32 aio_fildes;
+ u64 aio_buf;
+ u64 aio_nbytes;
+ s64 aio_offset;
+ u64 aio_reserved2;
+ u64 aio_reserved3;
+ };
+
+ const unsigned iocb_cmd_pread = 0;
+ const unsigned iocb_cmd_pwrite = 1;
+
+ struct __sanitizer___sysctl_args {
+ int *name;
+ int nlen;
+ void *oldval;
+ uptr *oldlenp;
+ void *newval;
+ uptr newlen;
+ unsigned long ___unused[4];
+ };
#endif // SANITIZER_LINUX
#if SANITIZER_LINUX && !SANITIZER_ANDROID
- extern unsigned struct_dirent64_sz;
extern unsigned struct_rlimit64_sz;
- extern unsigned struct_statfs64_sz;
-#endif // SANITIZER_LINUX && !SANITIZER_ANDROID
+ extern unsigned struct_statvfs_sz;
+ extern unsigned struct_statvfs64_sz;
+
+ struct __sanitizer_ipc_perm {
+ int __key;
+ int uid;
+ int gid;
+ int cuid;
+ int cgid;
+#ifdef __powerpc__
+ unsigned mode;
+ unsigned __seq;
+ u64 __unused1;
+ u64 __unused2;
+#else
+ unsigned short mode;
+ unsigned short __pad1;
+ unsigned short __seq;
+ unsigned short __pad2;
+#if defined(__x86_64__) && !defined(_LP64)
+ u64 __unused1;
+ u64 __unused2;
+#else
+ unsigned long __unused1;
+ unsigned long __unused2;
+#endif
+#endif
+ };
+
+ struct __sanitizer_shmid_ds {
+ __sanitizer_ipc_perm shm_perm;
+ #ifndef __powerpc__
+ uptr shm_segsz;
+ #elif !defined(__powerpc64__)
+ uptr __unused0;
+ #endif
+ uptr shm_atime;
+ #ifndef _LP64
+ uptr __unused1;
+ #endif
+ uptr shm_dtime;
+ #ifndef _LP64
+ uptr __unused2;
+ #endif
+ uptr shm_ctime;
+ #ifndef _LP64
+ uptr __unused3;
+ #endif
+ #ifdef __powerpc__
+ uptr shm_segsz;
+ #endif
+ int shm_cpid;
+ int shm_lpid;
+ uptr shm_nattch;
+ uptr __unused4;
+ uptr __unused5;
+ };
+ #endif // SANITIZER_LINUX && !SANITIZER_ANDROID
+
+ struct __sanitizer_iovec {
+ void *iov_base;
+ uptr iov_len;
+ };
+
+#if SANITIZER_MAC
+ typedef unsigned long __sanitizer_pthread_key_t;
+#else
+ typedef unsigned __sanitizer_pthread_key_t;
+#endif
+
+ struct __sanitizer_ether_addr {
+ u8 octet[6];
+ };
+
+ struct __sanitizer_tm {
+ int tm_sec;
+ int tm_min;
+ int tm_hour;
+ int tm_mday;
+ int tm_mon;
+ int tm_year;
+ int tm_wday;
+ int tm_yday;
+ int tm_isdst;
+ long int tm_gmtoff;
+ const char *tm_zone;
+ };
+
+#if SANITIZER_LINUX
+ struct __sanitizer_mntent {
+ char *mnt_fsname;
+ char *mnt_dir;
+ char *mnt_type;
+ char *mnt_opts;
+ int mnt_freq;
+ int mnt_passno;
+ };
+#endif
+
+#if SANITIZER_ANDROID || SANITIZER_MAC
+ struct __sanitizer_msghdr {
+ void *msg_name;
+ unsigned msg_namelen;
+ struct __sanitizer_iovec *msg_iov;
+ unsigned msg_iovlen;
+ void *msg_control;
+ unsigned msg_controllen;
+ int msg_flags;
+ };
+ struct __sanitizer_cmsghdr {
+ unsigned cmsg_len;
+ int cmsg_level;
+ int cmsg_type;
+ };
+#else
+ struct __sanitizer_msghdr {
+ void *msg_name;
+ unsigned msg_namelen;
+ struct __sanitizer_iovec *msg_iov;
+ uptr msg_iovlen;
+ void *msg_control;
+ uptr msg_controllen;
+ int msg_flags;
+ };
+ struct __sanitizer_cmsghdr {
+ uptr cmsg_len;
+ int cmsg_level;
+ int cmsg_type;
+ };
+#endif
+
+#if SANITIZER_MAC
+ struct __sanitizer_dirent {
+ unsigned long long d_ino;
+ unsigned long long d_seekoff;
+ 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;
+ unsigned long long d_off;
+ unsigned short d_reclen;
+ // more fields that we don't care about
+ };
+#else
+ struct __sanitizer_dirent {
+ uptr d_ino;
+ uptr d_off;
+ unsigned short d_reclen;
+ // more fields that we don't care about
+ };
+#endif
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+ struct __sanitizer_dirent64 {
+ unsigned long long d_ino;
+ unsigned long long d_off;
+ unsigned short d_reclen;
+ // more fields that we don't care about
+ };
+#endif
- void* __sanitizer_get_msghdr_iov_iov_base(void* msg, int idx);
- uptr __sanitizer_get_msghdr_iov_iov_len(void* msg, int idx);
- uptr __sanitizer_get_msghdr_iovlen(void* msg);
- uptr __sanitizer_get_socklen_t(void* socklen_ptr);
+#if SANITIZER_LINUX
+#if defined(_LP64) || defined(__x86_64__) || defined(__powerpc__)
+ typedef unsigned __sanitizer___kernel_uid_t;
+ typedef unsigned __sanitizer___kernel_gid_t;
+#else
+ typedef unsigned short __sanitizer___kernel_uid_t;
+ typedef unsigned short __sanitizer___kernel_gid_t;
+#endif
+#if defined(__x86_64__) && !defined(_LP64)
+ typedef long long __sanitizer___kernel_off_t;
+#else
+ typedef long __sanitizer___kernel_off_t;
+#endif
+
+#if defined(__powerpc__)
+ typedef unsigned int __sanitizer___kernel_old_uid_t;
+ typedef unsigned int __sanitizer___kernel_old_gid_t;
+#else
+ typedef unsigned short __sanitizer___kernel_old_uid_t;
+ typedef unsigned short __sanitizer___kernel_old_gid_t;
+#endif
+
+ typedef long long __sanitizer___kernel_loff_t;
+ typedef struct {
+ unsigned long fds_bits[1024 / (8 * sizeof(long))];
+ } __sanitizer___kernel_fd_set;
+#endif
// This thing depends on the platform. We are only interested in the upper
// limit. Verified with a compiler assert in .cc.
@@ -62,18 +324,53 @@ namespace __sanitizer {
void *align;
};
- uptr __sanitizer_get_sigaction_sa_sigaction(void *act);
- void __sanitizer_set_sigaction_sa_sigaction(void *act, uptr cb);
- bool __sanitizer_get_sigaction_sa_siginfo(void *act);
+#if SANITIZER_ANDROID
+ typedef unsigned long __sanitizer_sigset_t;
+#elif SANITIZER_MAC
+ typedef unsigned __sanitizer_sigset_t;
+#elif SANITIZER_LINUX
+ struct __sanitizer_sigset_t {
+ // The size is determined by looking at sizeof of real sigset_t on linux.
+ uptr val[128 / sizeof(uptr)];
+ };
+#endif
+
+ struct __sanitizer_sigaction {
+ union {
+ void (*sa_handler)(int sig);
+ void (*sa_sigaction)(int sig, void *siginfo, void *uctx);
+ };
+ __sanitizer_sigset_t sa_mask;
+ int sa_flags;
+#if SANITIZER_LINUX
+ void (*sa_restorer)();
+#endif
+ };
+
+ struct __sanitizer_kernel_sigset_t {
+ u8 sig[8];
+ };
- const unsigned struct_sigaction_max_sz = 256;
- union __sanitizer_sigaction {
- char size[struct_sigaction_max_sz]; // NOLINT
+ struct __sanitizer_kernel_sigaction_t {
+ union {
+ void (*sigaction)(int signo, void *info, void *ctx);
+ void (*handler)(int signo);
+ };
+ unsigned long sa_flags;
+ void (*sa_restorer)(void);
+ __sanitizer_kernel_sigset_t sa_mask;
};
extern uptr sig_ign;
extern uptr sig_dfl;
+ extern uptr sa_siginfo;
+
+#if SANITIZER_LINUX
+ extern int e_tabsz;
+#endif
+ extern int af_inet;
+ extern int af_inet6;
uptr __sanitizer_in_addr_sz(int af);
#if SANITIZER_LINUX
@@ -95,7 +392,7 @@ namespace __sanitizer {
char *ai_canonname;
void *ai_addr;
#else // LINUX
- uptr ai_addrlen;
+ unsigned ai_addrlen;
void *ai_addr;
char *ai_canonname;
#endif
@@ -110,6 +407,591 @@ namespace __sanitizer {
char **h_addr_list;
};
+ struct __sanitizer_pollfd {
+ int fd;
+ short events;
+ short revents;
+ };
+
+#if SANITIZER_ANDROID || SANITIZER_MAC
+ typedef unsigned __sanitizer_nfds_t;
+#else
+ typedef unsigned long __sanitizer_nfds_t;
+#endif
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+ struct __sanitizer_glob_t {
+ uptr gl_pathc;
+ char **gl_pathv;
+ uptr gl_offs;
+ int gl_flags;
+
+ void (*gl_closedir)(void *dirp);
+ void *(*gl_readdir)(void *dirp);
+ void *(*gl_opendir)(const char *);
+ int (*gl_lstat)(const char *, void *);
+ int (*gl_stat)(const char *, void *);
+ };
+
+ extern int glob_nomatch;
+ extern int glob_altdirfunc;
+#endif
+
+ extern unsigned path_max;
+
+ struct __sanitizer_wordexp_t {
+ uptr we_wordc;
+ char **we_wordv;
+ uptr we_offs;
+ };
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID && \
+ (defined(__i386) || defined (__x86_64)) // NOLINT
+ extern unsigned struct_user_regs_struct_sz;
+ extern unsigned struct_user_fpregs_struct_sz;
+ extern unsigned struct_user_fpxregs_struct_sz;
+
+ extern int ptrace_peektext;
+ extern int ptrace_peekdata;
+ extern int ptrace_peekuser;
+ extern int ptrace_getregs;
+ extern int ptrace_setregs;
+ extern int ptrace_getfpregs;
+ extern int ptrace_setfpregs;
+ extern int ptrace_getfpxregs;
+ extern int ptrace_setfpxregs;
+ extern int ptrace_getsiginfo;
+ extern int ptrace_setsiginfo;
+ extern int ptrace_getregset;
+ extern int ptrace_setregset;
+#endif
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+ extern unsigned struct_shminfo_sz;
+ extern unsigned struct_shm_info_sz;
+ extern int shmctl_ipc_stat;
+ extern int shmctl_ipc_info;
+ extern int shmctl_shm_info;
+ extern int shmctl_shm_stat;
+#endif
+
+ // ioctl arguments
+ struct __sanitizer_ifconf {
+ int ifc_len;
+ union {
+ void *ifcu_req;
+ } ifc_ifcu;
+#if SANITIZER_MAC
+ } __attribute__((packed));
+#else
+ };
+#endif
+
+#define IOC_SIZE(nr) (((nr) >> 16) & 0x3fff)
+
+ extern unsigned struct_arpreq_sz;
+ extern unsigned struct_ifreq_sz;
+ extern unsigned struct_termios_sz;
+ extern unsigned struct_winsize_sz;
+
+#if SANITIZER_LINUX
+ extern unsigned struct_cdrom_msf_sz;
+ extern unsigned struct_cdrom_multisession_sz;
+ extern unsigned struct_cdrom_read_audio_sz;
+ extern unsigned struct_cdrom_subchnl_sz;
+ extern unsigned struct_cdrom_ti_sz;
+ 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;
+ extern unsigned struct_floppy_fdc_state_sz;
+ extern unsigned struct_floppy_max_errors_sz;
+ extern unsigned struct_floppy_raw_cmd_sz;
+ extern unsigned struct_floppy_struct_sz;
+ extern unsigned struct_floppy_write_errors_sz;
+ extern unsigned struct_format_descr_sz;
+ extern unsigned struct_hd_driveid_sz;
+ extern unsigned struct_hd_geometry_sz;
+ extern unsigned struct_input_absinfo_sz;
+ extern unsigned struct_input_id_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
+
+#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;
+ extern unsigned struct_ipx_config_data_sz;
+ extern unsigned struct_kbdiacrs_sz;
+ extern unsigned struct_kbentry_sz;
+ extern unsigned struct_kbkeycode_sz;
+ 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;
+ extern unsigned struct_serial_struct_sz;
+ extern unsigned struct_sockaddr_ax25_sz;
+ extern unsigned struct_unimapdesc_sz;
+ extern unsigned struct_unimapinit_sz;
+#endif
+
+#if !SANITIZER_ANDROID && !SANITIZER_MAC
+ extern unsigned struct_sioc_sg_req_sz;
+ extern unsigned struct_sioc_vif_req_sz;
+#endif
+
+ // ioctl request identifiers
+
+ // 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 unsigned IOCTL_FIOASYNC;
+ extern unsigned IOCTL_FIOCLEX;
+ extern unsigned IOCTL_FIOGETOWN;
+ extern unsigned IOCTL_FIONBIO;
+ extern unsigned IOCTL_FIONCLEX;
+ extern unsigned IOCTL_FIOSETOWN;
+ extern unsigned IOCTL_SIOCADDMULTI;
+ extern unsigned IOCTL_SIOCATMARK;
+ extern unsigned IOCTL_SIOCDELMULTI;
+ extern unsigned IOCTL_SIOCGIFADDR;
+ extern unsigned IOCTL_SIOCGIFBRDADDR;
+ extern unsigned IOCTL_SIOCGIFCONF;
+ extern unsigned IOCTL_SIOCGIFDSTADDR;
+ extern unsigned IOCTL_SIOCGIFFLAGS;
+ extern unsigned IOCTL_SIOCGIFMETRIC;
+ extern unsigned IOCTL_SIOCGIFMTU;
+ extern unsigned IOCTL_SIOCGIFNETMASK;
+ extern unsigned IOCTL_SIOCGPGRP;
+ extern unsigned IOCTL_SIOCSIFADDR;
+ extern unsigned IOCTL_SIOCSIFBRDADDR;
+ extern unsigned IOCTL_SIOCSIFDSTADDR;
+ extern unsigned IOCTL_SIOCSIFFLAGS;
+ extern unsigned IOCTL_SIOCSIFMETRIC;
+ extern unsigned IOCTL_SIOCSIFMTU;
+ extern unsigned IOCTL_SIOCSIFNETMASK;
+ extern unsigned IOCTL_SIOCSPGRP;
+ extern unsigned IOCTL_TIOCCONS;
+ extern unsigned IOCTL_TIOCEXCL;
+ extern unsigned IOCTL_TIOCGETD;
+ extern unsigned IOCTL_TIOCGPGRP;
+ extern unsigned IOCTL_TIOCGWINSZ;
+ extern unsigned IOCTL_TIOCMBIC;
+ extern unsigned IOCTL_TIOCMBIS;
+ extern unsigned IOCTL_TIOCMGET;
+ extern unsigned IOCTL_TIOCMSET;
+ extern unsigned IOCTL_TIOCNOTTY;
+ extern unsigned IOCTL_TIOCNXCL;
+ extern unsigned IOCTL_TIOCOUTQ;
+ extern unsigned IOCTL_TIOCPKT;
+ extern unsigned IOCTL_TIOCSCTTY;
+ extern unsigned IOCTL_TIOCSETD;
+ extern unsigned IOCTL_TIOCSPGRP;
+ extern unsigned IOCTL_TIOCSTI;
+ extern unsigned IOCTL_TIOCSWINSZ;
+#if (SANITIZER_LINUX && !SANITIZER_ANDROID)
+ extern unsigned IOCTL_SIOCGETSGCNT;
+ extern unsigned IOCTL_SIOCGETVIFCNT;
+#endif
+#if SANITIZER_LINUX
+ extern unsigned IOCTL_EVIOCGABS;
+ extern unsigned IOCTL_EVIOCGBIT;
+ extern unsigned IOCTL_EVIOCGEFFECTS;
+ extern unsigned IOCTL_EVIOCGID;
+ extern unsigned IOCTL_EVIOCGKEY;
+ extern unsigned IOCTL_EVIOCGKEYCODE;
+ extern unsigned IOCTL_EVIOCGLED;
+ extern unsigned IOCTL_EVIOCGNAME;
+ extern unsigned IOCTL_EVIOCGPHYS;
+ extern unsigned IOCTL_EVIOCGRAB;
+ extern unsigned IOCTL_EVIOCGREP;
+ extern unsigned IOCTL_EVIOCGSND;
+ extern unsigned IOCTL_EVIOCGSW;
+ extern unsigned IOCTL_EVIOCGUNIQ;
+ extern unsigned IOCTL_EVIOCGVERSION;
+ extern unsigned IOCTL_EVIOCRMFF;
+ extern unsigned IOCTL_EVIOCSABS;
+ extern unsigned IOCTL_EVIOCSFF;
+ extern unsigned IOCTL_EVIOCSKEYCODE;
+ extern unsigned IOCTL_EVIOCSREP;
+ extern unsigned IOCTL_BLKFLSBUF;
+ extern unsigned IOCTL_BLKGETSIZE;
+ extern unsigned IOCTL_BLKRAGET;
+ extern unsigned IOCTL_BLKRASET;
+ extern unsigned IOCTL_BLKROGET;
+ extern unsigned IOCTL_BLKROSET;
+ extern unsigned IOCTL_BLKRRPART;
+ extern unsigned IOCTL_CDROMAUDIOBUFSIZ;
+ extern unsigned IOCTL_CDROMEJECT;
+ extern unsigned IOCTL_CDROMEJECT_SW;
+ extern unsigned IOCTL_CDROMMULTISESSION;
+ extern unsigned IOCTL_CDROMPAUSE;
+ extern unsigned IOCTL_CDROMPLAYMSF;
+ extern unsigned IOCTL_CDROMPLAYTRKIND;
+ extern unsigned IOCTL_CDROMREADAUDIO;
+ extern unsigned IOCTL_CDROMREADCOOKED;
+ extern unsigned IOCTL_CDROMREADMODE1;
+ extern unsigned IOCTL_CDROMREADMODE2;
+ extern unsigned IOCTL_CDROMREADRAW;
+ extern unsigned IOCTL_CDROMREADTOCENTRY;
+ extern unsigned IOCTL_CDROMREADTOCHDR;
+ extern unsigned IOCTL_CDROMRESET;
+ extern unsigned IOCTL_CDROMRESUME;
+ extern unsigned IOCTL_CDROMSEEK;
+ extern unsigned IOCTL_CDROMSTART;
+ extern unsigned IOCTL_CDROMSTOP;
+ extern unsigned IOCTL_CDROMSUBCHNL;
+ extern unsigned IOCTL_CDROMVOLCTRL;
+ extern unsigned IOCTL_CDROMVOLREAD;
+ extern unsigned IOCTL_CDROM_GET_UPC;
+ extern unsigned IOCTL_FDCLRPRM;
+ extern unsigned IOCTL_FDDEFPRM;
+ extern unsigned IOCTL_FDFLUSH;
+ extern unsigned IOCTL_FDFMTBEG;
+ extern unsigned IOCTL_FDFMTEND;
+ extern unsigned IOCTL_FDFMTTRK;
+ extern unsigned IOCTL_FDGETDRVPRM;
+ extern unsigned IOCTL_FDGETDRVSTAT;
+ extern unsigned IOCTL_FDGETDRVTYP;
+ extern unsigned IOCTL_FDGETFDCSTAT;
+ extern unsigned IOCTL_FDGETMAXERRS;
+ extern unsigned IOCTL_FDGETPRM;
+ extern unsigned IOCTL_FDMSGOFF;
+ extern unsigned IOCTL_FDMSGON;
+ extern unsigned IOCTL_FDPOLLDRVSTAT;
+ extern unsigned IOCTL_FDRAWCMD;
+ extern unsigned IOCTL_FDRESET;
+ extern unsigned IOCTL_FDSETDRVPRM;
+ extern unsigned IOCTL_FDSETEMSGTRESH;
+ extern unsigned IOCTL_FDSETMAXERRS;
+ extern unsigned IOCTL_FDSETPRM;
+ extern unsigned IOCTL_FDTWADDLE;
+ extern unsigned IOCTL_FDWERRORCLR;
+ extern unsigned IOCTL_FDWERRORGET;
+ extern unsigned IOCTL_HDIO_DRIVE_CMD;
+ extern unsigned IOCTL_HDIO_GETGEO;
+ extern unsigned IOCTL_HDIO_GET_32BIT;
+ extern unsigned IOCTL_HDIO_GET_DMA;
+ extern unsigned IOCTL_HDIO_GET_IDENTITY;
+ extern unsigned IOCTL_HDIO_GET_KEEPSETTINGS;
+ extern unsigned IOCTL_HDIO_GET_MULTCOUNT;
+ extern unsigned IOCTL_HDIO_GET_NOWERR;
+ extern unsigned IOCTL_HDIO_GET_UNMASKINTR;
+ extern unsigned IOCTL_HDIO_SET_32BIT;
+ extern unsigned IOCTL_HDIO_SET_DMA;
+ extern unsigned IOCTL_HDIO_SET_KEEPSETTINGS;
+ 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;
+ extern unsigned IOCTL_PPPIOCGUNIT;
+ extern unsigned IOCTL_PPPIOCGXASYNCMAP;
+ extern unsigned IOCTL_PPPIOCSASYNCMAP;
+ extern unsigned IOCTL_PPPIOCSDEBUG;
+ extern unsigned IOCTL_PPPIOCSFLAGS;
+ 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;
+ extern unsigned IOCTL_SIOCGIFHWADDR;
+ extern unsigned IOCTL_SIOCGIFMAP;
+ extern unsigned IOCTL_SIOCGIFMEM;
+ extern unsigned IOCTL_SIOCGIFNAME;
+ extern unsigned IOCTL_SIOCGIFSLAVE;
+ extern unsigned IOCTL_SIOCGRARP;
+ extern unsigned IOCTL_SIOCGSTAMP;
+ extern unsigned IOCTL_SIOCSARP;
+ extern unsigned IOCTL_SIOCSIFENCAP;
+ extern unsigned IOCTL_SIOCSIFHWADDR;
+ extern unsigned IOCTL_SIOCSIFLINK;
+ extern unsigned IOCTL_SIOCSIFMAP;
+ extern unsigned IOCTL_SIOCSIFMEM;
+ extern unsigned IOCTL_SIOCSIFSLAVE;
+ extern unsigned IOCTL_SIOCSRARP;
+ extern unsigned IOCTL_SNDCTL_COPR_HALT;
+ extern unsigned IOCTL_SNDCTL_COPR_LOAD;
+ extern unsigned IOCTL_SNDCTL_COPR_RCODE;
+ extern unsigned IOCTL_SNDCTL_COPR_RCVMSG;
+ extern unsigned IOCTL_SNDCTL_COPR_RDATA;
+ extern unsigned IOCTL_SNDCTL_COPR_RESET;
+ extern unsigned IOCTL_SNDCTL_COPR_RUN;
+ extern unsigned IOCTL_SNDCTL_COPR_SENDMSG;
+ extern unsigned IOCTL_SNDCTL_COPR_WCODE;
+ extern unsigned IOCTL_SNDCTL_COPR_WDATA;
+ extern unsigned IOCTL_SNDCTL_DSP_GETBLKSIZE;
+ extern unsigned IOCTL_SNDCTL_DSP_GETFMTS;
+ extern unsigned IOCTL_SNDCTL_DSP_NONBLOCK;
+ extern unsigned IOCTL_SNDCTL_DSP_POST;
+ extern unsigned IOCTL_SNDCTL_DSP_RESET;
+ extern unsigned IOCTL_SNDCTL_DSP_SETFMT;
+ extern unsigned IOCTL_SNDCTL_DSP_SETFRAGMENT;
+ extern unsigned IOCTL_SNDCTL_DSP_SPEED;
+ extern unsigned IOCTL_SNDCTL_DSP_STEREO;
+ extern unsigned IOCTL_SNDCTL_DSP_SUBDIVIDE;
+ extern unsigned IOCTL_SNDCTL_DSP_SYNC;
+ extern unsigned IOCTL_SNDCTL_FM_4OP_ENABLE;
+ extern unsigned IOCTL_SNDCTL_FM_LOAD_INSTR;
+ extern unsigned IOCTL_SNDCTL_MIDI_INFO;
+ extern unsigned IOCTL_SNDCTL_MIDI_PRETIME;
+ extern unsigned IOCTL_SNDCTL_SEQ_CTRLRATE;
+ extern unsigned IOCTL_SNDCTL_SEQ_GETINCOUNT;
+ extern unsigned IOCTL_SNDCTL_SEQ_GETOUTCOUNT;
+ extern unsigned IOCTL_SNDCTL_SEQ_NRMIDIS;
+ extern unsigned IOCTL_SNDCTL_SEQ_NRSYNTHS;
+ extern unsigned IOCTL_SNDCTL_SEQ_OUTOFBAND;
+ extern unsigned IOCTL_SNDCTL_SEQ_PANIC;
+ extern unsigned IOCTL_SNDCTL_SEQ_PERCMODE;
+ extern unsigned IOCTL_SNDCTL_SEQ_RESET;
+ extern unsigned IOCTL_SNDCTL_SEQ_RESETSAMPLES;
+ extern unsigned IOCTL_SNDCTL_SEQ_SYNC;
+ extern unsigned IOCTL_SNDCTL_SEQ_TESTMIDI;
+ extern unsigned IOCTL_SNDCTL_SEQ_THRESHOLD;
+ extern unsigned IOCTL_SNDCTL_SYNTH_INFO;
+ extern unsigned IOCTL_SNDCTL_SYNTH_MEMAVL;
+ extern unsigned IOCTL_SNDCTL_TMR_CONTINUE;
+ extern unsigned IOCTL_SNDCTL_TMR_METRONOME;
+ extern unsigned IOCTL_SNDCTL_TMR_SELECT;
+ extern unsigned IOCTL_SNDCTL_TMR_SOURCE;
+ extern unsigned IOCTL_SNDCTL_TMR_START;
+ extern unsigned IOCTL_SNDCTL_TMR_STOP;
+ extern unsigned IOCTL_SNDCTL_TMR_TEMPO;
+ extern unsigned IOCTL_SNDCTL_TMR_TIMEBASE;
+ extern unsigned IOCTL_SOUND_MIXER_READ_ALTPCM;
+ extern unsigned IOCTL_SOUND_MIXER_READ_BASS;
+ extern unsigned IOCTL_SOUND_MIXER_READ_CAPS;
+ extern unsigned IOCTL_SOUND_MIXER_READ_CD;
+ extern unsigned IOCTL_SOUND_MIXER_READ_DEVMASK;
+ extern unsigned IOCTL_SOUND_MIXER_READ_ENHANCE;
+ extern unsigned IOCTL_SOUND_MIXER_READ_IGAIN;
+ extern unsigned IOCTL_SOUND_MIXER_READ_IMIX;
+ extern unsigned IOCTL_SOUND_MIXER_READ_LINE1;
+ extern unsigned IOCTL_SOUND_MIXER_READ_LINE2;
+ extern unsigned IOCTL_SOUND_MIXER_READ_LINE3;
+ extern unsigned IOCTL_SOUND_MIXER_READ_LINE;
+ extern unsigned IOCTL_SOUND_MIXER_READ_LOUD;
+ extern unsigned IOCTL_SOUND_MIXER_READ_MIC;
+ extern unsigned IOCTL_SOUND_MIXER_READ_MUTE;
+ extern unsigned IOCTL_SOUND_MIXER_READ_OGAIN;
+ extern unsigned IOCTL_SOUND_MIXER_READ_PCM;
+ extern unsigned IOCTL_SOUND_MIXER_READ_RECLEV;
+ extern unsigned IOCTL_SOUND_MIXER_READ_RECMASK;
+ extern unsigned IOCTL_SOUND_MIXER_READ_RECSRC;
+ extern unsigned IOCTL_SOUND_MIXER_READ_SPEAKER;
+ extern unsigned IOCTL_SOUND_MIXER_READ_STEREODEVS;
+ extern unsigned IOCTL_SOUND_MIXER_READ_SYNTH;
+ extern unsigned IOCTL_SOUND_MIXER_READ_TREBLE;
+ extern unsigned IOCTL_SOUND_MIXER_READ_VOLUME;
+ extern unsigned IOCTL_SOUND_MIXER_WRITE_ALTPCM;
+ extern unsigned IOCTL_SOUND_MIXER_WRITE_BASS;
+ extern unsigned IOCTL_SOUND_MIXER_WRITE_CD;
+ extern unsigned IOCTL_SOUND_MIXER_WRITE_ENHANCE;
+ extern unsigned IOCTL_SOUND_MIXER_WRITE_IGAIN;
+ extern unsigned IOCTL_SOUND_MIXER_WRITE_IMIX;
+ extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE1;
+ extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE2;
+ extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE3;
+ extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE;
+ extern unsigned IOCTL_SOUND_MIXER_WRITE_LOUD;
+ extern unsigned IOCTL_SOUND_MIXER_WRITE_MIC;
+ extern unsigned IOCTL_SOUND_MIXER_WRITE_MUTE;
+ extern unsigned IOCTL_SOUND_MIXER_WRITE_OGAIN;
+ extern unsigned IOCTL_SOUND_MIXER_WRITE_PCM;
+ extern unsigned IOCTL_SOUND_MIXER_WRITE_RECLEV;
+ extern unsigned IOCTL_SOUND_MIXER_WRITE_RECSRC;
+ extern unsigned IOCTL_SOUND_MIXER_WRITE_SPEAKER;
+ extern unsigned IOCTL_SOUND_MIXER_WRITE_SYNTH;
+ extern unsigned IOCTL_SOUND_MIXER_WRITE_TREBLE;
+ extern unsigned IOCTL_SOUND_MIXER_WRITE_VOLUME;
+ extern unsigned IOCTL_SOUND_PCM_READ_BITS;
+ extern unsigned IOCTL_SOUND_PCM_READ_CHANNELS;
+ extern unsigned IOCTL_SOUND_PCM_READ_FILTER;
+ 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
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+ extern unsigned IOCTL_CYGETDEFTHRESH;
+ extern unsigned IOCTL_CYGETDEFTIMEOUT;
+ extern unsigned IOCTL_CYGETMON;
+ extern unsigned IOCTL_CYGETTHRESH;
+ extern unsigned IOCTL_CYGETTIMEOUT;
+ extern unsigned IOCTL_CYSETDEFTHRESH;
+ extern unsigned IOCTL_CYSETDEFTIMEOUT;
+ extern unsigned IOCTL_CYSETTHRESH;
+ extern unsigned IOCTL_CYSETTIMEOUT;
+ extern unsigned IOCTL_EQL_EMANCIPATE;
+ extern unsigned IOCTL_EQL_ENSLAVE;
+ extern unsigned IOCTL_EQL_GETMASTRCFG;
+ extern unsigned IOCTL_EQL_GETSLAVECFG;
+ extern unsigned IOCTL_EQL_SETMASTRCFG;
+ extern unsigned IOCTL_EQL_SETSLAVECFG;
+ extern unsigned IOCTL_EVIOCGKEYCODE_V2;
+ extern unsigned IOCTL_EVIOCGPROP;
+ extern unsigned IOCTL_EVIOCSKEYCODE_V2;
+ extern unsigned IOCTL_FS_IOC_GETFLAGS;
+ extern unsigned IOCTL_FS_IOC_GETVERSION;
+ extern unsigned IOCTL_FS_IOC_SETFLAGS;
+ 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;
+ extern unsigned IOCTL_LPCHAR;
+ extern unsigned IOCTL_LPGETIRQ;
+ extern unsigned IOCTL_LPGETSTATUS;
+ extern unsigned IOCTL_LPRESET;
+ extern unsigned IOCTL_LPSETIRQ;
+ extern unsigned IOCTL_LPTIME;
+ extern unsigned IOCTL_LPWAIT;
+ extern unsigned IOCTL_MTIOCGETCONFIG;
+ 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;
+ extern unsigned IOCTL_SCSI_IOCTL_GET_IDLUN;
+ extern unsigned IOCTL_SCSI_IOCTL_PROBE_HOST;
+ extern unsigned IOCTL_SCSI_IOCTL_TAGGED_DISABLE;
+ extern unsigned IOCTL_SCSI_IOCTL_TAGGED_ENABLE;
+ extern unsigned IOCTL_SIOCAIPXITFCRT;
+ extern unsigned IOCTL_SIOCAIPXPRISLT;
+ extern unsigned IOCTL_SIOCAX25ADDUID;
+ extern unsigned IOCTL_SIOCAX25DELUID;
+ extern unsigned IOCTL_SIOCAX25GETPARMS;
+ extern unsigned IOCTL_SIOCAX25GETUID;
+ extern unsigned IOCTL_SIOCAX25NOUID;
+ extern unsigned IOCTL_SIOCAX25SETPARMS;
+ extern unsigned IOCTL_SIOCDEVPLIP;
+ extern unsigned IOCTL_SIOCIPXCFGDATA;
+ extern unsigned IOCTL_SIOCNRDECOBS;
+ extern unsigned IOCTL_SIOCNRGETPARMS;
+ extern unsigned IOCTL_SIOCNRRTCTL;
+ extern unsigned IOCTL_SIOCNRSETPARMS;
+ extern unsigned IOCTL_SNDCTL_DSP_GETISPACE;
+ extern unsigned IOCTL_SNDCTL_DSP_GETOSPACE;
+ extern unsigned IOCTL_TIOCGSERIAL;
+ extern unsigned IOCTL_TIOCSERGETMULTI;
+ extern unsigned IOCTL_TIOCSERSETMULTI;
+ extern unsigned IOCTL_TIOCSSERIAL;
+#endif
+
+ extern const int errno_EOWNERDEAD;
} // namespace __sanitizer
+#define CHECK_TYPE_SIZE(TYPE) \
+ COMPILER_CHECK(sizeof(__sanitizer_##TYPE) == sizeof(TYPE))
+
+#define CHECK_SIZE_AND_OFFSET(CLASS, MEMBER) \
+ COMPILER_CHECK(sizeof(((__sanitizer_##CLASS *) NULL)->MEMBER) == \
+ sizeof(((CLASS *) NULL)->MEMBER)); \
+ COMPILER_CHECK(offsetof(__sanitizer_##CLASS, MEMBER) == \
+ offsetof(CLASS, MEMBER))
+
+// For sigaction, which is a function and struct at the same time,
+// and thus requires explicit "struct" in sizeof() expression.
+#define CHECK_STRUCT_SIZE_AND_OFFSET(CLASS, MEMBER) \
+ COMPILER_CHECK(sizeof(((struct __sanitizer_##CLASS *) NULL)->MEMBER) == \
+ sizeof(((struct CLASS *) NULL)->MEMBER)); \
+ COMPILER_CHECK(offsetof(struct __sanitizer_##CLASS, MEMBER) == \
+ offsetof(struct CLASS, MEMBER))
+
#endif
diff --git a/lib/sanitizer_common/sanitizer_posix.cc b/lib/sanitizer_common/sanitizer_posix.cc
index af25b245fdd3..ffe91df1a59e 100644
--- a/lib/sanitizer_common/sanitizer_posix.cc
+++ b/lib/sanitizer_common/sanitizer_posix.cc
@@ -29,6 +29,24 @@ uptr GetMmapGranularity() {
return GetPageSize();
}
+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
+ // 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
+# else
+ return (1ULL << 47) - 1; // 0x00007fffffffffffUL;
+# endif
+#else // SANITIZER_WORDSIZE == 32
+ // FIXME: We can probably lower this on Android?
+ return (1ULL << 32) - 1; // 0xffffffff;
+#endif // SANITIZER_WORDSIZE
+}
+
void *MmapOrDie(uptr size, const char *mem_type) {
size = RoundUpTo(size, GetPageSizeCached());
uptr res = internal_mmap(0, size,
@@ -155,6 +173,77 @@ const char *GetPwd() {
return GetEnv("PWD");
}
+char *FindPathToBinary(const char *name) {
+ const char *path = GetEnv("PATH");
+ if (!path)
+ return 0;
+ uptr name_len = internal_strlen(name);
+ InternalScopedBuffer<char> buffer(kMaxPathLength);
+ const char *beg = path;
+ while (true) {
+ const char *end = internal_strchrnul(beg, ':');
+ uptr prefix_len = end - beg;
+ if (prefix_len + name_len + 2 <= kMaxPathLength) {
+ internal_memcpy(buffer.data(), beg, prefix_len);
+ buffer[prefix_len] = '/';
+ internal_memcpy(&buffer[prefix_len + 1], name, name_len);
+ buffer[prefix_len + 1 + name_len] = '\0';
+ if (FileExists(buffer.data()))
+ return internal_strdup(buffer.data());
+ }
+ if (*end == '\0') break;
+ beg = end + 1;
+ }
+ return 0;
+}
+
+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));
+ Die();
+ }
+}
+
+bool GetCodeRangeForFile(const char *module, uptr *start, uptr *end) {
+ uptr s, e, off, prot;
+ InternalMmapVector<char> fn(4096);
+ fn.push_back(0);
+ MemoryMappingLayout proc_maps(/*cache_enabled*/false);
+ while (proc_maps.Next(&s, &e, &off, &fn[0], fn.capacity(), &prot)) {
+ if ((prot & MemoryMappingLayout::kProtectionExecute) != 0
+ && internal_strcmp(module, &fn[0]) == 0) {
+ *start = s;
+ *end = e;
+ return true;
+ }
+ }
+ return false;
+}
+
} // namespace __sanitizer
#endif // SANITIZER_LINUX || SANITIZER_MAC
diff --git a/lib/sanitizer_common/sanitizer_posix_libcdep.cc b/lib/sanitizer_common/sanitizer_posix_libcdep.cc
index 43da171ba271..6032f520dee0 100644
--- a/lib/sanitizer_common/sanitizer_posix_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_posix_libcdep.cc
@@ -89,28 +89,6 @@ int internal_isatty(fd_t fd) {
return isatty(fd);
}
-#ifndef SANITIZER_GO
-void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp,
- uptr stack_top, uptr stack_bottom, bool fast) {
-#if !SANITIZER_CAN_FAST_UNWIND
- fast = false;
-#endif
-#if SANITIZER_MAC
- // Always unwind fast on Mac.
- (void)fast;
-#else
- if (!fast || (stack_top == stack_bottom))
- return stack->SlowUnwindStack(pc, max_s);
-#endif // SANITIZER_MAC
- stack->size = 0;
- stack->trace[0] = pc;
- if (max_s > 1) {
- stack->max_size = max_s;
- stack->FastUnwindStack(pc, bp, stack_top, stack_bottom);
- }
-}
-#endif // SANITIZER_GO
-
} // namespace __sanitizer
#endif
diff --git a/lib/sanitizer_common/sanitizer_printf.cc b/lib/sanitizer_common/sanitizer_printf.cc
index 5935d7f17a5e..bbdb24b685de 100644
--- a/lib/sanitizer_common/sanitizer_printf.cc
+++ b/lib/sanitizer_common/sanitizer_printf.cc
@@ -21,7 +21,7 @@
#include <stdio.h>
#include <stdarg.h>
-#if SANITIZER_WINDOWS
+#if SANITIZER_WINDOWS && !defined(va_copy)
# define va_copy(dst, src) ((dst) = (src))
#endif
@@ -38,45 +38,60 @@ static int AppendChar(char **buff, const char *buff_end, char c) {
}
// Appends number in a given base to buffer. If its length is less than
-// "minimal_num_length", it is padded with leading zeroes.
-static int AppendUnsigned(char **buff, const char *buff_end, u64 num,
- u8 base, u8 minimal_num_length) {
+// |minimal_num_length|, it is padded with leading zeroes or spaces, depending
+// on the value of |pad_with_zero|.
+static int AppendNumber(char **buff, const char *buff_end, u64 absolute_value,
+ u8 base, u8 minimal_num_length, bool pad_with_zero,
+ bool negative) {
uptr const kMaxLen = 30;
RAW_CHECK(base == 10 || base == 16);
+ RAW_CHECK(base == 10 || !negative);
+ RAW_CHECK(absolute_value || !negative);
RAW_CHECK(minimal_num_length < kMaxLen);
+ int result = 0;
+ if (negative && minimal_num_length)
+ --minimal_num_length;
+ if (negative && pad_with_zero)
+ result += AppendChar(buff, buff_end, '-');
uptr num_buffer[kMaxLen];
- uptr pos = 0;
+ int pos = 0;
do {
- RAW_CHECK_MSG(pos < kMaxLen, "appendNumber buffer overflow");
- num_buffer[pos++] = num % base;
- num /= base;
- } while (num > 0);
+ RAW_CHECK_MSG((uptr)pos < kMaxLen, "AppendNumber buffer overflow");
+ num_buffer[pos++] = absolute_value % base;
+ absolute_value /= base;
+ } while (absolute_value > 0);
if (pos < minimal_num_length) {
// Make sure compiler doesn't insert call to memset here.
internal_memset(&num_buffer[pos], 0,
sizeof(num_buffer[0]) * (minimal_num_length - pos));
pos = minimal_num_length;
}
- int result = 0;
- while (pos-- > 0) {
- uptr digit = num_buffer[pos];
+ RAW_CHECK(pos > 0);
+ pos--;
+ for (; pos >= 0 && num_buffer[pos] == 0; pos--) {
+ char c = (pad_with_zero || pos == 0) ? '0' : ' ';
+ result += AppendChar(buff, buff_end, c);
+ }
+ if (negative && !pad_with_zero) result += AppendChar(buff, buff_end, '-');
+ for (; pos >= 0; pos--) {
+ char digit = static_cast<char>(num_buffer[pos]);
result += AppendChar(buff, buff_end, (digit < 10) ? '0' + digit
: 'a' + digit - 10);
}
return result;
}
+static int AppendUnsigned(char **buff, const char *buff_end, u64 num, u8 base,
+ u8 minimal_num_length, bool pad_with_zero) {
+ return AppendNumber(buff, buff_end, num, base, minimal_num_length,
+ pad_with_zero, false /* negative */);
+}
+
static int AppendSignedDecimal(char **buff, const char *buff_end, s64 num,
- u8 minimal_num_length) {
- int result = 0;
- if (num < 0) {
- result += AppendChar(buff, buff_end, '-');
- num = -num;
- if (minimal_num_length)
- --minimal_num_length;
- }
- result += AppendUnsigned(buff, buff_end, (u64)num, 10, minimal_num_length);
- return result;
+ u8 minimal_num_length, bool pad_with_zero) {
+ bool negative = (num < 0);
+ return AppendNumber(buff, buff_end, (u64)(negative ? -num : num), 10,
+ minimal_num_length, pad_with_zero, negative);
}
static int AppendString(char **buff, const char *buff_end, const char *s) {
@@ -93,14 +108,14 @@ static int AppendPointer(char **buff, const char *buff_end, u64 ptr_value) {
int result = 0;
result += AppendString(buff, buff_end, "0x");
result += AppendUnsigned(buff, buff_end, ptr_value, 16,
- (SANITIZER_WORDSIZE == 64) ? 12 : 8);
+ (SANITIZER_WORDSIZE == 64) ? 12 : 8, true);
return result;
}
int VSNPrintf(char *buff, int buff_length,
const char *format, va_list args) {
static const char *kPrintfFormatsHelp =
- "Supported Printf formats: %(0[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];
@@ -112,11 +127,11 @@ int VSNPrintf(char *buff, int buff_length,
continue;
}
cur++;
- bool have_width = (*cur == '0');
+ bool have_width = (*cur >= '0' && *cur <= '9');
+ bool pad_with_zero = (*cur == '0');
int width = 0;
if (have_width) {
while (*cur >= '0' && *cur <= '9') {
- have_width = true;
width = width * 10 + *cur++ - '0';
}
}
@@ -132,7 +147,8 @@ int VSNPrintf(char *buff, int buff_length,
dval = have_ll ? va_arg(args, s64)
: have_z ? va_arg(args, sptr)
: va_arg(args, int);
- result += AppendSignedDecimal(&buff, buff_end, dval, width);
+ result += AppendSignedDecimal(&buff, buff_end, dval, width,
+ pad_with_zero);
break;
}
case 'u':
@@ -141,7 +157,7 @@ int VSNPrintf(char *buff, int buff_length,
: have_z ? va_arg(args, uptr)
: va_arg(args, unsigned);
result += AppendUnsigned(&buff, buff_end, uval,
- (*cur == 'u') ? 10 : 16, width);
+ (*cur == 'u') ? 10 : 16, width, pad_with_zero);
break;
}
case 'p': {
@@ -179,17 +195,22 @@ void SetPrintfAndReportCallback(void (*callback)(const char *)) {
PrintfAndReportCallback = callback;
}
-#if SANITIZER_SUPPORTS_WEAK_HOOKS
// Can be overriden in frontend.
-SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
+#if SANITIZER_SUPPORTS_WEAK_HOOKS
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+void OnPrint(const char *str) {
+ (void)str;
+}
+#elif defined(SANITIZER_GO) && defined(TSAN_EXTERNAL_HOOKS)
void OnPrint(const char *str);
+#else
+void OnPrint(const char *str) {
+ (void)str;
+}
#endif
static void CallPrintfAndReportCallback(const char *str) {
-#if SANITIZER_SUPPORTS_WEAK_HOOKS
- if (&OnPrint != NULL)
- OnPrint(str);
-#endif
+ OnPrint(str);
if (PrintfAndReportCallback)
PrintfAndReportCallback(str);
}
@@ -273,4 +294,13 @@ int internal_snprintf(char *buffer, uptr length, const char *format, ...) {
return needed_length;
}
+void InternalScopedString::append(const char *format, ...) {
+ CHECK_LT(length_, size());
+ va_list args;
+ va_start(args, format);
+ VSNPrintf(data() + length_, size() - length_, format, args);
+ va_end(args);
+ length_ += internal_strlen(data() + length_);
+}
+
} // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_procmaps.h b/lib/sanitizer_common/sanitizer_procmaps.h
index b96f09ec4561..65bcac6338d5 100644
--- a/lib/sanitizer_common/sanitizer_procmaps.h
+++ b/lib/sanitizer_common/sanitizer_procmaps.h
@@ -32,7 +32,7 @@ class MemoryMappingLayout {
}
};
-#else // _WIN32
+#else // SANITIZER_WINDOWS
#if SANITIZER_LINUX
struct ProcSelfMapsBuff {
char *data;
@@ -118,7 +118,18 @@ class MemoryMappingLayout {
# endif
};
-#endif // _WIN32
+typedef void (*fill_profile_f)(uptr start, uptr rss, bool file,
+ /*out*/uptr *stats, uptr stats_size);
+
+// Parse the contents of /proc/self/smaps and generate a memory profile.
+// |cb| is a tool-specific callback that fills the |stats| array containing
+// |stats_size| elements.
+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
} // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_quarantine.h b/lib/sanitizer_common/sanitizer_quarantine.h
index 599d13645dd7..db4eb74505f9 100644
--- a/lib/sanitizer_common/sanitizer_quarantine.h
+++ b/lib/sanitizer_common/sanitizer_quarantine.h
@@ -26,13 +26,15 @@ namespace __sanitizer {
template<typename Node> class QuarantineCache;
struct QuarantineBatch {
- static const uptr kSize = 1024;
+ static const uptr kSize = 1021;
QuarantineBatch *next;
uptr size;
uptr count;
void *batch[kSize];
};
+COMPILER_CHECK(sizeof(QuarantineBatch) <= (1 << 13)); // 8Kb.
+
// The callback interface is:
// void Callback::Recycle(Node *ptr);
// void *cb.Allocate(uptr size);
@@ -123,8 +125,10 @@ class QuarantineCache {
}
void Enqueue(Callback cb, void *ptr, uptr size) {
- if (list_.empty() || list_.back()->count == QuarantineBatch::kSize)
+ if (list_.empty() || list_.back()->count == QuarantineBatch::kSize) {
AllocBatch(cb);
+ size += sizeof(QuarantineBatch); // Count the batch in Quarantine size.
+ }
QuarantineBatch *b = list_.back();
b->batch[b->count++] = ptr;
b->size += size;
@@ -147,7 +151,7 @@ class QuarantineCache {
return 0;
QuarantineBatch *b = list_.front();
list_.pop_front();
- SizeAdd(-b->size);
+ SizeSub(b->size);
return b;
}
@@ -158,6 +162,9 @@ class QuarantineCache {
void SizeAdd(uptr add) {
atomic_store(&size_, Size() + add, memory_order_relaxed);
}
+ void SizeSub(uptr sub) {
+ atomic_store(&size_, Size() - sub, memory_order_relaxed);
+ }
NOINLINE QuarantineBatch* AllocBatch(Callback cb) {
QuarantineBatch *b = (QuarantineBatch *)cb.Allocate(sizeof(*b));
diff --git a/lib/sanitizer_common/sanitizer_report_decorator.h b/lib/sanitizer_common/sanitizer_report_decorator.h
index 49334d5e0c71..eef2b15ccd34 100644
--- a/lib/sanitizer_common/sanitizer_report_decorator.h
+++ b/lib/sanitizer_common/sanitizer_report_decorator.h
@@ -19,6 +19,8 @@
namespace __sanitizer {
class AnsiColorDecorator {
+ // 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) { }
const char *Bold() const { return ansi_ ? "\033[1m" : ""; }
diff --git a/lib/sanitizer_common/sanitizer_stackdepot.cc b/lib/sanitizer_common/sanitizer_stackdepot.cc
index 08e5238325e5..2793bd0714a1 100644
--- a/lib/sanitizer_common/sanitizer_stackdepot.cc
+++ b/lib/sanitizer_common/sanitizer_stackdepot.cc
@@ -201,4 +201,38 @@ const uptr *StackDepotGet(u32 id, uptr *size) {
return 0;
}
+bool StackDepotReverseMap::IdDescPair::IdComparator(
+ const StackDepotReverseMap::IdDescPair &a,
+ const StackDepotReverseMap::IdDescPair &b) {
+ return a.id < b.id;
+}
+
+StackDepotReverseMap::StackDepotReverseMap()
+ : map_(StackDepotGetStats()->n_uniq_ids + 100) {
+ for (int idx = 0; idx < kTabSize; idx++) {
+ 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) {
+ IdDescPair pair = {s->id, s};
+ map_.push_back(pair);
+ }
+ }
+ InternalSort(&map_, map_.size(), IdDescPair::IdComparator);
+}
+
+const uptr *StackDepotReverseMap::Get(u32 id, uptr *size) {
+ if (!map_.size()) return 0;
+ 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;
+}
+
} // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_stackdepot.h b/lib/sanitizer_common/sanitizer_stackdepot.h
index 5915fdbb4310..4f77ff28eab1 100644
--- a/lib/sanitizer_common/sanitizer_stackdepot.h
+++ b/lib/sanitizer_common/sanitizer_stackdepot.h
@@ -13,6 +13,7 @@
#ifndef SANITIZER_STACKDEPOT_H
#define SANITIZER_STACKDEPOT_H
+#include "sanitizer_common.h"
#include "sanitizer_internal_defs.h"
namespace __sanitizer {
@@ -31,6 +32,31 @@ struct StackDepotStats {
StackDepotStats *StackDepotGetStats();
+struct StackDesc;
+
+// Instantiating this class creates a snapshot of StackDepot which can be
+// efficiently queried with StackDepotGet(). You can use it concurrently with
+// StackDepot, but the snapshot is only guaranteed to contain those stack traces
+// which were stored before it was instantiated.
+class StackDepotReverseMap {
+ public:
+ StackDepotReverseMap();
+ const uptr *Get(u32 id, uptr *size);
+
+ private:
+ struct IdDescPair {
+ u32 id;
+ StackDesc *desc;
+
+ static bool IdComparator(const IdDescPair &a, const IdDescPair &b);
+ };
+
+ InternalMmapVector<IdDescPair> map_;
+
+ // Disallow evil constructors.
+ StackDepotReverseMap(const StackDepotReverseMap&);
+ void operator=(const StackDepotReverseMap&);
+};
} // namespace __sanitizer
#endif // SANITIZER_STACKDEPOT_H
diff --git a/lib/sanitizer_common/sanitizer_stacktrace.cc b/lib/sanitizer_common/sanitizer_stacktrace.cc
index 724c29c86b66..70ce26bde0d2 100644
--- a/lib/sanitizer_common/sanitizer_stacktrace.cc
+++ b/lib/sanitizer_common/sanitizer_stacktrace.cc
@@ -12,20 +12,13 @@
//===----------------------------------------------------------------------===//
#include "sanitizer_common.h"
+#include "sanitizer_flags.h"
#include "sanitizer_procmaps.h"
#include "sanitizer_stacktrace.h"
#include "sanitizer_symbolizer.h"
namespace __sanitizer {
-const char *StripPathPrefix(const char *filepath,
- const char *strip_file_prefix) {
- if (filepath == 0) return 0;
- if (filepath == internal_strstr(filepath, strip_file_prefix))
- return filepath + internal_strlen(strip_file_prefix);
- return filepath;
-}
-// ----------------------- StackTrace ----------------------------- {{{1
uptr StackTrace::GetPreviousInstructionPc(uptr pc) {
#ifdef __arm__
// Cancel Thumb bit.
@@ -41,32 +34,21 @@ uptr StackTrace::GetPreviousInstructionPc(uptr pc) {
#endif
}
-static void PrintStackFramePrefix(uptr frame_num, uptr pc) {
- Printf(" #%zu 0x%zx", frame_num, pc);
-}
-
-static void PrintSourceLocation(const char *file, int line, int column,
- const char *strip_file_prefix) {
- CHECK(file);
- Printf(" %s", StripPathPrefix(file, strip_file_prefix));
- if (line > 0) {
- Printf(":%d", line);
- if (column > 0)
- Printf(":%d", column);
- }
-}
-
-static void PrintModuleAndOffset(const char *module, uptr offset,
- const char *strip_file_prefix) {
- Printf(" (%s+0x%zx)", StripPathPrefix(module, strip_file_prefix), offset);
+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,
- bool symbolize, const char *strip_file_prefix,
- SymbolizeCallback symbolize_callback ) {
+ 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,
@@ -77,50 +59,60 @@ void StackTrace::PrintStack(const uptr *addr, uptr size,
if (symbolize_callback) {
if (symbolize_callback((void*)pc, buff.data(), buff.size())) {
addr_frames_num = 1;
- PrintStackFramePrefix(frame_num, pc);
+ 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.
- Printf(" %s\n", StripPathPrefix(buff.data(), strip_file_prefix));
+ frame_desc.append(
+ " %s",
+ StripPathPrefix(buff.data(), common_flags()->strip_path_prefix));
+ Printf("%s\n", frame_desc.data());
frame_num++;
}
}
- if (symbolize && addr_frames_num == 0 && &SymbolizeCode) {
+ if (common_flags()->symbolize && addr_frames_num == 0) {
// Use our own (online) symbolizer, if necessary.
- addr_frames_num = SymbolizeCode(pc, addr_frames.data(),
- addr_frames.size());
+ 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];
- PrintStackFramePrefix(frame_num, pc);
+ frame_desc.clear();
+ PrintStackFramePrefix(&frame_desc, frame_num, pc);
if (info.function) {
- Printf(" in %s", info.function);
+ frame_desc.append(" in %s", info.function);
}
if (info.file) {
- PrintSourceLocation(info.file, info.line, info.column,
- strip_file_prefix);
+ frame_desc.append(" ");
+ PrintSourceLocation(&frame_desc, info.file, info.line, info.column);
} else if (info.module) {
- PrintModuleAndOffset(info.module, info.module_offset,
- strip_file_prefix);
+ frame_desc.append(" ");
+ PrintModuleAndOffset(&frame_desc, info.module, info.module_offset);
}
- Printf("\n");
- info.Clear();
+ 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.
- PrintStackFramePrefix(frame_num, pc);
+ frame_desc.clear();
+ PrintStackFramePrefix(&frame_desc, frame_num, pc);
uptr offset;
if (proc_maps.GetObjectNameAndOffset(pc, &offset,
buff.data(), buff.size(),
/* protection */0)) {
- PrintModuleAndOffset(buff.data(), offset, strip_file_prefix);
+ frame_desc.append(" ");
+ PrintModuleAndOffset(&frame_desc, buff.data(), offset);
}
- Printf("\n");
+ Printf("%s\n", frame_desc.data());
frame_num++;
}
}
+ // Always print a trailing empty line after stack trace.
+ Printf("\n");
}
uptr StackTrace::GetCurrentPc() {
@@ -128,17 +120,23 @@ uptr StackTrace::GetCurrentPc() {
}
void StackTrace::FastUnwindStack(uptr pc, uptr bp,
- uptr stack_top, uptr stack_bottom) {
- CHECK(size == 0 && trace[0] == pc);
+ uptr stack_top, uptr stack_bottom,
+ uptr max_depth) {
+ if (max_depth == 0) {
+ size = 0;
+ return;
+ }
+ trace[0] = pc;
size = 1;
uhwptr *frame = (uhwptr *)bp;
uhwptr *prev_frame = frame - 1;
+ if (stack_top < 4096) return; // Sanity check for stack top.
// 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 &&
IsAligned((uptr)frame, sizeof(*frame)) &&
- size < max_size) {
+ size < max_depth) {
uhwptr pc1 = frame[1];
if (pc1 != pc) {
trace[size++] = (uptr) pc1;
@@ -156,111 +154,19 @@ void StackTrace::PopStackFrames(uptr count) {
}
}
-// On 32-bits we don't compress stack traces.
-// On 64-bits we compress stack traces: if a given pc differes slightly from
-// the previous one, we record a 31-bit offset instead of the full pc.
-SANITIZER_INTERFACE_ATTRIBUTE
-uptr StackTrace::CompressStack(StackTrace *stack, u32 *compressed, uptr size) {
-#if SANITIZER_WORDSIZE == 32
- // Don't compress, just copy.
- uptr res = 0;
- for (uptr i = 0; i < stack->size && i < size; i++) {
- compressed[i] = stack->trace[i];
- res++;
- }
- if (stack->size < size)
- compressed[stack->size] = 0;
-#else // 64 bits, compress.
- uptr prev_pc = 0;
- const uptr kMaxOffset = (1ULL << 30) - 1;
- uptr c_index = 0;
- uptr res = 0;
- for (uptr i = 0, n = stack->size; i < n; i++) {
- uptr pc = stack->trace[i];
- if (!pc) break;
- if ((s64)pc < 0) break;
- // Printf("C pc[%zu] %zx\n", i, pc);
- if (prev_pc - pc < kMaxOffset || pc - prev_pc < kMaxOffset) {
- uptr offset = (s64)(pc - prev_pc);
- offset |= (1U << 31);
- if (c_index >= size) break;
- // Printf("C co[%zu] offset %zx\n", i, offset);
- compressed[c_index++] = offset;
- } else {
- uptr hi = pc >> 32;
- uptr lo = (pc << 32) >> 32;
- CHECK_EQ((hi & (1 << 31)), 0);
- if (c_index + 1 >= size) break;
- // Printf("C co[%zu] hi/lo: %zx %zx\n", c_index, hi, lo);
- compressed[c_index++] = hi;
- compressed[c_index++] = lo;
- }
- res++;
- prev_pc = pc;
- }
- if (c_index < size)
- compressed[c_index] = 0;
- if (c_index + 1 < size)
- compressed[c_index + 1] = 0;
-#endif // SANITIZER_WORDSIZE
-
- // debug-only code
-#if 0
- StackTrace check_stack;
- UncompressStack(&check_stack, compressed, size);
- if (res < check_stack.size) {
- Printf("res %zu check_stack.size %zu; c_size %zu\n", res,
- check_stack.size, size);
- }
- // |res| may be greater than check_stack.size, because
- // UncompressStack(CompressStack(stack)) eliminates the 0x0 frames.
- CHECK(res >= check_stack.size);
- CHECK_EQ(0, REAL(memcmp)(check_stack.trace, stack->trace,
- check_stack.size * sizeof(uptr)));
-#endif
-
- return res;
+static bool MatchPc(uptr cur_pc, uptr trace_pc, uptr threshold) {
+ return cur_pc - trace_pc <= threshold || trace_pc - cur_pc <= threshold;
}
-SANITIZER_INTERFACE_ATTRIBUTE
-void StackTrace::UncompressStack(StackTrace *stack,
- u32 *compressed, uptr size) {
-#if SANITIZER_WORDSIZE == 32
- // Don't uncompress, just copy.
- stack->size = 0;
- for (uptr i = 0; i < size && i < kStackTraceMax; i++) {
- if (!compressed[i]) break;
- stack->size++;
- stack->trace[i] = compressed[i];
- }
-#else // 64 bits, uncompress
- uptr prev_pc = 0;
- stack->size = 0;
- for (uptr i = 0; i < size && stack->size < kStackTraceMax; i++) {
- u32 x = compressed[i];
- uptr pc = 0;
- if (x & (1U << 31)) {
- // Printf("U co[%zu] offset: %x\n", i, x);
- // this is an offset
- s32 offset = x;
- offset = (offset << 1) >> 1; // remove the 31-byte and sign-extend.
- pc = prev_pc + offset;
- CHECK(pc);
- } else {
- // CHECK(i + 1 < size);
- if (i + 1 >= size) break;
- uptr hi = x;
- uptr lo = compressed[i+1];
- // Printf("U co[%zu] hi/lo: %zx %zx\n", i, hi, lo);
- i++;
- pc = (hi << 32) | lo;
- if (!pc) break;
- }
- // Printf("U pc[%zu] %zx\n", stack->size, pc);
- stack->trace[stack->size++] = pc;
- prev_pc = pc;
+uptr StackTrace::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;
+ for (uptr i = 0; i < size; ++i) {
+ if (MatchPc(pc, trace[i], kPcThreshold))
+ return i;
}
-#endif // SANITIZER_WORDSIZE
+ return 0;
}
} // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_stacktrace.h b/lib/sanitizer_common/sanitizer_stacktrace.h
index fcfdd7e0b59b..5042f230188a 100644
--- a/lib/sanitizer_common/sanitizer_stacktrace.h
+++ b/lib/sanitizer_common/sanitizer_stacktrace.h
@@ -21,57 +21,57 @@ static const uptr kStackTraceMax = 256;
#if SANITIZER_LINUX && (defined(__arm__) || \
defined(__powerpc__) || defined(__powerpc64__) || \
- defined(__sparc__))
-#define SANITIZER_CAN_FAST_UNWIND 0
+ defined(__sparc__) || \
+ defined(__mips__))
+# define SANITIZER_CAN_FAST_UNWIND 0
+#elif SANITIZER_WINDOWS
+# define SANITIZER_CAN_FAST_UNWIND 0
#else
-#define SANITIZER_CAN_FAST_UNWIND 1
+# define SANITIZER_CAN_FAST_UNWIND 1
#endif
struct StackTrace {
typedef bool (*SymbolizeCallback)(const void *pc, char *out_buffer,
int out_size);
+ uptr top_frame_bp;
uptr size;
- uptr max_size;
uptr trace[kStackTraceMax];
+
+ // Prints a symbolized stacktrace, followed by an empty line.
static void PrintStack(const uptr *addr, uptr size,
- bool symbolize, const char *strip_file_prefix,
- SymbolizeCallback symbolize_callback);
- void CopyTo(uptr *dst, uptr dst_size) {
- for (uptr i = 0; i < size && i < dst_size; i++)
- dst[i] = trace[i];
- for (uptr i = size; i < dst_size; i++)
- dst[i] = 0;
- }
+ SymbolizeCallback symbolize_callback = 0);
- void CopyFrom(uptr *src, uptr src_size) {
+ 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++) {
+ for (uptr i = 0; i < size; i++)
trace[i] = src[i];
- }
}
- void FastUnwindStack(uptr pc, uptr bp, uptr stack_top, uptr stack_bottom);
- void SlowUnwindStack(uptr pc, uptr max_depth);
+ 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)
+ return true;
+ return request_fast_unwind;
+ }
- void PopStackFrames(uptr count);
+ 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 CompressStack(StackTrace *stack,
- u32 *compressed, uptr size);
- static void UncompressStack(StackTrace *stack,
- u32 *compressed, uptr size);
+ private:
+ void FastUnwindStack(uptr pc, uptr bp, uptr stack_top, uptr stack_bottom,
+ uptr max_depth);
+ void SlowUnwindStack(uptr pc, uptr max_depth);
+ void PopStackFrames(uptr count);
+ uptr LocatePcInTrace(uptr pc);
};
-
-const char *StripPathPrefix(const char *filepath,
- const char *strip_file_prefix);
-
-void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp,
- uptr stack_top, uptr stack_bottom, bool fast);
-
} // namespace __sanitizer
// Use this macro if you want to print stack trace with the caller
diff --git a/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc b/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc
new file mode 100644
index 000000000000..58fa18251ecf
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc
@@ -0,0 +1,28 @@
+//===-- sanitizer_stacktrace_libcdep.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.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_stacktrace.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);
+
+ top_frame_bp = size ? bp : 0;
+}
+
+} // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_stoptheworld.h b/lib/sanitizer_common/sanitizer_stoptheworld.h
index cc9408bb845f..a32646708d45 100644
--- a/lib/sanitizer_common/sanitizer_stoptheworld.h
+++ b/lib/sanitizer_common/sanitizer_stoptheworld.h
@@ -46,7 +46,7 @@ class SuspendedThreadsList {
}
private:
- InternalVector<SuspendedThreadID> thread_ids_;
+ InternalMmapVector<SuspendedThreadID> thread_ids_;
// Prohibit copy and assign.
SuspendedThreadsList(const SuspendedThreadsList&);
diff --git a/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
index e5284ee2211a..a34ddd872209 100644
--- a/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
@@ -14,12 +14,14 @@
#include "sanitizer_platform.h"
-#if SANITIZER_LINUX
+#if SANITIZER_LINUX && defined(__x86_64__)
#include "sanitizer_stoptheworld.h"
+#include "sanitizer_platform_limits_posix.h"
+
#include <errno.h>
-#include <sched.h> // for clone
+#include <sched.h> // for CLONE_* definitions
#include <stddef.h>
#include <sys/prctl.h> // for PR_* definitions
#include <sys/ptrace.h> // for PTRACE_* definitions
@@ -31,7 +33,16 @@
#endif
#include <sys/wait.h> // for signal-related stuff
+#ifdef sa_handler
+# undef sa_handler
+#endif
+
+#ifdef sa_sigaction
+# undef sa_sigaction
+#endif
+
#include "sanitizer_common.h"
+#include "sanitizer_flags.h"
#include "sanitizer_libc.h"
#include "sanitizer_linux.h"
#include "sanitizer_mutex.h"
@@ -47,31 +58,14 @@
// clone() interface (we want to share the address space with the caller
// process, so we prefer clone() over fork()).
//
-// We avoid the use of libc for two reasons:
+// We don't use any libc functions, relying instead on direct syscalls. There
+// are two reasons for this:
// 1. calling a library function while threads are suspended could cause a
// deadlock, if one of the treads happens to be holding a libc lock;
// 2. it's generally not safe to call libc functions from the tracer task,
// because clone() does not set up a thread-local storage for it. Any
// thread-local variables used by libc will be shared between the tracer task
// and the thread which spawned it.
-//
-// We deal with this by replacing libc calls with calls to our own
-// implementations defined in sanitizer_libc.h and sanitizer_linux.h. However,
-// there are still some libc functions which are used here:
-//
-// * All of the system calls ultimately go through the libc syscall() function.
-// We're operating under the assumption that syscall()'s implementation does
-// not acquire any locks or use any thread-local data (except for the errno
-// variable, which we handle separately).
-//
-// * We lack custom implementations of sigfillset() and sigaction(), so we use
-// the libc versions instead. The same assumptions as above apply.
-//
-// * It is safe to call libc functions before the cloned thread is spawned or
-// after it has exited. The following functions are used in this manner:
-// sigdelset()
-// sigprocmask()
-// clone()
COMPILER_CHECK(sizeof(SuspendedThreadID) == sizeof(pid_t));
@@ -106,10 +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.
- Report("Could not attach to thread %d (errno %d).\n", thread_id, pterrno);
+ if (common_flags()->verbosity)
+ Report("Could not attach to thread %d (errno %d).\n", thread_id, pterrno);
return false;
} else {
- if (SanitizerVerbosity > 0)
+ if (common_flags()->verbosity)
Report("Attached to thread %d.\n", thread_id);
// The thread is not guaranteed to stop before ptrace returns, so we must
// wait on it.
@@ -119,8 +114,9 @@ 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.
- Report("Waiting on thread %d failed, detaching (errno %d).\n", thread_id,
- wperrno);
+ if (common_flags()->verbosity)
+ Report("Waiting on thread %d failed, detaching (errno %d).\n",
+ thread_id, wperrno);
internal_ptrace(PTRACE_DETACH, thread_id, NULL, NULL);
return false;
}
@@ -135,13 +131,14 @@ void ThreadSuspender::ResumeAllThreads() {
int pterrno;
if (!internal_iserror(internal_ptrace(PTRACE_DETACH, tid, NULL, NULL),
&pterrno)) {
- if (SanitizerVerbosity > 0)
+ if (common_flags()->verbosity)
Report("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.
- Report("Could not detach from thread %d (errno %d).\n", tid, pterrno);
+ if (common_flags()->verbosity)
+ Report("Could not detach from thread %d (errno %d).\n", tid, pterrno);
}
}
}
@@ -186,13 +183,16 @@ static const int kUnblockedSignals[] = { SIGABRT, SIGILL, SIGFPE, SIGSEGV,
struct TracerThreadArgument {
StopTheWorldCallback callback;
void *callback_argument;
- // The tracer thread waits on this mutex while the parent finished its
+ // The tracer thread waits on this mutex while the parent finishes its
// preparations.
BlockingMutex mutex;
+ uptr parent_pid;
};
+static DieCallbackType old_die_callback;
+
// Signal handler to wake up suspended threads when the tracer thread dies.
-void TracerThreadSignalHandler(int signum, siginfo_t *siginfo, void *) {
+void TracerThreadSignalHandler(int signum, void *siginfo, void *) {
if (thread_suspender_instance != NULL) {
if (signum == SIGABRT)
thread_suspender_instance->KillAllThreads();
@@ -202,6 +202,19 @@ void TracerThreadSignalHandler(int signum, siginfo_t *siginfo, void *) {
internal__exit((signum == SIGABRT) ? 1 : 2);
}
+static void TracerThreadDieCallback() {
+ // Generally a call to Die() in the tracer thread should be fatal to the
+ // parent process as well, because they share the address space.
+ // This really only works correctly if all the threads are suspended at this
+ // point. So we correctly handle calls to Die() from within the callback, but
+ // not those that happen before or after the callback. Hopefully there aren't
+ // a lot of opportunities for that to happen...
+ if (thread_suspender_instance)
+ thread_suspender_instance->KillAllThreads();
+ if (old_die_callback)
+ old_die_callback();
+}
+
// Size of alternative stack for signal handlers in the tracer thread.
static const int kHandlerStackSize = 4096;
@@ -210,10 +223,17 @@ static int TracerThread(void* argument) {
TracerThreadArgument *tracer_thread_argument =
(TracerThreadArgument *)argument;
+ internal_prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ // Check if parent is already dead.
+ if (internal_getppid() != tracer_thread_argument->parent_pid)
+ internal__exit(4);
+
// Wait for the parent thread to finish preparations.
tracer_thread_argument->mutex.Lock();
tracer_thread_argument->mutex.Unlock();
+ SetDieCallback(TracerThreadDieCallback);
+
ThreadSuspender thread_suspender(internal_getppid());
// Global pointer for the signal handler.
thread_suspender_instance = &thread_suspender;
@@ -230,17 +250,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++) {
- struct sigaction new_sigaction;
+ __sanitizer_kernel_sigaction_t new_sigaction;
internal_memset(&new_sigaction, 0, sizeof(new_sigaction));
- new_sigaction.sa_sigaction = TracerThreadSignalHandler;
+ new_sigaction.sigaction = TracerThreadSignalHandler;
new_sigaction.sa_flags = SA_ONSTACK | SA_SIGINFO;
- sigfillset(&new_sigaction.sa_mask);
- sigaction(kUnblockedSignals[signal_index], &new_sigaction, NULL);
+ internal_sigfillset(&new_sigaction.sa_mask);
+ internal_sigaction(kUnblockedSignals[signal_index], &new_sigaction, NULL);
}
int exit_code = 0;
if (!thread_suspender.SuspendAllThreads()) {
- Report("Failed suspending threads.\n");
+ if (common_flags()->verbosity)
+ Report("Failed suspending threads.\n");
exit_code = 3;
} else {
tracer_thread_argument->callback(thread_suspender.suspended_threads_list(),
@@ -278,50 +299,84 @@ class ScopedStackSpaceWithGuard {
uptr guard_start_;
};
-static sigset_t blocked_sigset;
-static sigset_t old_sigset;
-static struct sigaction old_sigactions[ARRAY_SIZE(kUnblockedSignals)];
+// 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
+ [ARRAY_SIZE(kUnblockedSignals)];
-void StopTheWorld(StopTheWorldCallback callback, void *argument) {
- // Block all signals that can be blocked safely, and install default handlers
- // for the remaining signals.
- // We cannot allow user-defined handlers to run while the ThreadSuspender
- // thread is active, because they could conceivably call some libc functions
- // which modify errno (which is shared between the two threads).
- sigfillset(&blocked_sigset);
- for (uptr signal_index = 0; signal_index < ARRAY_SIZE(kUnblockedSignals);
- signal_index++) {
- // Remove the signal from the set of blocked signals.
- sigdelset(&blocked_sigset, kUnblockedSignals[signal_index]);
- // Install the default handler.
- struct sigaction new_sigaction;
- internal_memset(&new_sigaction, 0, sizeof(new_sigaction));
- new_sigaction.sa_handler = SIG_DFL;
- sigfillset(&new_sigaction.sa_mask);
- sigaction(kUnblockedSignals[signal_index], &new_sigaction,
- &old_sigactions[signal_index]);
+class StopTheWorldScope {
+ public:
+ StopTheWorldScope() {
+ // Block all signals that can be blocked safely, and install
+ // default handlers for the remaining signals.
+ // We cannot allow user-defined handlers to run while the ThreadSuspender
+ // thread is active, because they could conceivably call some libc functions
+ // which modify errno (which is shared between the two threads).
+ internal_sigfillset(&blocked_sigset);
+ for (uptr signal_index = 0; signal_index < ARRAY_SIZE(kUnblockedSignals);
+ signal_index++) {
+ // 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;
+ 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]);
+ }
+ int sigprocmask_status =
+ internal_sigprocmask(SIG_BLOCK, &blocked_sigset, &old_sigset);
+ CHECK_EQ(sigprocmask_status, 0); // sigprocmask should never fail
+ // Make this process dumpable. Processes that are not dumpable cannot be
+ // attached to.
+ process_was_dumpable_ = internal_prctl(PR_GET_DUMPABLE, 0, 0, 0, 0);
+ if (!process_was_dumpable_)
+ internal_prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
+ old_die_callback = GetDieCallback();
}
- int sigprocmask_status = sigprocmask(SIG_BLOCK, &blocked_sigset, &old_sigset);
- CHECK_EQ(sigprocmask_status, 0); // sigprocmask should never fail
- // Make this process dumpable. Processes that are not dumpable cannot be
- // attached to.
- int process_was_dumpable = internal_prctl(PR_GET_DUMPABLE, 0, 0, 0, 0);
- if (!process_was_dumpable)
- internal_prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
+
+ ~StopTheWorldScope() {
+ SetDieCallback(old_die_callback);
+ // Restore the dumpable flag.
+ if (!process_was_dumpable_)
+ internal_prctl(PR_SET_DUMPABLE, 0, 0, 0, 0);
+ // 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_sigprocmask(SIG_SETMASK, &old_sigset, &old_sigset);
+ }
+
+ private:
+ int process_was_dumpable_;
+};
+
+void StopTheWorld(StopTheWorldCallback callback, void *argument) {
+ StopTheWorldScope in_stoptheworld;
// Prepare the arguments for TracerThread.
struct TracerThreadArgument tracer_thread_argument;
tracer_thread_argument.callback = callback;
tracer_thread_argument.callback_argument = argument;
+ tracer_thread_argument.parent_pid = internal_getpid();
const uptr kTracerStackSize = 2 * 1024 * 1024;
ScopedStackSpaceWithGuard tracer_stack(kTracerStackSize);
// Block the execution of TracerThread until after we have set ptrace
// permissions.
tracer_thread_argument.mutex.Lock();
- pid_t tracer_pid = clone(TracerThread, tracer_stack.Bottom(),
- CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_UNTRACED,
- &tracer_thread_argument, 0, 0, 0);
- if (tracer_pid < 0) {
- Report("Failed spawning a tracer thread (errno %d).\n", errno);
+ uptr tracer_pid = internal_clone(
+ TracerThread, tracer_stack.Bottom(),
+ CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_UNTRACED,
+ &tracer_thread_argument, 0 /* parent_tidptr */, 0 /* newtls */, 0
+ /* child_tidptr */);
+ 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);
tracer_thread_argument.mutex.Unlock();
} else {
// On some systems we have to explicitly declare that we want to be traced
@@ -336,20 +391,12 @@ 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);
- int wperrno;
- if (internal_iserror(waitpid_status, &wperrno))
- Report("Waiting on the tracer thread failed (errno %d).\n", wperrno);
- }
- // Restore the dumpable flag.
- if (!process_was_dumpable)
- internal_prctl(PR_SET_DUMPABLE, 0, 0, 0, 0);
- // Restore the signal handlers.
- for (uptr signal_index = 0; signal_index < ARRAY_SIZE(kUnblockedSignals);
- signal_index++) {
- sigaction(kUnblockedSignals[signal_index],
- &old_sigactions[signal_index], NULL);
+ if (internal_iserror(waitpid_status, &local_errno)) {
+ if (common_flags()->verbosity)
+ Report("Waiting on the tracer thread failed (errno %d).\n",
+ local_errno);
+ }
}
- sigprocmask(SIG_SETMASK, &old_sigset, &old_sigset);
}
// Platform-specific methods from SuspendedThreadsList.
@@ -373,6 +420,10 @@ typedef user_regs_struct regs_struct;
typedef pt_regs regs_struct;
#define REG_SP gpr[PT_R1]
+#elif defined(__mips__)
+typedef struct user regs_struct;
+#define REG_SP regs[EF_REG29]
+
#else
#error "Unsupported architecture"
#endif // SANITIZER_ANDROID && defined(__arm__)
@@ -385,7 +436,8 @@ int SuspendedThreadsList::GetRegistersAndSP(uptr index,
int pterrno;
if (internal_iserror(internal_ptrace(PTRACE_GETREGS, tid, NULL, &regs),
&pterrno)) {
- Report("Could not get registers from thread %d (errno %d).\n",
+ if (common_flags()->verbosity)
+ Report("Could not get registers from thread %d (errno %d).\n",
tid, pterrno);
return -1;
}
@@ -400,4 +452,4 @@ uptr SuspendedThreadsList::RegisterCount() {
}
} // namespace __sanitizer
-#endif // SANITIZER_LINUX
+#endif // SANITIZER_LINUX && defined(__x86_64__)
diff --git a/lib/sanitizer_common/sanitizer_suppressions.cc b/lib/sanitizer_common/sanitizer_suppressions.cc
new file mode 100644
index 000000000000..5f3d2cee8cef
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_suppressions.cc
@@ -0,0 +1,153 @@
+//===-- sanitizer_suppressions.cc -----------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Suppression parsing/matching code shared between TSan and LSan.
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_suppressions.h"
+
+#include "sanitizer_allocator_internal.h"
+#include "sanitizer_common.h"
+#include "sanitizer_libc.h"
+
+namespace __sanitizer {
+
+static const char *const kTypeStrings[SuppressionTypeCount] = {
+ "none", "race", "mutex", "thread", "signal", "leak", "called_from_lib"
+};
+
+bool TemplateMatch(char *templ, const char *str) {
+ if (str == 0 || str[0] == 0)
+ return false;
+ bool start = false;
+ if (templ && templ[0] == '^') {
+ start = true;
+ templ++;
+ }
+ bool asterisk = false;
+ while (templ && templ[0]) {
+ if (templ[0] == '*') {
+ templ++;
+ start = false;
+ asterisk = true;
+ continue;
+ }
+ if (templ[0] == '$')
+ return str[0] == 0 || asterisk;
+ if (str[0] == 0)
+ return false;
+ char *tpos = (char*)internal_strchr(templ, '*');
+ char *tpos1 = (char*)internal_strchr(templ, '$');
+ if (tpos == 0 || (tpos1 && tpos1 < tpos))
+ tpos = tpos1;
+ if (tpos != 0)
+ tpos[0] = 0;
+ const char *str0 = str;
+ const char *spos = internal_strstr(str, templ);
+ str = spos + internal_strlen(templ);
+ templ = tpos;
+ if (tpos)
+ tpos[0] = tpos == tpos1 ? '$' : '*';
+ if (spos == 0)
+ return false;
+ if (start && spos != str0)
+ return false;
+ start = false;
+ asterisk = false;
+ }
+ return true;
+}
+
+bool SuppressionContext::Match(const char *str, SuppressionType type,
+ Suppression **s) {
+ can_parse_ = false;
+ uptr i;
+ for (i = 0; i < suppressions_.size(); i++)
+ if (type == suppressions_[i].type &&
+ TemplateMatch(suppressions_[i].templ, str))
+ break;
+ if (i == suppressions_.size()) return false;
+ *s = &suppressions_[i];
+ return true;
+}
+
+static const char *StripPrefix(const char *str, const char *prefix) {
+ while (str && *str == *prefix) {
+ str++;
+ prefix++;
+ }
+ if (!*prefix)
+ return str;
+ return 0;
+}
+
+void SuppressionContext::Parse(const char *str) {
+ // Context must not mutate once Match has been called.
+ CHECK(can_parse_);
+ const char *line = str;
+ while (line) {
+ while (line[0] == ' ' || line[0] == '\t')
+ line++;
+ const char *end = internal_strchr(line, '\n');
+ if (end == 0)
+ end = line + internal_strlen(line);
+ if (line != end && line[0] != '#') {
+ const char *end2 = end;
+ while (line != end2 && (end2[-1] == ' ' || end2[-1] == '\t'))
+ end2--;
+ int type;
+ for (type = 0; type < SuppressionTypeCount; type++) {
+ const char *next_char = StripPrefix(line, kTypeStrings[type]);
+ if (next_char && *next_char == ':') {
+ line = ++next_char;
+ break;
+ }
+ }
+ if (type == SuppressionTypeCount) {
+ Printf("%s: failed to parse suppressions\n", SanitizerToolName);
+ Die();
+ }
+ Suppression s;
+ s.type = static_cast<SuppressionType>(type);
+ s.templ = (char*)InternalAlloc(end2 - line + 1);
+ internal_memcpy(s.templ, line, end2 - line);
+ s.templ[end2 - line] = 0;
+ s.hit_count = 0;
+ s.weight = 0;
+ suppressions_.push_back(s);
+ }
+ if (end[0] == 0)
+ break;
+ line = end + 1;
+ }
+}
+
+uptr SuppressionContext::SuppressionCount() const {
+ return suppressions_.size();
+}
+
+const Suppression *SuppressionContext::SuppressionAt(uptr i) const {
+ CHECK_LT(i, suppressions_.size());
+ return &suppressions_[i];
+}
+
+void SuppressionContext::GetMatched(
+ InternalMmapVector<Suppression *> *matched) {
+ for (uptr i = 0; i < suppressions_.size(); i++)
+ if (suppressions_[i].hit_count)
+ matched->push_back(&suppressions_[i]);
+}
+
+const char *SuppressionTypeString(SuppressionType t) {
+ CHECK(t < SuppressionTypeCount);
+ return kTypeStrings[t];
+}
+
+} // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_suppressions.h b/lib/sanitizer_common/sanitizer_suppressions.h
new file mode 100644
index 000000000000..92cb09365b5e
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_suppressions.h
@@ -0,0 +1,61 @@
+//===-- sanitizer_suppressions.h --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Suppression parsing/matching code shared between TSan and LSan.
+//
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_SUPPRESSIONS_H
+#define SANITIZER_SUPPRESSIONS_H
+
+#include "sanitizer_common.h"
+#include "sanitizer_internal_defs.h"
+
+namespace __sanitizer {
+
+enum SuppressionType {
+ SuppressionNone,
+ SuppressionRace,
+ SuppressionMutex,
+ SuppressionThread,
+ SuppressionSignal,
+ SuppressionLeak,
+ SuppressionLib,
+ SuppressionTypeCount
+};
+
+struct Suppression {
+ SuppressionType type;
+ char *templ;
+ unsigned hit_count;
+ uptr weight;
+};
+
+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;
+ const Suppression *SuppressionAt(uptr i) const;
+ void GetMatched(InternalMmapVector<Suppression *> *matched);
+
+ private:
+ InternalMmapVector<Suppression> suppressions_;
+ bool can_parse_;
+
+ friend class SuppressionContextTest;
+};
+
+const char *SuppressionTypeString(SuppressionType t);
+
+bool TemplateMatch(char *templ, const char *str);
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_SUPPRESSIONS_H
diff --git a/lib/sanitizer_common/sanitizer_symbolizer.cc b/lib/sanitizer_common/sanitizer_symbolizer.cc
new file mode 100644
index 000000000000..2290767b0930
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_symbolizer.cc
@@ -0,0 +1,63 @@
+//===-- sanitizer_symbolizer.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.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_platform.h"
+#include "sanitizer_internal_defs.h"
+#include "sanitizer_placement_new.h"
+#include "sanitizer_symbolizer.h"
+
+namespace __sanitizer {
+
+Symbolizer *Symbolizer::symbolizer_;
+StaticSpinMutex Symbolizer::init_mu_;
+LowLevelAllocator Symbolizer::symbolizer_allocator_;
+
+Symbolizer *Symbolizer::GetOrNull() {
+ SpinMutexLock l(&init_mu_);
+ return symbolizer_;
+}
+
+Symbolizer *Symbolizer::Get() {
+ SpinMutexLock l(&init_mu_);
+ RAW_CHECK_MSG(symbolizer_ != 0, "Using uninitialized symbolizer!");
+ return symbolizer_;
+}
+
+Symbolizer *Symbolizer::Disable() {
+ CHECK_EQ(0, symbolizer_);
+ // Initialize a dummy symbolizer.
+ symbolizer_ = new(symbolizer_allocator_) Symbolizer;
+ return symbolizer_;
+}
+
+void Symbolizer::AddHooks(Symbolizer::StartSymbolizationHook start_hook,
+ Symbolizer::EndSymbolizationHook end_hook) {
+ CHECK(start_hook_ == 0 && end_hook_ == 0);
+ start_hook_ = start_hook;
+ end_hook_ = end_hook;
+}
+
+Symbolizer::Symbolizer() : start_hook_(0), end_hook_(0) {}
+
+Symbolizer::SymbolizerScope::SymbolizerScope(const Symbolizer *sym)
+ : sym_(sym) {
+ if (sym_->start_hook_)
+ sym_->start_hook_();
+}
+
+Symbolizer::SymbolizerScope::~SymbolizerScope() {
+ if (sym_->end_hook_)
+ sym_->end_hook_();
+}
+
+} // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_symbolizer.h b/lib/sanitizer_common/sanitizer_symbolizer.h
index ef37fd387f98..886fed20db03 100644
--- a/lib/sanitizer_common/sanitizer_symbolizer.h
+++ b/lib/sanitizer_common/sanitizer_symbolizer.h
@@ -7,26 +7,21 @@
//
//===----------------------------------------------------------------------===//
//
-// Symbolizer is intended to be used by both
-// AddressSanitizer and ThreadSanitizer to symbolize a given
-// address. It is an analogue of addr2line utility and allows to map
-// instruction address to a location in source code at run-time.
+// Symbolizer is used by sanitizers to map instruction address to a location in
+// source code at run-time. Symbolizer either uses __sanitizer_symbolize_*
+// defined in the program, or (if they are missing) tries to find and
+// launch "llvm-symbolizer" commandline tool in a separate process and
+// communicate with it.
//
-// Symbolizer is planned to use debug information (in DWARF format)
-// in a binary via interface defined in "llvm/DebugInfo/DIContext.h"
-//
-// Symbolizer code should be called from the run-time library of
-// dynamic tools, and generally should not call memory allocation
-// routines or other system library functions intercepted by those tools.
-// Instead, Symbolizer code should use their replacements, defined in
-// "compiler-rt/lib/sanitizer_common/sanitizer_libc.h".
+// Generally we should try to avoid calling system library functions during
+// symbolization (and use their replacements from sanitizer_libc.h instead).
//===----------------------------------------------------------------------===//
#ifndef SANITIZER_SYMBOLIZER_H
#define SANITIZER_SYMBOLIZER_H
+#include "sanitizer_allocator_internal.h"
#include "sanitizer_internal_defs.h"
#include "sanitizer_libc.h"
-// WARNING: Do not include system headers here. See details above.
namespace __sanitizer {
@@ -42,8 +37,14 @@ struct AddressInfo {
AddressInfo() {
internal_memset(this, 0, sizeof(AddressInfo));
}
+
// Deletes all strings and sets all fields to zero.
- void Clear();
+ void Clear() {
+ InternalFree(module);
+ InternalFree(function);
+ InternalFree(file);
+ internal_memset(this, 0, sizeof(AddressInfo));
+ }
void FillAddressAndModuleInfo(uptr addr, const char *mod_name,
uptr mod_offset) {
@@ -62,60 +63,84 @@ struct DataInfo {
uptr size;
};
-// 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.
-// This function should NOT be called from two threads simultaneously.
-uptr SymbolizeCode(uptr address, AddressInfo *frames, uptr max_frames)
- SANITIZER_WEAK_ATTRIBUTE;
-bool SymbolizeData(uptr address, DataInfo *info);
-
-bool IsSymbolizerAvailable();
-void FlushSymbolizer(); // releases internal caches (if any)
-
-// Attempts to demangle the provided C++ mangled name.
-const char *Demangle(const char *Name);
-
-// Starts external symbolizer program in a subprocess. Sanitizer communicates
-// with external symbolizer via pipes.
-bool InitializeExternalSymbolizer(const char *path_to_symbolizer);
-
-class LoadedModule {
+class Symbolizer {
public:
- LoadedModule(const char *module_name, uptr base_address);
- void addAddressRange(uptr beg, uptr end);
- bool containsAddress(uptr address) const;
-
- const char *full_name() const { return full_name_; }
- uptr base_address() const { return base_address_; }
+ /// 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.
+ 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;
+ }
+ virtual bool SymbolizeData(uptr address, DataInfo *info) {
+ return false;
+ }
+ virtual bool IsAvailable() {
+ return false;
+ }
+ virtual bool IsExternalAvailable() {
+ return false;
+ }
+ // Release internal caches (if any).
+ virtual void Flush() {}
+ // Attempts to demangle the provided C++ mangled name.
+ virtual const char *Demangle(const char *name) {
+ return name;
+ }
+ virtual void PrepareForSandboxing() {}
+
+ // Allow user to install hooks that would be called before/after Symbolizer
+ // does the actual file/line info fetching. Specific sanitizers may need this
+ // to distinguish system library calls made in user code from calls made
+ // during in-process symbolization.
+ typedef void (*StartSymbolizationHook)();
+ typedef void (*EndSymbolizationHook)();
+ // May be called at most once.
+ void AddHooks(StartSymbolizationHook start_hook,
+ EndSymbolizationHook end_hook);
private:
- struct AddressRange {
- uptr beg;
- uptr end;
+ /// 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 *symbolizer_;
+ static StaticSpinMutex init_mu_;
+
+ protected:
+ Symbolizer();
+
+ static LowLevelAllocator symbolizer_allocator_;
+
+ StartSymbolizationHook start_hook_;
+ EndSymbolizationHook end_hook_;
+ class SymbolizerScope {
+ public:
+ explicit SymbolizerScope(const Symbolizer *sym);
+ ~SymbolizerScope();
+ private:
+ const Symbolizer *sym_;
};
- char *full_name_;
- uptr base_address_;
- static const uptr kMaxNumberOfAddressRanges = 6;
- AddressRange ranges_[kMaxNumberOfAddressRanges];
- uptr n_ranges_;
};
-// Creates external symbolizer connected via pipe, user should write
-// to output_fd and read from input_fd.
-bool StartSymbolizerSubprocess(const char *path_to_symbolizer,
- int *input_fd, int *output_fd);
-
-// OS-dependent function that fills array with descriptions of at most
-// "max_modules" currently loaded modules. Returns the number of
-// initialized modules. If filter is nonzero, ignores modules for which
-// filter(full_name) is false.
-typedef bool (*string_predicate_t)(const char *);
-uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
- string_predicate_t filter);
-
-void SymbolizerPrepareForSandboxing();
-
} // namespace __sanitizer
#endif // SANITIZER_SYMBOLIZER_H
diff --git a/lib/sanitizer_common/sanitizer_symbolizer_itanium.cc b/lib/sanitizer_common/sanitizer_symbolizer_itanium.cc
deleted file mode 100644
index e20fb91f0eb5..000000000000
--- a/lib/sanitizer_common/sanitizer_symbolizer_itanium.cc
+++ /dev/null
@@ -1,44 +0,0 @@
-//===-- sanitizer_symbolizer_itanium.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 the sanitizer run-time libraries.
-// Itanium C++ ABI-specific implementation of symbolizer parts.
-//===----------------------------------------------------------------------===//
-
-#include "sanitizer_platform.h"
-#if SANITIZER_MAC || SANITIZER_LINUX
-
-#include "sanitizer_symbolizer.h"
-
-#include <stdlib.h>
-
-// C++ demangling function, as required by Itanium C++ ABI. This is weak,
-// because we do not require a C++ ABI library to be linked to a program
-// using sanitizers; if it's not present, we'll just use the mangled name.
-namespace __cxxabiv1 {
- extern "C" char *__cxa_demangle(const char *mangled, char *buffer,
- size_t *length, int *status)
- SANITIZER_WEAK_ATTRIBUTE;
-}
-
-const char *__sanitizer::Demangle(const char *MangledName) {
- // FIXME: __cxa_demangle aggressively insists on allocating memory.
- // There's not much we can do about that, short of providing our
- // own demangler (libc++abi's implementation could be adapted so that
- // it does not allocate). For now, we just call it anyway, and we leak
- // the returned value.
- if (__cxxabiv1::__cxa_demangle)
- if (const char *Demangled =
- __cxxabiv1::__cxa_demangle(MangledName, 0, 0, 0))
- return Demangled;
-
- return MangledName;
-}
-
-#endif // SANITIZER_MAC || SANITIZER_LINUX
diff --git a/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc b/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc
index ad339e21a927..b431e51e24d6 100644
--- a/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc
@@ -8,446 +8,32 @@
//===----------------------------------------------------------------------===//
//
// This file is shared between AddressSanitizer and ThreadSanitizer
-// run-time libraries. See sanitizer_symbolizer.h for details.
+// run-time libraries.
//===----------------------------------------------------------------------===//
-#include "sanitizer_common.h"
-#include "sanitizer_placement_new.h"
-#include "sanitizer_procmaps.h"
+#include "sanitizer_internal_defs.h"
#include "sanitizer_symbolizer.h"
namespace __sanitizer {
-void AddressInfo::Clear() {
- InternalFree(module);
- InternalFree(function);
- InternalFree(file);
- internal_memset(this, 0, sizeof(AddressInfo));
+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;
}
-LoadedModule::LoadedModule(const char *module_name, uptr base_address) {
- full_name_ = internal_strdup(module_name);
- base_address_ = base_address;
- n_ranges_ = 0;
+Symbolizer *Symbolizer::Init(const char *path_to_external) {
+ CHECK_EQ(0, symbolizer_);
+ return CreateAndStore(path_to_external);
}
-void LoadedModule::addAddressRange(uptr beg, uptr end) {
- CHECK_LT(n_ranges_, kMaxNumberOfAddressRanges);
- ranges_[n_ranges_].beg = beg;
- ranges_[n_ranges_].end = end;
- n_ranges_++;
-}
-
-bool LoadedModule::containsAddress(uptr address) const {
- for (uptr i = 0; i < n_ranges_; i++) {
- if (ranges_[i].beg <= address && address < ranges_[i].end)
- return true;
- }
- return false;
-}
-
-// 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.
-// Returns a pointer to "str" after skipping extracted prefix and first
-// delimiter char.
-static const char *ExtractToken(const char *str, const char *delims,
- char **result) {
- uptr prefix_len = internal_strcspn(str, delims);
- *result = (char*)InternalAlloc(prefix_len + 1);
- internal_memcpy(*result, str, prefix_len);
- (*result)[prefix_len] = '\0';
- const char *prefix_end = str + prefix_len;
- if (*prefix_end != '\0') prefix_end++;
- return prefix_end;
-}
-
-// Same as ExtractToken, but converts extracted token to integer.
-static const char *ExtractInt(const char *str, const char *delims,
- int *result) {
- char *buff;
- const char *ret = ExtractToken(str, delims, &buff);
- if (buff != 0) {
- *result = (int)internal_atoll(buff);
- }
- InternalFree(buff);
- return ret;
-}
-
-static const char *ExtractUptr(const char *str, const char *delims,
- uptr *result) {
- char *buff;
- const char *ret = ExtractToken(str, delims, &buff);
- if (buff != 0) {
- *result = (uptr)internal_atoll(buff);
- }
- InternalFree(buff);
- 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 {
- public:
- ExternalSymbolizer(const char *path, int input_fd, int output_fd)
- : path_(path),
- input_fd_(input_fd),
- output_fd_(output_fd),
- times_restarted_(0) {
- CHECK(path_);
- CHECK_NE(input_fd_, kInvalidFd);
- CHECK_NE(output_fd_, kInvalidFd);
- }
-
- char *SendCommand(bool is_data, const char *module_name, uptr module_offset) {
- CHECK(module_name);
- internal_snprintf(buffer_, kBufferSize, "%s\"%s\" 0x%zx\n",
- is_data ? "DATA " : "", module_name, module_offset);
- if (!writeToSymbolizer(buffer_, internal_strlen(buffer_)))
- return 0;
- if (!readFromSymbolizer(buffer_, kBufferSize))
- return 0;
- 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);
- // We can't read 0 bytes, as we don't expect external symbolizer to close
- // its stdout.
- if (just_read == 0 || just_read == (uptr)-1) {
- Report("WARNING: Can't read from symbolizer at fd %d\n", input_fd_);
- return false;
- }
- read_len += just_read;
- // Empty line marks the end of symbolizer output.
- if (read_len >= 2 && buffer[read_len - 1] == '\n' &&
- buffer[read_len - 2] == '\n') {
- break;
- }
- }
- return true;
- }
-
- bool writeToSymbolizer(const char *buffer, uptr length) {
- if (length == 0)
- return true;
- uptr write_len = internal_write(output_fd_, buffer, length);
- if (write_len == 0 || write_len == (uptr)-1) {
- Report("WARNING: Can't write to symbolizer at fd %d\n", output_fd_);
- return false;
- }
- return true;
- }
-
- const char *path_;
- int input_fd_;
- int output_fd_;
-
- static const uptr kBufferSize = 16 * 1024;
- char buffer_[kBufferSize];
-
- static const uptr kMaxTimesRestarted = 5;
- uptr times_restarted_;
-};
-
-static LowLevelAllocator symbolizer_allocator; // Linker initialized.
-
-#if SANITIZER_SUPPORTS_WEAK_HOOKS
-extern "C" {
-SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
-bool __sanitizer_symbolize_code(const char *ModuleName, u64 ModuleOffset,
- char *Buffer, int MaxLength);
-SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
-bool __sanitizer_symbolize_data(const char *ModuleName, u64 ModuleOffset,
- char *Buffer, int MaxLength);
-SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
-void __sanitizer_symbolize_flush();
-} // extern "C"
-
-class InternalSymbolizer {
- public:
- typedef bool (*SanitizerSymbolizeFn)(const char*, u64, char*, int);
-
- static InternalSymbolizer *get() {
- if (__sanitizer_symbolize_code != 0 &&
- __sanitizer_symbolize_data != 0) {
- void *mem = symbolizer_allocator.Allocate(sizeof(InternalSymbolizer));
- return new(mem) InternalSymbolizer();
- }
- return 0;
- }
-
- char *SendCommand(bool is_data, const char *module_name, uptr module_offset) {
- SanitizerSymbolizeFn symbolize_fn = is_data ? __sanitizer_symbolize_data
- : __sanitizer_symbolize_code;
- if (symbolize_fn(module_name, module_offset, buffer_, kBufferSize))
- return buffer_;
- return 0;
- }
-
- void Flush() {
- if (__sanitizer_symbolize_flush)
- __sanitizer_symbolize_flush();
- }
-
- private:
- InternalSymbolizer() { }
-
- static const int kBufferSize = 16 * 1024;
- char buffer_[kBufferSize];
-};
-#else // SANITIZER_SUPPORTS_WEAK_HOOKS
-
-class InternalSymbolizer {
- public:
- static InternalSymbolizer *get() { return 0; }
- char *SendCommand(bool is_data, const char *module_name, uptr module_offset) {
- return 0;
- }
- void Flush() {
- }
-};
-
-#endif // SANITIZER_SUPPORTS_WEAK_HOOKS
-
-class Symbolizer {
- // This class has no constructor, as global constructors are forbidden in
- // sanitizer_common. It should be linker initialized instead.
- public:
- uptr SymbolizeCode(uptr addr, AddressInfo *frames, uptr max_frames) {
- 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 *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;
- }
- uptr frame_id = 0;
- for (frame_id = 0; frame_id < max_frames; frame_id++) {
- AddressInfo *info = &frames[frame_id];
- char *function_name = 0;
- str = ExtractToken(str, "\n", &function_name);
- CHECK(function_name);
- if (function_name[0] == '\0') {
- // There are no more frames.
- break;
- }
- info->Clear();
- info->FillAddressAndModuleInfo(addr, module_name, module_offset);
- info->function = function_name;
- // Parse <file>:<line>:<column> buffer.
- char *file_line_info = 0;
- str = ExtractToken(str, "\n", &file_line_info);
- CHECK(file_line_info);
- const char *line_info = ExtractToken(file_line_info, ":", &info->file);
- line_info = ExtractInt(line_info, ":", &info->line);
- line_info = ExtractInt(line_info, "", &info->column);
- InternalFree(file_line_info);
-
- // Functions and filenames can be "??", in which case we write 0
- // to address info to mark that names are unknown.
- if (0 == internal_strcmp(info->function, "??")) {
- InternalFree(info->function);
- info->function = 0;
- }
- if (0 == internal_strcmp(info->file, "??")) {
- InternalFree(info->file);
- info->file = 0;
- }
- }
- 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;
- }
-
- bool SymbolizeData(uptr addr, DataInfo *info) {
- 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->module = internal_strdup(module_name);
- info->module_offset = module_offset;
- const char *str = SendCommand(true, module_name, module_offset);
- if (str == 0)
- return true;
- str = ExtractToken(str, "\n", &info->name);
- str = ExtractUptr(str, " ", &info->start);
- str = ExtractUptr(str, "\n", &info->size);
- info->start += module->base_address();
- return true;
- }
-
- bool InitializeExternalSymbolizer(const char *path_to_symbolizer) {
- int input_fd, output_fd;
- if (!StartSymbolizerSubprocess(path_to_symbolizer, &input_fd, &output_fd))
- return false;
- void *mem = symbolizer_allocator.Allocate(sizeof(ExternalSymbolizer));
- external_symbolizer_ = new(mem) ExternalSymbolizer(path_to_symbolizer,
- input_fd, output_fd);
- return true;
- }
-
- bool IsSymbolizerAvailable() {
- if (internal_symbolizer_ == 0)
- internal_symbolizer_ = InternalSymbolizer::get();
- return internal_symbolizer_ || external_symbolizer_;
- }
-
- void Flush() {
- if (internal_symbolizer_)
- internal_symbolizer_->Flush();
- if (external_symbolizer_)
- external_symbolizer_->Flush();
- }
-
- private:
- char *SendCommand(bool is_data, const char *module_name, uptr module_offset) {
- // First, try to use internal symbolizer.
- if (!IsSymbolizerAvailable()) {
- return 0;
- }
- if (internal_symbolizer_) {
- return internal_symbolizer_->SendCommand(is_data, module_name,
- 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;
- }
- }
- }
-
- LoadedModule *FindModuleForAddress(uptr address) {
- bool modules_were_reloaded = false;
- if (modules_ == 0 || !modules_fresh_) {
- modules_ = (LoadedModule*)(symbolizer_allocator.Allocate(
- kMaxNumberOfModuleContexts * sizeof(LoadedModule)));
- 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_LT(n_modules_, kMaxNumberOfModuleContexts);
- modules_fresh_ = true;
- modules_were_reloaded = true;
- }
- for (uptr i = 0; i < n_modules_; i++) {
- if (modules_[i].containsAddress(address)) {
- return &modules_[i];
- }
- }
- // Reload the modules and look up again, if we haven't tried it yet.
- if (!modules_were_reloaded) {
- // FIXME: set modules_fresh_ from dlopen()/dlclose() interceptors.
- // It's too aggressive to reload the list of modules each time we fail
- // to find a module for a given address.
- modules_fresh_ = false;
- return FindModuleForAddress(address);
- }
- 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;
- }
- }
-
- // 16K loaded modules should be enough for everyone.
- static const uptr kMaxNumberOfModuleContexts = 1 << 14;
- LoadedModule *modules_; // Array of module descriptions is leaked.
- uptr n_modules_;
- // If stale, need to reload the modules before looking up addresses.
- bool modules_fresh_;
-
- ExternalSymbolizer *external_symbolizer_; // Leaked.
- InternalSymbolizer *internal_symbolizer_; // Leaked.
-};
-
-static Symbolizer symbolizer; // Linker initialized.
-
-uptr SymbolizeCode(uptr address, AddressInfo *frames, uptr max_frames) {
- return symbolizer.SymbolizeCode(address, frames, max_frames);
-}
-
-bool SymbolizeData(uptr address, DataInfo *info) {
- return symbolizer.SymbolizeData(address, info);
-}
-
-bool InitializeExternalSymbolizer(const char *path_to_symbolizer) {
- return symbolizer.InitializeExternalSymbolizer(path_to_symbolizer);
-}
-
-bool IsSymbolizerAvailable() {
- return symbolizer.IsSymbolizerAvailable();
-}
-
-void FlushSymbolizer() {
- symbolizer.Flush();
+Symbolizer *Symbolizer::GetOrInit() {
+ SpinMutexLock l(&init_mu_);
+ if (symbolizer_ == 0)
+ return CreateAndStore(0);
+ return symbolizer_;
}
} // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_symbolizer_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_symbolizer_linux_libcdep.cc
deleted file mode 100644
index 82ce50e0aacb..000000000000
--- a/lib/sanitizer_common/sanitizer_symbolizer_linux_libcdep.cc
+++ /dev/null
@@ -1,227 +0,0 @@
-//===-- sanitizer_symbolizer_linux_libcdep.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.
-// Linux-specific implementation of symbolizer parts.
-//===----------------------------------------------------------------------===//
-
-#include "sanitizer_platform.h"
-#if SANITIZER_LINUX
-#include "sanitizer_common.h"
-#include "sanitizer_internal_defs.h"
-#include "sanitizer_libc.h"
-#include "sanitizer_placement_new.h"
-#include "sanitizer_symbolizer.h"
-
-// Android NDK r8e elf.h depends on stdint.h without including the latter.
-#include <stdint.h>
-
-#include <elf.h>
-#include <errno.h>
-#include <poll.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-#if !SANITIZER_ANDROID
-#include <link.h>
-#endif
-
-namespace __sanitizer {
-
-static const int kSymbolizerStartupTimeMillis = 10;
-
-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, (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;
-}
-
-#if SANITIZER_ANDROID
-uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
- string_predicate_t filter) {
- return 0;
-}
-
-void SymbolizerPrepareForSandboxing() {
- // Do nothing on Android.
-}
-#else // SANITIZER_ANDROID
-typedef ElfW(Phdr) Elf_Phdr;
-
-struct DlIteratePhdrData {
- LoadedModule *modules;
- uptr current_n;
- bool first;
- uptr max_n;
- string_predicate_t filter;
-};
-
-static const uptr kMaxPathLength = 512;
-
-static char proc_self_exe_cache_str[kMaxPathLength];
-static uptr proc_self_exe_cache_len = 0;
-
-static uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) {
- uptr module_name_len = internal_readlink(
- "/proc/self/exe", buf, buf_len);
- int readlink_error;
- if (internal_iserror(buf_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");
- }
- CHECK_LT(module_name_len, buf_len);
- buf[module_name_len] = '\0';
- }
- return module_name_len;
-}
-
-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';
- 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());
- }
- if (module_name.data()[0] == '\0')
- return 0;
- if (data->filter && !data->filter(module_name.data()))
- return 0;
- void *mem = &data->modules[data->current_n];
- LoadedModule *cur_module = new(mem) LoadedModule(module_name.data(),
- info->dlpi_addr);
- data->current_n++;
- for (int i = 0; i < info->dlpi_phnum; i++) {
- const Elf_Phdr *phdr = &info->dlpi_phdr[i];
- 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);
- }
- }
- return 0;
-}
-
-uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
- string_predicate_t filter) {
- CHECK(modules);
- DlIteratePhdrData data = {modules, 0, true, max_modules, filter};
- dl_iterate_phdr(dl_iterate_phdr_cb, &data);
- return data.current_n;
-}
-
-void SymbolizerPrepareForSandboxing() {
- if (!proc_self_exe_cache_len) {
- proc_self_exe_cache_len =
- ReadBinaryName(proc_self_exe_cache_str, kMaxPathLength);
- }
-}
-#endif // SANITIZER_ANDROID
-
-} // namespace __sanitizer
-
-#endif // SANITIZER_LINUX
diff --git a/lib/sanitizer_common/sanitizer_symbolizer_mac.cc b/lib/sanitizer_common/sanitizer_symbolizer_mac.cc
deleted file mode 100644
index 9d96690bfda2..000000000000
--- a/lib/sanitizer_common/sanitizer_symbolizer_mac.cc
+++ /dev/null
@@ -1,40 +0,0 @@
-//===-- sanitizer_symbolizer_mac.cc ---------------------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file is shared between AddressSanitizer and ThreadSanitizer
-// run-time libraries.
-// Mac-specific implementation of symbolizer parts.
-//===----------------------------------------------------------------------===//
-
-#include "sanitizer_platform.h"
-#if SANITIZER_MAC
-#include "sanitizer_internal_defs.h"
-#include "sanitizer_symbolizer.h"
-
-namespace __sanitizer {
-
-bool StartSymbolizerSubprocess(const char *path_to_symbolizer,
- int *input_fd, int *output_fd) {
- UNIMPLEMENTED();
-}
-
-uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
- string_predicate_t filter) {
- // FIXME: Actually implement this on Mac. Just using MemoryMappingLayout
- // may be enough for this on Mac.
- return 0;
-}
-
-void SymbolizerPrepareForSandboxing() {
- // Do nothing on Mac.
-}
-
-} // namespace __sanitizer
-
-#endif // SANITIZER_MAC
diff --git a/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc b/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc
new file mode 100644
index 000000000000..de11832870e3
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc
@@ -0,0 +1,601 @@
+//===-- sanitizer_symbolizer_posix_libcdep.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.
+// POSIX-specific implementation of symbolizer parts.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_platform.h"
+#if SANITIZER_POSIX
+#include "sanitizer_allocator_internal.h"
+#include "sanitizer_common.h"
+#include "sanitizer_internal_defs.h"
+#include "sanitizer_linux.h"
+#include "sanitizer_placement_new.h"
+#include "sanitizer_procmaps.h"
+#include "sanitizer_symbolizer.h"
+
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+// C++ demangling function, as required by Itanium C++ ABI. This is weak,
+// because we do not require a C++ ABI library to be linked to a program
+// using sanitizers; if it's not present, we'll just use the mangled name.
+namespace __cxxabiv1 {
+ extern "C" SANITIZER_WEAK_ATTRIBUTE
+ char *__cxa_demangle(const char *mangled, char *buffer,
+ size_t *length, int *status);
+}
+
+namespace __sanitizer {
+
+// Attempts to demangle the name via __cxa_demangle from __cxxabiv1.
+static const char *DemangleCXXABI(const char *name) {
+ // FIXME: __cxa_demangle aggressively insists on allocating memory.
+ // There's not much we can do about that, short of providing our
+ // own demangler (libc++abi's implementation could be adapted so that
+ // it does not allocate). For now, we just call it anyway, and we leak
+ // the returned value.
+ if (__cxxabiv1::__cxa_demangle)
+ if (const char *demangled_name =
+ __cxxabiv1::__cxa_demangle(name, 0, 0, 0))
+ return demangled_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.
+// Returns a pointer to "str" after skipping extracted prefix and first
+// delimiter char.
+static const char *ExtractToken(const char *str, const char *delims,
+ char **result) {
+ uptr prefix_len = internal_strcspn(str, delims);
+ *result = (char*)InternalAlloc(prefix_len + 1);
+ internal_memcpy(*result, str, prefix_len);
+ (*result)[prefix_len] = '\0';
+ const char *prefix_end = str + prefix_len;
+ if (*prefix_end != '\0') prefix_end++;
+ return prefix_end;
+}
+
+// Same as ExtractToken, but converts extracted token to integer.
+static const char *ExtractInt(const char *str, const char *delims,
+ int *result) {
+ char *buff;
+ const char *ret = ExtractToken(str, delims, &buff);
+ if (buff != 0) {
+ *result = (int)internal_atoll(buff);
+ }
+ InternalFree(buff);
+ return ret;
+}
+
+static const char *ExtractUptr(const char *str, const char *delims,
+ uptr *result) {
+ char *buff;
+ const char *ret = ExtractToken(str, delims, &buff);
+ if (buff != 0) {
+ *result = (uptr)internal_atoll(buff);
+ }
+ InternalFree(buff);
+ 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 {
+ public:
+ ExternalSymbolizer(const char *path, int input_fd, int output_fd)
+ : path_(path),
+ input_fd_(input_fd),
+ output_fd_(output_fd),
+ times_restarted_(0) {
+ CHECK(path_);
+ CHECK_NE(input_fd_, kInvalidFd);
+ CHECK_NE(output_fd_, kInvalidFd);
+ }
+
+ char *SendCommand(bool is_data, const char *module_name, uptr module_offset) {
+ CHECK(module_name);
+ internal_snprintf(buffer_, kBufferSize, "%s\"%s\" 0x%zx\n",
+ is_data ? "DATA " : "", module_name, module_offset);
+ if (!writeToSymbolizer(buffer_, internal_strlen(buffer_)))
+ return 0;
+ if (!readFromSymbolizer(buffer_, kBufferSize))
+ return 0;
+ 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);
+ // We can't read 0 bytes, as we don't expect external symbolizer to close
+ // its stdout.
+ if (just_read == 0 || just_read == (uptr)-1) {
+ Report("WARNING: Can't read from symbolizer at fd %d\n", input_fd_);
+ return false;
+ }
+ read_len += just_read;
+ // Empty line marks the end of symbolizer output.
+ if (read_len >= 2 && buffer[read_len - 1] == '\n' &&
+ buffer[read_len - 2] == '\n') {
+ break;
+ }
+ }
+ return true;
+ }
+
+ bool writeToSymbolizer(const char *buffer, uptr length) {
+ if (length == 0)
+ return true;
+ uptr write_len = internal_write(output_fd_, buffer, length);
+ if (write_len == 0 || write_len == (uptr)-1) {
+ Report("WARNING: Can't write to symbolizer at fd %d\n", output_fd_);
+ return false;
+ }
+ return true;
+ }
+
+ const char *path_;
+ int input_fd_;
+ int output_fd_;
+
+ static const uptr kBufferSize = 16 * 1024;
+ char buffer_[kBufferSize];
+
+ static const uptr kMaxTimesRestarted = 5;
+ uptr times_restarted_;
+};
+
+#if SANITIZER_SUPPORTS_WEAK_HOOKS
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+bool __sanitizer_symbolize_code(const char *ModuleName, u64 ModuleOffset,
+ char *Buffer, int MaxLength);
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+bool __sanitizer_symbolize_data(const char *ModuleName, u64 ModuleOffset,
+ char *Buffer, int MaxLength);
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+void __sanitizer_symbolize_flush();
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+int __sanitizer_symbolize_demangle(const char *Name, char *Buffer,
+ int MaxLength);
+} // extern "C"
+
+class InternalSymbolizer {
+ public:
+ typedef bool (*SanitizerSymbolizeFn)(const char*, u64, char*, int);
+
+ static InternalSymbolizer *get(LowLevelAllocator *alloc) {
+ if (__sanitizer_symbolize_code != 0 &&
+ __sanitizer_symbolize_data != 0) {
+ return new(*alloc) InternalSymbolizer();
+ }
+ return 0;
+ }
+
+ char *SendCommand(bool is_data, const char *module_name, uptr module_offset) {
+ SanitizerSymbolizeFn symbolize_fn = is_data ? __sanitizer_symbolize_data
+ : __sanitizer_symbolize_code;
+ if (symbolize_fn(module_name, module_offset, buffer_, kBufferSize))
+ return buffer_;
+ return 0;
+ }
+
+ void Flush() {
+ if (__sanitizer_symbolize_flush)
+ __sanitizer_symbolize_flush();
+ }
+
+ const char *Demangle(const char *name) {
+ if (__sanitizer_symbolize_demangle) {
+ for (uptr res_length = 1024;
+ res_length <= InternalSizeClassMap::kMaxSize;) {
+ char *res_buff = static_cast<char*>(InternalAlloc(res_length));
+ uptr req_length =
+ __sanitizer_symbolize_demangle(name, res_buff, res_length);
+ if (req_length > res_length) {
+ res_length = req_length + 1;
+ InternalFree(res_buff);
+ continue;
+ }
+ return res_buff;
+ }
+ }
+ return name;
+ }
+
+ private:
+ InternalSymbolizer() { }
+
+ static const int kBufferSize = 16 * 1024;
+ static const int kMaxDemangledNameSize = 1024;
+ char buffer_[kBufferSize];
+};
+#else // SANITIZER_SUPPORTS_WEAK_HOOKS
+
+class InternalSymbolizer {
+ public:
+ static InternalSymbolizer *get(LowLevelAllocator *alloc) { return 0; }
+ char *SendCommand(bool is_data, const char *module_name, uptr module_offset) {
+ return 0;
+ }
+ void Flush() { }
+ const char *Demangle(const char *name) { return name; }
+};
+
+#endif // SANITIZER_SUPPORTS_WEAK_HOOKS
+
+class POSIXSymbolizer : public Symbolizer {
+ public:
+ POSIXSymbolizer(ExternalSymbolizer *external_symbolizer,
+ InternalSymbolizer *internal_symbolizer)
+ : Symbolizer(),
+ external_symbolizer_(external_symbolizer),
+ internal_symbolizer_(internal_symbolizer) {}
+
+ uptr SymbolizeCode(uptr addr, AddressInfo *frames, uptr max_frames) {
+ 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 *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;
+ }
+ uptr frame_id = 0;
+ for (frame_id = 0; frame_id < max_frames; frame_id++) {
+ AddressInfo *info = &frames[frame_id];
+ char *function_name = 0;
+ str = ExtractToken(str, "\n", &function_name);
+ CHECK(function_name);
+ if (function_name[0] == '\0') {
+ // There are no more frames.
+ break;
+ }
+ info->Clear();
+ info->FillAddressAndModuleInfo(addr, module_name, module_offset);
+ info->function = function_name;
+ // Parse <file>:<line>:<column> buffer.
+ char *file_line_info = 0;
+ str = ExtractToken(str, "\n", &file_line_info);
+ CHECK(file_line_info);
+ const char *line_info = ExtractToken(file_line_info, ":", &info->file);
+ line_info = ExtractInt(line_info, ":", &info->line);
+ line_info = ExtractInt(line_info, "", &info->column);
+ InternalFree(file_line_info);
+
+ // Functions and filenames can be "??", in which case we write 0
+ // to address info to mark that names are unknown.
+ if (0 == internal_strcmp(info->function, "??")) {
+ InternalFree(info->function);
+ info->function = 0;
+ }
+ if (0 == internal_strcmp(info->file, "??")) {
+ InternalFree(info->file);
+ info->file = 0;
+ }
+ }
+ 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;
+ }
+
+ bool SymbolizeData(uptr addr, DataInfo *info) {
+ 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->module = internal_strdup(module_name);
+ info->module_offset = module_offset;
+ const char *str = SendCommand(true, module_name, module_offset);
+ if (str == 0)
+ return true;
+ str = ExtractToken(str, "\n", &info->name);
+ str = ExtractUptr(str, " ", &info->start);
+ str = ExtractUptr(str, "\n", &info->size);
+ info->start += module->base_address();
+ return true;
+ }
+
+ bool IsAvailable() {
+ return internal_symbolizer_ != 0 || external_symbolizer_ != 0;
+ }
+
+ bool IsExternalAvailable() {
+ return external_symbolizer_ != 0;
+ }
+
+ void Flush() {
+ 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) {
+ BlockingMutexLock l(&mu_);
+ // Run hooks even if we don't use internal symbolizer, as cxxabi
+ // demangle may call system functions.
+ SymbolizerScope sym_scope(this);
+ if (internal_symbolizer_ != 0)
+ return internal_symbolizer_->Demangle(name);
+ return DemangleCXXABI(name);
+ }
+
+ void PrepareForSandboxing() {
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+ BlockingMutexLock l(&mu_);
+ // Cache /proc/self/exe on Linux.
+ CacheBinaryName();
+#endif
+ }
+
+ private:
+ char *SendCommand(bool is_data, const char *module_name, uptr module_offset) {
+ mu_.CheckLocked();
+ // First, try to use internal symbolizer.
+ if (internal_symbolizer_) {
+ SymbolizerScope sym_scope(this);
+ return internal_symbolizer_->SendCommand(is_data, module_name,
+ 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;
+ }
+ }
+ }
+
+ LoadedModule *FindModuleForAddress(uptr address) {
+ mu_.CheckLocked();
+ bool modules_were_reloaded = false;
+ if (modules_ == 0 || !modules_fresh_) {
+ modules_ = (LoadedModule*)(symbolizer_allocator_.Allocate(
+ kMaxNumberOfModuleContexts * sizeof(LoadedModule)));
+ 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_LT(n_modules_, kMaxNumberOfModuleContexts);
+ modules_fresh_ = true;
+ modules_were_reloaded = true;
+ }
+ for (uptr i = 0; i < n_modules_; i++) {
+ if (modules_[i].containsAddress(address)) {
+ return &modules_[i];
+ }
+ }
+ // Reload the modules and look up again, if we haven't tried it yet.
+ if (!modules_were_reloaded) {
+ // FIXME: set modules_fresh_ from dlopen()/dlclose() interceptors.
+ // It's too aggressive to reload the list of modules each time we fail
+ // to find a module for a given address.
+ modules_fresh_ = false;
+ return FindModuleForAddress(address);
+ }
+ 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;
+ }
+ }
+
+ // 16K loaded modules should be enough for everyone.
+ static const uptr kMaxNumberOfModuleContexts = 1 << 14;
+ LoadedModule *modules_; // Array of module descriptions is leaked.
+ uptr n_modules_;
+ // If stale, need to reload the modules before looking up addresses.
+ bool modules_fresh_;
+ BlockingMutex mu_;
+
+ ExternalSymbolizer *external_symbolizer_; // Leaked.
+ InternalSymbolizer *const internal_symbolizer_; // Leaked.
+};
+
+Symbolizer *Symbolizer::PlatformInit(const char *path_to_external) {
+ InternalSymbolizer* internal_symbolizer =
+ InternalSymbolizer::get(&symbolizer_allocator_);
+ ExternalSymbolizer *external_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);
+ }
+ }
+
+ return new(symbolizer_allocator_)
+ POSIXSymbolizer(external_symbolizer, internal_symbolizer);
+}
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_POSIX
diff --git a/lib/sanitizer_common/sanitizer_symbolizer_win.cc b/lib/sanitizer_common/sanitizer_symbolizer_win.cc
index 993261aab7b0..5d451eff62bd 100644
--- a/lib/sanitizer_common/sanitizer_symbolizer_win.cc
+++ b/lib/sanitizer_common/sanitizer_symbolizer_win.cc
@@ -14,30 +14,11 @@
#include "sanitizer_platform.h"
#if SANITIZER_WINDOWS
-#include <windows.h>
-
-#include "sanitizer_internal_defs.h"
#include "sanitizer_symbolizer.h"
namespace __sanitizer {
-bool StartSymbolizerSubprocess(const char *path_to_symbolizer,
- int *input_fd, int *output_fd) {
- UNIMPLEMENTED();
-}
-
-uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
- string_predicate_t filter) {
- UNIMPLEMENTED();
-};
-
-void SymbolizerPrepareForSandboxing() {
- // Do nothing on Windows.
-}
-
-const char *Demangle(const char *MangledName) {
- return MangledName;
-}
+Symbolizer *Symbolizer::PlatformInit(const char *path_to_external) { return 0; }
} // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_syscall_linux_x86_64.inc b/lib/sanitizer_common/sanitizer_syscall_linux_x86_64.inc
index e084b84ab118..5ccb83a236bd 100644
--- a/lib/sanitizer_common/sanitizer_syscall_linux_x86_64.inc
+++ b/lib/sanitizer_common/sanitizer_syscall_linux_x86_64.inc
@@ -13,7 +13,8 @@
static uptr internal_syscall(u64 nr) {
u64 retval;
- asm volatile("syscall" : "=a"(retval) : "a"(nr) : "rcx", "r11");
+ asm volatile("syscall" : "=a"(retval) : "a"(nr) : "rcx", "r11",
+ "memory", "cc");
return retval;
}
@@ -21,7 +22,7 @@ template <typename T1>
static uptr internal_syscall(u64 nr, T1 arg1) {
u64 retval;
asm volatile("syscall" : "=a"(retval) : "a"(nr), "D"((u64)arg1) :
- "rcx", "r11");
+ "rcx", "r11", "memory", "cc");
return retval;
}
@@ -29,7 +30,7 @@ template <typename T1, typename T2>
static uptr internal_syscall(u64 nr, T1 arg1, T2 arg2) {
u64 retval;
asm volatile("syscall" : "=a"(retval) : "a"(nr), "D"((u64)arg1),
- "S"((u64)arg2) : "rcx", "r11");
+ "S"((u64)arg2) : "rcx", "r11", "memory", "cc");
return retval;
}
@@ -37,7 +38,7 @@ template <typename T1, typename T2, typename T3>
static uptr internal_syscall(u64 nr, T1 arg1, T2 arg2, T3 arg3) {
u64 retval;
asm volatile("syscall" : "=a"(retval) : "a"(nr), "D"((u64)arg1),
- "S"((u64)arg2), "d"((u64)arg3) : "rcx", "r11");
+ "S"((u64)arg2), "d"((u64)arg3) : "rcx", "r11", "memory", "cc");
return retval;
}
@@ -47,7 +48,7 @@ static uptr internal_syscall(u64 nr, T1 arg1, T2 arg2, T3 arg3, T4 arg4) {
asm volatile("mov %5, %%r10;"
"syscall" : "=a"(retval) : "a"(nr), "D"((u64)arg1),
"S"((u64)arg2), "d"((u64)arg3), "r"((u64)arg4) :
- "rcx", "r11", "r10");
+ "rcx", "r11", "r10", "memory", "cc");
return retval;
}
@@ -59,7 +60,7 @@ static uptr internal_syscall(u64 nr, T1 arg1, T2 arg2, T3 arg3, T4 arg4,
"mov %6, %%r8;"
"syscall" : "=a"(retval) : "a"(nr), "D"((u64)arg1),
"S"((u64)arg2), "d"((u64)arg3), "r"((u64)arg4), "r"((u64)arg5) :
- "rcx", "r11", "r10", "r8");
+ "rcx", "r11", "r10", "r8", "memory", "cc");
return retval;
}
@@ -73,7 +74,8 @@ static uptr internal_syscall(u64 nr, T1 arg1, T2 arg2, T3 arg3, T4 arg4,
"mov %7, %%r9;"
"syscall" : "=a"(retval) : "a"(nr), "D"((u64)arg1),
"S"((u64)arg2), "d"((u64)arg3), "r"((u64)arg4), "r"((u64)arg5),
- "r"((u64)arg6) : "rcx", "r11", "r10", "r8", "r9");
+ "r"((u64)arg6) : "rcx", "r11", "r10", "r8", "r9",
+ "memory", "cc");
return retval;
}
diff --git a/lib/sanitizer_common/sanitizer_thread_registry.cc b/lib/sanitizer_common/sanitizer_thread_registry.cc
index 466dc3b8a27f..bfa29a19cd2d 100644
--- a/lib/sanitizer_common/sanitizer_thread_registry.cc
+++ b/lib/sanitizer_common/sanitizer_thread_registry.cc
@@ -85,7 +85,7 @@ void ThreadContextBase::Reset() {
// ThreadRegistry implementation.
-const u32 ThreadRegistry::kUnknownTid = -1U;
+const u32 ThreadRegistry::kUnknownTid = ~0U;
ThreadRegistry::ThreadRegistry(ThreadContextFactory factory, u32 max_threads,
u32 thread_quarantine_size)
@@ -200,6 +200,18 @@ void ThreadRegistry::SetThreadName(u32 tid, const char *name) {
tctx->SetName(name);
}
+void ThreadRegistry::SetThreadNameByUserId(uptr user_id, const char *name) {
+ BlockingMutexLock l(&mtx_);
+ for (u32 tid = 0; tid < n_contexts_; tid++) {
+ ThreadContextBase *tctx = threads_[tid];
+ if (tctx != 0 && tctx->user_id == user_id &&
+ tctx->status != ThreadStatusInvalid) {
+ tctx->SetName(name);
+ return;
+ }
+ }
+}
+
void ThreadRegistry::DetachThread(u32 tid) {
BlockingMutexLock l(&mtx_);
CHECK_LT(tid, n_contexts_);
diff --git a/lib/sanitizer_common/sanitizer_thread_registry.h b/lib/sanitizer_common/sanitizer_thread_registry.h
index 6072e7c0a002..a59bba570e88 100644
--- a/lib/sanitizer_common/sanitizer_thread_registry.h
+++ b/lib/sanitizer_common/sanitizer_thread_registry.h
@@ -109,6 +109,7 @@ class ThreadRegistry {
ThreadContextBase *FindThreadContextByOsIDLocked(uptr os_id);
void SetThreadName(u32 tid, const char *name);
+ void SetThreadNameByUserId(uptr user_id, const char *name);
void DetachThread(u32 tid);
void JoinThread(u32 tid, void *arg);
void FinishThread(u32 tid);
diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc
index e76f1d1f7fa6..362c8c99a74c 100644
--- a/lib/sanitizer_common/sanitizer_win.cc
+++ b/lib/sanitizer_common/sanitizer_win.cc
@@ -40,6 +40,12 @@ uptr GetMmapGranularity() {
return 1U << 16; // FIXME: is this configurable?
}
+uptr GetMaxVirtualAddress() {
+ SYSTEM_INFO si;
+ GetSystemInfo(&si);
+ return (uptr)si.lpMaximumApplicationAddress;
+}
+
bool FileExists(const char *filename) {
UNIMPLEMENTED();
}
@@ -124,7 +130,7 @@ void *MapFileToMemory(const char *file_name, uptr *buff_size) {
}
static const int kMaxEnvNameLength = 128;
-static const int kMaxEnvValueLength = 32767;
+static const DWORD kMaxEnvValueLength = 32767;
namespace {
@@ -190,6 +196,11 @@ void SetStackSizeLimitInBytes(uptr limit) {
UNIMPLEMENTED();
}
+char *FindPathToBinary(const char *name) {
+ // Nothing here for now.
+ return 0;
+}
+
void SleepForSeconds(int seconds) {
Sleep(seconds * 1000);
}
@@ -198,11 +209,20 @@ void SleepForMillis(int millis) {
Sleep(millis);
}
+u64 NanoTime() {
+ return 0;
+}
+
void Abort() {
abort();
_exit(-1); // abort is not NORETURN on Windows.
}
+uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
+ string_predicate_t filter) {
+ UNIMPLEMENTED();
+};
+
#ifndef SANITIZER_GO
int Atexit(void (*function)(void)) {
return atexit(function);
@@ -341,39 +361,48 @@ void InitTlsSize() {
void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
uptr *tls_addr, uptr *tls_size) {
+#ifdef SANITIZER_GO
+ *stk_addr = 0;
+ *stk_size = 0;
+ *tls_addr = 0;
+ *tls_size = 0;
+#else
uptr stack_top, stack_bottom;
GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom);
*stk_addr = stack_bottom;
*stk_size = stack_top - stack_bottom;
*tls_addr = 0;
*tls_size = 0;
+#endif
}
-void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp,
- uptr stack_top, uptr stack_bottom, bool fast) {
- (void)fast;
- (void)stack_top;
- (void)stack_bottom;
- stack->max_size = max_s;
- void *tmp[kStackTraceMax];
-
+void StackTrace::SlowUnwindStack(uptr pc, uptr max_depth) {
// FIXME: CaptureStackBackTrace might be too slow for us.
// FIXME: Compare with StackWalk64.
// FIXME: Look at LLVMUnhandledExceptionFilter in Signals.inc
- uptr cs_ret = CaptureStackBackTrace(1, stack->max_size, tmp, 0);
- uptr offset = 0;
+ size = CaptureStackBackTrace(2, Min(max_depth, kStackTraceMax),
+ (void**)trace, 0);
// Skip the RTL frames by searching for the PC in the stacktrace.
- // FIXME: this doesn't work well for the malloc/free stacks yet.
- for (uptr i = 0; i < cs_ret; i++) {
- if (pc != (uptr)tmp[i])
- continue;
- offset = i;
- break;
- }
+ uptr pc_location = LocatePcInTrace(pc);
+ PopStackFrames(pc_location);
+}
- stack->size = cs_ret - offset;
- for (uptr i = 0; i < stack->size; i++)
- stack->trace[i] = (uptr)tmp[i + offset];
+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 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)) {
+ // 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.
+ OutputDebugStringA(buffer);
+ }
}
} // namespace __sanitizer
diff --git a/lib/sanitizer_common/scripts/check_lint.sh b/lib/sanitizer_common/scripts/check_lint.sh
index 3240f6f18cee..5f1bd4ba4316 100755
--- a/lib/sanitizer_common/scripts/check_lint.sh
+++ b/lib/sanitizer_common/scripts/check_lint.sh
@@ -1,26 +1,21 @@
#!/bin/bash
-set -e
-
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
# Guess path to LLVM_CHECKOUT if not provided
if [ "${LLVM_CHECKOUT}" == "" ]; then
LLVM_CHECKOUT="${SCRIPT_DIR}/../../../../../"
- echo "LLVM Checkout: ${LLVM_CHECKOUT}"
fi
# Cpplint setup
-cd ${SCRIPT_DIR}
-if [ ! -d cpplint ]; then
- svn co http://google-styleguide.googlecode.com/svn/trunk/cpplint cpplint
-else
- (cd cpplint && svn up)
+CPPLINT=${SCRIPT_DIR}/cpplint.py
+if [ "${PYTHON_EXECUTABLE}" != "" ]; then
+ CPPLINT="${PYTHON_EXECUTABLE} ${CPPLINT}"
fi
-CPPLINT=${SCRIPT_DIR}/cpplint/cpplint.py
# Filters
# TODO: remove some of these filters
+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
@@ -34,62 +29,86 @@ 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
SANITIZER_INCLUDES_LINT_FILTER=${COMMON_LINT_FILTER},-runtime/int
-
+MKTEMP="mktemp -q /tmp/tmp.XXXXXXXXXX"
cd ${LLVM_CHECKOUT}
-# LLVM Instrumentation
-LLVM_INSTRUMENTATION=lib/Transforms/Instrumentation
-LLVM_LINT_FILTER=-,+whitespace
-${CPPLINT} --filter=${LLVM_LINT_FILTER} ${LLVM_INSTRUMENTATION}/*Sanitizer.cpp \
- ${LLVM_INSTRUMENTATION}/BlackList.*
+EXITSTATUS=0
+ERROR_LOG=$(${MKTEMP})
+
+run_lint() {
+ FILTER=$1
+ shift
+ TASK_LOG=$(${MKTEMP})
+ ${CPPLINT} --filter=${FILTER} "$@" 2>$TASK_LOG
+ if [ "$?" != "0" ]; then
+ cat $TASK_LOG | grep -v "Done processing" | grep -v "Total errors found" \
+ | grep -v "Skipping input" >> $ERROR_LOG
+ fi
+ if [[ "${SILENT}" != "1" ]]; then
+ cat $TASK_LOG
+ fi
+}
+
+run_lint ${LLVM_LINT_FILTER} --filter=${LLVM_LINT_FILTER} \
+ lib/Transforms/Instrumentation/*Sanitizer.cpp \
+ lib/Transforms/Utils/SpecialCaseList.cpp &
COMPILER_RT=projects/compiler-rt
-
# Headers
SANITIZER_INCLUDES=${COMPILER_RT}/include/sanitizer
-${CPPLINT} --filter=${SANITIZER_INCLUDES_LINT_FILTER} ${SANITIZER_INCLUDES}/*.h
+run_lint ${SANITIZER_INCLUDES_LINT_FILTER} ${SANITIZER_INCLUDES}/*.h &
# Sanitizer_common
COMMON_RTL=${COMPILER_RT}/lib/sanitizer_common
-${CPPLINT} --filter=${COMMON_RTL_INC_LINT_FILTER} ${COMMON_RTL}/*.{cc,h}
-${CPPLINT} --filter=${COMMON_RTL_INC_LINT_FILTER} ${COMMON_RTL}/tests/*.cc
+run_lint ${COMMON_RTL_INC_LINT_FILTER} ${COMMON_RTL}/*.{cc,h} \
+ ${COMMON_RTL}/tests/*.cc &
# Interception
INTERCEPTION=${COMPILER_RT}/lib/interception
-${CPPLINT} --filter=${ASAN_RTL_LINT_FILTER} ${INTERCEPTION}/*.{cc,h}
+run_lint ${ASAN_RTL_LINT_FILTER} ${INTERCEPTION}/*.{cc,h} &
# ASan
ASAN_RTL=${COMPILER_RT}/lib/asan
-${CPPLINT} --filter=${ASAN_RTL_LINT_FILTER} ${ASAN_RTL}/*.{cc,h}
-${CPPLINT} --filter=${ASAN_TEST_LINT_FILTER} ${ASAN_RTL}/tests/*.{cc,h}
-${CPPLINT} --filter=${ASAN_LIT_TEST_LINT_FILTER} ${ASAN_RTL}/lit_tests/*.cc \
- ${ASAN_RTL}/lit_tests/*/*.cc \
+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 &
# TSan
TSAN_RTL=${COMPILER_RT}/lib/tsan
-${CPPLINT} --filter=${TSAN_RTL_LINT_FILTER} ${TSAN_RTL}/rtl/*.{cc,h}
-${CPPLINT} --filter=${TSAN_TEST_LINT_FILTER} ${TSAN_RTL}/tests/rtl/*.{cc,h} \
- ${TSAN_RTL}/tests/unit/*.cc
-${CPPLINT} --filter=${TSAN_LIT_TEST_LINT_FILTER} ${TSAN_RTL}/lit_tests/*.cc
+run_lint ${TSAN_RTL_LINT_FILTER} ${TSAN_RTL}/rtl/*.{cc,h} &
+run_lint ${TSAN_TEST_LINT_FILTER} ${TSAN_RTL}/tests/rtl/*.{cc,h} \
+ ${TSAN_RTL}/tests/unit/*.cc &
+run_lint ${TSAN_LIT_TEST_LINT_FILTER} ${TSAN_RTL}/lit_tests/*.cc &
# MSan
MSAN_RTL=${COMPILER_RT}/lib/msan
-${CPPLINT} --filter=${MSAN_RTL_LINT_FILTER} ${MSAN_RTL}/*.{cc,h}
+run_lint ${MSAN_RTL_LINT_FILTER} ${MSAN_RTL}/*.{cc,h} &
# LSan
LSAN_RTL=${COMPILER_RT}/lib/lsan
-${CPPLINT} --filter=${LSAN_RTL_LINT_FILTER} ${LSAN_RTL}/*.{cc,h}
-${CPPLINT} --filter=${LSAN_RTL_LINT_FILTER} ${LSAN_RTL}/tests/*.{cc,h}
-${CPPLINT} --filter=${LSAN_LIT_TEST_LINT_FILTER} ${LSAN_RTL}/lit_tests/*.{cc,h}
-
-set +e
+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 &
# Misc files
FILES=${COMMON_RTL}/*.inc
+TMPFILES=""
for FILE in $FILES; do
- TMPFILE=$(mktemp -u ${FILE}.XXXXX).cc
- echo "Checking $FILE"
- cp -f $FILE $TMPFILE && \
- ${CPPLINT} --filter=${COMMON_RTL_INC_LINT_FILTER} $TMPFILE
- rm $TMPFILE
+ TMPFILE="$(${MKTEMP}).$(basename ${FILE}).cc"
+ cp -f $FILE $TMPFILE
+ run_lint ${COMMON_RTL_INC_LINT_FILTER} $TMPFILE &
+ TMPFILES="$TMPFILES $TMPFILE"
done
+
+wait
+
+for temp in $TMPFILES; do
+ rm -f $temp
+done
+
+if [[ -s $ERROR_LOG ]]; then
+ cat $ERROR_LOG
+ exit 1
+fi
+
+exit 0
diff --git a/lib/sanitizer_common/scripts/cpplint.py b/lib/sanitizer_common/scripts/cpplint.py
new file mode 100755
index 000000000000..a8c9f6784f2d
--- /dev/null
+++ b/lib/sanitizer_common/scripts/cpplint.py
@@ -0,0 +1,4024 @@
+#!/usr/bin/python
+#
+# Copyright (c) 2009 Google Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Here are some issues that I've had people identify in my code during reviews,
+# that I think are possible to flag automatically in a lint tool. If these were
+# caught by lint, it would save time both for myself and that of my reviewers.
+# Most likely, some of these are beyond the scope of the current lint framework,
+# but I think it is valuable to retain these wish-list items even if they cannot
+# be immediately implemented.
+#
+# Suggestions
+# -----------
+# - Check for no 'explicit' for multi-arg ctor
+# - Check for boolean assign RHS in parens
+# - Check for ctor initializer-list colon position and spacing
+# - Check that if there's a ctor, there should be a dtor
+# - Check accessors that return non-pointer member variables are
+# declared const
+# - Check accessors that return non-const pointer member vars are
+# *not* declared const
+# - Check for using public includes for testing
+# - Check for spaces between brackets in one-line inline method
+# - Check for no assert()
+# - Check for spaces surrounding operators
+# - Check for 0 in pointer context (should be NULL)
+# - Check for 0 in char context (should be '\0')
+# - Check for camel-case method name conventions for methods
+# that are not simple inline getters and setters
+# - Do not indent namespace contents
+# - Avoid inlining non-trivial constructors in header files
+# - Check for old-school (void) cast for call-sites of functions
+# ignored return value
+# - Check gUnit usage of anonymous namespace
+# - Check for class declaration order (typedefs, consts, enums,
+# ctor(s?), dtor, friend declarations, methods, member vars)
+#
+
+"""Does google-lint on c++ files.
+
+The goal of this script is to identify places in the code that *may*
+be in non-compliance with google style. It does not attempt to fix
+up these problems -- the point is to educate. It does also not
+attempt to find all problems, or to ensure that everything it does
+find is legitimately a problem.
+
+In particular, we can get very confused by /* and // inside strings!
+We do a small hack, which is to ignore //'s with "'s after them on the
+same line, but it is far from perfect (in either direction).
+"""
+
+import codecs
+import copy
+import getopt
+import math # for log
+import os
+import re
+import sre_compile
+import string
+import sys
+import unicodedata
+
+
+_USAGE = """
+Syntax: cpplint.py [--verbose=#] [--output=vs7] [--filter=-x,+y,...]
+ [--counting=total|toplevel|detailed]
+ <file> [file] ...
+
+ The style guidelines this tries to follow are those in
+ http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml
+
+ Every problem is given a confidence score from 1-5, with 5 meaning we are
+ certain of the problem, and 1 meaning it could be a legitimate construct.
+ This will miss some errors, and is not a substitute for a code review.
+
+ To suppress false-positive errors of a certain category, add a
+ 'NOLINT(category)' comment to the line. NOLINT or NOLINT(*)
+ suppresses errors of all categories on that line.
+
+ The files passed in will be linted; at least one file must be provided.
+ Linted extensions are .cc, .cpp, and .h. Other file types will be ignored.
+
+ Flags:
+
+ output=vs7
+ By default, the output is formatted to ease emacs parsing. Visual Studio
+ compatible output (vs7) may also be used. Other formats are unsupported.
+
+ verbose=#
+ Specify a number 0-5 to restrict errors to certain verbosity levels.
+
+ filter=-x,+y,...
+ Specify a comma-separated list of category-filters to apply: only
+ error messages whose category names pass the filters will be printed.
+ (Category names are printed with the message and look like
+ "[whitespace/indent]".) Filters are evaluated left to right.
+ "-FOO" and "FOO" means "do not print categories that start with FOO".
+ "+FOO" means "do print categories that start with FOO".
+
+ Examples: --filter=-whitespace,+whitespace/braces
+ --filter=whitespace,runtime/printf,+runtime/printf_format
+ --filter=-,+build/include_what_you_use
+
+ To see a list of all the categories used in cpplint, pass no arg:
+ --filter=
+
+ counting=total|toplevel|detailed
+ The total number of errors found is always printed. If
+ 'toplevel' is provided, then the count of errors in each of
+ the top-level categories like 'build' and 'whitespace' will
+ also be printed. If 'detailed' is provided, then a count
+ is provided for each category like 'build/class'.
+
+ root=subdir
+ The root directory used for deriving header guard CPP variable.
+ By default, the header guard CPP variable is calculated as the relative
+ path to the directory that contains .git, .hg, or .svn. When this flag
+ is specified, the relative path is calculated from the specified
+ directory. If the specified directory does not exist, this flag is
+ ignored.
+
+ Examples:
+ Assuing that src/.git exists, the header guard CPP variables for
+ src/chrome/browser/ui/browser.h are:
+
+ No flag => CHROME_BROWSER_UI_BROWSER_H_
+ --root=chrome => BROWSER_UI_BROWSER_H_
+ --root=chrome/browser => UI_BROWSER_H_
+"""
+
+# We categorize each error message we print. Here are the categories.
+# We want an explicit list so we can list them all in cpplint --filter=.
+# If you add a new error message with a new category, add it to the list
+# here! cpplint_unittest.py should tell you if you forget to do this.
+# \ used for clearer layout -- pylint: disable-msg=C6013
+_ERROR_CATEGORIES = [
+ 'build/class',
+ 'build/deprecated',
+ 'build/endif_comment',
+ 'build/explicit_make_pair',
+ 'build/forward_decl',
+ 'build/header_guard',
+ 'build/include',
+ 'build/include_alpha',
+ 'build/include_order',
+ 'build/include_what_you_use',
+ 'build/namespaces',
+ 'build/printf_format',
+ 'build/storage_class',
+ 'legal/copyright',
+ 'readability/alt_tokens',
+ 'readability/braces',
+ 'readability/casting',
+ 'readability/check',
+ 'readability/constructors',
+ 'readability/fn_size',
+ 'readability/function',
+ 'readability/multiline_comment',
+ 'readability/multiline_string',
+ 'readability/namespace',
+ 'readability/nolint',
+ 'readability/streams',
+ 'readability/todo',
+ 'readability/utf8',
+ 'runtime/arrays',
+ 'runtime/casting',
+ 'runtime/explicit',
+ 'runtime/int',
+ 'runtime/init',
+ 'runtime/invalid_increment',
+ 'runtime/member_string_references',
+ 'runtime/memset',
+ 'runtime/operator',
+ 'runtime/printf',
+ 'runtime/printf_format',
+ 'runtime/references',
+ 'runtime/rtti',
+ 'runtime/sizeof',
+ 'runtime/string',
+ 'runtime/threadsafe_fn',
+ 'whitespace/blank_line',
+ 'whitespace/braces',
+ 'whitespace/comma',
+ 'whitespace/comments',
+ 'whitespace/empty_loop_body',
+ 'whitespace/end_of_line',
+ 'whitespace/ending_newline',
+ 'whitespace/forcolon',
+ 'whitespace/indent',
+ 'whitespace/labels',
+ 'whitespace/line_length',
+ 'whitespace/newline',
+ 'whitespace/operators',
+ 'whitespace/parens',
+ 'whitespace/semicolon',
+ 'whitespace/tab',
+ 'whitespace/todo'
+ ]
+
+# The default state of the category filter. This is overrided by the --filter=
+# flag. By default all errors are on, so only add here categories that should be
+# off by default (i.e., categories that must be enabled by the --filter= flags).
+# All entries here should start with a '-' or '+', as in the --filter= flag.
+_DEFAULT_FILTERS = ['-build/include_alpha']
+
+# We used to check for high-bit characters, but after much discussion we
+# decided those were OK, as long as they were in UTF-8 and didn't represent
+# hard-coded international strings, which belong in a separate i18n file.
+
+# Headers that we consider STL headers.
+_STL_HEADERS = frozenset([
+ 'algobase.h', 'algorithm', 'alloc.h', 'bitset', 'deque', 'exception',
+ 'function.h', 'functional', 'hash_map', 'hash_map.h', 'hash_set',
+ 'hash_set.h', 'iterator', 'list', 'list.h', 'map', 'memory', 'new',
+ 'pair.h', 'pthread_alloc', 'queue', 'set', 'set.h', 'sstream', 'stack',
+ 'stl_alloc.h', 'stl_relops.h', 'type_traits.h',
+ 'utility', 'vector', 'vector.h',
+ ])
+
+
+# Non-STL C++ system headers.
+_CPP_HEADERS = frozenset([
+ 'algo.h', 'builtinbuf.h', 'bvector.h', 'cassert', 'cctype',
+ 'cerrno', 'cfloat', 'ciso646', 'climits', 'clocale', 'cmath',
+ 'complex', 'complex.h', 'csetjmp', 'csignal', 'cstdarg', 'cstddef',
+ 'cstdio', 'cstdlib', 'cstring', 'ctime', 'cwchar', 'cwctype',
+ 'defalloc.h', 'deque.h', 'editbuf.h', 'exception', 'fstream',
+ 'fstream.h', 'hashtable.h', 'heap.h', 'indstream.h', 'iomanip',
+ 'iomanip.h', 'ios', 'iosfwd', 'iostream', 'iostream.h', 'istream',
+ 'istream.h', 'iterator.h', 'limits', 'map.h', 'multimap.h', 'multiset.h',
+ 'numeric', 'ostream', 'ostream.h', 'parsestream.h', 'pfstream.h',
+ 'PlotFile.h', 'procbuf.h', 'pthread_alloc.h', 'rope', 'rope.h',
+ 'ropeimpl.h', 'SFile.h', 'slist', 'slist.h', 'stack.h', 'stdexcept',
+ 'stdiostream.h', 'streambuf', 'streambuf.h', 'stream.h', 'strfile.h',
+ 'string', 'strstream', 'strstream.h', 'tempbuf.h', 'tree.h', 'typeinfo',
+ 'valarray',
+ ])
+
+
+# Assertion macros. These are defined in base/logging.h and
+# testing/base/gunit.h. Note that the _M versions need to come first
+# for substring matching to work.
+_CHECK_MACROS = [
+ 'DCHECK', 'CHECK',
+ 'EXPECT_TRUE_M', 'EXPECT_TRUE',
+ 'ASSERT_TRUE_M', 'ASSERT_TRUE',
+ 'EXPECT_FALSE_M', 'EXPECT_FALSE',
+ 'ASSERT_FALSE_M', 'ASSERT_FALSE',
+ ]
+
+# Replacement macros for CHECK/DCHECK/EXPECT_TRUE/EXPECT_FALSE
+_CHECK_REPLACEMENT = dict([(m, {}) for m in _CHECK_MACROS])
+
+for op, replacement in [('==', 'EQ'), ('!=', 'NE'),
+ ('>=', 'GE'), ('>', 'GT'),
+ ('<=', 'LE'), ('<', 'LT')]:
+ _CHECK_REPLACEMENT['DCHECK'][op] = 'DCHECK_%s' % replacement
+ _CHECK_REPLACEMENT['CHECK'][op] = 'CHECK_%s' % replacement
+ _CHECK_REPLACEMENT['EXPECT_TRUE'][op] = 'EXPECT_%s' % replacement
+ _CHECK_REPLACEMENT['ASSERT_TRUE'][op] = 'ASSERT_%s' % replacement
+ _CHECK_REPLACEMENT['EXPECT_TRUE_M'][op] = 'EXPECT_%s_M' % replacement
+ _CHECK_REPLACEMENT['ASSERT_TRUE_M'][op] = 'ASSERT_%s_M' % replacement
+
+for op, inv_replacement in [('==', 'NE'), ('!=', 'EQ'),
+ ('>=', 'LT'), ('>', 'LE'),
+ ('<=', 'GT'), ('<', 'GE')]:
+ _CHECK_REPLACEMENT['EXPECT_FALSE'][op] = 'EXPECT_%s' % inv_replacement
+ _CHECK_REPLACEMENT['ASSERT_FALSE'][op] = 'ASSERT_%s' % inv_replacement
+ _CHECK_REPLACEMENT['EXPECT_FALSE_M'][op] = 'EXPECT_%s_M' % inv_replacement
+ _CHECK_REPLACEMENT['ASSERT_FALSE_M'][op] = 'ASSERT_%s_M' % inv_replacement
+
+# Alternative tokens and their replacements. For full list, see section 2.5
+# Alternative tokens [lex.digraph] in the C++ standard.
+#
+# Digraphs (such as '%:') are not included here since it's a mess to
+# match those on a word boundary.
+_ALT_TOKEN_REPLACEMENT = {
+ 'and': '&&',
+ 'bitor': '|',
+ 'or': '||',
+ 'xor': '^',
+ 'compl': '~',
+ 'bitand': '&',
+ 'and_eq': '&=',
+ 'or_eq': '|=',
+ 'xor_eq': '^=',
+ 'not': '!',
+ 'not_eq': '!='
+ }
+
+# Compile regular expression that matches all the above keywords. The "[ =()]"
+# bit is meant to avoid matching these keywords outside of boolean expressions.
+#
+# False positives include C-style multi-line comments (http://go/nsiut )
+# and multi-line strings (http://go/beujw ), but those have always been
+# troublesome for cpplint.
+_ALT_TOKEN_REPLACEMENT_PATTERN = re.compile(
+ r'[ =()](' + ('|'.join(_ALT_TOKEN_REPLACEMENT.keys())) + r')(?=[ (]|$)')
+
+
+# These constants define types of headers for use with
+# _IncludeState.CheckNextIncludeOrder().
+_C_SYS_HEADER = 1
+_CPP_SYS_HEADER = 2
+_LIKELY_MY_HEADER = 3
+_POSSIBLE_MY_HEADER = 4
+_OTHER_HEADER = 5
+
+# These constants define the current inline assembly state
+_NO_ASM = 0 # Outside of inline assembly block
+_INSIDE_ASM = 1 # Inside inline assembly block
+_END_ASM = 2 # Last line of inline assembly block
+_BLOCK_ASM = 3 # The whole block is an inline assembly block
+
+# Match start of assembly blocks
+_MATCH_ASM = re.compile(r'^\s*(?:asm|_asm|__asm|__asm__)'
+ r'(?:\s+(volatile|__volatile__))?'
+ r'\s*[{(]')
+
+
+_regexp_compile_cache = {}
+
+# Finds occurrences of NOLINT or NOLINT(...).
+_RE_SUPPRESSION = re.compile(r'\bNOLINT\b(\([^)]*\))?')
+
+# {str, set(int)}: a map from error categories to sets of linenumbers
+# on which those errors are expected and should be suppressed.
+_error_suppressions = {}
+
+# The root directory used for deriving header guard CPP variable.
+# This is set by --root flag.
+_root = None
+
+def ParseNolintSuppressions(filename, raw_line, linenum, error):
+ """Updates the global list of error-suppressions.
+
+ Parses any NOLINT comments on the current line, updating the global
+ error_suppressions store. Reports an error if the NOLINT comment
+ was malformed.
+
+ Args:
+ filename: str, the name of the input file.
+ raw_line: str, the line of input text, with comments.
+ linenum: int, the number of the current line.
+ error: function, an error handler.
+ """
+ # FIXME(adonovan): "NOLINT(" is misparsed as NOLINT(*).
+ matched = _RE_SUPPRESSION.search(raw_line)
+ if matched:
+ category = matched.group(1)
+ if category in (None, '(*)'): # => "suppress all"
+ _error_suppressions.setdefault(None, set()).add(linenum)
+ else:
+ if category.startswith('(') and category.endswith(')'):
+ category = category[1:-1]
+ if category in _ERROR_CATEGORIES:
+ _error_suppressions.setdefault(category, set()).add(linenum)
+ else:
+ error(filename, linenum, 'readability/nolint', 5,
+ 'Unknown NOLINT error category: %s' % category)
+
+
+def ResetNolintSuppressions():
+ "Resets the set of NOLINT suppressions to empty."
+ _error_suppressions.clear()
+
+
+def IsErrorSuppressedByNolint(category, linenum):
+ """Returns true if the specified error category is suppressed on this line.
+
+ Consults the global error_suppressions map populated by
+ ParseNolintSuppressions/ResetNolintSuppressions.
+
+ Args:
+ category: str, the category of the error.
+ linenum: int, the current line number.
+ Returns:
+ bool, True iff the error should be suppressed due to a NOLINT comment.
+ """
+ return (linenum in _error_suppressions.get(category, set()) or
+ linenum in _error_suppressions.get(None, set()))
+
+def Match(pattern, s):
+ """Matches the string with the pattern, caching the compiled regexp."""
+ # The regexp compilation caching is inlined in both Match and Search for
+ # performance reasons; factoring it out into a separate function turns out
+ # to be noticeably expensive.
+ if not pattern in _regexp_compile_cache:
+ _regexp_compile_cache[pattern] = sre_compile.compile(pattern)
+ return _regexp_compile_cache[pattern].match(s)
+
+
+def Search(pattern, s):
+ """Searches the string for the pattern, caching the compiled regexp."""
+ if not pattern in _regexp_compile_cache:
+ _regexp_compile_cache[pattern] = sre_compile.compile(pattern)
+ return _regexp_compile_cache[pattern].search(s)
+
+
+class _IncludeState(dict):
+ """Tracks line numbers for includes, and the order in which includes appear.
+
+ As a dict, an _IncludeState object serves as a mapping between include
+ filename and line number on which that file was included.
+
+ Call CheckNextIncludeOrder() once for each header in the file, passing
+ in the type constants defined above. Calls in an illegal order will
+ raise an _IncludeError with an appropriate error message.
+
+ """
+ # self._section will move monotonically through this set. If it ever
+ # needs to move backwards, CheckNextIncludeOrder will raise an error.
+ _INITIAL_SECTION = 0
+ _MY_H_SECTION = 1
+ _C_SECTION = 2
+ _CPP_SECTION = 3
+ _OTHER_H_SECTION = 4
+
+ _TYPE_NAMES = {
+ _C_SYS_HEADER: 'C system header',
+ _CPP_SYS_HEADER: 'C++ system header',
+ _LIKELY_MY_HEADER: 'header this file implements',
+ _POSSIBLE_MY_HEADER: 'header this file may implement',
+ _OTHER_HEADER: 'other header',
+ }
+ _SECTION_NAMES = {
+ _INITIAL_SECTION: "... nothing. (This can't be an error.)",
+ _MY_H_SECTION: 'a header this file implements',
+ _C_SECTION: 'C system header',
+ _CPP_SECTION: 'C++ system header',
+ _OTHER_H_SECTION: 'other header',
+ }
+
+ def __init__(self):
+ dict.__init__(self)
+ # The name of the current section.
+ self._section = self._INITIAL_SECTION
+ # The path of last found header.
+ self._last_header = ''
+
+ def CanonicalizeAlphabeticalOrder(self, header_path):
+ """Returns a path canonicalized for alphabetical comparison.
+
+ - replaces "-" with "_" so they both cmp the same.
+ - removes '-inl' since we don't require them to be after the main header.
+ - lowercase everything, just in case.
+
+ Args:
+ header_path: Path to be canonicalized.
+
+ Returns:
+ Canonicalized path.
+ """
+ return header_path.replace('-inl.h', '.h').replace('-', '_').lower()
+
+ def IsInAlphabeticalOrder(self, header_path):
+ """Check if a header is in alphabetical order with the previous header.
+
+ Args:
+ header_path: Header to be checked.
+
+ Returns:
+ Returns true if the header is in alphabetical order.
+ """
+ canonical_header = self.CanonicalizeAlphabeticalOrder(header_path)
+ if self._last_header > canonical_header:
+ return False
+ self._last_header = canonical_header
+ return True
+
+ def CheckNextIncludeOrder(self, header_type):
+ """Returns a non-empty error message if the next header is out of order.
+
+ This function also updates the internal state to be ready to check
+ the next include.
+
+ Args:
+ header_type: One of the _XXX_HEADER constants defined above.
+
+ Returns:
+ The empty string if the header is in the right order, or an
+ error message describing what's wrong.
+
+ """
+ error_message = ('Found %s after %s' %
+ (self._TYPE_NAMES[header_type],
+ self._SECTION_NAMES[self._section]))
+
+ last_section = self._section
+
+ if header_type == _C_SYS_HEADER:
+ if self._section <= self._C_SECTION:
+ self._section = self._C_SECTION
+ else:
+ self._last_header = ''
+ return error_message
+ elif header_type == _CPP_SYS_HEADER:
+ if self._section <= self._CPP_SECTION:
+ self._section = self._CPP_SECTION
+ else:
+ self._last_header = ''
+ return error_message
+ elif header_type == _LIKELY_MY_HEADER:
+ if self._section <= self._MY_H_SECTION:
+ self._section = self._MY_H_SECTION
+ else:
+ self._section = self._OTHER_H_SECTION
+ elif header_type == _POSSIBLE_MY_HEADER:
+ if self._section <= self._MY_H_SECTION:
+ self._section = self._MY_H_SECTION
+ else:
+ # This will always be the fallback because we're not sure
+ # enough that the header is associated with this file.
+ self._section = self._OTHER_H_SECTION
+ else:
+ assert header_type == _OTHER_HEADER
+ self._section = self._OTHER_H_SECTION
+
+ if last_section != self._section:
+ self._last_header = ''
+
+ return ''
+
+
+class _CppLintState(object):
+ """Maintains module-wide state.."""
+
+ def __init__(self):
+ self.verbose_level = 1 # global setting.
+ self.error_count = 0 # global count of reported errors
+ # filters to apply when emitting error messages
+ self.filters = _DEFAULT_FILTERS[:]
+ self.counting = 'total' # In what way are we counting errors?
+ self.errors_by_category = {} # string to int dict storing error counts
+
+ # output format:
+ # "emacs" - format that emacs can parse (default)
+ # "vs7" - format that Microsoft Visual Studio 7 can parse
+ self.output_format = 'emacs'
+
+ def SetOutputFormat(self, output_format):
+ """Sets the output format for errors."""
+ self.output_format = output_format
+
+ def SetVerboseLevel(self, level):
+ """Sets the module's verbosity, and returns the previous setting."""
+ last_verbose_level = self.verbose_level
+ self.verbose_level = level
+ return last_verbose_level
+
+ def SetCountingStyle(self, counting_style):
+ """Sets the module's counting options."""
+ self.counting = counting_style
+
+ def SetFilters(self, filters):
+ """Sets the error-message filters.
+
+ These filters are applied when deciding whether to emit a given
+ error message.
+
+ Args:
+ filters: A string of comma-separated filters (eg "+whitespace/indent").
+ Each filter should start with + or -; else we die.
+
+ Raises:
+ ValueError: The comma-separated filters did not all start with '+' or '-'.
+ E.g. "-,+whitespace,-whitespace/indent,whitespace/badfilter"
+ """
+ # Default filters always have less priority than the flag ones.
+ self.filters = _DEFAULT_FILTERS[:]
+ for filt in filters.split(','):
+ clean_filt = filt.strip()
+ if clean_filt:
+ self.filters.append(clean_filt)
+ for filt in self.filters:
+ if not (filt.startswith('+') or filt.startswith('-')):
+ raise ValueError('Every filter in --filters must start with + or -'
+ ' (%s does not)' % filt)
+
+ def ResetErrorCounts(self):
+ """Sets the module's error statistic back to zero."""
+ self.error_count = 0
+ self.errors_by_category = {}
+
+ def IncrementErrorCount(self, category):
+ """Bumps the module's error statistic."""
+ self.error_count += 1
+ if self.counting in ('toplevel', 'detailed'):
+ if self.counting != 'detailed':
+ category = category.split('/')[0]
+ if category not in self.errors_by_category:
+ self.errors_by_category[category] = 0
+ self.errors_by_category[category] += 1
+
+ def PrintErrorCounts(self):
+ """Print a summary of errors by category, and the total."""
+ for category, count in self.errors_by_category.iteritems():
+ sys.stderr.write('Category \'%s\' errors found: %d\n' %
+ (category, count))
+ sys.stderr.write('Total errors found: %d\n' % self.error_count)
+
+_cpplint_state = _CppLintState()
+
+
+def _OutputFormat():
+ """Gets the module's output format."""
+ return _cpplint_state.output_format
+
+
+def _SetOutputFormat(output_format):
+ """Sets the module's output format."""
+ _cpplint_state.SetOutputFormat(output_format)
+
+
+def _VerboseLevel():
+ """Returns the module's verbosity setting."""
+ return _cpplint_state.verbose_level
+
+
+def _SetVerboseLevel(level):
+ """Sets the module's verbosity, and returns the previous setting."""
+ return _cpplint_state.SetVerboseLevel(level)
+
+
+def _SetCountingStyle(level):
+ """Sets the module's counting options."""
+ _cpplint_state.SetCountingStyle(level)
+
+
+def _Filters():
+ """Returns the module's list of output filters, as a list."""
+ return _cpplint_state.filters
+
+
+def _SetFilters(filters):
+ """Sets the module's error-message filters.
+
+ These filters are applied when deciding whether to emit a given
+ error message.
+
+ Args:
+ filters: A string of comma-separated filters (eg "whitespace/indent").
+ Each filter should start with + or -; else we die.
+ """
+ _cpplint_state.SetFilters(filters)
+
+
+class _FunctionState(object):
+ """Tracks current function name and the number of lines in its body."""
+
+ _NORMAL_TRIGGER = 250 # for --v=0, 500 for --v=1, etc.
+ _TEST_TRIGGER = 400 # about 50% more than _NORMAL_TRIGGER.
+
+ def __init__(self):
+ self.in_a_function = False
+ self.lines_in_function = 0
+ self.current_function = ''
+
+ def Begin(self, function_name):
+ """Start analyzing function body.
+
+ Args:
+ function_name: The name of the function being tracked.
+ """
+ self.in_a_function = True
+ self.lines_in_function = 0
+ self.current_function = function_name
+
+ def Count(self):
+ """Count line in current function body."""
+ if self.in_a_function:
+ self.lines_in_function += 1
+
+ def Check(self, error, filename, linenum):
+ """Report if too many lines in function body.
+
+ Args:
+ error: The function to call with any errors found.
+ filename: The name of the current file.
+ linenum: The number of the line to check.
+ """
+ if Match(r'T(EST|est)', self.current_function):
+ base_trigger = self._TEST_TRIGGER
+ else:
+ base_trigger = self._NORMAL_TRIGGER
+ trigger = base_trigger * 2**_VerboseLevel()
+
+ if self.lines_in_function > trigger:
+ error_level = int(math.log(self.lines_in_function / base_trigger, 2))
+ # 50 => 0, 100 => 1, 200 => 2, 400 => 3, 800 => 4, 1600 => 5, ...
+ if error_level > 5:
+ error_level = 5
+ error(filename, linenum, 'readability/fn_size', error_level,
+ 'Small and focused functions are preferred:'
+ ' %s has %d non-comment lines'
+ ' (error triggered by exceeding %d lines).' % (
+ self.current_function, self.lines_in_function, trigger))
+
+ def End(self):
+ """Stop analyzing function body."""
+ self.in_a_function = False
+
+
+class _IncludeError(Exception):
+ """Indicates a problem with the include order in a file."""
+ pass
+
+
+class FileInfo:
+ """Provides utility functions for filenames.
+
+ FileInfo provides easy access to the components of a file's path
+ relative to the project root.
+ """
+
+ def __init__(self, filename):
+ self._filename = filename
+
+ def FullName(self):
+ """Make Windows paths like Unix."""
+ return os.path.abspath(self._filename).replace('\\', '/')
+
+ def RepositoryName(self):
+ """FullName after removing the local path to the repository.
+
+ If we have a real absolute path name here we can try to do something smart:
+ detecting the root of the checkout and truncating /path/to/checkout from
+ the name so that we get header guards that don't include things like
+ "C:\Documents and Settings\..." or "/home/username/..." in them and thus
+ people on different computers who have checked the source out to different
+ locations won't see bogus errors.
+ """
+ fullname = self.FullName()
+
+ if os.path.exists(fullname):
+ project_dir = os.path.dirname(fullname)
+
+ if os.path.exists(os.path.join(project_dir, ".svn")):
+ # If there's a .svn file in the current directory, we recursively look
+ # up the directory tree for the top of the SVN checkout
+ root_dir = project_dir
+ one_up_dir = os.path.dirname(root_dir)
+ while os.path.exists(os.path.join(one_up_dir, ".svn")):
+ root_dir = os.path.dirname(root_dir)
+ one_up_dir = os.path.dirname(one_up_dir)
+
+ prefix = os.path.commonprefix([root_dir, project_dir])
+ return fullname[len(prefix) + 1:]
+
+ # Not SVN <= 1.6? Try to find a git, hg, or svn top level directory by
+ # searching up from the current path.
+ root_dir = os.path.dirname(fullname)
+ while (root_dir != os.path.dirname(root_dir) and
+ not os.path.exists(os.path.join(root_dir, ".git")) and
+ not os.path.exists(os.path.join(root_dir, ".hg")) and
+ not os.path.exists(os.path.join(root_dir, ".svn"))):
+ root_dir = os.path.dirname(root_dir)
+
+ if (os.path.exists(os.path.join(root_dir, ".git")) or
+ os.path.exists(os.path.join(root_dir, ".hg")) or
+ os.path.exists(os.path.join(root_dir, ".svn"))):
+ prefix = os.path.commonprefix([root_dir, project_dir])
+ return fullname[len(prefix) + 1:]
+
+ # Don't know what to do; header guard warnings may be wrong...
+ return fullname
+
+ def Split(self):
+ """Splits the file into the directory, basename, and extension.
+
+ For 'chrome/browser/browser.cc', Split() would
+ return ('chrome/browser', 'browser', '.cc')
+
+ Returns:
+ A tuple of (directory, basename, extension).
+ """
+
+ googlename = self.RepositoryName()
+ project, rest = os.path.split(googlename)
+ return (project,) + os.path.splitext(rest)
+
+ def BaseName(self):
+ """File base name - text after the final slash, before the final period."""
+ return self.Split()[1]
+
+ def Extension(self):
+ """File extension - text following the final period."""
+ return self.Split()[2]
+
+ def NoExtension(self):
+ """File has no source file extension."""
+ return '/'.join(self.Split()[0:2])
+
+ def IsSource(self):
+ """File has a source file extension."""
+ return self.Extension()[1:] in ('c', 'cc', 'cpp', 'cxx')
+
+
+def _ShouldPrintError(category, confidence, linenum):
+ """If confidence >= verbose, category passes filter and is not suppressed."""
+
+ # There are three ways we might decide not to print an error message:
+ # a "NOLINT(category)" comment appears in the source,
+ # the verbosity level isn't high enough, or the filters filter it out.
+ if IsErrorSuppressedByNolint(category, linenum):
+ return False
+ if confidence < _cpplint_state.verbose_level:
+ return False
+
+ is_filtered = False
+ for one_filter in _Filters():
+ if one_filter.startswith('-'):
+ if category.startswith(one_filter[1:]):
+ is_filtered = True
+ elif one_filter.startswith('+'):
+ if category.startswith(one_filter[1:]):
+ is_filtered = False
+ else:
+ assert False # should have been checked for in SetFilter.
+ if is_filtered:
+ return False
+
+ return True
+
+
+def Error(filename, linenum, category, confidence, message):
+ """Logs the fact we've found a lint error.
+
+ We log where the error was found, and also our confidence in the error,
+ that is, how certain we are this is a legitimate style regression, and
+ not a misidentification or a use that's sometimes justified.
+
+ False positives can be suppressed by the use of
+ "cpplint(category)" comments on the offending line. These are
+ parsed into _error_suppressions.
+
+ Args:
+ filename: The name of the file containing the error.
+ linenum: The number of the line containing the error.
+ category: A string used to describe the "category" this bug
+ falls under: "whitespace", say, or "runtime". Categories
+ may have a hierarchy separated by slashes: "whitespace/indent".
+ confidence: A number from 1-5 representing a confidence score for
+ the error, with 5 meaning that we are certain of the problem,
+ and 1 meaning that it could be a legitimate construct.
+ message: The error message.
+ """
+ if _ShouldPrintError(category, confidence, linenum):
+ _cpplint_state.IncrementErrorCount(category)
+ if _cpplint_state.output_format == 'vs7':
+ sys.stderr.write('%s(%s): %s [%s] [%d]\n' % (
+ filename, linenum, message, category, confidence))
+ elif _cpplint_state.output_format == 'eclipse':
+ sys.stderr.write('%s:%s: warning: %s [%s] [%d]\n' % (
+ filename, linenum, message, category, confidence))
+ else:
+ sys.stderr.write('%s:%s: %s [%s] [%d]\n' % (
+ filename, linenum, message, category, confidence))
+
+
+# Matches standard C++ escape esequences per 2.13.2.3 of the C++ standard.
+_RE_PATTERN_CLEANSE_LINE_ESCAPES = re.compile(
+ r'\\([abfnrtv?"\\\']|\d+|x[0-9a-fA-F]+)')
+# Matches strings. Escape codes should already be removed by ESCAPES.
+_RE_PATTERN_CLEANSE_LINE_DOUBLE_QUOTES = re.compile(r'"[^"]*"')
+# Matches characters. Escape codes should already be removed by ESCAPES.
+_RE_PATTERN_CLEANSE_LINE_SINGLE_QUOTES = re.compile(r"'.'")
+# Matches multi-line C++ comments.
+# This RE is a little bit more complicated than one might expect, because we
+# have to take care of space removals tools so we can handle comments inside
+# statements better.
+# The current rule is: We only clear spaces from both sides when we're at the
+# end of the line. Otherwise, we try to remove spaces from the right side,
+# if this doesn't work we try on left side but only if there's a non-character
+# on the right.
+_RE_PATTERN_CLEANSE_LINE_C_COMMENTS = re.compile(
+ r"""(\s*/\*.*\*/\s*$|
+ /\*.*\*/\s+|
+ \s+/\*.*\*/(?=\W)|
+ /\*.*\*/)""", re.VERBOSE)
+
+
+def IsCppString(line):
+ """Does line terminate so, that the next symbol is in string constant.
+
+ This function does not consider single-line nor multi-line comments.
+
+ Args:
+ line: is a partial line of code starting from the 0..n.
+
+ Returns:
+ True, if next character appended to 'line' is inside a
+ string constant.
+ """
+
+ line = line.replace(r'\\', 'XX') # after this, \\" does not match to \"
+ return ((line.count('"') - line.count(r'\"') - line.count("'\"'")) & 1) == 1
+
+
+def FindNextMultiLineCommentStart(lines, lineix):
+ """Find the beginning marker for a multiline comment."""
+ while lineix < len(lines):
+ if lines[lineix].strip().startswith('/*'):
+ # Only return this marker if the comment goes beyond this line
+ if lines[lineix].strip().find('*/', 2) < 0:
+ return lineix
+ lineix += 1
+ return len(lines)
+
+
+def FindNextMultiLineCommentEnd(lines, lineix):
+ """We are inside a comment, find the end marker."""
+ while lineix < len(lines):
+ if lines[lineix].strip().endswith('*/'):
+ return lineix
+ lineix += 1
+ return len(lines)
+
+
+def RemoveMultiLineCommentsFromRange(lines, begin, end):
+ """Clears a range of lines for multi-line comments."""
+ # Having // dummy comments makes the lines non-empty, so we will not get
+ # unnecessary blank line warnings later in the code.
+ for i in range(begin, end):
+ lines[i] = '// dummy'
+
+
+def RemoveMultiLineComments(filename, lines, error):
+ """Removes multiline (c-style) comments from lines."""
+ lineix = 0
+ while lineix < len(lines):
+ lineix_begin = FindNextMultiLineCommentStart(lines, lineix)
+ if lineix_begin >= len(lines):
+ return
+ lineix_end = FindNextMultiLineCommentEnd(lines, lineix_begin)
+ if lineix_end >= len(lines):
+ error(filename, lineix_begin + 1, 'readability/multiline_comment', 5,
+ 'Could not find end of multi-line comment')
+ return
+ RemoveMultiLineCommentsFromRange(lines, lineix_begin, lineix_end + 1)
+ lineix = lineix_end + 1
+
+
+def CleanseComments(line):
+ """Removes //-comments and single-line C-style /* */ comments.
+
+ Args:
+ line: A line of C++ source.
+
+ Returns:
+ The line with single-line comments removed.
+ """
+ commentpos = line.find('//')
+ if commentpos != -1 and not IsCppString(line[:commentpos]):
+ line = line[:commentpos].rstrip()
+ # get rid of /* ... */
+ return _RE_PATTERN_CLEANSE_LINE_C_COMMENTS.sub('', line)
+
+
+class CleansedLines(object):
+ """Holds 3 copies of all lines with different preprocessing applied to them.
+
+ 1) elided member contains lines without strings and comments,
+ 2) lines member contains lines without comments, and
+ 3) raw_lines member contains all the lines without processing.
+ All these three members are of <type 'list'>, and of the same length.
+ """
+
+ def __init__(self, lines):
+ self.elided = []
+ self.lines = []
+ self.raw_lines = lines
+ self.num_lines = len(lines)
+ for linenum in range(len(lines)):
+ self.lines.append(CleanseComments(lines[linenum]))
+ elided = self._CollapseStrings(lines[linenum])
+ self.elided.append(CleanseComments(elided))
+
+ def NumLines(self):
+ """Returns the number of lines represented."""
+ return self.num_lines
+
+ @staticmethod
+ def _CollapseStrings(elided):
+ """Collapses strings and chars on a line to simple "" or '' blocks.
+
+ We nix strings first so we're not fooled by text like '"http://"'
+
+ Args:
+ elided: The line being processed.
+
+ Returns:
+ The line with collapsed strings.
+ """
+ if not _RE_PATTERN_INCLUDE.match(elided):
+ # Remove escaped characters first to make quote/single quote collapsing
+ # basic. Things that look like escaped characters shouldn't occur
+ # outside of strings and chars.
+ elided = _RE_PATTERN_CLEANSE_LINE_ESCAPES.sub('', elided)
+ elided = _RE_PATTERN_CLEANSE_LINE_SINGLE_QUOTES.sub("''", elided)
+ elided = _RE_PATTERN_CLEANSE_LINE_DOUBLE_QUOTES.sub('""', elided)
+ return elided
+
+
+def FindEndOfExpressionInLine(line, startpos, depth, startchar, endchar):
+ """Find the position just after the matching endchar.
+
+ Args:
+ line: a CleansedLines line.
+ startpos: start searching at this position.
+ depth: nesting level at startpos.
+ startchar: expression opening character.
+ endchar: expression closing character.
+
+ Returns:
+ Index just after endchar.
+ """
+ for i in xrange(startpos, len(line)):
+ if line[i] == startchar:
+ depth += 1
+ elif line[i] == endchar:
+ depth -= 1
+ if depth == 0:
+ return i + 1
+ return -1
+
+
+def CloseExpression(clean_lines, linenum, pos):
+ """If input points to ( or { or [, finds the position that closes it.
+
+ If lines[linenum][pos] points to a '(' or '{' or '[', finds the
+ linenum/pos that correspond to the closing of the expression.
+
+ Args:
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ pos: A position on the line.
+
+ Returns:
+ A tuple (line, linenum, pos) pointer *past* the closing brace, or
+ (line, len(lines), -1) if we never find a close. Note we ignore
+ strings and comments when matching; and the line we return is the
+ 'cleansed' line at linenum.
+ """
+
+ line = clean_lines.elided[linenum]
+ startchar = line[pos]
+ if startchar not in '({[':
+ return (line, clean_lines.NumLines(), -1)
+ if startchar == '(': endchar = ')'
+ if startchar == '[': endchar = ']'
+ if startchar == '{': endchar = '}'
+
+ # Check first line
+ end_pos = FindEndOfExpressionInLine(line, pos, 0, startchar, endchar)
+ if end_pos > -1:
+ return (line, linenum, end_pos)
+ tail = line[pos:]
+ num_open = tail.count(startchar) - tail.count(endchar)
+ while linenum < clean_lines.NumLines() - 1:
+ linenum += 1
+ line = clean_lines.elided[linenum]
+ delta = line.count(startchar) - line.count(endchar)
+ if num_open + delta <= 0:
+ return (line, linenum,
+ FindEndOfExpressionInLine(line, 0, num_open, startchar, endchar))
+ num_open += delta
+
+ # Did not find endchar before end of file, give up
+ return (line, clean_lines.NumLines(), -1)
+
+def CheckForCopyright(filename, lines, error):
+ """Logs an error if no Copyright message appears at the top of the file."""
+
+ # We'll say it should occur by line 10. Don't forget there's a
+ # dummy line at the front.
+ for line in xrange(1, min(len(lines), 11)):
+ if re.search(r'Copyright', lines[line], re.I): break
+ else: # means no copyright line was found
+ error(filename, 0, 'legal/copyright', 5,
+ 'No copyright message found. '
+ 'You should have a line: "Copyright [year] <Copyright Owner>"')
+
+
+def GetHeaderGuardCPPVariable(filename):
+ """Returns the CPP variable that should be used as a header guard.
+
+ Args:
+ filename: The name of a C++ header file.
+
+ Returns:
+ The CPP variable that should be used as a header guard in the
+ named file.
+
+ """
+
+ # Restores original filename in case that cpplint is invoked from Emacs's
+ # flymake.
+ filename = re.sub(r'_flymake\.h$', '.h', filename)
+ filename = re.sub(r'/\.flymake/([^/]*)$', r'/\1', filename)
+
+ fileinfo = FileInfo(filename)
+ file_path_from_root = fileinfo.RepositoryName()
+ if _root:
+ file_path_from_root = re.sub('^' + _root + os.sep, '', file_path_from_root)
+ return re.sub(r'[-./\s]', '_', file_path_from_root).upper() + '_'
+
+
+def CheckForHeaderGuard(filename, lines, error):
+ """Checks that the file contains a header guard.
+
+ Logs an error if no #ifndef header guard is present. For other
+ headers, checks that the full pathname is used.
+
+ Args:
+ filename: The name of the C++ header file.
+ lines: An array of strings, each representing a line of the file.
+ error: The function to call with any errors found.
+ """
+
+ cppvar = GetHeaderGuardCPPVariable(filename)
+
+ ifndef = None
+ ifndef_linenum = 0
+ define = None
+ endif = None
+ endif_linenum = 0
+ for linenum, line in enumerate(lines):
+ linesplit = line.split()
+ if len(linesplit) >= 2:
+ # find the first occurrence of #ifndef and #define, save arg
+ if not ifndef and linesplit[0] == '#ifndef':
+ # set ifndef to the header guard presented on the #ifndef line.
+ ifndef = linesplit[1]
+ ifndef_linenum = linenum
+ if not define and linesplit[0] == '#define':
+ define = linesplit[1]
+ # find the last occurrence of #endif, save entire line
+ if line.startswith('#endif'):
+ endif = line
+ endif_linenum = linenum
+
+ if not ifndef:
+ error(filename, 0, 'build/header_guard', 5,
+ 'No #ifndef header guard found, suggested CPP variable is: %s' %
+ cppvar)
+ return
+
+ if not define:
+ error(filename, 0, 'build/header_guard', 5,
+ 'No #define header guard found, suggested CPP variable is: %s' %
+ cppvar)
+ return
+
+ # The guard should be PATH_FILE_H_, but we also allow PATH_FILE_H__
+ # for backward compatibility.
+ if ifndef != cppvar:
+ error_level = 0
+ if ifndef != cppvar + '_':
+ error_level = 5
+
+ ParseNolintSuppressions(filename, lines[ifndef_linenum], ifndef_linenum,
+ error)
+ error(filename, ifndef_linenum, 'build/header_guard', error_level,
+ '#ifndef header guard has wrong style, please use: %s' % cppvar)
+
+ if define != ifndef:
+ error(filename, 0, 'build/header_guard', 5,
+ '#ifndef and #define don\'t match, suggested CPP variable is: %s' %
+ cppvar)
+ return
+
+ if endif != ('#endif // %s' % cppvar):
+ error_level = 0
+ if endif != ('#endif // %s' % (cppvar + '_')):
+ error_level = 5
+
+ ParseNolintSuppressions(filename, lines[endif_linenum], endif_linenum,
+ error)
+ error(filename, endif_linenum, 'build/header_guard', error_level,
+ '#endif line should be "#endif // %s"' % cppvar)
+
+
+def CheckForUnicodeReplacementCharacters(filename, lines, error):
+ """Logs an error for each line containing Unicode replacement characters.
+
+ These indicate that either the file contained invalid UTF-8 (likely)
+ or Unicode replacement characters (which it shouldn't). Note that
+ it's possible for this to throw off line numbering if the invalid
+ UTF-8 occurred adjacent to a newline.
+
+ Args:
+ filename: The name of the current file.
+ lines: An array of strings, each representing a line of the file.
+ error: The function to call with any errors found.
+ """
+ for linenum, line in enumerate(lines):
+ if u'\ufffd' in line:
+ error(filename, linenum, 'readability/utf8', 5,
+ 'Line contains invalid UTF-8 (or Unicode replacement character).')
+
+
+def CheckForNewlineAtEOF(filename, lines, error):
+ """Logs an error if there is no newline char at the end of the file.
+
+ Args:
+ filename: The name of the current file.
+ lines: An array of strings, each representing a line of the file.
+ error: The function to call with any errors found.
+ """
+
+ # The array lines() was created by adding two newlines to the
+ # original file (go figure), then splitting on \n.
+ # To verify that the file ends in \n, we just have to make sure the
+ # last-but-two element of lines() exists and is empty.
+ if len(lines) < 3 or lines[-2]:
+ error(filename, len(lines) - 2, 'whitespace/ending_newline', 5,
+ 'Could not find a newline character at the end of the file.')
+
+
+def CheckForMultilineCommentsAndStrings(filename, clean_lines, linenum, error):
+ """Logs an error if we see /* ... */ or "..." that extend past one line.
+
+ /* ... */ comments are legit inside macros, for one line.
+ Otherwise, we prefer // comments, so it's ok to warn about the
+ other. Likewise, it's ok for strings to extend across multiple
+ lines, as long as a line continuation character (backslash)
+ terminates each line. Although not currently prohibited by the C++
+ style guide, it's ugly and unnecessary. We don't do well with either
+ in this lint program, so we warn about both.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ error: The function to call with any errors found.
+ """
+ line = clean_lines.elided[linenum]
+
+ # Remove all \\ (escaped backslashes) from the line. They are OK, and the
+ # second (escaped) slash may trigger later \" detection erroneously.
+ line = line.replace('\\\\', '')
+
+ if line.count('/*') > line.count('*/'):
+ error(filename, linenum, 'readability/multiline_comment', 5,
+ 'Complex multi-line /*...*/-style comment found. '
+ 'Lint may give bogus warnings. '
+ 'Consider replacing these with //-style comments, '
+ 'with #if 0...#endif, '
+ 'or with more clearly structured multi-line comments.')
+
+ if (line.count('"') - line.count('\\"')) % 2:
+ error(filename, linenum, 'readability/multiline_string', 5,
+ 'Multi-line string ("...") found. This lint script doesn\'t '
+ 'do well with such strings, and may give bogus warnings. They\'re '
+ 'ugly and unnecessary, and you should use concatenation instead".')
+
+
+threading_list = (
+ ('asctime(', 'asctime_r('),
+ ('ctime(', 'ctime_r('),
+ ('getgrgid(', 'getgrgid_r('),
+ ('getgrnam(', 'getgrnam_r('),
+ ('getlogin(', 'getlogin_r('),
+ ('getpwnam(', 'getpwnam_r('),
+ ('getpwuid(', 'getpwuid_r('),
+ ('gmtime(', 'gmtime_r('),
+ ('localtime(', 'localtime_r('),
+ ('rand(', 'rand_r('),
+ ('readdir(', 'readdir_r('),
+ ('strtok(', 'strtok_r('),
+ ('ttyname(', 'ttyname_r('),
+ )
+
+
+def CheckPosixThreading(filename, clean_lines, linenum, error):
+ """Checks for calls to thread-unsafe functions.
+
+ Much code has been originally written without consideration of
+ multi-threading. Also, engineers are relying on their old experience;
+ they have learned posix before threading extensions were added. These
+ tests guide the engineers to use thread-safe functions (when using
+ posix directly).
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ error: The function to call with any errors found.
+ """
+ line = clean_lines.elided[linenum]
+ for single_thread_function, multithread_safe_function in threading_list:
+ ix = line.find(single_thread_function)
+ # Comparisons made explicit for clarity -- pylint: disable-msg=C6403
+ if ix >= 0 and (ix == 0 or (not line[ix - 1].isalnum() and
+ line[ix - 1] not in ('_', '.', '>'))):
+ error(filename, linenum, 'runtime/threadsafe_fn', 2,
+ 'Consider using ' + multithread_safe_function +
+ '...) instead of ' + single_thread_function +
+ '...) for improved thread safety.')
+
+
+# Matches invalid increment: *count++, which moves pointer instead of
+# incrementing a value.
+_RE_PATTERN_INVALID_INCREMENT = re.compile(
+ r'^\s*\*\w+(\+\+|--);')
+
+
+def CheckInvalidIncrement(filename, clean_lines, linenum, error):
+ """Checks for invalid increment *count++.
+
+ For example following function:
+ void increment_counter(int* count) {
+ *count++;
+ }
+ is invalid, because it effectively does count++, moving pointer, and should
+ be replaced with ++*count, (*count)++ or *count += 1.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ error: The function to call with any errors found.
+ """
+ line = clean_lines.elided[linenum]
+ if _RE_PATTERN_INVALID_INCREMENT.match(line):
+ error(filename, linenum, 'runtime/invalid_increment', 5,
+ 'Changing pointer instead of value (or unused value of operator*).')
+
+
+class _BlockInfo(object):
+ """Stores information about a generic block of code."""
+
+ def __init__(self, seen_open_brace):
+ self.seen_open_brace = seen_open_brace
+ self.open_parentheses = 0
+ self.inline_asm = _NO_ASM
+
+ def CheckBegin(self, filename, clean_lines, linenum, error):
+ """Run checks that applies to text up to the opening brace.
+
+ This is mostly for checking the text after the class identifier
+ and the "{", usually where the base class is specified. For other
+ blocks, there isn't much to check, so we always pass.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ error: The function to call with any errors found.
+ """
+ pass
+
+ def CheckEnd(self, filename, clean_lines, linenum, error):
+ """Run checks that applies to text after the closing brace.
+
+ This is mostly used for checking end of namespace comments.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ error: The function to call with any errors found.
+ """
+ pass
+
+
+class _ClassInfo(_BlockInfo):
+ """Stores information about a class."""
+
+ def __init__(self, name, class_or_struct, clean_lines, linenum):
+ _BlockInfo.__init__(self, False)
+ self.name = name
+ self.starting_linenum = linenum
+ self.is_derived = False
+ if class_or_struct == 'struct':
+ self.access = 'public'
+ else:
+ self.access = 'private'
+
+ # Try to find the end of the class. This will be confused by things like:
+ # class A {
+ # } *x = { ...
+ #
+ # But it's still good enough for CheckSectionSpacing.
+ self.last_line = 0
+ depth = 0
+ for i in range(linenum, clean_lines.NumLines()):
+ line = clean_lines.elided[i]
+ depth += line.count('{') - line.count('}')
+ if not depth:
+ self.last_line = i
+ break
+
+ def CheckBegin(self, filename, clean_lines, linenum, error):
+ # Look for a bare ':'
+ if Search('(^|[^:]):($|[^:])', clean_lines.elided[linenum]):
+ self.is_derived = True
+
+
+class _NamespaceInfo(_BlockInfo):
+ """Stores information about a namespace."""
+
+ def __init__(self, name, linenum):
+ _BlockInfo.__init__(self, False)
+ self.name = name or ''
+ self.starting_linenum = linenum
+
+ def CheckEnd(self, filename, clean_lines, linenum, error):
+ """Check end of namespace comments."""
+ line = clean_lines.raw_lines[linenum]
+
+ # Check how many lines is enclosed in this namespace. Don't issue
+ # warning for missing namespace comments if there aren't enough
+ # lines. However, do apply checks if there is already an end of
+ # namespace comment and it's incorrect.
+ #
+ # TODO(unknown): We always want to check end of namespace comments
+ # if a namespace is large, but sometimes we also want to apply the
+ # check if a short namespace contained nontrivial things (something
+ # other than forward declarations). There is currently no logic on
+ # deciding what these nontrivial things are, so this check is
+ # triggered by namespace size only, which works most of the time.
+ if (linenum - self.starting_linenum < 10
+ and not Match(r'};*\s*(//|/\*).*\bnamespace\b', line)):
+ return
+
+ # Look for matching comment at end of namespace.
+ #
+ # Note that we accept C style "/* */" comments for terminating
+ # namespaces, so that code that terminate namespaces inside
+ # preprocessor macros can be cpplint clean. Example: http://go/nxpiz
+ #
+ # We also accept stuff like "// end of namespace <name>." with the
+ # period at the end.
+ #
+ # Besides these, we don't accept anything else, otherwise we might
+ # get false negatives when existing comment is a substring of the
+ # expected namespace. Example: http://go/ldkdc, http://cl/23548205
+ if self.name:
+ # Named namespace
+ if not Match((r'};*\s*(//|/\*).*\bnamespace\s+' + re.escape(self.name) +
+ r'[\*/\.\\\s]*$'),
+ line):
+ error(filename, linenum, 'readability/namespace', 5,
+ 'Namespace should be terminated with "// namespace %s"' %
+ self.name)
+ else:
+ # Anonymous namespace
+ if not Match(r'};*\s*(//|/\*).*\bnamespace[\*/\.\\\s]*$', line):
+ error(filename, linenum, 'readability/namespace', 5,
+ 'Namespace should be terminated with "// namespace"')
+
+
+class _PreprocessorInfo(object):
+ """Stores checkpoints of nesting stacks when #if/#else is seen."""
+
+ def __init__(self, stack_before_if):
+ # The entire nesting stack before #if
+ self.stack_before_if = stack_before_if
+
+ # The entire nesting stack up to #else
+ self.stack_before_else = []
+
+ # Whether we have already seen #else or #elif
+ self.seen_else = False
+
+
+class _NestingState(object):
+ """Holds states related to parsing braces."""
+
+ def __init__(self):
+ # Stack for tracking all braces. An object is pushed whenever we
+ # see a "{", and popped when we see a "}". Only 3 types of
+ # objects are possible:
+ # - _ClassInfo: a class or struct.
+ # - _NamespaceInfo: a namespace.
+ # - _BlockInfo: some other type of block.
+ self.stack = []
+
+ # Stack of _PreprocessorInfo objects.
+ self.pp_stack = []
+
+ def SeenOpenBrace(self):
+ """Check if we have seen the opening brace for the innermost block.
+
+ Returns:
+ True if we have seen the opening brace, False if the innermost
+ block is still expecting an opening brace.
+ """
+ return (not self.stack) or self.stack[-1].seen_open_brace
+
+ def InNamespaceBody(self):
+ """Check if we are currently one level inside a namespace body.
+
+ Returns:
+ True if top of the stack is a namespace block, False otherwise.
+ """
+ return self.stack and isinstance(self.stack[-1], _NamespaceInfo)
+
+ def UpdatePreprocessor(self, line):
+ """Update preprocessor stack.
+
+ We need to handle preprocessors due to classes like this:
+ #ifdef SWIG
+ struct ResultDetailsPageElementExtensionPoint {
+ #else
+ struct ResultDetailsPageElementExtensionPoint : public Extension {
+ #endif
+ (see http://go/qwddn for original example)
+
+ We make the following assumptions (good enough for most files):
+ - Preprocessor condition evaluates to true from #if up to first
+ #else/#elif/#endif.
+
+ - Preprocessor condition evaluates to false from #else/#elif up
+ to #endif. We still perform lint checks on these lines, but
+ these do not affect nesting stack.
+
+ Args:
+ line: current line to check.
+ """
+ if Match(r'^\s*#\s*(if|ifdef|ifndef)\b', line):
+ # Beginning of #if block, save the nesting stack here. The saved
+ # stack will allow us to restore the parsing state in the #else case.
+ self.pp_stack.append(_PreprocessorInfo(copy.deepcopy(self.stack)))
+ elif Match(r'^\s*#\s*(else|elif)\b', line):
+ # Beginning of #else block
+ if self.pp_stack:
+ if not self.pp_stack[-1].seen_else:
+ # This is the first #else or #elif block. Remember the
+ # whole nesting stack up to this point. This is what we
+ # keep after the #endif.
+ self.pp_stack[-1].seen_else = True
+ self.pp_stack[-1].stack_before_else = copy.deepcopy(self.stack)
+
+ # Restore the stack to how it was before the #if
+ self.stack = copy.deepcopy(self.pp_stack[-1].stack_before_if)
+ else:
+ # TODO(unknown): unexpected #else, issue warning?
+ pass
+ elif Match(r'^\s*#\s*endif\b', line):
+ # End of #if or #else blocks.
+ if self.pp_stack:
+ # If we saw an #else, we will need to restore the nesting
+ # stack to its former state before the #else, otherwise we
+ # will just continue from where we left off.
+ if self.pp_stack[-1].seen_else:
+ # Here we can just use a shallow copy since we are the last
+ # reference to it.
+ self.stack = self.pp_stack[-1].stack_before_else
+ # Drop the corresponding #if
+ self.pp_stack.pop()
+ else:
+ # TODO(unknown): unexpected #endif, issue warning?
+ pass
+
+ def Update(self, filename, clean_lines, linenum, error):
+ """Update nesting state with current line.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ error: The function to call with any errors found.
+ """
+ line = clean_lines.elided[linenum]
+
+ # Update pp_stack first
+ self.UpdatePreprocessor(line)
+
+ # Count parentheses. This is to avoid adding struct arguments to
+ # the nesting stack.
+ if self.stack:
+ inner_block = self.stack[-1]
+ depth_change = line.count('(') - line.count(')')
+ inner_block.open_parentheses += depth_change
+
+ # Also check if we are starting or ending an inline assembly block.
+ if inner_block.inline_asm in (_NO_ASM, _END_ASM):
+ if (depth_change != 0 and
+ inner_block.open_parentheses == 1 and
+ _MATCH_ASM.match(line)):
+ # Enter assembly block
+ inner_block.inline_asm = _INSIDE_ASM
+ else:
+ # Not entering assembly block. If previous line was _END_ASM,
+ # we will now shift to _NO_ASM state.
+ inner_block.inline_asm = _NO_ASM
+ elif (inner_block.inline_asm == _INSIDE_ASM and
+ inner_block.open_parentheses == 0):
+ # Exit assembly block
+ inner_block.inline_asm = _END_ASM
+
+ # Consume namespace declaration at the beginning of the line. Do
+ # this in a loop so that we catch same line declarations like this:
+ # namespace proto2 { namespace bridge { class MessageSet; } }
+ while True:
+ # Match start of namespace. The "\b\s*" below catches namespace
+ # declarations even if it weren't followed by a whitespace, this
+ # is so that we don't confuse our namespace checker. The
+ # missing spaces will be flagged by CheckSpacing.
+ namespace_decl_match = Match(r'^\s*namespace\b\s*([:\w]+)?(.*)$', line)
+ if not namespace_decl_match:
+ break
+
+ new_namespace = _NamespaceInfo(namespace_decl_match.group(1), linenum)
+ self.stack.append(new_namespace)
+
+ line = namespace_decl_match.group(2)
+ if line.find('{') != -1:
+ new_namespace.seen_open_brace = True
+ line = line[line.find('{') + 1:]
+
+ # Look for a class declaration in whatever is left of the line
+ # after parsing namespaces. The regexp accounts for decorated classes
+ # such as in:
+ # class LOCKABLE API Object {
+ # };
+ #
+ # Templates with class arguments may confuse the parser, for example:
+ # template <class T
+ # class Comparator = less<T>,
+ # class Vector = vector<T> >
+ # class HeapQueue {
+ #
+ # Because this parser has no nesting state about templates, by the
+ # time it saw "class Comparator", it may think that it's a new class.
+ # Nested templates have a similar problem:
+ # template <
+ # typename ExportedType,
+ # typename TupleType,
+ # template <typename, typename> class ImplTemplate>
+ #
+ # To avoid these cases, we ignore classes that are followed by '=' or '>'
+ class_decl_match = Match(
+ r'\s*(template\s*<[\w\s<>,:]*>\s*)?'
+ '(class|struct)\s+([A-Z_]+\s+)*(\w+(?:::\w+)*)'
+ '(([^=>]|<[^<>]*>)*)$', line)
+ if (class_decl_match and
+ (not self.stack or self.stack[-1].open_parentheses == 0)):
+ self.stack.append(_ClassInfo(
+ class_decl_match.group(4), class_decl_match.group(2),
+ clean_lines, linenum))
+ line = class_decl_match.group(5)
+
+ # If we have not yet seen the opening brace for the innermost block,
+ # run checks here.
+ if not self.SeenOpenBrace():
+ self.stack[-1].CheckBegin(filename, clean_lines, linenum, error)
+
+ # Update access control if we are inside a class/struct
+ if self.stack and isinstance(self.stack[-1], _ClassInfo):
+ access_match = Match(r'\s*(public|private|protected)\s*:', line)
+ if access_match:
+ self.stack[-1].access = access_match.group(1)
+
+ # Consume braces or semicolons from what's left of the line
+ while True:
+ # Match first brace, semicolon, or closed parenthesis.
+ matched = Match(r'^[^{;)}]*([{;)}])(.*)$', line)
+ if not matched:
+ break
+
+ token = matched.group(1)
+ if token == '{':
+ # If namespace or class hasn't seen a opening brace yet, mark
+ # namespace/class head as complete. Push a new block onto the
+ # stack otherwise.
+ if not self.SeenOpenBrace():
+ self.stack[-1].seen_open_brace = True
+ else:
+ self.stack.append(_BlockInfo(True))
+ if _MATCH_ASM.match(line):
+ self.stack[-1].inline_asm = _BLOCK_ASM
+ elif token == ';' or token == ')':
+ # If we haven't seen an opening brace yet, but we already saw
+ # a semicolon, this is probably a forward declaration. Pop
+ # the stack for these.
+ #
+ # Similarly, if we haven't seen an opening brace yet, but we
+ # already saw a closing parenthesis, then these are probably
+ # function arguments with extra "class" or "struct" keywords.
+ # Also pop these stack for these.
+ if not self.SeenOpenBrace():
+ self.stack.pop()
+ else: # token == '}'
+ # Perform end of block checks and pop the stack.
+ if self.stack:
+ self.stack[-1].CheckEnd(filename, clean_lines, linenum, error)
+ self.stack.pop()
+ line = matched.group(2)
+
+ def InnermostClass(self):
+ """Get class info on the top of the stack.
+
+ Returns:
+ A _ClassInfo object if we are inside a class, or None otherwise.
+ """
+ for i in range(len(self.stack), 0, -1):
+ classinfo = self.stack[i - 1]
+ if isinstance(classinfo, _ClassInfo):
+ return classinfo
+ return None
+
+ def CheckClassFinished(self, filename, error):
+ """Checks that all classes have been completely parsed.
+
+ Call this when all lines in a file have been processed.
+ Args:
+ filename: The name of the current file.
+ error: The function to call with any errors found.
+ """
+ # Note: This test can result in false positives if #ifdef constructs
+ # get in the way of brace matching. See the testBuildClass test in
+ # cpplint_unittest.py for an example of this.
+ for obj in self.stack:
+ if isinstance(obj, _ClassInfo):
+ error(filename, obj.starting_linenum, 'build/class', 5,
+ 'Failed to find complete declaration of class %s' %
+ obj.name)
+
+
+def CheckForNonStandardConstructs(filename, clean_lines, linenum,
+ nesting_state, error):
+ """Logs an error if we see certain non-ANSI constructs ignored by gcc-2.
+
+ Complain about several constructs which gcc-2 accepts, but which are
+ not standard C++. Warning about these in lint is one way to ease the
+ transition to new compilers.
+ - put storage class first (e.g. "static const" instead of "const static").
+ - "%lld" instead of %qd" in printf-type functions.
+ - "%1$d" is non-standard in printf-type functions.
+ - "\%" is an undefined character escape sequence.
+ - text after #endif is not allowed.
+ - invalid inner-style forward declaration.
+ - >? and <? operators, and their >?= and <?= cousins.
+
+ Additionally, check for constructor/destructor style violations and reference
+ members, as it is very convenient to do so while checking for
+ gcc-2 compliance.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ nesting_state: A _NestingState instance which maintains information about
+ the current stack of nested blocks being parsed.
+ error: A callable to which errors are reported, which takes 4 arguments:
+ filename, line number, error level, and message
+ """
+
+ # Remove comments from the line, but leave in strings for now.
+ line = clean_lines.lines[linenum]
+
+ if Search(r'printf\s*\(.*".*%[-+ ]?\d*q', line):
+ error(filename, linenum, 'runtime/printf_format', 3,
+ '%q in format strings is deprecated. Use %ll instead.')
+
+ if Search(r'printf\s*\(.*".*%\d+\$', line):
+ error(filename, linenum, 'runtime/printf_format', 2,
+ '%N$ formats are unconventional. Try rewriting to avoid them.')
+
+ # Remove escaped backslashes before looking for undefined escapes.
+ line = line.replace('\\\\', '')
+
+ if Search(r'("|\').*\\(%|\[|\(|{)', line):
+ error(filename, linenum, 'build/printf_format', 3,
+ '%, [, (, and { are undefined character escapes. Unescape them.')
+
+ # For the rest, work with both comments and strings removed.
+ line = clean_lines.elided[linenum]
+
+ if Search(r'\b(const|volatile|void|char|short|int|long'
+ r'|float|double|signed|unsigned'
+ r'|schar|u?int8|u?int16|u?int32|u?int64)'
+ r'\s+(register|static|extern|typedef)\b',
+ line):
+ error(filename, linenum, 'build/storage_class', 5,
+ 'Storage class (static, extern, typedef, etc) should be first.')
+
+ if Match(r'\s*#\s*endif\s*[^/\s]+', line):
+ error(filename, linenum, 'build/endif_comment', 5,
+ 'Uncommented text after #endif is non-standard. Use a comment.')
+
+ if Match(r'\s*class\s+(\w+\s*::\s*)+\w+\s*;', line):
+ error(filename, linenum, 'build/forward_decl', 5,
+ 'Inner-style forward declarations are invalid. Remove this line.')
+
+ if Search(r'(\w+|[+-]?\d+(\.\d*)?)\s*(<|>)\?=?\s*(\w+|[+-]?\d+)(\.\d*)?',
+ line):
+ error(filename, linenum, 'build/deprecated', 3,
+ '>? and <? (max and min) operators are non-standard and deprecated.')
+
+ if Search(r'^\s*const\s*string\s*&\s*\w+\s*;', line):
+ # TODO(unknown): Could it be expanded safely to arbitrary references,
+ # without triggering too many false positives? The first
+ # attempt triggered 5 warnings for mostly benign code in the regtest, hence
+ # the restriction.
+ # Here's the original regexp, for the reference:
+ # type_name = r'\w+((\s*::\s*\w+)|(\s*<\s*\w+?\s*>))?'
+ # r'\s*const\s*' + type_name + '\s*&\s*\w+\s*;'
+ error(filename, linenum, 'runtime/member_string_references', 2,
+ 'const string& members are dangerous. It is much better to use '
+ 'alternatives, such as pointers or simple constants.')
+
+ # Everything else in this function operates on class declarations.
+ # Return early if the top of the nesting stack is not a class, or if
+ # the class head is not completed yet.
+ classinfo = nesting_state.InnermostClass()
+ if not classinfo or not classinfo.seen_open_brace:
+ return
+
+ # The class may have been declared with namespace or classname qualifiers.
+ # The constructor and destructor will not have those qualifiers.
+ base_classname = classinfo.name.split('::')[-1]
+
+ # Look for single-argument constructors that aren't marked explicit.
+ # Technically a valid construct, but against style.
+ args = Match(r'\s+(?:inline\s+)?%s\s*\(([^,()]+)\)'
+ % re.escape(base_classname),
+ line)
+ if (args and
+ args.group(1) != 'void' and
+ not Match(r'(const\s+)?%s\s*(?:<\w+>\s*)?&' % re.escape(base_classname),
+ args.group(1).strip())):
+ error(filename, linenum, 'runtime/explicit', 5,
+ 'Single-argument constructors should be marked explicit.')
+
+
+def CheckSpacingForFunctionCall(filename, line, linenum, error):
+ """Checks for the correctness of various spacing around function calls.
+
+ Args:
+ filename: The name of the current file.
+ line: The text of the line to check.
+ linenum: The number of the line to check.
+ error: The function to call with any errors found.
+ """
+
+ # Since function calls often occur inside if/for/while/switch
+ # expressions - which have their own, more liberal conventions - we
+ # first see if we should be looking inside such an expression for a
+ # function call, to which we can apply more strict standards.
+ fncall = line # if there's no control flow construct, look at whole line
+ for pattern in (r'\bif\s*\((.*)\)\s*{',
+ r'\bfor\s*\((.*)\)\s*{',
+ r'\bwhile\s*\((.*)\)\s*[{;]',
+ r'\bswitch\s*\((.*)\)\s*{'):
+ match = Search(pattern, line)
+ if match:
+ fncall = match.group(1) # look inside the parens for function calls
+ break
+
+ # Except in if/for/while/switch, there should never be space
+ # immediately inside parens (eg "f( 3, 4 )"). We make an exception
+ # for nested parens ( (a+b) + c ). Likewise, there should never be
+ # a space before a ( when it's a function argument. I assume it's a
+ # function argument when the char before the whitespace is legal in
+ # a function name (alnum + _) and we're not starting a macro. Also ignore
+ # pointers and references to arrays and functions coz they're too tricky:
+ # we use a very simple way to recognize these:
+ # " (something)(maybe-something)" or
+ # " (something)(maybe-something," or
+ # " (something)[something]"
+ # Note that we assume the contents of [] to be short enough that
+ # they'll never need to wrap.
+ if ( # Ignore control structures.
+ not Search(r'\b(if|for|while|switch|return|delete)\b', fncall) and
+ # Ignore pointers/references to functions.
+ not Search(r' \([^)]+\)\([^)]*(\)|,$)', fncall) and
+ # Ignore pointers/references to arrays.
+ not Search(r' \([^)]+\)\[[^\]]+\]', fncall)):
+ if Search(r'\w\s*\(\s(?!\s*\\$)', fncall): # a ( used for a fn call
+ error(filename, linenum, 'whitespace/parens', 4,
+ 'Extra space after ( in function call')
+ elif Search(r'\(\s+(?!(\s*\\)|\()', fncall):
+ error(filename, linenum, 'whitespace/parens', 2,
+ 'Extra space after (')
+ if (Search(r'\w\s+\(', fncall) and
+ not Search(r'#\s*define|typedef', fncall) and
+ not Search(r'\w\s+\((\w+::)?\*\w+\)\(', fncall)):
+ error(filename, linenum, 'whitespace/parens', 4,
+ 'Extra space before ( in function call')
+ # If the ) is followed only by a newline or a { + newline, assume it's
+ # part of a control statement (if/while/etc), and don't complain
+ if Search(r'[^)]\s+\)\s*[^{\s]', fncall):
+ # If the closing parenthesis is preceded by only whitespaces,
+ # try to give a more descriptive error message.
+ if Search(r'^\s+\)', fncall):
+ error(filename, linenum, 'whitespace/parens', 2,
+ 'Closing ) should be moved to the previous line')
+ else:
+ error(filename, linenum, 'whitespace/parens', 2,
+ 'Extra space before )')
+
+
+def IsBlankLine(line):
+ """Returns true if the given line is blank.
+
+ We consider a line to be blank if the line is empty or consists of
+ only white spaces.
+
+ Args:
+ line: A line of a string.
+
+ Returns:
+ True, if the given line is blank.
+ """
+ return not line or line.isspace()
+
+
+def CheckForFunctionLengths(filename, clean_lines, linenum,
+ function_state, error):
+ """Reports for long function bodies.
+
+ For an overview why this is done, see:
+ http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Write_Short_Functions
+
+ Uses a simplistic algorithm assuming other style guidelines
+ (especially spacing) are followed.
+ Only checks unindented functions, so class members are unchecked.
+ Trivial bodies are unchecked, so constructors with huge initializer lists
+ may be missed.
+ Blank/comment lines are not counted so as to avoid encouraging the removal
+ of vertical space and comments just to get through a lint check.
+ NOLINT *on the last line of a function* disables this check.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ function_state: Current function name and lines in body so far.
+ error: The function to call with any errors found.
+ """
+ lines = clean_lines.lines
+ line = lines[linenum]
+ raw = clean_lines.raw_lines
+ raw_line = raw[linenum]
+ joined_line = ''
+
+ starting_func = False
+ regexp = r'(\w(\w|::|\*|\&|\s)*)\(' # decls * & space::name( ...
+ match_result = Match(regexp, line)
+ if match_result:
+ # If the name is all caps and underscores, figure it's a macro and
+ # ignore it, unless it's TEST or TEST_F.
+ function_name = match_result.group(1).split()[-1]
+ if function_name == 'TEST' or function_name == 'TEST_F' or (
+ not Match(r'[A-Z_]+$', function_name)):
+ starting_func = True
+
+ if starting_func:
+ body_found = False
+ for start_linenum in xrange(linenum, clean_lines.NumLines()):
+ start_line = lines[start_linenum]
+ joined_line += ' ' + start_line.lstrip()
+ if Search(r'(;|})', start_line): # Declarations and trivial functions
+ body_found = True
+ break # ... ignore
+ elif Search(r'{', start_line):
+ body_found = True
+ function = Search(r'((\w|:)*)\(', line).group(1)
+ if Match(r'TEST', function): # Handle TEST... macros
+ parameter_regexp = Search(r'(\(.*\))', joined_line)
+ if parameter_regexp: # Ignore bad syntax
+ function += parameter_regexp.group(1)
+ else:
+ function += '()'
+ function_state.Begin(function)
+ break
+ if not body_found:
+ # No body for the function (or evidence of a non-function) was found.
+ error(filename, linenum, 'readability/fn_size', 5,
+ 'Lint failed to find start of function body.')
+ elif Match(r'^\}\s*$', line): # function end
+ function_state.Check(error, filename, linenum)
+ function_state.End()
+ elif not Match(r'^\s*$', line):
+ function_state.Count() # Count non-blank/non-comment lines.
+
+
+_RE_PATTERN_TODO = re.compile(r'^//(\s*)TODO(\(.+?\))?:?(\s|$)?')
+
+
+def CheckComment(comment, filename, linenum, error):
+ """Checks for common mistakes in TODO comments.
+
+ Args:
+ comment: The text of the comment from the line in question.
+ filename: The name of the current file.
+ linenum: The number of the line to check.
+ error: The function to call with any errors found.
+ """
+ match = _RE_PATTERN_TODO.match(comment)
+ if match:
+ # One whitespace is correct; zero whitespace is handled elsewhere.
+ leading_whitespace = match.group(1)
+ if len(leading_whitespace) > 1:
+ error(filename, linenum, 'whitespace/todo', 2,
+ 'Too many spaces before TODO')
+
+ username = match.group(2)
+ if not username:
+ error(filename, linenum, 'readability/todo', 2,
+ 'Missing username in TODO; it should look like '
+ '"// TODO(my_username): Stuff."')
+
+ middle_whitespace = match.group(3)
+ # Comparisons made explicit for correctness -- pylint: disable-msg=C6403
+ if middle_whitespace != ' ' and middle_whitespace != '':
+ error(filename, linenum, 'whitespace/todo', 2,
+ 'TODO(my_username) should be followed by a space')
+
+def CheckAccess(filename, clean_lines, linenum, nesting_state, error):
+ """Checks for improper use of DISALLOW* macros.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ nesting_state: A _NestingState instance which maintains information about
+ the current stack of nested blocks being parsed.
+ error: The function to call with any errors found.
+ """
+ line = clean_lines.elided[linenum] # get rid of comments and strings
+
+ matched = Match((r'\s*(DISALLOW_COPY_AND_ASSIGN|'
+ r'DISALLOW_EVIL_CONSTRUCTORS|'
+ r'DISALLOW_IMPLICIT_CONSTRUCTORS)'), line)
+ if not matched:
+ return
+ if nesting_state.stack and isinstance(nesting_state.stack[-1], _ClassInfo):
+ if nesting_state.stack[-1].access != 'private':
+ error(filename, linenum, 'readability/constructors', 3,
+ '%s must be in the private: section' % matched.group(1))
+
+ else:
+ # Found DISALLOW* macro outside a class declaration, or perhaps it
+ # was used inside a function when it should have been part of the
+ # class declaration. We could issue a warning here, but it
+ # probably resulted in a compiler error already.
+ pass
+
+
+def FindNextMatchingAngleBracket(clean_lines, linenum, init_suffix):
+ """Find the corresponding > to close a template.
+
+ Args:
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: Current line number.
+ init_suffix: Remainder of the current line after the initial <.
+
+ Returns:
+ True if a matching bracket exists.
+ """
+ line = init_suffix
+ nesting_stack = ['<']
+ while True:
+ # Find the next operator that can tell us whether < is used as an
+ # opening bracket or as a less-than operator. We only want to
+ # warn on the latter case.
+ #
+ # We could also check all other operators and terminate the search
+ # early, e.g. if we got something like this "a<b+c", the "<" is
+ # most likely a less-than operator, but then we will get false
+ # positives for default arguments (e.g. http://go/prccd) and
+ # other template expressions (e.g. http://go/oxcjq).
+ match = Search(r'^[^<>(),;\[\]]*([<>(),;\[\]])(.*)$', line)
+ if match:
+ # Found an operator, update nesting stack
+ operator = match.group(1)
+ line = match.group(2)
+
+ if nesting_stack[-1] == '<':
+ # Expecting closing angle bracket
+ if operator in ('<', '(', '['):
+ nesting_stack.append(operator)
+ elif operator == '>':
+ nesting_stack.pop()
+ if not nesting_stack:
+ # Found matching angle bracket
+ return True
+ elif operator == ',':
+ # Got a comma after a bracket, this is most likely a template
+ # argument. We have not seen a closing angle bracket yet, but
+ # it's probably a few lines later if we look for it, so just
+ # return early here.
+ return True
+ else:
+ # Got some other operator.
+ return False
+
+ else:
+ # Expecting closing parenthesis or closing bracket
+ if operator in ('<', '(', '['):
+ nesting_stack.append(operator)
+ elif operator in (')', ']'):
+ # We don't bother checking for matching () or []. If we got
+ # something like (] or [), it would have been a syntax error.
+ nesting_stack.pop()
+
+ else:
+ # Scan the next line
+ linenum += 1
+ if linenum >= len(clean_lines.elided):
+ break
+ line = clean_lines.elided[linenum]
+
+ # Exhausted all remaining lines and still no matching angle bracket.
+ # Most likely the input was incomplete, otherwise we should have
+ # seen a semicolon and returned early.
+ return True
+
+
+def FindPreviousMatchingAngleBracket(clean_lines, linenum, init_prefix):
+ """Find the corresponding < that started a template.
+
+ Args:
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: Current line number.
+ init_prefix: Part of the current line before the initial >.
+
+ Returns:
+ True if a matching bracket exists.
+ """
+ line = init_prefix
+ nesting_stack = ['>']
+ while True:
+ # Find the previous operator
+ match = Search(r'^(.*)([<>(),;\[\]])[^<>(),;\[\]]*$', line)
+ if match:
+ # Found an operator, update nesting stack
+ operator = match.group(2)
+ line = match.group(1)
+
+ if nesting_stack[-1] == '>':
+ # Expecting opening angle bracket
+ if operator in ('>', ')', ']'):
+ nesting_stack.append(operator)
+ elif operator == '<':
+ nesting_stack.pop()
+ if not nesting_stack:
+ # Found matching angle bracket
+ return True
+ elif operator == ',':
+ # Got a comma before a bracket, this is most likely a
+ # template argument. The opening angle bracket is probably
+ # there if we look for it, so just return early here.
+ return True
+ else:
+ # Got some other operator.
+ return False
+
+ else:
+ # Expecting opening parenthesis or opening bracket
+ if operator in ('>', ')', ']'):
+ nesting_stack.append(operator)
+ elif operator in ('(', '['):
+ nesting_stack.pop()
+
+ else:
+ # Scan the previous line
+ linenum -= 1
+ if linenum < 0:
+ break
+ line = clean_lines.elided[linenum]
+
+ # Exhausted all earlier lines and still no matching angle bracket.
+ return False
+
+
+def CheckSpacing(filename, clean_lines, linenum, nesting_state, error):
+ """Checks for the correctness of various spacing issues in the code.
+
+ Things we check for: spaces around operators, spaces after
+ if/for/while/switch, no spaces around parens in function calls, two
+ spaces between code and comment, don't start a block with a blank
+ line, don't end a function with a blank line, don't add a blank line
+ after public/protected/private, don't have too many blank lines in a row.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ nesting_state: A _NestingState instance which maintains information about
+ the current stack of nested blocks being parsed.
+ error: The function to call with any errors found.
+ """
+
+ raw = clean_lines.raw_lines
+ line = raw[linenum]
+
+ # Before nixing comments, check if the line is blank for no good
+ # reason. This includes the first line after a block is opened, and
+ # blank lines at the end of a function (ie, right before a line like '}'
+ #
+ # Skip all the blank line checks if we are immediately inside a
+ # namespace body. In other words, don't issue blank line warnings
+ # for this block:
+ # namespace {
+ #
+ # }
+ #
+ # A warning about missing end of namespace comments will be issued instead.
+ if IsBlankLine(line) and not nesting_state.InNamespaceBody():
+ elided = clean_lines.elided
+ prev_line = elided[linenum - 1]
+ prevbrace = prev_line.rfind('{')
+ # TODO(unknown): Don't complain if line before blank line, and line after,
+ # both start with alnums and are indented the same amount.
+ # This ignores whitespace at the start of a namespace block
+ # because those are not usually indented.
+ if prevbrace != -1 and prev_line[prevbrace:].find('}') == -1:
+ # OK, we have a blank line at the start of a code block. Before we
+ # complain, we check if it is an exception to the rule: The previous
+ # non-empty line has the parameters of a function header that are indented
+ # 4 spaces (because they did not fit in a 80 column line when placed on
+ # the same line as the function name). We also check for the case where
+ # the previous line is indented 6 spaces, which may happen when the
+ # initializers of a constructor do not fit into a 80 column line.
+ exception = False
+ if Match(r' {6}\w', prev_line): # Initializer list?
+ # We are looking for the opening column of initializer list, which
+ # should be indented 4 spaces to cause 6 space indentation afterwards.
+ search_position = linenum-2
+ while (search_position >= 0
+ and Match(r' {6}\w', elided[search_position])):
+ search_position -= 1
+ exception = (search_position >= 0
+ and elided[search_position][:5] == ' :')
+ else:
+ # Search for the function arguments or an initializer list. We use a
+ # simple heuristic here: If the line is indented 4 spaces; and we have a
+ # closing paren, without the opening paren, followed by an opening brace
+ # or colon (for initializer lists) we assume that it is the last line of
+ # a function header. If we have a colon indented 4 spaces, it is an
+ # initializer list.
+ exception = (Match(r' {4}\w[^\(]*\)\s*(const\s*)?(\{\s*$|:)',
+ prev_line)
+ or Match(r' {4}:', prev_line))
+
+ if not exception:
+ error(filename, linenum, 'whitespace/blank_line', 2,
+ 'Blank line at the start of a code block. Is this needed?')
+ # Ignore blank lines at the end of a block in a long if-else
+ # chain, like this:
+ # if (condition1) {
+ # // Something followed by a blank line
+ #
+ # } else if (condition2) {
+ # // Something else
+ # }
+ if linenum + 1 < clean_lines.NumLines():
+ next_line = raw[linenum + 1]
+ if (next_line
+ and Match(r'\s*}', next_line)
+ and next_line.find('} else ') == -1):
+ error(filename, linenum, 'whitespace/blank_line', 3,
+ 'Blank line at the end of a code block. Is this needed?')
+
+ matched = Match(r'\s*(public|protected|private):', prev_line)
+ if matched:
+ error(filename, linenum, 'whitespace/blank_line', 3,
+ 'Do not leave a blank line after "%s:"' % matched.group(1))
+
+ # Next, we complain if there's a comment too near the text
+ commentpos = line.find('//')
+ if commentpos != -1:
+ # Check if the // may be in quotes. If so, ignore it
+ # Comparisons made explicit for clarity -- pylint: disable-msg=C6403
+ if (line.count('"', 0, commentpos) -
+ line.count('\\"', 0, commentpos)) % 2 == 0: # not in quotes
+ # Allow one space for new scopes, two spaces otherwise:
+ if (not Match(r'^\s*{ //', line) and
+ ((commentpos >= 1 and
+ line[commentpos-1] not in string.whitespace) or
+ (commentpos >= 2 and
+ line[commentpos-2] not in string.whitespace))):
+ error(filename, linenum, 'whitespace/comments', 2,
+ 'At least two spaces is best between code and comments')
+ # There should always be a space between the // and the comment
+ commentend = commentpos + 2
+ if commentend < len(line) and not line[commentend] == ' ':
+ # but some lines are exceptions -- e.g. if they're big
+ # comment delimiters like:
+ # //----------------------------------------------------------
+ # or are an empty C++ style Doxygen comment, like:
+ # ///
+ # or they begin with multiple slashes followed by a space:
+ # //////// Header comment
+ match = (Search(r'[=/-]{4,}\s*$', line[commentend:]) or
+ Search(r'^/$', line[commentend:]) or
+ Search(r'^/+ ', line[commentend:]))
+ if not match:
+ error(filename, linenum, 'whitespace/comments', 4,
+ 'Should have a space between // and comment')
+ CheckComment(line[commentpos:], filename, linenum, error)
+
+ line = clean_lines.elided[linenum] # get rid of comments and strings
+
+ # Don't try to do spacing checks for operator methods
+ line = re.sub(r'operator(==|!=|<|<<|<=|>=|>>|>)\(', 'operator\(', line)
+
+ # We allow no-spaces around = within an if: "if ( (a=Foo()) == 0 )".
+ # Otherwise not. Note we only check for non-spaces on *both* sides;
+ # sometimes people put non-spaces on one side when aligning ='s among
+ # many lines (not that this is behavior that I approve of...)
+ if Search(r'[\w.]=[\w.]', line) and not Search(r'\b(if|while) ', line):
+ error(filename, linenum, 'whitespace/operators', 4,
+ 'Missing spaces around =')
+
+ # It's ok not to have spaces around binary operators like + - * /, but if
+ # there's too little whitespace, we get concerned. It's hard to tell,
+ # though, so we punt on this one for now. TODO.
+
+ # You should always have whitespace around binary operators.
+ #
+ # Check <= and >= first to avoid false positives with < and >, then
+ # check non-include lines for spacing around < and >.
+ match = Search(r'[^<>=!\s](==|!=|<=|>=)[^<>=!\s]', line)
+ if match:
+ error(filename, linenum, 'whitespace/operators', 3,
+ 'Missing spaces around %s' % match.group(1))
+ # We allow no-spaces around << when used like this: 10<<20, but
+ # not otherwise (particularly, not when used as streams)
+ match = Search(r'(\S)(?:L|UL|ULL|l|ul|ull)?<<(\S)', line)
+ if match and not (match.group(1).isdigit() and match.group(2).isdigit()):
+ error(filename, linenum, 'whitespace/operators', 3,
+ 'Missing spaces around <<')
+ elif not Match(r'#.*include', line):
+ # Avoid false positives on ->
+ reduced_line = line.replace('->', '')
+
+ # Look for < that is not surrounded by spaces. This is only
+ # triggered if both sides are missing spaces, even though
+ # technically should should flag if at least one side is missing a
+ # space. This is done to avoid some false positives with shifts.
+ match = Search(r'[^\s<]<([^\s=<].*)', reduced_line)
+ if (match and
+ not FindNextMatchingAngleBracket(clean_lines, linenum, match.group(1))):
+ error(filename, linenum, 'whitespace/operators', 3,
+ 'Missing spaces around <')
+
+ # Look for > that is not surrounded by spaces. Similar to the
+ # above, we only trigger if both sides are missing spaces to avoid
+ # false positives with shifts.
+ match = Search(r'^(.*[^\s>])>[^\s=>]', reduced_line)
+ if (match and
+ not FindPreviousMatchingAngleBracket(clean_lines, linenum,
+ match.group(1))):
+ error(filename, linenum, 'whitespace/operators', 3,
+ 'Missing spaces around >')
+
+ # We allow no-spaces around >> for almost anything. This is because
+ # C++11 allows ">>" to close nested templates, which accounts for
+ # most cases when ">>" is not followed by a space.
+ #
+ # We still warn on ">>" followed by alpha character, because that is
+ # likely due to ">>" being used for right shifts, e.g.:
+ # value >> alpha
+ #
+ # When ">>" is used to close templates, the alphanumeric letter that
+ # follows would be part of an identifier, and there should still be
+ # a space separating the template type and the identifier.
+ # type<type<type>> alpha
+ match = Search(r'>>[a-zA-Z_]', line)
+ if match:
+ error(filename, linenum, 'whitespace/operators', 3,
+ 'Missing spaces around >>')
+
+ # There shouldn't be space around unary operators
+ match = Search(r'(!\s|~\s|[\s]--[\s;]|[\s]\+\+[\s;])', line)
+ if match:
+ error(filename, linenum, 'whitespace/operators', 4,
+ 'Extra space for operator %s' % match.group(1))
+
+ # A pet peeve of mine: no spaces after an if, while, switch, or for
+ match = Search(r' (if\(|for\(|while\(|switch\()', line)
+ if match:
+ error(filename, linenum, 'whitespace/parens', 5,
+ 'Missing space before ( in %s' % match.group(1))
+
+ # For if/for/while/switch, the left and right parens should be
+ # consistent about how many spaces are inside the parens, and
+ # there should either be zero or one spaces inside the parens.
+ # We don't want: "if ( foo)" or "if ( foo )".
+ # Exception: "for ( ; foo; bar)" and "for (foo; bar; )" are allowed.
+ match = Search(r'\b(if|for|while|switch)\s*'
+ r'\(([ ]*)(.).*[^ ]+([ ]*)\)\s*{\s*$',
+ line)
+ if match:
+ if len(match.group(2)) != len(match.group(4)):
+ if not (match.group(3) == ';' and
+ len(match.group(2)) == 1 + len(match.group(4)) or
+ not match.group(2) and Search(r'\bfor\s*\(.*; \)', line)):
+ error(filename, linenum, 'whitespace/parens', 5,
+ 'Mismatching spaces inside () in %s' % match.group(1))
+ if not len(match.group(2)) in [0, 1]:
+ error(filename, linenum, 'whitespace/parens', 5,
+ 'Should have zero or one spaces inside ( and ) in %s' %
+ match.group(1))
+
+ # You should always have a space after a comma (either as fn arg or operator)
+ if Search(r',[^\s]', line):
+ error(filename, linenum, 'whitespace/comma', 3,
+ 'Missing space after ,')
+
+ # You should always have a space after a semicolon
+ # except for few corner cases
+ # TODO(unknown): clarify if 'if (1) { return 1;}' is requires one more
+ # space after ;
+ if Search(r';[^\s};\\)/]', line):
+ error(filename, linenum, 'whitespace/semicolon', 3,
+ 'Missing space after ;')
+
+ # Next we will look for issues with function calls.
+ CheckSpacingForFunctionCall(filename, line, linenum, error)
+
+ # Except after an opening paren, or after another opening brace (in case of
+ # an initializer list, for instance), you should have spaces before your
+ # braces. And since you should never have braces at the beginning of a line,
+ # this is an easy test.
+ if Search(r'[^ ({]{', line):
+ error(filename, linenum, 'whitespace/braces', 5,
+ 'Missing space before {')
+
+ # Make sure '} else {' has spaces.
+ if Search(r'}else', line):
+ error(filename, linenum, 'whitespace/braces', 5,
+ 'Missing space before else')
+
+ # You shouldn't have spaces before your brackets, except maybe after
+ # 'delete []' or 'new char * []'.
+ if Search(r'\w\s+\[', line) and not Search(r'delete\s+\[', line):
+ error(filename, linenum, 'whitespace/braces', 5,
+ 'Extra space before [')
+
+ # You shouldn't have a space before a semicolon at the end of the line.
+ # There's a special case for "for" since the style guide allows space before
+ # the semicolon there.
+ if Search(r':\s*;\s*$', line):
+ error(filename, linenum, 'whitespace/semicolon', 5,
+ 'Semicolon defining empty statement. Use {} instead.')
+ elif Search(r'^\s*;\s*$', line):
+ error(filename, linenum, 'whitespace/semicolon', 5,
+ 'Line contains only semicolon. If this should be an empty statement, '
+ 'use {} instead.')
+ elif (Search(r'\s+;\s*$', line) and
+ not Search(r'\bfor\b', line)):
+ error(filename, linenum, 'whitespace/semicolon', 5,
+ 'Extra space before last semicolon. If this should be an empty '
+ 'statement, use {} instead.')
+
+ # In range-based for, we wanted spaces before and after the colon, but
+ # not around "::" tokens that might appear.
+ if (Search('for *\(.*[^:]:[^: ]', line) or
+ Search('for *\(.*[^: ]:[^:]', line)):
+ error(filename, linenum, 'whitespace/forcolon', 2,
+ 'Missing space around colon in range-based for loop')
+
+
+def CheckSectionSpacing(filename, clean_lines, class_info, linenum, error):
+ """Checks for additional blank line issues related to sections.
+
+ Currently the only thing checked here is blank line before protected/private.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ class_info: A _ClassInfo objects.
+ linenum: The number of the line to check.
+ error: The function to call with any errors found.
+ """
+ # Skip checks if the class is small, where small means 25 lines or less.
+ # 25 lines seems like a good cutoff since that's the usual height of
+ # terminals, and any class that can't fit in one screen can't really
+ # be considered "small".
+ #
+ # Also skip checks if we are on the first line. This accounts for
+ # classes that look like
+ # class Foo { public: ... };
+ #
+ # If we didn't find the end of the class, last_line would be zero,
+ # and the check will be skipped by the first condition.
+ if (class_info.last_line - class_info.starting_linenum <= 24 or
+ linenum <= class_info.starting_linenum):
+ return
+
+ matched = Match(r'\s*(public|protected|private):', clean_lines.lines[linenum])
+ if matched:
+ # Issue warning if the line before public/protected/private was
+ # not a blank line, but don't do this if the previous line contains
+ # "class" or "struct". This can happen two ways:
+ # - We are at the beginning of the class.
+ # - We are forward-declaring an inner class that is semantically
+ # private, but needed to be public for implementation reasons.
+ # Also ignores cases where the previous line ends with a backslash as can be
+ # common when defining classes in C macros.
+ prev_line = clean_lines.lines[linenum - 1]
+ if (not IsBlankLine(prev_line) and
+ not Search(r'\b(class|struct)\b', prev_line) and
+ not Search(r'\\$', prev_line)):
+ # Try a bit harder to find the beginning of the class. This is to
+ # account for multi-line base-specifier lists, e.g.:
+ # class Derived
+ # : public Base {
+ end_class_head = class_info.starting_linenum
+ for i in range(class_info.starting_linenum, linenum):
+ if Search(r'\{\s*$', clean_lines.lines[i]):
+ end_class_head = i
+ break
+ if end_class_head < linenum - 1:
+ error(filename, linenum, 'whitespace/blank_line', 3,
+ '"%s:" should be preceded by a blank line' % matched.group(1))
+
+
+def GetPreviousNonBlankLine(clean_lines, linenum):
+ """Return the most recent non-blank line and its line number.
+
+ Args:
+ clean_lines: A CleansedLines instance containing the file contents.
+ linenum: The number of the line to check.
+
+ Returns:
+ A tuple with two elements. The first element is the contents of the last
+ non-blank line before the current line, or the empty string if this is the
+ first non-blank line. The second is the line number of that line, or -1
+ if this is the first non-blank line.
+ """
+
+ prevlinenum = linenum - 1
+ while prevlinenum >= 0:
+ prevline = clean_lines.elided[prevlinenum]
+ if not IsBlankLine(prevline): # if not a blank line...
+ return (prevline, prevlinenum)
+ prevlinenum -= 1
+ return ('', -1)
+
+
+def CheckBraces(filename, clean_lines, linenum, error):
+ """Looks for misplaced braces (e.g. at the end of line).
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ error: The function to call with any errors found.
+ """
+
+ line = clean_lines.elided[linenum] # get rid of comments and strings
+
+ if Match(r'\s*{\s*$', line):
+ # We allow an open brace to start a line in the case where someone
+ # is using braces in a block to explicitly create a new scope,
+ # which is commonly used to control the lifetime of
+ # stack-allocated variables. We don't detect this perfectly: we
+ # just don't complain if the last non-whitespace character on the
+ # previous non-blank line is ';', ':', '{', or '}', or if the previous
+ # line starts a preprocessor block.
+ prevline = GetPreviousNonBlankLine(clean_lines, linenum)[0]
+ if (not Search(r'[;:}{]\s*$', prevline) and
+ not Match(r'\s*#', prevline)):
+ error(filename, linenum, 'whitespace/braces', 4,
+ '{ should almost always be at the end of the previous line')
+
+ # An else clause should be on the same line as the preceding closing brace.
+ if Match(r'\s*else\s*', line):
+ prevline = GetPreviousNonBlankLine(clean_lines, linenum)[0]
+ if Match(r'\s*}\s*$', prevline):
+ error(filename, linenum, 'whitespace/newline', 4,
+ 'An else should appear on the same line as the preceding }')
+
+ # If braces come on one side of an else, they should be on both.
+ # However, we have to worry about "else if" that spans multiple lines!
+ if Search(r'}\s*else[^{]*$', line) or Match(r'[^}]*else\s*{', line):
+ if Search(r'}\s*else if([^{]*)$', line): # could be multi-line if
+ # find the ( after the if
+ pos = line.find('else if')
+ pos = line.find('(', pos)
+ if pos > 0:
+ (endline, _, endpos) = CloseExpression(clean_lines, linenum, pos)
+ if endline[endpos:].find('{') == -1: # must be brace after if
+ error(filename, linenum, 'readability/braces', 5,
+ 'If an else has a brace on one side, it should have it on both')
+ else: # common case: else not followed by a multi-line if
+ error(filename, linenum, 'readability/braces', 5,
+ 'If an else has a brace on one side, it should have it on both')
+
+ # Likewise, an else should never have the else clause on the same line
+ if Search(r'\belse [^\s{]', line) and not Search(r'\belse if\b', line):
+ error(filename, linenum, 'whitespace/newline', 4,
+ 'Else clause should never be on same line as else (use 2 lines)')
+
+ # In the same way, a do/while should never be on one line
+ if Match(r'\s*do [^\s{]', line):
+ error(filename, linenum, 'whitespace/newline', 4,
+ 'do/while clauses should not be on a single line')
+
+ # Braces shouldn't be followed by a ; unless they're defining a struct
+ # or initializing an array.
+ # We can't tell in general, but we can for some common cases.
+ prevlinenum = linenum
+ while True:
+ (prevline, prevlinenum) = GetPreviousNonBlankLine(clean_lines, prevlinenum)
+ if Match(r'\s+{.*}\s*;', line) and not prevline.count(';'):
+ line = prevline + line
+ else:
+ break
+ if (Search(r'{.*}\s*;', line) and
+ line.count('{') == line.count('}') and
+ not Search(r'struct|class|enum|\s*=\s*{', line)):
+ error(filename, linenum, 'readability/braces', 4,
+ "You don't need a ; after a }")
+
+
+def CheckEmptyLoopBody(filename, clean_lines, linenum, error):
+ """Loop for empty loop body with only a single semicolon.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ error: The function to call with any errors found.
+ """
+
+ # Search for loop keywords at the beginning of the line. Because only
+ # whitespaces are allowed before the keywords, this will also ignore most
+ # do-while-loops, since those lines should start with closing brace.
+ line = clean_lines.elided[linenum]
+ if Match(r'\s*(for|while)\s*\(', line):
+ # Find the end of the conditional expression
+ (end_line, end_linenum, end_pos) = CloseExpression(
+ clean_lines, linenum, line.find('('))
+
+ # Output warning if what follows the condition expression is a semicolon.
+ # No warning for all other cases, including whitespace or newline, since we
+ # have a separate check for semicolons preceded by whitespace.
+ if end_pos >= 0 and Match(r';', end_line[end_pos:]):
+ error(filename, end_linenum, 'whitespace/empty_loop_body', 5,
+ 'Empty loop bodies should use {} or continue')
+
+
+def ReplaceableCheck(operator, macro, line):
+ """Determine whether a basic CHECK can be replaced with a more specific one.
+
+ For example suggest using CHECK_EQ instead of CHECK(a == b) and
+ similarly for CHECK_GE, CHECK_GT, CHECK_LE, CHECK_LT, CHECK_NE.
+
+ Args:
+ operator: The C++ operator used in the CHECK.
+ macro: The CHECK or EXPECT macro being called.
+ line: The current source line.
+
+ Returns:
+ True if the CHECK can be replaced with a more specific one.
+ """
+
+ # This matches decimal and hex integers, strings, and chars (in that order).
+ match_constant = r'([-+]?(\d+|0[xX][0-9a-fA-F]+)[lLuU]{0,3}|".*"|\'.*\')'
+
+ # Expression to match two sides of the operator with something that
+ # looks like a literal, since CHECK(x == iterator) won't compile.
+ # This means we can't catch all the cases where a more specific
+ # CHECK is possible, but it's less annoying than dealing with
+ # extraneous warnings.
+ match_this = (r'\s*' + macro + r'\((\s*' +
+ match_constant + r'\s*' + operator + r'[^<>].*|'
+ r'.*[^<>]' + operator + r'\s*' + match_constant +
+ r'\s*\))')
+
+ # Don't complain about CHECK(x == NULL) or similar because
+ # CHECK_EQ(x, NULL) won't compile (requires a cast).
+ # Also, don't complain about more complex boolean expressions
+ # involving && or || such as CHECK(a == b || c == d).
+ return Match(match_this, line) and not Search(r'NULL|&&|\|\|', line)
+
+
+def CheckCheck(filename, clean_lines, linenum, error):
+ """Checks the use of CHECK and EXPECT macros.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ error: The function to call with any errors found.
+ """
+
+ # Decide the set of replacement macros that should be suggested
+ raw_lines = clean_lines.raw_lines
+ current_macro = ''
+ for macro in _CHECK_MACROS:
+ if raw_lines[linenum].find(macro) >= 0:
+ current_macro = macro
+ break
+ if not current_macro:
+ # Don't waste time here if line doesn't contain 'CHECK' or 'EXPECT'
+ return
+
+ line = clean_lines.elided[linenum] # get rid of comments and strings
+
+ # Encourage replacing plain CHECKs with CHECK_EQ/CHECK_NE/etc.
+ for operator in ['==', '!=', '>=', '>', '<=', '<']:
+ if ReplaceableCheck(operator, current_macro, line):
+ error(filename, linenum, 'readability/check', 2,
+ 'Consider using %s instead of %s(a %s b)' % (
+ _CHECK_REPLACEMENT[current_macro][operator],
+ current_macro, operator))
+ break
+
+
+def CheckAltTokens(filename, clean_lines, linenum, error):
+ """Check alternative keywords being used in boolean expressions.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ error: The function to call with any errors found.
+ """
+ line = clean_lines.elided[linenum]
+
+ # Avoid preprocessor lines
+ if Match(r'^\s*#', line):
+ return
+
+ # Last ditch effort to avoid multi-line comments. This will not help
+ # if the comment started before the current line or ended after the
+ # current line, but it catches most of the false positives. At least,
+ # it provides a way to workaround this warning for people who use
+ # multi-line comments in preprocessor macros.
+ #
+ # TODO(unknown): remove this once cpplint has better support for
+ # multi-line comments.
+ if line.find('/*') >= 0 or line.find('*/') >= 0:
+ return
+
+ for match in _ALT_TOKEN_REPLACEMENT_PATTERN.finditer(line):
+ error(filename, linenum, 'readability/alt_tokens', 2,
+ 'Use operator %s instead of %s' % (
+ _ALT_TOKEN_REPLACEMENT[match.group(1)], match.group(1)))
+
+
+def GetLineWidth(line):
+ """Determines the width of the line in column positions.
+
+ Args:
+ line: A string, which may be a Unicode string.
+
+ Returns:
+ The width of the line in column positions, accounting for Unicode
+ combining characters and wide characters.
+ """
+ if isinstance(line, unicode):
+ width = 0
+ for uc in unicodedata.normalize('NFC', line):
+ if unicodedata.east_asian_width(uc) in ('W', 'F'):
+ width += 2
+ elif not unicodedata.combining(uc):
+ width += 1
+ return width
+ else:
+ return len(line)
+
+
+def CheckStyle(filename, clean_lines, linenum, file_extension, nesting_state,
+ error):
+ """Checks rules from the 'C++ style rules' section of cppguide.html.
+
+ Most of these rules are hard to test (naming, comment style), but we
+ do what we can. In particular we check for 2-space indents, line lengths,
+ tab usage, spaces inside code, etc.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ file_extension: The extension (without the dot) of the filename.
+ nesting_state: A _NestingState instance which maintains information about
+ the current stack of nested blocks being parsed.
+ error: The function to call with any errors found.
+ """
+
+ raw_lines = clean_lines.raw_lines
+ line = raw_lines[linenum]
+
+ if line.find('\t') != -1:
+ error(filename, linenum, 'whitespace/tab', 1,
+ 'Tab found; better to use spaces')
+
+ # One or three blank spaces at the beginning of the line is weird; it's
+ # hard to reconcile that with 2-space indents.
+ # NOTE: here are the conditions rob pike used for his tests. Mine aren't
+ # as sophisticated, but it may be worth becoming so: RLENGTH==initial_spaces
+ # if(RLENGTH > 20) complain = 0;
+ # if(match($0, " +(error|private|public|protected):")) complain = 0;
+ # if(match(prev, "&& *$")) complain = 0;
+ # if(match(prev, "\\|\\| *$")) complain = 0;
+ # if(match(prev, "[\",=><] *$")) complain = 0;
+ # if(match($0, " <<")) complain = 0;
+ # if(match(prev, " +for \\(")) complain = 0;
+ # if(prevodd && match(prevprev, " +for \\(")) complain = 0;
+ initial_spaces = 0
+ cleansed_line = clean_lines.elided[linenum]
+ while initial_spaces < len(line) and line[initial_spaces] == ' ':
+ initial_spaces += 1
+ if line and line[-1].isspace():
+ error(filename, linenum, 'whitespace/end_of_line', 4,
+ 'Line ends in whitespace. Consider deleting these extra spaces.')
+ # There are certain situations we allow one space, notably for labels
+ elif ((initial_spaces == 1 or initial_spaces == 3) and
+ not Match(r'\s*\w+\s*:\s*$', cleansed_line)):
+ error(filename, linenum, 'whitespace/indent', 3,
+ 'Weird number of spaces at line-start. '
+ 'Are you using a 2-space indent?')
+ # Labels should always be indented at least one space.
+ elif not initial_spaces and line[:2] != '//' and Search(r'[^:]:\s*$',
+ line):
+ error(filename, linenum, 'whitespace/labels', 4,
+ 'Labels should always be indented at least one space. '
+ 'If this is a member-initializer list in a constructor or '
+ 'the base class list in a class definition, the colon should '
+ 'be on the following line.')
+
+
+ # Check if the line is a header guard.
+ is_header_guard = False
+ if file_extension == 'h':
+ cppvar = GetHeaderGuardCPPVariable(filename)
+ if (line.startswith('#ifndef %s' % cppvar) or
+ line.startswith('#define %s' % cppvar) or
+ line.startswith('#endif // %s' % cppvar)):
+ is_header_guard = True
+ # #include lines and header guards can be long, since there's no clean way to
+ # split them.
+ #
+ # URLs can be long too. It's possible to split these, but it makes them
+ # harder to cut&paste.
+ #
+ # The "$Id:...$" comment may also get very long without it being the
+ # developers fault.
+ if (not line.startswith('#include') and not is_header_guard and
+ not Match(r'^\s*//.*http(s?)://\S*$', line) and
+ not Match(r'^// \$Id:.*#[0-9]+ \$$', line)):
+ line_width = GetLineWidth(line)
+ if line_width > 100:
+ error(filename, linenum, 'whitespace/line_length', 4,
+ 'Lines should very rarely be longer than 100 characters')
+ elif line_width > 80:
+ error(filename, linenum, 'whitespace/line_length', 2,
+ 'Lines should be <= 80 characters long')
+
+ if (cleansed_line.count(';') > 1 and
+ # for loops are allowed two ;'s (and may run over two lines).
+ cleansed_line.find('for') == -1 and
+ (GetPreviousNonBlankLine(clean_lines, linenum)[0].find('for') == -1 or
+ GetPreviousNonBlankLine(clean_lines, linenum)[0].find(';') != -1) and
+ # It's ok to have many commands in a switch case that fits in 1 line
+ not ((cleansed_line.find('case ') != -1 or
+ cleansed_line.find('default:') != -1) and
+ cleansed_line.find('break;') != -1)):
+ error(filename, linenum, 'whitespace/newline', 0,
+ 'More than one command on the same line')
+
+ # Some more style checks
+ CheckBraces(filename, clean_lines, linenum, error)
+ CheckEmptyLoopBody(filename, clean_lines, linenum, error)
+ CheckAccess(filename, clean_lines, linenum, nesting_state, error)
+ CheckSpacing(filename, clean_lines, linenum, nesting_state, error)
+ CheckCheck(filename, clean_lines, linenum, error)
+ CheckAltTokens(filename, clean_lines, linenum, error)
+ classinfo = nesting_state.InnermostClass()
+ if classinfo:
+ CheckSectionSpacing(filename, clean_lines, classinfo, linenum, error)
+
+
+_RE_PATTERN_INCLUDE_NEW_STYLE = re.compile(r'#include +"[^/]+\.h"')
+_RE_PATTERN_INCLUDE = re.compile(r'^\s*#\s*include\s*([<"])([^>"]*)[>"].*$')
+# Matches the first component of a filename delimited by -s and _s. That is:
+# _RE_FIRST_COMPONENT.match('foo').group(0) == 'foo'
+# _RE_FIRST_COMPONENT.match('foo.cc').group(0) == 'foo'
+# _RE_FIRST_COMPONENT.match('foo-bar_baz.cc').group(0) == 'foo'
+# _RE_FIRST_COMPONENT.match('foo_bar-baz.cc').group(0) == 'foo'
+_RE_FIRST_COMPONENT = re.compile(r'^[^-_.]+')
+
+
+def _DropCommonSuffixes(filename):
+ """Drops common suffixes like _test.cc or -inl.h from filename.
+
+ For example:
+ >>> _DropCommonSuffixes('foo/foo-inl.h')
+ 'foo/foo'
+ >>> _DropCommonSuffixes('foo/bar/foo.cc')
+ 'foo/bar/foo'
+ >>> _DropCommonSuffixes('foo/foo_internal.h')
+ 'foo/foo'
+ >>> _DropCommonSuffixes('foo/foo_unusualinternal.h')
+ 'foo/foo_unusualinternal'
+
+ Args:
+ filename: The input filename.
+
+ Returns:
+ The filename with the common suffix removed.
+ """
+ for suffix in ('test.cc', 'regtest.cc', 'unittest.cc',
+ 'inl.h', 'impl.h', 'internal.h'):
+ if (filename.endswith(suffix) and len(filename) > len(suffix) and
+ filename[-len(suffix) - 1] in ('-', '_')):
+ return filename[:-len(suffix) - 1]
+ return os.path.splitext(filename)[0]
+
+
+def _IsTestFilename(filename):
+ """Determines if the given filename has a suffix that identifies it as a test.
+
+ Args:
+ filename: The input filename.
+
+ Returns:
+ True if 'filename' looks like a test, False otherwise.
+ """
+ if (filename.endswith('_test.cc') or
+ filename.endswith('_unittest.cc') or
+ filename.endswith('_regtest.cc')):
+ return True
+ else:
+ return False
+
+
+def _ClassifyInclude(fileinfo, include, is_system):
+ """Figures out what kind of header 'include' is.
+
+ Args:
+ fileinfo: The current file cpplint is running over. A FileInfo instance.
+ include: The path to a #included file.
+ is_system: True if the #include used <> rather than "".
+
+ Returns:
+ One of the _XXX_HEADER constants.
+
+ For example:
+ >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'stdio.h', True)
+ _C_SYS_HEADER
+ >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'string', True)
+ _CPP_SYS_HEADER
+ >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'foo/foo.h', False)
+ _LIKELY_MY_HEADER
+ >>> _ClassifyInclude(FileInfo('foo/foo_unknown_extension.cc'),
+ ... 'bar/foo_other_ext.h', False)
+ _POSSIBLE_MY_HEADER
+ >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'foo/bar.h', False)
+ _OTHER_HEADER
+ """
+ # This is a list of all standard c++ header files, except
+ # those already checked for above.
+ is_stl_h = include in _STL_HEADERS
+ is_cpp_h = is_stl_h or include in _CPP_HEADERS
+
+ if is_system:
+ if is_cpp_h:
+ return _CPP_SYS_HEADER
+ else:
+ return _C_SYS_HEADER
+
+ # If the target file and the include we're checking share a
+ # basename when we drop common extensions, and the include
+ # lives in . , then it's likely to be owned by the target file.
+ target_dir, target_base = (
+ os.path.split(_DropCommonSuffixes(fileinfo.RepositoryName())))
+ include_dir, include_base = os.path.split(_DropCommonSuffixes(include))
+ if target_base == include_base and (
+ include_dir == target_dir or
+ include_dir == os.path.normpath(target_dir + '/../public')):
+ return _LIKELY_MY_HEADER
+
+ # If the target and include share some initial basename
+ # component, it's possible the target is implementing the
+ # include, so it's allowed to be first, but we'll never
+ # complain if it's not there.
+ target_first_component = _RE_FIRST_COMPONENT.match(target_base)
+ include_first_component = _RE_FIRST_COMPONENT.match(include_base)
+ if (target_first_component and include_first_component and
+ target_first_component.group(0) ==
+ include_first_component.group(0)):
+ return _POSSIBLE_MY_HEADER
+
+ return _OTHER_HEADER
+
+
+
+def CheckIncludeLine(filename, clean_lines, linenum, include_state, error):
+ """Check rules that are applicable to #include lines.
+
+ Strings on #include lines are NOT removed from elided line, to make
+ certain tasks easier. However, to prevent false positives, checks
+ applicable to #include lines in CheckLanguage must be put here.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ include_state: An _IncludeState instance in which the headers are inserted.
+ error: The function to call with any errors found.
+ """
+ fileinfo = FileInfo(filename)
+
+ line = clean_lines.lines[linenum]
+
+ # "include" should use the new style "foo/bar.h" instead of just "bar.h"
+ if _RE_PATTERN_INCLUDE_NEW_STYLE.search(line):
+ error(filename, linenum, 'build/include', 4,
+ 'Include the directory when naming .h files')
+
+ # we shouldn't include a file more than once. actually, there are a
+ # handful of instances where doing so is okay, but in general it's
+ # not.
+ match = _RE_PATTERN_INCLUDE.search(line)
+ if match:
+ include = match.group(2)
+ is_system = (match.group(1) == '<')
+ if include in include_state:
+ error(filename, linenum, 'build/include', 4,
+ '"%s" already included at %s:%s' %
+ (include, filename, include_state[include]))
+ else:
+ include_state[include] = linenum
+
+ # We want to ensure that headers appear in the right order:
+ # 1) for foo.cc, foo.h (preferred location)
+ # 2) c system files
+ # 3) cpp system files
+ # 4) for foo.cc, foo.h (deprecated location)
+ # 5) other google headers
+ #
+ # We classify each include statement as one of those 5 types
+ # using a number of techniques. The include_state object keeps
+ # track of the highest type seen, and complains if we see a
+ # lower type after that.
+ error_message = include_state.CheckNextIncludeOrder(
+ _ClassifyInclude(fileinfo, include, is_system))
+ if error_message:
+ error(filename, linenum, 'build/include_order', 4,
+ '%s. Should be: %s.h, c system, c++ system, other.' %
+ (error_message, fileinfo.BaseName()))
+ if not include_state.IsInAlphabeticalOrder(include):
+ error(filename, linenum, 'build/include_alpha', 4,
+ 'Include "%s" not in alphabetical order' % include)
+
+ # Look for any of the stream classes that are part of standard C++.
+ match = _RE_PATTERN_INCLUDE.match(line)
+ if match:
+ include = match.group(2)
+ if Match(r'(f|ind|io|i|o|parse|pf|stdio|str|)?stream$', include):
+ # Many unit tests use cout, so we exempt them.
+ if not _IsTestFilename(filename):
+ error(filename, linenum, 'readability/streams', 3,
+ 'Streams are highly discouraged.')
+
+
+def _GetTextInside(text, start_pattern):
+ """Retrieves all the text between matching open and close parentheses.
+
+ Given a string of lines and a regular expression string, retrieve all the text
+ following the expression and between opening punctuation symbols like
+ (, [, or {, and the matching close-punctuation symbol. This properly nested
+ occurrences of the punctuations, so for the text like
+ printf(a(), b(c()));
+ a call to _GetTextInside(text, r'printf\(') will return 'a(), b(c())'.
+ start_pattern must match string having an open punctuation symbol at the end.
+
+ Args:
+ text: The lines to extract text. Its comments and strings must be elided.
+ It can be single line and can span multiple lines.
+ start_pattern: The regexp string indicating where to start extracting
+ the text.
+ Returns:
+ The extracted text.
+ None if either the opening string or ending punctuation could not be found.
+ """
+ # TODO(sugawarayu): Audit cpplint.py to see what places could be profitably
+ # rewritten to use _GetTextInside (and use inferior regexp matching today).
+
+ # Give opening punctuations to get the matching close-punctuations.
+ matching_punctuation = {'(': ')', '{': '}', '[': ']'}
+ closing_punctuation = set(matching_punctuation.itervalues())
+
+ # Find the position to start extracting text.
+ match = re.search(start_pattern, text, re.M)
+ if not match: # start_pattern not found in text.
+ return None
+ start_position = match.end(0)
+
+ assert start_position > 0, (
+ 'start_pattern must ends with an opening punctuation.')
+ assert text[start_position - 1] in matching_punctuation, (
+ 'start_pattern must ends with an opening punctuation.')
+ # Stack of closing punctuations we expect to have in text after position.
+ punctuation_stack = [matching_punctuation[text[start_position - 1]]]
+ position = start_position
+ while punctuation_stack and position < len(text):
+ if text[position] == punctuation_stack[-1]:
+ punctuation_stack.pop()
+ elif text[position] in closing_punctuation:
+ # A closing punctuation without matching opening punctuations.
+ return None
+ elif text[position] in matching_punctuation:
+ punctuation_stack.append(matching_punctuation[text[position]])
+ position += 1
+ if punctuation_stack:
+ # Opening punctuations left without matching close-punctuations.
+ return None
+ # punctuations match.
+ return text[start_position:position - 1]
+
+
+def CheckLanguage(filename, clean_lines, linenum, file_extension, include_state,
+ error):
+ """Checks rules from the 'C++ language rules' section of cppguide.html.
+
+ Some of these rules are hard to test (function overloading, using
+ uint32 inappropriately), but we do the best we can.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ file_extension: The extension (without the dot) of the filename.
+ include_state: An _IncludeState instance in which the headers are inserted.
+ error: The function to call with any errors found.
+ """
+ # If the line is empty or consists of entirely a comment, no need to
+ # check it.
+ line = clean_lines.elided[linenum]
+ if not line:
+ return
+
+ match = _RE_PATTERN_INCLUDE.search(line)
+ if match:
+ CheckIncludeLine(filename, clean_lines, linenum, include_state, error)
+ return
+
+ # Create an extended_line, which is the concatenation of the current and
+ # next lines, for more effective checking of code that may span more than one
+ # line.
+ if linenum + 1 < clean_lines.NumLines():
+ extended_line = line + clean_lines.elided[linenum + 1]
+ else:
+ extended_line = line
+
+ # Make Windows paths like Unix.
+ fullname = os.path.abspath(filename).replace('\\', '/')
+
+ # TODO(unknown): figure out if they're using default arguments in fn proto.
+
+ # Check for non-const references in functions. This is tricky because &
+ # is also used to take the address of something. We allow <> for templates,
+ # (ignoring whatever is between the braces) and : for classes.
+ # These are complicated re's. They try to capture the following:
+ # paren (for fn-prototype start), typename, &, varname. For the const
+ # version, we're willing for const to be before typename or after
+ # Don't check the implementation on same line.
+ fnline = line.split('{', 1)[0]
+ if (len(re.findall(r'\([^()]*\b(?:[\w:]|<[^()]*>)+(\s?&|&\s?)\w+', fnline)) >
+ len(re.findall(r'\([^()]*\bconst\s+(?:typename\s+)?(?:struct\s+)?'
+ r'(?:[\w:]|<[^()]*>)+(\s?&|&\s?)\w+', fnline)) +
+ len(re.findall(r'\([^()]*\b(?:[\w:]|<[^()]*>)+\s+const(\s?&|&\s?)[\w]+',
+ fnline))):
+
+ # We allow non-const references in a few standard places, like functions
+ # called "swap()" or iostream operators like "<<" or ">>". We also filter
+ # out for loops, which lint otherwise mistakenly thinks are functions.
+ if not Search(
+ r'(for|swap|Swap|operator[<>][<>])\s*\(\s*'
+ r'(?:(?:typename\s*)?[\w:]|<.*>)+\s*&',
+ fnline):
+ error(filename, linenum, 'runtime/references', 2,
+ 'Is this a non-const reference? '
+ 'If so, make const or use a pointer.')
+
+ # Check to see if they're using an conversion function cast.
+ # I just try to capture the most common basic types, though there are more.
+ # Parameterless conversion functions, such as bool(), are allowed as they are
+ # probably a member operator declaration or default constructor.
+ match = Search(
+ r'(\bnew\s+)?\b' # Grab 'new' operator, if it's there
+ r'(int|float|double|bool|char|int32|uint32|int64|uint64)\([^)]', line)
+ if match:
+ # gMock methods are defined using some variant of MOCK_METHODx(name, type)
+ # where type may be float(), int(string), etc. Without context they are
+ # virtually indistinguishable from int(x) casts. Likewise, gMock's
+ # MockCallback takes a template parameter of the form return_type(arg_type),
+ # which looks much like the cast we're trying to detect.
+ if (match.group(1) is None and # If new operator, then this isn't a cast
+ not (Match(r'^\s*MOCK_(CONST_)?METHOD\d+(_T)?\(', line) or
+ Match(r'^\s*MockCallback<.*>', line))):
+ # Try a bit harder to catch gmock lines: the only place where
+ # something looks like an old-style cast is where we declare the
+ # return type of the mocked method, and the only time when we
+ # are missing context is if MOCK_METHOD was split across
+ # multiple lines (for example http://go/hrfhr ), so we only need
+ # to check the previous line for MOCK_METHOD.
+ if (linenum == 0 or
+ not Match(r'^\s*MOCK_(CONST_)?METHOD\d+(_T)?\(\S+,\s*$',
+ clean_lines.elided[linenum - 1])):
+ error(filename, linenum, 'readability/casting', 4,
+ 'Using deprecated casting style. '
+ 'Use static_cast<%s>(...) instead' %
+ match.group(2))
+
+ CheckCStyleCast(filename, linenum, line, clean_lines.raw_lines[linenum],
+ 'static_cast',
+ r'\((int|float|double|bool|char|u?int(16|32|64))\)', error)
+
+ # This doesn't catch all cases. Consider (const char * const)"hello".
+ #
+ # (char *) "foo" should always be a const_cast (reinterpret_cast won't
+ # compile).
+ if CheckCStyleCast(filename, linenum, line, clean_lines.raw_lines[linenum],
+ 'const_cast', r'\((char\s?\*+\s?)\)\s*"', error):
+ pass
+ else:
+ # Check pointer casts for other than string constants
+ CheckCStyleCast(filename, linenum, line, clean_lines.raw_lines[linenum],
+ 'reinterpret_cast', r'\((\w+\s?\*+\s?)\)', error)
+
+ # In addition, we look for people taking the address of a cast. This
+ # is dangerous -- casts can assign to temporaries, so the pointer doesn't
+ # point where you think.
+ if Search(
+ r'(&\([^)]+\)[\w(])|(&(static|dynamic|reinterpret)_cast\b)', line):
+ error(filename, linenum, 'runtime/casting', 4,
+ ('Are you taking an address of a cast? '
+ 'This is dangerous: could be a temp var. '
+ 'Take the address before doing the cast, rather than after'))
+
+ # Check for people declaring static/global STL strings at the top level.
+ # This is dangerous because the C++ language does not guarantee that
+ # globals with constructors are initialized before the first access.
+ match = Match(
+ r'((?:|static +)(?:|const +))string +([a-zA-Z0-9_:]+)\b(.*)',
+ line)
+ # Make sure it's not a function.
+ # Function template specialization looks like: "string foo<Type>(...".
+ # Class template definitions look like: "string Foo<Type>::Method(...".
+ if match and not Match(r'\s*(<.*>)?(::[a-zA-Z0-9_]+)?\s*\(([^"]|$)',
+ match.group(3)):
+ error(filename, linenum, 'runtime/string', 4,
+ 'For a static/global string constant, use a C style string instead: '
+ '"%schar %s[]".' %
+ (match.group(1), match.group(2)))
+
+ # Check that we're not using RTTI outside of testing code.
+ if Search(r'\bdynamic_cast<', line) and not _IsTestFilename(filename):
+ error(filename, linenum, 'runtime/rtti', 5,
+ 'Do not use dynamic_cast<>. If you need to cast within a class '
+ "hierarchy, use static_cast<> to upcast. Google doesn't support "
+ 'RTTI.')
+
+ if Search(r'\b([A-Za-z0-9_]*_)\(\1\)', line):
+ error(filename, linenum, 'runtime/init', 4,
+ 'You seem to be initializing a member variable with itself.')
+
+ if file_extension == 'h':
+ # TODO(unknown): check that 1-arg constructors are explicit.
+ # How to tell it's a constructor?
+ # (handled in CheckForNonStandardConstructs for now)
+ # TODO(unknown): check that classes have DISALLOW_EVIL_CONSTRUCTORS
+ # (level 1 error)
+ pass
+
+ # Check if people are using the verboten C basic types. The only exception
+ # we regularly allow is "unsigned short port" for port.
+ if Search(r'\bshort port\b', line):
+ if not Search(r'\bunsigned short port\b', line):
+ error(filename, linenum, 'runtime/int', 4,
+ 'Use "unsigned short" for ports, not "short"')
+ else:
+ match = Search(r'\b(short|long(?! +double)|long long)\b', line)
+ if match:
+ error(filename, linenum, 'runtime/int', 4,
+ 'Use int16/int64/etc, rather than the C type %s' % match.group(1))
+
+ # When snprintf is used, the second argument shouldn't be a literal.
+ match = Search(r'snprintf\s*\(([^,]*),\s*([0-9]*)\s*,', line)
+ if match and match.group(2) != '0':
+ # If 2nd arg is zero, snprintf is used to calculate size.
+ error(filename, linenum, 'runtime/printf', 3,
+ 'If you can, use sizeof(%s) instead of %s as the 2nd arg '
+ 'to snprintf.' % (match.group(1), match.group(2)))
+
+ # Check if some verboten C functions are being used.
+ if Search(r'\bsprintf\b', line):
+ error(filename, linenum, 'runtime/printf', 5,
+ 'Never use sprintf. Use snprintf instead.')
+ match = Search(r'\b(strcpy|strcat)\b', line)
+ if match:
+ error(filename, linenum, 'runtime/printf', 4,
+ 'Almost always, snprintf is better than %s' % match.group(1))
+
+ if Search(r'\bsscanf\b', line):
+ error(filename, linenum, 'runtime/printf', 1,
+ 'sscanf can be ok, but is slow and can overflow buffers.')
+
+ # Check if some verboten operator overloading is going on
+ # TODO(unknown): catch out-of-line unary operator&:
+ # class X {};
+ # int operator&(const X& x) { return 42; } // unary operator&
+ # The trick is it's hard to tell apart from binary operator&:
+ # class Y { int operator&(const Y& x) { return 23; } }; // binary operator&
+ if Search(r'\boperator\s*&\s*\(\s*\)', line):
+ error(filename, linenum, 'runtime/operator', 4,
+ 'Unary operator& is dangerous. Do not use it.')
+
+ # Check for suspicious usage of "if" like
+ # } if (a == b) {
+ if Search(r'\}\s*if\s*\(', line):
+ error(filename, linenum, 'readability/braces', 4,
+ 'Did you mean "else if"? If not, start a new line for "if".')
+
+ # Check for potential format string bugs like printf(foo).
+ # We constrain the pattern not to pick things like DocidForPrintf(foo).
+ # Not perfect but it can catch printf(foo.c_str()) and printf(foo->c_str())
+ # TODO(sugawarayu): Catch the following case. Need to change the calling
+ # convention of the whole function to process multiple line to handle it.
+ # printf(
+ # boy_this_is_a_really_long_variable_that_cannot_fit_on_the_prev_line);
+ printf_args = _GetTextInside(line, r'(?i)\b(string)?printf\s*\(')
+ if printf_args:
+ match = Match(r'([\w.\->()]+)$', printf_args)
+ if match and match.group(1) != '__VA_ARGS__':
+ function_name = re.search(r'\b((?:string)?printf)\s*\(',
+ line, re.I).group(1)
+ error(filename, linenum, 'runtime/printf', 4,
+ 'Potential format string bug. Do %s("%%s", %s) instead.'
+ % (function_name, match.group(1)))
+
+ # Check for potential memset bugs like memset(buf, sizeof(buf), 0).
+ match = Search(r'memset\s*\(([^,]*),\s*([^,]*),\s*0\s*\)', line)
+ if match and not Match(r"^''|-?[0-9]+|0x[0-9A-Fa-f]$", match.group(2)):
+ error(filename, linenum, 'runtime/memset', 4,
+ 'Did you mean "memset(%s, 0, %s)"?'
+ % (match.group(1), match.group(2)))
+
+ if Search(r'\busing namespace\b', line):
+ error(filename, linenum, 'build/namespaces', 5,
+ 'Do not use namespace using-directives. '
+ 'Use using-declarations instead.')
+
+ # Detect variable-length arrays.
+ match = Match(r'\s*(.+::)?(\w+) [a-z]\w*\[(.+)];', line)
+ if (match and match.group(2) != 'return' and match.group(2) != 'delete' and
+ match.group(3).find(']') == -1):
+ # Split the size using space and arithmetic operators as delimiters.
+ # If any of the resulting tokens are not compile time constants then
+ # report the error.
+ tokens = re.split(r'\s|\+|\-|\*|\/|<<|>>]', match.group(3))
+ is_const = True
+ skip_next = False
+ for tok in tokens:
+ if skip_next:
+ skip_next = False
+ continue
+
+ if Search(r'sizeof\(.+\)', tok): continue
+ if Search(r'arraysize\(\w+\)', tok): continue
+
+ tok = tok.lstrip('(')
+ tok = tok.rstrip(')')
+ if not tok: continue
+ if Match(r'\d+', tok): continue
+ if Match(r'0[xX][0-9a-fA-F]+', tok): continue
+ if Match(r'k[A-Z0-9]\w*', tok): continue
+ if Match(r'(.+::)?k[A-Z0-9]\w*', tok): continue
+ if Match(r'(.+::)?[A-Z][A-Z0-9_]*', tok): continue
+ # A catch all for tricky sizeof cases, including 'sizeof expression',
+ # 'sizeof(*type)', 'sizeof(const type)', 'sizeof(struct StructName)'
+ # requires skipping the next token because we split on ' ' and '*'.
+ if tok.startswith('sizeof'):
+ skip_next = True
+ continue
+ is_const = False
+ break
+ if not is_const:
+ error(filename, linenum, 'runtime/arrays', 1,
+ 'Do not use variable-length arrays. Use an appropriately named '
+ "('k' followed by CamelCase) compile-time constant for the size.")
+
+ # If DISALLOW_EVIL_CONSTRUCTORS, DISALLOW_COPY_AND_ASSIGN, or
+ # DISALLOW_IMPLICIT_CONSTRUCTORS is present, then it should be the last thing
+ # in the class declaration.
+ match = Match(
+ (r'\s*'
+ r'(DISALLOW_(EVIL_CONSTRUCTORS|COPY_AND_ASSIGN|IMPLICIT_CONSTRUCTORS))'
+ r'\(.*\);$'),
+ line)
+ if match and linenum + 1 < clean_lines.NumLines():
+ next_line = clean_lines.elided[linenum + 1]
+ # We allow some, but not all, declarations of variables to be present
+ # in the statement that defines the class. The [\w\*,\s]* fragment of
+ # the regular expression below allows users to declare instances of
+ # the class or pointers to instances, but not less common types such
+ # as function pointers or arrays. It's a tradeoff between allowing
+ # reasonable code and avoiding trying to parse more C++ using regexps.
+ if not Search(r'^\s*}[\w\*,\s]*;', next_line):
+ error(filename, linenum, 'readability/constructors', 3,
+ match.group(1) + ' should be the last thing in the class')
+
+ # Check for use of unnamed namespaces in header files. Registration
+ # macros are typically OK, so we allow use of "namespace {" on lines
+ # that end with backslashes.
+ if (file_extension == 'h'
+ and Search(r'\bnamespace\s*{', line)
+ and line[-1] != '\\'):
+ error(filename, linenum, 'build/namespaces', 4,
+ 'Do not use unnamed namespaces in header files. See '
+ 'http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Namespaces'
+ ' for more information.')
+
+
+def CheckCStyleCast(filename, linenum, line, raw_line, cast_type, pattern,
+ error):
+ """Checks for a C-style cast by looking for the pattern.
+
+ This also handles sizeof(type) warnings, due to similarity of content.
+
+ Args:
+ filename: The name of the current file.
+ linenum: The number of the line to check.
+ line: The line of code to check.
+ raw_line: The raw line of code to check, with comments.
+ cast_type: The string for the C++ cast to recommend. This is either
+ reinterpret_cast, static_cast, or const_cast, depending.
+ pattern: The regular expression used to find C-style casts.
+ error: The function to call with any errors found.
+
+ Returns:
+ True if an error was emitted.
+ False otherwise.
+ """
+ match = Search(pattern, line)
+ if not match:
+ return False
+
+ # e.g., sizeof(int)
+ sizeof_match = Match(r'.*sizeof\s*$', line[0:match.start(1) - 1])
+ if sizeof_match:
+ error(filename, linenum, 'runtime/sizeof', 1,
+ 'Using sizeof(type). Use sizeof(varname) instead if possible')
+ return True
+
+ # operator++(int) and operator--(int)
+ if (line[0:match.start(1) - 1].endswith(' operator++') or
+ line[0:match.start(1) - 1].endswith(' operator--')):
+ return False
+
+ remainder = line[match.end(0):]
+
+ # The close paren is for function pointers as arguments to a function.
+ # eg, void foo(void (*bar)(int));
+ # The semicolon check is a more basic function check; also possibly a
+ # function pointer typedef.
+ # eg, void foo(int); or void foo(int) const;
+ # The equals check is for function pointer assignment.
+ # eg, void *(*foo)(int) = ...
+ # The > is for MockCallback<...> ...
+ #
+ # Right now, this will only catch cases where there's a single argument, and
+ # it's unnamed. It should probably be expanded to check for multiple
+ # arguments with some unnamed.
+ function_match = Match(r'\s*(\)|=|(const)?\s*(;|\{|throw\(\)|>))', remainder)
+ if function_match:
+ if (not function_match.group(3) or
+ function_match.group(3) == ';' or
+ ('MockCallback<' not in raw_line and
+ '/*' not in raw_line)):
+ error(filename, linenum, 'readability/function', 3,
+ 'All parameters should be named in a function')
+ return True
+
+ # At this point, all that should be left is actual casts.
+ error(filename, linenum, 'readability/casting', 4,
+ 'Using C-style cast. Use %s<%s>(...) instead' %
+ (cast_type, match.group(1)))
+
+ return True
+
+
+_HEADERS_CONTAINING_TEMPLATES = (
+ ('<deque>', ('deque',)),
+ ('<functional>', ('unary_function', 'binary_function',
+ 'plus', 'minus', 'multiplies', 'divides', 'modulus',
+ 'negate',
+ 'equal_to', 'not_equal_to', 'greater', 'less',
+ 'greater_equal', 'less_equal',
+ 'logical_and', 'logical_or', 'logical_not',
+ 'unary_negate', 'not1', 'binary_negate', 'not2',
+ 'bind1st', 'bind2nd',
+ 'pointer_to_unary_function',
+ 'pointer_to_binary_function',
+ 'ptr_fun',
+ 'mem_fun_t', 'mem_fun', 'mem_fun1_t', 'mem_fun1_ref_t',
+ 'mem_fun_ref_t',
+ 'const_mem_fun_t', 'const_mem_fun1_t',
+ 'const_mem_fun_ref_t', 'const_mem_fun1_ref_t',
+ 'mem_fun_ref',
+ )),
+ ('<limits>', ('numeric_limits',)),
+ ('<list>', ('list',)),
+ ('<map>', ('map', 'multimap',)),
+ ('<memory>', ('allocator',)),
+ ('<queue>', ('queue', 'priority_queue',)),
+ ('<set>', ('set', 'multiset',)),
+ ('<stack>', ('stack',)),
+ ('<string>', ('char_traits', 'basic_string',)),
+ ('<utility>', ('pair',)),
+ ('<vector>', ('vector',)),
+
+ # gcc extensions.
+ # Note: std::hash is their hash, ::hash is our hash
+ ('<hash_map>', ('hash_map', 'hash_multimap',)),
+ ('<hash_set>', ('hash_set', 'hash_multiset',)),
+ ('<slist>', ('slist',)),
+ )
+
+_RE_PATTERN_STRING = re.compile(r'\bstring\b')
+
+_re_pattern_algorithm_header = []
+for _template in ('copy', 'max', 'min', 'min_element', 'sort', 'swap',
+ 'transform'):
+ # Match max<type>(..., ...), max(..., ...), but not foo->max, foo.max or
+ # type::max().
+ _re_pattern_algorithm_header.append(
+ (re.compile(r'[^>.]\b' + _template + r'(<.*?>)?\([^\)]'),
+ _template,
+ '<algorithm>'))
+
+_re_pattern_templates = []
+for _header, _templates in _HEADERS_CONTAINING_TEMPLATES:
+ for _template in _templates:
+ _re_pattern_templates.append(
+ (re.compile(r'(\<|\b)' + _template + r'\s*\<'),
+ _template + '<>',
+ _header))
+
+
+def FilesBelongToSameModule(filename_cc, filename_h):
+ """Check if these two filenames belong to the same module.
+
+ The concept of a 'module' here is a as follows:
+ foo.h, foo-inl.h, foo.cc, foo_test.cc and foo_unittest.cc belong to the
+ same 'module' if they are in the same directory.
+ some/path/public/xyzzy and some/path/internal/xyzzy are also considered
+ to belong to the same module here.
+
+ If the filename_cc contains a longer path than the filename_h, for example,
+ '/absolute/path/to/base/sysinfo.cc', and this file would include
+ 'base/sysinfo.h', this function also produces the prefix needed to open the
+ header. This is used by the caller of this function to more robustly open the
+ header file. We don't have access to the real include paths in this context,
+ so we need this guesswork here.
+
+ Known bugs: tools/base/bar.cc and base/bar.h belong to the same module
+ according to this implementation. Because of this, this function gives
+ some false positives. This should be sufficiently rare in practice.
+
+ Args:
+ filename_cc: is the path for the .cc file
+ filename_h: is the path for the header path
+
+ Returns:
+ Tuple with a bool and a string:
+ bool: True if filename_cc and filename_h belong to the same module.
+ string: the additional prefix needed to open the header file.
+ """
+
+ if not filename_cc.endswith('.cc'):
+ return (False, '')
+ filename_cc = filename_cc[:-len('.cc')]
+ if filename_cc.endswith('_unittest'):
+ filename_cc = filename_cc[:-len('_unittest')]
+ elif filename_cc.endswith('_test'):
+ filename_cc = filename_cc[:-len('_test')]
+ filename_cc = filename_cc.replace('/public/', '/')
+ filename_cc = filename_cc.replace('/internal/', '/')
+
+ if not filename_h.endswith('.h'):
+ return (False, '')
+ filename_h = filename_h[:-len('.h')]
+ if filename_h.endswith('-inl'):
+ filename_h = filename_h[:-len('-inl')]
+ filename_h = filename_h.replace('/public/', '/')
+ filename_h = filename_h.replace('/internal/', '/')
+
+ files_belong_to_same_module = filename_cc.endswith(filename_h)
+ common_path = ''
+ if files_belong_to_same_module:
+ common_path = filename_cc[:-len(filename_h)]
+ return files_belong_to_same_module, common_path
+
+
+def UpdateIncludeState(filename, include_state, io=codecs):
+ """Fill up the include_state with new includes found from the file.
+
+ Args:
+ filename: the name of the header to read.
+ include_state: an _IncludeState instance in which the headers are inserted.
+ io: The io factory to use to read the file. Provided for testability.
+
+ Returns:
+ True if a header was succesfully added. False otherwise.
+ """
+ headerfile = None
+ try:
+ headerfile = io.open(filename, 'r', 'utf8', 'replace')
+ except IOError:
+ return False
+ linenum = 0
+ for line in headerfile:
+ linenum += 1
+ clean_line = CleanseComments(line)
+ match = _RE_PATTERN_INCLUDE.search(clean_line)
+ if match:
+ include = match.group(2)
+ # The value formatting is cute, but not really used right now.
+ # What matters here is that the key is in include_state.
+ include_state.setdefault(include, '%s:%d' % (filename, linenum))
+ return True
+
+
+def CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error,
+ io=codecs):
+ """Reports for missing stl includes.
+
+ This function will output warnings to make sure you are including the headers
+ necessary for the stl containers and functions that you use. We only give one
+ reason to include a header. For example, if you use both equal_to<> and
+ less<> in a .h file, only one (the latter in the file) of these will be
+ reported as a reason to include the <functional>.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ include_state: An _IncludeState instance.
+ error: The function to call with any errors found.
+ io: The IO factory to use to read the header file. Provided for unittest
+ injection.
+ """
+ required = {} # A map of header name to linenumber and the template entity.
+ # Example of required: { '<functional>': (1219, 'less<>') }
+
+ for linenum in xrange(clean_lines.NumLines()):
+ line = clean_lines.elided[linenum]
+ if not line or line[0] == '#':
+ continue
+
+ # String is special -- it is a non-templatized type in STL.
+ matched = _RE_PATTERN_STRING.search(line)
+ if matched:
+ # Don't warn about strings in non-STL namespaces:
+ # (We check only the first match per line; good enough.)
+ prefix = line[:matched.start()]
+ if prefix.endswith('std::') or not prefix.endswith('::'):
+ required['<string>'] = (linenum, 'string')
+
+ for pattern, template, header in _re_pattern_algorithm_header:
+ if pattern.search(line):
+ required[header] = (linenum, template)
+
+ # The following function is just a speed up, no semantics are changed.
+ if not '<' in line: # Reduces the cpu time usage by skipping lines.
+ continue
+
+ for pattern, template, header in _re_pattern_templates:
+ if pattern.search(line):
+ required[header] = (linenum, template)
+
+ # The policy is that if you #include something in foo.h you don't need to
+ # include it again in foo.cc. Here, we will look at possible includes.
+ # Let's copy the include_state so it is only messed up within this function.
+ include_state = include_state.copy()
+
+ # Did we find the header for this file (if any) and succesfully load it?
+ header_found = False
+
+ # Use the absolute path so that matching works properly.
+ abs_filename = FileInfo(filename).FullName()
+
+ # For Emacs's flymake.
+ # If cpplint is invoked from Emacs's flymake, a temporary file is generated
+ # by flymake and that file name might end with '_flymake.cc'. In that case,
+ # restore original file name here so that the corresponding header file can be
+ # found.
+ # e.g. If the file name is 'foo_flymake.cc', we should search for 'foo.h'
+ # instead of 'foo_flymake.h'
+ abs_filename = re.sub(r'_flymake\.cc$', '.cc', abs_filename)
+
+ # include_state is modified during iteration, so we iterate over a copy of
+ # the keys.
+ header_keys = include_state.keys()
+ for header in header_keys:
+ (same_module, common_path) = FilesBelongToSameModule(abs_filename, header)
+ fullpath = common_path + header
+ if same_module and UpdateIncludeState(fullpath, include_state, io):
+ header_found = True
+
+ # If we can't find the header file for a .cc, assume it's because we don't
+ # know where to look. In that case we'll give up as we're not sure they
+ # didn't include it in the .h file.
+ # TODO(unknown): Do a better job of finding .h files so we are confident that
+ # not having the .h file means there isn't one.
+ if filename.endswith('.cc') and not header_found:
+ return
+
+ # All the lines have been processed, report the errors found.
+ for required_header_unstripped in required:
+ template = required[required_header_unstripped][1]
+ if required_header_unstripped.strip('<>"') not in include_state:
+ error(filename, required[required_header_unstripped][0],
+ 'build/include_what_you_use', 4,
+ 'Add #include ' + required_header_unstripped + ' for ' + template)
+
+
+_RE_PATTERN_EXPLICIT_MAKEPAIR = re.compile(r'\bmake_pair\s*<')
+
+
+def CheckMakePairUsesDeduction(filename, clean_lines, linenum, error):
+ """Check that make_pair's template arguments are deduced.
+
+ G++ 4.6 in C++0x mode fails badly if make_pair's template arguments are
+ specified explicitly, and such use isn't intended in any case.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ error: The function to call with any errors found.
+ """
+ raw = clean_lines.raw_lines
+ line = raw[linenum]
+ match = _RE_PATTERN_EXPLICIT_MAKEPAIR.search(line)
+ if match:
+ error(filename, linenum, 'build/explicit_make_pair',
+ 4, # 4 = high confidence
+ 'For C++11-compatibility, omit template arguments from make_pair'
+ ' OR use pair directly OR if appropriate, construct a pair directly')
+
+
+def ProcessLine(filename, file_extension, clean_lines, line,
+ include_state, function_state, nesting_state, error,
+ extra_check_functions=[]):
+ """Processes a single line in the file.
+
+ Args:
+ filename: Filename of the file that is being processed.
+ file_extension: The extension (dot not included) of the file.
+ clean_lines: An array of strings, each representing a line of the file,
+ with comments stripped.
+ line: Number of line being processed.
+ include_state: An _IncludeState instance in which the headers are inserted.
+ function_state: A _FunctionState instance which counts function lines, etc.
+ nesting_state: A _NestingState instance which maintains information about
+ the current stack of nested blocks being parsed.
+ error: A callable to which errors are reported, which takes 4 arguments:
+ filename, line number, error level, and message
+ extra_check_functions: An array of additional check functions that will be
+ run on each source line. Each function takes 4
+ arguments: filename, clean_lines, line, error
+ """
+ raw_lines = clean_lines.raw_lines
+ ParseNolintSuppressions(filename, raw_lines[line], line, error)
+ nesting_state.Update(filename, clean_lines, line, error)
+ if nesting_state.stack and nesting_state.stack[-1].inline_asm != _NO_ASM:
+ return
+ CheckForFunctionLengths(filename, clean_lines, line, function_state, error)
+ CheckForMultilineCommentsAndStrings(filename, clean_lines, line, error)
+ CheckStyle(filename, clean_lines, line, file_extension, nesting_state, error)
+ CheckLanguage(filename, clean_lines, line, file_extension, include_state,
+ error)
+ CheckForNonStandardConstructs(filename, clean_lines, line,
+ nesting_state, error)
+ CheckPosixThreading(filename, clean_lines, line, error)
+ CheckInvalidIncrement(filename, clean_lines, line, error)
+ CheckMakePairUsesDeduction(filename, clean_lines, line, error)
+ for check_fn in extra_check_functions:
+ check_fn(filename, clean_lines, line, error)
+
+def ProcessFileData(filename, file_extension, lines, error,
+ extra_check_functions=[]):
+ """Performs lint checks and reports any errors to the given error function.
+
+ Args:
+ filename: Filename of the file that is being processed.
+ file_extension: The extension (dot not included) of the file.
+ lines: An array of strings, each representing a line of the file, with the
+ last element being empty if the file is terminated with a newline.
+ error: A callable to which errors are reported, which takes 4 arguments:
+ filename, line number, error level, and message
+ extra_check_functions: An array of additional check functions that will be
+ run on each source line. Each function takes 4
+ arguments: filename, clean_lines, line, error
+ """
+ lines = (['// marker so line numbers and indices both start at 1'] + lines +
+ ['// marker so line numbers end in a known way'])
+
+ include_state = _IncludeState()
+ function_state = _FunctionState()
+ nesting_state = _NestingState()
+
+ ResetNolintSuppressions()
+
+ CheckForCopyright(filename, lines, error)
+
+ if file_extension == 'h':
+ CheckForHeaderGuard(filename, lines, error)
+
+ RemoveMultiLineComments(filename, lines, error)
+ clean_lines = CleansedLines(lines)
+ for line in xrange(clean_lines.NumLines()):
+ ProcessLine(filename, file_extension, clean_lines, line,
+ include_state, function_state, nesting_state, error,
+ extra_check_functions)
+ nesting_state.CheckClassFinished(filename, error)
+
+ CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error)
+
+ # We check here rather than inside ProcessLine so that we see raw
+ # lines rather than "cleaned" lines.
+ CheckForUnicodeReplacementCharacters(filename, lines, error)
+
+ CheckForNewlineAtEOF(filename, lines, error)
+
+def ProcessFile(filename, vlevel, extra_check_functions=[]):
+ """Does google-lint on a single file.
+
+ Args:
+ filename: The name of the file to parse.
+
+ vlevel: The level of errors to report. Every error of confidence
+ >= verbose_level will be reported. 0 is a good default.
+
+ extra_check_functions: An array of additional check functions that will be
+ run on each source line. Each function takes 4
+ arguments: filename, clean_lines, line, error
+ """
+
+ _SetVerboseLevel(vlevel)
+
+ try:
+ # Support the UNIX convention of using "-" for stdin. Note that
+ # we are not opening the file with universal newline support
+ # (which codecs doesn't support anyway), so the resulting lines do
+ # contain trailing '\r' characters if we are reading a file that
+ # has CRLF endings.
+ # If after the split a trailing '\r' is present, it is removed
+ # below. If it is not expected to be present (i.e. os.linesep !=
+ # '\r\n' as in Windows), a warning is issued below if this file
+ # is processed.
+
+ if filename == '-':
+ lines = codecs.StreamReaderWriter(sys.stdin,
+ codecs.getreader('utf8'),
+ codecs.getwriter('utf8'),
+ 'replace').read().split('\n')
+ else:
+ lines = codecs.open(filename, 'r', 'utf8', 'replace').read().split('\n')
+
+ carriage_return_found = False
+ # Remove trailing '\r'.
+ for linenum in range(len(lines)):
+ if lines[linenum].endswith('\r'):
+ lines[linenum] = lines[linenum].rstrip('\r')
+ carriage_return_found = True
+
+ except IOError:
+ sys.stderr.write(
+ "Skipping input '%s': Can't open for reading\n" % filename)
+ return
+
+ # Note, if no dot is found, this will give the entire filename as the ext.
+ file_extension = filename[filename.rfind('.') + 1:]
+
+ # When reading from stdin, the extension is unknown, so no cpplint tests
+ # should rely on the extension.
+ if (filename != '-' and file_extension != 'cc' and file_extension != 'h'
+ and file_extension != 'cpp'):
+ sys.stderr.write('Ignoring %s; not a .cc or .h file\n' % filename)
+ else:
+ ProcessFileData(filename, file_extension, lines, Error,
+ extra_check_functions)
+ if carriage_return_found and os.linesep != '\r\n':
+ # Use 0 for linenum since outputting only one error for potentially
+ # several lines.
+ Error(filename, 0, 'whitespace/newline', 1,
+ 'One or more unexpected \\r (^M) found;'
+ 'better to use only a \\n')
+
+ sys.stderr.write('Done processing %s\n' % filename)
+
+
+def PrintUsage(message):
+ """Prints a brief usage string and exits, optionally with an error message.
+
+ Args:
+ message: The optional error message.
+ """
+ sys.stderr.write(_USAGE)
+ if message:
+ sys.exit('\nFATAL ERROR: ' + message)
+ else:
+ sys.exit(1)
+
+
+def PrintCategories():
+ """Prints a list of all the error-categories used by error messages.
+
+ These are the categories used to filter messages via --filter.
+ """
+ sys.stderr.write(''.join(' %s\n' % cat for cat in _ERROR_CATEGORIES))
+ sys.exit(0)
+
+
+def ParseArguments(args):
+ """Parses the command line arguments.
+
+ This may set the output format and verbosity level as side-effects.
+
+ Args:
+ args: The command line arguments:
+
+ Returns:
+ The list of filenames to lint.
+ """
+ try:
+ (opts, filenames) = getopt.getopt(args, '', ['help', 'output=', 'verbose=',
+ 'counting=',
+ 'filter=',
+ 'root='])
+ except getopt.GetoptError:
+ PrintUsage('Invalid arguments.')
+
+ verbosity = _VerboseLevel()
+ output_format = _OutputFormat()
+ filters = ''
+ counting_style = ''
+
+ for (opt, val) in opts:
+ if opt == '--help':
+ PrintUsage(None)
+ elif opt == '--output':
+ if not val in ('emacs', 'vs7', 'eclipse'):
+ PrintUsage('The only allowed output formats are emacs, vs7 and eclipse.')
+ output_format = val
+ elif opt == '--verbose':
+ verbosity = int(val)
+ elif opt == '--filter':
+ filters = val
+ if not filters:
+ PrintCategories()
+ elif opt == '--counting':
+ if val not in ('total', 'toplevel', 'detailed'):
+ PrintUsage('Valid counting options are total, toplevel, and detailed')
+ counting_style = val
+ elif opt == '--root':
+ global _root
+ _root = val
+
+ if not filenames:
+ PrintUsage('No files were specified.')
+
+ _SetOutputFormat(output_format)
+ _SetVerboseLevel(verbosity)
+ _SetFilters(filters)
+ _SetCountingStyle(counting_style)
+
+ return filenames
+
+
+def main():
+ filenames = ParseArguments(sys.argv[1:])
+
+ # Change stderr to write with replacement characters so we don't die
+ # if we try to print something containing non-ASCII characters.
+ sys.stderr = codecs.StreamReaderWriter(sys.stderr,
+ codecs.getreader('utf8'),
+ codecs.getwriter('utf8'),
+ 'replace')
+
+ _cpplint_state.ResetErrorCounts()
+ for filename in filenames:
+ ProcessFile(filename, _cpplint_state.verbose_level)
+ _cpplint_state.PrintErrorCounts()
+
+ sys.exit(_cpplint_state.error_count > 0)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/lib/sanitizer_common/scripts/gen_dynamic_list.py b/lib/sanitizer_common/scripts/gen_dynamic_list.py
new file mode 100755
index 000000000000..32ba9226911e
--- /dev/null
+++ b/lib/sanitizer_common/scripts/gen_dynamic_list.py
@@ -0,0 +1,85 @@
+#!/usr/bin/env python
+#===- lib/sanitizer_common/scripts/gen_dynamic_list.py ---------------------===#
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+#
+# Generates the list of functions that should be exported from sanitizer
+# runtimes. The output format is recognized by --dynamic-list linker option.
+# Usage:
+# gen_dynamic_list.py libclang_rt.*san*.a [ files ... ]
+#
+#===------------------------------------------------------------------------===#
+import os
+import re
+import subprocess
+import sys
+
+new_delete = set(['_ZdaPv', '_ZdaPvRKSt9nothrow_t',
+ '_ZdlPv', '_ZdlPvRKSt9nothrow_t',
+ '_Znam', '_ZnamRKSt9nothrow_t',
+ '_Znwm', '_ZnwmRKSt9nothrow_t'])
+
+versioned_functions = set(['memcpy', 'pthread_attr_getaffinity_np',
+ 'pthread_cond_broadcast',
+ 'pthread_cond_destroy', 'pthread_cond_init',
+ 'pthread_cond_signal', 'pthread_cond_timedwait',
+ 'pthread_cond_wait', 'realpath',
+ 'sched_getaffinity'])
+
+def get_global_functions(library):
+ functions = []
+ nm_proc = subprocess.Popen(['nm', library], stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ nm_out = nm_proc.communicate()[0].split('\n')
+ if nm_proc.returncode != 0:
+ raise subprocess.CalledProcessError(nm_proc.returncode, 'nm')
+ for line in nm_out:
+ cols = line.split(' ')
+ if (len(cols) == 3 and cols[1] in ('T', 'W')) :
+ functions.append(cols[2])
+ return functions
+
+def main(argv):
+ result = []
+
+ library = argv[1]
+ all_functions = get_global_functions(library)
+ function_set = set(all_functions)
+ for func in all_functions:
+ # Export new/delete operators.
+ if func in new_delete:
+ result.append(func)
+ continue
+ # Export interceptors.
+ match = re.match('__interceptor_(.*)', func)
+ if match:
+ result.append(func)
+ # We have to avoid exporting the interceptors for versioned library
+ # functions due to gold internal error.
+ orig_name = match.group(1)
+ if orig_name in function_set and orig_name not in versioned_functions:
+ result.append(orig_name)
+ continue
+ # Export sanitizer interface functions.
+ if re.match('__sanitizer_(.*)', func):
+ result.append(func)
+
+ # Additional exported functions from files.
+ for fname in argv[2:]:
+ f = open(fname, 'r')
+ for line in f:
+ result.append(line.rstrip())
+ # Print the resulting list in the format recognized by ld.
+ print '{'
+ result.sort()
+ for f in result:
+ print ' ' + f + ';'
+ print '};'
+
+if __name__ == '__main__':
+ main(sys.argv)
diff --git a/lib/sanitizer_common/scripts/sancov.py b/lib/sanitizer_common/scripts/sancov.py
new file mode 100755
index 000000000000..aa791bc4eb01
--- /dev/null
+++ b/lib/sanitizer_common/scripts/sancov.py
@@ -0,0 +1,56 @@
+#!/usr/bin/env python
+# Merge or print the coverage data collected by asan's coverage.
+# Input files are sequences of 4-byte integers.
+# We need to merge these integers into a set and then
+# either print them (as hex) or dump them into another file.
+import array
+import sys
+
+prog_name = "";
+
+def Usage():
+ print >> sys.stderr, "Usage: \n" + \
+ " " + prog_name + " merge file1 [file2 ...] > output\n" \
+ " " + prog_name + " print 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()
+ print >>sys.stderr, "%s: read %d PCs from %s" % (prog_name, size / 4, path)
+ return s
+
+def Merge(files):
+ s = set()
+ for f in files:
+ s = s.union(ReadOneFile(f))
+ print >> sys.stderr, "%s: %d files merged; %d PCs total" % \
+ (prog_name, len(files), len(s))
+ return sorted(s)
+
+def PrintFiles(files):
+ s = Merge(files)
+ for i in s:
+ print "0x%x" % i
+
+def MergeAndPrint(files):
+ if sys.stdout.isatty():
+ Usage()
+ s = Merge(files)
+ a = array.array('I', s)
+ a.tofile(sys.stdout)
+
+if __name__ == '__main__':
+ prog_name = sys.argv[0]
+ if len(sys.argv) <= 2:
+ Usage();
+ if sys.argv[1] == "print":
+ PrintFiles(sys.argv[2:])
+ elif sys.argv[1] == "merge":
+ MergeAndPrint(sys.argv[2:])
+ else:
+ Usage()
diff --git a/lib/sanitizer_common/tests/CMakeLists.txt b/lib/sanitizer_common/tests/CMakeLists.txt
index 25e57507ad14..5b66917b05b0 100644
--- a/lib/sanitizer_common/tests/CMakeLists.txt
+++ b/lib/sanitizer_common/tests/CMakeLists.txt
@@ -5,20 +5,24 @@ set(SANITIZER_UNITTESTS
sanitizer_atomic_test.cc
sanitizer_common_test.cc
sanitizer_flags_test.cc
+ sanitizer_ioctl_test.cc
sanitizer_libc_test.cc
sanitizer_linux_test.cc
sanitizer_list_test.cc
sanitizer_mutex_test.cc
+ sanitizer_nolibc_test.cc
+ sanitizer_posix_test.cc
sanitizer_printf_test.cc
sanitizer_scanf_interceptor_test.cc
sanitizer_stackdepot_test.cc
sanitizer_stacktrace_test.cc
sanitizer_stoptheworld_test.cc
+ sanitizer_suppressions_test.cc
sanitizer_test_main.cc
- sanitizer_thread_registry_test.cc
- )
+ sanitizer_thread_registry_test.cc)
-set(SANITIZER_TEST_HEADERS)
+set(SANITIZER_TEST_HEADERS
+ sanitizer_test_utils.h)
foreach(header ${SANITIZER_HEADERS})
list(APPEND SANITIZER_TEST_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/../${header})
endforeach()
@@ -86,6 +90,24 @@ macro(add_sanitizer_tests_for_arch arch)
DEPS ${SANITIZER_TEST_OBJECTS} ${SANITIZER_COMMON_LIB}
LINK_FLAGS ${SANITIZER_TEST_LINK_FLAGS_COMMON}
-lpthread ${TARGET_FLAGS})
+
+ if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux" AND "${arch}" STREQUAL "x86_64")
+ # Test that the libc-independent part of sanitizer_common is indeed
+ # independent of libc, by linking this binary without libc (here) and
+ # executing it (unit test in sanitizer_nolibc_test.cc).
+ 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})
+ add_compiler_rt_test(SanitizerUnitTests "Sanitizer-${arch}-Test-Nolibc"
+ OBJECTS sanitizer_nolibc_test_main.${arch}.o
+ -Wl,-whole-archive
+ libRTSanitizerCommon.test.nolibc.${arch}.a
+ -Wl,-no-whole-archive
+ DEPS sanitizer_nolibc_test_main.${arch}.o
+ RTSanitizerCommon.test.nolibc.${arch}
+ LINK_FLAGS -nostdlib ${TARGET_FLAGS})
+ endif()
endmacro()
if(COMPILER_RT_CAN_EXECUTE_TESTS)
@@ -99,6 +121,8 @@ if(COMPILER_RT_CAN_EXECUTE_TESTS)
add_sanitizer_common_lib("RTSanitizerCommon.test.x86_64"
$<TARGET_OBJECTS:RTSanitizerCommon.x86_64>
$<TARGET_OBJECTS:RTSanitizerCommonLibc.x86_64>)
+ add_sanitizer_common_lib("RTSanitizerCommon.test.nolibc.x86_64"
+ $<TARGET_OBJECTS:RTSanitizerCommon.x86_64>)
endif()
if(CAN_TARGET_i386)
add_sanitizer_common_lib("RTSanitizerCommon.test.i386"
diff --git a/lib/sanitizer_common/tests/lit.cfg b/lib/sanitizer_common/tests/lit.cfg
deleted file mode 100644
index 303d56c91079..000000000000
--- a/lib/sanitizer_common/tests/lit.cfg
+++ /dev/null
@@ -1,28 +0,0 @@
-# -*- Python -*-
-
-import os
-
-def get_required_attr(config, attr_name):
- attr_value = getattr(config, attr_name, None)
- if not attr_value:
- lit.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 attributes common for all compiler-rt projects.
-compiler_rt_src_root = get_required_attr(config, 'compiler_rt_src_root')
-compiler_rt_lit_unit_cfg = os.path.join(compiler_rt_src_root, "lib",
- "lit.common.unit.cfg")
-lit.load_config(config, compiler_rt_lit_unit_cfg)
-
-# 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 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",
- "sanitizer_common", "tests")
-config.test_source_root = config.test_exec_root
diff --git a/lib/sanitizer_common/tests/lit.site.cfg.in b/lib/sanitizer_common/tests/lit.site.cfg.in
index 50485aa16ec2..5ceb9e4c5c28 100644
--- a/lib/sanitizer_common/tests/lit.site.cfg.in
+++ b/lib/sanitizer_common/tests/lit.site.cfg.in
@@ -1,16 +1,14 @@
## Autogenerated by LLVM/Clang configuration.
# Do not edit!
-config.llvm_obj_root = "@LLVM_BINARY_DIR@"
-config.llvm_src_root = "@LLVM_SOURCE_DIR@"
-config.compiler_rt_src_root = "@COMPILER_RT_SOURCE_DIR@"
-config.llvm_build_mode = "@LLVM_BUILD_MODE@"
+# Load common config for all compiler-rt unit tests.
+lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/lib/lit.common.unit.configured")
-try:
- config.llvm_build_mode = config.llvm_build_mode % lit.params
-except KeyError,e:
- key, = e.args
- lit.fatal("unable to find %r parameter, use '--param=%s=VALUE'" % (key, key))
+# Setup config name.
+config.name = 'SanitizerCommon-Unit'
-# Let the main config do the real work.
-lit.load_config(config, "@CMAKE_CURRENT_SOURCE_DIR@/lit.cfg")
+# 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 de949ca7defe..d92a07fe4c2d 100644
--- a/lib/sanitizer_common/tests/sanitizer_allocator_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_allocator_test.cc
@@ -12,7 +12,9 @@
//
//===----------------------------------------------------------------------===//
#include "sanitizer_common/sanitizer_allocator.h"
+#include "sanitizer_common/sanitizer_allocator_internal.h"
#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_flags.h"
#include "sanitizer_test_utils.h"
@@ -67,6 +69,10 @@ TEST(SanitizerCommon, CompactSizeClassMap) {
TestSizeClassMap<CompactSizeClassMap>();
}
+TEST(SanitizerCommon, InternalSizeClassMap) {
+ TestSizeClassMap<InternalSizeClassMap>();
+}
+
template <class Allocator>
void TestSizeClassAllocator() {
Allocator *a = new Allocator;
@@ -411,12 +417,20 @@ void TestCombinedAllocator() {
memset(&cache, 0, sizeof(cache));
a->InitCache(&cache);
+ bool allocator_may_return_null = common_flags()->allocator_may_return_null;
+ common_flags()->allocator_may_return_null = true;
EXPECT_EQ(a->Allocate(&cache, -1, 1), (void*)0);
EXPECT_EQ(a->Allocate(&cache, -1, 1024), (void*)0);
EXPECT_EQ(a->Allocate(&cache, (uptr)-1 - 1024, 1), (void*)0);
EXPECT_EQ(a->Allocate(&cache, (uptr)-1 - 1024, 1024), (void*)0);
EXPECT_EQ(a->Allocate(&cache, (uptr)-1 - 1023, 1024), (void*)0);
+ common_flags()->allocator_may_return_null = false;
+ EXPECT_DEATH(a->Allocate(&cache, -1, 1),
+ "allocator is terminating the process");
+ // Restore the original value.
+ common_flags()->allocator_may_return_null = allocator_may_return_null;
+
const uptr kNumAllocs = 100000;
const uptr kNumIter = 10;
for (uptr iter = 0; iter < kNumIter; iter++) {
@@ -611,6 +625,11 @@ TEST(Allocator, Stress) {
}
}
+TEST(Allocator, InternalAllocFailure) {
+ EXPECT_DEATH(Ident(InternalAlloc(10 << 20)),
+ "Unexpected mmap in InternalAllocator!");
+}
+
TEST(Allocator, ScopedBuffer) {
const int kSize = 512;
{
@@ -625,16 +644,9 @@ TEST(Allocator, ScopedBuffer) {
}
}
-class IterationTestCallback {
- public:
- explicit IterationTestCallback(std::set<void *> *chunks)
- : chunks_(chunks) {}
- void operator()(void *chunk) const {
- chunks_->insert(chunk);
- }
- private:
- std::set<void *> *chunks_;
-};
+void IterationTestCallback(uptr chunk, void *arg) {
+ reinterpret_cast<std::set<uptr> *>(arg)->insert(chunk);
+}
template <class Allocator>
void TestSizeClassAllocatorIteration() {
@@ -663,15 +675,15 @@ void TestSizeClassAllocatorIteration() {
}
}
- std::set<void *> reported_chunks;
- IterationTestCallback callback(&reported_chunks);
+ std::set<uptr> reported_chunks;
a->ForceLock();
- a->ForEachChunk(callback);
+ a->ForEachChunk(IterationTestCallback, &reported_chunks);
a->ForceUnlock();
for (uptr i = 0; i < allocated.size(); i++) {
// Don't use EXPECT_NE. Reporting the first mismatch is enough.
- ASSERT_NE(reported_chunks.find(allocated[i]), reported_chunks.end());
+ ASSERT_NE(reported_chunks.find(reinterpret_cast<uptr>(allocated[i])),
+ reported_chunks.end());
}
a->TestOnlyUnmap();
@@ -698,22 +710,61 @@ TEST(SanitizerCommon, LargeMmapAllocatorIteration) {
char *allocated[kNumAllocs];
static const uptr size = 40;
// Allocate some.
- for (uptr i = 0; i < kNumAllocs; i++) {
+ for (uptr i = 0; i < kNumAllocs; i++)
allocated[i] = (char *)a.Allocate(&stats, size, 1);
- }
- std::set<void *> reported_chunks;
- IterationTestCallback callback(&reported_chunks);
+ std::set<uptr> reported_chunks;
a.ForceLock();
- a.ForEachChunk(callback);
+ a.ForEachChunk(IterationTestCallback, &reported_chunks);
a.ForceUnlock();
for (uptr i = 0; i < kNumAllocs; i++) {
// Don't use EXPECT_NE. Reporting the first mismatch is enough.
- ASSERT_NE(reported_chunks.find(allocated[i]), reported_chunks.end());
+ ASSERT_NE(reported_chunks.find(reinterpret_cast<uptr>(allocated[i])),
+ reported_chunks.end());
+ }
+ for (uptr i = 0; i < kNumAllocs; i++)
+ a.Deallocate(&stats, allocated[i]);
+}
+
+TEST(SanitizerCommon, LargeMmapAllocatorBlockBegin) {
+ LargeMmapAllocator<> a;
+ a.Init();
+ AllocatorStats stats;
+ stats.Init();
+
+ static const uptr kNumAllocs = 1024;
+ static const uptr kNumExpectedFalseLookups = 10000000;
+ char *allocated[kNumAllocs];
+ static const uptr size = 4096;
+ // Allocate some.
+ for (uptr i = 0; i < kNumAllocs; i++) {
+ allocated[i] = (char *)a.Allocate(&stats, size, 1);
}
+
+ a.ForceLock();
+ for (uptr i = 0; i < kNumAllocs * kNumAllocs; i++) {
+ // if ((i & (i - 1)) == 0) fprintf(stderr, "[%zd]\n", i);
+ char *p1 = allocated[i % kNumAllocs];
+ EXPECT_EQ(p1, a.GetBlockBeginFastLocked(p1));
+ EXPECT_EQ(p1, a.GetBlockBeginFastLocked(p1 + size / 2));
+ EXPECT_EQ(p1, a.GetBlockBeginFastLocked(p1 + size - 1));
+ EXPECT_EQ(p1, a.GetBlockBeginFastLocked(p1 - 100));
+ }
+
+ for (uptr i = 0; i < kNumExpectedFalseLookups; i++) {
+ void *p = reinterpret_cast<void *>(i % 1024);
+ EXPECT_EQ((void *)0, a.GetBlockBeginFastLocked(p));
+ p = reinterpret_cast<void *>(~0L - (i % 1024));
+ EXPECT_EQ((void *)0, a.GetBlockBeginFastLocked(p));
+ }
+ a.ForceUnlock();
+
+ for (uptr i = 0; i < kNumAllocs; i++)
+ a.Deallocate(&stats, allocated[i]);
}
+
#if SANITIZER_WORDSIZE == 64
// Regression test for out-of-memory condition in PopulateFreeList().
TEST(SanitizerCommon, SizeClassAllocator64PopulateFreeListOOM) {
diff --git a/lib/sanitizer_common/tests/sanitizer_common_test.cc b/lib/sanitizer_common/tests/sanitizer_common_test.cc
index 424c279d4ada..608f90487a7b 100644
--- a/lib/sanitizer_common/tests/sanitizer_common_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_common_test.cc
@@ -10,7 +10,9 @@
// This file is a part of ThreadSanitizer/AddressSanitizer runtime.
//
//===----------------------------------------------------------------------===//
+#include "sanitizer_common/sanitizer_allocator_internal.h"
#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_flags.h"
#include "sanitizer_common/sanitizer_libc.h"
#include "sanitizer_common/sanitizer_platform.h"
#include "gtest/gtest.h"
@@ -97,8 +99,8 @@ TEST(SanitizerCommon, SanitizerSetThreadName) {
}
#endif
-TEST(SanitizerCommon, InternalVector) {
- InternalVector<uptr> vector(1);
+TEST(SanitizerCommon, InternalMmapVector) {
+ InternalMmapVector<uptr> vector(1);
for (uptr i = 0; i < 100; i++) {
EXPECT_EQ(i, vector.size());
vector.push_back(i);
@@ -158,4 +160,100 @@ TEST(SanitizerCommon, ThreadStackTlsWorker) {
pthread_join(t, 0);
}
+bool UptrLess(uptr a, uptr b) {
+ return a < b;
+}
+
+TEST(SanitizerCommon, InternalBinarySearch) {
+ static const uptr kSize = 5;
+ uptr arr[kSize];
+ for (uptr i = 0; i < kSize; i++) arr[i] = i * i;
+
+ for (uptr i = 0; i < kSize; i++)
+ ASSERT_EQ(InternalBinarySearch(arr, 0, kSize, i * i, UptrLess), i);
+
+ ASSERT_EQ(InternalBinarySearch(arr, 0, kSize, 7, UptrLess), kSize + 1);
+}
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+TEST(SanitizerCommon, FindPathToBinary) {
+ char *true_path = FindPathToBinary("true");
+ EXPECT_NE((char*)0, internal_strstr(true_path, "/bin/true"));
+ InternalFree(true_path);
+ EXPECT_EQ(0, FindPathToBinary("unexisting_binary.ergjeorj"));
+}
+#endif
+
+TEST(SanitizerCommon, StripPathPrefix) {
+ EXPECT_EQ(0, StripPathPrefix(0, "prefix"));
+ EXPECT_STREQ("foo", StripPathPrefix("foo", 0));
+ EXPECT_STREQ("dir/file.cc",
+ StripPathPrefix("/usr/lib/dir/file.cc", "/usr/lib/"));
+ EXPECT_STREQ("/file.cc", StripPathPrefix("/usr/myroot/file.cc", "/myroot"));
+ EXPECT_STREQ("file.h", StripPathPrefix("/usr/lib/./file.h", "/usr/lib/"));
+}
+
+TEST(SanitizerCommon, InternalScopedString) {
+ InternalScopedString str(10);
+ EXPECT_EQ(0U, str.length());
+ EXPECT_STREQ("", str.data());
+
+ str.append("foo");
+ EXPECT_EQ(3U, str.length());
+ EXPECT_STREQ("foo", str.data());
+
+ int x = 1234;
+ str.append("%d", x);
+ EXPECT_EQ(7U, str.length());
+ EXPECT_STREQ("foo1234", str.data());
+
+ str.append("%d", x);
+ EXPECT_EQ(9U, str.length());
+ EXPECT_STREQ("foo123412", str.data());
+
+ str.clear();
+ EXPECT_EQ(0U, str.length());
+ EXPECT_STREQ("", str.data());
+
+ str.append("0123456789");
+ EXPECT_EQ(9U, str.length());
+ EXPECT_STREQ("012345678", str.data());
+}
+
+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_ioctl_test.cc b/lib/sanitizer_common/tests/sanitizer_ioctl_test.cc
new file mode 100644
index 000000000000..154d9860b79f
--- /dev/null
+++ b/lib/sanitizer_common/tests/sanitizer_ioctl_test.cc
@@ -0,0 +1,77 @@
+//===-- sanitizer_ioctl_test.cc -------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Tests for ioctl interceptor implementation in sanitizer_common.
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_platform.h"
+#if SANITIZER_LINUX
+
+#include <linux/input.h>
+#include <vector>
+
+#include "interception/interception.h"
+#include "sanitizer_test_utils.h"
+#include "sanitizer_common/sanitizer_platform_limits_posix.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "gtest/gtest.h"
+
+
+using namespace __sanitizer;
+
+#define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, sz) \
+ do { \
+ (void) ctx; \
+ (void) ptr; \
+ (void) sz; \
+ } while (0)
+#define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, sz) \
+ do { \
+ (void) ctx; \
+ (void) ptr; \
+ (void) sz; \
+ } while (0)
+
+#include "sanitizer_common/sanitizer_common_interceptors_ioctl.inc"
+
+static struct IoctlInit {
+ IoctlInit() {
+ ioctl_init();
+ // Avoid unused function warnings.
+ (void)&ioctl_common_pre;
+ (void)&ioctl_common_post;
+ }
+} ioctl_static_initializer;
+
+TEST(SanitizerIoctl, Fixup) {
+ EXPECT_EQ((unsigned)FIONBIO, ioctl_request_fixup(FIONBIO));
+
+ EXPECT_EQ(EVIOCGBIT(0, 0), ioctl_request_fixup(EVIOCGBIT(0, 16)));
+ EXPECT_EQ(EVIOCGBIT(0, 0), ioctl_request_fixup(EVIOCGBIT(1, 16)));
+ EXPECT_EQ(EVIOCGBIT(0, 0), ioctl_request_fixup(EVIOCGBIT(1, 17)));
+ EXPECT_EQ(EVIOCGBIT(0, 0), ioctl_request_fixup(EVIOCGBIT(31, 16)));
+ EXPECT_NE(EVIOCGBIT(0, 0), ioctl_request_fixup(EVIOCGBIT(32, 16)));
+
+ EXPECT_EQ(EVIOCGABS(0), ioctl_request_fixup(EVIOCGABS(0)));
+ EXPECT_EQ(EVIOCGABS(0), ioctl_request_fixup(EVIOCGABS(5)));
+ EXPECT_EQ(EVIOCGABS(0), ioctl_request_fixup(EVIOCGABS(63)));
+ EXPECT_NE(EVIOCGABS(0), ioctl_request_fixup(EVIOCGABS(64)));
+
+ EXPECT_EQ(EVIOCSABS(0), ioctl_request_fixup(EVIOCSABS(0)));
+ EXPECT_EQ(EVIOCSABS(0), ioctl_request_fixup(EVIOCSABS(5)));
+ EXPECT_EQ(EVIOCSABS(0), ioctl_request_fixup(EVIOCSABS(63)));
+ EXPECT_NE(EVIOCSABS(0), ioctl_request_fixup(EVIOCSABS(64)));
+
+ const ioctl_desc *desc = ioctl_lookup(EVIOCGKEY(16));
+ EXPECT_NE((void *)0, desc);
+ EXPECT_EQ(EVIOCGKEY(0), desc->req);
+}
+
+#endif // SANITIZER_LINUX
diff --git a/lib/sanitizer_common/tests/sanitizer_libc_test.cc b/lib/sanitizer_common/tests/sanitizer_libc_test.cc
index 39c29d357327..c4f3d8033c2d 100644
--- a/lib/sanitizer_common/tests/sanitizer_libc_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_libc_test.cc
@@ -115,3 +115,10 @@ TEST(SanitizerCommon, FileOps) {
internal_close(fd);
}
+TEST(SanitizerCommon, InternalStrFunctions) {
+ const char *haystack = "haystack";
+ EXPECT_EQ(haystack + 2, internal_strchr(haystack, 'y'));
+ EXPECT_EQ(haystack + 2, internal_strchrnul(haystack, 'y'));
+ EXPECT_EQ(0, internal_strchr(haystack, 'z'));
+ EXPECT_EQ(haystack + 8, internal_strchrnul(haystack, 'z'));
+}
diff --git a/lib/sanitizer_common/tests/sanitizer_linux_test.cc b/lib/sanitizer_common/tests/sanitizer_linux_test.cc
index b18aeb030acf..592d9c3eeaf5 100644
--- a/lib/sanitizer_common/tests/sanitizer_linux_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_linux_test.cc
@@ -19,9 +19,6 @@
#include "sanitizer_common/sanitizer_common.h"
#include "gtest/gtest.h"
-#ifdef __x86_64__
-#include <asm/prctl.h>
-#endif
#include <pthread.h>
#include <sched.h>
#include <stdlib.h>
@@ -29,10 +26,6 @@
#include <algorithm>
#include <vector>
-#ifdef __x86_64__
-extern "C" int arch_prctl(int code, __sanitizer::uptr *addr);
-#endif
-
namespace __sanitizer {
struct TidReporterArgument {
@@ -202,23 +195,37 @@ TEST(SanitizerCommon, SetEnvTest) {
EXPECT_EQ(0, getenv(kEnvName));
}
-#ifdef __x86_64__
-// libpthread puts the thread descriptor (%fs:0x0) at the end of stack space.
-void *thread_descriptor_test_func(void *arg) {
- uptr fs;
- arch_prctl(ARCH_GET_FS, &fs);
+#if defined(__x86_64__) || defined(__i386__)
+void *thread_self_offset_test_func(void *arg) {
+ bool result =
+ *(uptr *)((char *)ThreadSelf() + ThreadSelfOffset()) == ThreadSelf();
+ return (void *)result;
+}
+
+TEST(SanitizerLinux, ThreadSelfOffset) {
+ EXPECT_TRUE((bool)thread_self_offset_test_func(0));
+ pthread_t tid;
+ void *result;
+ ASSERT_EQ(0, pthread_create(&tid, 0, thread_self_offset_test_func, 0));
+ ASSERT_EQ(0, pthread_join(tid, &result));
+ EXPECT_TRUE((bool)result);
+}
+
+// libpthread puts the thread descriptor at the end of stack space.
+void *thread_descriptor_size_test_func(void *arg) {
+ uptr descr_addr = ThreadSelf();
pthread_attr_t attr;
pthread_getattr_np(pthread_self(), &attr);
void *stackaddr;
- uptr stacksize;
+ size_t stacksize;
pthread_attr_getstack(&attr, &stackaddr, &stacksize);
- return (void *)((uptr)stackaddr + stacksize - fs);
+ return (void *)((uptr)stackaddr + stacksize - descr_addr);
}
TEST(SanitizerLinux, ThreadDescriptorSize) {
pthread_t tid;
void *result;
- pthread_create(&tid, 0, thread_descriptor_test_func, 0);
+ ASSERT_EQ(0, pthread_create(&tid, 0, thread_descriptor_size_test_func, 0));
ASSERT_EQ(0, pthread_join(tid, &result));
EXPECT_EQ((uptr)result, ThreadDescriptorSize());
}
diff --git a/lib/sanitizer_common/tests/sanitizer_mutex_test.cc b/lib/sanitizer_common/tests/sanitizer_mutex_test.cc
index 1dc9bef20710..06f742b41796 100644
--- a/lib/sanitizer_common/tests/sanitizer_mutex_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_mutex_test.cc
@@ -65,7 +65,6 @@ class TestData {
};
const int kThreads = 8;
-const int kWriteRate = 1024;
#if SANITIZER_DEBUG
const int kIters = 16*1024;
#else
diff --git a/lib/sanitizer_common/tests/sanitizer_nolibc_test.cc b/lib/sanitizer_common/tests/sanitizer_nolibc_test.cc
new file mode 100644
index 000000000000..d0d5a5e13898
--- /dev/null
+++ b/lib/sanitizer_common/tests/sanitizer_nolibc_test.cc
@@ -0,0 +1,31 @@
+//===-- sanitizer_nolibc_test.cc ------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of ThreadSanitizer/AddressSanitizer runtime.
+// Tests for libc independence of sanitizer_common.
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_platform.h"
+
+#include "gtest/gtest.h"
+
+#include <stdlib.h>
+
+extern const char *argv0;
+
+#if SANITIZER_LINUX && defined(__x86_64__)
+TEST(SanitizerCommon, NolibcMain) {
+ std::string NolibcTestPath = argv0;
+ NolibcTestPath += "-Nolibc";
+ int status = system(NolibcTestPath.c_str());
+ EXPECT_EQ(true, WIFEXITED(status));
+ EXPECT_EQ(0, WEXITSTATUS(status));
+}
+#endif
diff --git a/lib/sanitizer_common/tests/sanitizer_nolibc_test_main.cc b/lib/sanitizer_common/tests/sanitizer_nolibc_test_main.cc
new file mode 100644
index 000000000000..72df621d07ff
--- /dev/null
+++ b/lib/sanitizer_common/tests/sanitizer_nolibc_test_main.cc
@@ -0,0 +1,19 @@
+//===-- sanitizer_nolibc_test_main.cc -------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of ThreadSanitizer/AddressSanitizer runtime.
+// Tests for libc independence of sanitizer_common.
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_libc.h"
+
+extern "C" void _start() {
+ internal__exit(0);
+}
diff --git a/lib/sanitizer_common/tests/sanitizer_posix_test.cc b/lib/sanitizer_common/tests/sanitizer_posix_test.cc
new file mode 100644
index 000000000000..035899c83022
--- /dev/null
+++ b/lib/sanitizer_common/tests/sanitizer_posix_test.cc
@@ -0,0 +1,62 @@
+//===-- sanitizer_posix_test.cc -------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Tests for POSIX-specific code.
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_platform.h"
+#if SANITIZER_POSIX
+
+#include "sanitizer_common/sanitizer_common.h"
+#include "gtest/gtest.h"
+
+#include <pthread.h>
+
+namespace __sanitizer {
+
+static pthread_key_t key;
+static bool destructor_executed;
+
+extern "C"
+void destructor(void *arg) {
+ uptr iter = reinterpret_cast<uptr>(arg);
+ if (iter > 1) {
+ ASSERT_EQ(0, pthread_setspecific(key, reinterpret_cast<void *>(iter - 1)));
+ return;
+ }
+ destructor_executed = true;
+}
+
+extern "C"
+void *thread_func(void *arg) {
+ return reinterpret_cast<void*>(pthread_setspecific(key, arg));
+}
+
+static void SpawnThread(uptr iteration) {
+ destructor_executed = false;
+ pthread_t tid;
+ ASSERT_EQ(0, pthread_create(&tid, 0, &thread_func,
+ reinterpret_cast<void *>(iteration)));
+ void *retval;
+ ASSERT_EQ(0, pthread_join(tid, &retval));
+ ASSERT_EQ(0, retval);
+}
+
+TEST(SanitizerCommon, PthreadDestructorIterations) {
+ ASSERT_EQ(0, pthread_key_create(&key, &destructor));
+ SpawnThread(kPthreadDestructorIterations);
+ EXPECT_TRUE(destructor_executed);
+ SpawnThread(kPthreadDestructorIterations + 1);
+ EXPECT_FALSE(destructor_executed);
+}
+
+} // 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 b1889cd8794e..2c478cc74286 100644
--- a/lib/sanitizer_common/tests/sanitizer_printf_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_printf_test.cc
@@ -104,22 +104,36 @@ TEST(Printf, OverflowPtr) {
}
template<typename T>
-static void TestMinMax(const char *fmt, T min, T max) {
+static void TestAgainstLibc(const char *fmt, T arg1, T arg2) {
char buf[1024];
- uptr len = internal_snprintf(buf, sizeof(buf), fmt, min, max);
+ uptr len = internal_snprintf(buf, sizeof(buf), fmt, arg1, arg2);
char buf2[1024];
- snprintf(buf2, sizeof(buf2), fmt, min, max);
+ snprintf(buf2, sizeof(buf2), fmt, arg1, arg2);
EXPECT_EQ(len, strlen(buf));
EXPECT_STREQ(buf2, buf);
}
TEST(Printf, MinMax) {
- TestMinMax<int>("%d-%d", INT_MIN, INT_MAX); // NOLINT
- TestMinMax<long>("%zd-%zd", LONG_MIN, LONG_MAX); // NOLINT
- TestMinMax<unsigned>("%u-%u", 0, UINT_MAX); // NOLINT
- TestMinMax<unsigned long>("%zu-%zu", 0, ULONG_MAX); // NOLINT
- TestMinMax<unsigned>("%x-%x", 0, UINT_MAX); // NOLINT
- TestMinMax<unsigned long>("%zx-%zx", 0, ULONG_MAX); // NOLINT
+ 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
+ TestAgainstLibc<unsigned long>("%zx-%zx", 0, ULONG_MAX); // NOLINT
+ Report("%zd\n", LONG_MIN);
+}
+
+TEST(Printf, Padding) {
+ TestAgainstLibc<int>("%3d - %3d", 1, 0);
+ TestAgainstLibc<int>("%3d - %3d", -1, 123);
+ TestAgainstLibc<int>("%3d - %3d", -1, -123);
+ TestAgainstLibc<int>("%3d - %3d", 12, 1234);
+ TestAgainstLibc<int>("%3d - %3d", -12, -1234);
+ TestAgainstLibc<int>("%03d - %03d", 1, 0);
+ TestAgainstLibc<int>("%03d - %03d", -1, 123);
+ TestAgainstLibc<int>("%03d - %03d", -1, -123);
+ TestAgainstLibc<int>("%03d - %03d", 12, 1234);
+ TestAgainstLibc<int>("%03d - %03d", -12, -1234);
}
} // namespace __sanitizer
diff --git a/lib/sanitizer_common/tests/sanitizer_procmaps_test.cc b/lib/sanitizer_common/tests/sanitizer_procmaps_test.cc
new file mode 100644
index 000000000000..d16e2eebf98e
--- /dev/null
+++ b/lib/sanitizer_common/tests/sanitizer_procmaps_test.cc
@@ -0,0 +1,30 @@
+//===-- sanitizer_procmaps_test.cc ----------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of ThreadSanitizer/AddressSanitizer runtime.
+//
+//===----------------------------------------------------------------------===//
+#include "sanitizer_common/sanitizer_procmaps.h"
+//#include "sanitizer_common/sanitizer_internal_defs.h"
+//#include "sanitizer_common/sanitizer_libc.h"
+#include "gtest/gtest.h"
+
+namespace __sanitizer {
+
+#ifdef SANITIZER_LINUX
+TEST(ProcMaps, CodeRange) {
+ uptr start, end;
+ bool res = GetCodeRangeForFile("[vdso]", &start, &end);
+ EXPECT_EQ(res, true);
+ EXPECT_GT(start, (uptr)0);
+ EXPECT_LT(start, end);
+}
+#endif
+
+} // namespace __sanitizer
diff --git a/lib/sanitizer_common/tests/sanitizer_scanf_interceptor_test.cc b/lib/sanitizer_common/tests/sanitizer_scanf_interceptor_test.cc
index 1df2bcfd4bec..e0354062508f 100644
--- a/lib/sanitizer_common/tests/sanitizer_scanf_interceptor_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_scanf_interceptor_test.cc
@@ -169,7 +169,7 @@ TEST(SanitizerCommonInterceptors, Scanf) {
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, 1, 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);
diff --git a/lib/sanitizer_common/tests/sanitizer_stackdepot_test.cc b/lib/sanitizer_common/tests/sanitizer_stackdepot_test.cc
index 5350c2ab8dbc..5c075d53ebff 100644
--- a/lib/sanitizer_common/tests/sanitizer_stackdepot_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_stackdepot_test.cc
@@ -66,4 +66,27 @@ TEST(SanitizerCommon, StackDepotSeveral) {
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};
+ 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));
+
+ 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);
+ }
+}
+
} // namespace __sanitizer
diff --git a/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc b/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc
index 3d352cb97a5e..2b842cd8134a 100644
--- a/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc
@@ -20,6 +20,13 @@ namespace __sanitizer {
class FastUnwindTest : public ::testing::Test {
protected:
virtual void SetUp();
+ bool TryFastUnwind(uptr max_depth) {
+ if (!StackTrace::WillUseFastUnwind(true))
+ return false;
+ trace.Unwind(max_depth, start_pc, (uptr)&fake_stack[0], fake_top,
+ fake_bottom, true);
+ return true;
+ }
uptr fake_stack[10];
uptr start_pc;
@@ -47,16 +54,11 @@ void FastUnwindTest::SetUp() {
// Bottom is one slot before the start because FastUnwindStack uses >.
fake_bottom = (uptr)&fake_stack[-1];
start_pc = PC(0);
-
- // This is common setup done by __asan::GetStackTrace().
- trace.size = 0;
- trace.max_size = ARRAY_SIZE(fake_stack);
- trace.trace[0] = start_pc;
}
TEST_F(FastUnwindTest, Basic) {
- trace.FastUnwindStack(start_pc, (uptr)&fake_stack[0],
- fake_top, fake_bottom);
+ if (!TryFastUnwind(kStackTraceMax))
+ return;
// Should get all on-stack retaddrs and start_pc.
EXPECT_EQ(6U, trace.size);
EXPECT_EQ(start_pc, trace.trace[0]);
@@ -69,8 +71,8 @@ TEST_F(FastUnwindTest, Basic) {
TEST_F(FastUnwindTest, FramePointerLoop) {
// Make one fp point to itself.
fake_stack[4] = (uptr)&fake_stack[4];
- trace.FastUnwindStack(start_pc, (uptr)&fake_stack[0],
- fake_top, fake_bottom);
+ if (!TryFastUnwind(kStackTraceMax))
+ return;
// Should get all on-stack retaddrs up to the 4th slot and start_pc.
EXPECT_EQ(4U, trace.size);
EXPECT_EQ(start_pc, trace.trace[0]);
@@ -82,8 +84,8 @@ TEST_F(FastUnwindTest, FramePointerLoop) {
TEST_F(FastUnwindTest, MisalignedFramePointer) {
// Make one fp misaligned.
fake_stack[4] += 3;
- trace.FastUnwindStack(start_pc, (uptr)&fake_stack[0],
- fake_top, fake_bottom);
+ if (!TryFastUnwind(kStackTraceMax))
+ return;
// Should get all on-stack retaddrs up to the 4th slot and start_pc.
EXPECT_EQ(4U, trace.size);
EXPECT_EQ(start_pc, trace.trace[0]);
@@ -92,5 +94,12 @@ TEST_F(FastUnwindTest, MisalignedFramePointer) {
}
}
+TEST_F(FastUnwindTest, OneFrameStackTrace) {
+ if (!TryFastUnwind(1))
+ return;
+ EXPECT_EQ(1U, trace.size);
+ EXPECT_EQ(start_pc, trace.trace[0]);
+ EXPECT_EQ((uptr)&fake_stack[0], trace.top_frame_bp);
+}
} // namespace __sanitizer
diff --git a/lib/sanitizer_common/tests/sanitizer_stoptheworld_test.cc b/lib/sanitizer_common/tests/sanitizer_stoptheworld_test.cc
index a5f8516df575..b6786ba8b013 100644
--- a/lib/sanitizer_common/tests/sanitizer_stoptheworld_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_stoptheworld_test.cc
@@ -12,7 +12,7 @@
//===----------------------------------------------------------------------===//
#include "sanitizer_common/sanitizer_platform.h"
-#if SANITIZER_LINUX
+#if SANITIZER_LINUX && defined(__x86_64__)
#include "sanitizer_common/sanitizer_stoptheworld.h"
#include "gtest/gtest.h"
@@ -191,4 +191,4 @@ TEST(StopTheWorld, SuspendThreadsAdvanced) {
} // namespace __sanitizer
-#endif // SANITIZER_LINUX
+#endif // SANITIZER_LINUX && defined(__x86_64__)
diff --git a/lib/sanitizer_common/tests/sanitizer_suppressions_test.cc b/lib/sanitizer_common/tests/sanitizer_suppressions_test.cc
new file mode 100644
index 000000000000..ea8741d4f01a
--- /dev/null
+++ b/lib/sanitizer_common/tests/sanitizer_suppressions_test.cc
@@ -0,0 +1,152 @@
+//===-- sanitizer_suppressions_test.cc ------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of ThreadSanitizer/AddressSanitizer runtime.
+//
+//===----------------------------------------------------------------------===//
+#include "sanitizer_common/sanitizer_suppressions.h"
+#include "gtest/gtest.h"
+
+#include <string.h>
+
+namespace __sanitizer {
+
+static bool MyMatch(const char *templ, const char *func) {
+ char tmp[1024];
+ strcpy(tmp, templ); // NOLINT
+ return TemplateMatch(tmp, func);
+}
+
+TEST(Suppressions, Match) {
+ EXPECT_TRUE(MyMatch("foobar$", "foobar"));
+
+ EXPECT_TRUE(MyMatch("foobar", "foobar"));
+ EXPECT_TRUE(MyMatch("*foobar*", "foobar"));
+ EXPECT_TRUE(MyMatch("foobar", "prefix_foobar_postfix"));
+ EXPECT_TRUE(MyMatch("*foobar*", "prefix_foobar_postfix"));
+ EXPECT_TRUE(MyMatch("foo*bar", "foo_middle_bar"));
+ EXPECT_TRUE(MyMatch("foo*bar", "foobar"));
+ EXPECT_TRUE(MyMatch("foo*bar*baz", "foo_middle_bar_another_baz"));
+ EXPECT_TRUE(MyMatch("foo*bar*baz", "foo_middle_barbaz"));
+ EXPECT_TRUE(MyMatch("^foobar", "foobar"));
+ EXPECT_TRUE(MyMatch("^foobar", "foobar_postfix"));
+ EXPECT_TRUE(MyMatch("^*foobar", "foobar"));
+ EXPECT_TRUE(MyMatch("^*foobar", "prefix_foobar"));
+ EXPECT_TRUE(MyMatch("foobar$", "foobar"));
+ EXPECT_TRUE(MyMatch("foobar$", "prefix_foobar"));
+ EXPECT_TRUE(MyMatch("*foobar*$", "foobar"));
+ EXPECT_TRUE(MyMatch("*foobar*$", "foobar_postfix"));
+ EXPECT_TRUE(MyMatch("^foobar$", "foobar"));
+
+ EXPECT_FALSE(MyMatch("foo", "baz"));
+ EXPECT_FALSE(MyMatch("foobarbaz", "foobar"));
+ EXPECT_FALSE(MyMatch("foobarbaz", "barbaz"));
+ EXPECT_FALSE(MyMatch("foo*bar", "foobaz"));
+ EXPECT_FALSE(MyMatch("foo*bar", "foo_baz"));
+ EXPECT_FALSE(MyMatch("^foobar", "prefix_foobar"));
+ EXPECT_FALSE(MyMatch("foobar$", "foobar_postfix"));
+ EXPECT_FALSE(MyMatch("^foobar$", "prefix_foobar"));
+ EXPECT_FALSE(MyMatch("^foobar$", "foobar_postfix"));
+ EXPECT_FALSE(MyMatch("foo^bar", "foobar"));
+ EXPECT_FALSE(MyMatch("foo$bar", "foobar"));
+ EXPECT_FALSE(MyMatch("foo$^bar", "foobar"));
+}
+
+TEST(Suppressions, TypeStrings) {
+ CHECK(!internal_strcmp(SuppressionTypeString(SuppressionNone), "none"));
+ CHECK(!internal_strcmp(SuppressionTypeString(SuppressionRace), "race"));
+ CHECK(!internal_strcmp(SuppressionTypeString(SuppressionMutex), "mutex"));
+ CHECK(!internal_strcmp(SuppressionTypeString(SuppressionThread), "thread"));
+ CHECK(!internal_strcmp(SuppressionTypeString(SuppressionSignal), "signal"));
+ CHECK(!internal_strcmp(SuppressionTypeString(SuppressionLeak), "leak"));
+ CHECK(!internal_strcmp(SuppressionTypeString(SuppressionLib),
+ "called_from_lib"));
+ // Ensure this test is up-to-date when suppression types are added.
+ CHECK_EQ(SuppressionTypeCount, 7);
+}
+
+class SuppressionContextTest : public ::testing::Test {
+ public:
+ virtual void SetUp() { ctx_ = new(placeholder_) SuppressionContext; }
+ virtual void TearDown() { ctx_->~SuppressionContext(); }
+
+ protected:
+ InternalMmapVector<Suppression> *Suppressions() {
+ return &ctx_->suppressions_;
+ }
+ SuppressionContext *ctx_;
+ ALIGNED(64) char placeholder_[sizeof(SuppressionContext)];
+};
+
+TEST_F(SuppressionContextTest, Parse) {
+ ctx_->Parse(
+ "race:foo\n"
+ " race:bar\n" // NOLINT
+ "race:baz \n" // NOLINT
+ "# a comment\n"
+ "race:quz\n"
+ ); // NOLINT
+ EXPECT_EQ((unsigned)4, ctx_->SuppressionCount());
+ EXPECT_EQ((*Suppressions())[3].type, SuppressionRace);
+ EXPECT_EQ(0, strcmp((*Suppressions())[3].templ, "quz"));
+ EXPECT_EQ((*Suppressions())[2].type, SuppressionRace);
+ EXPECT_EQ(0, strcmp((*Suppressions())[2].templ, "baz"));
+ EXPECT_EQ((*Suppressions())[1].type, SuppressionRace);
+ EXPECT_EQ(0, strcmp((*Suppressions())[1].templ, "bar"));
+ EXPECT_EQ((*Suppressions())[0].type, SuppressionRace);
+ EXPECT_EQ(0, strcmp((*Suppressions())[0].templ, "foo"));
+}
+
+TEST_F(SuppressionContextTest, Parse2) {
+ ctx_->Parse(
+ " # first line comment\n" // NOLINT
+ " race:bar \n" // NOLINT
+ "race:baz* *baz\n"
+ "# a comment\n"
+ "# last line comment\n"
+ ); // NOLINT
+ EXPECT_EQ((unsigned)2, ctx_->SuppressionCount());
+ EXPECT_EQ((*Suppressions())[1].type, SuppressionRace);
+ EXPECT_EQ(0, strcmp((*Suppressions())[1].templ, "baz* *baz"));
+ EXPECT_EQ((*Suppressions())[0].type, SuppressionRace);
+ EXPECT_EQ(0, strcmp((*Suppressions())[0].templ, "bar"));
+}
+
+TEST_F(SuppressionContextTest, Parse3) {
+ ctx_->Parse(
+ "# last suppression w/o line-feed\n"
+ "race:foo\n"
+ "race:bar"
+ ); // NOLINT
+ EXPECT_EQ((unsigned)2, ctx_->SuppressionCount());
+ EXPECT_EQ((*Suppressions())[1].type, SuppressionRace);
+ EXPECT_EQ(0, strcmp((*Suppressions())[1].templ, "bar"));
+ EXPECT_EQ((*Suppressions())[0].type, SuppressionRace);
+ EXPECT_EQ(0, strcmp((*Suppressions())[0].templ, "foo"));
+}
+
+TEST_F(SuppressionContextTest, ParseType) {
+ ctx_->Parse(
+ "race:foo\n"
+ "thread:bar\n"
+ "mutex:baz\n"
+ "signal:quz\n"
+ ); // NOLINT
+ EXPECT_EQ((unsigned)4, ctx_->SuppressionCount());
+ EXPECT_EQ((*Suppressions())[3].type, SuppressionSignal);
+ EXPECT_EQ(0, strcmp((*Suppressions())[3].templ, "quz"));
+ EXPECT_EQ((*Suppressions())[2].type, SuppressionMutex);
+ EXPECT_EQ(0, strcmp((*Suppressions())[2].templ, "baz"));
+ EXPECT_EQ((*Suppressions())[1].type, SuppressionThread);
+ EXPECT_EQ(0, strcmp((*Suppressions())[1].templ, "bar"));
+ EXPECT_EQ((*Suppressions())[0].type, SuppressionRace);
+ EXPECT_EQ(0, strcmp((*Suppressions())[0].templ, "foo"));
+}
+
+} // namespace __sanitizer
diff --git a/lib/sanitizer_common/tests/sanitizer_test_main.cc b/lib/sanitizer_common/tests/sanitizer_test_main.cc
index 12d1d15af917..b7fd3dafab26 100644
--- a/lib/sanitizer_common/tests/sanitizer_test_main.cc
+++ b/lib/sanitizer_common/tests/sanitizer_test_main.cc
@@ -12,7 +12,10 @@
//===----------------------------------------------------------------------===//
#include "gtest/gtest.h"
+const char *argv0;
+
int main(int argc, char **argv) {
+ argv0 = argv[0];
testing::GTEST_FLAG(death_test_style) = "threadsafe";
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
diff --git a/lib/sanitizer_common/tests/sanitizer_test_utils.h b/lib/sanitizer_common/tests/sanitizer_test_utils.h
index a770d0fbd39e..17adb2647656 100644
--- a/lib/sanitizer_common/tests/sanitizer_test_utils.h
+++ b/lib/sanitizer_common/tests/sanitizer_test_utils.h
@@ -36,14 +36,14 @@ typedef __int64 int64_t;
#define __has_feature(x) 0
#endif
-#ifndef ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS
+#ifndef ATTRIBUTE_NO_SANITIZE_ADDRESS
# if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
-# define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS \
+# define ATTRIBUTE_NO_SANITIZE_ADDRESS \
__attribute__((no_sanitize_address))
# else
-# define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS
+# define ATTRIBUTE_NO_SANITIZE_ADDRESS
# endif
-#endif // ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS
+#endif // ATTRIBUTE_NO_SANITIZE_ADDRESS
#if __LP64__ || defined(_WIN64)
# define SANITIZER_WORDSIZE 64
diff --git a/lib/sanitizer_common/tests/sanitizer_thread_registry_test.cc b/lib/sanitizer_common/tests/sanitizer_thread_registry_test.cc
index e080403fb56c..ddc8dba5d3e0 100644
--- a/lib/sanitizer_common/tests/sanitizer_thread_registry_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_thread_registry_test.cc
@@ -23,8 +23,7 @@ static LowLevelAllocator tctx_allocator;
template<typename TCTX>
static ThreadContextBase *GetThreadContext(u32 tid) {
BlockingMutexLock l(&tctx_allocator_lock);
- void *mem = tctx_allocator.Allocate(sizeof(TCTX));
- return new(mem) TCTX(tid);
+ return new(tctx_allocator) TCTX(tid);
}
static const u32 kMaxRegistryThreads = 1000;
diff --git a/lib/tsan/CMakeLists.txt b/lib/tsan/CMakeLists.txt
index 282889567509..fc1944b02fa5 100644
--- a/lib/tsan/CMakeLists.txt
+++ b/lib/tsan/CMakeLists.txt
@@ -8,10 +8,14 @@ set(TSAN_CFLAGS
${SANITIZER_COMMON_CFLAGS}
-fPIE
-fno-rtti)
-# FIXME: Add support for compile flags:
-# -Wframe-larger-than=512,
-# -Wglobal-constructors,
-# --sysroot=.
+
+set(TSAN_RTL_CFLAGS
+ ${TSAN_CFLAGS}
+ -Wframe-larger-than=512)
+if(SUPPORTS_GLOBAL_CONSTRUCTORS_FLAG)
+ list(APPEND TSAN_RTL_CFLAGS -Wglobal-constructors)
+endif()
+# FIXME: Add support for --sysroot=. compile flag:
if("${CMAKE_BUILD_TYPE}" EQUAL "Release")
set(TSAN_COMMON_DEFINITIONS DEBUG=0)
@@ -19,7 +23,57 @@ else()
set(TSAN_COMMON_DEFINITIONS DEBUG=1)
endif()
-add_subdirectory(rtl)
+set(TSAN_SOURCES
+ rtl/tsan_clock.cc
+ rtl/tsan_flags.cc
+ rtl/tsan_fd.cc
+ rtl/tsan_interceptors.cc
+ rtl/tsan_interface_ann.cc
+ rtl/tsan_interface_atomic.cc
+ rtl/tsan_interface.cc
+ rtl/tsan_interface_java.cc
+ rtl/tsan_md5.cc
+ rtl/tsan_mman.cc
+ rtl/tsan_mutex.cc
+ rtl/tsan_mutexset.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_symbolize.cc
+ rtl/tsan_sync.cc)
+
+if(APPLE)
+ list(APPEND TSAN_SOURCES rtl/tsan_platform_mac.cc)
+elseif(UNIX)
+ # Assume Linux
+ list(APPEND TSAN_SOURCES
+ rtl/tsan_platform_linux.cc
+ rtl/tsan_symbolize_addr2line_linux.cc)
+endif()
+
+set(TSAN_RUNTIME_LIBRARIES)
+# 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)
+ # Pass ASM file directly to the C++ compiler.
+ set_source_files_properties(${TSAN_ASM_SOURCES} PROPERTIES
+ LANGUAGE C)
+ set(arch "x86_64")
+ add_compiler_rt_static_runtime(clang_rt.tsan-${arch} ${arch}
+ 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})
+ add_sanitizer_rt_symbols(clang_rt.tsan-${arch} rtl/tsan.syms.extra)
+ list(APPEND TSAN_RUNTIME_LIBRARIES clang_rt.tsan-${arch}
+ clang_rt.tsan-${arch}-symbols)
+endif()
if(LLVM_INCLUDE_TESTS)
add_subdirectory(tests)
diff --git a/lib/tsan/Makefile.old b/lib/tsan/Makefile.old
index b548f5d2f6ee..c10d49842cac 100644
--- a/lib/tsan/Makefile.old
+++ b/lib/tsan/Makefile.old
@@ -21,8 +21,11 @@ GTEST_BUILD_DIR=$(GTEST_ROOT)/build
GTEST_LIB_NAME=gtest-all.o
GTEST_LIB=$(GTEST_BUILD_DIR)/$(GTEST_LIB_NAME)
-SANITIZER_COMMON_TESTS_SRC=$(wildcard ../sanitizer_common/tests/*_test.cc)
-SANITIZER_COMMON_TESTS_OBJ=$(patsubst %.cc,%.o,$(SANITIZER_COMMON_TESTS_SRC))
+SANITIZER_TESTS_PATH=../sanitizer_common/tests
+SANITIZER_COMMON_TESTS_SRC=$(wildcard $(SANITIZER_TESTS_PATH)/*_test.cc)
+SANITIZER_COMMON_EXCLUDED_TESTS=$(SANITIZER_TESTS_PATH)/sanitizer_nolibc_test.cc
+SANITIZER_COMMON_GOOD_TESTS=$(filter-out $(SANITIZER_COMMON_EXCLUDED_TESTS), $(SANITIZER_COMMON_TESTS_SRC))
+SANITIZER_COMMON_TESTS_OBJ=$(patsubst %.cc,%.o,$(SANITIZER_COMMON_GOOD_TESTS))
RTL_TEST_SRC=$(wildcard tests/rtl/*.cc)
RTL_TEST_OBJ=$(patsubst %.cc,%.o,$(RTL_TEST_SRC))
UNIT_TEST_SRC=$(wildcard tests/unit/*_test.cc)
@@ -51,7 +54,7 @@ libtsan:
tsan_test: $(UNIT_TEST_OBJ) $(RTL_TEST_OBJ) \
$(SANITIZER_COMMON_TESTS_OBJ) $(LIBTSAN) $(GTEST_LIB)
- $(CXX) $^ -o $@ $(LDFLAGS)
+ $(CXX) -Wl,--whole-archive $^ -Wl,--no-whole-archive -o $@ $(LDFLAGS)
test: libtsan tsan_test
diff --git a/lib/tsan/check_cmake.sh b/lib/tsan/check_cmake.sh
index 52c97c339096..7e858efee913 100755
--- a/lib/tsan/check_cmake.sh
+++ b/lib/tsan/check_cmake.sh
@@ -3,10 +3,16 @@ set -u
set -e
ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
-mkdir -p $ROOT/build
-cd $ROOT/build
-CC=clang CXX=clang++ cmake -DLLVM_ENABLE_WERROR=ON -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_ASSERTIONS=ON $ROOT/../../../..
-make -j64
-make check-sanitizer -j64
-make check-tsan -j64
-make check-asan -j64
+if [ -d "$ROOT/build" ]; then
+ cd $ROOT/build
+else
+ mkdir -p $ROOT/build
+ cd $ROOT/build
+ CC=clang CXX=clang++ cmake -G Ninja -DLLVM_ENABLE_WERROR=ON -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_ASSERTIONS=ON $ROOT/../../../..
+fi
+ninja
+ninja check-sanitizer
+ninja check-tsan
+ninja check-asan
+ninja check-msan
+ninja check-lsan
diff --git a/lib/tsan/go/buildgo.sh b/lib/tsan/go/buildgo.sh
index 51f1a7975b57..bd03fc0b65e0 100755
--- a/lib/tsan/go/buildgo.sh
+++ b/lib/tsan/go/buildgo.sh
@@ -20,12 +20,13 @@ SRCS="
../../sanitizer_common/sanitizer_flags.cc
../../sanitizer_common/sanitizer_libc.cc
../../sanitizer_common/sanitizer_printf.cc
+ ../../sanitizer_common/sanitizer_suppressions.cc
../../sanitizer_common/sanitizer_thread_registry.cc
"
if [ "`uname -a | grep Linux`" != "" ]; then
SUFFIX="linux_amd64"
- OSCFLAGS="-fPIC -ffreestanding"
+ OSCFLAGS="-fPIC -ffreestanding -Wno-maybe-uninitialized -Werror"
OSLDFLAGS="-lpthread -fPIC -fpie"
SRCS+="
../rtl/tsan_platform_linux.cc
@@ -33,6 +34,7 @@ if [ "`uname -a | grep Linux`" != "" ]; then
../../sanitizer_common/sanitizer_posix_libcdep.cc
../../sanitizer_common/sanitizer_linux.cc
../../sanitizer_common/sanitizer_linux_libcdep.cc
+ ../../sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
"
elif [ "`uname -a | grep Darwin`" != "" ]; then
SUFFIX="darwin_amd64"
@@ -42,6 +44,7 @@ elif [ "`uname -a | grep Darwin`" != "" ]; then
../rtl/tsan_platform_mac.cc
../../sanitizer_common/sanitizer_posix.cc
../../sanitizer_common/sanitizer_mac.cc
+ ../../sanitizer_common/sanitizer_posix_libcdep.cc
"
elif [ "`uname -a | grep MINGW`" != "" ]; then
SUFFIX="windows_amd64"
@@ -63,7 +66,7 @@ for F in $SRCS; do
cat $F >> gotsan.cc
done
-FLAGS=" -I../rtl -I../.. -I../../sanitizer_common -I../../../include -m64 -Wall -Werror -fno-exceptions -fno-rtti -DTSAN_GO -DSANITIZER_GO -DTSAN_SHADOW_COUNT=4 $OSCFLAGS"
+FLAGS=" -I../rtl -I../.. -I../../sanitizer_common -I../../../include -m64 -Wall -fno-exceptions -fno-rtti -DTSAN_GO -DSANITIZER_GO -DTSAN_SHADOW_COUNT=4 $OSCFLAGS"
if [ "$DEBUG" == "" ]; then
FLAGS+=" -DTSAN_DEBUG=0 -O3 -fomit-frame-pointer"
else
diff --git a/lib/tsan/go/test.c b/lib/tsan/go/test.c
index 902dfc915582..859b35d348e8 100644
--- a/lib/tsan/go/test.c
+++ b/lib/tsan/go/test.c
@@ -34,20 +34,32 @@ int __tsan_symbolize(void *pc, char **img, char **rtn, char **file, int *l) {
char buf[10];
+void foobar() {}
+void barfoo() {}
+
int main(void) {
void *thr0 = 0;
__tsan_init(&thr0);
__tsan_map_shadow(buf, sizeof(buf) + 4096);
- __tsan_func_enter(thr0, &main);
+ __tsan_func_enter(thr0, (char*)&main + 1);
__tsan_malloc(thr0, buf, 10, 0);
__tsan_release(thr0, buf);
__tsan_release_merge(thr0, buf);
void *thr1 = 0;
- __tsan_go_start(thr0, &thr1, 0);
- __tsan_write(thr1, buf, 0);
+ __tsan_go_start(thr0, &thr1, (char*)&barfoo + 1);
+ void *thr2 = 0;
+ __tsan_go_start(thr0, &thr2, (char*)&barfoo + 1);
+ __tsan_func_enter(thr1, (char*)&foobar + 1);
+ __tsan_func_enter(thr1, (char*)&foobar + 1);
+ __tsan_write(thr1, buf, (char*)&barfoo + 1);
__tsan_acquire(thr1, buf);
+ __tsan_func_exit(thr1);
+ __tsan_func_exit(thr1);
__tsan_go_end(thr1);
- __tsan_read(thr0, buf, 0);
+ __tsan_func_enter(thr2, (char*)&foobar + 1);
+ __tsan_read(thr2, buf, (char*)&barfoo + 1);
+ __tsan_func_exit(thr2);
+ __tsan_go_end(thr2);
__tsan_free(buf);
__tsan_func_exit(thr0);
__tsan_fini();
diff --git a/lib/tsan/go/tsan_go.cc b/lib/tsan/go/tsan_go.cc
index 957d58211281..df54bb8e216c 100644
--- a/lib/tsan/go/tsan_go.cc
+++ b/lib/tsan/go/tsan_go.cc
@@ -116,12 +116,14 @@ void __tsan_write(ThreadState *thr, void *addr, void *pc) {
void __tsan_read_range(ThreadState *thr, void *addr, uptr size, uptr step,
void *pc) {
- MemoryAccessRangeStep(thr, (uptr)pc, (uptr)addr, size, step, false);
+ (void)step;
+ MemoryAccessRange(thr, (uptr)pc, (uptr)addr, size, false);
}
void __tsan_write_range(ThreadState *thr, void *addr, uptr size, uptr step,
void *pc) {
- MemoryAccessRangeStep(thr, (uptr)pc, (uptr)addr, size, step, true);
+ (void)step;
+ MemoryAccessRange(thr, (uptr)pc, (uptr)addr, size, true);
}
void __tsan_func_enter(ThreadState *thr, void *pc) {
@@ -184,40 +186,6 @@ void __tsan_finalizer_goroutine(ThreadState *thr) {
AcquireGlobal(thr, 0);
}
-#if SANITIZER_WINDOWS
-// MinGW gcc emits calls to the function.
-void ___chkstk_ms(void) {
-// The implementation must be along the lines of:
-// .code64
-// PUBLIC ___chkstk_ms
-// //cfi_startproc()
-// ___chkstk_ms:
-// push rcx
-// //cfi_push(%rcx)
-// push rax
-// //cfi_push(%rax)
-// cmp rax, PAGE_SIZE
-// lea rcx, [rsp + 24]
-// jb l_LessThanAPage
-// .l_MoreThanAPage:
-// sub rcx, PAGE_SIZE
-// or rcx, 0
-// sub rax, PAGE_SIZE
-// cmp rax, PAGE_SIZE
-// ja l_MoreThanAPage
-// .l_LessThanAPage:
-// sub rcx, rax
-// or [rcx], 0
-// pop rax
-// //cfi_pop(%rax)
-// pop rcx
-// //cfi_pop(%rcx)
-// ret
-// //cfi_endproc()
-// END
-}
-#endif
-
} // extern "C"
} // namespace __tsan
diff --git a/lib/tsan/lit_tests/CMakeLists.txt b/lib/tsan/lit_tests/CMakeLists.txt
index 53e5015d1bc4..1f2fbf98e080 100644
--- a/lib/tsan/lit_tests/CMakeLists.txt
+++ b/lib/tsan/lit_tests/CMakeLists.txt
@@ -8,7 +8,7 @@ configure_lit_site_cfg(
${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg
)
-if(COMPILER_RT_CAN_EXECUTE_TESTS)
+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}
@@ -25,7 +25,7 @@ if(COMPILER_RT_CAN_EXECUTE_TESTS)
DEPENDS ${TSAN_TEST_DEPS}
)
set_target_properties(check-tsan PROPERTIES FOLDER "TSan unittests")
-elseif(LLVM_INCLUDE_TESTS)
+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"
diff --git a/lib/tsan/lit_tests/Unit/lit.cfg b/lib/tsan/lit_tests/Unit/lit.cfg
index 0a0dbbfa5495..36585df1c671 100644
--- a/lib/tsan/lit_tests/Unit/lit.cfg
+++ b/lib/tsan/lit_tests/Unit/lit.cfg
@@ -5,17 +5,12 @@ import os
def get_required_attr(config, attr_name):
attr_value = getattr(config, attr_name, None)
if not attr_value:
- lit.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)
+ 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 attributes common for all compiler-rt projects.
-compiler_rt_src_root = get_required_attr(config, 'compiler_rt_src_root')
-compiler_rt_lit_unit_cfg = os.path.join(compiler_rt_src_root, "lib",
- "lit.common.unit.cfg")
-lit.load_config(config, compiler_rt_lit_unit_cfg)
-
# Setup config name.
config.name = 'ThreadSanitizer-Unit'
@@ -26,11 +21,3 @@ config.test_exec_root = os.path.join(llvm_obj_root, "projects",
"compiler-rt", "lib",
"tsan", "tests")
config.test_source_root = config.test_exec_root
-
-# Get path to external LLVM symbolizer to run ThreadSanitizer unit tests.
-llvm_tools_dir = getattr(config, 'llvm_tools_dir', None)
-if llvm_tools_dir:
- llvm_symbolizer_path = os.path.join(llvm_tools_dir, "llvm-symbolizer")
- config.environment['TSAN_OPTIONS'] = ("external_symbolizer_path=" +
- llvm_symbolizer_path)
-
diff --git a/lib/tsan/lit_tests/Unit/lit.site.cfg.in b/lib/tsan/lit_tests/Unit/lit.site.cfg.in
index 6eedc2180876..3701a2cad74c 100644
--- a/lib/tsan/lit_tests/Unit/lit.site.cfg.in
+++ b/lib/tsan/lit_tests/Unit/lit.site.cfg.in
@@ -1,20 +1,8 @@
## Autogenerated by LLVM/Clang configuration.
# Do not edit!
-config.llvm_obj_root = "@LLVM_BINARY_DIR@"
-config.llvm_src_root = "@LLVM_SOURCE_DIR@"
-config.compiler_rt_src_root = "@COMPILER_RT_SOURCE_DIR@"
-config.llvm_tools_dir = "@LLVM_TOOLS_DIR@"
-config.llvm_build_mode = "@LLVM_BUILD_MODE@"
+# Load common config for all compiler-rt unit tests.
+lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/lib/lit.common.unit.configured")
-# LLVM tools dir can be passed in lit parameters, so try to
-# apply substitution.
-try:
- config.llvm_tools_dir = config.llvm_tools_dir % lit.params
- config.llvm_build_mode = config.llvm_build_mode % lit.params
-except KeyError,e:
- key, = e.args
- lit.fatal("unable to find %r parameter, use '--param=%s=VALUE'" % (key, key))
-
-# Let the main config do the real work.
-lit.load_config(config, "@CMAKE_CURRENT_SOURCE_DIR@/Unit/lit.cfg")
+# 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/allocator_returns_null.cc b/lib/tsan/lit_tests/allocator_returns_null.cc
new file mode 100644
index 000000000000..4b5eb5504c27
--- /dev/null
+++ b/lib/tsan/lit_tests/allocator_returns_null.cc
@@ -0,0 +1,64 @@
+// 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
index ba9bd5ac4aed..87d559362af4 100644
--- a/lib/tsan/lit_tests/atomic_free.cc
+++ b/lib/tsan/lit_tests/atomic_free.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
#include <pthread.h>
#include <unistd.h>
diff --git a/lib/tsan/lit_tests/atomic_free2.cc b/lib/tsan/lit_tests/atomic_free2.cc
index 5517bf7ce902..961ff38c843b 100644
--- a/lib/tsan/lit_tests/atomic_free2.cc
+++ b/lib/tsan/lit_tests/atomic_free2.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
#include <pthread.h>
#include <unistd.h>
diff --git a/lib/tsan/lit_tests/atomic_race.cc b/lib/tsan/lit_tests/atomic_race.cc
index 360b81238889..0dfe4d93df6e 100644
--- a/lib/tsan/lit_tests/atomic_race.cc
+++ b/lib/tsan/lit_tests/atomic_race.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
#include <pthread.h>
#include <unistd.h>
#include <stdio.h>
diff --git a/lib/tsan/lit_tests/atomic_stack.cc b/lib/tsan/lit_tests/atomic_stack.cc
index 50f6a8a889ca..841f74b891ab 100644
--- a/lib/tsan/lit_tests/atomic_stack.cc
+++ b/lib/tsan/lit_tests/atomic_stack.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
#include <pthread.h>
#include <unistd.h>
diff --git a/lib/tsan/lit_tests/cond.c b/lib/tsan/lit_tests/cond.c
new file mode 100644
index 000000000000..52c87a413eb7
--- /dev/null
+++ b/lib/tsan/lit_tests/cond.c
@@ -0,0 +1,53 @@
+// 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
new file mode 100644
index 000000000000..1e2acb243279
--- /dev/null
+++ b/lib/tsan/lit_tests/cond_race.cc
@@ -0,0 +1,36 @@
+// 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
new file mode 100644
index 000000000000..1f966bfacb8d
--- /dev/null
+++ b/lib/tsan/lit_tests/cond_version.c
@@ -0,0 +1,44 @@
+// 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
new file mode 100644
index 000000000000..3048aa8745bb
--- /dev/null
+++ b/lib/tsan/lit_tests/deep_stack1.cc
@@ -0,0 +1,44 @@
+// 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
new file mode 100644
index 000000000000..62c6c028f9e4
--- /dev/null
+++ b/lib/tsan/lit_tests/default_options.cc
@@ -0,0 +1,32 @@
+// 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_norace2.cc b/lib/tsan/lit_tests/fd_close_norace2.cc
new file mode 100644
index 000000000000..b42b334a27c0
--- /dev/null
+++ b/lib/tsan/lit_tests/fd_close_norace2.cc
@@ -0,0 +1,30 @@
+// 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_location.cc b/lib/tsan/lit_tests/fd_location.cc
index 35f9aabb0377..2b1e9c56e361 100644
--- a/lib/tsan/lit_tests/fd_location.cc
+++ b/lib/tsan/lit_tests/fd_location.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
diff --git a/lib/tsan/lit_tests/fd_pipe_race.cc b/lib/tsan/lit_tests/fd_pipe_race.cc
index dfdb7795aae6..4dd2b77861ab 100644
--- a/lib/tsan/lit_tests/fd_pipe_race.cc
+++ b/lib/tsan/lit_tests/fd_pipe_race.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
diff --git a/lib/tsan/lit_tests/fd_stdout_race.cc b/lib/tsan/lit_tests/fd_stdout_race.cc
index 6581fc503a1b..4b512bb78874 100644
--- a/lib/tsan/lit_tests/fd_stdout_race.cc
+++ b/lib/tsan/lit_tests/fd_stdout_race.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
diff --git a/lib/tsan/lit_tests/free_race.c b/lib/tsan/lit_tests/free_race.c
index ff71a4d2116b..d1db9fece90a 100644
--- a/lib/tsan/lit_tests/free_race.c
+++ b/lib/tsan/lit_tests/free_race.c
@@ -1,4 +1,7 @@
-// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// 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>
@@ -34,11 +37,13 @@ int main() {
return 0;
}
-// CHECK: WARNING: ThreadSanitizer: heap-use-after-free
-// CHECK: Write of size 4 at {{.*}} by main thread{{.*}}:
-// CHECK: #0 Thread2
-// CHECK: #1 main
-// CHECK: Previous write of size 8 at {{.*}} by thread T1{{.*}}:
-// CHECK: #0 free
-// CHECK: #{{(1|2)}} Thread1
-// CHECK: SUMMARY: ThreadSanitizer: heap-use-after-free{{.*}}Thread2
+// 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
new file mode 100644
index 000000000000..f5d6a4969a41
--- /dev/null
+++ b/lib/tsan/lit_tests/free_race.c.supp
@@ -0,0 +1,2 @@
+# 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
index f20774b2d8d4..2b9a41927a47 100644
--- a/lib/tsan/lit_tests/free_race2.c
+++ b/lib/tsan/lit_tests/free_race2.c
@@ -1,4 +1,4 @@
-// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clang_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
#include <stdlib.h>
void __attribute__((noinline)) foo(int *mem) {
diff --git a/lib/tsan/lit_tests/global_race.cc b/lib/tsan/lit_tests/global_race.cc
index 0892d07da2cb..ac2016155575 100644
--- a/lib/tsan/lit_tests/global_race.cc
+++ b/lib/tsan/lit_tests/global_race.cc
@@ -1,25 +1,42 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// 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
-// Requires llvm-symbolizer, so disabled for now.
-// CHECK0: Location is global 'GlobalData' of size 40 at [[ADDR]]
-// CHECK0: (global_race.cc.exe+0x[0-9,a-f]+)
+// 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
new file mode 100644
index 000000000000..fddaffff29aa
--- /dev/null
+++ b/lib/tsan/lit_tests/halt_on_error.cc
@@ -0,0 +1,25 @@
+// 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
index 297f8dbdec7d..cc2c1fee532b 100644
--- a/lib/tsan/lit_tests/heap_race.cc
+++ b/lib/tsan/lit_tests/heap_race.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
#include <pthread.h>
#include <stdio.h>
#include <stddef.h>
diff --git a/lib/tsan/lit_tests/ignore_free.cc b/lib/tsan/lit_tests/ignore_free.cc
new file mode 100644
index 000000000000..60369cc1baa5
--- /dev/null
+++ b/lib/tsan/lit_tests/ignore_free.cc
@@ -0,0 +1,35 @@
+// 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
new file mode 100644
index 000000000000..ea0f061e609d
--- /dev/null
+++ b/lib/tsan/lit_tests/ignore_lib0.cc
@@ -0,0 +1,30 @@
+// 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
new file mode 100644
index 000000000000..7728c926b7de
--- /dev/null
+++ b/lib/tsan/lit_tests/ignore_lib0.cc.supp
@@ -0,0 +1,2 @@
+called_from_lib:/libignore_lib0.so
+
diff --git a/lib/tsan/lit_tests/ignore_lib1.cc b/lib/tsan/lit_tests/ignore_lib1.cc
new file mode 100644
index 000000000000..c4f2e7344135
--- /dev/null
+++ b/lib/tsan/lit_tests/ignore_lib1.cc
@@ -0,0 +1,42 @@
+// 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
new file mode 100644
index 000000000000..9f4119ec0bc4
--- /dev/null
+++ b/lib/tsan/lit_tests/ignore_lib1.cc.supp
@@ -0,0 +1,2 @@
+called_from_lib:/libignore_lib1.so$
+
diff --git a/lib/tsan/lit_tests/ignore_lib2.cc b/lib/tsan/lit_tests/ignore_lib2.cc
new file mode 100644
index 000000000000..97f9419e4d89
--- /dev/null
+++ b/lib/tsan/lit_tests/ignore_lib2.cc
@@ -0,0 +1,33 @@
+// 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
new file mode 100644
index 000000000000..1419c71c67ef
--- /dev/null
+++ b/lib/tsan/lit_tests/ignore_lib2.cc.supp
@@ -0,0 +1,2 @@
+called_from_lib:ignore_lib2
+
diff --git a/lib/tsan/lit_tests/ignore_lib3.cc b/lib/tsan/lit_tests/ignore_lib3.cc
new file mode 100644
index 000000000000..8f237fcc81fd
--- /dev/null
+++ b/lib/tsan/lit_tests/ignore_lib3.cc
@@ -0,0 +1,33 @@
+// 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
new file mode 100644
index 000000000000..975dbcef99fe
--- /dev/null
+++ b/lib/tsan/lit_tests/ignore_lib3.cc.supp
@@ -0,0 +1,2 @@
+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
new file mode 100644
index 000000000000..2bfe84dfc0ec
--- /dev/null
+++ b/lib/tsan/lit_tests/ignore_lib_lib.h
@@ -0,0 +1,25 @@
+#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
new file mode 100644
index 000000000000..63bd4241b59e
--- /dev/null
+++ b/lib/tsan/lit_tests/ignore_malloc.cc
@@ -0,0 +1,38 @@
+// 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_sync.cc b/lib/tsan/lit_tests/ignore_sync.cc
new file mode 100644
index 000000000000..67f2d906d9c7
--- /dev/null
+++ b/lib/tsan/lit_tests/ignore_sync.cc
@@ -0,0 +1,30 @@
+// 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
index 6efe5a956e9d..5dda36e4b9e7 100644
--- a/lib/tsan/lit_tests/inlined_memcpy_race.cc
+++ b/lib/tsan/lit_tests/inlined_memcpy_race.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
#include <pthread.h>
#include <stddef.h>
#include <stdio.h>
diff --git a/lib/tsan/lit_tests/java.h b/lib/tsan/lit_tests/java.h
index 04094197edb7..7aa0bca32cec 100644
--- a/lib/tsan/lit_tests/java.h
+++ b/lib/tsan/lit_tests/java.h
@@ -5,6 +5,7 @@
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);
diff --git a/lib/tsan/lit_tests/java_lock_rec_race.cc b/lib/tsan/lit_tests/java_lock_rec_race.cc
index 61626aaddc0d..a868e260c86d 100644
--- a/lib/tsan/lit_tests/java_lock_rec_race.cc
+++ b/lib/tsan/lit_tests/java_lock_rec_race.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
#include "java.h"
#include <unistd.h>
diff --git a/lib/tsan/lit_tests/java_race.cc b/lib/tsan/lit_tests/java_race.cc
index 722bb6e8d09c..4841a7db0a9c 100644
--- a/lib/tsan/lit_tests/java_race.cc
+++ b/lib/tsan/lit_tests/java_race.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
#include "java.h"
void *Thread(void *p) {
diff --git a/lib/tsan/lit_tests/java_race_move.cc b/lib/tsan/lit_tests/java_race_move.cc
index bb63ea985c58..6da8a106483c 100644
--- a/lib/tsan/lit_tests/java_race_move.cc
+++ b/lib/tsan/lit_tests/java_race_move.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
#include "java.h"
jptr varaddr;
diff --git a/lib/tsan/lit_tests/lit.cfg b/lib/tsan/lit_tests/lit.cfg
index d483d2fcbdc6..c4193639f493 100644
--- a/lib/tsan/lit_tests/lit.cfg
+++ b/lib/tsan/lit_tests/lit.cfg
@@ -2,12 +2,15 @@
import os
+import lit.util
+
def get_required_attr(config, attr_name):
attr_value = getattr(config, attr_name, None)
if not attr_value:
- lit.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)
+ 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.
@@ -17,9 +20,9 @@ config.name = 'ThreadSanitizer'
config.test_source_root = os.path.dirname(__file__)
def DisplayNoConfigMessage():
- lit.fatal("No site specific configuration available! " +
- "Try running your test from the build tree or running " +
- "make check-tsan")
+ 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)
@@ -27,9 +30,9 @@ 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.params.get('tsan_site_config', None)
+ tsan_site_cfg = lit_config.params.get('tsan_site_config', None)
if (tsan_site_cfg) and (os.path.exists(tsan_site_cfg)):
- lit.load_config(config, 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
@@ -45,25 +48,11 @@ if llvm_src_root is None:
if (not tsan_site_cfg) or (not os.path.exists(tsan_site_cfg)):
DisplayNoConfigMessage()
- lit.load_config(config, tsan_site_cfg)
+ lit_config.load_config(config, tsan_site_cfg)
raise SystemExit
-# Setup attributes common for all compiler-rt projects.
-compiler_rt_src_root = get_required_attr(config, 'compiler_rt_src_root')
-compiler_rt_lit_cfg = os.path.join(compiler_rt_src_root, "lib",
- "lit.common.cfg")
-if (not compiler_rt_lit_cfg) or (not os.path.exists(compiler_rt_lit_cfg)):
- lit.fatal("Can't find common compiler-rt lit config at: %r"
- % compiler_rt_lit_cfg)
-lit.load_config(config, compiler_rt_lit_cfg)
-
# Setup environment variables for running ThreadSanitizer.
tsan_options = "atexit_sleep_ms=0"
-# Get path to external LLVM symbolizer to run ThreadSanitizer output tests.
-llvm_tools_dir = getattr(config, 'llvm_tools_dir', None)
-if llvm_tools_dir:
- llvm_symbolizer_path = os.path.join(llvm_tools_dir, "llvm-symbolizer")
- tsan_options += " " + "external_symbolizer_path=" + llvm_symbolizer_path
config.environment['TSAN_OPTIONS'] = tsan_options
@@ -73,8 +62,9 @@ clang_tsan_cflags = ("-fsanitize=thread "
+ "-g "
+ "-Wall "
+ "-lpthread "
- + "-ldl ")
-clang_tsan_cxxflags = "-ccc-cxx " + clang_tsan_cflags
+ + "-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 + " " +
diff --git a/lib/tsan/lit_tests/lit.site.cfg.in b/lib/tsan/lit_tests/lit.site.cfg.in
index 07b521af061f..b0e427446eaa 100644
--- a/lib/tsan/lit_tests/lit.site.cfg.in
+++ b/lib/tsan/lit_tests/lit.site.cfg.in
@@ -1,20 +1,8 @@
## Autogenerated by LLVM/Clang configuration.
# Do not edit!
-config.clang = "@LLVM_BINARY_DIR@/bin/clang"
-config.host_os = "@HOST_OS@"
-config.llvm_src_root = "@LLVM_SOURCE_DIR@"
-config.compiler_rt_src_root = "@COMPILER_RT_SOURCE_DIR@"
-config.llvm_tools_dir = "@LLVM_TOOLS_DIR@"
-config.target_triple = "@TARGET_TRIPLE@"
+# Load common config for all compiler-rt lit tests.
+lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/lib/lit.common.configured")
-# LLVM tools dir can be passed in lit parameters, so try to
-# apply substitution.
-try:
- config.llvm_tools_dir = config.llvm_tools_dir % lit.params
-except KeyError,e:
- key, = e.args
- lit.fatal("unable to find %r parameter, use '--param=%s=VALUE'" % (key, key))
-
-# Let the main config do the real work.
-lit.load_config(config, "@CMAKE_CURRENT_SOURCE_DIR@/lit.cfg")
+# 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
index dd6fa0964f4a..d60cd5700a8a 100644
--- a/lib/tsan/lit_tests/load_shared_lib.cc
+++ b/lib/tsan/lit_tests/load_shared_lib.cc
@@ -4,7 +4,7 @@
// 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 && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
#include <dlfcn.h>
#include <pthread.h>
diff --git a/lib/tsan/lit_tests/longjmp3.cc b/lib/tsan/lit_tests/longjmp3.cc
index 87fabd0b3be2..ae2cfd05fe1a 100644
--- a/lib/tsan/lit_tests/longjmp3.cc
+++ b/lib/tsan/lit_tests/longjmp3.cc
@@ -1,4 +1,4 @@
-// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clang_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
diff --git a/lib/tsan/lit_tests/longjmp4.cc b/lib/tsan/lit_tests/longjmp4.cc
index a8764dda5a6b..6b0526ef3a66 100644
--- a/lib/tsan/lit_tests/longjmp4.cc
+++ b/lib/tsan/lit_tests/longjmp4.cc
@@ -1,4 +1,4 @@
-// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clang_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
diff --git a/lib/tsan/lit_tests/malloc_overflow.cc b/lib/tsan/lit_tests/malloc_overflow.cc
index 19423c5f93f1..afbebc8bec44 100644
--- a/lib/tsan/lit_tests/malloc_overflow.cc
+++ b/lib/tsan/lit_tests/malloc_overflow.cc
@@ -1,4 +1,5 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// 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>
diff --git a/lib/tsan/lit_tests/malloc_stack.cc b/lib/tsan/lit_tests/malloc_stack.cc
index c185623ff5ca..3603497ef311 100644
--- a/lib/tsan/lit_tests/malloc_stack.cc
+++ b/lib/tsan/lit_tests/malloc_stack.cc
@@ -1,4 +1,4 @@
-// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clang_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
#include <pthread.h>
#include <unistd.h>
diff --git a/lib/tsan/lit_tests/memcpy_race.cc b/lib/tsan/lit_tests/memcpy_race.cc
index 857728ba0540..8f39113674d6 100644
--- a/lib/tsan/lit_tests/memcpy_race.cc
+++ b/lib/tsan/lit_tests/memcpy_race.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
#include <pthread.h>
#include <stddef.h>
#include <stdio.h>
diff --git a/lib/tsan/lit_tests/mop_with_offset.cc b/lib/tsan/lit_tests/mop_with_offset.cc
index 0c11ef6b9187..2b6a4ff50aaf 100644
--- a/lib/tsan/lit_tests/mop_with_offset.cc
+++ b/lib/tsan/lit_tests/mop_with_offset.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
#include <pthread.h>
#include <stddef.h>
#include <stdio.h>
diff --git a/lib/tsan/lit_tests/mop_with_offset2.cc b/lib/tsan/lit_tests/mop_with_offset2.cc
index ee0d64a0afbf..037c4db5f524 100644
--- a/lib/tsan/lit_tests/mop_with_offset2.cc
+++ b/lib/tsan/lit_tests/mop_with_offset2.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
#include <pthread.h>
#include <stddef.h>
#include <stdio.h>
diff --git a/lib/tsan/lit_tests/mutex_destroy_locked.cc b/lib/tsan/lit_tests/mutex_destroy_locked.cc
index 27a04248b172..9b020d31b94c 100644
--- a/lib/tsan/lit_tests/mutex_destroy_locked.cc
+++ b/lib/tsan/lit_tests/mutex_destroy_locked.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
#include <pthread.h>
#include <unistd.h>
diff --git a/lib/tsan/lit_tests/mutex_robust.cc b/lib/tsan/lit_tests/mutex_robust.cc
new file mode 100644
index 000000000000..b826616076ae
--- /dev/null
+++ b/lib/tsan/lit_tests/mutex_robust.cc
@@ -0,0 +1,36 @@
+// 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
new file mode 100644
index 000000000000..5bd7ff682d1b
--- /dev/null
+++ b/lib/tsan/lit_tests/mutex_robust2.cc
@@ -0,0 +1,41 @@
+// 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
index f32a770ab075..ca87a7ba047d 100644
--- a/lib/tsan/lit_tests/mutexset1.cc
+++ b/lib/tsan/lit_tests/mutexset1.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
diff --git a/lib/tsan/lit_tests/mutexset2.cc b/lib/tsan/lit_tests/mutexset2.cc
index 15d230332512..9ccf952b0050 100644
--- a/lib/tsan/lit_tests/mutexset2.cc
+++ b/lib/tsan/lit_tests/mutexset2.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
diff --git a/lib/tsan/lit_tests/mutexset3.cc b/lib/tsan/lit_tests/mutexset3.cc
index 6ac7ad15e4f9..272ddafb3c4a 100644
--- a/lib/tsan/lit_tests/mutexset3.cc
+++ b/lib/tsan/lit_tests/mutexset3.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
diff --git a/lib/tsan/lit_tests/mutexset4.cc b/lib/tsan/lit_tests/mutexset4.cc
index 75684cf9ae5b..be751fa92bf0 100644
--- a/lib/tsan/lit_tests/mutexset4.cc
+++ b/lib/tsan/lit_tests/mutexset4.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
diff --git a/lib/tsan/lit_tests/mutexset5.cc b/lib/tsan/lit_tests/mutexset5.cc
index 6e75810aff22..e013edb4656a 100644
--- a/lib/tsan/lit_tests/mutexset5.cc
+++ b/lib/tsan/lit_tests/mutexset5.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
diff --git a/lib/tsan/lit_tests/mutexset6.cc b/lib/tsan/lit_tests/mutexset6.cc
index 4b19a12e0434..f5e6e66becf8 100644
--- a/lib/tsan/lit_tests/mutexset6.cc
+++ b/lib/tsan/lit_tests/mutexset6.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
diff --git a/lib/tsan/lit_tests/mutexset7.cc b/lib/tsan/lit_tests/mutexset7.cc
index 3ec1b5202983..51451b215490 100644
--- a/lib/tsan/lit_tests/mutexset7.cc
+++ b/lib/tsan/lit_tests/mutexset7.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
diff --git a/lib/tsan/lit_tests/mutexset8.cc b/lib/tsan/lit_tests/mutexset8.cc
index 6db63f7d16db..8822b050e939 100644
--- a/lib/tsan/lit_tests/mutexset8.cc
+++ b/lib/tsan/lit_tests/mutexset8.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
diff --git a/lib/tsan/lit_tests/oob_race.cc b/lib/tsan/lit_tests/oob_race.cc
index 2e7f0593fd8d..9d8e2220d9a5 100644
--- a/lib/tsan/lit_tests/oob_race.cc
+++ b/lib/tsan/lit_tests/oob_race.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
#include <pthread.h>
#include <stdio.h>
diff --git a/lib/tsan/lit_tests/race_on_barrier.c b/lib/tsan/lit_tests/race_on_barrier.c
index 3e76f8bf5e20..3c0199dec22e 100644
--- a/lib/tsan/lit_tests/race_on_barrier.c
+++ b/lib/tsan/lit_tests/race_on_barrier.c
@@ -1,4 +1,4 @@
-// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clang_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
#include <pthread.h>
#include <stdio.h>
#include <stddef.h>
diff --git a/lib/tsan/lit_tests/race_on_barrier2.c b/lib/tsan/lit_tests/race_on_barrier2.c
index 46a4f50b133d..62773d43e66e 100644
--- a/lib/tsan/lit_tests/race_on_barrier2.c
+++ b/lib/tsan/lit_tests/race_on_barrier2.c
@@ -1,4 +1,4 @@
-// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clang_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
#include <pthread.h>
#include <stdio.h>
#include <stddef.h>
diff --git a/lib/tsan/lit_tests/race_on_heap.cc b/lib/tsan/lit_tests/race_on_heap.cc
index 35434eac1850..a84c0de96558 100644
--- a/lib/tsan/lit_tests/race_on_heap.cc
+++ b/lib/tsan/lit_tests/race_on_heap.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
diff --git a/lib/tsan/lit_tests/race_on_mutex.c b/lib/tsan/lit_tests/race_on_mutex.c
index aff32f9bb1a2..e66341414831 100644
--- a/lib/tsan/lit_tests/race_on_mutex.c
+++ b/lib/tsan/lit_tests/race_on_mutex.c
@@ -1,4 +1,4 @@
-// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clang_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
#include <pthread.h>
#include <stdio.h>
#include <stddef.h>
diff --git a/lib/tsan/lit_tests/race_on_mutex2.c b/lib/tsan/lit_tests/race_on_mutex2.c
index 84bef75a3449..80c395e1f9ce 100644
--- a/lib/tsan/lit_tests/race_on_mutex2.c
+++ b/lib/tsan/lit_tests/race_on_mutex2.c
@@ -1,4 +1,4 @@
-// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clang_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
#include <pthread.h>
#include <stdio.h>
#include <stddef.h>
diff --git a/lib/tsan/lit_tests/race_on_read.cc b/lib/tsan/lit_tests/race_on_read.cc
index 7d226814816e..4ca4b25bfa81 100644
--- a/lib/tsan/lit_tests/race_on_read.cc
+++ b/lib/tsan/lit_tests/race_on_read.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
diff --git a/lib/tsan/lit_tests/race_on_write.cc b/lib/tsan/lit_tests/race_on_write.cc
index f1b0bb1cbd6e..8a56c8464b91 100644
--- a/lib/tsan/lit_tests/race_on_write.cc
+++ b/lib/tsan/lit_tests/race_on_write.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
diff --git a/lib/tsan/lit_tests/race_with_finished_thread.cc b/lib/tsan/lit_tests/race_with_finished_thread.cc
index a267290e661e..c713c67a398e 100644
--- a/lib/tsan/lit_tests/race_with_finished_thread.cc
+++ b/lib/tsan/lit_tests/race_with_finished_thread.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
#include <pthread.h>
#include <stddef.h>
#include <stdio.h>
diff --git a/lib/tsan/lit_tests/signal_errno.cc b/lib/tsan/lit_tests/signal_errno.cc
index 8181555f6f63..2febca38294e 100644
--- a/lib/tsan/lit_tests/signal_errno.cc
+++ b/lib/tsan/lit_tests/signal_errno.cc
@@ -1,4 +1,4 @@
-// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clang_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
diff --git a/lib/tsan/lit_tests/signal_malloc.cc b/lib/tsan/lit_tests/signal_malloc.cc
index 4dbc2f78ab17..ef180b8a25b6 100644
--- a/lib/tsan/lit_tests/signal_malloc.cc
+++ b/lib/tsan/lit_tests/signal_malloc.cc
@@ -1,4 +1,4 @@
-// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clang_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
diff --git a/lib/tsan/lit_tests/sigsuspend.cc b/lib/tsan/lit_tests/sigsuspend.cc
new file mode 100644
index 000000000000..78d507fa0af5
--- /dev/null
+++ b/lib/tsan/lit_tests/sigsuspend.cc
@@ -0,0 +1,38 @@
+// 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
index 44aff897406a..80a83e01a294 100644
--- a/lib/tsan/lit_tests/simple_race.c
+++ b/lib/tsan/lit_tests/simple_race.c
@@ -1,4 +1,4 @@
-// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clang_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
#include <pthread.h>
#include <stdio.h>
diff --git a/lib/tsan/lit_tests/simple_race.cc b/lib/tsan/lit_tests/simple_race.cc
index 99cf228ac2f2..47854cfd9a3e 100644
--- a/lib/tsan/lit_tests/simple_race.cc
+++ b/lib/tsan/lit_tests/simple_race.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
#include <pthread.h>
#include <stdio.h>
diff --git a/lib/tsan/lit_tests/simple_stack.c b/lib/tsan/lit_tests/simple_stack.c
index 4539cb7c1f37..a447e2880447 100644
--- a/lib/tsan/lit_tests/simple_stack.c
+++ b/lib/tsan/lit_tests/simple_stack.c
@@ -1,4 +1,4 @@
-// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clang_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
diff --git a/lib/tsan/lit_tests/simple_stack2.cc b/lib/tsan/lit_tests/simple_stack2.cc
index bf27a15ffad5..7a034c4cd6ed 100644
--- a/lib/tsan/lit_tests/simple_stack2.cc
+++ b/lib/tsan/lit_tests/simple_stack2.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
diff --git a/lib/tsan/lit_tests/sleep_sync.cc b/lib/tsan/lit_tests/sleep_sync.cc
index c3d47d311749..217a52a097ce 100644
--- a/lib/tsan/lit_tests/sleep_sync.cc
+++ b/lib/tsan/lit_tests/sleep_sync.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
#include <pthread.h>
#include <unistd.h>
diff --git a/lib/tsan/lit_tests/sleep_sync2.cc b/lib/tsan/lit_tests/sleep_sync2.cc
index d9961bccc808..e22999279f9f 100644
--- a/lib/tsan/lit_tests/sleep_sync2.cc
+++ b/lib/tsan/lit_tests/sleep_sync2.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
#include <pthread.h>
#include <unistd.h>
diff --git a/lib/tsan/lit_tests/stack_race.cc b/lib/tsan/lit_tests/stack_race.cc
index beeb57353bf3..7fabce22a85c 100644
--- a/lib/tsan/lit_tests/stack_race.cc
+++ b/lib/tsan/lit_tests/stack_race.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
#include <pthread.h>
#include <stddef.h>
diff --git a/lib/tsan/lit_tests/stack_race2.cc b/lib/tsan/lit_tests/stack_race2.cc
index 5bdf1bd664a1..c759ec92774f 100644
--- a/lib/tsan/lit_tests/stack_race2.cc
+++ b/lib/tsan/lit_tests/stack_race2.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
#include <pthread.h>
#include <stddef.h>
#include <unistd.h>
diff --git a/lib/tsan/lit_tests/static_init3.cc b/lib/tsan/lit_tests/static_init3.cc
index 40fd4b940f55..70a3c16878ca 100644
--- a/lib/tsan/lit_tests/static_init3.cc
+++ b/lib/tsan/lit_tests/static_init3.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
diff --git a/lib/tsan/lit_tests/suppress_same_address.cc b/lib/tsan/lit_tests/suppress_same_address.cc
index 174d1cc8fcb3..c516f89529f3 100644
--- a/lib/tsan/lit_tests/suppress_same_address.cc
+++ b/lib/tsan/lit_tests/suppress_same_address.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
#include <pthread.h>
int X;
diff --git a/lib/tsan/lit_tests/suppress_same_stacks.cc b/lib/tsan/lit_tests/suppress_same_stacks.cc
index 32bff9d50071..f0ab8b30435e 100644
--- a/lib/tsan/lit_tests/suppress_same_stacks.cc
+++ b/lib/tsan/lit_tests/suppress_same_stacks.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
#include <pthread.h>
volatile int N; // Prevent loop unrolling.
diff --git a/lib/tsan/lit_tests/suppressions_global.cc b/lib/tsan/lit_tests/suppressions_global.cc
new file mode 100644
index 000000000000..181cb56cf2e6
--- /dev/null
+++ b/lib/tsan/lit_tests/suppressions_global.cc
@@ -0,0 +1,29 @@
+// 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
new file mode 100644
index 000000000000..5fa8a2e43a93
--- /dev/null
+++ b/lib/tsan/lit_tests/suppressions_global.cc.supp
@@ -0,0 +1,2 @@
+race:RacyGlobal
+
diff --git a/lib/tsan/lit_tests/suppressions_race.cc b/lib/tsan/lit_tests/suppressions_race.cc
new file mode 100644
index 000000000000..c88e69bec6a3
--- /dev/null
+++ b/lib/tsan/lit_tests/suppressions_race.cc
@@ -0,0 +1,31 @@
+// 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
new file mode 100644
index 000000000000..cbdba76ea93a
--- /dev/null
+++ b/lib/tsan/lit_tests/suppressions_race.cc.supp
@@ -0,0 +1,2 @@
+race:Thread1
+
diff --git a/lib/tsan/lit_tests/suppressions_race2.cc b/lib/tsan/lit_tests/suppressions_race2.cc
new file mode 100644
index 000000000000..57146f96a428
--- /dev/null
+++ b/lib/tsan/lit_tests/suppressions_race2.cc
@@ -0,0 +1,31 @@
+// 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
new file mode 100644
index 000000000000..b3c4dbc59363
--- /dev/null
+++ b/lib/tsan/lit_tests/suppressions_race2.cc.supp
@@ -0,0 +1,2 @@
+race:Thread2
+
diff --git a/lib/tsan/lit_tests/test_output.sh b/lib/tsan/lit_tests/test_output.sh
index 1eedf6eb20a3..79e773aa2c98 100755
--- a/lib/tsan/lit_tests/test_output.sh
+++ b/lib/tsan/lit_tests/test_output.sh
@@ -13,7 +13,7 @@ BLACKLIST=$ROOTDIR/lit_tests/Helpers/blacklist.txt
# TODO: add testing for all of -O0...-O3
CFLAGS="-fsanitize=thread -fsanitize-blacklist=$BLACKLIST -fPIE -O1 -g -Wall"
-LDFLAGS="-pie -lpthread -ldl $ROOTDIR/rtl/libtsan.a"
+LDFLAGS="-pie -lpthread -ldl -lrt -Wl,--whole-archive $ROOTDIR/rtl/libtsan.a -Wl,--no-whole-archive"
test_file() {
SRC=$1
@@ -40,6 +40,10 @@ if [ "$1" == "" ]; 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
diff --git a/lib/tsan/lit_tests/thread_leak3.c b/lib/tsan/lit_tests/thread_leak3.c
index 3577164cad4a..5f447dbdbdf3 100644
--- a/lib/tsan/lit_tests/thread_leak3.c
+++ b/lib/tsan/lit_tests/thread_leak3.c
@@ -1,4 +1,4 @@
-// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clang_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
#include <pthread.h>
#include <unistd.h>
diff --git a/lib/tsan/lit_tests/thread_leak5.c b/lib/tsan/lit_tests/thread_leak5.c
index fc72b149ec25..329f7233a38a 100644
--- a/lib/tsan/lit_tests/thread_leak5.c
+++ b/lib/tsan/lit_tests/thread_leak5.c
@@ -1,4 +1,4 @@
-// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clang_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
#include <pthread.h>
#include <unistd.h>
diff --git a/lib/tsan/lit_tests/thread_name.cc b/lib/tsan/lit_tests/thread_name.cc
index 37f308ffbc0c..646ab5836241 100644
--- a/lib/tsan/lit_tests/thread_name.cc
+++ b/lib/tsan/lit_tests/thread_name.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
diff --git a/lib/tsan/lit_tests/thread_name2.cc b/lib/tsan/lit_tests/thread_name2.cc
new file mode 100644
index 000000000000..8c5cb741f61f
--- /dev/null
+++ b/lib/tsan/lit_tests/thread_name2.cc
@@ -0,0 +1,32 @@
+// 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
index 44cc1332f2ab..f77e1606c1dd 100644
--- a/lib/tsan/lit_tests/tiny_race.c
+++ b/lib/tsan/lit_tests/tiny_race.c
@@ -1,15 +1,21 @@
-// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// 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, NULL, Thread1, NULL);
+ pthread_create(&t, 0, Thread1, 0);
Global = 43;
- pthread_join(t, NULL);
+ 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
index bed6aafaacfc..3cbcc9dbba42 100644
--- a/lib/tsan/lit_tests/tls_race.cc
+++ b/lib/tsan/lit_tests/tls_race.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
#include <pthread.h>
#include <stddef.h>
diff --git a/lib/tsan/lit_tests/tls_race2.cc b/lib/tsan/lit_tests/tls_race2.cc
index 110abaa6a9df..136087065c12 100644
--- a/lib/tsan/lit_tests/tls_race2.cc
+++ b/lib/tsan/lit_tests/tls_race2.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
#include <pthread.h>
#include <stddef.h>
#include <unistd.h>
diff --git a/lib/tsan/lit_tests/unaligned_race.cc b/lib/tsan/lit_tests/unaligned_race.cc
index 18bed8555cc5..6ac87b577ec5 100644
--- a/lib/tsan/lit_tests/unaligned_race.cc
+++ b/lib/tsan/lit_tests/unaligned_race.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
diff --git a/lib/tsan/lit_tests/vptr_harmful_race.cc b/lib/tsan/lit_tests/vptr_harmful_race.cc
index 76d31c00ad4f..0105c4cedd99 100644
--- a/lib/tsan/lit_tests/vptr_harmful_race.cc
+++ b/lib/tsan/lit_tests/vptr_harmful_race.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
#include <pthread.h>
#include <semaphore.h>
#include <stdio.h>
diff --git a/lib/tsan/lit_tests/vptr_harmful_race2.cc b/lib/tsan/lit_tests/vptr_harmful_race2.cc
index d7e1d19a11bd..378790c62340 100644
--- a/lib/tsan/lit_tests/vptr_harmful_race2.cc
+++ b/lib/tsan/lit_tests/vptr_harmful_race2.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
#include <pthread.h>
#include <semaphore.h>
#include <stdio.h>
diff --git a/lib/tsan/lit_tests/write_in_reader_lock.cc b/lib/tsan/lit_tests/write_in_reader_lock.cc
index db8bac32b6e4..e872fe3ff960 100644
--- a/lib/tsan/lit_tests/write_in_reader_lock.cc
+++ b/lib/tsan/lit_tests/write_in_reader_lock.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
#include <pthread.h>
#include <unistd.h>
diff --git a/lib/tsan/rtl/CMakeLists.txt b/lib/tsan/rtl/CMakeLists.txt
deleted file mode 100644
index f1a8ff4d6558..000000000000
--- a/lib/tsan/rtl/CMakeLists.txt
+++ /dev/null
@@ -1,51 +0,0 @@
-set(TSAN_SOURCES
- tsan_clock.cc
- tsan_flags.cc
- tsan_fd.cc
- tsan_interceptors.cc
- tsan_interface_ann.cc
- tsan_interface_atomic.cc
- tsan_interface.cc
- tsan_interface_java.cc
- tsan_md5.cc
- tsan_mman.cc
- tsan_mutex.cc
- tsan_mutexset.cc
- tsan_report.cc
- tsan_rtl.cc
- tsan_rtl_mutex.cc
- tsan_rtl_report.cc
- tsan_rtl_thread.cc
- tsan_stat.cc
- tsan_suppressions.cc
- tsan_symbolize.cc
- tsan_sync.cc
- )
-
-if(APPLE)
- list(APPEND TSAN_SOURCES tsan_platform_mac.cc)
-elseif(UNIX)
- # Assume Linux
- list(APPEND TSAN_SOURCES
- tsan_platform_linux.cc
- tsan_symbolize_addr2line_linux.cc)
-endif()
-
-set(TSAN_RUNTIME_LIBRARIES)
-# TSan is currently supported on 64-bit Linux only.
-if(CAN_TARGET_x86_64 AND UNIX AND NOT APPLE)
- set(TSAN_ASM_SOURCES tsan_rtl_amd64.S)
- # Pass ASM file directly to the C++ compiler.
- set_source_files_properties(${TSAN_ASM_SOURCES} PROPERTIES
- LANGUAGE C)
- set(arch "x86_64")
- add_compiler_rt_static_runtime(clang_rt.tsan-${arch} ${arch}
- SOURCES ${TSAN_SOURCES} ${TSAN_ASM_SOURCES}
- $<TARGET_OBJECTS:RTInterception.${arch}>
- $<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
- $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>
- CFLAGS ${TSAN_CFLAGS}
- DEFS ${TSAN_COMMON_DEFINITIONS}
- SYMS tsan.syms)
- list(APPEND TSAN_RUNTIME_LIBRARIES clang_rt.tsan-${arch})
-endif()
diff --git a/lib/tsan/rtl/tsan.syms b/lib/tsan/rtl/tsan.syms
deleted file mode 100644
index 4464a0a231c9..000000000000
--- a/lib/tsan/rtl/tsan.syms
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- __tsan_*;
- __sanitizer_syscall_pre_*;
- __sanitizer_syscall_post_*;
-};
diff --git a/lib/tsan/rtl/tsan.syms.extra b/lib/tsan/rtl/tsan.syms.extra
new file mode 100644
index 000000000000..49ed6b46629e
--- /dev/null
+++ b/lib/tsan/rtl/tsan.syms.extra
@@ -0,0 +1,14 @@
+__tsan_init
+__tsan_read*
+__tsan_write*
+__tsan_vptr*
+__tsan_func*
+__tsan_atomic*
+__tsan_java*
+__tsan_unaligned*
+__tsan_release
+__tsan_acquire
+Annotate*
+WTFAnnotate*
+RunningOnValgrind
+ValgrindSlowdown
diff --git a/lib/tsan/rtl/tsan_defs.h b/lib/tsan/rtl/tsan_defs.h
index 7150e2e255d8..1e53a8e02f0a 100644
--- a/lib/tsan/rtl/tsan_defs.h
+++ b/lib/tsan/rtl/tsan_defs.h
@@ -41,10 +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;
-#ifndef TSAN_GO
-const int kShadowStackSize = 4 * 1024;
-const int kTraceStackSize = 256;
-#endif
+const uptr kShadowStackSize = 64 * 1024;
+const uptr kTraceStackSize = 256;
#ifdef TSAN_SHADOW_COUNT
# if TSAN_SHADOW_COUNT == 2 \
@@ -162,7 +160,6 @@ class ReportDesc;
class RegionAlloc;
class StackTrace;
struct MBlock;
-struct Suppression;
} // namespace __tsan
diff --git a/lib/tsan/rtl/tsan_fd.cc b/lib/tsan/rtl/tsan_fd.cc
index 14bdbb53b322..86db119fc918 100644
--- a/lib/tsan/rtl/tsan_fd.cc
+++ b/lib/tsan/rtl/tsan_fd.cc
@@ -42,6 +42,11 @@ struct FdContext {
static FdContext fdctx;
+static bool bogusfd(int fd) {
+ // Apparently a bogus fd value.
+ return fd < 0 || fd >= (1 << 30);
+}
+
static FdSync *allocsync() {
FdSync *s = (FdSync*)internal_alloc(MBlockFD, sizeof(FdSync));
atomic_store(&s->rc, 1, memory_order_relaxed);
@@ -69,6 +74,7 @@ static void unref(ThreadState *thr, uptr pc, FdSync *s) {
}
static FdDesc *fddesc(ThreadState *thr, uptr pc, int fd) {
+ CHECK_GE(fd, 0);
CHECK_LT(fd, kTableSize);
atomic_uintptr_t *pl1 = &fdctx.tab[fd / kTableSizeL2];
uptr l1 = atomic_load(pl1, memory_order_consume);
@@ -148,6 +154,8 @@ bool FdLocation(uptr addr, int *fd, int *tid, u32 *stack) {
}
void FdAcquire(ThreadState *thr, uptr pc, int fd) {
+ if (bogusfd(fd))
+ return;
FdDesc *d = fddesc(thr, pc, fd);
FdSync *s = d->sync;
DPrintf("#%d: FdAcquire(%d) -> %p\n", thr->tid, fd, s);
@@ -157,22 +165,28 @@ void FdAcquire(ThreadState *thr, uptr pc, int fd) {
}
void FdRelease(ThreadState *thr, uptr pc, int fd) {
+ if (bogusfd(fd))
+ return;
FdDesc *d = fddesc(thr, pc, fd);
FdSync *s = d->sync;
DPrintf("#%d: FdRelease(%d) -> %p\n", thr->tid, fd, s);
+ MemoryRead(thr, pc, (uptr)d, kSizeLog8);
if (s)
Release(thr, pc, (uptr)s);
- MemoryRead(thr, pc, (uptr)d, kSizeLog8);
}
void FdAccess(ThreadState *thr, uptr pc, int fd) {
DPrintf("#%d: FdAccess(%d)\n", thr->tid, fd);
+ if (bogusfd(fd))
+ return;
FdDesc *d = fddesc(thr, pc, fd);
MemoryRead(thr, pc, (uptr)d, kSizeLog8);
}
void FdClose(ThreadState *thr, uptr pc, int fd) {
DPrintf("#%d: FdClose(%d)\n", thr->tid, fd);
+ if (bogusfd(fd))
+ return;
FdDesc *d = fddesc(thr, pc, fd);
// To catch races between fd usage and close.
MemoryWrite(thr, pc, (uptr)d, kSizeLog8);
@@ -187,11 +201,15 @@ void FdClose(ThreadState *thr, uptr pc, int fd) {
void FdFileCreate(ThreadState *thr, uptr pc, int fd) {
DPrintf("#%d: FdFileCreate(%d)\n", thr->tid, fd);
+ if (bogusfd(fd))
+ return;
init(thr, pc, fd, &fdctx.filesync);
}
void FdDup(ThreadState *thr, uptr pc, int oldfd, int newfd) {
DPrintf("#%d: FdDup(%d, %d)\n", thr->tid, oldfd, newfd);
+ if (bogusfd(oldfd) || bogusfd(newfd))
+ return;
// Ignore the case when user dups not yet connected socket.
FdDesc *od = fddesc(thr, pc, oldfd);
MemoryRead(thr, pc, (uptr)od, kSizeLog8);
@@ -209,32 +227,44 @@ void FdPipeCreate(ThreadState *thr, uptr pc, int rfd, int wfd) {
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());
}
void FdSignalCreate(ThreadState *thr, uptr pc, int fd) {
DPrintf("#%d: FdSignalCreate(%d)\n", thr->tid, fd);
+ if (bogusfd(fd))
+ return;
init(thr, pc, fd, 0);
}
void FdInotifyCreate(ThreadState *thr, uptr pc, int fd) {
DPrintf("#%d: FdInotifyCreate(%d)\n", thr->tid, fd);
+ if (bogusfd(fd))
+ return;
init(thr, pc, fd, 0);
}
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());
}
void FdSocketCreate(ThreadState *thr, uptr pc, int fd) {
DPrintf("#%d: FdSocketCreate(%d)\n", thr->tid, fd);
+ if (bogusfd(fd))
+ return;
// It can be a UDP socket.
init(thr, pc, fd, &fdctx.socksync);
}
void FdSocketAccept(ThreadState *thr, uptr pc, int fd, int newfd) {
DPrintf("#%d: FdSocketAccept(%d, %d)\n", thr->tid, fd, newfd);
+ if (bogusfd(fd))
+ return;
// Synchronize connect->accept.
Acquire(thr, pc, (uptr)&fdctx.connectsync);
init(thr, pc, newfd, &fdctx.socksync);
@@ -242,12 +272,16 @@ void FdSocketAccept(ThreadState *thr, uptr pc, int fd, int newfd) {
void FdSocketConnecting(ThreadState *thr, uptr pc, int fd) {
DPrintf("#%d: FdSocketConnecting(%d)\n", thr->tid, fd);
+ if (bogusfd(fd))
+ return;
// Synchronize connect->accept.
Release(thr, pc, (uptr)&fdctx.connectsync);
}
void FdSocketConnect(ThreadState *thr, uptr pc, int fd) {
DPrintf("#%d: FdSocketConnect(%d)\n", thr->tid, fd);
+ if (bogusfd(fd))
+ return;
init(thr, pc, fd, &fdctx.socksync);
}
diff --git a/lib/tsan/rtl/tsan_flags.cc b/lib/tsan/rtl/tsan_flags.cc
index c062592f482d..c6f24bf49abd 100644
--- a/lib/tsan/rtl/tsan_flags.cc
+++ b/lib/tsan/rtl/tsan_flags.cc
@@ -26,13 +26,42 @@ Flags *flags() {
// Can be overriden in frontend.
#ifdef TSAN_EXTERNAL_HOOKS
void OverrideFlags(Flags *f);
+extern "C" const char* __tsan_default_options();
#else
-SANITIZER_INTERFACE_ATTRIBUTE
void WEAK OverrideFlags(Flags *f) {
(void)f;
}
+extern "C" 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");
+}
+
void InitializeFlags(Flags *f, const char *env) {
internal_memset(f, 0, sizeof(*f));
@@ -47,53 +76,35 @@ void InitializeFlags(Flags *f, const char *env) {
f->report_signal_unsafe = true;
f->report_atomic_races = true;
f->force_seq_cst_atomics = false;
- f->strip_path_prefix = "";
f->suppressions = "";
f->print_suppressions = false;
f->print_benign = false;
f->exitcode = 66;
- f->log_path = "stderr";
+ f->halt_on_error = false;
f->atexit_sleep_ms = 1000;
- f->verbosity = 0;
f->profile_memory = "";
f->flush_memory_ms = 0;
f->flush_symbolizer_ms = 5000;
+ f->memory_limit_mb = 0;
f->stop_on_start = false;
f->running_on_valgrind = false;
- f->external_symbolizer_path = "";
f->history_size = kGoMode ? 1 : 2; // There are a lot of goroutines in Go.
f->io_sync = 1;
+ CommonFlags *cf = common_flags();
+ SetCommonFlagDefaults();
+ *static_cast<CommonFlags*>(f) = *cf;
+
// Let a frontend override.
OverrideFlags(f);
-
+ ParseFlags(f, __tsan_default_options());
+ ParseCommonFlagsFromString(__tsan_default_options());
// Override from command line.
- 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->strip_path_prefix, "strip_path_prefix");
- 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->log_path, "log_path");
- ParseFlag(env, &f->atexit_sleep_ms, "atexit_sleep_ms");
- ParseFlag(env, &f->verbosity, "verbosity");
- 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->stop_on_start, "stop_on_start");
- ParseFlag(env, &f->external_symbolizer_path, "external_symbolizer_path");
- ParseFlag(env, &f->history_size, "history_size");
- ParseFlag(env, &f->io_sync, "io_sync");
+ ParseFlags(f, env);
+ ParseCommonFlagsFromString(env);
+ *static_cast<CommonFlags*>(f) = *cf;
+ // Sanity check.
if (!f->report_bugs) {
f->report_thread_leaks = false;
f->report_destroy_locked = false;
diff --git a/lib/tsan/rtl/tsan_flags.h b/lib/tsan/rtl/tsan_flags.h
index aaacd98a6223..3916df3cc9e1 100644
--- a/lib/tsan/rtl/tsan_flags.h
+++ b/lib/tsan/rtl/tsan_flags.h
@@ -20,9 +20,11 @@
// 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"
+
namespace __tsan {
-struct Flags {
+struct Flags : CommonFlags {
// Enable dynamic annotations, otherwise they are no-ops.
bool enable_annotations;
// Supress a race report if we've already output another race report
@@ -48,8 +50,6 @@ struct Flags {
// If set, all atomics are effectively sequentially consistent (seq_cst),
// regardless of what user actually specified.
bool force_seq_cst_atomics;
- // Strip that prefix from file paths in reports.
- const char *strip_path_prefix;
// Suppressions filename.
const char *suppressions;
// Print matched suppressions at exit.
@@ -58,27 +58,24 @@ struct Flags {
bool print_benign;
// Override exit status if something was reported.
int exitcode;
- // Write logs to "log_path.pid".
- // The special values are "stdout" and "stderr".
- // The default is "stderr".
- const char *log_path;
+ // Exit after first reported error.
+ bool halt_on_error;
// Sleep in main thread before exiting for that many ms
// (useful to catch "at exit" races).
int atexit_sleep_ms;
- // Verbosity level (0 - silent, 1 - a bit of output, 2+ - more output).
- int verbosity;
// If set, periodically write memory profile to that file.
const char *profile_memory;
// Flush shadow memory every X ms.
int flush_memory_ms;
// Flush symbolizer caches every X ms.
int flush_symbolizer_ms;
+ // Resident memory limit in MB to aim at.
+ // If the process consumes more memory, then TSan will flush shadow memory.
+ int memory_limit_mb;
// Stops on start until __tsan_resume() is called (for debugging).
bool stop_on_start;
// Controls whether RunningOnValgrind() returns true or false.
bool running_on_valgrind;
- // Path to external symbolizer.
- const char *external_symbolizer_path;
// Per-thread history size, controls how many previous memory accesses
// are remembered per thread. Possible values are [0..7].
// history_size=0 amounts to 32K memory accesses. Each next value doubles
diff --git a/lib/tsan/rtl/tsan_interceptors.cc b/lib/tsan/rtl/tsan_interceptors.cc
index f18b26f6abe4..ef38f7987cde 100644
--- a/lib/tsan/rtl/tsan_interceptors.cc
+++ b/lib/tsan/rtl/tsan_interceptors.cc
@@ -22,6 +22,7 @@
#include "interception/interception.h"
#include "tsan_interface.h"
#include "tsan_platform.h"
+#include "tsan_suppressions.h"
#include "tsan_rtl.h"
#include "tsan_mman.h"
#include "tsan_fd.h"
@@ -35,11 +36,6 @@ struct my_siginfo_t {
u64 opaque[128 / sizeof(u64)];
};
-struct sigset_t {
- // The size is determined by looking at sizeof of real sigset_t on linux.
- u64 val[128 / sizeof(u64)];
-};
-
struct ucontext_t {
// The size is determined by looking at sizeof of real ucontext_t on linux.
u64 opaque[936 / sizeof(u64) + 1];
@@ -47,15 +43,16 @@ struct ucontext_t {
extern "C" int pthread_attr_init(void *attr);
extern "C" int pthread_attr_destroy(void *attr);
-extern "C" int pthread_attr_getdetachstate(void *attr, int *v);
+DECLARE_REAL(int, pthread_attr_getdetachstate, void *, void *)
extern "C" int pthread_attr_setstacksize(void *attr, uptr stacksize);
-extern "C" int pthread_attr_getstacksize(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);
extern "C" int pthread_yield();
-extern "C" int pthread_sigmask(int how, const sigset_t *set, sigset_t *oldset);
-extern "C" int sigfillset(sigset_t *set);
+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)
extern "C" void *pthread_self();
extern "C" void _exit(int status);
extern "C" int *__errno_location();
@@ -67,9 +64,9 @@ extern "C" void __libc_free(void *ptr);
extern "C" int mallopt(int param, int value);
const int PTHREAD_MUTEX_RECURSIVE = 1;
const int PTHREAD_MUTEX_RECURSIVE_NP = 1;
-const int kPthreadAttrSize = 56;
const int EINVAL = 22;
const int EBUSY = 16;
+const int EOWNERDEAD = 130;
const int EPOLL_CTL_ADD = 1;
const int SIGILL = 4;
const int SIGABRT = 6;
@@ -77,6 +74,7 @@ const int SIGFPE = 8;
const int SIGSEGV = 11;
const int SIGPIPE = 13;
const int SIGBUS = 7;
+const int SIGSYS = 31;
void *const MAP_FAILED = (void*)-1;
const int PTHREAD_BARRIER_SERIAL_THREAD = -1;
const int MAP_FIXED = 0x10;
@@ -97,7 +95,7 @@ struct sigaction_t {
sighandler_t sa_handler;
void (*sa_sigaction)(int sig, my_siginfo_t *siginfo, void *uctx);
};
- sigset_t sa_mask;
+ __sanitizer_sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)();
};
@@ -128,6 +126,19 @@ struct SignalContext {
int pending_signal_count;
SignalDesc pending_signals[kSigCount];
};
+
+// The object is 64-byte aligned, because we want hot data to be located in
+// a single cache line if possible (it's accessed in every interceptor).
+static ALIGNED(64) char libignore_placeholder[sizeof(LibIgnore)];
+static LibIgnore *libignore() {
+ return reinterpret_cast<LibIgnore*>(&libignore_placeholder[0]);
+}
+
+void InitializeLibIgnore() {
+ libignore()->Init(*GetSuppressionContext());
+ libignore()->OnLibraryLoaded(0);
+}
+
} // namespace __tsan
static SignalContext *SigCtx(ThreadState *thr) {
@@ -150,12 +161,14 @@ class ScopedInterceptor {
private:
ThreadState *const thr_;
const int in_rtl_;
+ bool in_ignored_lib_;
};
ScopedInterceptor::ScopedInterceptor(ThreadState *thr, const char *fname,
uptr pc)
: thr_(thr)
- , in_rtl_(thr->in_rtl) {
+ , in_rtl_(thr->in_rtl)
+ , in_ignored_lib_(false) {
if (thr_->in_rtl == 0) {
Initialize(thr);
FuncEntry(thr, pc);
@@ -164,9 +177,18 @@ ScopedInterceptor::ScopedInterceptor(ThreadState *thr, const char *fname,
} else {
thr_->in_rtl++;
}
+ if (!thr_->in_ignored_lib && libignore()->IsIgnored(pc)) {
+ in_ignored_lib_ = true;
+ thr_->in_ignored_lib = true;
+ ThreadIgnoreBegin(thr_);
+ }
}
ScopedInterceptor::~ScopedInterceptor() {
+ if (in_ignored_lib_) {
+ thr_->in_ignored_lib = false;
+ ThreadIgnoreEnd(thr_);
+ }
thr_->in_rtl--;
if (thr_->in_rtl == 0) {
FuncExit(thr_);
@@ -181,8 +203,7 @@ ScopedInterceptor::~ScopedInterceptor() {
StatInc(thr, StatInt_##func); \
const uptr caller_pc = GET_CALLER_PC(); \
ScopedInterceptor si(thr, #func, caller_pc); \
- const uptr pc = __sanitizer::StackTrace::GetPreviousInstructionPc( \
- __sanitizer::StackTrace::GetCurrentPc()); \
+ const uptr pc = __sanitizer::StackTrace::GetCurrentPc(); \
(void)pc; \
/**/
@@ -192,7 +213,7 @@ ScopedInterceptor::~ScopedInterceptor() {
Printf("FATAL: ThreadSanitizer: failed to intercept %s\n", #func); \
Die(); \
} \
- if (thr->in_rtl > 1) \
+ if (thr->in_rtl > 1 || thr->in_ignored_lib) \
return REAL(func)(__VA_ARGS__); \
/**/
@@ -235,6 +256,28 @@ 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;
+}
+
+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;
+}
+
class AtExitContext {
public:
AtExitContext()
@@ -314,8 +357,14 @@ TSAN_INTERCEPTOR(int, __cxa_atexit, void (*f)(void *a), void *arg, void *dso) {
if (cur_thread()->in_symbolizer)
return 0;
SCOPED_TSAN_INTERCEPTOR(__cxa_atexit, f, arg, dso);
- if (dso)
- return REAL(__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);
}
@@ -362,27 +411,37 @@ static void LongJmp(ThreadState *thr, uptr *env) {
CHECK(0);
}
+// 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);
}
// Not called. Merely to satisfy TSAN_INTERCEPT().
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+int __interceptor_setjmp(void *env);
extern "C" int __interceptor_setjmp(void *env) {
CHECK(0);
return 0;
}
+// FIXME: any reason to have a separate declaration?
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+int __interceptor__setjmp(void *env);
extern "C" int __interceptor__setjmp(void *env) {
CHECK(0);
return 0;
}
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+int __interceptor_sigsetjmp(void *env);
extern "C" int __interceptor_sigsetjmp(void *env) {
CHECK(0);
return 0;
}
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+int __interceptor___sigsetjmp(void *env);
extern "C" int __interceptor___sigsetjmp(void *env) {
CHECK(0);
return 0;
@@ -433,7 +492,8 @@ TSAN_INTERCEPTOR(void*, __libc_memalign, uptr align, uptr sz) {
TSAN_INTERCEPTOR(void*, calloc, uptr size, uptr n) {
if (cur_thread()->in_symbolizer)
return __libc_calloc(size, n);
- if (__sanitizer::CallocShouldReturnNullDueToOverflow(size, n)) return 0;
+ if (__sanitizer::CallocShouldReturnNullDueToOverflow(size, n))
+ return AllocatorReturnNull();
void *p = 0;
{
SCOPED_INTERCEPTOR_RAW(calloc, size, n);
@@ -494,15 +554,26 @@ TSAN_INTERCEPTOR(uptr, malloc_usable_size, void *p) {
invoke_malloc_hook(p, size); \
return p;
+SANITIZER_INTERFACE_ATTRIBUTE
+void *operator new(__sanitizer::uptr size);
void *operator new(__sanitizer::uptr size) {
OPERATOR_NEW_BODY(_Znwm);
}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void *operator new[](__sanitizer::uptr size);
void *operator new[](__sanitizer::uptr size) {
OPERATOR_NEW_BODY(_Znam);
}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void *operator new(__sanitizer::uptr size, std::nothrow_t const&);
void *operator new(__sanitizer::uptr size, std::nothrow_t const&) {
OPERATOR_NEW_BODY(_ZnwmRKSt9nothrow_t);
}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void *operator new[](__sanitizer::uptr size, std::nothrow_t const&);
void *operator new[](__sanitizer::uptr size, std::nothrow_t const&) {
OPERATOR_NEW_BODY(_ZnamRKSt9nothrow_t);
}
@@ -515,15 +586,26 @@ void *operator new[](__sanitizer::uptr size, std::nothrow_t const&) {
SCOPED_INTERCEPTOR_RAW(mangled_name, ptr); \
user_free(thr, pc, ptr);
+SANITIZER_INTERFACE_ATTRIBUTE
+void operator delete(void *ptr);
void operator delete(void *ptr) {
OPERATOR_DELETE_BODY(_ZdlPv);
}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void operator delete[](void *ptr);
void operator delete[](void *ptr) {
OPERATOR_DELETE_BODY(_ZdlPvRKSt9nothrow_t);
}
+
+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);
}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void operator delete[](void *ptr, std::nothrow_t const&);
void operator delete[](void *ptr, std::nothrow_t const&) {
OPERATOR_DELETE_BODY(_ZdaPvRKSt9nothrow_t);
}
@@ -561,30 +643,6 @@ TSAN_INTERCEPTOR(int, memcmp, const void *s1, const void *s2, uptr n) {
return res;
}
-TSAN_INTERCEPTOR(int, strcmp, const char *s1, const char *s2) {
- SCOPED_TSAN_INTERCEPTOR(strcmp, s1, s2);
- uptr len = 0;
- for (; s1[len] && s2[len]; len++) {
- if (s1[len] != s2[len])
- break;
- }
- MemoryAccessRange(thr, pc, (uptr)s1, len + 1, false);
- MemoryAccessRange(thr, pc, (uptr)s2, len + 1, false);
- return s1[len] - s2[len];
-}
-
-TSAN_INTERCEPTOR(int, strncmp, const char *s1, const char *s2, uptr n) {
- SCOPED_TSAN_INTERCEPTOR(strncmp, s1, s2, n);
- uptr len = 0;
- for (; len < n && s1[len] && s2[len]; len++) {
- if (s1[len] != s2[len])
- break;
- }
- MemoryAccessRange(thr, pc, (uptr)s1, len < n ? len + 1 : n, false);
- MemoryAccessRange(thr, pc, (uptr)s2, len < n ? len + 1 : n, false);
- return len == n ? 0 : s1[len] - s2[len];
-}
-
TSAN_INTERCEPTOR(void*, memchr, void *s, int c, uptr n) {
SCOPED_TSAN_INTERCEPTOR(memchr, s, c, n);
void *res = REAL(memchr)(s, c, n);
@@ -654,6 +712,12 @@ TSAN_INTERCEPTOR(const char*, strstr, const char *s1, const char *s2) {
return res;
}
+TSAN_INTERCEPTOR(char*, strdup, const char *str) {
+ SCOPED_TSAN_INTERCEPTOR(strdup, str);
+ // strdup will call malloc, so no instrumentation is required here.
+ return REAL(strdup)(str);
+}
+
static bool fix_mmap_addr(void **addr, long_t sz, int flags) {
if (*addr) {
if (!IsAppMem((uptr)*addr) || !IsAppMem((uptr)*addr + sz - 1)) {
@@ -704,23 +768,23 @@ TSAN_INTERCEPTOR(int, munmap, void *addr, long_t sz) {
}
TSAN_INTERCEPTOR(void*, memalign, uptr align, uptr sz) {
- SCOPED_TSAN_INTERCEPTOR(memalign, align, sz);
+ SCOPED_INTERCEPTOR_RAW(memalign, align, sz);
return user_alloc(thr, pc, sz, align);
}
TSAN_INTERCEPTOR(void*, valloc, uptr sz) {
- SCOPED_TSAN_INTERCEPTOR(valloc, sz);
+ SCOPED_INTERCEPTOR_RAW(valloc, sz);
return user_alloc(thr, pc, sz, GetPageSizeCached());
}
TSAN_INTERCEPTOR(void*, pvalloc, uptr sz) {
- SCOPED_TSAN_INTERCEPTOR(pvalloc, sz);
+ SCOPED_INTERCEPTOR_RAW(pvalloc, sz);
sz = RoundUp(sz, GetPageSizeCached());
return user_alloc(thr, pc, sz, GetPageSizeCached());
}
TSAN_INTERCEPTOR(int, posix_memalign, void **memptr, uptr align, uptr sz) {
- SCOPED_TSAN_INTERCEPTOR(posix_memalign, memptr, align, sz);
+ SCOPED_INTERCEPTOR_RAW(posix_memalign, memptr, align, sz);
*memptr = user_alloc(thr, pc, sz, align);
return 0;
}
@@ -789,7 +853,8 @@ extern "C" void *__tsan_thread_start_func(void *arg) {
{
ThreadState *thr = cur_thread();
ScopedInRtl in_rtl;
- if (pthread_setspecific(g_thread_finalize_key, (void*)4)) {
+ if (pthread_setspecific(g_thread_finalize_key,
+ (void *)kPthreadDestructorIterations)) {
Printf("ThreadSanitizer: failed to set thread key\n");
Die();
}
@@ -809,21 +874,15 @@ extern "C" void *__tsan_thread_start_func(void *arg) {
TSAN_INTERCEPTOR(int, pthread_create,
void *th, void *attr, void *(*callback)(void*), void * param) {
- SCOPED_TSAN_INTERCEPTOR(pthread_create, th, attr, callback, param);
+ SCOPED_INTERCEPTOR_RAW(pthread_create, th, attr, callback, param);
__sanitizer_pthread_attr_t myattr;
if (attr == 0) {
pthread_attr_init(&myattr);
attr = &myattr;
}
int detached = 0;
- pthread_attr_getdetachstate(attr, &detached);
-
-#if defined(TSAN_DEBUG_OUTPUT)
- int verbosity = (TSAN_DEBUG_OUTPUT);
-#else
- int verbosity = 0;
-#endif
- AdjustStackSizeLinux(attr, verbosity);
+ REAL(pthread_attr_getdetachstate)(attr, &detached);
+ AdjustStackSizeLinux(attr);
ThreadParam p;
p.callback = callback;
@@ -843,7 +902,7 @@ TSAN_INTERCEPTOR(int, pthread_create,
}
TSAN_INTERCEPTOR(int, pthread_join, void *th, void **ret) {
- SCOPED_TSAN_INTERCEPTOR(pthread_join, th, ret);
+ SCOPED_INTERCEPTOR_RAW(pthread_join, th, ret);
int tid = ThreadTid(thr, pc, (uptr)th);
int res = BLOCK_REAL(pthread_join)(th, ret);
if (res == 0) {
@@ -887,21 +946,13 @@ TSAN_INTERCEPTOR(int, pthread_mutex_destroy, void *m) {
return res;
}
-TSAN_INTERCEPTOR(int, pthread_mutex_lock, void *m) {
- SCOPED_TSAN_INTERCEPTOR(pthread_mutex_lock, m);
- int res = REAL(pthread_mutex_lock)(m);
- if (res == 0) {
- MutexLock(thr, pc, (uptr)m);
- }
- return res;
-}
-
TSAN_INTERCEPTOR(int, pthread_mutex_trylock, void *m) {
SCOPED_TSAN_INTERCEPTOR(pthread_mutex_trylock, m);
int res = REAL(pthread_mutex_trylock)(m);
- if (res == 0) {
+ if (res == EOWNERDEAD)
+ MutexRepair(thr, pc, (uptr)m);
+ if (res == 0 || res == EOWNERDEAD)
MutexLock(thr, pc, (uptr)m);
- }
return res;
}
@@ -914,13 +965,6 @@ TSAN_INTERCEPTOR(int, pthread_mutex_timedlock, void *m, void *abstime) {
return res;
}
-TSAN_INTERCEPTOR(int, pthread_mutex_unlock, void *m) {
- SCOPED_TSAN_INTERCEPTOR(pthread_mutex_unlock, m);
- MutexUnlock(thr, pc, (uptr)m);
- int res = REAL(pthread_mutex_unlock)(m);
- return res;
-}
-
TSAN_INTERCEPTOR(int, pthread_spin_init, void *m, int pshared) {
SCOPED_TSAN_INTERCEPTOR(pthread_spin_init, m, pshared);
int res = REAL(pthread_spin_init)(m, pshared);
@@ -1043,45 +1087,18 @@ TSAN_INTERCEPTOR(int, pthread_rwlock_unlock, void *m) {
return res;
}
-// libpthread.so contains several versions of pthread_cond_init symbol.
-// When we just dlsym() it, we get the wrong (old) version.
-/*
-TSAN_INTERCEPTOR(int, pthread_cond_init, void *c, void *a) {
- SCOPED_TSAN_INTERCEPTOR(pthread_cond_init, c, a);
- int res = REAL(pthread_cond_init)(c, a);
- 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_signal, void *c) {
- SCOPED_TSAN_INTERCEPTOR(pthread_cond_signal, c);
- int res = REAL(pthread_cond_signal)(c);
- return res;
-}
-
-TSAN_INTERCEPTOR(int, pthread_cond_broadcast, void *c) {
- SCOPED_TSAN_INTERCEPTOR(pthread_cond_broadcast, c);
- int res = REAL(pthread_cond_broadcast)(c);
- return res;
-}
-
-TSAN_INTERCEPTOR(int, pthread_cond_wait, void *c, void *m) {
- SCOPED_TSAN_INTERCEPTOR(pthread_cond_wait, c, m);
- MutexUnlock(thr, pc, (uptr)m);
- int res = REAL(pthread_cond_wait)(c, m);
- MutexLock(thr, pc, (uptr)m);
- return res;
-}
-
-TSAN_INTERCEPTOR(int, pthread_cond_timedwait, void *c, void *m, void *abstime) {
+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;
@@ -1114,7 +1131,9 @@ TSAN_INTERCEPTOR(int, pthread_barrier_wait, void *b) {
}
TSAN_INTERCEPTOR(int, pthread_once, void *o, void (*f)()) {
- SCOPED_TSAN_INTERCEPTOR(pthread_once, o, 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);
@@ -1126,14 +1145,16 @@ TSAN_INTERCEPTOR(int, pthread_once, void *o, void (*f)()) {
(*f)();
CHECK_EQ(thr->in_rtl, 0);
thr->in_rtl = old_in_rtl;
- Release(thr, pc, (uptr)o);
+ if (!thr->in_ignored_lib)
+ Release(thr, pc, (uptr)o);
atomic_store(a, 2, memory_order_release);
} else {
while (v != 2) {
pthread_yield();
v = atomic_load(a, memory_order_acquire);
}
- Acquire(thr, pc, (uptr)o);
+ if (!thr->in_ignored_lib)
+ Acquire(thr, pc, (uptr)o);
}
return 0;
}
@@ -1392,22 +1413,6 @@ TSAN_INTERCEPTOR(int, listen, int fd, int backlog) {
return res;
}
-TSAN_INTERCEPTOR(int, accept, int fd, void *addr, unsigned *addrlen) {
- SCOPED_TSAN_INTERCEPTOR(accept, fd, addr, addrlen);
- int fd2 = REAL(accept)(fd, addr, addrlen);
- if (fd >= 0 && fd2 >= 0)
- FdSocketAccept(thr, pc, fd, fd2);
- return fd2;
-}
-
-TSAN_INTERCEPTOR(int, accept4, int fd, void *addr, unsigned *addrlen, int f) {
- SCOPED_TSAN_INTERCEPTOR(accept4, fd, addr, addrlen, f);
- int fd2 = REAL(accept4)(fd, addr, addrlen, f);
- if (fd >= 0 && fd2 >= 0)
- FdSocketAccept(thr, pc, fd, fd2);
- return fd2;
-}
-
TSAN_INTERCEPTOR(int, epoll_create, int size) {
SCOPED_TSAN_INTERCEPTOR(epoll_create, size);
int fd = REAL(epoll_create)(size);
@@ -1466,58 +1471,30 @@ TSAN_INTERCEPTOR(int, pipe2, int *pipefd, int flags) {
return res;
}
-TSAN_INTERCEPTOR(long_t, readv, int fd, void *vec, int cnt) {
- SCOPED_TSAN_INTERCEPTOR(readv, fd, vec, cnt);
- int res = REAL(readv)(fd, vec, cnt);
- if (res >= 0 && fd >= 0) {
- FdAcquire(thr, pc, fd);
- }
- return res;
-}
-
-TSAN_INTERCEPTOR(long_t, preadv64, int fd, void *vec, int cnt, u64 off) {
- SCOPED_TSAN_INTERCEPTOR(preadv64, fd, vec, cnt, off);
- int res = REAL(preadv64)(fd, vec, cnt, off);
- if (res >= 0 && fd >= 0) {
- FdAcquire(thr, pc, fd);
- }
- return res;
-}
-
-TSAN_INTERCEPTOR(long_t, writev, int fd, void *vec, int cnt) {
- SCOPED_TSAN_INTERCEPTOR(writev, fd, vec, cnt);
- if (fd >= 0)
- FdRelease(thr, pc, fd);
- int res = REAL(writev)(fd, vec, cnt);
- return res;
-}
-
-TSAN_INTERCEPTOR(long_t, pwritev64, int fd, void *vec, int cnt, u64 off) {
- SCOPED_TSAN_INTERCEPTOR(pwritev64, fd, vec, cnt, off);
- if (fd >= 0)
- FdRelease(thr, pc, fd);
- int res = REAL(pwritev64)(fd, vec, cnt, off);
- return res;
-}
-
TSAN_INTERCEPTOR(long_t, send, int fd, void *buf, long_t len, int flags) {
SCOPED_TSAN_INTERCEPTOR(send, fd, buf, len, flags);
- if (fd >= 0)
+ if (fd >= 0) {
+ FdAccess(thr, pc, fd);
FdRelease(thr, pc, fd);
+ }
int res = REAL(send)(fd, buf, len, flags);
return res;
}
TSAN_INTERCEPTOR(long_t, sendmsg, int fd, void *msg, int flags) {
SCOPED_TSAN_INTERCEPTOR(sendmsg, fd, msg, flags);
- if (fd >= 0)
+ if (fd >= 0) {
+ FdAccess(thr, pc, fd);
FdRelease(thr, pc, fd);
+ }
int res = REAL(sendmsg)(fd, msg, flags);
return res;
}
TSAN_INTERCEPTOR(long_t, recv, int fd, void *buf, long_t len, int flags) {
SCOPED_TSAN_INTERCEPTOR(recv, fd, buf, len, flags);
+ if (fd >= 0)
+ FdAccess(thr, pc, fd);
int res = REAL(recv)(fd, buf, len, flags);
if (res >= 0 && fd >= 0) {
FdAcquire(thr, pc, fd);
@@ -1525,15 +1502,6 @@ TSAN_INTERCEPTOR(long_t, recv, int fd, void *buf, long_t len, int flags) {
return res;
}
-TSAN_INTERCEPTOR(long_t, recvmsg, int fd, void *msg, int flags) {
- SCOPED_TSAN_INTERCEPTOR(recvmsg, fd, msg, flags);
- int res = REAL(recvmsg)(fd, msg, flags);
- if (res >= 0 && fd >= 0) {
- FdAcquire(thr, pc, fd);
- }
- return res;
-}
-
TSAN_INTERCEPTOR(int, unlink, char *path) {
SCOPED_TSAN_INTERCEPTOR(unlink, path);
Release(thr, pc, File2addr(path));
@@ -1571,6 +1539,7 @@ TSAN_INTERCEPTOR(void*, freopen, char *path, char *mode, void *stream) {
}
TSAN_INTERCEPTOR(int, fclose, void *stream) {
+ // libc file streams can call user-supplied functions, see fopencookie.
{
SCOPED_TSAN_INTERCEPTOR(fclose, stream);
if (stream) {
@@ -1583,6 +1552,7 @@ TSAN_INTERCEPTOR(int, fclose, void *stream) {
}
TSAN_INTERCEPTOR(uptr, fread, void *ptr, uptr size, uptr nmemb, void *f) {
+ // libc file streams can call user-supplied functions, see fopencookie.
{
SCOPED_TSAN_INTERCEPTOR(fread, ptr, size, nmemb, f);
MemoryAccessRange(thr, pc, (uptr)ptr, size * nmemb, true);
@@ -1591,6 +1561,7 @@ TSAN_INTERCEPTOR(uptr, fread, void *ptr, uptr size, uptr nmemb, void *f) {
}
TSAN_INTERCEPTOR(uptr, fwrite, const void *p, uptr size, uptr nmemb, void *f) {
+ // libc file streams can call user-supplied functions, see fopencookie.
{
SCOPED_TSAN_INTERCEPTOR(fwrite, p, size, nmemb, f);
MemoryAccessRange(thr, pc, (uptr)p, size * nmemb, false);
@@ -1599,7 +1570,10 @@ TSAN_INTERCEPTOR(uptr, fwrite, const void *p, uptr size, uptr nmemb, void *f) {
}
TSAN_INTERCEPTOR(int, fflush, void *stream) {
- SCOPED_TSAN_INTERCEPTOR(fflush, stream);
+ // libc file streams can call user-supplied functions, see fopencookie.
+ {
+ SCOPED_TSAN_INTERCEPTOR(fflush, stream);
+ }
return REAL(fflush)(stream);
}
@@ -1632,27 +1606,23 @@ TSAN_INTERCEPTOR(void*, opendir, char *path) {
TSAN_INTERCEPTOR(int, epoll_ctl, int epfd, int op, int fd, void *ev) {
SCOPED_TSAN_INTERCEPTOR(epoll_ctl, epfd, op, fd, ev);
- if (op == EPOLL_CTL_ADD && epfd >= 0) {
+ if (epfd >= 0)
+ FdAccess(thr, pc, epfd);
+ if (epfd >= 0 && fd >= 0)
+ FdAccess(thr, pc, fd);
+ if (op == EPOLL_CTL_ADD && epfd >= 0)
FdRelease(thr, pc, epfd);
- }
int res = REAL(epoll_ctl)(epfd, op, fd, ev);
- if (fd >= 0)
- FdAccess(thr, pc, fd);
return res;
}
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)
+ FdAccess(thr, pc, epfd);
int res = BLOCK_REAL(epoll_wait)(epfd, ev, cnt, timeout);
- if (res > 0 && epfd >= 0) {
+ if (res > 0 && epfd >= 0)
FdAcquire(thr, pc, epfd);
- }
- return res;
-}
-
-TSAN_INTERCEPTOR(int, poll, void *fds, long_t nfds, int timeout) {
- SCOPED_TSAN_INTERCEPTOR(poll, fds, nfds, timeout);
- int res = BLOCK_REAL(poll)(fds, nfds, timeout);
return res;
}
@@ -1662,7 +1632,7 @@ void ALWAYS_INLINE rtl_generic_sighandler(bool sigact, int sig,
SignalContext *sctx = SigCtx(thr);
// Don't mess with synchronous signals.
if (sig == SIGSEGV || sig == SIGBUS || sig == SIGILL ||
- sig == SIGABRT || sig == SIGFPE || sig == SIGPIPE ||
+ 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) ||
// If we are in blocking function, we can safely process it now
@@ -1714,7 +1684,7 @@ TSAN_INTERCEPTOR(int, sigaction, int sig, sigaction_t *act, sigaction_t *old) {
internal_memcpy(&sigactions[sig], act, sizeof(*act));
sigaction_t newact;
internal_memcpy(&newact, act, sizeof(newact));
- sigfillset(&newact.sa_mask);
+ REAL(sigfillset)(&newact.sa_mask);
if (act->sa_handler != SIG_IGN && act->sa_handler != SIG_DFL) {
if (newact.sa_flags & SA_SIGINFO)
newact.sa_sigaction = rtl_sigaction;
@@ -1737,6 +1707,11 @@ TSAN_INTERCEPTOR(sighandler_t, signal, int sig, sighandler_t h) {
return old.sa_handler;
}
+TSAN_INTERCEPTOR(int, sigsuspend, const __sanitizer_sigset_t *mask) {
+ SCOPED_TSAN_INTERCEPTOR(sigsuspend, mask);
+ return REAL(sigsuspend)(mask);
+}
+
TSAN_INTERCEPTOR(int, raise, int sig) {
SCOPED_TSAN_INTERCEPTOR(raise, sig);
SignalContext *sctx = SigCtx(thr);
@@ -1787,13 +1762,30 @@ TSAN_INTERCEPTOR(int, gettimeofday, void *tv, void *tz) {
return REAL(gettimeofday)(tv, tz);
}
+TSAN_INTERCEPTOR(int, getaddrinfo, void *node, void *service,
+ void *hints, void *rv) {
+ SCOPED_TSAN_INTERCEPTOR(getaddrinfo, node, service, hints, rv);
+ // 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);
+ int res = REAL(getaddrinfo)(node, service, hints, rv);
+ thr->in_rtl++;
+ ThreadIgnoreEnd(thr);
+ 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;
- Printf("INFO: ThreadSanitizer ignores mlock/mlockall/munlock/munlockall\n");
+ if (flags()->verbosity > 0)
+ Printf("INFO: ThreadSanitizer ignores mlock/mlockall/munlock/munlockall\n");
}
TSAN_INTERCEPTOR(int, mlock, const void *addr, uptr len) {
@@ -1817,8 +1809,7 @@ TSAN_INTERCEPTOR(int, munlockall, void) {
}
TSAN_INTERCEPTOR(int, fork, int fake) {
- SCOPED_TSAN_INTERCEPTOR(fork, fake);
- // It's intercepted merely to process pending signals.
+ SCOPED_INTERCEPTOR_RAW(fork, fake);
int pid = REAL(fork)(fake);
if (pid == 0) {
// child
@@ -1829,6 +1820,12 @@ TSAN_INTERCEPTOR(int, fork, int fake) {
return pid;
}
+static int OnExit(ThreadState *thr) {
+ int status = Finalize(thr);
+ REAL(fflush)(0);
+ return status;
+}
+
struct TsanInterceptorContext {
ThreadState *thr;
const uptr caller_pc;
@@ -1839,39 +1836,150 @@ struct TsanInterceptorContext {
// 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
-#define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \
- MemoryAccessRange(((TsanInterceptorContext*)ctx)->thr, \
- ((TsanInterceptorContext*)ctx)->pc, \
- (uptr)ptr, size, true)
-#define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) \
- MemoryAccessRange(((TsanInterceptorContext*)ctx)->thr, \
- ((TsanInterceptorContext*)ctx)->pc, \
- (uptr)ptr, size, false)
-#define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \
- SCOPED_TSAN_INTERCEPTOR(func, __VA_ARGS__) \
- TsanInterceptorContext _ctx = {thr, caller_pc, pc}; \
- ctx = (void*)&_ctx; \
- (void)ctx;
+#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, \
+ ((TsanInterceptorContext *)ctx)->pc, (uptr)ptr, size, \
+ true)
+
+#define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) \
+ MemoryAccessRange(((TsanInterceptorContext *) ctx)->thr, \
+ ((TsanInterceptorContext *) ctx)->pc, (uptr) ptr, size, \
+ false)
+
+#define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \
+ SCOPED_TSAN_INTERCEPTOR(func, __VA_ARGS__); \
+ TsanInterceptorContext _ctx = {thr, caller_pc, pc}; \
+ ctx = (void *)&_ctx; \
+ (void) ctx;
+
#define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd) \
- FdAcquire(((TsanInterceptorContext*)ctx)->thr, pc, fd)
+ FdAcquire(((TsanInterceptorContext *) ctx)->thr, pc, fd)
+
#define COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd) \
- FdRelease(((TsanInterceptorContext*)ctx)->thr, pc, fd)
+ FdRelease(((TsanInterceptorContext *) ctx)->thr, pc, fd)
+
+#define COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd) \
+ FdAccess(((TsanInterceptorContext *) ctx)->thr, pc, fd)
+
+#define COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, newfd) \
+ FdSocketAccept(((TsanInterceptorContext *) ctx)->thr, pc, fd, newfd)
+
#define COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, name) \
- ThreadSetName(((TsanInterceptorContext*)ctx)->thr, name)
+ ThreadSetName(((TsanInterceptorContext *) ctx)->thr, name)
+
+#define COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name) \
+ CTX()->thread_registry->SetThreadNameByUserId(thread, name)
+
+#define COMMON_INTERCEPTOR_BLOCK_REAL(name) BLOCK_REAL(name)
+
+#define COMMON_INTERCEPTOR_ON_EXIT(ctx) \
+ OnExit(((TsanInterceptorContext *) ctx)->thr)
+
+#define COMMON_INTERCEPTOR_MUTEX_LOCK(ctx, m) \
+ MutexLock(((TsanInterceptorContext *)ctx)->thr, \
+ ((TsanInterceptorContext *)ctx)->pc, (uptr)m)
+
+#define COMMON_INTERCEPTOR_MUTEX_UNLOCK(ctx, m) \
+ MutexUnlock(((TsanInterceptorContext *)ctx)->thr, \
+ ((TsanInterceptorContext *)ctx)->pc, (uptr)m)
+
+#define COMMON_INTERCEPTOR_MUTEX_REPAIR(ctx, m) \
+ MutexRepair(((TsanInterceptorContext *)ctx)->thr, \
+ ((TsanInterceptorContext *)ctx)->pc, (uptr)m)
+
#include "sanitizer_common/sanitizer_common_interceptors.inc"
-// FIXME: Implement these with MemoryAccessRange().
-#define COMMON_SYSCALL_PRE_READ_RANGE(p, s)
-#define COMMON_SYSCALL_PRE_WRITE_RANGE(p, s)
-#define COMMON_SYSCALL_POST_READ_RANGE(p, s)
-#define COMMON_SYSCALL_POST_WRITE_RANGE(p, s)
+#define TSAN_SYSCALL() \
+ ThreadState *thr = cur_thread(); \
+ ScopedSyscall scoped_syscall(thr) \
+/**/
+
+struct ScopedSyscall {
+ ThreadState *thr;
+
+ explicit ScopedSyscall(ThreadState *thr)
+ : thr(thr) {
+ if (thr->in_rtl == 0)
+ Initialize(thr);
+ thr->in_rtl++;
+ }
+
+ ~ScopedSyscall() {
+ thr->in_rtl--;
+ if (thr->in_rtl == 0)
+ ProcessPendingSignals(thr);
+ }
+};
+
+static void syscall_access_range(uptr pc, uptr p, uptr s, bool write) {
+ TSAN_SYSCALL();
+ MemoryAccessRange(thr, pc, p, s, write);
+}
+
+static void syscall_fd_close(uptr pc, int fd) {
+ TSAN_SYSCALL();
+ if (fd >= 0)
+ FdClose(thr, pc, fd);
+}
+
+static void syscall_pre_fork(uptr pc) {
+ TSAN_SYSCALL();
+}
+
+static void syscall_post_fork(uptr pc, int res) {
+ TSAN_SYSCALL();
+ if (res == 0) {
+ // child
+ FdOnFork(thr, pc);
+ } else if (res > 0) {
+ // parent
+ }
+}
+
+#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_FD_CLOSE(fd) syscall_fd_close(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);
+ if (status)
+ REAL(_exit)(status);
+}
+
void ProcessPendingSignals(ThreadState *thr) {
CHECK_EQ(thr->in_rtl, 0);
SignalContext *sctx = SigCtx(thr);
@@ -1881,8 +1989,8 @@ void ProcessPendingSignals(ThreadState *thr) {
thr->in_signal_handler = true;
sctx->pending_signal_count = 0;
// These are too big for stack.
- static THREADLOCAL sigset_t emptyset, oldset;
- sigfillset(&emptyset);
+ 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];
@@ -1903,6 +2011,7 @@ void ProcessPendingSignals(ThreadState *thr) {
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);
@@ -1920,16 +2029,6 @@ void ProcessPendingSignals(ThreadState *thr) {
thr->in_signal_handler = false;
}
-static void finalize(void *arg) {
- ThreadState * thr = cur_thread();
- uptr pc = 0;
- atexit_ctx->exit(thr, pc);
- int status = Finalize(cur_thread());
- REAL(fflush)(0);
- if (status)
- _exit(status);
-}
-
static void unreachable() {
Printf("FATAL: ThreadSanitizer: unreachable called\n");
Die();
@@ -1973,7 +2072,6 @@ void InitializeInterceptors() {
TSAN_INTERCEPT(strlen);
TSAN_INTERCEPT(memset);
TSAN_INTERCEPT(memcpy);
- TSAN_INTERCEPT(strcmp);
TSAN_INTERCEPT(memchr);
TSAN_INTERCEPT(memrchr);
TSAN_INTERCEPT(memmove);
@@ -1981,10 +2079,10 @@ void InitializeInterceptors() {
TSAN_INTERCEPT(strchr);
TSAN_INTERCEPT(strchrnul);
TSAN_INTERCEPT(strrchr);
- TSAN_INTERCEPT(strncmp);
TSAN_INTERCEPT(strcpy); // NOLINT
TSAN_INTERCEPT(strncpy);
TSAN_INTERCEPT(strstr);
+ TSAN_INTERCEPT(strdup);
TSAN_INTERCEPT(pthread_create);
TSAN_INTERCEPT(pthread_join);
@@ -1992,10 +2090,8 @@ void InitializeInterceptors() {
TSAN_INTERCEPT(pthread_mutex_init);
TSAN_INTERCEPT(pthread_mutex_destroy);
- TSAN_INTERCEPT(pthread_mutex_lock);
TSAN_INTERCEPT(pthread_mutex_trylock);
TSAN_INTERCEPT(pthread_mutex_timedlock);
- TSAN_INTERCEPT(pthread_mutex_unlock);
TSAN_INTERCEPT(pthread_spin_init);
TSAN_INTERCEPT(pthread_spin_destroy);
@@ -2013,12 +2109,8 @@ void InitializeInterceptors() {
TSAN_INTERCEPT(pthread_rwlock_timedwrlock);
TSAN_INTERCEPT(pthread_rwlock_unlock);
- // TSAN_INTERCEPT(pthread_cond_init);
- TSAN_INTERCEPT(pthread_cond_destroy);
- TSAN_INTERCEPT(pthread_cond_signal);
- TSAN_INTERCEPT(pthread_cond_broadcast);
- TSAN_INTERCEPT(pthread_cond_wait);
- TSAN_INTERCEPT(pthread_cond_timedwait);
+ 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);
@@ -2062,8 +2154,6 @@ void InitializeInterceptors() {
TSAN_INTERCEPT(connect);
TSAN_INTERCEPT(bind);
TSAN_INTERCEPT(listen);
- TSAN_INTERCEPT(accept);
- TSAN_INTERCEPT(accept4);
TSAN_INTERCEPT(epoll_create);
TSAN_INTERCEPT(epoll_create1);
TSAN_INTERCEPT(close);
@@ -2072,14 +2162,9 @@ void InitializeInterceptors() {
TSAN_INTERCEPT(pipe);
TSAN_INTERCEPT(pipe2);
- TSAN_INTERCEPT(readv);
- TSAN_INTERCEPT(preadv64);
- TSAN_INTERCEPT(writev);
- TSAN_INTERCEPT(pwritev64);
TSAN_INTERCEPT(send);
TSAN_INTERCEPT(sendmsg);
TSAN_INTERCEPT(recv);
- TSAN_INTERCEPT(recvmsg);
TSAN_INTERCEPT(unlink);
TSAN_INTERCEPT(fopen);
@@ -2095,10 +2180,10 @@ void InitializeInterceptors() {
TSAN_INTERCEPT(epoll_ctl);
TSAN_INTERCEPT(epoll_wait);
- TSAN_INTERCEPT(poll);
TSAN_INTERCEPT(sigaction);
TSAN_INTERCEPT(signal);
+ TSAN_INTERCEPT(sigsuspend);
TSAN_INTERCEPT(raise);
TSAN_INTERCEPT(kill);
TSAN_INTERCEPT(pthread_kill);
@@ -2106,6 +2191,7 @@ void InitializeInterceptors() {
TSAN_INTERCEPT(usleep);
TSAN_INTERCEPT(nanosleep);
TSAN_INTERCEPT(gettimeofday);
+ TSAN_INTERCEPT(getaddrinfo);
TSAN_INTERCEPT(mlock);
TSAN_INTERCEPT(munlock);
@@ -2113,8 +2199,11 @@ void InitializeInterceptors() {
TSAN_INTERCEPT(munlockall);
TSAN_INTERCEPT(fork);
+ TSAN_INTERCEPT(dlopen);
+ TSAN_INTERCEPT(dlclose);
TSAN_INTERCEPT(on_exit);
TSAN_INTERCEPT(__cxa_atexit);
+ TSAN_INTERCEPT(_exit);
// 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.
@@ -2136,9 +2225,15 @@ void InitializeInterceptors() {
}
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;
+ 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);
}
} // namespace __tsan
diff --git a/lib/tsan/rtl/tsan_interface.cc b/lib/tsan/rtl/tsan_interface.cc
index efad8c192d6e..9de3808e79ff 100644
--- a/lib/tsan/rtl/tsan_interface.cc
+++ b/lib/tsan/rtl/tsan_interface.cc
@@ -38,49 +38,55 @@ void __tsan_write16(void *addr) {
MemoryWrite(cur_thread(), CALLERPC, (uptr)addr + 8, kSizeLog8);
}
-u16 __tsan_unaligned_read2(void *addr) {
+u16 __tsan_unaligned_read2(const uu16 *addr) {
UnalignedMemoryAccess(cur_thread(), CALLERPC, (uptr)addr, 2, false, false);
- return *(u16*)addr;
+ return *addr;
}
-u32 __tsan_unaligned_read4(void *addr) {
+u32 __tsan_unaligned_read4(const uu32 *addr) {
UnalignedMemoryAccess(cur_thread(), CALLERPC, (uptr)addr, 4, false, false);
- return *(u32*)addr;
+ return *addr;
}
-u64 __tsan_unaligned_read8(void *addr) {
+u64 __tsan_unaligned_read8(const uu64 *addr) {
UnalignedMemoryAccess(cur_thread(), CALLERPC, (uptr)addr, 8, false, false);
- return *(u64*)addr;
+ return *addr;
}
-void __tsan_unaligned_write2(void *addr, u16 v) {
+void __tsan_unaligned_write2(uu16 *addr, u16 v) {
UnalignedMemoryAccess(cur_thread(), CALLERPC, (uptr)addr, 2, true, false);
- *(u16*)addr = v;
+ *addr = v;
}
-void __tsan_unaligned_write4(void *addr, u32 v) {
+void __tsan_unaligned_write4(uu32 *addr, u32 v) {
UnalignedMemoryAccess(cur_thread(), CALLERPC, (uptr)addr, 4, true, false);
- *(u32*)addr = v;
+ *addr = v;
}
-void __tsan_unaligned_write8(void *addr, u64 v) {
+void __tsan_unaligned_write8(uu64 *addr, u64 v) {
UnalignedMemoryAccess(cur_thread(), CALLERPC, (uptr)addr, 8, true, false);
- *(u64*)addr = v;
+ *addr = v;
}
extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE
uint16_t __sanitizer_unaligned_load16(void *addr)
- ALIAS("__tsan_unaligned_read2") SANITIZER_INTERFACE_ATTRIBUTE;
+ ALIAS("__tsan_unaligned_read2");
+SANITIZER_INTERFACE_ATTRIBUTE
uint32_t __sanitizer_unaligned_load32(void *addr)
- ALIAS("__tsan_unaligned_read4") SANITIZER_INTERFACE_ATTRIBUTE;
+ ALIAS("__tsan_unaligned_read4");
+SANITIZER_INTERFACE_ATTRIBUTE
uint64_t __sanitizer_unaligned_load64(void *addr)
- ALIAS("__tsan_unaligned_read8") SANITIZER_INTERFACE_ATTRIBUTE;
+ ALIAS("__tsan_unaligned_read8");
+SANITIZER_INTERFACE_ATTRIBUTE
void __sanitizer_unaligned_store16(void *addr, uint16_t v)
- ALIAS("__tsan_unaligned_write2") SANITIZER_INTERFACE_ATTRIBUTE;
+ ALIAS("__tsan_unaligned_write2");
+SANITIZER_INTERFACE_ATTRIBUTE
void __sanitizer_unaligned_store32(void *addr, uint32_t v)
- ALIAS("__tsan_unaligned_write4") SANITIZER_INTERFACE_ATTRIBUTE;
+ ALIAS("__tsan_unaligned_write4");
+SANITIZER_INTERFACE_ATTRIBUTE
void __sanitizer_unaligned_store64(void *addr, uint64_t v)
- ALIAS("__tsan_unaligned_write8") SANITIZER_INTERFACE_ATTRIBUTE;
+ ALIAS("__tsan_unaligned_write8");
}
void __tsan_acquire(void *addr) {
diff --git a/lib/tsan/rtl/tsan_interface.h b/lib/tsan/rtl/tsan_interface.h
index 457fb55e0d2d..70450697d480 100644
--- a/lib/tsan/rtl/tsan_interface.h
+++ b/lib/tsan/rtl/tsan_interface.h
@@ -27,38 +27,38 @@ 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.
-void __tsan_init() SANITIZER_INTERFACE_ATTRIBUTE;
+SANITIZER_INTERFACE_ATTRIBUTE void __tsan_init();
-void __tsan_read1(void *addr) SANITIZER_INTERFACE_ATTRIBUTE;
-void __tsan_read2(void *addr) SANITIZER_INTERFACE_ATTRIBUTE;
-void __tsan_read4(void *addr) SANITIZER_INTERFACE_ATTRIBUTE;
-void __tsan_read8(void *addr) SANITIZER_INTERFACE_ATTRIBUTE;
-void __tsan_read16(void *addr) SANITIZER_INTERFACE_ATTRIBUTE;
+SANITIZER_INTERFACE_ATTRIBUTE void __tsan_read1(void *addr);
+SANITIZER_INTERFACE_ATTRIBUTE void __tsan_read2(void *addr);
+SANITIZER_INTERFACE_ATTRIBUTE void __tsan_read4(void *addr);
+SANITIZER_INTERFACE_ATTRIBUTE void __tsan_read8(void *addr);
+SANITIZER_INTERFACE_ATTRIBUTE void __tsan_read16(void *addr);
-void __tsan_write1(void *addr) SANITIZER_INTERFACE_ATTRIBUTE;
-void __tsan_write2(void *addr) SANITIZER_INTERFACE_ATTRIBUTE;
-void __tsan_write4(void *addr) SANITIZER_INTERFACE_ATTRIBUTE;
-void __tsan_write8(void *addr) SANITIZER_INTERFACE_ATTRIBUTE;
-void __tsan_write16(void *addr) SANITIZER_INTERFACE_ATTRIBUTE;
+SANITIZER_INTERFACE_ATTRIBUTE void __tsan_write1(void *addr);
+SANITIZER_INTERFACE_ATTRIBUTE void __tsan_write2(void *addr);
+SANITIZER_INTERFACE_ATTRIBUTE void __tsan_write4(void *addr);
+SANITIZER_INTERFACE_ATTRIBUTE void __tsan_write8(void *addr);
+SANITIZER_INTERFACE_ATTRIBUTE void __tsan_write16(void *addr);
-u16 __tsan_unaligned_read2(void *addr) SANITIZER_INTERFACE_ATTRIBUTE;
-u32 __tsan_unaligned_read4(void *addr) SANITIZER_INTERFACE_ATTRIBUTE;
-u64 __tsan_unaligned_read8(void *addr) SANITIZER_INTERFACE_ATTRIBUTE;
-void __tsan_unaligned_write2(void *addr, u16 v) SANITIZER_INTERFACE_ATTRIBUTE;
-void __tsan_unaligned_write4(void *addr, u32 v) SANITIZER_INTERFACE_ATTRIBUTE;
-void __tsan_unaligned_write8(void *addr, u64 v) SANITIZER_INTERFACE_ATTRIBUTE;
+SANITIZER_INTERFACE_ATTRIBUTE u16 __tsan_unaligned_read2(const uu16 *addr);
+SANITIZER_INTERFACE_ATTRIBUTE u32 __tsan_unaligned_read4(const uu32 *addr);
+SANITIZER_INTERFACE_ATTRIBUTE u64 __tsan_unaligned_read8(const uu64 *addr);
+SANITIZER_INTERFACE_ATTRIBUTE void __tsan_unaligned_write2(uu16 *addr, u16 v);
+SANITIZER_INTERFACE_ATTRIBUTE void __tsan_unaligned_write4(uu32 *addr, u32 v);
+SANITIZER_INTERFACE_ATTRIBUTE void __tsan_unaligned_write8(uu64 *addr, u64 v);
-void __tsan_vptr_read(void **vptr_p) SANITIZER_INTERFACE_ATTRIBUTE;
-void __tsan_vptr_update(void **vptr_p, void *new_val)
- SANITIZER_INTERFACE_ATTRIBUTE;
+SANITIZER_INTERFACE_ATTRIBUTE void __tsan_vptr_read(void **vptr_p);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_vptr_update(void **vptr_p, void *new_val);
-void __tsan_func_entry(void *call_pc) SANITIZER_INTERFACE_ATTRIBUTE;
-void __tsan_func_exit() SANITIZER_INTERFACE_ATTRIBUTE;
+SANITIZER_INTERFACE_ATTRIBUTE void __tsan_func_entry(void *call_pc);
+SANITIZER_INTERFACE_ATTRIBUTE void __tsan_func_exit();
-void __tsan_read_range(void *addr, unsigned long size) // NOLINT
- SANITIZER_INTERFACE_ATTRIBUTE;
-void __tsan_write_range(void *addr, unsigned long size) // NOLINT
- SANITIZER_INTERFACE_ATTRIBUTE;
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_read_range(void *addr, unsigned long size); // NOLINT
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_write_range(void *addr, unsigned long size); // NOLINT
#ifdef __cplusplus
} // extern "C"
diff --git a/lib/tsan/rtl/tsan_interface_ann.cc b/lib/tsan/rtl/tsan_interface_ann.cc
index 04b4b455d15e..cacbc0281d0f 100644
--- a/lib/tsan/rtl/tsan_interface_ann.cc
+++ b/lib/tsan/rtl/tsan_interface_ann.cc
@@ -13,6 +13,7 @@
#include "sanitizer_common/sanitizer_libc.h"
#include "sanitizer_common/sanitizer_internal_defs.h"
#include "sanitizer_common/sanitizer_placement_new.h"
+#include "sanitizer_common/sanitizer_stacktrace.h"
#include "tsan_interface_ann.h"
#include "tsan_mutex.h"
#include "tsan_report.h"
@@ -229,12 +230,12 @@ using namespace __tsan; // NOLINT
extern "C" {
void INTERFACE_ATTRIBUTE AnnotateHappensBefore(char *f, int l, uptr addr) {
SCOPED_ANNOTATION(AnnotateHappensBefore);
- Release(cur_thread(), CALLERPC, addr);
+ Release(thr, pc, addr);
}
void INTERFACE_ATTRIBUTE AnnotateHappensAfter(char *f, int l, uptr addr) {
SCOPED_ANNOTATION(AnnotateHappensAfter);
- Acquire(cur_thread(), CALLERPC, addr);
+ Acquire(thr, pc, addr);
}
void INTERFACE_ATTRIBUTE AnnotateCondVarSignal(char *f, int l, uptr cv) {
@@ -382,22 +383,32 @@ void INTERFACE_ATTRIBUTE AnnotateBenignRace(
void INTERFACE_ATTRIBUTE AnnotateIgnoreReadsBegin(char *f, int l) {
SCOPED_ANNOTATION(AnnotateIgnoreReadsBegin);
- IgnoreCtl(cur_thread(), false, true);
+ ThreadIgnoreBegin(thr);
}
void INTERFACE_ATTRIBUTE AnnotateIgnoreReadsEnd(char *f, int l) {
SCOPED_ANNOTATION(AnnotateIgnoreReadsEnd);
- IgnoreCtl(cur_thread(), false, false);
+ ThreadIgnoreEnd(thr);
}
void INTERFACE_ATTRIBUTE AnnotateIgnoreWritesBegin(char *f, int l) {
SCOPED_ANNOTATION(AnnotateIgnoreWritesBegin);
- IgnoreCtl(cur_thread(), true, true);
+ ThreadIgnoreBegin(thr);
}
void INTERFACE_ATTRIBUTE AnnotateIgnoreWritesEnd(char *f, int l) {
SCOPED_ANNOTATION(AnnotateIgnoreWritesEnd);
- IgnoreCtl(thr, true, false);
+ ThreadIgnoreEnd(thr);
+}
+
+void INTERFACE_ATTRIBUTE AnnotateIgnoreSyncBegin(char *f, int l) {
+ SCOPED_ANNOTATION(AnnotateIgnoreSyncBegin);
+ ThreadIgnoreSyncBegin(thr);
+}
+
+void INTERFACE_ATTRIBUTE AnnotateIgnoreSyncEnd(char *f, int l) {
+ SCOPED_ANNOTATION(AnnotateIgnoreSyncEnd);
+ ThreadIgnoreSyncEnd(thr);
}
void INTERFACE_ATTRIBUTE AnnotatePublishMemoryRange(
@@ -447,4 +458,7 @@ const char INTERFACE_ATTRIBUTE* ThreadSanitizerQuery(const char *query) {
else
return "0";
}
+
+void INTERFACE_ATTRIBUTE
+AnnotateMemoryIsInitialized(char *f, int l, uptr mem, uptr sz) {}
} // extern "C"
diff --git a/lib/tsan/rtl/tsan_interface_ann.h b/lib/tsan/rtl/tsan_interface_ann.h
index 8e45328e7ec1..963bcc55afaa 100644
--- a/lib/tsan/rtl/tsan_interface_ann.h
+++ b/lib/tsan/rtl/tsan_interface_ann.h
@@ -23,8 +23,8 @@
extern "C" {
#endif
-void __tsan_acquire(void *addr) SANITIZER_INTERFACE_ATTRIBUTE;
-void __tsan_release(void *addr) SANITIZER_INTERFACE_ATTRIBUTE;
+SANITIZER_INTERFACE_ATTRIBUTE void __tsan_acquire(void *addr);
+SANITIZER_INTERFACE_ATTRIBUTE void __tsan_release(void *addr);
#ifdef __cplusplus
} // extern "C"
diff --git a/lib/tsan/rtl/tsan_interface_atomic.cc b/lib/tsan/rtl/tsan_interface_atomic.cc
index 80266969849a..d9f8cdf5b106 100644
--- a/lib/tsan/rtl/tsan_interface_atomic.cc
+++ b/lib/tsan/rtl/tsan_interface_atomic.cc
@@ -30,23 +30,37 @@ using namespace __tsan; // NOLINT
#define SCOPED_ATOMIC(func, ...) \
const uptr callpc = (uptr)__builtin_return_address(0); \
uptr pc = __sanitizer::StackTrace::GetCurrentPc(); \
- pc = __sanitizer::StackTrace::GetPreviousInstructionPc(pc); \
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, __FUNCTION__); \
+ 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;
+
class ScopedAtomic {
public:
- ScopedAtomic(ThreadState *thr, uptr pc, const char *func)
+ 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\n", thr_->tid, func);
+ DPrintf("#%d: %s(%p, %d)\n", thr_->tid, func, a, mo);
thr_->in_rtl++;
}
~ScopedAtomic() {
@@ -58,20 +72,6 @@ class ScopedAtomic {
ThreadState *thr_;
};
-// 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;
-
static void AtomicStatInc(ThreadState *thr, uptr size, morder mo, StatType t) {
StatInc(thr, StatAtomic);
StatInc(thr, t);
@@ -251,11 +251,10 @@ static T AtomicLoad(ThreadState *thr, uptr pc, const volatile T *a,
// Assume the access is atomic.
if (!IsAcquireOrder(mo) && sizeof(T) <= sizeof(a)) {
MemoryReadAtomic(thr, pc, (uptr)a, SizeLog<T>());
- return *a;
+ return *a; // as if atomic
}
SyncVar *s = CTX()->synctab.GetOrCreateAndLock(thr, pc, (uptr)a, false);
- thr->clock.set(thr->tid, thr->fast_state.epoch());
- thr->clock.acquire(&s->clock);
+ AcquireImpl(thr, pc, &s->clock);
T v = *a;
s->mtx.ReadUnlock();
__sync_synchronize();
@@ -273,13 +272,15 @@ static void AtomicStore(ThreadState *thr, uptr pc, volatile T *a, T v,
// Strictly saying even relaxed store cuts off release sequence,
// so must reset the clock.
if (!IsReleaseOrder(mo) && sizeof(T) <= sizeof(a)) {
- *a = v;
+ *a = v; // as if atomic
return;
}
__sync_synchronize();
SyncVar *s = CTX()->synctab.GetOrCreateAndLock(thr, pc, (uptr)a, true);
- thr->clock.set(thr->tid, thr->fast_state.epoch());
- thr->clock.ReleaseStore(&s->clock);
+ 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;
s->mtx.Unlock();
// Trainling memory barrier to provide sequential consistency
@@ -293,13 +294,15 @@ static T AtomicRMW(ThreadState *thr, uptr pc, volatile T *a, T v, morder mo) {
SyncVar *s = 0;
if (mo != mo_relaxed) {
s = CTX()->synctab.GetOrCreateAndLock(thr, pc, (uptr)a, true);
- thr->clock.set(thr->tid, thr->fast_state.epoch());
+ thr->fast_state.IncrementEpoch();
+ // Can't increment epoch w/o writing to the trace as well.
+ TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0);
if (IsAcqRelOrder(mo))
- thr->clock.acq_rel(&s->clock);
+ AcquireReleaseImpl(thr, pc, &s->clock);
else if (IsReleaseOrder(mo))
- thr->clock.release(&s->clock);
+ ReleaseImpl(thr, pc, &s->clock);
else if (IsAcquireOrder(mo))
- thr->clock.acquire(&s->clock);
+ AcquireImpl(thr, pc, &s->clock);
}
v = F(a, v);
if (s)
@@ -357,13 +360,15 @@ static bool AtomicCAS(ThreadState *thr, uptr pc,
SyncVar *s = 0;
if (mo != mo_relaxed) {
s = CTX()->synctab.GetOrCreateAndLock(thr, pc, (uptr)a, true);
- thr->clock.set(thr->tid, thr->fast_state.epoch());
+ thr->fast_state.IncrementEpoch();
+ // Can't increment epoch w/o writing to the trace as well.
+ TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0);
if (IsAcqRelOrder(mo))
- thr->clock.acq_rel(&s->clock);
+ AcquireReleaseImpl(thr, pc, &s->clock);
else if (IsReleaseOrder(mo))
- thr->clock.release(&s->clock);
+ ReleaseImpl(thr, pc, &s->clock);
else if (IsAcquireOrder(mo))
- thr->clock.acquire(&s->clock);
+ AcquireImpl(thr, pc, &s->clock);
}
T cc = *c;
T pr = func_cas(a, cc, v);
@@ -659,14 +664,14 @@ a64 __tsan_atomic64_compare_exchange_val(volatile a64 *a, a64 c, a64 v,
}
#if __TSAN_HAS_INT128
-a128 __tsan_atomic64_compare_exchange_val(volatile a128 *a, a128 c, a128 v,
+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
void __tsan_atomic_thread_fence(morder mo) {
- char* a;
+ char* a = 0;
SCOPED_ATOMIC(Fence, mo);
}
diff --git a/lib/tsan/rtl/tsan_interface_java.cc b/lib/tsan/rtl/tsan_interface_java.cc
index 71e0747c3646..53f14cf07b59 100644
--- a/lib/tsan/rtl/tsan_interface_java.cc
+++ b/lib/tsan/rtl/tsan_interface_java.cc
@@ -17,6 +17,8 @@
#include "sanitizer_common/sanitizer_internal_defs.h"
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_placement_new.h"
+#include "sanitizer_common/sanitizer_stacktrace.h"
+#include "sanitizer_common/sanitizer_procmaps.h"
using namespace __tsan; // NOLINT
@@ -157,7 +159,7 @@ SyncVar* GetAndRemoveJavaSync(ThreadState *thr, uptr pc, uptr addr) {
#define SCOPED_JAVA_FUNC(func) \
ThreadState *thr = cur_thread(); \
const uptr caller_pc = GET_CALLER_PC(); \
- const uptr pc = (uptr)&func; \
+ const uptr pc = __sanitizer::StackTrace::GetCurrentPc(); \
(void)pc; \
ScopedJavaFunc scoped(thr, caller_pc); \
/**/
diff --git a/lib/tsan/rtl/tsan_mman.cc b/lib/tsan/rtl/tsan_mman.cc
index b6671b1abf09..8547f714be13 100644
--- a/lib/tsan/rtl/tsan_mman.cc
+++ b/lib/tsan/rtl/tsan_mman.cc
@@ -75,10 +75,12 @@ void InitializeAllocator() {
void AllocatorThreadStart(ThreadState *thr) {
allocator()->InitCache(&thr->alloc_cache);
+ internal_allocator()->InitCache(&thr->internal_alloc_cache);
}
void AllocatorThreadFinish(ThreadState *thr) {
allocator()->DestroyCache(&thr->alloc_cache);
+ internal_allocator()->DestroyCache(&thr->internal_alloc_cache);
}
void AllocatorPrintStats() {
@@ -102,14 +104,18 @@ static void SignalUnsafeCall(ThreadState *thr, uptr pc) {
void *user_alloc(ThreadState *thr, uptr pc, uptr sz, uptr align) {
CHECK_GT(thr->in_rtl, 0);
if ((sz >= (1ull << 40)) || (align >= (1ull << 40)))
- return 0;
+ 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)
- MemoryRangeImitateWrite(thr, pc, (uptr)p, sz);
+ 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);
return p;
@@ -132,8 +138,10 @@ void user_free(ThreadState *thr, uptr pc, void *p) {
}
b->ListReset();
}
- if (CTX() && CTX()->initialized && thr->in_rtl == 1)
- MemoryRangeFreed(thr, pc, (uptr)p, b->Size());
+ if (CTX() && CTX()->initialized && thr->in_rtl == 1) {
+ if (thr->ignore_reads_and_writes == 0)
+ MemoryRangeFreed(thr, pc, (uptr)p, b->Size());
+ }
allocator()->Deallocate(&thr->alloc_cache, p);
SignalUnsafeCall(thr, pc);
}
@@ -194,11 +202,12 @@ void invoke_free_hook(void *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);
}
- return InternalAlloc(sz);
+ return InternalAlloc(sz, &thr->internal_alloc_cache);
}
void internal_free(void *p) {
@@ -208,7 +217,7 @@ void internal_free(void *p) {
thr->nomalloc = 0; // CHECK calls internal_malloc().
CHECK(0);
}
- InternalFree(p);
+ InternalFree(p, &thr->internal_alloc_cache);
}
} // namespace __tsan
@@ -261,5 +270,6 @@ uptr __tsan_get_allocated_size(void *p) {
void __tsan_on_thread_idle() {
ThreadState *thr = cur_thread();
allocator()->SwallowCache(&thr->alloc_cache);
+ internal_allocator()->SwallowCache(&thr->internal_alloc_cache);
}
} // extern "C"
diff --git a/lib/tsan/rtl/tsan_platform.h b/lib/tsan/rtl/tsan_platform.h
index 666b4d0c482f..32e22ba60434 100644
--- a/lib/tsan/rtl/tsan_platform.h
+++ b/lib/tsan/rtl/tsan_platform.h
@@ -134,17 +134,24 @@ static inline uptr AlternativeAddress(uptr addr) {
void FlushShadowMemory();
void WriteMemoryProfile(char *buf, uptr buf_size);
+uptr GetRSS();
const char *InitializePlatform();
void FinalizePlatform();
+
+// The additional page is to catch shadow stack overflow as paging fault.
+const uptr kTotalTraceSize = (kTraceSize * sizeof(Event) + sizeof(Trace) + 4096
+ + 4095) & ~4095;
+
uptr ALWAYS_INLINE GetThreadTrace(int tid) {
- uptr p = kTraceMemBegin + (uptr)(tid * 2) * kTraceSize * sizeof(Event);
+ uptr p = kTraceMemBegin + (uptr)tid * kTotalTraceSize;
DCHECK_LT(p, kTraceMemBegin + kTraceMemSize);
return p;
}
uptr ALWAYS_INLINE GetThreadTraceHeader(int tid) {
- uptr p = kTraceMemBegin + (uptr)(tid * 2 + 1) * kTraceSize * sizeof(Event);
+ uptr p = kTraceMemBegin + (uptr)tid * kTotalTraceSize
+ + kTraceSize * sizeof(Event);
DCHECK_LT(p, kTraceMemBegin + kTraceMemSize);
return p;
}
diff --git a/lib/tsan/rtl/tsan_platform_linux.cc b/lib/tsan/rtl/tsan_platform_linux.cc
index a0d71e8589d6..906b5dc73be4 100644
--- a/lib/tsan/rtl/tsan_platform_linux.cc
+++ b/lib/tsan/rtl/tsan_platform_linux.cc
@@ -19,6 +19,7 @@
#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 "tsan_platform.h"
#include "tsan_rtl.h"
#include "tsan_flags.h"
@@ -45,6 +46,14 @@
#include <resolv.h>
#include <malloc.h>
+#ifdef sa_handler
+# undef sa_handler
+#endif
+
+#ifdef sa_sigaction
+# undef sa_sigaction
+#endif
+
extern "C" struct mallinfo __libc_mallinfo();
namespace __tsan {
@@ -72,70 +81,33 @@ ScopedInRtl::~ScopedInRtl() {
}
#endif
-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 readdec(const char *p) {
- uptr v = 0;
- for (; p[0] >= '0' && p[0] <= '9' ; p++)
- v = v * 10 + p[0] - '0';
- return v;
+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) {
- char *smaps = 0;
- uptr smaps_cap = 0;
- uptr smaps_len = ReadFileToBuffer("/proc/self/smaps",
- &smaps, &smaps_cap, 64<<20);
- uptr mem[6] = {};
- uptr total = 0;
- 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 = readdec(pos) * 1024;
- total += rss;
- 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;
- }
- while (*pos++ != '\n') {}
- }
- UnmapOrDie(smaps, smaps_cap);
+ 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",
- total >> 20, mem[0] >> 20, mem[1] >> 20, mem[2] >> 20,
+ 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,
@@ -143,10 +115,23 @@ void WriteMemoryProfile(char *buf, uptr buf_size) {
mi.arena >> 20, mi.hblkhd >> 20, mi.fordblks >> 20, mi.keepcost >> 20);
}
-void FlushShadowMemory() {
+uptr GetRSS() {
+ uptr mem[7] = {};
+ __sanitizer::GetMemoryProfile(FillProfileCallback, mem, 7);
+ return mem[6];
+}
+
+
+void FlushShadowMemoryCallback(
+ const SuspendedThreadsList &suspended_threads_list,
+ void *argument) {
FlushUnneededShadowMemory(kLinuxShadowBeg, kLinuxShadowEnd - kLinuxShadowBeg);
}
+void FlushShadowMemory() {
+ StopTheWorld(FlushShadowMemoryCallback, 0);
+}
+
#ifndef TSAN_GO
static void ProtectRange(uptr beg, uptr end) {
ScopedInRtl in_rtl;
diff --git a/lib/tsan/rtl/tsan_report.cc b/lib/tsan/rtl/tsan_report.cc
index c95c5c86be69..66307ae09dcd 100644
--- a/lib/tsan/rtl/tsan_report.cc
+++ b/lib/tsan/rtl/tsan_report.cc
@@ -13,9 +13,27 @@
#include "tsan_report.h"
#include "tsan_platform.h"
#include "tsan_rtl.h"
+#include "sanitizer_common/sanitizer_report_decorator.h"
namespace __tsan {
+class Decorator: private __sanitizer::AnsiColorDecorator {
+ public:
+ Decorator() : __sanitizer::AnsiColorDecorator(PrintsToTtyCached()) { }
+ const char *Warning() { return Red(); }
+ const char *EndWarning() { return Default(); }
+ const char *Access() { return Blue(); }
+ const char *EndAccess() { return Default(); }
+ const char *ThreadDescription() { return Cyan(); }
+ const char *EndThreadDescription() { return Default(); }
+ const char *Location() { return Green(); }
+ const char *EndLocation() { return Default(); }
+ const char *Sleep() { return Yellow(); }
+ const char *EndSleep() { return Default(); }
+ const char *Mutex() { return Magenta(); }
+ const char *EndMutex() { return Default(); }
+};
+
ReportDesc::ReportDesc()
: stacks(MBlockReportStack)
, mops(MBlockReportMop)
@@ -97,26 +115,32 @@ static const char *MopDesc(bool first, bool write, bool atomic) {
}
static void PrintMop(const ReportMop *mop, bool first) {
+ Decorator d;
char thrbuf[kThreadBufSize];
+ Printf("%s", d.Access());
Printf(" %s of size %d at %p by %s",
MopDesc(first, mop->write, mop->atomic),
mop->size, (void*)mop->addr,
thread_name(thrbuf, mop->tid));
PrintMutexSet(mop->mset);
Printf(":\n");
+ Printf("%s", d.EndAccess());
PrintStack(mop->stack);
}
static void PrintLocation(const ReportLocation *loc) {
+ Decorator d;
char thrbuf[kThreadBufSize];
+ bool print_stack = false;
+ Printf("%s", d.Location());
if (loc->type == ReportLocationGlobal) {
- Printf(" Location is global '%s' of size %zu at %zx (%s+%p)\n\n",
+ Printf(" Location is global '%s' of size %zu at %p (%s+%p)\n\n",
loc->name, loc->size, loc->addr, loc->module, loc->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));
- PrintStack(loc->stack);
+ print_stack = true;
} else if (loc->type == ReportLocationStack) {
Printf(" Location is stack of %s.\n\n", thread_name(thrbuf, loc->tid));
} else if (loc->type == ReportLocationTLS) {
@@ -124,22 +148,32 @@ static void PrintLocation(const ReportLocation *loc) {
} else if (loc->type == ReportLocationFD) {
Printf(" Location is file descriptor %d created by %s at:\n",
loc->fd, thread_name(thrbuf, loc->tid));
- PrintStack(loc->stack);
+ print_stack = true;
}
+ Printf("%s", d.EndLocation());
+ if (print_stack)
+ PrintStack(loc->stack);
}
static void PrintMutex(const ReportMutex *rm) {
+ Decorator d;
if (rm->destroyed) {
+ Printf("%s", d.Mutex());
Printf(" Mutex M%llu is already destroyed.\n\n", rm->id);
+ Printf("%s", d.EndMutex());
} else {
+ Printf("%s", d.Mutex());
Printf(" Mutex M%llu created at:\n", rm->id);
+ Printf("%s", d.EndMutex());
PrintStack(rm->stack);
}
}
static void PrintThread(const ReportThread *rt) {
+ Decorator d;
if (rt->id == 0) // Little sense in describing the main thread.
return;
+ Printf("%s", d.ThreadDescription());
Printf(" Thread T%d", rt->id);
if (rt->name && rt->name[0] != '\0')
Printf(" '%s'", rt->name);
@@ -150,11 +184,15 @@ static void PrintThread(const ReportThread *rt) {
if (rt->stack)
Printf(" at:");
Printf("\n");
+ Printf("%s", d.EndThreadDescription());
PrintStack(rt->stack);
}
static void PrintSleep(const ReportStack *s) {
+ Decorator d;
+ Printf("%s", d.Sleep());
Printf(" As if synchronized via sleep:\n");
+ Printf("%s", d.EndSleep());
PrintStack(s);
}
@@ -177,10 +215,13 @@ ReportStack *SkipTsanInternalFrames(ReportStack *ent) {
}
void PrintReport(const ReportDesc *rep) {
+ Decorator d;
Printf("==================\n");
const char *rep_typ_str = ReportTypeString(rep->typ);
+ Printf("%s", d.Warning());
Printf("WARNING: ThreadSanitizer: %s (pid=%d)\n", rep_typ_str,
(int)internal_getpid());
+ Printf("%s", d.EndWarning());
for (uptr i = 0; i < rep->stacks.Size(); i++) {
if (i)
@@ -212,31 +253,37 @@ void PrintReport(const ReportDesc *rep) {
Printf("==================\n");
}
-#else
+#else // #ifndef TSAN_GO
+
+const int kMainThreadId = 1;
void PrintStack(const ReportStack *ent) {
if (ent == 0) {
- Printf(" [failed to restore the stack]\n\n");
+ 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);
}
- Printf("\n");
}
static void PrintMop(const ReportMop *mop, bool first) {
- Printf("%s by goroutine %d:\n",
+ Printf("\n");
+ Printf("%s by ",
(first ? (mop->write ? "Write" : "Read")
- : (mop->write ? "Previous write" : "Previous read")),
- mop->tid);
+ : (mop->write ? "Previous write" : "Previous read")));
+ if (mop->tid == kMainThreadId)
+ Printf("main goroutine:\n");
+ else
+ Printf("goroutine %d:\n", mop->tid);
PrintStack(mop->stack);
}
static void PrintThread(const ReportThread *rt) {
- if (rt->id == 0) // Little sense in describing the main thread.
+ if (rt->id == kMainThreadId)
return;
+ Printf("\n");
Printf("Goroutine %d (%s) created at:\n",
rt->id, rt->running ? "running" : "finished");
PrintStack(rt->stack);
@@ -244,7 +291,7 @@ static void PrintThread(const ReportThread *rt) {
void PrintReport(const ReportDesc *rep) {
Printf("==================\n");
- Printf("WARNING: DATA RACE\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++)
diff --git a/lib/tsan/rtl/tsan_rtl.cc b/lib/tsan/rtl/tsan_rtl.cc
index 5924858c84c5..1f66d29a741c 100644
--- a/lib/tsan/rtl/tsan_rtl.cc
+++ b/lib/tsan/rtl/tsan_rtl.cc
@@ -39,9 +39,13 @@ THREADLOCAL char cur_thread_placeholder[sizeof(ThreadState)] ALIGNED(64);
static char ctx_placeholder[sizeof(Context)] ALIGNED(64);
// Can be overriden by a front-end.
-bool CPP_WEAK OnFinalize(bool failed) {
+#ifdef TSAN_EXTERNAL_HOOKS
+bool OnFinalize(bool failed);
+#else
+bool WEAK OnFinalize(bool failed) {
return failed;
}
+#endif
static Context *ctx;
Context *CTX() {
@@ -74,7 +78,7 @@ Context::Context()
CreateThreadContext, kMaxTid, kThreadQuarantineSize))
, racy_stacks(MBlockRacyStacks)
, racy_addresses(MBlockRacyAddresses)
- , fired_suppressions(MBlockRacyAddresses) {
+ , fired_suppressions(8) {
}
// The objects are allocated in TLS, so one may rely on zero-initialization.
@@ -86,7 +90,6 @@ ThreadState::ThreadState(Context *ctx, int tid, int unique_id, u64 epoch,
// they may be accessed before the ctor.
// , ignore_reads_and_writes()
// , in_rtl()
- , shadow_stack_pos(&shadow_stack[0])
#ifndef TSAN_GO
, jmp_bufs(MBlockJmpBuf)
#endif
@@ -130,17 +133,38 @@ static void BackgroundThread(void *arg) {
}
u64 last_flush = NanoTime();
+ uptr last_rss = 0;
for (int i = 0; ; i++) {
SleepForSeconds(1);
u64 now = NanoTime();
// Flush memory if requested.
- if (flags()->flush_memory_ms) {
+ 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");
FlushShadowMemory();
last_flush = NanoTime();
}
}
+ 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);
+ }
+ if (2 * rss > limit + last_rss) {
+ if (flags()->verbosity > 0)
+ Printf("ThreadSanitizer: flushing memory due to RSS\n");
+ FlushShadowMemory();
+ rss = GetRSS();
+ if (flags()->verbosity > 0)
+ Printf("ThreadSanitizer: memory flushed RSS=%llu\n", (u64)rss>>20);
+ }
+ last_rss = rss;
+ }
// Write memory profile if requested.
if (mprof_fd != kInvalidFd)
@@ -176,8 +200,10 @@ 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);
- if (addr != (uptr)MmapFixedNoReserve(addr, size)) {
- Printf("FATAL: ThreadSanitizer can not mmap thread trace\n");
+ uptr addr1 = (uptr)MmapFixedNoReserve(addr, size);
+ if (addr1 != addr) {
+ Printf("FATAL: ThreadSanitizer can not mmap thread trace (%p/%p->%p)\n",
+ addr, size, addr1);
Die();
}
}
@@ -206,23 +232,21 @@ void Initialize(ThreadState *thr) {
#endif
InitializeFlags(&ctx->flags, env);
// Setup correct file descriptor for error reports.
- if (internal_strcmp(flags()->log_path, "stdout") == 0)
- __sanitizer_set_report_fd(kStdoutFd);
- else if (internal_strcmp(flags()->log_path, "stderr") == 0)
- __sanitizer_set_report_fd(kStderrFd);
- else
- __sanitizer_set_report_path(flags()->log_path);
+ __sanitizer_set_report_path(flags()->log_path);
InitializeSuppressions();
#ifndef TSAN_GO
+ InitializeLibIgnore();
// Initialize external symbolizer before internal threads are started.
const char *external_symbolizer = flags()->external_symbolizer_path;
- if (external_symbolizer != 0 && external_symbolizer[0] != '\0') {
- if (!InitializeExternalSymbolizer(external_symbolizer)) {
- Printf("Failed to start external symbolizer: '%s'\n",
- external_symbolizer);
- Die();
- }
+ 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);
#endif
internal_start_thread(&BackgroundThread, 0);
@@ -556,7 +580,9 @@ static void MemoryRangeSet(ThreadState *thr, uptr pc, uptr addr, uptr size,
// Don't want to touch lots of shadow memory.
// If a program maps 10MB stack, there is no need reset the whole range.
size = (size + (kShadowCell - 1)) & ~(kShadowCell - 1);
- if (size < 64*1024) {
+ // UnmapOrDie/MmapFixedNoReserve does not work on Windows,
+ // so we do it only for C/C++.
+ if (kGoMode || size < 64*1024) {
u64 *p = (u64*)MemToShadow(addr);
CHECK(IsShadowMem((uptr)p));
CHECK(IsShadowMem((uptr)(p + size * kShadowCnt / kShadowCell - 1)));
@@ -636,9 +662,9 @@ void FuncEntry(ThreadState *thr, uptr 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[0]);
+ DCHECK_GE(thr->shadow_stack_pos, thr->shadow_stack);
#ifndef TSAN_GO
- DCHECK_LT(thr->shadow_stack_pos, &thr->shadow_stack[kShadowStackSize]);
+ 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;
@@ -664,23 +690,40 @@ void FuncExit(ThreadState *thr) {
thr->fast_state.IncrementEpoch();
TraceAddEvent(thr, thr->fast_state, EventTypeFuncExit, 0);
- DCHECK_GT(thr->shadow_stack_pos, &thr->shadow_stack[0]);
+ DCHECK_GT(thr->shadow_stack_pos, thr->shadow_stack);
#ifndef TSAN_GO
- DCHECK_LT(thr->shadow_stack_pos, &thr->shadow_stack[kShadowStackSize]);
+ DCHECK_LT(thr->shadow_stack_pos, thr->shadow_stack_end);
#endif
thr->shadow_stack_pos--;
}
-void IgnoreCtl(ThreadState *thr, bool write, bool begin) {
- DPrintf("#%d: IgnoreCtl(%d, %d)\n", thr->tid, write, begin);
- thr->ignore_reads_and_writes += begin ? 1 : -1;
+void ThreadIgnoreBegin(ThreadState *thr) {
+ DPrintf("#%d: ThreadIgnoreBegin\n", thr->tid);
+ thr->ignore_reads_and_writes++;
+ CHECK_GT(thr->ignore_reads_and_writes, 0);
+ thr->fast_state.SetIgnoreBit();
+}
+
+void ThreadIgnoreEnd(ThreadState *thr) {
+ 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)
- thr->fast_state.SetIgnoreBit();
- else
+ if (thr->ignore_reads_and_writes == 0)
thr->fast_state.ClearIgnoreBit();
}
+void ThreadIgnoreSyncBegin(ThreadState *thr) {
+ DPrintf("#%d: ThreadIgnoreSyncBegin\n", thr->tid);
+ thr->ignore_sync++;
+ CHECK_GT(thr->ignore_sync, 0);
+}
+
+void ThreadIgnoreSyncEnd(ThreadState *thr) {
+ DPrintf("#%d: ThreadIgnoreSyncEnd\n", thr->tid);
+ thr->ignore_sync--;
+ CHECK_GE(thr->ignore_sync, 0);
+}
+
bool MD5Hash::operator==(const MD5Hash &other) const {
return hash[0] == other.hash[0] && hash[1] == other.hash[1];
}
diff --git a/lib/tsan/rtl/tsan_rtl.h b/lib/tsan/rtl/tsan_rtl.h
index f1a73e457331..4ee667543a6e 100644
--- a/lib/tsan/rtl/tsan_rtl.h
+++ b/lib/tsan/rtl/tsan_rtl.h
@@ -27,7 +27,10 @@
#define TSAN_RTL_H
#include "sanitizer_common/sanitizer_allocator.h"
+#include "sanitizer_common/sanitizer_allocator_internal.h"
#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_libignore.h"
+#include "sanitizer_common/sanitizer_suppressions.h"
#include "sanitizer_common/sanitizer_thread_registry.h"
#include "tsan_clock.h"
#include "tsan_defs.h"
@@ -409,21 +412,19 @@ struct ThreadState {
// We do not distinguish beteween ignoring reads and writes
// for better performance.
int ignore_reads_and_writes;
+ int ignore_sync;
+ // C/C++ uses fixed size shadow stack embed into Trace.
+ // Go uses malloc-allocated shadow stack with dynamic size.
+ uptr *shadow_stack;
+ uptr *shadow_stack_end;
uptr *shadow_stack_pos;
u64 *racy_shadow_addr;
u64 racy_state[2];
-#ifndef TSAN_GO
- // C/C++ uses embed shadow stack of fixed size.
- uptr shadow_stack[kShadowStackSize];
-#else
- // Go uses satellite shadow stack with dynamic size.
- uptr *shadow_stack;
- uptr *shadow_stack_end;
-#endif
MutexSet mset;
ThreadClock clock;
#ifndef TSAN_GO
AllocatorCache alloc_cache;
+ InternalAllocatorCache internal_alloc_cache;
Vector<JmpBuf> jmp_bufs;
#endif
u64 stat[StatCnt];
@@ -431,6 +432,7 @@ struct ThreadState {
const int unique_id;
int in_rtl;
bool in_symbolizer;
+ bool in_ignored_lib;
bool is_alive;
bool is_freeing;
bool is_vptr_access;
@@ -531,7 +533,8 @@ struct Context {
Vector<RacyStacks> racy_stacks;
Vector<RacyAddress> racy_addresses;
- Vector<FiredSuppression> fired_suppressions;
+ // Number of fired suppressions may be large enough.
+ InternalMmapVector<FiredSuppression> fired_suppressions;
Flags flags;
@@ -594,13 +597,15 @@ void MapThreadTrace(uptr addr, uptr size);
void DontNeedShadowFor(uptr addr, uptr size);
void InitializeShadowMemory();
void InitializeInterceptors();
+void InitializeLibIgnore();
void InitializeDynamicAnnotations();
void ReportRace(ThreadState *thr);
bool OutputReport(Context *ctx,
const ScopedReport &srep,
const ReportStack *suppress_stack1 = 0,
- const ReportStack *suppress_stack2 = 0);
+ const ReportStack *suppress_stack2 = 0,
+ const ReportLocation *suppress_loc = 0);
bool IsFiredSuppression(Context *ctx,
const ScopedReport &srep,
const StackTrace &trace);
@@ -672,7 +677,11 @@ void ALWAYS_INLINE MemoryWriteAtomic(ThreadState *thr, uptr pc,
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 IgnoreCtl(ThreadState *thr, bool write, bool begin);
+
+void ThreadIgnoreBegin(ThreadState *thr);
+void ThreadIgnoreEnd(ThreadState *thr);
+void ThreadIgnoreSyncBegin(ThreadState *thr);
+void ThreadIgnoreSyncEnd(ThreadState *thr);
void FuncEntry(ThreadState *thr, uptr pc);
void FuncExit(ThreadState *thr);
@@ -696,12 +705,17 @@ int MutexUnlock(ThreadState *thr, uptr pc, uptr addr, bool all = false);
void MutexReadLock(ThreadState *thr, uptr pc, uptr addr);
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);
void AcquireGlobal(ThreadState *thr, uptr pc);
void Release(ThreadState *thr, uptr pc, uptr addr);
void ReleaseStore(ThreadState *thr, uptr pc, uptr addr);
void AfterSleep(ThreadState *thr, uptr pc);
+void AcquireImpl(ThreadState *thr, uptr pc, SyncClock *c);
+void ReleaseImpl(ThreadState *thr, uptr pc, SyncClock *c);
+void ReleaseStoreImpl(ThreadState *thr, uptr pc, SyncClock *c);
+void AcquireReleaseImpl(ThreadState *thr, uptr pc, SyncClock *c);
// The hacky call uses custom calling convention and an assembly thunk.
// It is considerably faster that a normal call for the caller
@@ -714,11 +728,11 @@ void AfterSleep(ThreadState *thr, uptr pc);
// 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_adjust_cfa_offset 1024;" \
".hidden " #f "_thunk;" \
"call " #f "_thunk;" \
"add $1024, %%rsp;" \
- "/*.cfi_adjust_cfa_offset -1024;*/" \
+ ".cfi_adjust_cfa_offset -1024;" \
::: "memory", "cc");
#else
#define HACKY_CALL(f) f()
diff --git a/lib/tsan/rtl/tsan_rtl_mutex.cc b/lib/tsan/rtl/tsan_rtl_mutex.cc
index cf2e44dd09ee..409391678f01 100644
--- a/lib/tsan/rtl/tsan_rtl_mutex.cc
+++ b/lib/tsan/rtl/tsan_rtl_mutex.cc
@@ -95,16 +95,13 @@ void MutexLock(ThreadState *thr, uptr pc, uptr addr, int rec) {
} else if (s->owner_tid == thr->tid) {
CHECK_GT(s->recursion, 0);
} else {
- Printf("ThreadSanitizer WARNING: double lock\n");
+ Printf("ThreadSanitizer WARNING: double lock of mutex %p\n", addr);
PrintCurrentStack(thr, pc);
}
if (s->recursion == 0) {
StatInc(thr, StatMutexLock);
- thr->clock.set(thr->tid, thr->fast_state.epoch());
- thr->clock.acquire(&s->clock);
- StatInc(thr, StatSyncAcquire);
- thr->clock.acquire(&s->read_clock);
- StatInc(thr, StatSyncAcquire);
+ AcquireImpl(thr, pc, &s->clock);
+ AcquireImpl(thr, pc, &s->read_clock);
} else if (!s->is_recursive) {
StatInc(thr, StatMutexRecLock);
}
@@ -125,13 +122,14 @@ int MutexUnlock(ThreadState *thr, uptr pc, uptr addr, bool all) {
if (s->recursion == 0) {
if (!s->is_broken) {
s->is_broken = true;
- Printf("ThreadSanitizer WARNING: unlock of unlocked mutex\n");
+ 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 unlock by another thread\n");
+ Printf("ThreadSanitizer WARNING: mutex %p is unlocked by wrong thread\n",
+ addr);
PrintCurrentStack(thr, pc);
}
} else {
@@ -140,10 +138,7 @@ int MutexUnlock(ThreadState *thr, uptr pc, uptr addr, bool all) {
if (s->recursion == 0) {
StatInc(thr, StatMutexUnlock);
s->owner_tid = SyncVar::kInvalidTid;
- thr->clock.set(thr->tid, thr->fast_state.epoch());
- thr->fast_synch_epoch = thr->fast_state.epoch();
- thr->clock.ReleaseStore(&s->clock);
- StatInc(thr, StatSyncRelease);
+ ReleaseStoreImpl(thr, pc, &s->clock);
} else {
StatInc(thr, StatMutexRecUnlock);
}
@@ -163,13 +158,12 @@ void MutexReadLock(ThreadState *thr, uptr pc, uptr addr) {
thr->fast_state.IncrementEpoch();
TraceAddEvent(thr, thr->fast_state, EventTypeRLock, s->GetId());
if (s->owner_tid != SyncVar::kInvalidTid) {
- Printf("ThreadSanitizer WARNING: read lock of a write locked mutex\n");
+ Printf("ThreadSanitizer WARNING: read lock of a write locked mutex %p\n",
+ addr);
PrintCurrentStack(thr, pc);
}
- thr->clock.set(thr->tid, thr->fast_state.epoch());
- thr->clock.acquire(&s->clock);
+ AcquireImpl(thr, pc, &s->clock);
s->last_lock = thr->fast_state.raw();
- StatInc(thr, StatSyncAcquire);
thr->mset.Add(s->GetId(), false, thr->fast_state.epoch());
s->mtx.ReadUnlock();
}
@@ -184,14 +178,11 @@ void MutexReadUnlock(ThreadState *thr, uptr pc, uptr addr) {
thr->fast_state.IncrementEpoch();
TraceAddEvent(thr, thr->fast_state, EventTypeRUnlock, s->GetId());
if (s->owner_tid != SyncVar::kInvalidTid) {
- Printf("ThreadSanitizer WARNING: read unlock of a write "
- "locked mutex\n");
+ Printf("ThreadSanitizer WARNING: read unlock of a write locked mutex %p\n",
+ addr);
PrintCurrentStack(thr, pc);
}
- thr->clock.set(thr->tid, thr->fast_state.epoch());
- thr->fast_synch_epoch = thr->fast_state.epoch();
- thr->clock.release(&s->read_clock);
- StatInc(thr, StatSyncRelease);
+ ReleaseImpl(thr, pc, &s->read_clock);
s->mtx.Unlock();
thr->mset.Del(s->GetId(), false);
}
@@ -209,10 +200,7 @@ void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr) {
StatInc(thr, StatMutexReadUnlock);
thr->fast_state.IncrementEpoch();
TraceAddEvent(thr, thr->fast_state, EventTypeRUnlock, s->GetId());
- thr->clock.set(thr->tid, thr->fast_state.epoch());
- thr->fast_synch_epoch = thr->fast_state.epoch();
- thr->clock.release(&s->read_clock);
- StatInc(thr, StatSyncRelease);
+ ReleaseImpl(thr, pc, &s->read_clock);
} else if (s->owner_tid == thr->tid) {
// Seems to be write unlock.
thr->fast_state.IncrementEpoch();
@@ -222,33 +210,37 @@ void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr) {
if (s->recursion == 0) {
StatInc(thr, StatMutexUnlock);
s->owner_tid = SyncVar::kInvalidTid;
- // FIXME: Refactor me, plz.
- // The sequence of events is quite tricky and doubled in several places.
- // First, it's a bug to increment the epoch w/o writing to the trace.
- // Then, the acquire/release logic can be factored out as well.
- thr->clock.set(thr->tid, thr->fast_state.epoch());
- thr->fast_synch_epoch = thr->fast_state.epoch();
- thr->clock.ReleaseStore(&s->clock);
- StatInc(thr, StatSyncRelease);
+ ReleaseImpl(thr, pc, &s->clock);
} else {
StatInc(thr, StatMutexRecUnlock);
}
} else if (!s->is_broken) {
s->is_broken = true;
- Printf("ThreadSanitizer WARNING: mutex unlock by another thread\n");
+ Printf("ThreadSanitizer WARNING: mutex %p is unlock by wrong thread\n",
+ addr);
PrintCurrentStack(thr, pc);
}
thr->mset.Del(s->GetId(), write);
s->mtx.Unlock();
}
+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);
+ 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);
- thr->clock.set(thr->tid, thr->fast_state.epoch());
- thr->clock.acquire(&s->clock);
- StatInc(thr, StatSyncAcquire);
+ AcquireImpl(thr, pc, &s->clock);
s->mtx.ReadUnlock();
}
@@ -262,6 +254,9 @@ static void UpdateClockCallback(ThreadContextBase *tctx_base, void *arg) {
}
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(
UpdateClockCallback, thr);
@@ -270,20 +265,26 @@ void AcquireGlobal(ThreadState *thr, uptr pc) {
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);
- thr->clock.set(thr->tid, thr->fast_state.epoch());
- thr->clock.release(&s->clock);
- StatInc(thr, StatSyncRelease);
+ 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);
s->mtx.Unlock();
}
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);
- thr->clock.set(thr->tid, thr->fast_state.epoch());
- thr->clock.ReleaseStore(&s->clock);
- StatInc(thr, StatSyncRelease);
+ thr->fast_state.IncrementEpoch();
+ // Can't increment epoch w/o writing to the trace as well.
+ TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0);
+ ReleaseStoreImpl(thr, pc, &s->clock);
s->mtx.Unlock();
}
@@ -298,6 +299,9 @@ static void UpdateSleepClockCallback(ThreadContextBase *tctx_base, void *arg) {
}
void AfterSleep(ThreadState *thr, uptr pc) {
+ DPrintf("#%d: AfterSleep %zx\n", thr->tid);
+ if (thr->ignore_sync)
+ return;
thr->last_sleep_stack_id = CurrentStackId(thr, pc);
ThreadRegistryLock l(CTX()->thread_registry);
CTX()->thread_registry->RunCallbackForEachThreadLocked(
@@ -305,4 +309,40 @@ void AfterSleep(ThreadState *thr, uptr pc) {
}
#endif
+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);
+ 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->fast_synch_epoch = thr->fast_state.epoch();
+ thr->clock.release(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->fast_synch_epoch = thr->fast_state.epoch();
+ thr->clock.ReleaseStore(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->fast_synch_epoch = thr->fast_state.epoch();
+ thr->clock.acq_rel(c);
+ StatInc(thr, StatSyncAcquire);
+ StatInc(thr, StatSyncRelease);
+}
+
} // namespace __tsan
diff --git a/lib/tsan/rtl/tsan_rtl_report.cc b/lib/tsan/rtl/tsan_rtl_report.cc
index f77a7a2efa96..4fed43faf25f 100644
--- a/lib/tsan/rtl/tsan_rtl_report.cc
+++ b/lib/tsan/rtl/tsan_rtl_report.cc
@@ -95,8 +95,9 @@ static void StackStripMain(ReportStack *stack) {
DPrintf("Bottom stack frame of stack %zx is missed\n", stack->pc);
}
#else
- if (last && 0 == internal_strcmp(last, "schedunlock"))
- last_frame2->next = 0;
+ // The last frame always point into runtime (gosched0, goexit0, runtime.main).
+ last_frame2->next = 0;
+ (void)last;
#endif
}
@@ -105,17 +106,25 @@ static ReportStack *SymbolizeStack(const StackTrace& trace) {
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.
- bool is_last = (si == trace.Size() - 1);
- ReportStack *ent = SymbolizeCode(trace.Get(si) - !is_last);
+ const uptr pc1 = __sanitizer::StackTrace::GetPreviousInstructionPc(pc);
+#else
+ // FIXME(dvyukov): Go sometimes uses address of a function as top pc.
+ uptr pc1 = pc;
+ if (si != trace.Size() - 1)
+ pc1 -= 1;
+#endif
+ ReportStack *ent = SymbolizeCode(pc1);
CHECK_NE(ent, 0);
ReportStack *last = ent;
while (last->next) {
- last->pc += !is_last;
+ last->pc = pc; // restore original pc for report
last = last->next;
}
- last->pc += !is_last;
+ last->pc = pc; // restore original pc for report
last->next = stack;
stack = ent;
}
@@ -401,7 +410,7 @@ void RestoreStack(int tid, const u64 epoch, StackTrace *stk, MutexSet *mset) {
const u64 ebegin = RoundDown(eend, kTracePartSize);
DPrintf("#%d: RestoreStack epoch=%zu ebegin=%zu eend=%zu partidx=%d\n",
tid, (uptr)epoch, (uptr)ebegin, (uptr)eend, partidx);
- InternalScopedBuffer<uptr> stack(1024); // FIXME: de-hardcode 1024
+ InternalScopedBuffer<uptr> stack(kShadowStackSize);
for (uptr i = 0; i < hdr->stack0.Size(); i++) {
stack[i] = hdr->stack0.Get(i);
DPrintf2(" #%02lu: pc=%zx\n", i, stack[i]);
@@ -501,28 +510,33 @@ 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 ReportStack *suppress_stack2,
+ const ReportLocation *suppress_loc) {
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);
if (suppress_pc != 0) {
FiredSuppression s = {srep.GetReport()->typ, suppress_pc, supp};
- ctx->fired_suppressions.PushBack(s);
+ ctx->fired_suppressions.push_back(s);
}
if (OnReport(rep, suppress_pc != 0))
return false;
PrintReport(rep);
- CTX()->nreported++;
+ ctx->nreported++;
+ if (flags()->halt_on_error)
+ internal__exit(flags()->exitcode);
return true;
}
bool IsFiredSuppression(Context *ctx,
const ScopedReport &srep,
const StackTrace &trace) {
- for (uptr k = 0; k < ctx->fired_suppressions.Size(); k++) {
+ 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++) {
@@ -537,6 +551,22 @@ bool IsFiredSuppression(Context *ctx,
return false;
}
+static bool IsFiredSuppression(Context *ctx,
+ const ScopedReport &srep,
+ uptr addr) {
+ for (uptr k = 0; k < ctx->fired_suppressions.size(); k++) {
+ if (ctx->fired_suppressions[k].type != srep.GetReport()->typ)
+ continue;
+ FiredSuppression *s = &ctx->fired_suppressions[k];
+ if (addr == s->pc) {
+ if (s->supp)
+ s->supp->hit_count++;
+ return true;
+ }
+ }
+ return false;
+}
+
bool FrameIsInternal(const ReportStack *frame) {
return frame != 0 && frame->file != 0
&& (internal_strstr(frame->file, "tsan_interceptors.cc") ||
@@ -569,7 +599,7 @@ static bool IsJavaNonsense(const ReportDesc *rep) {
&& frame->module == 0)) {
if (frame) {
FiredSuppression supp = {rep->typ, frame->pc, 0};
- CTX()->fired_suppressions.PushBack(supp);
+ CTX()->fired_suppressions.push_back(supp);
}
return true;
}
@@ -630,6 +660,8 @@ void ReportRace(ThreadState *thr) {
else if (freed)
typ = ReportTypeUseAfterFree;
ScopedReport rep(typ);
+ if (IsFiredSuppression(ctx, rep, addr))
+ return;
const uptr kMop = 2;
StackTrace traces[kMop];
const uptr toppc = TraceTopPC(thr);
@@ -640,6 +672,8 @@ void ReportRace(ThreadState *thr) {
new(mset2.data()) MutexSet();
Shadow s2(thr->racy_state[1]);
RestoreStack(s2.tid(), s2.epoch(), &traces[1], mset2.data());
+ if (IsFiredSuppression(ctx, rep, traces[1]))
+ return;
if (HandleRacyStacks(thr, traces, addr_min, addr_max))
return;
@@ -672,8 +706,11 @@ 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))
+ rep.GetReport()->mops[1]->stack,
+ suppress_loc))
return;
AddRacyStacks(thr, traces, addr_min, addr_max);
@@ -689,8 +726,8 @@ void PrintCurrentStackSlow() {
#ifndef TSAN_GO
__sanitizer::StackTrace *ptrace = new(internal_alloc(MBlockStackTrace,
sizeof(__sanitizer::StackTrace))) __sanitizer::StackTrace;
- ptrace->SlowUnwindStack(__sanitizer::StackTrace::GetCurrentPc(),
- kStackTraceMax);
+ ptrace->Unwind(kStackTraceMax, __sanitizer::StackTrace::GetCurrentPc(),
+ 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];
diff --git a/lib/tsan/rtl/tsan_rtl_thread.cc b/lib/tsan/rtl/tsan_rtl_thread.cc
index ee13fa18db3f..4e451b042947 100644
--- a/lib/tsan/rtl/tsan_rtl_thread.cc
+++ b/lib/tsan/rtl/tsan_rtl_thread.cc
@@ -41,8 +41,7 @@ void ThreadContext::OnDead() {
void ThreadContext::OnJoined(void *arg) {
ThreadState *caller_thr = static_cast<ThreadState *>(arg);
- caller_thr->clock.acquire(&sync);
- StatInc(caller_thr, StatSyncAcquire);
+ AcquireImpl(caller_thr, 0, &sync);
sync.Reset();
}
@@ -59,10 +58,7 @@ void ThreadContext::OnCreated(void *arg) {
args->thr->fast_state.IncrementEpoch();
// Can't increment epoch w/o writing to the trace as well.
TraceAddEvent(args->thr, args->thr->fast_state, EventTypeMop, 0);
- args->thr->clock.set(args->thr->tid, args->thr->fast_state.epoch());
- args->thr->fast_synch_epoch = args->thr->fast_state.epoch();
- args->thr->clock.release(&sync);
- StatInc(args->thr, StatSyncRelease);
+ ReleaseImpl(args->thr, 0, &sync);
#ifdef TSAN_GO
creation_stack.ObtainCurrent(args->thr, args->pc);
#else
@@ -95,21 +91,23 @@ void ThreadContext::OnStarted(void *arg) {
epoch1 = (u64)-1;
new(thr) ThreadState(CTX(), tid, unique_id,
epoch0, args->stk_addr, args->stk_size, args->tls_addr, args->tls_size);
-#ifdef TSAN_GO
+#ifndef TSAN_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;
+#else
// Setup dynamic shadow stack.
const int kInitStackSize = 8;
- args->thr->shadow_stack = (uptr*)internal_alloc(MBlockShadowStack,
+ thr->shadow_stack = (uptr*)internal_alloc(MBlockShadowStack,
kInitStackSize * sizeof(uptr));
- args->thr->shadow_stack_pos = thr->shadow_stack;
- args->thr->shadow_stack_end = thr->shadow_stack + kInitStackSize;
+ thr->shadow_stack_pos = thr->shadow_stack;
+ thr->shadow_stack_end = thr->shadow_stack + kInitStackSize;
#endif
#ifndef TSAN_GO
- AllocatorThreadStart(args->thr);
+ AllocatorThreadStart(thr);
#endif
- thr = args->thr;
thr->fast_synch_epoch = epoch0;
- thr->clock.set(tid, epoch0);
- thr->clock.acquire(&sync);
+ AcquireImpl(thr, 0, &sync);
thr->fast_state.SetHistorySize(flags()->history_size);
const uptr trace = (epoch0 / kTracePartSize) % TraceParts();
Trace *thr_trace = ThreadTrace(thr->tid);
@@ -128,10 +126,7 @@ void ThreadContext::OnFinished() {
thr->fast_state.IncrementEpoch();
// Can't increment epoch w/o writing to the trace as well.
TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0);
- thr->clock.set(thr->tid, thr->fast_state.epoch());
- thr->fast_synch_epoch = thr->fast_state.epoch();
- thr->clock.release(&sync);
- StatInc(thr, StatSyncRelease);
+ ReleaseImpl(thr, 0, &sync);
}
epoch1 = thr->fast_state.epoch();
@@ -170,6 +165,10 @@ static void ThreadCheckIgnore(ThreadState *thr) {
Printf("ThreadSanitizer: thread T%d finished with ignores enabled.\n",
thr->tid);
}
+ if (thr->ignore_sync) {
+ Printf("ThreadSanitizer: thread T%d finished with sync ignores enabled.\n",
+ thr->tid);
+ }
}
void ThreadFinalize(ThreadState *thr) {
@@ -374,25 +373,4 @@ void MemoryAccessRange(ThreadState *thr, uptr pc, uptr addr,
}
}
-void MemoryAccessRangeStep(ThreadState *thr, uptr pc, uptr addr,
- uptr size, uptr step, bool is_write) {
- if (size == 0)
- return;
- FastState fast_state = thr->fast_state;
- if (fast_state.GetIgnoreBit())
- return;
- StatInc(thr, StatMopRange);
- fast_state.IncrementEpoch();
- thr->fast_state = fast_state;
- TraceAddEvent(thr, fast_state, EventTypeMop, pc);
-
- for (uptr addr_end = addr + size; addr < addr_end; addr += step) {
- u64 *shadow_mem = (u64*)MemToShadow(addr);
- Shadow cur(fast_state);
- cur.SetWrite(is_write);
- cur.SetAddr0AndSizeLog(addr & (kShadowCell - 1), kSizeLog1);
- MemoryAccessImpl(thr, addr, kSizeLog1, is_write, false,
- shadow_mem, cur);
- }
-}
} // namespace __tsan
diff --git a/lib/tsan/rtl/tsan_stat.cc b/lib/tsan/rtl/tsan_stat.cc
index 9676e0872e08..f9dbf121cef4 100644
--- a/lib/tsan/rtl/tsan_stat.cc
+++ b/lib/tsan/rtl/tsan_stat.cc
@@ -138,9 +138,11 @@ void StatOutput(u64 *stat) {
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 ";
@@ -180,6 +182,7 @@ void StatOutput(u64 *stat) {
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 ";
@@ -229,11 +232,13 @@ void StatOutput(u64 *stat) {
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 ";
@@ -253,8 +258,10 @@ void StatOutput(u64 *stat) {
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 ";
@@ -285,6 +292,7 @@ void StatOutput(u64 *stat) {
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 ";
@@ -311,7 +319,9 @@ void StatOutput(u64 *stat) {
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 ";
@@ -322,6 +332,99 @@ void StatOutput(u64 *stat) {
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 ";
@@ -353,6 +456,8 @@ void StatOutput(u64 *stat) {
name[StatAnnotateIgnoreReadsEnd] = " IgnoreReadsEnd ";
name[StatAnnotateIgnoreWritesBegin] = " IgnoreWritesBegin ";
name[StatAnnotateIgnoreWritesEnd] = " IgnoreWritesEnd ";
+ name[StatAnnotateIgnoreSyncBegin] = " IgnoreSyncBegin ";
+ name[StatAnnotateIgnoreSyncEnd] = " IgnoreSyncEnd ";
name[StatAnnotatePublishMemoryRange] = " PublishMemoryRange ";
name[StatAnnotateUnpublishMemoryRange] = " UnpublishMemoryRange ";
name[StatAnnotateThreadName] = " ThreadName ";
diff --git a/lib/tsan/rtl/tsan_stat.h b/lib/tsan/rtl/tsan_stat.h
index d5c8b4389394..a44edfcd65c6 100644
--- a/lib/tsan/rtl/tsan_stat.h
+++ b/lib/tsan/rtl/tsan_stat.h
@@ -137,7 +137,9 @@ enum StatType {
StatInt_strcasecmp,
StatInt_strncasecmp,
StatInt_strstr,
+ StatInt_strdup,
StatInt_atexit,
+ StatInt__exit,
StatInt___cxa_guard_acquire,
StatInt___cxa_guard_release,
StatInt___cxa_guard_abort,
@@ -175,6 +177,7 @@ enum StatType {
StatInt_pthread_barrier_wait,
StatInt_pthread_once,
StatInt_pthread_getschedparam,
+ StatInt_pthread_setname_np,
StatInt_sem_init,
StatInt_sem_destroy,
StatInt_sem_wait,
@@ -224,11 +227,13 @@ enum StatType {
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,
@@ -248,8 +253,10 @@ enum StatType {
StatInt_epoll_ctl,
StatInt_epoll_wait,
StatInt_poll,
+ StatInt_ppoll,
StatInt_sigaction,
StatInt_signal,
+ StatInt_sigsuspend,
StatInt_raise,
StatInt_kill,
StatInt_pthread_kill,
@@ -280,6 +287,7 @@ enum StatType {
StatInt_ctime_r,
StatInt_asctime,
StatInt_asctime_r,
+ StatInt_strptime,
StatInt_frexp,
StatInt_frexpf,
StatInt_frexpl,
@@ -306,7 +314,9 @@ enum StatType {
StatInt_wait4,
StatInt_inet_ntop,
StatInt_inet_pton,
+ StatInt_inet_aton,
StatInt_getaddrinfo,
+ StatInt_getnameinfo,
StatInt_getsockname,
StatInt_gethostent,
StatInt_gethostbyname,
@@ -317,6 +327,99 @@ enum StatType {
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,
@@ -349,6 +452,8 @@ enum StatType {
StatAnnotateIgnoreReadsEnd,
StatAnnotateIgnoreWritesBegin,
StatAnnotateIgnoreWritesEnd,
+ StatAnnotateIgnoreSyncBegin,
+ StatAnnotateIgnoreSyncEnd,
StatAnnotatePublishMemoryRange,
StatAnnotateUnpublishMemoryRange,
StatAnnotateThreadName,
diff --git a/lib/tsan/rtl/tsan_suppressions.cc b/lib/tsan/rtl/tsan_suppressions.cc
index 6c49355bed88..4b0ac04c48a6 100644
--- a/lib/tsan/rtl/tsan_suppressions.cc
+++ b/lib/tsan/rtl/tsan_suppressions.cc
@@ -13,12 +13,25 @@
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_libc.h"
+#include "sanitizer_common/sanitizer_placement_new.h"
+#include "sanitizer_common/sanitizer_suppressions.h"
#include "tsan_suppressions.h"
#include "tsan_rtl.h"
#include "tsan_flags.h"
#include "tsan_mman.h"
#include "tsan_platform.h"
+// Suppressions for true/false positives in standard libraries.
+static const char *const std_suppressions =
+// Libstdc++ 4.4 has data races in std::string.
+// See http://crbug.com/181502 for an example.
+"race:^_M_rep$\n"
+"race:^_M_is_leaked$\n"
+// False positive when using std <thread>.
+// Happens because we miss atomic synchronization in libstdc++.
+// See http://llvm.org/bugs/show_bug.cgi?id=17066 for details.
+"race:std::_Sp_counted_ptr_inplace<std::thread::_Impl\n";
+
// Can be overriden in frontend.
#ifndef TSAN_GO
extern "C" const char *WEAK __tsan_default_suppressions() {
@@ -28,7 +41,7 @@ extern "C" const char *WEAK __tsan_default_suppressions() {
namespace __tsan {
-static Suppression *g_suppressions;
+static SuppressionContext* g_ctx;
static char *ReadFile(const char *filename) {
if (filename == 0 || filename[0] == 0)
@@ -62,143 +75,96 @@ static char *ReadFile(const char *filename) {
return buf;
}
-bool SuppressionMatch(char *templ, const char *str) {
- if (str == 0 || str[0] == 0)
- return false;
- char *tpos;
- const char *spos;
- while (templ && templ[0]) {
- if (templ[0] == '*') {
- templ++;
- continue;
- }
- if (str[0] == 0)
- return false;
- tpos = (char*)internal_strchr(templ, '*');
- if (tpos != 0)
- tpos[0] = 0;
- spos = internal_strstr(str, templ);
- str = spos + internal_strlen(templ);
- templ = tpos;
- if (tpos)
- tpos[0] = '*';
- if (spos == 0)
- return false;
- }
- return true;
-}
-
-Suppression *SuppressionParse(Suppression *head, const char* supp) {
- const char *line = supp;
- while (line) {
- while (line[0] == ' ' || line[0] == '\t')
- line++;
- const char *end = internal_strchr(line, '\n');
- if (end == 0)
- end = line + internal_strlen(line);
- if (line != end && line[0] != '#') {
- const char *end2 = end;
- while (line != end2 && (end2[-1] == ' ' || end2[-1] == '\t'))
- end2--;
- SuppressionType stype;
- if (0 == internal_strncmp(line, "race:", sizeof("race:") - 1)) {
- stype = SuppressionRace;
- line += sizeof("race:") - 1;
- } else if (0 == internal_strncmp(line, "thread:",
- sizeof("thread:") - 1)) {
- stype = SuppressionThread;
- line += sizeof("thread:") - 1;
- } else if (0 == internal_strncmp(line, "mutex:",
- sizeof("mutex:") - 1)) {
- stype = SuppressionMutex;
- line += sizeof("mutex:") - 1;
- } else if (0 == internal_strncmp(line, "signal:",
- sizeof("signal:") - 1)) {
- stype = SuppressionSignal;
- line += sizeof("signal:") - 1;
- } else {
- Printf("ThreadSanitizer: failed to parse suppressions file\n");
- Die();
- }
- Suppression *s = (Suppression*)internal_alloc(MBlockSuppression,
- sizeof(Suppression));
- s->next = head;
- head = s;
- s->type = stype;
- s->templ = (char*)internal_alloc(MBlockSuppression, end2 - line + 1);
- internal_memcpy(s->templ, line, end2 - line);
- s->templ[end2 - line] = 0;
- s->hit_count = 0;
- }
- if (end[0] == 0)
- break;
- line = end + 1;
- }
- return head;
-}
-
void InitializeSuppressions() {
+ ALIGNED(64) static char placeholder_[sizeof(SuppressionContext)];
+ g_ctx = new(placeholder_) SuppressionContext;
const char *supp = ReadFile(flags()->suppressions);
- g_suppressions = SuppressionParse(0, supp);
+ g_ctx->Parse(supp);
#ifndef TSAN_GO
supp = __tsan_default_suppressions();
- g_suppressions = SuppressionParse(g_suppressions, supp);
+ g_ctx->Parse(supp);
+ g_ctx->Parse(std_suppressions);
#endif
}
-uptr IsSuppressed(ReportType typ, const ReportStack *stack, Suppression **sp) {
- if (g_suppressions == 0 || stack == 0)
- return 0;
- SuppressionType stype;
+SuppressionContext *GetSuppressionContext() {
+ CHECK_NE(g_ctx, 0);
+ return g_ctx;
+}
+
+SuppressionType conv(ReportType typ) {
if (typ == ReportTypeRace)
- stype = SuppressionRace;
+ return SuppressionRace;
+ else if (typ == ReportTypeVptrRace)
+ return SuppressionRace;
+ else if (typ == ReportTypeUseAfterFree)
+ return SuppressionRace;
else if (typ == ReportTypeThreadLeak)
- stype = SuppressionThread;
+ return SuppressionThread;
else if (typ == ReportTypeMutexDestroyLocked)
- stype = SuppressionMutex;
+ return SuppressionMutex;
else if (typ == ReportTypeSignalUnsafe)
- stype = SuppressionSignal;
- else
+ return SuppressionSignal;
+ else if (typ == ReportTypeErrnoInSignal)
+ return SuppressionNone;
+ 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;
+ SuppressionType stype = conv(typ);
+ if (stype == SuppressionNone)
return 0;
+ Suppression *s;
for (const ReportStack *frame = stack; frame; frame = frame->next) {
- for (Suppression *supp = g_suppressions; supp; supp = supp->next) {
- if (stype == supp->type &&
- (SuppressionMatch(supp->templ, frame->func) ||
- SuppressionMatch(supp->templ, frame->file) ||
- SuppressionMatch(supp->templ, frame->module))) {
- DPrintf("ThreadSanitizer: matched suppression '%s'\n", supp->templ);
- supp->hit_count++;
- *sp = supp;
- return frame->pc;
- }
+ if (g_ctx->Match(frame->func, stype, &s) ||
+ g_ctx->Match(frame->file, stype, &s) ||
+ g_ctx->Match(frame->module, stype, &s)) {
+ DPrintf("ThreadSanitizer: matched suppression '%s'\n", s->templ);
+ s->hit_count++;
+ *sp = s;
+ return frame->pc;
}
}
return 0;
}
-static const char *SuppTypeStr(SuppressionType t) {
- switch (t) {
- case SuppressionRace: return "race";
- case SuppressionMutex: return "mutex";
- case SuppressionThread: return "thread";
- case SuppressionSignal: return "signal";
+uptr IsSuppressed(ReportType typ, const ReportLocation *loc, Suppression **sp) {
+ CHECK(g_ctx);
+ if (!g_ctx->SuppressionCount() || loc == 0 ||
+ loc->type != ReportLocationGlobal)
+ 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)) {
+ DPrintf("ThreadSanitizer: matched suppression '%s'\n", s->templ);
+ s->hit_count++;
+ *sp = s;
+ return loc->addr;
}
- CHECK(0);
- return "unknown";
+ return 0;
}
void PrintMatchedSuppressions() {
- int hit_count = 0;
- for (Suppression *supp = g_suppressions; supp; supp = supp->next)
- hit_count += supp->hit_count;
- if (hit_count == 0)
+ CHECK(g_ctx);
+ InternalMmapVector<Suppression *> matched(1);
+ g_ctx->GetMatched(&matched);
+ if (!matched.size())
return;
- Printf("ThreadSanitizer: Matched %d suppressions (pid=%d):\n",
- hit_count, (int)internal_getpid());
- for (Suppression *supp = g_suppressions; supp; supp = supp->next) {
- if (supp->hit_count == 0)
- continue;
- Printf("%d %s:%s\n", supp->hit_count, SuppTypeStr(supp->type), supp->templ);
+ int hit_count = 0;
+ for (uptr i = 0; i < matched.size(); i++)
+ hit_count += matched[i]->hit_count;
+ Printf("ThreadSanitizer: Matched %d suppressions (pid=%d):\n", hit_count,
+ (int)internal_getpid());
+ for (uptr i = 0; i < matched.size(); i++) {
+ Printf("%d %s:%s\n", matched[i]->hit_count,
+ SuppressionTypeString(matched[i]->type), matched[i]->templ);
}
}
} // namespace __tsan
diff --git a/lib/tsan/rtl/tsan_suppressions.h b/lib/tsan/rtl/tsan_suppressions.h
index 1c98363383dc..fe7db588f50f 100644
--- a/lib/tsan/rtl/tsan_suppressions.h
+++ b/lib/tsan/rtl/tsan_suppressions.h
@@ -13,31 +13,16 @@
#ifndef TSAN_SUPPRESSIONS_H
#define TSAN_SUPPRESSIONS_H
+#include "sanitizer_common/sanitizer_suppressions.h"
#include "tsan_report.h"
namespace __tsan {
-// Exposed for testing.
-enum SuppressionType {
- SuppressionRace,
- SuppressionMutex,
- SuppressionThread,
- SuppressionSignal
-};
-
-struct Suppression {
- Suppression *next;
- SuppressionType type;
- char *templ;
- int hit_count;
-};
-
void InitializeSuppressions();
-void FinalizeSuppressions();
void PrintMatchedSuppressions();
uptr IsSuppressed(ReportType typ, const ReportStack *stack, Suppression **sp);
-Suppression *SuppressionParse(Suppression *head, const char* supp);
-bool SuppressionMatch(char *templ, const char *str);
+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 12226064f5a4..75acf1d8438b 100644
--- a/lib/tsan/rtl/tsan_symbolize.cc
+++ b/lib/tsan/rtl/tsan_symbolize.cc
@@ -22,19 +22,17 @@
namespace __tsan {
-struct ScopedInSymbolizer {
- ScopedInSymbolizer() {
- ThreadState *thr = cur_thread();
- CHECK(!thr->in_symbolizer);
- thr->in_symbolizer = true;
- }
+void EnterSymbolizer() {
+ ThreadState *thr = cur_thread();
+ CHECK(!thr->in_symbolizer);
+ thr->in_symbolizer = true;
+}
- ~ScopedInSymbolizer() {
- ThreadState *thr = cur_thread();
- CHECK(thr->in_symbolizer);
- thr->in_symbolizer = false;
- }
-};
+void ExitSymbolizer() {
+ ThreadState *thr = cur_thread();
+ CHECK(thr->in_symbolizer);
+ thr->in_symbolizer = false;
+}
ReportStack *NewReportStackEntry(uptr addr) {
ReportStack *ent = (ReportStack*)internal_alloc(MBlockReportStack,
@@ -44,18 +42,6 @@ ReportStack *NewReportStackEntry(uptr addr) {
return ent;
}
-// Strip module path to make output shorter.
-static 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 ReportStack *NewReportStackEntry(const AddressInfo &info) {
ReportStack *ent = NewReportStackEntry(info.address);
ent->module = StripModuleName(info.module);
@@ -69,16 +55,64 @@ static ReportStack *NewReportStackEntry(const AddressInfo &info) {
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,
+ char *func_buf, uptr func_siz,
+ char *file_buf, uptr file_siz,
+ int *line, int *col)
+ SANITIZER_WEAK_ATTRIBUTE;
+
+bool __tsan_symbolize_external(uptr pc,
+ char *func_buf, uptr func_siz,
+ char *file_buf, uptr file_siz,
+ int *line, int *col) {
+ return false;
+}
+
ReportStack *SymbolizeCode(uptr addr) {
- if (!IsSymbolizerAvailable())
+ // Check if PC comes from non-native land.
+ if (addr & kExternalPCBit) {
+ // Declare static to not consume too much stack space.
+ // We symbolize reports in a single thread, so this is fine.
+ 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);
- ScopedInSymbolizer in_symbolizer;
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 = __sanitizer::SymbolizeCode(addr, addr_frames.data(),
- kMaxAddrFrames);
+ uptr addr_frames_num = Symbolizer::Get()->SymbolizeCode(
+ addr, addr_frames.data(), kMaxAddrFrames);
if (addr_frames_num == 0)
return NewReportStackEntry(addr);
ReportStack *top = 0;
@@ -97,11 +131,10 @@ ReportStack *SymbolizeCode(uptr addr) {
}
ReportLocation *SymbolizeData(uptr addr) {
- if (!IsSymbolizerAvailable())
+ if (!Symbolizer::Get()->IsAvailable())
return 0;
- ScopedInSymbolizer in_symbolizer;
DataInfo info;
- if (!__sanitizer::SymbolizeData(addr, &info))
+ if (!Symbolizer::Get()->SymbolizeData(addr, &info))
return 0;
ReportLocation *ent = (ReportLocation*)internal_alloc(MBlockReportStack,
sizeof(ReportLocation));
@@ -117,10 +150,9 @@ ReportLocation *SymbolizeData(uptr addr) {
}
void SymbolizeFlush() {
- if (!IsSymbolizerAvailable())
+ if (!Symbolizer::Get()->IsAvailable())
return;
- ScopedInSymbolizer in_symbolizer;
- __sanitizer::FlushSymbolizer();
+ Symbolizer::Get()->Flush();
}
} // namespace __tsan
diff --git a/lib/tsan/rtl/tsan_symbolize.h b/lib/tsan/rtl/tsan_symbolize.h
index 7bc6123df57d..6282e45b40d5 100644
--- a/lib/tsan/rtl/tsan_symbolize.h
+++ b/lib/tsan/rtl/tsan_symbolize.h
@@ -18,6 +18,8 @@
namespace __tsan {
+void EnterSymbolizer();
+void ExitSymbolizer();
ReportStack *SymbolizeCode(uptr addr);
ReportLocation *SymbolizeData(uptr addr);
void SymbolizeFlush();
diff --git a/lib/tsan/rtl/tsan_symbolize_addr2line_linux.cc b/lib/tsan/rtl/tsan_symbolize_addr2line_linux.cc
index 47f9e1fbf418..b186d3b38ec9 100644
--- a/lib/tsan/rtl/tsan_symbolize_addr2line_linux.cc
+++ b/lib/tsan/rtl/tsan_symbolize_addr2line_linux.cc
@@ -60,7 +60,6 @@ static void NOINLINE InitModule(ModuleDesc *m) {
}
int pid = fork();
if (pid == 0) {
- __sanitizer_set_report_fd(STDERR_FILENO);
internal_close(STDOUT_FILENO);
internal_close(STDIN_FILENO);
internal_dup2(outfd[0], STDIN_FILENO);
diff --git a/lib/tsan/rtl/tsan_sync.cc b/lib/tsan/rtl/tsan_sync.cc
index c6ddcdb37426..f8f3c40fab04 100644
--- a/lib/tsan/rtl/tsan_sync.cc
+++ b/lib/tsan/rtl/tsan_sync.cc
@@ -265,6 +265,11 @@ void StackTrace::ObtainCurrent(ThreadState *thr, uptr toppc) {
n_ = c_ - !!toppc;
}
} else {
+ // Cap potentially huge stacks.
+ if (n_ + !!toppc > kTraceStackSize) {
+ start = n_ - kTraceStackSize + !!toppc;
+ n_ = kTraceStackSize - !!toppc;
+ }
s_ = (uptr*)internal_alloc(MBlockStackTrace,
(n_ + !!toppc) * sizeof(s_[0]));
}
diff --git a/lib/tsan/rtl/tsan_trace.h b/lib/tsan/rtl/tsan_trace.h
index 7df716046567..5ed0356e2bf5 100644
--- a/lib/tsan/rtl/tsan_trace.h
+++ b/lib/tsan/rtl/tsan_trace.h
@@ -62,6 +62,11 @@ struct TraceHeader {
struct Trace {
TraceHeader headers[kTraceParts];
Mutex mtx;
+#ifndef TSAN_GO
+ // Must be last to catch overflow as paging fault.
+ // Go shadow stack is dynamically allocated.
+ uptr shadow_stack[kShadowStackSize];
+#endif
Trace()
: mtx(MutexTypeTrace, StatMtxTrace) {
diff --git a/lib/tsan/rtl/tsan_update_shadow_word_inl.h b/lib/tsan/rtl/tsan_update_shadow_word_inl.h
index e7c036c5dea8..a11c9bc52509 100644
--- a/lib/tsan/rtl/tsan_update_shadow_word_inl.h
+++ b/lib/tsan/rtl/tsan_update_shadow_word_inl.h
@@ -57,8 +57,7 @@ do {
goto RACE;
}
// Do the memory access intersect?
- // In Go all memory accesses are 1 byte, so there can be no intersections.
- if (kCppMode && Shadow::TwoRangesIntersect(old, cur, kAccessSize)) {
+ if (Shadow::TwoRangesIntersect(old, cur, kAccessSize)) {
StatInc(thr, StatShadowIntersect);
if (Shadow::TidsAreEqual(old, cur)) {
StatInc(thr, StatShadowSameThread);
diff --git a/lib/tsan/tests/CMakeLists.txt b/lib/tsan/tests/CMakeLists.txt
index 7cc079f3d27a..f73a89242859 100644
--- a/lib/tsan/tests/CMakeLists.txt
+++ b/lib/tsan/tests/CMakeLists.txt
@@ -3,22 +3,44 @@ include_directories(../rtl)
add_custom_target(TsanUnitTests)
set_target_properties(TsanUnitTests PROPERTIES
FOLDER "TSan unittests")
-function(add_tsan_unittest testname)
- # Build unit tests only on 64-bit Linux.
- if(UNIX AND NOT APPLE
- AND CAN_TARGET_x86_64
- AND CMAKE_SIZEOF_VOID_P EQUAL 8
- AND NOT LLVM_BUILD_32_BITS)
- add_unittest(TsanUnitTests ${testname} ${ARGN})
- # Link with TSan runtime.
- target_link_libraries(${testname} clang_rt.tsan-x86_64)
- # Compile tests with the same flags as TSan runtime.
- set_target_compile_flags(${testname} ${TSAN_CFLAGS})
- # Link tests with -pie.
- set_property(TARGET ${testname} APPEND_STRING
- PROPERTY LINK_FLAGS " -pie")
+
+set(TSAN_UNITTEST_CFLAGS
+ ${TSAN_CFLAGS}
+ ${COMPILER_RT_GTEST_INCLUDE_CFLAGS}
+ -I${COMPILER_RT_SOURCE_DIR}/lib
+ -I${COMPILER_RT_SOURCE_DIR}/lib/tsan/rtl
+ -DGTEST_HAS_RTTI=0)
+
+# 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)
+ clang_compile(${output_obj} ${source}
+ CFLAGS ${TSAN_UNITTEST_CFLAGS} ${TARGET_CFLAGS}
+ DEPS gtest ${TSAN_RUNTIME_LIBRARIES} ${ARGN})
+ list(APPEND ${obj_list} ${output_obj})
+endmacro()
+
+macro(add_tsan_unittest testname)
+ # Build unit tests only for 64-bit Linux.
+ if(UNIX AND NOT APPLE AND CAN_TARGET_x86_64)
+ parse_arguments(TEST "SOURCES;HEADERS" "" ${ARGN})
+ set(TEST_OBJECTS)
+ foreach(SOURCE ${TEST_SOURCES} ${COMPILER_RT_GTEST_SOURCE})
+ tsan_compile(TEST_OBJECTS ${SOURCE} x86_64 ${TEST_HEADERS})
+ endforeach()
+ get_target_flags_for_arch(${arch} TARGET_LINK_FLAGS)
+ add_compiler_rt_test(TsanUnitTests ${testname}
+ OBJECTS ${TEST_OBJECTS}
+ DEPS ${TSAN_RUNTIME_LIBRARIES} ${TEST_OBJECTS}
+ LINK_FLAGS ${TARGET_LINK_FLAGS}
+ -fsanitize=thread
+ -lstdc++ -lm)
endif()
-endfunction()
+endmacro()
-add_subdirectory(rtl)
-add_subdirectory(unit)
+if(COMPILER_RT_CAN_EXECUTE_TESTS)
+ add_subdirectory(rtl)
+ add_subdirectory(unit)
+endif()
diff --git a/lib/tsan/tests/rtl/CMakeLists.txt b/lib/tsan/tests/rtl/CMakeLists.txt
index b585660e8b4a..989566d9e041 100644
--- a/lib/tsan/tests/rtl/CMakeLists.txt
+++ b/lib/tsan/tests/rtl/CMakeLists.txt
@@ -1,15 +1,19 @@
-set(TSAN_RTL_TESTS
+set(TSAN_RTL_TEST_SOURCES
tsan_bench.cc
tsan_mop.cc
tsan_mutex.cc
tsan_posix.cc
tsan_string.cc
tsan_test.cc
- tsan_thread.cc
- )
+ tsan_thread.cc)
if(UNIX AND NOT APPLE)
- list(APPEND TSAN_RTL_TESTS tsan_test_util_linux.cc)
+ list(APPEND TSAN_RTL_TEST_SOURCES tsan_test_util_linux.cc)
endif()
-add_tsan_unittest(TsanRtlTest ${TSAN_RTL_TESTS})
+set(TSAN_RTL_TEST_HEADERS
+ tsan_test_util.h)
+
+add_tsan_unittest(TsanRtlTest
+ SOURCES ${TSAN_RTL_TEST_SOURCES}
+ HEADERS ${TSAN_RTL_TEST_HEADERS})
diff --git a/lib/tsan/tests/unit/CMakeLists.txt b/lib/tsan/tests/unit/CMakeLists.txt
index b25a56d8d55c..6898f641d6a0 100644
--- a/lib/tsan/tests/unit/CMakeLists.txt
+++ b/lib/tsan/tests/unit/CMakeLists.txt
@@ -1,13 +1,13 @@
-set(TSAN_UNIT_TESTS
+set(TSAN_UNIT_TEST_SOURCES
tsan_clock_test.cc
tsan_flags_test.cc
tsan_mman_test.cc
tsan_mutex_test.cc
tsan_shadow_test.cc
tsan_stack_test.cc
- tsan_suppressions_test.cc
tsan_sync_test.cc
- tsan_vector_test.cc
- )
+ tsan_unit_test_main.cc
+ tsan_vector_test.cc)
-add_tsan_unittest(TsanUnitTest ${TSAN_UNIT_TESTS})
+add_tsan_unittest(TsanUnitTest
+ SOURCES ${TSAN_UNIT_TEST_SOURCES})
diff --git a/lib/tsan/tests/unit/tsan_mman_test.cc b/lib/tsan/tests/unit/tsan_mman_test.cc
index 0961d2b75d11..e1ad7ac51ad6 100644
--- a/lib/tsan/tests/unit/tsan_mman_test.cc
+++ b/lib/tsan/tests/unit/tsan_mman_test.cc
@@ -164,7 +164,9 @@ TEST(Mman, CallocOverflow) {
size_t kArraySize = 4096;
volatile size_t kMaxSizeT = std::numeric_limits<size_t>::max();
volatile size_t kArraySize2 = kMaxSizeT / kArraySize + 10;
- volatile void *p = calloc(kArraySize, kArraySize2); // Should return 0.
+ volatile void *p = NULL;
+ EXPECT_DEATH(p = calloc(kArraySize, kArraySize2),
+ "allocator is terminating the process instead of returning 0");
EXPECT_EQ(0L, p);
}
diff --git a/lib/tsan/tests/unit/tsan_stack_test.cc b/lib/tsan/tests/unit/tsan_stack_test.cc
index d5392959c48c..9aa2967628cf 100644
--- a/lib/tsan/tests/unit/tsan_stack_test.cc
+++ b/lib/tsan/tests/unit/tsan_stack_test.cc
@@ -19,6 +19,10 @@ namespace __tsan {
static void TestStackTrace(StackTrace *trace) {
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];
trace->ObtainCurrent(&thr, 0);
EXPECT_EQ(trace->Size(), (uptr)0);
@@ -60,7 +64,12 @@ TEST(StackTrace, StaticTrim) {
ScopedInRtl in_rtl;
uptr buf[2];
StackTrace trace(buf, 2);
+
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];
*thr.shadow_stack_pos++ = 100;
*thr.shadow_stack_pos++ = 101;
diff --git a/lib/tsan/tests/unit/tsan_suppressions_test.cc b/lib/tsan/tests/unit/tsan_suppressions_test.cc
deleted file mode 100644
index decfa3214d23..000000000000
--- a/lib/tsan/tests/unit/tsan_suppressions_test.cc
+++ /dev/null
@@ -1,128 +0,0 @@
-//===-- tsan_suppressions_test.cc -----------------------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file is a part of ThreadSanitizer (TSan), a race detector.
-//
-//===----------------------------------------------------------------------===//
-#include "tsan_suppressions.h"
-#include "tsan_rtl.h"
-#include "gtest/gtest.h"
-
-#include <string.h>
-
-namespace __tsan {
-
-TEST(Suppressions, Parse) {
- ScopedInRtl in_rtl;
- Suppression *supp0 = SuppressionParse(0,
- "race:foo\n"
- " race:bar\n" // NOLINT
- "race:baz \n" // NOLINT
- "# a comment\n"
- "race:quz\n"
- ); // NOLINT
- Suppression *supp = supp0;
- EXPECT_EQ(supp->type, SuppressionRace);
- EXPECT_EQ(0, strcmp(supp->templ, "quz"));
- supp = supp->next;
- EXPECT_EQ(supp->type, SuppressionRace);
- EXPECT_EQ(0, strcmp(supp->templ, "baz"));
- supp = supp->next;
- EXPECT_EQ(supp->type, SuppressionRace);
- EXPECT_EQ(0, strcmp(supp->templ, "bar"));
- supp = supp->next;
- EXPECT_EQ(supp->type, SuppressionRace);
- EXPECT_EQ(0, strcmp(supp->templ, "foo"));
- supp = supp->next;
- EXPECT_EQ((Suppression*)0, supp);
-}
-
-TEST(Suppressions, Parse2) {
- ScopedInRtl in_rtl;
- Suppression *supp0 = SuppressionParse(0,
- " # first line comment\n" // NOLINT
- " race:bar \n" // NOLINT
- "race:baz* *baz\n"
- "# a comment\n"
- "# last line comment\n"
- ); // NOLINT
- Suppression *supp = supp0;
- EXPECT_EQ(supp->type, SuppressionRace);
- EXPECT_EQ(0, strcmp(supp->templ, "baz* *baz"));
- supp = supp->next;
- EXPECT_EQ(supp->type, SuppressionRace);
- EXPECT_EQ(0, strcmp(supp->templ, "bar"));
- supp = supp->next;
- EXPECT_EQ((Suppression*)0, supp);
-}
-
-TEST(Suppressions, Parse3) {
- ScopedInRtl in_rtl;
- Suppression *supp0 = SuppressionParse(0,
- "# last suppression w/o line-feed\n"
- "race:foo\n"
- "race:bar"
- ); // NOLINT
- Suppression *supp = supp0;
- EXPECT_EQ(supp->type, SuppressionRace);
- EXPECT_EQ(0, strcmp(supp->templ, "bar"));
- supp = supp->next;
- EXPECT_EQ(supp->type, SuppressionRace);
- EXPECT_EQ(0, strcmp(supp->templ, "foo"));
- supp = supp->next;
- EXPECT_EQ((Suppression*)0, supp);
-}
-
-TEST(Suppressions, ParseType) {
- ScopedInRtl in_rtl;
- Suppression *supp0 = SuppressionParse(0,
- "race:foo\n"
- "thread:bar\n"
- "mutex:baz\n"
- "signal:quz\n"
- ); // NOLINT
- Suppression *supp = supp0;
- EXPECT_EQ(supp->type, SuppressionSignal);
- EXPECT_EQ(0, strcmp(supp->templ, "quz"));
- supp = supp->next;
- EXPECT_EQ(supp->type, SuppressionMutex);
- EXPECT_EQ(0, strcmp(supp->templ, "baz"));
- supp = supp->next;
- EXPECT_EQ(supp->type, SuppressionThread);
- EXPECT_EQ(0, strcmp(supp->templ, "bar"));
- supp = supp->next;
- EXPECT_EQ(supp->type, SuppressionRace);
- EXPECT_EQ(0, strcmp(supp->templ, "foo"));
- supp = supp->next;
- EXPECT_EQ((Suppression*)0, supp);
-}
-
-static bool MyMatch(const char *templ, const char *func) {
- char tmp[1024];
- strcpy(tmp, templ); // NOLINT
- return SuppressionMatch(tmp, func);
-}
-
-TEST(Suppressions, Match) {
- EXPECT_TRUE(MyMatch("foobar", "foobar"));
- EXPECT_TRUE(MyMatch("foobar", "prefix_foobar_postfix"));
- EXPECT_TRUE(MyMatch("*foobar*", "prefix_foobar_postfix"));
- EXPECT_TRUE(MyMatch("foo*bar", "foo_middle_bar"));
- EXPECT_TRUE(MyMatch("foo*bar", "foobar"));
- EXPECT_TRUE(MyMatch("foo*bar*baz", "foo_middle_bar_another_baz"));
- EXPECT_TRUE(MyMatch("foo*bar*baz", "foo_middle_barbaz"));
-
- EXPECT_FALSE(MyMatch("foo", "baz"));
- EXPECT_FALSE(MyMatch("foobarbaz", "foobar"));
- EXPECT_FALSE(MyMatch("foobarbaz", "barbaz"));
- EXPECT_FALSE(MyMatch("foo*bar", "foobaz"));
- EXPECT_FALSE(MyMatch("foo*bar", "foo_baz"));
-}
-
-} // namespace __tsan
diff --git a/lib/tsan/tests/unit/tsan_unit_test_main.cc b/lib/tsan/tests/unit/tsan_unit_test_main.cc
new file mode 100644
index 000000000000..84d94dd03748
--- /dev/null
+++ b/lib/tsan/tests/unit/tsan_unit_test_main.cc
@@ -0,0 +1,19 @@
+//===-- tsan_unit_test_main.cc --------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+#include "gtest/gtest.h"
+
+int main(int argc, char **argv) {
+ testing::GTEST_FLAG(death_test_style) = "threadsafe";
+ testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/lib/ubsan/CMakeLists.txt b/lib/ubsan/CMakeLists.txt
index c8470bc6d353..675c47f6a65e 100644
--- a/lib/ubsan/CMakeLists.txt
+++ b/lib/ubsan/CMakeLists.txt
@@ -34,17 +34,22 @@ else()
# Main UBSan runtime.
add_compiler_rt_static_runtime(clang_rt.ubsan-${arch} ${arch}
SOURCES ${UBSAN_SOURCES}
- CFLAGS ${UBSAN_CFLAGS}
- SYMS ubsan.syms)
+ 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}
SOURCES ${UBSAN_CXX_SOURCES}
- CFLAGS ${UBSAN_CFLAGS}
- SYMS ubsan.syms)
+ CFLAGS ${UBSAN_CFLAGS})
list(APPEND UBSAN_RUNTIME_LIBRARIES
- clang_rt.san-${arch}
- clang_rt.ubsan-${arch}
- clang_rt.ubsan_cxx-${arch})
+ clang_rt.san-${arch}
+ clang_rt.ubsan-${arch}
+ clang_rt.ubsan_cxx-${arch})
+ if (UNIX AND NOT ${arch} STREQUAL "i386")
+ 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
+ clang_rt.ubsan-${arch}-symbols
+ clang_rt.ubsan_cxx-${arch}-symbols)
+ endif()
endforeach()
endif()
diff --git a/lib/ubsan/lit_tests/AsanConfig/lit.cfg b/lib/ubsan/lit_tests/AsanConfig/lit.cfg
new file mode 100644
index 000000000000..407e5ec32e60
--- /dev/null
+++ b/lib/ubsan/lit_tests/AsanConfig/lit.cfg
@@ -0,0 +1,25 @@
+# -*- 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
new file mode 100644
index 000000000000..f75741838f83
--- /dev/null
+++ b/lib/ubsan/lit_tests/AsanConfig/lit.site.cfg.in
@@ -0,0 +1,9 @@
+# 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
index 7e1a13c782d2..36d8dc1f9205 100644
--- a/lib/ubsan/lit_tests/CMakeLists.txt
+++ b/lib/ubsan/lit_tests/CMakeLists.txt
@@ -1,21 +1,23 @@
+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}/lit.site.cfg.in
- ${CMAKE_CURRENT_BINARY_DIR}/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})
- set(UBSAN_TEST_PARAMS
- ubsan_site_config=${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg
- )
+ ${UBSAN_RUNTIME_LIBRARIES}
+ asan_runtime_libraries)
add_lit_testsuite(check-ubsan "Running UndefinedBehaviorSanitizer tests"
- ${CMAKE_CURRENT_BINARY_DIR}
- PARAMS ${UBSAN_TEST_PARAMS}
- DEPENDS ${UBSAN_TEST_DEPS}
- )
+ ${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/Integer/div-zero.cpp b/lib/ubsan/lit_tests/Integer/div-zero.cpp
deleted file mode 100644
index b2a839566c5f..000000000000
--- a/lib/ubsan/lit_tests/Integer/div-zero.cpp
+++ /dev/null
@@ -1,15 +0,0 @@
-// RUN: %clang -fsanitize=integer-divide-by-zero -DDIVIDEND=0 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clang -fsanitize=integer-divide-by-zero -DDIVIDEND=1U %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clang -fsanitize=float-divide-by-zero -DDIVIDEND=1.5 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clang -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/Integer/incdec-overflow.cpp b/lib/ubsan/lit_tests/Integer/incdec-overflow.cpp
deleted file mode 100644
index 48b68b6365c6..000000000000
--- a/lib/ubsan/lit_tests/Integer/incdec-overflow.cpp
+++ /dev/null
@@ -1,16 +0,0 @@
-// RUN: %clang -DOP=n++ -fsanitize=signed-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clang -DOP=++n -fsanitize=signed-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clang -DOP=m-- -fsanitize=signed-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clang -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/Integer/shift.cpp b/lib/ubsan/lit_tests/Integer/shift.cpp
deleted file mode 100644
index 19101c53e75e..000000000000
--- a/lib/ubsan/lit_tests/Integer/shift.cpp
+++ /dev/null
@@ -1,37 +0,0 @@
-// RUN: %clang -DLSH_OVERFLOW -DOP='<<' -fsanitize=shift %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=LSH_OVERFLOW
-// RUN: %clang -DLSH_OVERFLOW -DOP='<<=' -fsanitize=shift %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=LSH_OVERFLOW
-// RUN: %clang -DTOO_LOW -DOP='<<' -fsanitize=shift %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=TOO_LOW
-// RUN: %clang -DTOO_LOW -DOP='>>' -fsanitize=shift %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=TOO_LOW
-// RUN: %clang -DTOO_LOW -DOP='<<=' -fsanitize=shift %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=TOO_LOW
-// RUN: %clang -DTOO_LOW -DOP='>>=' -fsanitize=shift %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=TOO_LOW
-// RUN: %clang -DTOO_HIGH -DOP='<<' -fsanitize=shift %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=TOO_HIGH
-// RUN: %clang -DTOO_HIGH -DOP='>>' -fsanitize=shift %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=TOO_HIGH
-// RUN: %clang -DTOO_HIGH -DOP='<<=' -fsanitize=shift %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=TOO_HIGH
-// RUN: %clang -DTOO_HIGH -DOP='>>=' -fsanitize=shift %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=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/Integer/uincdec-overflow.cpp b/lib/ubsan/lit_tests/Integer/uincdec-overflow.cpp
deleted file mode 100644
index 6b677ca5bd35..000000000000
--- a/lib/ubsan/lit_tests/Integer/uincdec-overflow.cpp
+++ /dev/null
@@ -1,16 +0,0 @@
-// RUN: %clang -DOP=n++ -fsanitize=unsigned-integer-overflow %s -o %t && %t 2>&1 | FileCheck --check-prefix=INC %s
-// RUN: %clang -DOP=++n -fsanitize=unsigned-integer-overflow %s -o %t && %t 2>&1 | FileCheck --check-prefix=INC %s
-// RUN: %clang -DOP=m-- -fsanitize=unsigned-integer-overflow %s -o %t && %t 2>&1 | FileCheck --check-prefix=DEC %s
-// RUN: %clang -DOP=--m -fsanitize=unsigned-integer-overflow %s -o %t && %t 2>&1 | FileCheck --check-prefix=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/Misc/bool.cpp b/lib/ubsan/lit_tests/Misc/bool.cpp
deleted file mode 100644
index 8fafe7eac053..000000000000
--- a/lib/ubsan/lit_tests/Misc/bool.cpp
+++ /dev/null
@@ -1,11 +0,0 @@
-// RUN: %clang -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;
-
- // FIXME: Provide a better source location here.
- // CHECK: bool.exe:0x{{[0-9a-f]*}}: runtime error: load of value 123, which is not a valid value for type 'bool'
- return *p;
-}
diff --git a/lib/ubsan/lit_tests/Float/cast-overflow.cpp b/lib/ubsan/lit_tests/TestCases/Float/cast-overflow.cpp
index 8d9120d586a1..35f9336c904a 100644
--- a/lib/ubsan/lit_tests/Float/cast-overflow.cpp
+++ b/lib/ubsan/lit_tests/TestCases/Float/cast-overflow.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang -fsanitize=float-cast-overflow %s -o %t
+// 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
diff --git a/lib/ubsan/lit_tests/Integer/add-overflow.cpp b/lib/ubsan/lit_tests/TestCases/Integer/add-overflow.cpp
index 80543524f51d..412eb7621033 100644
--- a/lib/ubsan/lit_tests/Integer/add-overflow.cpp
+++ b/lib/ubsan/lit_tests/TestCases/Integer/add-overflow.cpp
@@ -1,6 +1,6 @@
-// RUN: %clang -DADD_I32 -fsanitize=signed-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=ADD_I32
-// RUN: %clang -DADD_I64 -fsanitize=signed-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=ADD_I64
-// RUN: %clang -DADD_I128 -fsanitize=signed-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=ADD_I128
+// 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>
diff --git a/lib/ubsan/lit_tests/Integer/div-overflow.cpp b/lib/ubsan/lit_tests/TestCases/Integer/div-overflow.cpp
index dd82427f9d5b..83aa854485b4 100644
--- a/lib/ubsan/lit_tests/Integer/div-overflow.cpp
+++ b/lib/ubsan/lit_tests/TestCases/Integer/div-overflow.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang -fsanitize=signed-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx -fsanitize=signed-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s
#include <stdint.h>
diff --git a/lib/ubsan/lit_tests/TestCases/Integer/div-zero.cpp b/lib/ubsan/lit_tests/TestCases/Integer/div-zero.cpp
new file mode 100644
index 000000000000..6b8aadfe15e6
--- /dev/null
+++ b/lib/ubsan/lit_tests/TestCases/Integer/div-zero.cpp
@@ -0,0 +1,15 @@
+// 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
new file mode 100644
index 000000000000..904250a76c79
--- /dev/null
+++ b/lib/ubsan/lit_tests/TestCases/Integer/incdec-overflow.cpp
@@ -0,0 +1,16 @@
+// 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/Integer/mul-overflow.cpp b/lib/ubsan/lit_tests/TestCases/Integer/mul-overflow.cpp
index 8d1e70d6ad48..1cfe23f57213 100644
--- a/lib/ubsan/lit_tests/Integer/mul-overflow.cpp
+++ b/lib/ubsan/lit_tests/TestCases/Integer/mul-overflow.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang -fsanitize=signed-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx -fsanitize=signed-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s
#include <stdint.h>
diff --git a/lib/ubsan/lit_tests/Integer/negate-overflow.cpp b/lib/ubsan/lit_tests/TestCases/Integer/negate-overflow.cpp
index 2ee4f10115e8..6bee3eea2980 100644
--- a/lib/ubsan/lit_tests/Integer/negate-overflow.cpp
+++ b/lib/ubsan/lit_tests/TestCases/Integer/negate-overflow.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang -fsanitize=signed-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=CHECKS
-// RUN: %clang -fsanitize=unsigned-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=CHECKU
+// 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
diff --git a/lib/ubsan/lit_tests/Integer/no-recover.cpp b/lib/ubsan/lit_tests/TestCases/Integer/no-recover.cpp
index e200feaa79ae..64787b7cfbf5 100644
--- a/lib/ubsan/lit_tests/Integer/no-recover.cpp
+++ b/lib/ubsan/lit_tests/TestCases/Integer/no-recover.cpp
@@ -1,6 +1,6 @@
-// RUN: %clang -fsanitize=unsigned-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=RECOVER
-// RUN: %clang -fsanitize=unsigned-integer-overflow -fsanitize-recover %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=RECOVER
-// RUN: %clang -fsanitize=unsigned-integer-overflow -fno-sanitize-recover %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=ABORT
+// 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>
@@ -17,6 +17,6 @@ int main() {
// 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'
+ // 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
new file mode 100644
index 000000000000..f35fa1f959ae
--- /dev/null
+++ b/lib/ubsan/lit_tests/TestCases/Integer/shift.cpp
@@ -0,0 +1,37 @@
+// 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/Integer/sub-overflow.cpp b/lib/ubsan/lit_tests/TestCases/Integer/sub-overflow.cpp
index b43a69bee4e6..bf33d293799b 100644
--- a/lib/ubsan/lit_tests/Integer/sub-overflow.cpp
+++ b/lib/ubsan/lit_tests/TestCases/Integer/sub-overflow.cpp
@@ -1,6 +1,6 @@
-// RUN: %clang -DSUB_I32 -fsanitize=signed-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=SUB_I32
-// RUN: %clang -DSUB_I64 -fsanitize=signed-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=SUB_I64
-// RUN: %clang -DSUB_I128 -fsanitize=signed-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=SUB_I128
+// 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>
diff --git a/lib/ubsan/lit_tests/Integer/uadd-overflow.cpp b/lib/ubsan/lit_tests/TestCases/Integer/uadd-overflow.cpp
index 0edb10092e2c..2ef31c0640d1 100644
--- a/lib/ubsan/lit_tests/Integer/uadd-overflow.cpp
+++ b/lib/ubsan/lit_tests/TestCases/Integer/uadd-overflow.cpp
@@ -1,6 +1,6 @@
-// RUN: %clang -DADD_I32 -fsanitize=unsigned-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=ADD_I32
-// RUN: %clang -DADD_I64 -fsanitize=unsigned-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=ADD_I64
-// RUN: %clang -DADD_I128 -fsanitize=unsigned-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=ADD_I128
+// 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>
@@ -18,7 +18,7 @@ int main() {
#ifdef ADD_I64
(void)(uint64_t(10000000000000000000ull) + uint64_t(9000000000000000000ull));
- // CHECK-ADD_I64: 10000000000000000000 + 9000000000000000000 cannot be represented in type 'unsigned long'
+ // CHECK-ADD_I64: 10000000000000000000 + 9000000000000000000 cannot be represented in type 'unsigned {{long( long)?}}'
#endif
#ifdef ADD_I128
diff --git a/lib/ubsan/lit_tests/TestCases/Integer/uincdec-overflow.cpp b/lib/ubsan/lit_tests/TestCases/Integer/uincdec-overflow.cpp
new file mode 100644
index 000000000000..a14bd6a776f5
--- /dev/null
+++ b/lib/ubsan/lit_tests/TestCases/Integer/uincdec-overflow.cpp
@@ -0,0 +1,16 @@
+// 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/Integer/umul-overflow.cpp b/lib/ubsan/lit_tests/TestCases/Integer/umul-overflow.cpp
index 42cf3a780ed0..c84bb39ef2f7 100644
--- a/lib/ubsan/lit_tests/Integer/umul-overflow.cpp
+++ b/lib/ubsan/lit_tests/TestCases/Integer/umul-overflow.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang -fsanitize=unsigned-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx -fsanitize=unsigned-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s
#include <stdint.h>
diff --git a/lib/ubsan/lit_tests/Integer/usub-overflow.cpp b/lib/ubsan/lit_tests/TestCases/Integer/usub-overflow.cpp
index 357d662ad63e..78f745578583 100644
--- a/lib/ubsan/lit_tests/Integer/usub-overflow.cpp
+++ b/lib/ubsan/lit_tests/TestCases/Integer/usub-overflow.cpp
@@ -1,6 +1,6 @@
-// RUN: %clang -DSUB_I32 -fsanitize=unsigned-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=SUB_I32
-// RUN: %clang -DSUB_I64 -fsanitize=unsigned-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=SUB_I64
-// RUN: %clang -DSUB_I128 -fsanitize=unsigned-integer-overflow %s -o %t && %t 2>&1 | FileCheck %s --check-prefix=SUB_I128
+// 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>
@@ -17,7 +17,7 @@ int main() {
#ifdef SUB_I64
(void)(uint64_t(8000000000000000000ll) - uint64_t(9000000000000000000ll));
- // CHECK-SUB_I64: 8000000000000000000 - 9000000000000000000 cannot be represented in type 'unsigned long'
+ // CHECK-SUB_I64: 8000000000000000000 - 9000000000000000000 cannot be represented in type 'unsigned {{long( long)?}}'
#endif
#ifdef SUB_I128
diff --git a/lib/ubsan/lit_tests/TestCases/Misc/bool.cpp b/lib/ubsan/lit_tests/TestCases/Misc/bool.cpp
new file mode 100644
index 000000000000..e916e7fb3c1d
--- /dev/null
+++ b/lib/ubsan/lit_tests/TestCases/Misc/bool.cpp
@@ -0,0 +1,10 @@
+// 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/Misc/bounds.cpp b/lib/ubsan/lit_tests/TestCases/Misc/bounds.cpp
index 07b30d384df9..dc4c4a513c1c 100644
--- a/lib/ubsan/lit_tests/Misc/bounds.cpp
+++ b/lib/ubsan/lit_tests/TestCases/Misc/bounds.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang -fsanitize=bounds %s -O3 -o %T/bounds.exe
+// 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
diff --git a/lib/ubsan/lit_tests/Misc/deduplication.cpp b/lib/ubsan/lit_tests/TestCases/Misc/deduplication.cpp
index d9c909f9af4f..d325bf6dd899 100644
--- a/lib/ubsan/lit_tests/Misc/deduplication.cpp
+++ b/lib/ubsan/lit_tests/TestCases/Misc/deduplication.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang -fsanitize=undefined %s -o %t && %t 2>&1 | FileCheck %s
+// 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>
diff --git a/lib/ubsan/lit_tests/Misc/enum.cpp b/lib/ubsan/lit_tests/TestCases/Misc/enum.cpp
index b363fea3487f..c5642507ad42 100644
--- a/lib/ubsan/lit_tests/Misc/enum.cpp
+++ b/lib/ubsan/lit_tests/TestCases/Misc/enum.cpp
@@ -1,6 +1,6 @@
-// RUN: %clang -fsanitize=enum %s -O3 -o %t && %t 2>&1 | FileCheck %s --check-prefix=CHECK-PLAIN
-// RUN: %clang -fsanitize=enum -std=c++11 -DE="class E" %s -O3 -o %t && %t
-// RUN: %clang -fsanitize=enum -std=c++11 -DE="class E : bool" %s -O3 -o %t && %t 2>&1 | FileCheck %s --check-prefix=CHECK-BOOL
+// 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
diff --git a/lib/ubsan/lit_tests/Misc/missing_return.cpp b/lib/ubsan/lit_tests/TestCases/Misc/missing_return.cpp
index 9997b8386f21..7da238e25dca 100644
--- a/lib/ubsan/lit_tests/Misc/missing_return.cpp
+++ b/lib/ubsan/lit_tests/TestCases/Misc/missing_return.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang -fsanitize=return %s -O3 -o %t && %t 2>&1 | FileCheck %s
+// 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() {
diff --git a/lib/ubsan/lit_tests/Misc/unreachable.cpp b/lib/ubsan/lit_tests/TestCases/Misc/unreachable.cpp
index 5ca4e5fd8b0c..75fc3e5bd9a6 100644
--- a/lib/ubsan/lit_tests/Misc/unreachable.cpp
+++ b/lib/ubsan/lit_tests/TestCases/Misc/unreachable.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang -fsanitize=unreachable %s -O3 -o %t && %t 2>&1 | FileCheck %s
+// 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
diff --git a/lib/ubsan/lit_tests/Misc/vla.c b/lib/ubsan/lit_tests/TestCases/Misc/vla.c
index 2fa88addc0d3..2fa88addc0d3 100644
--- a/lib/ubsan/lit_tests/Misc/vla.c
+++ b/lib/ubsan/lit_tests/TestCases/Misc/vla.c
diff --git a/lib/ubsan/lit_tests/TestCases/TypeCheck/Function/function.cpp b/lib/ubsan/lit_tests/TestCases/TypeCheck/Function/function.cpp
new file mode 100644
index 000000000000..8106ae47ee4f
--- /dev/null
+++ b/lib/ubsan/lit_tests/TestCases/TypeCheck/Function/function.cpp
@@ -0,0 +1,17 @@
+// 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
new file mode 100644
index 000000000000..27c61a34387c
--- /dev/null
+++ b/lib/ubsan/lit_tests/TestCases/TypeCheck/Function/lit.local.cfg
@@ -0,0 +1,3 @@
+# 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/TypeCheck/misaligned.cpp b/lib/ubsan/lit_tests/TestCases/TypeCheck/misaligned.cpp
index 3abacae8be89..9b0b9a1197c0 100644
--- a/lib/ubsan/lit_tests/TypeCheck/misaligned.cpp
+++ b/lib/ubsan/lit_tests/TestCases/TypeCheck/misaligned.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang -fsanitize=alignment %s -O3 -o %t
+// 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
@@ -64,7 +64,7 @@ int main(int, char **argv) {
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: 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: {{^ \^}}
diff --git a/lib/ubsan/lit_tests/TypeCheck/null.cpp b/lib/ubsan/lit_tests/TestCases/TypeCheck/null.cpp
index f72af28ce160..79726924d213 100644
--- a/lib/ubsan/lit_tests/TypeCheck/null.cpp
+++ b/lib/ubsan/lit_tests/TestCases/TypeCheck/null.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang -fsanitize=null %s -O3 -o %t
+// 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
diff --git a/lib/ubsan/lit_tests/TypeCheck/vptr.cpp b/lib/ubsan/lit_tests/TestCases/TypeCheck/vptr.cpp
index 109e7a824f58..9095f7279a66 100644
--- a/lib/ubsan/lit_tests/TypeCheck/vptr.cpp
+++ b/lib/ubsan/lit_tests/TestCases/TypeCheck/vptr.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang -ccc-cxx -fsanitize=vptr %s -O3 -o %t
+// 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
@@ -101,7 +101,7 @@ int main(int, char **argv) {
// 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: {{^ \^ ( ~~~~~~~~~~~~)?~~~~~~~~~~~ *$}}
// CHECK-OFFSET-NEXT: {{^ ( )?vptr for}} 'T' base class of [[DYN_TYPE]]
return reinterpret_cast<U*>(p)->v() - 2;
diff --git a/lib/ubsan/lit_tests/UbsanConfig/lit.cfg b/lib/ubsan/lit_tests/UbsanConfig/lit.cfg
new file mode 100644
index 000000000000..fcc93035c600
--- /dev/null
+++ b/lib/ubsan/lit_tests/UbsanConfig/lit.cfg
@@ -0,0 +1,23 @@
+# -*- 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
new file mode 100644
index 000000000000..c08fc30d0042
--- /dev/null
+++ b/lib/ubsan/lit_tests/UbsanConfig/lit.site.cfg.in
@@ -0,0 +1,8 @@
+# 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.cfg b/lib/ubsan/lit_tests/lit.cfg
deleted file mode 100644
index ea6ebdf9001f..000000000000
--- a/lib/ubsan/lit_tests/lit.cfg
+++ /dev/null
@@ -1,66 +0,0 @@
-# -*- Python -*-
-
-import os
-
-def get_required_attr(config, attr_name):
- attr_value = getattr(config, attr_name, None)
- if not attr_value:
- lit.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 = 'UndefinedBehaviorSanitizer'
-
-# Setup source root.
-config.test_source_root = os.path.dirname(__file__)
-
-def DisplayNoConfigMessage():
- lit.fatal("No site specific configuration available! " +
- "Try running your test from the build tree or running " +
- "make check-ubsan")
-
-# 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 or we're performing an out-of-tree build.
- ubsan_site_cfg = lit.params.get('ubsan_site_config', None)
- if ubsan_site_cfg and os.path.exists(ubsan_site_cfg):
- lit.load_config(config, ubsan_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()
- ubsan_site_cfg = os.path.join(llvm_obj_root, "projects", "compiler-rt",
- "lib", "ubsan", "lit_tests", "lit.site.cfg")
- if not ubsan_site_cfg or not os.path.exists(ubsan_site_cfg):
- DisplayNoConfigMessage()
-
- lit.load_config(config, ubsan_site_cfg)
- raise SystemExit
-
-# Setup attributes common for all compiler-rt projects.
-compiler_rt_src_root = get_required_attr(config, 'compiler_rt_src_root')
-compiler_rt_lit_cfg = os.path.join(compiler_rt_src_root, "lib",
- "lit.common.cfg")
-if not compiler_rt_lit_cfg or not os.path.exists(compiler_rt_lit_cfg):
- lit.fatal("Can't find common compiler-rt lit config at: %r"
- % compiler_rt_lit_cfg)
-lit.load_config(config, compiler_rt_lit_cfg)
-
-# 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
diff --git a/lib/ubsan/lit_tests/lit.common.cfg b/lib/ubsan/lit_tests/lit.common.cfg
new file mode 100644
index 000000000000..23c85e9fa065
--- /dev/null
+++ b/lib/ubsan/lit_tests/lit.common.cfg
@@ -0,0 +1,31 @@
+# -*- 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/lit_tests/lit.site.cfg.in b/lib/ubsan/lit_tests/lit.site.cfg.in
deleted file mode 100644
index 07b521af061f..000000000000
--- a/lib/ubsan/lit_tests/lit.site.cfg.in
+++ /dev/null
@@ -1,20 +0,0 @@
-## Autogenerated by LLVM/Clang configuration.
-# Do not edit!
-
-config.clang = "@LLVM_BINARY_DIR@/bin/clang"
-config.host_os = "@HOST_OS@"
-config.llvm_src_root = "@LLVM_SOURCE_DIR@"
-config.compiler_rt_src_root = "@COMPILER_RT_SOURCE_DIR@"
-config.llvm_tools_dir = "@LLVM_TOOLS_DIR@"
-config.target_triple = "@TARGET_TRIPLE@"
-
-# LLVM tools dir can be passed in lit parameters, so try to
-# apply substitution.
-try:
- config.llvm_tools_dir = config.llvm_tools_dir % lit.params
-except KeyError,e:
- key, = e.args
- lit.fatal("unable to find %r parameter, use '--param=%s=VALUE'" % (key, key))
-
-# Let the main config do the real work.
-lit.load_config(config, "@CMAKE_CURRENT_SOURCE_DIR@/lit.cfg")
diff --git a/lib/ubsan/ubsan.syms b/lib/ubsan/ubsan.syms
deleted file mode 100644
index e74de33f012c..000000000000
--- a/lib/ubsan/ubsan.syms
+++ /dev/null
@@ -1 +0,0 @@
-{ __ubsan_*; };
diff --git a/lib/ubsan/ubsan.syms.extra b/lib/ubsan/ubsan.syms.extra
new file mode 100644
index 000000000000..7f8be694401a
--- /dev/null
+++ b/lib/ubsan/ubsan.syms.extra
@@ -0,0 +1 @@
+__ubsan_*
diff --git a/lib/ubsan/ubsan_diag.cc b/lib/ubsan/ubsan_diag.cc
index 3f92761465de..fa643658ea36 100644
--- a/lib/ubsan/ubsan_diag.cc
+++ b/lib/ubsan/ubsan_diag.cc
@@ -26,11 +26,21 @@ Location __ubsan::getCallerLocation(uptr CallerLoc) {
return Location();
uptr Loc = StackTrace::GetPreviousInstructionPc(CallerLoc);
+ return getFunctionLocation(Loc, 0);
+}
+
+Location __ubsan::getFunctionLocation(uptr Loc, const char **FName) {
+ if (!Loc)
+ return Location();
AddressInfo Info;
- if (!SymbolizeCode(Loc, &Info, 1) || !Info.module || !*Info.module)
+ if (!Symbolizer::GetOrInit()->SymbolizeCode(Loc, &Info, 1) ||
+ !Info.module || !*Info.module)
return Location(Loc);
+ if (FName && Info.function)
+ *FName = Info.function;
+
if (!Info.file)
return ModuleLocation(Info.module, Info.module_offset);
@@ -67,29 +77,29 @@ static void PrintHex(UIntMax Val) {
}
static void renderLocation(Location Loc) {
+ InternalScopedString LocBuffer(1024);
switch (Loc.getKind()) {
case Location::LK_Source: {
SourceLocation SLoc = Loc.getSourceLocation();
if (SLoc.isInvalid())
- Printf("<unknown>:");
- else {
- Printf("%s:%d:", SLoc.getFilename(), SLoc.getLine());
- if (SLoc.getColumn())
- Printf("%d:", SLoc.getColumn());
- }
+ LocBuffer.append("<unknown>");
+ else
+ PrintSourceLocation(&LocBuffer, SLoc.getFilename(), SLoc.getLine(),
+ SLoc.getColumn());
break;
}
case Location::LK_Module:
- Printf("%s:0x%zx:", Loc.getModuleLocation().getModuleName(),
- Loc.getModuleLocation().getOffset());
+ PrintModuleAndOffset(&LocBuffer, Loc.getModuleLocation().getModuleName(),
+ Loc.getModuleLocation().getOffset());
break;
case Location::LK_Memory:
- Printf("%p:", Loc.getMemoryLocation());
+ LocBuffer.append("%p", Loc.getMemoryLocation());
break;
case Location::LK_Null:
- Printf("<unknown>:");
+ LocBuffer.append("<unknown>");
break;
}
+ Printf("%s:", LocBuffer.data());
}
static void renderText(const char *Message, const Diag::Arg *Args) {
@@ -109,7 +119,7 @@ static void renderText(const char *Message, const Diag::Arg *Args) {
Printf("%s", A.String);
break;
case Diag::AK_Mangled: {
- Printf("'%s'", Demangle(A.String));
+ Printf("'%s'", Symbolizer::GetOrInit()->Demangle(A.String));
break;
}
case Diag::AK_SInt:
diff --git a/lib/ubsan/ubsan_diag.h b/lib/ubsan/ubsan_diag.h
index 16afffdb0a76..54d15a0cc1ba 100644
--- a/lib/ubsan/ubsan_diag.h
+++ b/lib/ubsan/ubsan_diag.h
@@ -80,6 +80,12 @@ public:
/// an invalid location or a module location for the caller.
Location getCallerLocation(uptr CallerLoc = GET_CALLER_PC());
+/// Try to obtain a location for the given function pointer. This might fail,
+/// and produce either an invalid location or a module location for the caller.
+/// If FName is non-null and the name of the function is known, set *FName to
+/// the function name, otherwise *FName is unchanged.
+Location getFunctionLocation(uptr Loc, const char **FName);
+
/// A diagnostic severity level.
enum DiagLevel {
DL_Error, ///< An error.
diff --git a/lib/ubsan/ubsan_handlers.cc b/lib/ubsan/ubsan_handlers.cc
index fa93b095d0bb..d55643143295 100644
--- a/lib/ubsan/ubsan_handlers.cc
+++ b/lib/ubsan/ubsan_handlers.cc
@@ -246,15 +246,36 @@ void __ubsan::__ubsan_handle_float_cast_overflow_abort(
void __ubsan::__ubsan_handle_load_invalid_value(InvalidValueData *Data,
ValueHandle Val) {
- // TODO: Add deduplication once a SourceLocation is generated for this check.
- Diag(getCallerLocation(), DL_Error,
+ SourceLocation Loc = Data->Loc.acquire();
+ if (Loc.isDisabled())
+ return;
+
+ 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_abort(InvalidValueData *Data,
ValueHandle Val) {
- Diag(getCallerLocation(), DL_Error,
- "load of value %0, which is not a valid value for type %1")
- << Value(Data->Type, Val) << Data->Type;
+ __ubsan_handle_load_invalid_value(Data, Val);
+ Die();
+}
+
+void __ubsan::__ubsan_handle_function_type_mismatch(
+ FunctionTypeMismatchData *Data,
+ ValueHandle Function) {
+ const char *FName = "(unknown)";
+
+ Location Loc = getFunctionLocation(Function, &FName);
+
+ 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_abort(
+ FunctionTypeMismatchData *Data,
+ ValueHandle Function) {
+ __ubsan_handle_function_type_mismatch(Data, Function);
Die();
}
diff --git a/lib/ubsan/ubsan_handlers.h b/lib/ubsan/ubsan_handlers.h
index 5e237e1aa2de..14e6f04c2a1b 100644
--- a/lib/ubsan/ubsan_handlers.h
+++ b/lib/ubsan/ubsan_handlers.h
@@ -105,13 +105,22 @@ struct FloatCastOverflowData {
RECOVERABLE(float_cast_overflow, FloatCastOverflowData *Data, ValueHandle From)
struct InvalidValueData {
- // FIXME: SourceLocation Loc;
+ SourceLocation Loc;
const TypeDescriptor &Type;
};
/// \brief Handle a load of an invalid value for the type.
RECOVERABLE(load_invalid_value, InvalidValueData *Data, ValueHandle Val)
+struct FunctionTypeMismatchData {
+ SourceLocation Loc;
+ const TypeDescriptor &Type;
+};
+
+RECOVERABLE(function_type_mismatch,
+ FunctionTypeMismatchData *Data,
+ ValueHandle Val)
+
}
#endif // UBSAN_HANDLERS_H
diff --git a/lib/ubsan/ubsan_type_hash.cc b/lib/ubsan/ubsan_type_hash.cc
index b27aefc16821..a388bcc6d72e 100644
--- a/lib/ubsan/ubsan_type_hash.cc
+++ b/lib/ubsan/ubsan_type_hash.cc
@@ -85,16 +85,18 @@ namespace abi = __cxxabiv1;
// reused as needed. The second caching layer is a large hash table with open
// chaining. We can freely evict from either layer since this is just a cache.
//
-// FIXME: Make these hash table accesses thread-safe. The races here are benign
-// (worst-case, we could miss a bug or see a slowdown) but we should
-// avoid upsetting race detectors.
+// FIXME: Make these hash table accesses thread-safe. The races here are benign:
+// assuming the unsequenced loads and stores don't misbehave too badly,
+// the worst case is false negatives or poor cache behavior, not false
+// positives or crashes.
/// Find a bucket to store the given hash value in.
static __ubsan::HashValue *getTypeCacheHashTableBucket(__ubsan::HashValue V) {
static const unsigned HashTableSize = 65537;
- static __ubsan::HashValue __ubsan_vptr_hash_set[HashTableSize] = { 1 };
+ static __ubsan::HashValue __ubsan_vptr_hash_set[HashTableSize];
- unsigned Probe = V & 65535;
+ unsigned First = (V & 65535) ^ 1;
+ unsigned Probe = First;
for (int Tries = 5; Tries; --Tries) {
if (!__ubsan_vptr_hash_set[Probe] || __ubsan_vptr_hash_set[Probe] == V)
return &__ubsan_vptr_hash_set[Probe];
@@ -104,12 +106,12 @@ static __ubsan::HashValue *getTypeCacheHashTableBucket(__ubsan::HashValue V) {
}
// FIXME: Pick a random entry from the probe sequence to evict rather than
// just taking the first.
- return &__ubsan_vptr_hash_set[V];
+ return &__ubsan_vptr_hash_set[First];
}
/// A cache of recently-checked hashes. Mini hash table with "random" evictions.
__ubsan::HashValue
-__ubsan::__ubsan_vptr_type_cache[__ubsan::VptrTypeCacheSize] = { 1 };
+__ubsan::__ubsan_vptr_type_cache[__ubsan::VptrTypeCacheSize];
/// \brief Determine whether \p Derived has a \p Base base class subobject at
/// offset \p Offset.
diff --git a/make/AppleBI.mk b/make/AppleBI.mk
index d3d4771309c4..b236152158ff 100644
--- a/make/AppleBI.mk
+++ b/make/AppleBI.mk
@@ -12,10 +12,14 @@ else
ProjObjRoot := $(ProjSrcRoot)
endif
-ifeq (,$(SDKROOT))
+ifeq (,$(RC_PURPLE))
INSTALL_TARGET = install-MacOSX
else
- INSTALL_TARGET = install-iOS
+ ifeq (,$(RC_INDIGO))
+ INSTALL_TARGET = install-iOS
+ else
+ INSTALL_TARGET = install-iOS-Simulator
+ endif
endif
@@ -61,9 +65,9 @@ $(OBJROOT)/libcompiler_rt-%.dylib : $(OBJROOT)/darwin_bni/Release/%/libcompiler_
-Wl,-upward-lunwind \
-Wl,-upward-lsystem_m \
-Wl,-upward-lsystem_c \
+ -Wl,-upward-lsystem_kernel \
-Wl,-upward-lsystem_platform \
-Wl,-ldyld \
- -Wl,-lsystem_kernel \
-L$(SDKROOT)/usr/lib/system \
$(DYLIB_FLAGS) -Wl,-force_load,$^ -o $@
@@ -88,7 +92,6 @@ install-iOS: $(SYMROOT)/libcompiler_rt-static.a \
$(call GetCNAVar,STRIP,Platform.darwin_bni,Release,) -S $(SYMROOT)/libcompiler_rt.dylib \
-o $(DSTROOT)/usr/lib/system/libcompiler_rt.dylib
-
# Rule to make fat archive
$(SYMROOT)/libcompiler_rt-static.a : $(foreach arch,$(RC_ARCHS), \
$(OBJROOT)/darwin_bni/Static/$(arch)/libcompiler_rt.a)
@@ -109,3 +112,38 @@ $(SYMROOT)/libcompiler_rt-dyld.a : $(foreach arch,$(RC_ARCHS), \
$(OBJROOT)/libcompiler_rt-dyld-$(arch).a)
$(call GetCNAVar,LIPO,Platform.darwin_bni,Release,) -create $^ -o $@
+
+
+# Copy results to DSTROOT.
+install-iOS-Simulator: $(SYMROOT)/libcompiler_rt_sim.dylib \
+ $(SYMROOT)/libcompiler_rt-dyld.a
+ mkdir -p $(DSTROOT)/$(SDKROOT)/usr/lib/system
+ $(call GetCNAVar,STRIP,Platform.darwin_bni,Release,) -S $(SYMROOT)/libcompiler_rt_sim.dylib \
+ -o $(DSTROOT)/$(SDKROOT)/usr/lib/system/libcompiler_rt_sim.dylib
+ mkdir -p $(DSTROOT)/$(SDKROOT)/usr/local/lib/dyld
+ cp $(SYMROOT)/libcompiler_rt-dyld.a \
+ $(DSTROOT)/$(SDKROOT)/usr/local/lib/dyld/libcompiler_rt.a
+
+# Rule to make fat dylib
+$(SYMROOT)/libcompiler_rt_sim.dylib: $(foreach arch,$(RC_ARCHS), \
+ $(OBJROOT)/libcompiler_rt_sim-$(arch).dylib)
+ $(call GetCNAVar,LIPO,Platform.darwin_bni,Release,) -create $^ -o $@
+ $(call GetCNAVar,DSYMUTIL,Platform.darwin_bni,Release,) $@
+
+# Rule to make each dylib slice
+$(OBJROOT)/libcompiler_rt_sim-%.dylib : $(OBJROOT)/darwin_bni/Release/%/libcompiler_rt.a
+ echo "const char vers[] = \"@(#) $(RC_ProjectName)-$(RC_ProjectSourceVersion)\"; " > $(OBJROOT)/version.c
+ $(call GetCNAVar,CC,Platform.darwin_bni,Release,$*) \
+ $(OBJROOT)/version.c -arch $* -dynamiclib \
+ -install_name /usr/lib/system/libcompiler_rt_sim.dylib \
+ -compatibility_version 1 -current_version $(RC_ProjectSourceVersion) \
+ -Wl,-unexported_symbol,___enable_execute_stack \
+ -nostdlib \
+ -Wl,-upward-lunwind_sim \
+ -Wl,-upward-lsystem_sim_m \
+ -Wl,-upward-lsystem_sim_c \
+ -ldyld_sim \
+ -Wl,-upward-lSystem \
+ -umbrella System -Wl,-no_implicit_dylibs -L$(SDKROOT)/usr/lib/system -dead_strip \
+ $(DYLIB_FLAGS) -Wl,-force_load,$^ -o $@
+
diff --git a/make/platform/clang_darwin.mk b/make/platform/clang_darwin.mk
index cb61744e5b7e..ddb702944874 100644
--- a/make/platform/clang_darwin.mk
+++ b/make/platform/clang_darwin.mk
@@ -25,9 +25,24 @@ CheckArches = \
done; \
echo $$result)
+XCRun = \
+ $(shell \
+ result=`xcrun -find $(1) 2> /dev/null`; \
+ if [ "$$?" != "0" ]; then result=$(1); fi; \
+ echo $$result)
+XCRunSdkPath = \
+ $(shell \
+ result=`xcrun --sdk $(1) --show-sdk-path 2> /dev/null`; \
+ if [ "$$?" != "0" ]; then result=""; fi; \
+ echo $$result)
###
-CC := clang
+CC := $(call XCRun,clang)
+AR := $(call XCRun,ar)
+RANLIB := $(call XCRun,ranlib)
+STRIP := $(call XCRun,strip)
+LIPO := $(call XCRun,lipo)
+DSYMUTIL := $(call XCRun,dsymutil)
Configs :=
UniversalArchs :=
@@ -73,6 +88,12 @@ UniversalArchs.profile_ios := $(call CheckArches,i386 x86_64 armv7,profile_ios)
Configs += asan_osx_dynamic
UniversalArchs.asan_osx_dynamic := $(call CheckArches,i386 x86_64,asan_osx_dynamic)
+IOSSIM_SDK_PATH := $(call XCRunSdkPath,iphonesimulator)
+ifneq ($(IOSSIM_SDK_PATH),)
+Configs += asan_iossim_dynamic
+UniversalArchs.asan_iossim_dynamic := $(call CheckArches,i386 x86_64,asan_iossim_dynamic)
+endif
+
Configs += ubsan_osx
UniversalArchs.ubsan_osx := $(call CheckArches,i386 x86_64,ubsan_osx)
@@ -127,12 +148,20 @@ CFLAGS.eprintf := $(CFLAGS) $(OSX_DEPLOYMENT_ARGS)
CFLAGS.10.4 := $(CFLAGS) $(OSX_DEPLOYMENT_ARGS)
# FIXME: We can't build ASAN with our stub SDK yet.
CFLAGS.asan_osx_dynamic := \
- $(CFLAGS) -mmacosx-version-min=10.5 -fno-builtin \
+ $(CFLAGS) -mmacosx-version-min=10.6 -fno-builtin \
-gline-tables-only \
-DMAC_INTERPOSE_FUNCTIONS=1 \
-DASAN_FLEXIBLE_MAPPING_AND_OFFSET=1
-CFLAGS.ubsan_osx := $(CFLAGS) -mmacosx-version-min=10.5 -fno-builtin
+CFLAGS.asan_iossim_dynamic := \
+ $(CFLAGS) -mios-simulator-version-min=7.0 \
+ -isysroot $(IOSSIM_SDK_PATH) \
+ -fno-builtin \
+ -gline-tables-only \
+ -DMAC_INTERPOSE_FUNCTIONS=1 \
+ -DASAN_FLEXIBLE_MAPPING_AND_OFFSET=1
+
+CFLAGS.ubsan_osx := $(CFLAGS) -mmacosx-version-min=10.6 -fno-builtin
CFLAGS.ios.i386 := $(CFLAGS) $(IOSSIM_DEPLOYMENT_ARGS)
CFLAGS.ios.x86_64 := $(CFLAGS) $(IOSSIM_DEPLOYMENT_ARGS)
@@ -163,7 +192,15 @@ CFLAGS.profile_ios.armv7s := $(CFLAGS) $(IOS_DEPLOYMENT_ARGS)
# Configure the asan_osx_dynamic library to be built shared.
SHARED_LIBRARY.asan_osx_dynamic := 1
-LDFLAGS.asan_osx_dynamic := -framework Foundation -lstdc++ -undefined dynamic_lookup
+LDFLAGS.asan_osx_dynamic := -lstdc++ -undefined dynamic_lookup
+
+# Configure the asan_iossim_dynamic library to be built shared.
+SHARED_LIBRARY.asan_iossim_dynamic := 1
+# configure+make uses Clang, so we're using isysroot instead of --sysroot
+# or -Wl,-syslibroot.
+LDFLAGS.asan_iossim_dynamic := -undefined dynamic_lookup \
+ -Wl,-ios_simulator_version_min,7.0.0 \
+ -mios-simulator-version-min=7.0 -isysroot $(IOSSIM_SDK_PATH)
FUNCTIONS.eprintf := eprintf
FUNCTIONS.10.4 := eprintf floatundidf floatundisf floatundixf
@@ -184,6 +221,10 @@ FUNCTIONS.asan_osx_dynamic := $(AsanFunctions) $(InterceptionFunctions) \
$(SanitizerCommonFunctions) \
$(AsanDynamicFunctions)
+FUNCTIONS.asan_iossim_dynamic := $(AsanFunctions) $(InterceptionFunctions) \
+ $(SanitizerCommonFunctions) \
+ $(AsanDynamicFunctions)
+
FUNCTIONS.ubsan_osx := $(UbsanFunctions) $(UbsanCXXFunctions) \
$(SanitizerCommonFunctions)
diff --git a/make/platform/clang_darwin_embedded.mk b/make/platform/clang_darwin_embedded.mk
new file mode 100644
index 000000000000..3cea2e45c8ab
--- /dev/null
+++ b/make/platform/clang_darwin_embedded.mk
@@ -0,0 +1,250 @@
+# These are the functions which clang needs when it is targetting a previous
+# version of the OS. The issue is that the backend may use functions which were
+# not present in the libgcc that shipped on the platform. In such cases, we link
+# with a version of the library which contains private_extern definitions of all
+# the extra functions which might be referenced.
+
+Description := Static runtime libraries for embedded clang/Darwin
+
+XCRun = \
+ $(shell \
+ result=`xcrun -find $(1) 2> /dev/null`; \
+ if [ "$$?" != "0" ]; then result=$(1); fi; \
+ echo $$result)
+
+###
+
+CC := $(call XCRun,clang)
+AR := $(call XCRun,ar)
+RANLIB := $(call XCRun,ranlib)
+STRIP := $(call XCRun,strip)
+LIPO := $(call XCRun,lipo)
+DSYMUTIL := $(call XCRun,dsymutil)
+
+Configs :=
+UniversalArchs :=
+
+# Soft-float version of the runtime. No floating-point instructions will be used
+# and the ABI (out of necessity) passes floating values in normal registers:
+# non-VFP variant of the AAPCS.
+Configs += soft_static
+UniversalArchs.soft_static := armv6m armv7m armv7em armv7
+
+# Hard-float version of the runtime. On ARM VFP instructions and registers are
+# allowed, and floating point values get passed in them. VFP variant of the
+# AAPCS.
+Configs += hard_static
+UniversalArchs.hard_static := armv7em armv7 i386 x86_64
+
+Configs += soft_pic
+UniversalArchs.soft_pic := armv6m armv7m armv7em armv7
+
+Configs += hard_pic
+UniversalArchs.hard_pic := armv7em armv7 i386 x86_64
+
+CFLAGS := -Wall -Werror -Oz -fomit-frame-pointer -ffreestanding
+
+PIC_CFLAGS := -fPIC
+STATIC_CFLAGS := -static
+
+CFLAGS_SOFT := -mfloat-abi=soft
+CFLAGS_HARD := -mfloat-abi=hard
+
+CFLAGS_ARMV7 := -target thumbv7-apple-darwin-eabi
+CFLAGS_I386 := -march=pentium
+
+CFLAGS.soft_static := $(CFLAGS) $(STATIC_CFLAGS) $(CFLAGS_SOFT)
+CFLAGS.hard_static := $(CFLAGS) $(STATIC_CFLAGS) $(CFLAGS_HARD)
+CFLAGS.soft_pic := $(CFLAGS) $(PIC_CFLAGS) $(CFLAGS_SOFT)
+CFLAGS.hard_pic := $(CFLAGS) $(PIC_CFLAGS) $(CFLAGS_HARD)
+
+CFLAGS.soft_static.armv7 := $(CFLAGS.soft_static) $(CFLAGS_ARMV7)
+CFLAGS.hard_static.armv7 := $(CFLAGS.hard_static) $(CFLAGS_ARMV7)
+CFLAGS.soft_pic.armv7 := $(CFLAGS.soft_pic) $(CFLAGS_ARMV7)
+CFLAGS.hard_pic.armv7 := $(CFLAGS.hard_pic) $(CFLAGS_ARMV7)
+
+# x86 platforms ignore -mfloat-abi options and complain about doing so. Despite
+# this they're hard-float.
+CFLAGS.hard_static.i386 := $(CFLAGS) $(STATIC_CFLAGS) $(CFLAGS_I386)
+CFLAGS.hard_pic.i386 := $(CFLAGS) $(PIC_CFLAGS) $(CFLAGS_I386)
+CFLAGS.hard_static.x86_64 := $(CFLAGS) $(STATIC_CFLAGS)
+CFLAGS.hard_pic.x86_64 := $(CFLAGS) $(PIC_CFLAGS)
+
+# Functions not wanted:
+# + eprintf is obsolete anyway
+# + *vfp: designed for Thumb1 CPUs with VFPv2
+
+COMMON_FUNCTIONS := \
+ absvdi2 \
+ absvsi2 \
+ addvdi3 \
+ addvsi3 \
+ ashldi3 \
+ ashrdi3 \
+ bswapdi2 \
+ bswapsi2 \
+ clzdi2 \
+ clzsi2 \
+ cmpdi2 \
+ ctzdi2 \
+ ctzsi2 \
+ divdc3 \
+ divdi3 \
+ divsc3 \
+ divmodsi4 \
+ udivmodsi4 \
+ do_global_dtors \
+ ffsdi2 \
+ fixdfdi \
+ fixsfdi \
+ fixunsdfdi \
+ fixunsdfsi \
+ fixunssfdi \
+ fixunssfsi \
+ floatdidf \
+ floatdisf \
+ floatundidf \
+ floatundisf \
+ gcc_bcmp \
+ lshrdi3 \
+ moddi3 \
+ muldc3 \
+ muldi3 \
+ mulsc3 \
+ mulvdi3 \
+ mulvsi3 \
+ negdi2 \
+ negvdi2 \
+ negvsi2 \
+ paritydi2 \
+ paritysi2 \
+ popcountdi2 \
+ popcountsi2 \
+ powidf2 \
+ powisf2 \
+ subvdi3 \
+ subvsi3 \
+ ucmpdi2 \
+ udiv_w_sdiv \
+ udivdi3 \
+ udivmoddi4 \
+ umoddi3 \
+ adddf3 \
+ addsf3 \
+ cmpdf2 \
+ cmpsf2 \
+ div0 \
+ divdf3 \
+ divsf3 \
+ divsi3 \
+ extendsfdf2 \
+ ffssi2 \
+ fixdfsi \
+ fixsfsi \
+ floatsidf \
+ floatsisf \
+ floatunsidf \
+ floatunsisf \
+ comparedf2 \
+ comparesf2 \
+ modsi3 \
+ muldf3 \
+ mulsf3 \
+ negdf2 \
+ negsf2 \
+ subdf3 \
+ subsf3 \
+ truncdfsf2 \
+ udivsi3 \
+ umodsi3 \
+ unorddf2 \
+ unordsf2
+
+ARM_FUNCTIONS := \
+ aeabi_cdcmpeq \
+ aeabi_cdrcmple \
+ aeabi_cfcmpeq \
+ aeabi_cfrcmple \
+ aeabi_dcmpeq \
+ aeabi_dcmpge \
+ aeabi_dcmpgt \
+ aeabi_dcmple \
+ aeabi_dcmplt \
+ aeabi_drsub \
+ aeabi_fcmpeq \
+ aeabi_fcmpge \
+ aeabi_fcmpgt \
+ aeabi_fcmple \
+ aeabi_fcmplt \
+ aeabi_frsub \
+ aeabi_idivmod \
+ aeabi_uidivmod \
+
+# ARM Assembly implementation which requires Thumb2 (i.e. won't work on v6M).
+THUMB2_FUNCTIONS := \
+ switch16 \
+ switch32 \
+ switch8 \
+ switchu8 \
+
+I386_FUNCTIONS := \
+ i686.get_pc_thunk.eax \
+ i686.get_pc_thunk.ebp \
+ i686.get_pc_thunk.ebx \
+ i686.get_pc_thunk.ecx \
+ i686.get_pc_thunk.edi \
+ i686.get_pc_thunk.edx \
+ i686.get_pc_thunk.esi
+
+# FIXME: Currently, compiler-rt is missing implementations for a number of the
+# functions. Filter them out for now.
+MISSING_FUNCTIONS := \
+ cmpdf2 cmpsf2 div0 \
+ ffssi2 \
+ udiv_w_sdiv unorddf2 unordsf2 bswapdi2 \
+ bswapsi2 \
+ gcc_bcmp \
+ do_global_dtors \
+ i686.get_pc_thunk.eax i686.get_pc_thunk.ebp i686.get_pc_thunk.ebx \
+ i686.get_pc_thunk.ecx i686.get_pc_thunk.edi i686.get_pc_thunk.edx \
+ i686.get_pc_thunk.esi \
+ aeabi_cdcmpeq aeabi_cdrcmple aeabi_cfcmpeq aeabi_cfrcmple aeabi_dcmpeq \
+ aeabi_dcmpge aeabi_dcmpgt aeabi_dcmple aeabi_dcmplt aeabi_drsub \
+ aeabi_fcmpeq \ aeabi_fcmpge aeabi_fcmpgt aeabi_fcmple aeabi_fcmplt \
+ aeabi_frsub aeabi_idivmod aeabi_uidivmod
+
+FUNCTIONS_ARMV6M := $(COMMON_FUNCTIONS) $(ARM_FUNCTIONS)
+FUNCTIONS_ARM_ALL := $(COMMON_FUNCTIONS) $(ARM_FUNCTIONS) $(THUMB2_FUNCTIONS)
+FUNCTIONS_I386 := $(COMMON_FUNCTIONS) $(I386_FUNCTIONS)
+FUNCTIONS_X86_64 := $(COMMON_FUNCTIONS)
+
+FUNCTIONS_ARMV6M := \
+ $(filter-out $(MISSING_FUNCTIONS),$(FUNCTIONS_ARMV6M))
+FUNCTIONS_ARM_ALL := \
+ $(filter-out $(MISSING_FUNCTIONS),$(FUNCTIONS_ARM_ALL))
+FUNCTIONS_I386 := \
+ $(filter-out $(MISSING_FUNCTIONS),$(FUNCTIONS_I386))
+FUNCTIONS_X86_64 := \
+ $(filter-out $(MISSING_FUNCTIONS),$(FUNCTIONS_X86_64))
+
+FUNCTIONS.soft_static.armv6m := $(FUNCTIONS_ARMV6M)
+FUNCTIONS.soft_pic.armv6m := $(FUNCTIONS_ARMV6M)
+
+FUNCTIONS.soft_static.armv7m := $(FUNCTIONS_ARM_ALL)
+FUNCTIONS.soft_pic.armv7m := $(FUNCTIONS_ARM_ALL)
+
+FUNCTIONS.soft_static.armv7em := $(FUNCTIONS_ARM_ALL)
+FUNCTIONS.hard_static.armv7em := $(FUNCTIONS_ARM_ALL)
+FUNCTIONS.soft_pic.armv7em := $(FUNCTIONS_ARM_ALL)
+FUNCTIONS.hard_pic.armv7em := $(FUNCTIONS_ARM_ALL)
+
+FUNCTIONS.soft_static.armv7 := $(FUNCTIONS_ARM_ALL)
+FUNCTIONS.hard_static.armv7 := $(FUNCTIONS_ARM_ALL)
+FUNCTIONS.soft_pic.armv7 := $(FUNCTIONS_ARM_ALL)
+FUNCTIONS.hard_pic.armv7 := $(FUNCTIONS_ARM_ALL)
+
+FUNCTIONS.hard_static.i386 := $(FUNCTIONS_I386)
+FUNCTIONS.hard_pic.i386 := $(FUNCTIONS_I386)
+
+FUNCTIONS.hard_static.x86_64 := $(FUNCTIONS_X86_64)
+FUNCTIONS.hard_pic.x86_64 := $(FUNCTIONS_X86_64)
diff --git a/make/platform/clang_linux.mk b/make/platform/clang_linux.mk
index 05efdb6d67ea..5796e8671fc9 100644
--- a/make/platform/clang_linux.mk
+++ b/make/platform/clang_linux.mk
@@ -12,11 +12,9 @@ Configs :=
# compiler and only define configurations we know that compiler can generate.
CompilerTargetTriple := $(shell \
$(CC) -v 2>&1 | grep 'Target:' | cut -d' ' -f2)
-ifneq ($(DEBUGMAKE),)
ifeq ($(CompilerTargetTriple),)
$(error "unable to infer compiler target triple for $(CC)")
endif
-endif
# Only define configs if we detected a linux target.
ifneq ($(findstring -linux-,$(CompilerTargetTriple)),)
@@ -63,7 +61,7 @@ endif
# Build runtime libraries for x86_64.
ifeq ($(call contains,$(SupportedArches),x86_64),true)
Configs += full-x86_64 profile-x86_64 san-x86_64 asan-x86_64 tsan-x86_64 \
- msan-x86_64 ubsan-x86_64 ubsan_cxx-x86_64
+ msan-x86_64 ubsan-x86_64 ubsan_cxx-x86_64 dfsan-x86_64 lsan-x86_64
Arch.full-x86_64 := x86_64
Arch.profile-x86_64 := x86_64
Arch.san-x86_64 := x86_64
@@ -72,6 +70,10 @@ Arch.tsan-x86_64 := x86_64
Arch.msan-x86_64 := x86_64
Arch.ubsan-x86_64 := x86_64
Arch.ubsan_cxx-x86_64 := x86_64
+Arch.dfsan-x86_64 := x86_64
+Arch.lsan-x86_64 := x86_64
+endif
+
endif
ifneq ($(LLVM_ANDROID_TOOLCHAIN_DIR),)
@@ -80,7 +82,6 @@ Arch.asan-arm-android := arm-android
endif
endif
-endif
###
@@ -103,6 +104,8 @@ CFLAGS.ubsan-i386 := $(CFLAGS) -m32 $(SANITIZER_CFLAGS) -fno-rtti
CFLAGS.ubsan-x86_64 := $(CFLAGS) -m64 $(SANITIZER_CFLAGS) -fno-rtti
CFLAGS.ubsan_cxx-i386 := $(CFLAGS) -m32 $(SANITIZER_CFLAGS)
CFLAGS.ubsan_cxx-x86_64 := $(CFLAGS) -m64 $(SANITIZER_CFLAGS)
+CFLAGS.dfsan-x86_64 := $(CFLAGS) -m64 $(SANITIZER_CFLAGS)
+CFLAGS.lsan-x86_64 := $(CFLAGS) -m64 $(SANITIZER_CFLAGS) -fno-rtti
SHARED_LIBRARY.asan-arm-android := 1
ANDROID_COMMON_FLAGS := -target arm-linux-androideabi \
@@ -114,12 +117,10 @@ LDFLAGS.asan-arm-android := $(LDFLAGS) $(ANDROID_COMMON_FLAGS) -ldl \
-Wl,-soname=libclang_rt.asan-arm-android.so
# Use our stub SDK as the sysroot to support more portable building. For now we
-# just do this for the non-ASAN modules, because the stub SDK doesn't have
-# enough support to build ASAN.
+# just do this for the core module, because the stub SDK doesn't have
+# enough support to build the sanitizers or profile runtimes.
CFLAGS.full-i386 += --sysroot=$(ProjSrcRoot)/SDKs/linux
CFLAGS.full-x86_64 += --sysroot=$(ProjSrcRoot)/SDKs/linux
-CFLAGS.profile-i386 += --sysroot=$(ProjSrcRoot)/SDKs/linux
-CFLAGS.profile-x86_64 += --sysroot=$(ProjSrcRoot)/SDKs/linux
FUNCTIONS.full-i386 := $(CommonFunctions) $(ArchFunctions.i386)
FUNCTIONS.full-x86_64 := $(CommonFunctions) $(ArchFunctions.x86_64)
@@ -141,6 +142,9 @@ FUNCTIONS.ubsan-i386 := $(UbsanFunctions)
FUNCTIONS.ubsan-x86_64 := $(UbsanFunctions)
FUNCTIONS.ubsan_cxx-i386 := $(UbsanCXXFunctions)
FUNCTIONS.ubsan_cxx-x86_64 := $(UbsanCXXFunctions)
+FUNCTIONS.dfsan-x86_64 := $(DfsanFunctions) $(SanitizerCommonFunctions)
+FUNCTIONS.lsan-x86_64 := $(LsanFunctions) $(InterceptionFunctions) \
+ $(SanitizerCommonFunctions)
# Always use optimized variants.
OPTIMIZED := 1
diff --git a/make/platform/darwin_bni.mk b/make/platform/darwin_bni.mk
index afd04313e62d..03e8d290cffe 100644
--- a/make/platform/darwin_bni.mk
+++ b/make/platform/darwin_bni.mk
@@ -9,12 +9,12 @@ Configs := Debug Release Profile Static
UniversalArchs := $(RC_ARCHS)
ifneq (,$(SDKROOT))
- override CC := $(shell xcrun -sdk $(SDKROOT) -find clang)
- AR := $(shell xcrun -sdk $(SDKROOT) -find ar)
- RANLIB := $(shell xcrun -sdk $(SDKROOT) -find ranlib)
- STRIP := $(shell xcrun -sdk $(SDKROOT) -find strip)
- LIPO := $(shell xcrun -sdk $(SDKROOT) -find lipo)
- DSYMUTIL := $(shell xcrun -sdk $(SDKROOT) -find dsymutil)
+ override CC := $(shell xcrun -sdk $(SDKROOT) -find clang || echo "false")
+ AR := $(shell xcrun -sdk $(SDKROOT) -find ar || echo "false")
+ RANLIB := $(shell xcrun -sdk $(SDKROOT) -find ranlib || echo "false")
+ STRIP := $(shell xcrun -sdk $(SDKROOT) -find strip || echo "false")
+ LIPO := $(shell xcrun -sdk $(SDKROOT) -find lipo || echo "false")
+ DSYMUTIL := $(shell xcrun -sdk $(SDKROOT) -find dsymutil || echo "false")
endif
ifneq ($(IPHONEOS_DEPLOYMENT_TARGET),)