aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/CMakeLists.txt13
-rw-r--r--test/asan/CMakeLists.txt18
-rw-r--r--test/asan/TestCases/Android/coverage-android.cc4
-rw-r--r--test/asan/TestCases/Darwin/abort_on_error.cc2
-rw-r--r--test/asan/TestCases/Darwin/address-range-limit.mm4
-rw-r--r--test/asan/TestCases/Darwin/atos-symbolizer-dyld-root-path.cc2
-rw-r--r--test/asan/TestCases/Darwin/atos-symbolizer.cc2
-rw-r--r--test/asan/TestCases/Darwin/dead-strip.c22
-rw-r--r--test/asan/TestCases/Darwin/dladdr-demangling.cc4
-rw-r--r--test/asan/TestCases/Darwin/malloc_size_crash.mm15
-rw-r--r--test/asan/TestCases/Darwin/objc-odr.mm2
-rw-r--r--test/asan/TestCases/Darwin/segv_read_write.c26
-rw-r--r--test/asan/TestCases/Darwin/suppressions-darwin.cc1
-rw-r--r--test/asan/TestCases/Linux/abort_on_error.cc2
-rw-r--r--test/asan/TestCases/Linux/asan-asm-stacktrace-test.cc2
-rw-r--r--test/asan/TestCases/Linux/asan_prelink_test.cc2
-rw-r--r--test/asan/TestCases/Linux/clang_gcc_abi.cc2
-rw-r--r--test/asan/TestCases/Linux/clone_test.cc2
-rw-r--r--test/asan/TestCases/Linux/coverage-missing.cc2
-rw-r--r--test/asan/TestCases/Linux/coverage_html_report.cc24
-rw-r--r--test/asan/TestCases/Linux/interface_symbols_linux.c2
-rw-r--r--test/asan/TestCases/Linux/kernel-area.cc2
-rw-r--r--test/asan/TestCases/Linux/leak_check_segv.cc6
-rw-r--r--test/asan/TestCases/Linux/local_alias.cc40
-rw-r--r--test/asan/TestCases/Linux/malloc-in-qsort.cc2
-rw-r--r--test/asan/TestCases/Linux/memmem_test.cc21
-rw-r--r--test/asan/TestCases/Linux/new_delete_mismatch.cc16
-rw-r--r--test/asan/TestCases/Linux/nohugepage_test.cc2
-rw-r--r--test/asan/TestCases/Linux/odr-violation.cc8
-rw-r--r--test/asan/TestCases/Linux/odr_c_test.c28
-rw-r--r--test/asan/TestCases/Linux/overflow-in-qsort.cc2
-rw-r--r--test/asan/TestCases/Linux/print_memory_profile_test.cc29
-rw-r--r--test/asan/TestCases/Linux/ptrace.cc7
-rw-r--r--test/asan/TestCases/Linux/recvfrom.cc81
-rw-r--r--test/asan/TestCases/Linux/scariness_score_test.cc192
-rw-r--r--test/asan/TestCases/Linux/segv_read_write.c26
-rw-r--r--test/asan/TestCases/Linux/stack-overflow-recovery-mode.cc36
-rw-r--r--test/asan/TestCases/Linux/static_tls.cc2
-rw-r--r--test/asan/TestCases/Linux/swapcontext_annotation.cc178
-rw-r--r--test/asan/TestCases/Linux/swapcontext_test.cc2
-rw-r--r--test/asan/TestCases/Linux/unpoison_tls.cc2
-rw-r--r--test/asan/TestCases/Posix/closed-fds.cc2
-rw-r--r--test/asan/TestCases/Posix/coverage-sandboxing.cc4
-rw-r--r--test/asan/TestCases/Posix/dlclose-test.cc4
-rw-r--r--test/asan/TestCases/Posix/dump_instruction_bytes.cc (renamed from test/asan/TestCases/dump_instruction_bytes.cc)2
-rw-r--r--test/asan/TestCases/Posix/global-registration.c69
-rw-r--r--test/asan/TestCases/Posix/halt_on_error-torture.cc8
-rw-r--r--test/asan/TestCases/Posix/mmap_limit_mb.cc (renamed from test/asan/TestCases/mmap_limit_mb.cc)0
-rw-r--r--test/asan/TestCases/Posix/print_cmdline.cc18
-rw-r--r--test/asan/TestCases/Posix/start-deactivated.cc2
-rw-r--r--test/asan/TestCases/Windows/bind_io_completion_callback.cc8
-rw-r--r--test/asan/TestCases/Windows/coverage-basic.cc4
-rw-r--r--test/asan/TestCases/Windows/crash_read_write.cc29
-rw-r--r--test/asan/TestCases/Windows/dll_seh.cc14
-rw-r--r--test/asan/TestCases/Windows/intercept_strdup.cc12
-rw-r--r--test/asan/TestCases/Windows/oom.cc1
-rw-r--r--test/asan/TestCases/Windows/queue_user_work_item.cc13
-rw-r--r--test/asan/TestCases/Windows/queue_user_work_item_report.cc2
-rw-r--r--test/asan/TestCases/Windows/report_after_syminitialize.cc4
-rw-r--r--test/asan/TestCases/Windows/throw_catch.cc73
-rw-r--r--test/asan/TestCases/alloca_constant_size.cc51
-rw-r--r--test/asan/TestCases/asan_and_llvm_coverage_test.cc4
-rw-r--r--test/asan/TestCases/contiguous_container_crash.cc1
-rw-r--r--test/asan/TestCases/coverage-levels.cc10
-rw-r--r--test/asan/TestCases/coverage-pc-buffer.cc69
-rw-r--r--test/asan/TestCases/coverage-reset.cc7
-rw-r--r--test/asan/TestCases/coverage-trace-pc.cc31
-rw-r--r--test/asan/TestCases/debug_ppc64_mapping.cc2
-rw-r--r--test/asan/TestCases/double-free.cc6
-rw-r--r--test/asan/TestCases/initialization-bug.cc3
-rw-r--r--test/asan/TestCases/invalid-pointer-pairs.cc44
-rw-r--r--test/asan/TestCases/large_func_test.cc2
-rw-r--r--test/asan/TestCases/printf-2.c10
-rw-r--r--test/asan/TestCases/printf-4.c14
-rw-r--r--test/asan/TestCases/stack-oob-frames.cc3
-rw-r--r--test/asan/TestCases/strcasestr-2.c2
-rw-r--r--test/asan/TestCases/strdup_oob_test.cc9
-rw-r--r--test/asan/TestCases/strstr-2.c2
-rw-r--r--test/asan/TestCases/throw_call_test.cc3
-rw-r--r--test/asan/TestCases/throw_invoke_test.cc5
-rw-r--r--test/asan/TestCases/uar_and_exceptions.cc3
-rw-r--r--test/asan/TestCases/use-after-scope-capture.cc17
-rw-r--r--test/asan/TestCases/use-after-scope-chars.cc15
-rw-r--r--test/asan/TestCases/use-after-scope-dtor-order.cc6
-rw-r--r--test/asan/TestCases/use-after-scope-if.cc15
-rw-r--r--test/asan/TestCases/use-after-scope-inlined.cc4
-rw-r--r--test/asan/TestCases/use-after-scope-loop-bug.cc16
-rw-r--r--test/asan/TestCases/use-after-scope-loop-removed.cc19
-rw-r--r--test/asan/TestCases/use-after-scope-loop.cc14
-rw-r--r--test/asan/TestCases/use-after-scope-nobug.cc11
-rw-r--r--test/asan/TestCases/use-after-scope-temp.cc18
-rw-r--r--test/asan/TestCases/use-after-scope.cc9
-rw-r--r--test/asan/Unit/lit.site.cfg.in3
-rw-r--r--test/asan/android_commands/android_common.py27
-rw-r--r--test/asan/lit.cfg4
-rw-r--r--test/asan/lit.site.cfg.in4
-rw-r--r--test/builtins/Unit/cpu_model_test.c19
-rw-r--r--test/cfi/CMakeLists.txt20
-rw-r--r--test/cfi/create-derivers.test8
-rw-r--r--test/cfi/cross-dso/dlopen.cpp147
-rw-r--r--test/cfi/cross-dso/icall/diag.cpp159
-rw-r--r--test/cfi/cross-dso/icall/icall-from-dso.cpp8
-rw-r--r--test/cfi/cross-dso/icall/icall.cpp8
-rw-r--r--test/cfi/cross-dso/shadow_is_read_only.cpp85
-rw-r--r--test/cfi/cross-dso/simple-fail.cpp9
-rw-r--r--test/cfi/cross-dso/stats.cpp59
-rw-r--r--test/cfi/cross-dso/target_out_of_bounds.cpp64
-rw-r--r--test/cfi/icall/bad-signature.c8
-rw-r--r--test/cfi/icall/external-call.c2
-rw-r--r--test/cfi/lit.cfg26
-rw-r--r--test/cfi/lit.site.cfg.in4
-rw-r--r--test/cfi/overwrite.cpp7
-rw-r--r--test/cfi/stats.cpp52
-rw-r--r--test/cfi/target_uninstrumented.cpp44
-rw-r--r--test/dfsan/CMakeLists.txt35
-rw-r--r--test/dfsan/custom.cc2
-rw-r--r--test/dfsan/lit.cfg4
-rw-r--r--test/dfsan/lit.site.cfg.in7
-rw-r--r--test/esan/CMakeLists.txt32
-rw-r--r--test/esan/TestCases/large-stack-linux.c74
-rw-r--r--test/esan/TestCases/libc-intercept.c20
-rw-r--r--test/esan/TestCases/mmap-shadow-conflict.c30
-rw-r--r--test/esan/TestCases/struct-simple.cpp204
-rw-r--r--test/esan/TestCases/verbose-simple.c14
-rw-r--r--test/esan/TestCases/workingset-early-fault.c33
-rw-r--r--test/esan/TestCases/workingset-memset.cpp20
-rw-r--r--test/esan/TestCases/workingset-midreport.cpp71
-rw-r--r--test/esan/TestCases/workingset-samples.cpp44
-rw-r--r--test/esan/TestCases/workingset-signal-posix.cpp75
-rw-r--r--test/esan/TestCases/workingset-simple.cpp30
-rw-r--r--test/esan/Unit/circular_buffer.cpp61
-rw-r--r--test/esan/lit.cfg44
-rw-r--r--test/esan/lit.site.cfg.in14
-rw-r--r--test/lit.common.cfg44
-rw-r--r--test/lit.common.configured.in9
-rw-r--r--test/lsan/CMakeLists.txt49
-rw-r--r--test/lsan/TestCases/disabler_in_tsd_destructor.c2
-rw-r--r--test/lsan/TestCases/guard-page.c60
-rw-r--r--test/lsan/TestCases/high_allocator_contention.cc3
-rw-r--r--test/lsan/TestCases/leak_check_before_thread_started.cc13
-rw-r--r--test/lsan/TestCases/use_registers.cc5
-rw-r--r--test/lsan/TestCases/use_tls_dynamic.cc2
-rw-r--r--test/lsan/lit.common.cfg3
-rw-r--r--test/lsan/lit.site.cfg.in9
-rw-r--r--test/msan/CMakeLists.txt36
-rw-r--r--test/msan/Linux/cmsghdr.cc101
-rw-r--r--test/msan/Linux/eventfd.cc18
-rw-r--r--test/msan/Linux/process_vm_readv.cc22
-rw-r--r--test/msan/Linux/sendmsg.cc83
-rw-r--r--test/msan/Linux/syscalls.cc14
-rw-r--r--test/msan/Linux/syscalls_sigaction.cc40
-rw-r--r--test/msan/Unit/lit.site.cfg.in3
-rw-r--r--test/msan/coverage-levels.cc4
-rw-r--r--test/msan/dlerror.cc4
-rw-r--r--test/msan/dtls_test.c2
-rw-r--r--test/msan/fork.cc5
-rw-r--r--test/msan/lit.cfg16
-rw-r--r--test/msan/lit.site.cfg.in7
-rw-r--r--test/msan/memcmp_test.cc5
-rw-r--r--test/msan/msan_print_shadow3.cc2
-rw-r--r--test/msan/param_tls_limit.cc19
-rw-r--r--test/msan/vector_cvt.cc2
-rw-r--r--test/profile/CMakeLists.txt33
-rw-r--r--test/profile/Inputs/extern_template.cpp14
-rw-r--r--test/profile/Inputs/extern_template.h17
-rw-r--r--test/profile/Inputs/extern_template1.cpp9
-rw-r--r--test/profile/Inputs/extern_template2.cpp9
-rw-r--r--test/profile/Inputs/instrprof-alloc.c41
-rw-r--r--test/profile/Inputs/instrprof-comdat-1.cpp17
-rw-r--r--test/profile/Inputs/instrprof-comdat-2.cpp12
-rw-r--r--test/profile/Inputs/instrprof-comdat.h23
-rw-r--r--test/profile/Inputs/instrprof-dynamic-a.cpp10
-rw-r--r--test/profile/Inputs/instrprof-file_ex.c59
-rw-r--r--test/profile/Inputs/instrprof-icall-promo.h4
-rw-r--r--test/profile/Inputs/instrprof-icall-promo_1.cc7
-rw-r--r--test/profile/Inputs/instrprof-icall-promo_2.cc15
-rw-r--r--test/profile/Inputs/instrprof-merge-match-lib.c39
-rw-r--r--test/profile/Inputs/instrprof-merge-match.c54
-rw-r--r--test/profile/Inputs/instrprof-value-prof-evict.c141
-rw-r--r--test/profile/Inputs/instrprof-value-prof-real.c1096
-rw-r--r--test/profile/Inputs/instrprof-visibility-helper.cpp3
-rw-r--r--test/profile/Linux/coverage_ctors.cpp32
-rw-r--r--test/profile/Linux/coverage_dtor.cpp26
-rw-r--r--test/profile/Linux/coverage_shared.test16
-rw-r--r--test/profile/Linux/coverage_test.cpp35
-rw-r--r--test/profile/Linux/extern_template.test29
-rw-r--r--test/profile/Linux/instrprof-alloc.test6
-rw-r--r--test/profile/Linux/instrprof-comdat.test6
-rw-r--r--test/profile/Linux/instrprof-file_ex.test17
-rw-r--r--test/profile/Linux/instrprof-merge-vp.c113
-rw-r--r--test/profile/Linux/instrprof-set-filename-shared.test8
-rw-r--r--test/profile/Linux/instrprof-value-prof-warn.test8
-rw-r--r--test/profile/gcc-flag-compatibility.test1
-rw-r--r--test/profile/instrprof-basic.c28
-rw-r--r--test/profile/instrprof-bufferio.c43
-rw-r--r--test/profile/instrprof-error.c7
-rw-r--r--test/profile/instrprof-hostname.c14
-rw-r--r--test/profile/instrprof-icall-promo.test17
-rw-r--r--test/profile/instrprof-merge-match.test5
-rw-r--r--test/profile/instrprof-merge.c96
-rw-r--r--test/profile/instrprof-set-filename.c43
-rw-r--r--test/profile/instrprof-value-prof-2.c173
-rw-r--r--test/profile/instrprof-value-prof-evict.test16
-rw-r--r--test/profile/instrprof-value-prof-shared.test37
-rw-r--r--test/profile/instrprof-value-prof.c27
-rw-r--r--test/profile/instrprof-value-prof.test21
-rw-r--r--test/profile/instrprof-version-mismatch.c4
-rw-r--r--test/profile/instrprof-visibility-kinds.inc36
-rw-r--r--test/profile/instrprof-visibility.cpp89
-rw-r--r--test/profile/instrprof-without-libc.c38
-rw-r--r--test/profile/instrprof-write-file-only.c2
-rw-r--r--test/profile/lit.cfg21
-rw-r--r--test/profile/lit.site.cfg.in5
-rw-r--r--test/safestack/CMakeLists.txt2
-rw-r--r--test/safestack/canary.c37
-rw-r--r--test/safestack/lit.site.cfg.in3
-rw-r--r--test/sanitizer_common/CMakeLists.txt2
-rw-r--r--test/sanitizer_common/TestCases/Darwin/abort_on_error.cc2
-rw-r--r--test/sanitizer_common/TestCases/Linux/abort_on_error.cc2
-rw-r--r--test/sanitizer_common/TestCases/Linux/decorate_proc_maps.cc (renamed from test/sanitizer_common/TestCases/Posix/decorate_proc_maps.cc)0
-rw-r--r--test/sanitizer_common/TestCases/Linux/fpe.cc2
-rw-r--r--test/sanitizer_common/TestCases/Linux/ill.cc2
-rw-r--r--test/sanitizer_common/TestCases/Linux/open_memstream.cc2
-rw-r--r--test/sanitizer_common/TestCases/Linux/ptrace.cc20
-rw-r--r--test/sanitizer_common/TestCases/Linux/recv_msg_trunc.cc36
-rw-r--r--test/sanitizer_common/TestCases/Linux/sem_init_glibc.cc19
-rw-r--r--test/sanitizer_common/TestCases/Linux/weak_hook_test.cc82
-rw-r--r--test/sanitizer_common/TestCases/Posix/dedup_token_length_test.cc40
-rw-r--r--test/sanitizer_common/TestCases/Posix/getpass.cc (renamed from test/sanitizer_common/TestCases/Linux/getpass.cc)4
-rw-r--r--test/sanitizer_common/TestCases/Posix/lit.local.cfg2
-rw-r--r--test/sanitizer_common/TestCases/Posix/sanitizer_set_death_callback_test.cc (renamed from test/sanitizer_common/TestCases/Linux/sanitizer_set_death_callback_test.cc)0
-rw-r--r--test/sanitizer_common/TestCases/Posix/sanitizer_set_report_fd_test.cc37
-rw-r--r--test/sanitizer_common/TestCases/malloc_hook.cc30
-rw-r--r--test/sanitizer_common/TestCases/options-include.cc7
-rw-r--r--test/sanitizer_common/TestCases/print-stack-trace.cc10
-rw-r--r--test/sanitizer_common/TestCases/strnlen.c12
-rw-r--r--test/sanitizer_common/Unit/lit.site.cfg.in3
-rw-r--r--test/sanitizer_common/lit.common.cfg5
-rw-r--r--test/sanitizer_common/lit.site.cfg.in7
-rw-r--r--test/scudo/CMakeLists.txt28
-rw-r--r--test/scudo/alignment.cpp25
-rw-r--r--test/scudo/double-free.cpp49
-rw-r--r--test/scudo/lit.cfg39
-rw-r--r--test/scudo/lit.site.cfg.in7
-rw-r--r--test/scudo/malloc.cpp27
-rw-r--r--test/scudo/memalign.cpp45
-rw-r--r--test/scudo/mismatch.cpp41
-rw-r--r--test/scudo/overflow.cpp38
-rw-r--r--test/scudo/preinit.cpp38
-rw-r--r--test/scudo/quarantine.cpp43
-rw-r--r--test/scudo/realloc.cpp69
-rw-r--r--test/scudo/sized-delete.cpp40
-rw-r--r--test/scudo/sizes.cpp61
-rw-r--r--test/tsan/CMakeLists.txt3
-rw-r--r--test/tsan/Darwin/dispatch_main.mm38
-rw-r--r--test/tsan/Darwin/dispatch_once_deadlock.mm41
-rw-r--r--test/tsan/Darwin/dlopen.cc41
-rw-r--r--test/tsan/Darwin/gcd-after.mm41
-rw-r--r--test/tsan/Darwin/gcd-apply-race.mm26
-rw-r--r--test/tsan/Darwin/gcd-apply.mm44
-rw-r--r--test/tsan/Darwin/gcd-async-norace.mm2
-rw-r--r--test/tsan/Darwin/gcd-async-race.mm6
-rw-r--r--test/tsan/Darwin/gcd-barrier-race.mm48
-rw-r--r--test/tsan/Darwin/gcd-barrier.mm49
-rw-r--r--test/tsan/Darwin/gcd-blocks.mm34
-rw-r--r--test/tsan/Darwin/gcd-data.mm36
-rw-r--r--test/tsan/Darwin/gcd-fd.mm60
-rw-r--r--test/tsan/Darwin/gcd-groups-destructor.mm43
-rw-r--r--test/tsan/Darwin/gcd-groups-leave.mm56
-rw-r--r--test/tsan/Darwin/gcd-groups-norace.mm2
-rw-r--r--test/tsan/Darwin/gcd-groups-stress.mm4
-rw-r--r--test/tsan/Darwin/gcd-io-barrier-race.mm55
-rw-r--r--test/tsan/Darwin/gcd-io-barrier.mm48
-rw-r--r--test/tsan/Darwin/gcd-io-cleanup.mm56
-rw-r--r--test/tsan/Darwin/gcd-io-race.mm56
-rw-r--r--test/tsan/Darwin/gcd-io.mm117
-rw-r--r--test/tsan/Darwin/gcd-once.mm2
-rw-r--r--test/tsan/Darwin/gcd-semaphore-norace.mm2
-rw-r--r--test/tsan/Darwin/gcd-serial-queue-norace.mm2
-rw-r--r--test/tsan/Darwin/gcd-source-cancel.mm36
-rw-r--r--test/tsan/Darwin/gcd-source-cancel2.mm38
-rw-r--r--test/tsan/Darwin/gcd-source-event.mm35
-rw-r--r--test/tsan/Darwin/gcd-source-event2.mm37
-rw-r--r--test/tsan/Darwin/gcd-source-registration.mm33
-rw-r--r--test/tsan/Darwin/gcd-source-registration2.mm35
-rw-r--r--test/tsan/Darwin/gcd-source-serial.mm33
-rw-r--r--test/tsan/Darwin/gcd-sync-norace.mm2
-rw-r--r--test/tsan/Darwin/gcd-sync-race.mm6
-rw-r--r--test/tsan/Darwin/ignored-interceptors.mm55
-rw-r--r--test/tsan/Darwin/libcxx-shared-ptr-recursive.mm36
-rw-r--r--test/tsan/Darwin/libcxx-shared-ptr-stress.mm75
-rw-r--r--test/tsan/Darwin/libcxx-shared-ptr.mm50
-rw-r--r--test/tsan/Darwin/malloc-stack-logging.cc24
-rw-r--r--test/tsan/Darwin/malloc_size.mm57
-rw-r--r--test/tsan/Darwin/objc-race.mm4
-rw-r--r--test/tsan/Darwin/objc-simple.mm2
-rw-r--r--test/tsan/Darwin/osatomics-add.mm48
-rw-r--r--test/tsan/Darwin/osatomics-list.mm43
-rw-r--r--test/tsan/Darwin/xpc-race.mm81
-rw-r--r--test/tsan/Darwin/xpc.mm74
-rw-r--r--test/tsan/Linux/check_preinit.cc60
-rw-r--r--test/tsan/Linux/user_malloc.cc2
-rw-r--r--test/tsan/Unit/lit.site.cfg.in3
-rw-r--r--test/tsan/aligned_vs_unaligned_race.cc4
-rw-r--r--test/tsan/benign_race.cc2
-rw-r--r--test/tsan/blacklist.cc2
-rw-r--r--test/tsan/blacklist2.cc2
-rw-r--r--test/tsan/debugging.cc108
-rw-r--r--test/tsan/dl_iterate_phdr.cc2
-rw-r--r--test/tsan/dtls.c62
-rw-r--r--test/tsan/fd_close_norace.cc2
-rw-r--r--test/tsan/fd_close_norace2.cc2
-rw-r--r--test/tsan/fd_dup_norace.cc2
-rw-r--r--test/tsan/fd_dup_norace2.cc2
-rw-r--r--test/tsan/fd_dup_race.cc2
-rw-r--r--test/tsan/fd_pipe_norace.cc2
-rw-r--r--test/tsan/fd_socket_connect_norace.cc2
-rw-r--r--test/tsan/fd_socket_norace.cc2
-rw-r--r--test/tsan/fd_socketpair_norace.cc2
-rw-r--r--test/tsan/fork_atexit.cc1
-rw-r--r--test/tsan/fork_deadlock.cc11
-rw-r--r--test/tsan/fork_multithreaded.cc3
-rw-r--r--test/tsan/fork_multithreaded3.cc1
-rw-r--r--test/tsan/ignore_lib4.cc48
-rw-r--r--test/tsan/ignore_race.cc2
-rw-r--r--test/tsan/ignored-interceptors-mmap.cc61
-rw-r--r--test/tsan/inlined_memcpy_race.cc4
-rw-r--r--test/tsan/inlined_memcpy_race2.cc6
-rw-r--r--test/tsan/interface_atomic_test.c4
-rw-r--r--test/tsan/java_alloc.cc4
-rw-r--r--test/tsan/java_heap_init.cc2
-rw-r--r--test/tsan/java_lock_move.cc2
-rw-r--r--test/tsan/java_lock_rec.cc8
-rw-r--r--test/tsan/java_lock_rec_race.cc6
-rw-r--r--test/tsan/java_move_overlap.cc2
-rw-r--r--test/tsan/java_move_overlap_race.cc6
-rw-r--r--test/tsan/java_race_pc.cc8
-rw-r--r--test/tsan/java_rwlock.cc2
-rw-r--r--test/tsan/lit.cfg3
-rw-r--r--test/tsan/lit.site.cfg.in5
-rw-r--r--test/tsan/longjmp.cc4
-rw-r--r--test/tsan/longjmp2.cc4
-rw-r--r--test/tsan/longjmp3.cc4
-rw-r--r--test/tsan/longjmp4.cc4
-rw-r--r--test/tsan/lots_of_threads.c30
-rw-r--r--test/tsan/malloc_overflow.cc10
-rw-r--r--test/tsan/mmap_stress.cc5
-rw-r--r--test/tsan/mutex_annotations.cc49
-rw-r--r--test/tsan/mutex_cycle_long.c42
-rw-r--r--test/tsan/mutex_lock_destroyed.cc25
-rw-r--r--test/tsan/pthread_key.cc39
-rw-r--r--test/tsan/race_on_mutex.c32
-rw-r--r--test/tsan/race_on_speculative_load.cc4
-rw-r--r--test/tsan/setuid.c6
-rw-r--r--test/tsan/setuid2.c6
-rw-r--r--test/tsan/signal_sync2.cc77
-rw-r--r--test/tsan/static_init1.cc2
-rw-r--r--test/tsan/static_init2.cc2
-rw-r--r--test/tsan/static_init4.cc2
-rw-r--r--test/tsan/static_init5.cc2
-rw-r--r--test/tsan/static_init6.cc4
-rw-r--r--test/tsan/sunrpc.cc2
-rw-r--r--test/tsan/suppressions_global.cc2
-rw-r--r--test/tsan/suppressions_race.cc2
-rw-r--r--test/tsan/suppressions_race2.cc2
-rw-r--r--test/tsan/test.h35
-rw-r--r--test/tsan/thread_detach.c2
-rw-r--r--test/tsan/thread_detach2.c2
-rw-r--r--test/tsan/thread_leak.c2
-rw-r--r--test/tsan/thread_leak2.c2
-rw-r--r--test/tsan/thread_leak4.c2
-rw-r--r--test/tsan/tsan-vs-gvn.cc2
-rw-r--r--test/tsan/unaligned_norace.cc2
-rw-r--r--test/tsan/vfork.cc5
-rw-r--r--test/tsan/virtual_inheritance_compile_bug.cc2
-rw-r--r--test/ubsan/CMakeLists.txt8
-rw-r--r--test/ubsan/TestCases/Float/cast-overflow.cpp8
-rw-r--r--test/ubsan/TestCases/Integer/suppressions.cpp5
-rw-r--r--test/ubsan/TestCases/Misc/coverage-levels.cc20
-rw-r--r--test/ubsan/TestCases/TypeCheck/misaligned.cpp2
-rw-r--r--test/ubsan/TestCases/TypeCheck/null.cpp2
-rw-r--r--test/ubsan/TestCases/TypeCheck/vptr-corrupted-vtable-itanium.cpp41
-rw-r--r--test/ubsan/TestCases/TypeCheck/vptr-non-unique-typeinfo.cpp25
-rw-r--r--test/ubsan/TestCases/TypeCheck/vptr.cpp6
-rw-r--r--test/ubsan/lit.common.cfg5
-rw-r--r--test/ubsan/lit.site.cfg.in6
386 files changed, 9242 insertions, 705 deletions
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index e5c51c8cd474..03d4571e0de7 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Needed for lit support
+include(AddLLVM)
+
configure_lit_site_cfg(
${CMAKE_CURRENT_SOURCE_DIR}/lit.common.configured.in
${CMAKE_CURRENT_BINARY_DIR}/lit.common.configured)
@@ -20,7 +23,7 @@ if(NOT ANDROID)
# Use LLVM utils and Clang from the same build tree.
list(APPEND SANITIZER_COMMON_LIT_TEST_DEPS
clang clang-headers FileCheck count not llvm-config llvm-nm llvm-objdump
- llvm-symbolizer compiler-rt-headers)
+ llvm-symbolizer compiler-rt-headers sancov)
if (COMPILER_RT_HAS_PROFILE)
list(APPEND SANITIZER_COMMON_LIT_TEST_DEPS profile)
endif()
@@ -28,7 +31,7 @@ if(NOT ANDROID)
list(APPEND SANITIZER_COMMON_LIT_TEST_DEPS KillTheDoctor)
endif()
endif()
- if(UNIX)
+ if(CMAKE_HOST_UNIX)
list(APPEND SANITIZER_COMMON_LIT_TEST_DEPS SanitizerLintCheck)
endif()
endif()
@@ -67,6 +70,12 @@ if(COMPILER_RT_CAN_EXECUTE_TESTS)
if(COMPILER_RT_HAS_SAFESTACK)
add_subdirectory(safestack)
endif()
+ if(COMPILER_RT_HAS_ESAN)
+ add_subdirectory(esan)
+ endif()
+ if(COMPILER_RT_HAS_SCUDO)
+ add_subdirectory(scudo)
+ endif()
endif()
if(COMPILER_RT_STANDALONE_BUILD)
diff --git a/test/asan/CMakeLists.txt b/test/asan/CMakeLists.txt
index b2be9572002f..cb32cfba83b0 100644
--- a/test/asan/CMakeLists.txt
+++ b/test/asan/CMakeLists.txt
@@ -3,10 +3,16 @@ set(ASAN_LIT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
set(ASAN_TESTSUITES)
set(ASAN_DYNAMIC_TESTSUITES)
+# TODO(wwchrome): Re-enable Win64 asan tests when ready.
+# Disable tests for asan Win64 temporarily.
+if(OS_NAME MATCHES "Windows" AND CMAKE_SIZEOF_VOID_P EQUAL 8)
+ set(EXCLUDE_FROM_ALL TRUE)
+endif()
+
macro(get_bits_for_arch arch bits)
if (${arch} MATCHES "i386|i686|arm|mips|mipsel")
set(${bits} 32)
- elseif (${arch} MATCHES "x86_64|powerpc64|powerpc64le|aarch64|mips64|mips64el")
+ elseif (${arch} MATCHES "x86_64|powerpc64|powerpc64le|aarch64|mips64|mips64el|s390x")
set(${bits} 64)
else()
message(FATAL_ERROR "Unknown target architecture: ${arch}")
@@ -97,11 +103,12 @@ endif()
add_lit_testsuite(check-asan "Running the AddressSanitizer tests"
${ASAN_TESTSUITES}
DEPENDS ${ASAN_TEST_DEPS})
-set_target_properties(check-asan PROPERTIES FOLDER "ASan tests")
+set_target_properties(check-asan PROPERTIES FOLDER "Compiler-RT Misc")
if(COMPILER_RT_ASAN_HAS_STATIC_RUNTIME)
# Add check-dynamic-asan target. It is a part of check-all only on Windows,
# where we want to always test both dynamic and static runtime.
+
if(NOT OS_NAME MATCHES "Windows")
set(EXCLUDE_FROM_ALL TRUE)
endif()
@@ -110,8 +117,13 @@ if(COMPILER_RT_ASAN_HAS_STATIC_RUNTIME)
${ASAN_DYNAMIC_TESTSUITES}
DEPENDS ${ASAN_DYNAMIC_TEST_DEPS})
set_target_properties(check-asan-dynamic
- PROPERTIES FOLDER "ASan dynamic tests")
+ PROPERTIES FOLDER "Compiler-RT Misc")
if(NOT OS_NAME MATCHES "Windows")
set(EXCLUDE_FROM_ALL FALSE)
endif()
endif()
+
+# TODO(wwchrome): Re-enable the tests for asan Win64 when ready.
+if(OS_NAME MATCHES "Windows" AND CMAKE_SIZEOF_VOID_P EQUAL 8)
+ set(EXCLUDE_FROM_ALL FALSE)
+endif()
diff --git a/test/asan/TestCases/Android/coverage-android.cc b/test/asan/TestCases/Android/coverage-android.cc
index 16a6e1f7e160..2a3359948691 100644
--- a/test/asan/TestCases/Android/coverage-android.cc
+++ b/test/asan/TestCases/Android/coverage-android.cc
@@ -139,5 +139,5 @@ int main(int argc, char **argv) {
#endif
// CHECK1: 2 PCs total
-// CHECK2: 7 PCs total
-// CHECK3: 8 PCs total
+// CHECK2: 4 PCs total
+// CHECK3: 5 PCs total
diff --git a/test/asan/TestCases/Darwin/abort_on_error.cc b/test/asan/TestCases/Darwin/abort_on_error.cc
index f09718bda06e..295afb8442a4 100644
--- a/test/asan/TestCases/Darwin/abort_on_error.cc
+++ b/test/asan/TestCases/Darwin/abort_on_error.cc
@@ -4,7 +4,7 @@
// RUN: %clangxx_asan %s -o %t
// Intentionally don't inherit the default ASAN_OPTIONS.
-// RUN: ASAN_OPTIONS="" not --crash %run %t 2>&1 | FileCheck %s
+// RUN: env ASAN_OPTIONS="" not --crash %run %t 2>&1 | FileCheck %s
// When we use lit's default ASAN_OPTIONS, we shouldn't crash.
// RUN: not %run %t 2>&1 | FileCheck %s
diff --git a/test/asan/TestCases/Darwin/address-range-limit.mm b/test/asan/TestCases/Darwin/address-range-limit.mm
index a6906766d7ee..ba9175a2ce20 100644
--- a/test/asan/TestCases/Darwin/address-range-limit.mm
+++ b/test/asan/TestCases/Darwin/address-range-limit.mm
@@ -1,7 +1,7 @@
// Regression test for https://code.google.com/p/address-sanitizer/issues/detail?id=368.
-// RUN: %clang_asan %s -Wno-deprecated-declarations -flat_namespace -bundle -undefined suppress -o %t.bundle
-// RUN: %clang_asan %s -Wno-deprecated-declarations -o %t -framework Foundation && not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan %s -Wno-deprecated-declarations -flat_namespace -bundle -undefined suppress -o %t.bundle
+// RUN: %clangxx_asan %s -Wno-deprecated-declarations -o %t -framework Foundation && not %run %t 2>&1 | FileCheck %s
#import <Foundation/Foundation.h>
#import <mach-o/dyld.h>
diff --git a/test/asan/TestCases/Darwin/atos-symbolizer-dyld-root-path.cc b/test/asan/TestCases/Darwin/atos-symbolizer-dyld-root-path.cc
index 4595fb547f57..d2facd6d0c2e 100644
--- a/test/asan/TestCases/Darwin/atos-symbolizer-dyld-root-path.cc
+++ b/test/asan/TestCases/Darwin/atos-symbolizer-dyld-root-path.cc
@@ -14,8 +14,8 @@ int main(int argc, char **argv) {
int res = x[argc];
free(x);
free(x + argc - 1); // BOOM
- // CHECK: AddressSanitizer: attempting double-free{{.*}}in thread T0
// CHECK: Using atos at user-specified path:
+ // CHECK: AddressSanitizer: attempting double-free{{.*}}in thread T0
// CHECK: #0 0x{{.*}} in {{.*}}free
// CHECK: #1 0x{{.*}} in main {{.*}}atos-symbolizer-dyld-root-path.cc:[[@LINE-4]]
// CHECK: freed by thread T0 here:
diff --git a/test/asan/TestCases/Darwin/atos-symbolizer.cc b/test/asan/TestCases/Darwin/atos-symbolizer.cc
index 2a9ffbc5b25c..b4a868e242ea 100644
--- a/test/asan/TestCases/Darwin/atos-symbolizer.cc
+++ b/test/asan/TestCases/Darwin/atos-symbolizer.cc
@@ -11,8 +11,8 @@ int main(int argc, char **argv) {
int res = x[argc];
free(x);
free(x + argc - 1); // BOOM
- // CHECK: AddressSanitizer: attempting double-free{{.*}}in thread T0
// CHECK: Using atos at user-specified path:
+ // CHECK: AddressSanitizer: attempting double-free{{.*}}in thread T0
// CHECK: #0 0x{{.*}} in {{.*}}free
// CHECK: #1 0x{{.*}} in main {{.*}}atos-symbolizer.cc:[[@LINE-4]]
// CHECK: freed by thread T0 here:
diff --git a/test/asan/TestCases/Darwin/dead-strip.c b/test/asan/TestCases/Darwin/dead-strip.c
new file mode 100644
index 000000000000..212dedd469c1
--- /dev/null
+++ b/test/asan/TestCases/Darwin/dead-strip.c
@@ -0,0 +1,22 @@
+// Test that AddressSanitizer does not re-animate dead globals when dead
+// stripping is turned on.
+//
+// This test verifies that an out-of-bounds access on a global variable is
+// detected after dead stripping has been performed. This proves that the
+// runtime is able to register globals in the __DATA,__asan_globals section.
+
+// REQUIRES: osx-ld64-live_support
+// RUN: %clang_asan -mllvm -asan-globals-live-support -Xlinker -dead_strip -o %t %s
+// RUN: llvm-nm -format=posix %t | FileCheck --check-prefix NM-CHECK %s
+// RUN: not %run %t 2>&1 | FileCheck --check-prefix ASAN-CHECK %s
+
+int alive[1] = {};
+int dead[1] = {};
+// NM-CHECK: {{^_alive }}
+// NM-CHECK-NOT: {{^_dead }}
+
+int main(int argc, char *argv[]) {
+ alive[argc] = 0;
+ // ASAN-CHECK: {{0x.* is located 0 bytes to the right of global variable}}
+ return 0;
+}
diff --git a/test/asan/TestCases/Darwin/dladdr-demangling.cc b/test/asan/TestCases/Darwin/dladdr-demangling.cc
index d773659b74f8..6f52b93da04b 100644
--- a/test/asan/TestCases/Darwin/dladdr-demangling.cc
+++ b/test/asan/TestCases/Darwin/dladdr-demangling.cc
@@ -13,10 +13,10 @@ class MyClass {
char *x = (char*)malloc(n * sizeof(char));
free(x);
return x[5];
+ // CHECK-DLADDR: Using dladdr symbolizer
// CHECK: {{.*ERROR: AddressSanitizer: heap-use-after-free on address}}
// CHECK: {{READ of size 1 at 0x.* thread T0}}
- // CHECK-DLADDR: Using dladdr symbolizer
- // CHECK-DLADDR: failed to fork external symbolizer
+ // CHECK-DLADDR: failed to fork
// CHECK: {{ #0 0x.* in MyClass::my_function\(int\)}}
// CHECK: {{freed by thread T0 here:}}
// CHECK: {{ #0 0x.* in wrap_free}}
diff --git a/test/asan/TestCases/Darwin/malloc_size_crash.mm b/test/asan/TestCases/Darwin/malloc_size_crash.mm
new file mode 100644
index 000000000000..04cb7637635c
--- /dev/null
+++ b/test/asan/TestCases/Darwin/malloc_size_crash.mm
@@ -0,0 +1,15 @@
+// RUN: %clang_asan %s -o %t -framework Foundation
+// RUN: %run %t 2>&1 | FileCheck %s
+
+#import <Foundation/Foundation.h>
+#include <malloc/malloc.h>
+
+int main(int argc, char *argv[]) {
+ id obj = @0;
+ fprintf(stderr, "obj = %p\n", obj);
+ size_t size = malloc_size(obj);
+ fprintf(stderr, "size = 0x%zx\n", size);
+ fprintf(stderr, "Done.\n");
+ // CHECK: Done.
+ return 0;
+}
diff --git a/test/asan/TestCases/Darwin/objc-odr.mm b/test/asan/TestCases/Darwin/objc-odr.mm
index 72bc39c80dd4..c4c240ee419c 100644
--- a/test/asan/TestCases/Darwin/objc-odr.mm
+++ b/test/asan/TestCases/Darwin/objc-odr.mm
@@ -16,7 +16,7 @@ void f() {
}
int main() {
- NSLog(@"Hello world");
+ fprintf(stderr,"Hello world");
}
// CHECK-NOT: AddressSanitizer: odr-violation
diff --git a/test/asan/TestCases/Darwin/segv_read_write.c b/test/asan/TestCases/Darwin/segv_read_write.c
new file mode 100644
index 000000000000..d8e2d215f832
--- /dev/null
+++ b/test/asan/TestCases/Darwin/segv_read_write.c
@@ -0,0 +1,26 @@
+// RUN: %clangxx_asan -std=c++11 -O0 %s -o %t
+// RUN: not %run %t 2>&1 | FileCheck %s --check-prefix=READ
+// RUN: not %run %t write 2>&1 | FileCheck %s --check-prefix=WRITE
+// REQUIRES: x86-target-arch
+
+#include <sys/mman.h>
+
+static volatile int sink;
+__attribute__((noinline)) void Read(int *ptr) { sink = *ptr; }
+__attribute__((noinline)) void Write(int *ptr) { *ptr = 0; }
+int main(int argc, char **argv) {
+ // Writes to shadow are detected as reads from shadow gap (because of how the
+ // shadow mapping works). This is kinda hard to fix. Test a random address in
+ // the application part of the address space.
+ void *volatile p =
+ mmap(nullptr, 4096, PROT_READ, MAP_PRIVATE | MAP_ANON, 0, 0);
+ munmap(p, 4096);
+ if (argc == 1)
+ Read((int *)p);
+ else
+ Write((int *)p);
+}
+// READ: AddressSanitizer: SEGV on unknown address
+// READ: The signal is caused by a READ memory access.
+// WRITE: AddressSanitizer: SEGV on unknown address
+// WRITE: The signal is caused by a WRITE memory access.
diff --git a/test/asan/TestCases/Darwin/suppressions-darwin.cc b/test/asan/TestCases/Darwin/suppressions-darwin.cc
index 403d819706a9..a177c4e17ec4 100644
--- a/test/asan/TestCases/Darwin/suppressions-darwin.cc
+++ b/test/asan/TestCases/Darwin/suppressions-darwin.cc
@@ -4,6 +4,7 @@
// Check that suppressing the interceptor by name works.
// RUN: echo "interceptor_name:memmove" > %t.supp
+// RUN: echo "interceptor_name:memcpy" >> %t.supp
// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t 2>&1 | FileCheck --check-prefix=CHECK-IGNORE %s
// Check that suppressing by interceptor name works even without the symbolizer
diff --git a/test/asan/TestCases/Linux/abort_on_error.cc b/test/asan/TestCases/Linux/abort_on_error.cc
index 406d98b6764a..67fa9b83e65d 100644
--- a/test/asan/TestCases/Linux/abort_on_error.cc
+++ b/test/asan/TestCases/Linux/abort_on_error.cc
@@ -4,7 +4,7 @@
// RUN: %clangxx_asan %s -o %t
// Intentionally don't inherit the default ASAN_OPTIONS.
-// RUN: ASAN_OPTIONS="" not %run %t 2>&1 | FileCheck %s
+// RUN: env ASAN_OPTIONS="" not %run %t 2>&1 | FileCheck %s
// When we use lit's default ASAN_OPTIONS, we shouldn't crash either. On Linux
// lit doesn't set ASAN_OPTIONS anyway.
// RUN: not %run %t 2>&1 | FileCheck %s
diff --git a/test/asan/TestCases/Linux/asan-asm-stacktrace-test.cc b/test/asan/TestCases/Linux/asan-asm-stacktrace-test.cc
index 5332c992a0db..cbc900decea3 100644
--- a/test/asan/TestCases/Linux/asan-asm-stacktrace-test.cc
+++ b/test/asan/TestCases/Linux/asan-asm-stacktrace-test.cc
@@ -1,7 +1,7 @@
// Check that a stack unwinding algorithm works corretly even with the assembly
// instrumentation.
-// REQUIRES: x86_64-supported-target
+// REQUIRES: x86_64-target-arch
// RUN: %clangxx_asan -g -O1 %s -fno-inline-functions -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -mllvm -asan-instrument-assembly -o %t && not %run %t 2>&1 | FileCheck %s
// RUN: %clangxx_asan -g -O1 %s -fno-inline-functions -fomit-frame-pointer -momit-leaf-frame-pointer -mllvm -asan-instrument-assembly -o %t && not %run %t 2>&1 | FileCheck %s
// RUN: %clangxx_asan -g0 -O1 %s -fno-unwind-tables -fno-asynchronous-unwind-tables -fno-exceptions -fno-inline-functions -fomit-frame-pointer -momit-leaf-frame-pointer -mllvm -asan-instrument-assembly -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-nounwind
diff --git a/test/asan/TestCases/Linux/asan_prelink_test.cc b/test/asan/TestCases/Linux/asan_prelink_test.cc
index d67d945851f9..a5808ba3a9a5 100644
--- a/test/asan/TestCases/Linux/asan_prelink_test.cc
+++ b/test/asan/TestCases/Linux/asan_prelink_test.cc
@@ -10,7 +10,7 @@
// RUN: %env_asan_opts=verbosity=1 %run %t 2>&1 | FileCheck %s
// GNU driver doesn't handle .so files properly.
-// REQUIRES: x86_64-supported-target, asan-64-bits, Clang
+// REQUIRES: x86_64-target-arch, Clang
#if BUILD_SO
int G;
int *getG() {
diff --git a/test/asan/TestCases/Linux/clang_gcc_abi.cc b/test/asan/TestCases/Linux/clang_gcc_abi.cc
index 669d1524077c..845f4121adcc 100644
--- a/test/asan/TestCases/Linux/clang_gcc_abi.cc
+++ b/test/asan/TestCases/Linux/clang_gcc_abi.cc
@@ -3,7 +3,7 @@
// RUN: %clangxx_asan -O2 -x c %s -o %t && not %run %t 2>&1 | FileCheck %s
// RUN: %clangxx_asan -O3 -x c %s -o %t && not %run %t 2>&1 | FileCheck %s
-// REQUIRES: arm-supported-target
+// REQUIRES: arm-target-arch
// XFAIL: armv7l-unknown-linux-gnueabihf
#include <stdlib.h>
diff --git a/test/asan/TestCases/Linux/clone_test.cc b/test/asan/TestCases/Linux/clone_test.cc
index e9c1f166eb45..f6eb26100f5e 100644
--- a/test/asan/TestCases/Linux/clone_test.cc
+++ b/test/asan/TestCases/Linux/clone_test.cc
@@ -22,7 +22,7 @@ int Child(void *arg) {
int main(int argc, char **argv) {
const int kStackSize = 1 << 20;
- char child_stack[kStackSize + 1];
+ char __attribute__((aligned(16))) child_stack[kStackSize + 1];
char *sp = child_stack + kStackSize; // Stack grows down.
printf("Parent: %p\n", sp);
pid_t clone_pid = clone(Child, sp, CLONE_FILES | CLONE_VM, NULL);
diff --git a/test/asan/TestCases/Linux/coverage-missing.cc b/test/asan/TestCases/Linux/coverage-missing.cc
index 6cd3201c48d1..49487d39a15b 100644
--- a/test/asan/TestCases/Linux/coverage-missing.cc
+++ b/test/asan/TestCases/Linux/coverage-missing.cc
@@ -43,7 +43,7 @@
// RUN: %sancov missing %dynamiclib < foo.txt > foo-missing.txt
// RUN: ( diff bar.txt foo-missing.txt || true ) | not grep "^<"
-// REQUIRES: x86_64-supported-target, i386-supported-target
+// REQUIRES: x86-target-arch
// XFAIL: android
#include <stdio.h>
diff --git a/test/asan/TestCases/Linux/coverage_html_report.cc b/test/asan/TestCases/Linux/coverage_html_report.cc
new file mode 100644
index 000000000000..78fbfb372403
--- /dev/null
+++ b/test/asan/TestCases/Linux/coverage_html_report.cc
@@ -0,0 +1,24 @@
+// REQUIRES: has_sancovcc, x86_64-linux, asan-dynamic-runtime
+// RUN: %clangxx_asan_static -fsanitize-coverage=func %s -o %t
+// RUN: rm -rf %T/coverage_html_report
+// RUN: mkdir -p %T/coverage_html_report
+// RUN: cd %T/coverage_html_report
+// RUN: %env_asan_opts=coverage=1:verbosity=1:html_cov_report=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-main
+// RUN: ls *.html | FileCheck %s --check-prefix=CHECK-ls
+// RUN: rm -r %T/coverage_html_report
+
+#include <stdio.h>
+#include <unistd.h>
+
+void bar() { printf("bar\n"); }
+
+int main(int argc, char **argv) {
+ fprintf(stderr, "PID: %d\n", getpid());
+ bar();
+ return 0;
+}
+
+// CHECK-main: PID: [[PID:[0-9]+]]
+// CHECK-main: [[PID]].sancov: 2 PCs written
+// CHECK-main: coverage report generated to ./coverage_html_report.cc.tmp.[[PID]].html
+// CHECK-ls: coverage_html_report.cc.tmp.{{[0-9]+}}.html
diff --git a/test/asan/TestCases/Linux/interface_symbols_linux.c b/test/asan/TestCases/Linux/interface_symbols_linux.c
index 971feb5dc09f..2e648575f28c 100644
--- a/test/asan/TestCases/Linux/interface_symbols_linux.c
+++ b/test/asan/TestCases/Linux/interface_symbols_linux.c
@@ -56,6 +56,6 @@
// FIXME: nm -D on powerpc somewhy shows ASan interface symbols residing
// in "initialized data section".
-// REQUIRES: x86_64-supported-target,i386-supported-target,asan-static-runtime
+// REQUIRES: x86-target-arch,asan-static-runtime
int main() { return 0; }
diff --git a/test/asan/TestCases/Linux/kernel-area.cc b/test/asan/TestCases/Linux/kernel-area.cc
index c0f17272ad27..d7a544fecaf9 100644
--- a/test/asan/TestCases/Linux/kernel-area.cc
+++ b/test/asan/TestCases/Linux/kernel-area.cc
@@ -16,7 +16,7 @@
// CHECK-kernel-64-bits: || `[0x28{{0+}}, 0x3{{f+}}]` || HighShadow ||
// CHECK-kernel-64-bits: || `[0x24{{0+}}, 0x27{{f+}}]` || ShadowGap ||
//
-// REQUIRES: asan-32-bits,i386-supported-target
+// REQUIRES: i386-target-arch
int main() {
return 0;
diff --git a/test/asan/TestCases/Linux/leak_check_segv.cc b/test/asan/TestCases/Linux/leak_check_segv.cc
index 8160d5fe56bb..2a2010f7ab0f 100644
--- a/test/asan/TestCases/Linux/leak_check_segv.cc
+++ b/test/asan/TestCases/Linux/leak_check_segv.cc
@@ -1,5 +1,5 @@
// Test that SIGSEGV during leak checking does not crash the process.
-// RUN: %clangxx_asan -O1 %s -o %t && LSAN_OPTIONS="verbosity=1" not %run %t 2>&1
+// RUN: %clangxx_asan -O1 %s -o %t && not %run %t 2>&1 | FileCheck %s
// REQUIRES: leak-detection
#include <stdlib.h>
#include <stdio.h>
@@ -11,7 +11,7 @@ char data[10 * 1024 * 1024];
int main() {
void *p = malloc(10 * 1024 * 1024);
// surprise-surprise!
- mprotect((void*)(((unsigned long)p + 4095) & ~4095), 16 * 1024, PROT_NONE);
+ mprotect((void*)(((unsigned long)p + 4095) & ~4095), 16 * 1024, PROT_NONE);
mprotect((void*)(((unsigned long)data + 4095) & ~4095), 16 * 1024, PROT_NONE);
__lsan_do_leak_check();
fprintf(stderr, "DONE\n");
@@ -19,5 +19,5 @@ int main() {
// CHECK: Tracer caught signal 11
// CHECK: LeakSanitizer has encountered a fatal error
+// CHECK: HINT: For debugging, try setting {{.*}} LSAN_OPTIONS
// CHECK-NOT: DONE
-
diff --git a/test/asan/TestCases/Linux/local_alias.cc b/test/asan/TestCases/Linux/local_alias.cc
new file mode 100644
index 000000000000..d941ff2f9171
--- /dev/null
+++ b/test/asan/TestCases/Linux/local_alias.cc
@@ -0,0 +1,40 @@
+// Test that mixing instrumented and non-instrumented code doesn't lead to crash.
+// Build two modules (one is instrumented, another is not) that have globals
+// with same names. Check, that ASan doesn't crash with CHECK failure or
+// false positive global-buffer-overflow due to sanitized library poisons
+// globals from non-sanitized one.
+//
+// FIXME: https://github.com/google/sanitizers/issues/316
+// XFAIL: android
+// XFAIL: mips64
+//
+// RUN: %clangxx_asan -DBUILD_INSTRUMENTED_DSO=1 -fPIC -shared -mllvm -asan-use-private-alias %s -o %t-INSTRUMENTED-SO.so
+// RUN: %clangxx -DBUILD_UNINSTRUMENTED_DSO=1 -fPIC -shared %s -o %t-UNINSTRUMENTED-SO.so
+// RUN: %clangxx %s -c -mllvm -asan-use-private-alias -o %t.o
+// RUN: %clangxx_asan %t.o %t-UNINSTRUMENTED-SO.so %t-INSTRUMENTED-SO.so -o %t-EXE
+// RUN: %env_asan_opts=use_odr_indicator=true %run %t-EXE
+
+#if defined (BUILD_INSTRUMENTED_DSO)
+long h = 15;
+long f = 4;
+long foo(long *p) {
+ return *p;
+}
+#elif defined (BUILD_UNINSTRUMENTED_DSO)
+long foo(long *);
+long h = 12;
+long i = 13;
+long f = 5;
+
+int bar() {
+ if (foo(&f) != 5 || foo(&h) != 12 || foo(&i) != 13)
+ return 1;
+ return 0;
+}
+#else
+extern int bar();
+
+int main() {
+ return bar();
+}
+#endif
diff --git a/test/asan/TestCases/Linux/malloc-in-qsort.cc b/test/asan/TestCases/Linux/malloc-in-qsort.cc
index e8c9b7480b76..ea239244290f 100644
--- a/test/asan/TestCases/Linux/malloc-in-qsort.cc
+++ b/test/asan/TestCases/Linux/malloc-in-qsort.cc
@@ -7,7 +7,7 @@
// https://code.google.com/p/address-sanitizer/issues/detail?id=137
// Fast unwinder is only available on x86_64 and i386.
-// REQUIRES: x86_64-supported-target
+// REQUIRES: x86-target-arch
// REQUIRES: compiler-rt-optimized
diff --git a/test/asan/TestCases/Linux/memmem_test.cc b/test/asan/TestCases/Linux/memmem_test.cc
new file mode 100644
index 000000000000..54883004e0aa
--- /dev/null
+++ b/test/asan/TestCases/Linux/memmem_test.cc
@@ -0,0 +1,21 @@
+// RUN: %clangxx_asan %s -o %t
+// RUN: not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=A1
+// RUN: not %run %t 1 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=A2
+// RUN: %env_asan_opts=intercept_memmem=0 %run %t
+
+#include <string.h>
+int main(int argc, char **argv) {
+ char a1[] = {1, 2, 3, 4, 5, 6, 7, 8};
+ char a2[] = {3, 4, 5};
+ void *res;
+ if (argc == 1)
+ res = memmem(a1, sizeof(a1) + 1, a2, sizeof(a2)); // BOOM
+ else
+ res = memmem(a1, sizeof(a1), a2, sizeof(a2) + 1); // BOOM
+ // CHECK: AddressSanitizer: stack-buffer-overflow
+ // CHECK: {{#0.*memmem}}
+ // CHECK: {{#1.*main}}
+ // A1: 'a1' <== Memory access at offset
+ // A2: 'a2' <== Memory access at offset
+ return res == NULL;
+}
diff --git a/test/asan/TestCases/Linux/new_delete_mismatch.cc b/test/asan/TestCases/Linux/new_delete_mismatch.cc
new file mode 100644
index 000000000000..1cfc0ef05312
--- /dev/null
+++ b/test/asan/TestCases/Linux/new_delete_mismatch.cc
@@ -0,0 +1,16 @@
+// Check that we report new[] vs delete as alloc-dealloc-mismatch and not as
+// new-delete-type-mismatch when -fsized-deallocation is enabled.
+
+// RUN: %clangxx_asan -g %s -o %t && not %run %t |& FileCheck %s
+// RUN: %clangxx_asan -fsized-deallocation -g %s -o %t && not %run %t |& FileCheck %s
+
+#include <stdlib.h>
+
+static volatile char *x;
+
+int main() {
+ x = new char[10];
+ delete x;
+}
+
+// CHECK: AddressSanitizer: alloc-dealloc-mismatch (operator new [] vs operator delete) on 0x
diff --git a/test/asan/TestCases/Linux/nohugepage_test.cc b/test/asan/TestCases/Linux/nohugepage_test.cc
index 2758f0ad04f5..ce8f17e7899e 100644
--- a/test/asan/TestCases/Linux/nohugepage_test.cc
+++ b/test/asan/TestCases/Linux/nohugepage_test.cc
@@ -9,7 +9,7 @@
// Would be great to run the test with no_huge_pages_for_shadow=0, but
// the result will depend on the OS version and settings...
//
-// REQUIRES: x86_64-supported-target, asan-64-bits
+// REQUIRES: x86_64-target-arch
//
// WARNING: this test is very subtle and may nto work on some systems.
// If this is the case we'll need to futher improve it or disable it.
diff --git a/test/asan/TestCases/Linux/odr-violation.cc b/test/asan/TestCases/Linux/odr-violation.cc
index bc76116632ec..143fb6e14344 100644
--- a/test/asan/TestCases/Linux/odr-violation.cc
+++ b/test/asan/TestCases/Linux/odr-violation.cc
@@ -1,5 +1,6 @@
// FIXME: https://code.google.com/p/address-sanitizer/issues/detail?id=316
// XFAIL: android
+// XFAIL: mips64
//
// We use fast_unwind_on_malloc=0 to have full unwinding even w/o frame
// pointers. This setting is not on by default because it's too expensive.
@@ -22,6 +23,13 @@
// RUN: echo "odr_violation:foo::G" > %t.supp
// RUN: %env_asan_opts=fast_unwind_on_malloc=0:detect_odr_violation=2:suppressions=%t.supp %run %t-ODR-EXE 2>&1 | FileCheck %s --check-prefix=DISABLED
// RUN: rm -f %t.supp
+//
+// Use private aliases for global variables: use indicator symbol to detect ODR violation.
+// RUN: %clangxx_asan -DBUILD_SO=1 -fPIC -shared -mllvm -asan-use-private-alias %s -o %t-ODR-SO.so -DSZ=100
+// RUN: %clangxx_asan -mllvm -asan-use-private-alias %s %t-ODR-SO.so -Wl,-R. -o %t-ODR-EXE
+// RUN: %env_asan_opts=fast_unwind_on_malloc=0 %run %t-ODR-EXE 2>&1 | FileCheck %s --check-prefix=DISABLED
+// RUN: %env_asan_opts=fast_unwind_on_malloc=0:use_odr_indicator=false %run %t-ODR-EXE 2>&1 | FileCheck %s --check-prefix=DISABLED
+// RUN: %env_asan_opts=fast_unwind_on_malloc=0:use_odr_indicator=true not %run %t-ODR-EXE 2>&1 | FileCheck %s
// GNU driver doesn't handle .so files properly.
// REQUIRES: Clang
diff --git a/test/asan/TestCases/Linux/odr_c_test.c b/test/asan/TestCases/Linux/odr_c_test.c
new file mode 100644
index 000000000000..b1d23493b570
--- /dev/null
+++ b/test/asan/TestCases/Linux/odr_c_test.c
@@ -0,0 +1,28 @@
+// Test that we can properly report an ODR violation
+// between an instrumented global and a non-instrumented global.
+
+// RUN: %clang_asan %s -fPIC -shared -o %t-1.so -DFILE1
+// RUN: %clang_asan %s -fPIC -shared -o %t-2.so -DFILE2
+// RUN: %clang_asan %s -fPIE %t-1.so %t-2.so -Wl,-R`pwd` -o %t
+// RUN: not %run %t 2>&1 | FileCheck %s
+//
+// REQUIRES: x86_64-target-arch
+//
+// CHECK: The following global variable is not properly aligned.
+// CHECK: ERROR: AddressSanitizer: odr-violation
+#if defined(FILE1)
+__attribute__((aligned(8))) int x;
+__attribute__((aligned(1))) char y;
+// The gold linker puts ZZZ at the start of bss (where it is aligned)
+// unless we have a large alternative like Displace:
+__attribute__((aligned(1))) char Displace[105];
+__attribute__((aligned(1))) char ZZZ[100];
+#elif defined(FILE2)
+int ZZZ = 1;
+#else
+extern int ZZZ;
+int main() {
+ return ZZZ;
+}
+#endif
+
diff --git a/test/asan/TestCases/Linux/overflow-in-qsort.cc b/test/asan/TestCases/Linux/overflow-in-qsort.cc
index dc3918e876a6..6990518e43ac 100644
--- a/test/asan/TestCases/Linux/overflow-in-qsort.cc
+++ b/test/asan/TestCases/Linux/overflow-in-qsort.cc
@@ -7,7 +7,7 @@
// https://code.google.com/p/address-sanitizer/issues/detail?id=137
// Fast unwinder is only available on x86_64 and i386.
-// REQUIRES: x86_64-supported-target
+// REQUIRES: x86-target-arch
#include <stdlib.h>
#include <stdio.h>
diff --git a/test/asan/TestCases/Linux/print_memory_profile_test.cc b/test/asan/TestCases/Linux/print_memory_profile_test.cc
new file mode 100644
index 000000000000..d30dbea1cf6d
--- /dev/null
+++ b/test/asan/TestCases/Linux/print_memory_profile_test.cc
@@ -0,0 +1,29 @@
+// Printing memory profiling only works in the configuration where we can
+// detect leaks.
+// REQUIRES: leak-detection
+//
+// RUN: %clangxx_asan %s -o %t
+// RUN: %run %t 2>&1 | FileCheck %s
+#include <sanitizer/common_interface_defs.h>
+
+#include <stdio.h>
+
+char *sink[1000];
+
+int main() {
+ int idx = 0;
+ for (int i = 0; i < 17; i++)
+ sink[idx++] = new char[131000];
+ for (int i = 0; i < 28; i++)
+ sink[idx++] = new char[24000];
+
+ __sanitizer_print_memory_profile(100);
+ __sanitizer_print_memory_profile(50);
+}
+
+// CHECK: Live Heap Allocations: {{.*}}; showing top 100%
+// CHECK: 2227000 byte(s) ({{.*}}%) in 17 allocation(s)
+// CHECK: 672000 byte(s) ({{.*}}%) in 28 allocation(s)
+// CHECK: Live Heap Allocations: {{.*}}; showing top 50%
+// CHECK: 2227000 byte(s) ({{.*}}%) in 17 allocation(s)
+// CHECK-NOT: 1008 byte
diff --git a/test/asan/TestCases/Linux/ptrace.cc b/test/asan/TestCases/Linux/ptrace.cc
index d87d90be4753..bd3d2d27e1de 100644
--- a/test/asan/TestCases/Linux/ptrace.cc
+++ b/test/asan/TestCases/Linux/ptrace.cc
@@ -59,6 +59,13 @@ typedef char fpregs_struct[ARM_VFPREGS_SIZE];
#define PRINT_REG_PC(__regs) printf ("%x\n", (unsigned) (__regs.ARM_pc))
#define PRINT_REG_FP(__fpregs) printf ("%x\n", (unsigned) (__fpregs + 32 * 8))
#define __PTRACE_FPREQUEST PTRACE_GETVFPREGS
+
+#elif defined(__s390__)
+typedef _user_regs_struct regs_struct;
+typedef _user_fpregs_struct fpregs_struct;
+#define PRINT_REG_PC(__regs) printf ("%lx\n", (unsigned long) (__regs.psw.addr))
+#define PRINT_REG_FP(__fpregs) printf ("%lx\n", (unsigned long) (__fpregs.fpc))
+#define ARCH_IOVEC_FOR_GETREGSET
#endif
diff --git a/test/asan/TestCases/Linux/recvfrom.cc b/test/asan/TestCases/Linux/recvfrom.cc
new file mode 100644
index 000000000000..9c6eec35c957
--- /dev/null
+++ b/test/asan/TestCases/Linux/recvfrom.cc
@@ -0,0 +1,81 @@
+// Test that ASan detects buffer overflow on read from socket via recvfrom.
+//
+// RUN: %clangxx_asan %s -DRECVFROM -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-RECVFROM
+// RUN: %clangxx_asan %s -DSENDTO -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-SENDTO
+// RUN: %clangxx_asan %s -DSENDTO -o %t && %env_asan_opts=intercept_send=0 %run %t 2>&1
+//
+// UNSUPPORTED: android
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <netdb.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <pthread.h>
+
+#define CHECK_ERROR(p, m) \
+ do { \
+ if (p) { \
+ fprintf(stderr, "ERROR " m "\n"); \
+ exit(1); \
+ } \
+ } while (0)
+
+const int kBufSize = 10;
+int sockfd;
+
+static void *client_thread_udp(void *data) {
+#ifdef SENDTO
+ const char buf[kBufSize / 2] = {0, };
+#else
+ const char buf[kBufSize] = {0, };
+#endif
+ struct sockaddr_in serveraddr;
+ socklen_t addrlen = sizeof(serveraddr);
+
+ int succeeded = getsockname(sockfd, (struct sockaddr *)&serveraddr, &addrlen);
+ CHECK_ERROR(succeeded < 0, "in getsockname");
+
+ succeeded = sendto(sockfd, buf, kBufSize, 0, (struct sockaddr *)&serveraddr,
+ sizeof(serveraddr));
+ // CHECK-SENDTO: {{READ of size 10 at 0x.* thread T1}}
+ // CHECK-SENDTO: {{ #1 0x.* in client_thread_udp.*recvfrom.cc:}}[[@LINE-3]]
+ CHECK_ERROR(succeeded < 0, "in sending message");
+ return NULL;
+}
+
+int main() {
+#ifdef RECVFROM
+ char buf[kBufSize / 2];
+#else
+ char buf[kBufSize];
+#endif
+ pthread_t client_thread;
+ struct sockaddr_in serveraddr;
+
+ sockfd = socket(AF_INET, SOCK_DGRAM, 0);
+ CHECK_ERROR(sockfd < 0, "opening socket");
+
+ memset(&serveraddr, 0, sizeof(serveraddr));
+ serveraddr.sin_family = AF_INET;
+ serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
+ serveraddr.sin_port = 0;
+
+ int bound = bind(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));
+ CHECK_ERROR(bound < 0, "on binding");
+
+ int succeeded =
+ pthread_create(&client_thread, NULL, client_thread_udp, &serveraddr);
+ CHECK_ERROR(succeeded, "creating thread");
+
+ recvfrom(sockfd, buf, kBufSize, 0, NULL, NULL); // BOOM
+ // CHECK-RECVFROM: {{WRITE of size 10 at 0x.* thread T0}}
+ // CHECK-RECVFROM: {{ #1 0x.* in main.*recvfrom.cc:}}[[@LINE-2]]
+ // CHECK-RECVFROM: {{Address 0x.* is located in stack of thread T0 at offset}}
+ // CHECK-RECVFROM-NEXT: in{{.*}}main{{.*}}recvfrom.cc
+ succeeded = pthread_join(client_thread, NULL);
+ CHECK_ERROR(succeeded, "joining thread");
+ return 0;
+}
diff --git a/test/asan/TestCases/Linux/scariness_score_test.cc b/test/asan/TestCases/Linux/scariness_score_test.cc
new file mode 100644
index 000000000000..24854132f539
--- /dev/null
+++ b/test/asan/TestCases/Linux/scariness_score_test.cc
@@ -0,0 +1,192 @@
+// Test how we produce the scariness score.
+
+// RUN: %clangxx_asan -O0 %s -o %t
+// RUN: export %env_asan_opts=detect_stack_use_after_return=1:handle_abort=1:print_scariness=1
+// Make sure the stack is limited (may not be the default under GNU make)
+// RUN: ulimit -s 4096
+// RUN: not %run %t 1 2>&1 | FileCheck %s --check-prefix=CHECK1
+// RUN: not %run %t 2 2>&1 | FileCheck %s --check-prefix=CHECK2
+// RUN: not %run %t 3 2>&1 | FileCheck %s --check-prefix=CHECK3
+// RUN: not %run %t 4 2>&1 | FileCheck %s --check-prefix=CHECK4
+// RUN: not %run %t 5 2>&1 | FileCheck %s --check-prefix=CHECK5
+// RUN: not %run %t 6 2>&1 | FileCheck %s --check-prefix=CHECK6
+// RUN: not %run %t 7 2>&1 | FileCheck %s --check-prefix=CHECK7
+// RUN: not %run %t 8 2>&1 | FileCheck %s --check-prefix=CHECK8
+// RUN: not %run %t 9 2>&1 | FileCheck %s --check-prefix=CHECK9
+// RUN: not %run %t 10 2>&1 | FileCheck %s --check-prefix=CHECK10
+// RUN: not %run %t 11 2>&1 | FileCheck %s --check-prefix=CHECK11
+// RUN: not %run %t 12 2>&1 | FileCheck %s --check-prefix=CHECK12
+// RUN: not %run %t 13 2>&1 | FileCheck %s --check-prefix=CHECK13
+// RUN: not %run %t 14 2>&1 | FileCheck %s --check-prefix=CHECK14
+// RUN: not %run %t 15 2>&1 | FileCheck %s --check-prefix=CHECK15
+// RUN: not %run %t 16 2>&1 | FileCheck %s --check-prefix=CHECK16
+// RUN: not %run %t 17 2>&1 | FileCheck %s --check-prefix=CHECK17
+// RUN: not %run %t 18 2>&1 | FileCheck %s --check-prefix=CHECK18
+// RUN: not %run %t 19 2>&1 | FileCheck %s --check-prefix=CHECK19
+// RUN: not %run %t 20 2>&1 | FileCheck %s --check-prefix=CHECK20
+// RUN: not %run %t 21 2>&1 | FileCheck %s --check-prefix=CHECK21
+// RUN: not %run %t 22 2>&1 | FileCheck %s --check-prefix=CHECK22
+// RUN: not %run %t 23 2>&1 | FileCheck %s --check-prefix=CHECK23
+// RUN: not %run %t 24 2>&1 | FileCheck %s --check-prefix=CHECK24
+// RUN: not %run %t 25 2>&1 | FileCheck %s --check-prefix=CHECK25
+// RUN: not %run %t 26 2>&1 | FileCheck %s --check-prefix=CHECK26
+// RUN: not %run %t 27 2>&1 | FileCheck %s --check-prefix=CHECK27
+// Parts of the test are too platform-specific:
+// REQUIRES: x86_64-target-arch
+// REQUIRES: shell
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <sanitizer/asan_interface.h>
+
+enum ReadOrWrite { Read = 0, Write = 1 };
+
+struct S32 {
+ char x[32];
+};
+
+template<class T>
+void HeapBuferOverflow(int Idx, ReadOrWrite w) {
+ T *t = new T[100];
+ static T sink;
+ if (w)
+ t[100 + Idx] = T();
+ else
+ sink = t[100 + Idx];
+ delete [] t;
+}
+
+template<class T>
+void HeapUseAfterFree(int Idx, ReadOrWrite w) {
+ T *t = new T[100];
+ static T sink;
+ sink = t[0];
+ delete [] t;
+ if (w)
+ t[Idx] = T();
+ else
+ sink = t[Idx];
+}
+
+template<class T>
+void StackBufferOverflow(int Idx, ReadOrWrite w) {
+ T t[100];
+ static T sink;
+ sink = t[Idx];
+ if (w)
+ t[100 + Idx] = T();
+ else
+ sink = t[100 + Idx];
+}
+
+template<class T>
+T *LeakStack() {
+ T t[100];
+ static volatile T *x;
+ x = &t[0];
+ return (T*)x;
+}
+
+template<class T>
+void StackUseAfterReturn(int Idx, ReadOrWrite w) {
+ static T sink;
+ T *t = LeakStack<T>();
+ if (w)
+ t[100 + Idx] = T();
+ else
+ sink = t[100 + Idx];
+}
+
+char g1[100];
+short g2[100];
+int g4[100];
+int64_t g8[100];
+S32 gm[100];
+
+void DoubleFree() {
+ int *x = new int;
+ static volatile int two = 2;
+ for (int i = 0; i < two; i++)
+ delete x;
+}
+
+void StackOverflow(int Idx) {
+ int some_stack[10000];
+ static volatile int *x;
+ x = &some_stack[0];
+ if (Idx > 0)
+ StackOverflow(Idx - 1);
+}
+
+void UseAfterPoison() {
+ int buf[100];
+ __asan_poison_memory_region(buf, sizeof(buf));
+ static volatile int sink;
+ sink = buf[42];
+}
+
+int main(int argc, char **argv) {
+ char arr[100];
+ static volatile int zero = 0;
+ static volatile int *zero_ptr = 0;
+ static volatile int *wild_addr = (int*)0x10000000; // System-dependent.
+ if (argc != 2) return 1;
+ int kind = atoi(argv[1]);
+ switch (kind) {
+ case 1: HeapBuferOverflow<char>(0, Read); break;
+ case 2: HeapBuferOverflow<int>(0, Read); break;
+ case 3: HeapBuferOverflow<short>(0, Write); break;
+ case 4: HeapBuferOverflow<int64_t>(2, Write); break;
+ case 5: HeapBuferOverflow<S32>(4, Write); break;
+ case 6: HeapUseAfterFree<char>(0, Read); break;
+ case 7: HeapUseAfterFree<int>(0, Write); break;
+ case 8: HeapUseAfterFree<int64_t>(0, Read); break;
+ case 9: HeapUseAfterFree<S32>(0, Write); break;
+ case 10: StackBufferOverflow<char>(0, Write); break;
+ case 11: StackBufferOverflow<int64_t>(0, Read); break;
+ case 12: StackBufferOverflow<int>(4, Write); break;
+ case 13: StackUseAfterReturn<char>(0, Read); break;
+ case 14: StackUseAfterReturn<S32>(0, Write); break;
+ case 15: g1[zero + 100] = 0; break;
+ case 16: gm[0] = gm[zero + 100 + 1]; break;
+ case 17: DoubleFree(); break;
+ case 18: StackOverflow(1000000); break;
+ case 19: *zero_ptr = 0; break;
+ case 20: *wild_addr = 0; break;
+ case 21: zero = *wild_addr; break;
+ case 22: abort(); break;
+ case 23: ((void (*)(void))wild_addr)(); break;
+ case 24: delete (new int[10]); break;
+ case 25: free((char*)malloc(100) + 10); break;
+ case 26: memcpy(arr, arr+10, 20); break;
+ case 27: UseAfterPoison(); break;
+ // CHECK1: SCARINESS: 12 (1-byte-read-heap-buffer-overflow)
+ // CHECK2: SCARINESS: 17 (4-byte-read-heap-buffer-overflow)
+ // CHECK3: SCARINESS: 33 (2-byte-write-heap-buffer-overflow)
+ // CHECK4: SCARINESS: 52 (8-byte-write-heap-buffer-overflow-far-from-bounds)
+ // CHECK5: SCARINESS: 55 (multi-byte-write-heap-buffer-overflow-far-from-bounds)
+ // CHECK6: SCARINESS: 40 (1-byte-read-heap-use-after-free)
+ // CHECK7: SCARINESS: 46 (4-byte-write-heap-use-after-free)
+ // CHECK8: SCARINESS: 51 (8-byte-read-heap-use-after-free)
+ // CHECK9: SCARINESS: 55 (multi-byte-write-heap-use-after-free)
+ // CHECK10: SCARINESS: 46 (1-byte-write-stack-buffer-overflow)
+ // CHECK11: SCARINESS: 38 (8-byte-read-stack-buffer-overflow)
+ // CHECK12: SCARINESS: 61 (4-byte-write-stack-buffer-overflow-far-from-bounds)
+ // CHECK13: SCARINESS: 50 (1-byte-read-stack-use-after-return)
+ // CHECK14: SCARINESS: 65 (multi-byte-write-stack-use-after-return)
+ // CHECK15: SCARINESS: 31 (1-byte-write-global-buffer-overflow)
+ // CHECK16: SCARINESS: 36 (multi-byte-read-global-buffer-overflow-far-from-bounds)
+ // CHECK17: SCARINESS: 42 (double-free)
+ // CHECK18: SCARINESS: 10 (stack-overflow)
+ // CHECK19: SCARINESS: 10 (null-deref)
+ // CHECK20: SCARINESS: 30 (wild-addr-write)
+ // CHECK21: SCARINESS: 20 (wild-addr-read)
+ // CHECK22: SCARINESS: 10 (signal)
+ // CHECK23: SCARINESS: 60 (wild-jump)
+ // CHECK24: SCARINESS: 10 (alloc-dealloc-mismatch)
+ // CHECK25: SCARINESS: 40 (bad-free)
+ // CHECK26: SCARINESS: 10 (memcpy-param-overlap)
+ // CHECK27: SCARINESS: 27 (4-byte-read-use-after-poison)
+ }
+}
diff --git a/test/asan/TestCases/Linux/segv_read_write.c b/test/asan/TestCases/Linux/segv_read_write.c
new file mode 100644
index 000000000000..b1379703ed86
--- /dev/null
+++ b/test/asan/TestCases/Linux/segv_read_write.c
@@ -0,0 +1,26 @@
+// RUN: %clangxx_asan -std=c++11 -O0 %s -o %t
+// RUN: not %run %t 2>&1 | FileCheck %s --check-prefix=READ
+// RUN: not %run %t write 2>&1 | FileCheck %s --check-prefix=WRITE
+// UNSUPPORTED: powerpc64,mips,s390
+
+#include <sys/mman.h>
+
+static volatile int sink;
+__attribute__((noinline)) void Read(int *ptr) { sink = *ptr; }
+__attribute__((noinline)) void Write(int *ptr) { *ptr = 0; }
+int main(int argc, char **argv) {
+ // Writes to shadow are detected as reads from shadow gap (because of how the
+ // shadow mapping works). This is kinda hard to fix. Test a random address in
+ // the application part of the address space.
+ void *volatile p =
+ mmap(nullptr, 4096, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
+ munmap(p, 4096);
+ if (argc == 1)
+ Read((int *)p);
+ else
+ Write((int *)p);
+}
+// READ: AddressSanitizer: SEGV on unknown address
+// READ: The signal is caused by a READ memory access.
+// WRITE: AddressSanitizer: SEGV on unknown address
+// WRITE: The signal is caused by a WRITE memory access.
diff --git a/test/asan/TestCases/Linux/stack-overflow-recovery-mode.cc b/test/asan/TestCases/Linux/stack-overflow-recovery-mode.cc
new file mode 100644
index 000000000000..e99665953784
--- /dev/null
+++ b/test/asan/TestCases/Linux/stack-overflow-recovery-mode.cc
@@ -0,0 +1,36 @@
+// Test that ASan doesn't hang on stack overflow in recovery mode.
+//
+// RUN: %clang_asan -O0 -fsanitize-recover=address %s -o %t
+// RUN: %env_asan_opts=halt_on_error=false not %run %t 2>&1 | FileCheck %s
+
+#include <assert.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/resource.h>
+
+static volatile int *recurse(volatile int n, volatile int *p) {
+ // CHECK: {{stack-overflow on address 0x.* \(pc 0x.* bp 0x.* sp 0x.* T.*\)}}
+ if (n >= 0) *recurse(n + 1, p) += n;
+ return p;
+}
+
+
+void LimitStackAndReexec(int argc, char **argv) {
+ struct rlimit rlim;
+ int res = getrlimit(RLIMIT_STACK, &rlim);
+ assert(res == 0);
+ if (rlim.rlim_cur == RLIM_INFINITY) {
+ rlim.rlim_cur = 256 * 1024;
+ res = setrlimit(RLIMIT_STACK, &rlim);
+ assert(res == 0);
+
+ execv(argv[0], argv);
+ assert(0 && "unreachable");
+ }
+}
+
+int main(int argc, char **argv) {
+ LimitStackAndReexec(argc, argv);
+ volatile int res;
+ return *recurse(argc + 1, &res);
+}
diff --git a/test/asan/TestCases/Linux/static_tls.cc b/test/asan/TestCases/Linux/static_tls.cc
index 11bb1a4f849c..5e569ddabd32 100644
--- a/test/asan/TestCases/Linux/static_tls.cc
+++ b/test/asan/TestCases/Linux/static_tls.cc
@@ -10,6 +10,8 @@
// CHECK: after
// XFAIL: aarch64
+// binutils 2.26 has a change that causes this test to fail on powerpc64.
+// UNSUPPORTED: powerpc64
#ifndef SHARED
#include <stdio.h>
diff --git a/test/asan/TestCases/Linux/swapcontext_annotation.cc b/test/asan/TestCases/Linux/swapcontext_annotation.cc
new file mode 100644
index 000000000000..90aabaee205b
--- /dev/null
+++ b/test/asan/TestCases/Linux/swapcontext_annotation.cc
@@ -0,0 +1,178 @@
+// Check that ASan plays well with annotated makecontext/swapcontext.
+
+// RUN: %clangxx_asan -lpthread -O0 %s -o %t && %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -lpthread -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -lpthread -O2 %s -o %t && %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -lpthread -O3 %s -o %t && %run %t 2>&1 | FileCheck %s
+//
+// This test is too subtle to try on non-x86 arch for now.
+// REQUIRES: x86_64-supported-target,i386-supported-target
+
+#include <pthread.h>
+#include <setjmp.h>
+#include <stdio.h>
+#include <sys/time.h>
+#include <ucontext.h>
+#include <unistd.h>
+
+#include <sanitizer/common_interface_defs.h>
+
+ucontext_t orig_context;
+ucontext_t child_context;
+ucontext_t next_child_context;
+
+char *next_child_stack;
+
+const int kStackSize = 1 << 20;
+
+void *main_thread_stack;
+size_t main_thread_stacksize;
+
+__attribute__((noinline, noreturn)) void LongJump(jmp_buf env) {
+ longjmp(env, 1);
+ _exit(1);
+}
+
+// Simulate __asan_handle_no_return().
+__attribute__((noinline)) void CallNoReturn() {
+ jmp_buf env;
+ if (setjmp(env) != 0) return;
+
+ LongJump(env);
+ _exit(1);
+}
+
+void NextChild() {
+ CallNoReturn();
+ __sanitizer_finish_switch_fiber();
+
+ char x[32] = {0}; // Stack gets poisoned.
+ printf("NextChild: %p\n", x);
+
+ CallNoReturn();
+
+ __sanitizer_start_switch_fiber(main_thread_stack, main_thread_stacksize);
+ CallNoReturn();
+ if (swapcontext(&next_child_context, &orig_context) < 0) {
+ perror("swapcontext");
+ _exit(1);
+ }
+}
+
+void Child(int mode) {
+ CallNoReturn();
+ __sanitizer_finish_switch_fiber();
+ char x[32] = {0}; // Stack gets poisoned.
+ printf("Child: %p\n", x);
+ CallNoReturn();
+ // (a) Do nothing, just return to parent function.
+ // (b) Jump into the original function. Stack remains poisoned unless we do
+ // something.
+ // (c) Jump to another function which will then jump back to the main function
+ if (mode == 0) {
+ __sanitizer_start_switch_fiber(main_thread_stack, main_thread_stacksize);
+ CallNoReturn();
+ } else if (mode == 1) {
+ __sanitizer_start_switch_fiber(main_thread_stack, main_thread_stacksize);
+ CallNoReturn();
+ if (swapcontext(&child_context, &orig_context) < 0) {
+ perror("swapcontext");
+ _exit(1);
+ }
+ } else if (mode == 2) {
+ getcontext(&next_child_context);
+ next_child_context.uc_stack.ss_sp = next_child_stack;
+ next_child_context.uc_stack.ss_size = kStackSize / 2;
+ makecontext(&next_child_context, (void (*)())NextChild, 0);
+ __sanitizer_start_switch_fiber(next_child_context.uc_stack.ss_sp,
+ next_child_context.uc_stack.ss_size);
+ CallNoReturn();
+ if (swapcontext(&child_context, &next_child_context) < 0) {
+ perror("swapcontext");
+ _exit(1);
+ }
+ }
+}
+
+int Run(int arg, int mode, char *child_stack) {
+ printf("Child stack: %p\n", child_stack);
+ // Setup child context.
+ getcontext(&child_context);
+ child_context.uc_stack.ss_sp = child_stack;
+ child_context.uc_stack.ss_size = kStackSize / 2;
+ if (mode == 0) {
+ child_context.uc_link = &orig_context;
+ }
+ makecontext(&child_context, (void (*)())Child, 1, mode);
+ CallNoReturn();
+ __sanitizer_start_switch_fiber(child_context.uc_stack.ss_sp,
+ child_context.uc_stack.ss_size);
+ CallNoReturn();
+ if (swapcontext(&orig_context, &child_context) < 0) {
+ perror("swapcontext");
+ _exit(1);
+ }
+ CallNoReturn();
+ __sanitizer_finish_switch_fiber();
+ CallNoReturn();
+
+ // Touch childs's stack to make sure it's unpoisoned.
+ for (int i = 0; i < kStackSize; i++) {
+ child_stack[i] = i;
+ }
+ return child_stack[arg];
+}
+
+void handler(int sig) { CallNoReturn(); }
+
+void InitStackBounds() {
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_getattr_np(pthread_self(), &attr);
+ pthread_attr_getstack(&attr, &main_thread_stack, &main_thread_stacksize);
+ pthread_attr_destroy(&attr);
+}
+
+int main(int argc, char **argv) {
+ InitStackBounds();
+
+ // set up a signal that will spam and trigger __asan_handle_no_return at
+ // tricky moments
+ struct sigaction act = {};
+ act.sa_handler = &handler;
+ if (sigaction(SIGPROF, &act, 0)) {
+ perror("sigaction");
+ _exit(1);
+ }
+
+ itimerval t;
+ t.it_interval.tv_sec = 0;
+ t.it_interval.tv_usec = 10;
+ t.it_value = t.it_interval;
+ if (setitimer(ITIMER_PROF, &t, 0)) {
+ perror("setitimer");
+ _exit(1);
+ }
+
+ char *heap = new char[kStackSize + 1];
+ next_child_stack = new char[kStackSize + 1];
+ char stack[kStackSize + 1];
+ // CHECK: WARNING: ASan doesn't fully support makecontext/swapcontext
+ int ret = 0;
+ // CHECK-NOT: ASan is ignoring requested __asan_handle_no_return
+ for (unsigned int i = 0; i < 30; ++i) {
+ ret += Run(argc - 1, 0, stack);
+ ret += Run(argc - 1, 1, stack);
+ ret += Run(argc - 1, 2, stack);
+ ret += Run(argc - 1, 0, heap);
+ ret += Run(argc - 1, 1, heap);
+ ret += Run(argc - 1, 2, heap);
+ }
+ // CHECK: Test passed
+ printf("Test passed\n");
+
+ delete[] heap;
+ delete[] next_child_stack;
+
+ return ret;
+}
diff --git a/test/asan/TestCases/Linux/swapcontext_test.cc b/test/asan/TestCases/Linux/swapcontext_test.cc
index 86ed5930bcf4..210a667d096a 100644
--- a/test/asan/TestCases/Linux/swapcontext_test.cc
+++ b/test/asan/TestCases/Linux/swapcontext_test.cc
@@ -6,7 +6,7 @@
// RUN: %clangxx_asan -O3 %s -o %t && %run %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
+// REQUIRES: x86-target-arch
#include <stdio.h>
#include <ucontext.h>
diff --git a/test/asan/TestCases/Linux/unpoison_tls.cc b/test/asan/TestCases/Linux/unpoison_tls.cc
index 9c1d74b28e5f..19ebec467c6c 100644
--- a/test/asan/TestCases/Linux/unpoison_tls.cc
+++ b/test/asan/TestCases/Linux/unpoison_tls.cc
@@ -1,5 +1,5 @@
// Test that TLS is unpoisoned on thread death.
-// REQUIRES: x86_64-supported-target,i386-supported-target
+// REQUIRES: x86-target-arch
// RUN: %clangxx_asan -O1 %s -pthread -o %t && %run %t 2>&1
diff --git a/test/asan/TestCases/Posix/closed-fds.cc b/test/asan/TestCases/Posix/closed-fds.cc
index 3bbe3d8e68e1..b7bca26c305d 100644
--- a/test/asan/TestCases/Posix/closed-fds.cc
+++ b/test/asan/TestCases/Posix/closed-fds.cc
@@ -2,7 +2,7 @@
// symbolizer still works.
// RUN: rm -f %t.log.*
-// RUN: %clangxx_asan -O0 %s -o %t 2>&1 && %env_asan_opts=log_path=%t.log:verbosity=2 not %run %t 2>&1
+// RUN: %clangxx_asan -O0 %s -o %t 2>&1 && %env_asan_opts=log_path='"%t.log"':verbosity=2 not %run %t 2>&1
// RUN: FileCheck %s --check-prefix=CHECK-FILE < %t.log.*
// FIXME: copy %t.log back from the device and re-enable on Android.
diff --git a/test/asan/TestCases/Posix/coverage-sandboxing.cc b/test/asan/TestCases/Posix/coverage-sandboxing.cc
index f6fc5266607c..c4e6bc7eef8a 100644
--- a/test/asan/TestCases/Posix/coverage-sandboxing.cc
+++ b/test/asan/TestCases/Posix/coverage-sandboxing.cc
@@ -79,8 +79,8 @@ int main(int argc, char **argv) {
#endif
// CHECK-vanilla: PID: [[PID:[0-9]+]]
-// CHECK-vanilla: .so.[[PID]].sancov: 258 PCs written
+// CHECK-vanilla: .so.[[PID]].sancov: 257 PCs written
// CHECK-vanilla: [[PID]].sancov: 1 PCs written
// CHECK-sandbox: PID: [[PID:[0-9]+]]
-// CHECK-sandbox: 258 PCs written to packed file
+// CHECK-sandbox: 257 PCs written to packed file
diff --git a/test/asan/TestCases/Posix/dlclose-test.cc b/test/asan/TestCases/Posix/dlclose-test.cc
index 369abd3127cc..0aafa3e79f6b 100644
--- a/test/asan/TestCases/Posix/dlclose-test.cc
+++ b/test/asan/TestCases/Posix/dlclose-test.cc
@@ -11,8 +11,8 @@
// This sublte test assumes that after a foo.so is dlclose-d
// we can mmap the region of memory that has been occupied by the library.
-// It works on i368/x86_64 Linux, but not necessary anywhere else.
-// REQUIRES: x86_64-supported-target,i386-supported-target
+// It works on x86 Linux, but not necessary anywhere else.
+// REQUIRES: x86-target-arch
// RUN: %clangxx_asan -O0 -DSHARED_LIB %s -fPIC -shared -o %t-so.so
// RUN: %clangxx_asan -O0 %s %libdl -o %t && %run %t 2>&1 | FileCheck %s
diff --git a/test/asan/TestCases/dump_instruction_bytes.cc b/test/asan/TestCases/Posix/dump_instruction_bytes.cc
index da86a0f9aa48..b5b38ff08191 100644
--- a/test/asan/TestCases/dump_instruction_bytes.cc
+++ b/test/asan/TestCases/Posix/dump_instruction_bytes.cc
@@ -4,7 +4,7 @@
// RUN: %env_asan_opts=dump_instruction_bytes=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-DUMP
// RUN: not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-NODUMP
//
-// REQUIRES: x86_64-supported-target,i386-supported-target
+// REQUIRES: x86-target-arch
int main() {
#if defined(__x86_64__)
diff --git a/test/asan/TestCases/Posix/global-registration.c b/test/asan/TestCases/Posix/global-registration.c
new file mode 100644
index 000000000000..62009b36cb7e
--- /dev/null
+++ b/test/asan/TestCases/Posix/global-registration.c
@@ -0,0 +1,69 @@
+// Test that globals from different shared objects all get registered.
+
+// This source file is compiled into three different source object files. Each
+// object file declares a global buffer. The first two are linked together, and
+// the third is loaded at runtime. We make sure that out-of-bounds accesses
+// are caught for all three buffers.
+
+// RUN: %clang_asan -c -o %t-one.o -DMAIN_FILE %s
+// RUN: %clang_asan -c -o %t-two.o -DSECONDARY_FILE %s
+// RUN: %clang_asan -o %t %t-one.o %t-two.o %libdl
+// RUN: %clang_asan -o %t-dynamic.so -shared -fPIC -DSHARED_LIBRARY_FILE %s
+// RUN: not %run %t 1 2>&1 | FileCheck --check-prefix ASAN-CHECK-1 %s
+// RUN: not %run %t 2 2>&1 | FileCheck --check-prefix ASAN-CHECK-2 %s
+// RUN: not %run %t 3 2>&1 | FileCheck --check-prefix ASAN-CHECK-3 %s
+
+#if MAIN_FILE
+
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+extern char buffer1[1];
+extern char buffer2[1];
+char buffer1[1] = { 0 };
+
+int main(int argc, char *argv[]) {
+ int n = atoi(argv[1]);
+ if (n == 1) {
+ buffer1[argc] = 0;
+ // ASAN-CHECK-1: {{0x.* is located 1 bytes .* 'buffer1'}}
+ } else if (n == 2) {
+ buffer2[argc] = 0;
+ // ASAN-CHECK-2: {{0x.* is located 1 bytes .* 'buffer2'}}
+ } else if (n == 3) {
+ char *libsuffix = "-dynamic.so";
+ char *libpath = malloc(strlen(argv[0]) + strlen(libsuffix) + 1);
+ sprintf(libpath, "%s%s", argv[0], libsuffix);
+
+ void *handle = dlopen(libpath, RTLD_NOW);
+ if (!handle) {
+ fprintf(stderr, "dlopen: %s\n", dlerror());
+ return 1;
+ }
+
+ char *buffer = (char *)dlsym(handle, "buffer3");
+ if (!buffer) {
+ fprintf(stderr, "dlsym: %s\n", dlerror());
+ return 1;
+ }
+
+ buffer[argc] = 0;
+ // ASAN-CHECK-3: {{0x.* is located 1 bytes .* 'buffer3'}}
+ }
+
+ return 0;
+}
+
+#elif SECONDARY_FILE
+
+extern char buffer2[1];
+char buffer2[1] = { 0 };
+
+#elif SHARED_LIBRARY_FILE
+
+extern char buffer3[1];
+char buffer3[1] = { 0 };
+
+#endif
diff --git a/test/asan/TestCases/Posix/halt_on_error-torture.cc b/test/asan/TestCases/Posix/halt_on_error-torture.cc
index 019f7d126a47..d3af1d027703 100644
--- a/test/asan/TestCases/Posix/halt_on_error-torture.cc
+++ b/test/asan/TestCases/Posix/halt_on_error-torture.cc
@@ -9,15 +9,11 @@
//
// Collisions are unlikely but still possible so we need the ||.
// RUN: %env_asan_opts=halt_on_error=false:suppress_equal_pcs=false %run %t 10 20 >10.txt 2>&1 || true
-// This one is racy although _very_ unlikely to fail:
-// RUN: FileCheck %s < 10.txt
-// RUN: FileCheck --check-prefix=CHECK-COLLISION %s < 1.txt || FileCheck --check-prefix=CHECK-NO-COLLISION %s < 1.txt
+// RUN: FileCheck --check-prefix=CHECK-COLLISION %s < 10.txt || FileCheck --check-prefix=CHECK-NO-COLLISION %s < 10.txt
//
// Collisions are unlikely but still possible so we need the ||.
// RUN: %env_asan_opts=halt_on_error=false %run %t 10 20 >10.txt 2>&1 || true
-// This one is racy although _very_ unlikely to fail:
-// RUN: FileCheck %s < 10.txt
-// RUN: FileCheck --check-prefix=CHECK-COLLISION %s < 1.txt || FileCheck --check-prefix=CHECK-NO-COLLISION %s < 1.txt
+// RUN: FileCheck --check-prefix=CHECK-COLLISION %s < 10.txt || FileCheck --check-prefix=CHECK-NO-COLLISION %s < 10.txt
#include <stdio.h>
#include <stdlib.h>
diff --git a/test/asan/TestCases/mmap_limit_mb.cc b/test/asan/TestCases/Posix/mmap_limit_mb.cc
index 379524121a88..379524121a88 100644
--- a/test/asan/TestCases/mmap_limit_mb.cc
+++ b/test/asan/TestCases/Posix/mmap_limit_mb.cc
diff --git a/test/asan/TestCases/Posix/print_cmdline.cc b/test/asan/TestCases/Posix/print_cmdline.cc
new file mode 100644
index 000000000000..8c83bd97e0ce
--- /dev/null
+++ b/test/asan/TestCases/Posix/print_cmdline.cc
@@ -0,0 +1,18 @@
+// Check that ASan can print reproducer cmdline for failed binary if desired.
+//
+// RUN: %clang_asan %s -o %t-exe
+//
+// RUN: env not %run %t-exe 2>&1 | FileCheck %s
+// RUN: %env_asan_opts=print_cmdline=false not %run %t-exe 2>&1 | FileCheck %s
+// RUN: %env_asan_opts=print_cmdline=true not %run %t-exe first second/third [fourth] 2>&1 | FileCheck %s --check-prefix CHECK-PRINT
+
+volatile int ten = 10;
+
+int main() {
+ char x[10];
+ // CHECK-NOT: Command:
+ // CHECK-PRINT: {{Command: .*-exe first second/third \[fourth\]}}
+ x[ten] = 1; // BOOM
+ return 0;
+}
+
diff --git a/test/asan/TestCases/Posix/start-deactivated.cc b/test/asan/TestCases/Posix/start-deactivated.cc
index b30141549014..187ee5e549ef 100644
--- a/test/asan/TestCases/Posix/start-deactivated.cc
+++ b/test/asan/TestCases/Posix/start-deactivated.cc
@@ -6,7 +6,7 @@
// RUN: %clangxx -O0 %s -c -o %t.o
// RUN: %clangxx_asan -O0 %t.o %libdl -o %t
// RUN: %env_asan_opts=start_deactivated=1,allocator_may_return_null=0 \
-// RUN: ASAN_ACTIVATION_OPTIONS=allocator_may_return_null=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK
+// RUN: ASAN_ACTIVATION_OPTIONS=allocator_may_return_null=1 not %run %t 2>&1 | FileCheck %s
// RUN: %env_asan_opts=start_deactivated=1 \
// RUN: ASAN_ACTIVATION_OPTIONS=help=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-HELP
// RUN: %env_asan_opts=start_deactivated=1,verbosity=1 \
diff --git a/test/asan/TestCases/Windows/bind_io_completion_callback.cc b/test/asan/TestCases/Windows/bind_io_completion_callback.cc
index c062a799fdcc..44b92ab91465 100644
--- a/test/asan/TestCases/Windows/bind_io_completion_callback.cc
+++ b/test/asan/TestCases/Windows/bind_io_completion_callback.cc
@@ -6,8 +6,7 @@
// the rest is built with Clang. This represents the typical scenario when we
// build a large project using "clang-cl -fallback -fsanitize=address".
//
-// RUN: cl -c %s -Fo%t.obj
-// RUN: %clangxx_asan -o %t.exe %s %t.obj
+// RUN: %clangxx_asan %s -o %t.exe
// RUN: %run %t.exe 2>&1 | FileCheck %s
#include <windows.h>
@@ -15,7 +14,6 @@
void ThrowAndCatch();
-#if !defined(__clang__)
__declspec(noinline)
void Throw() {
fprintf(stderr, "Throw\n");
@@ -32,7 +30,6 @@ void ThrowAndCatch() {
// CHECK: Catch
}
}
-#else
char buffer[65536];
HANDLE done;
@@ -62,9 +59,8 @@ int main(int argc, char **argv) {
GetLastError() != ERROR_IO_PENDING)
return 4;
- if (WAIT_OBJECT_0 != WaitForSingleObject(done, INFINITE))
+ if (WAIT_OBJECT_0 != WaitForSingleObject(done, 10 * 1000))
return 5;
fprintf(stderr, "Done!\n");
// CHECK: Done!
}
-#endif
diff --git a/test/asan/TestCases/Windows/coverage-basic.cc b/test/asan/TestCases/Windows/coverage-basic.cc
index 0ff105d1624e..918872f18f91 100644
--- a/test/asan/TestCases/Windows/coverage-basic.cc
+++ b/test/asan/TestCases/Windows/coverage-basic.cc
@@ -6,8 +6,8 @@
// RUN: %sancov print *.sancov | FileCheck %s
#include <stdio.h>
-void foo() { fprintf(stderr, "FOO\n"); }
-void bar() { fprintf(stderr, "BAR\n"); }
+void foo() { fputs("FOO", stderr); }
+void bar() { fputs("BAR", stderr); }
int main(int argc, char **argv) {
if (argc == 2) {
diff --git a/test/asan/TestCases/Windows/crash_read_write.cc b/test/asan/TestCases/Windows/crash_read_write.cc
new file mode 100644
index 000000000000..74200cca1521
--- /dev/null
+++ b/test/asan/TestCases/Windows/crash_read_write.cc
@@ -0,0 +1,29 @@
+// RUN: %clangxx_asan -std=c++11 -O0 %s -o %t
+// RUN: not %run %t 2>&1 | FileCheck %s --check-prefix=READ
+// RUN: not %run %t write 2>&1 | FileCheck %s --check-prefix=WRITE
+
+#include <windows.h>
+#include <stdio.h>
+
+static volatile int sink;
+__attribute__((noinline)) void Read(int *ptr) { sink = *ptr; }
+__attribute__((noinline)) void Write(int *ptr) { *ptr = 0; }
+int main(int argc, char **argv) {
+ // Writes to shadow are detected as reads from shadow gap (because of how the
+ // shadow mapping works). This is kinda hard to fix. Test a random address in
+ // the application part of the address space.
+ void *volatile p = VirtualAlloc(0, 4096, MEM_COMMIT, PAGE_READONLY);
+ bool ok = VirtualFree(p, 0, MEM_RELEASE);
+ if (!ok) {
+ printf("VirtualFree failed\n");
+ return 0;
+ }
+ if (argc == 1)
+ Read((int *)p);
+ else
+ Write((int *)p);
+}
+// READ: AddressSanitizer: access-violation on unknown address
+// READ: The signal is caused by a READ memory access.
+// WRITE: AddressSanitizer: access-violation on unknown address
+// WRITE: The signal is caused by a WRITE memory access.
diff --git a/test/asan/TestCases/Windows/dll_seh.cc b/test/asan/TestCases/Windows/dll_seh.cc
index 6e4c724e504d..0962138cb52f 100644
--- a/test/asan/TestCases/Windows/dll_seh.cc
+++ b/test/asan/TestCases/Windows/dll_seh.cc
@@ -1,17 +1,10 @@
-// Clang doesn't support SEH on Windows yet, so for the time being we
-// build this program in two parts: the code with SEH is built with CL,
-// the rest is built with Clang. This represents the typical scenario when we
-// build a large project using "clang-cl -fallback -fsanitize=address".
-//
// RUN: %clang_cl_asan -O0 %p/dll_host.cc -Fe%t
//
// Check both -GS and -GS- builds:
-// RUN: cl -LD -c %s -Fo%t.obj
-// RUN: %clang_cl_asan -LD -O0 %s -Fe%t.dll %t.obj
+// RUN: %clang_cl_asan -GS -LD -O0 %s -Fe%t.dll
// RUN: %run %t %t.dll
//
-// RUN: cl -LD -GS- -c %s -Fo%t.obj
-// RUN: %clang_cl_asan -LD -O0 %s -Fe%t.dll %t.obj
+// RUN: %clang_cl_asan -GS- -LD -O0 %s -Fe%t.dll
// RUN: %run %t %t.dll
#include <windows.h>
@@ -24,7 +17,6 @@ extern "C" bool __asan_address_is_poisoned(void *p);
void ThrowAndCatch();
-#if !defined(__clang__)
__declspec(noinline)
void Throw() {
int local, zero = 0;
@@ -41,7 +33,6 @@ void ThrowAndCatch() {
fprintf(stderr, "__except: %p\n", &local);
}
}
-#else
extern "C" __declspec(dllexport)
int test_function() {
@@ -57,4 +48,3 @@ int test_function() {
assert(!__asan_address_is_poisoned(x + 32));
return 0;
}
-#endif
diff --git a/test/asan/TestCases/Windows/intercept_strdup.cc b/test/asan/TestCases/Windows/intercept_strdup.cc
index 371053480d2c..95b659ffd336 100644
--- a/test/asan/TestCases/Windows/intercept_strdup.cc
+++ b/test/asan/TestCases/Windows/intercept_strdup.cc
@@ -20,9 +20,13 @@ int main() {
// CHECK: {{#0 .* main .*}}intercept_strdup.cc:[[@LINE-3]]
// CHECK: [[ADDR]] is located 1 bytes to the left of 6-byte region
// CHECK: allocated by thread T0 here:
-// CHECK: {{#0 .* malloc }}
-// FIXME: llvm-symbolizer can't find strdup in the CRT.
-// CHECKX: {{#1 .*strdup}}
-// CHECK: {{#2 .* main .*}}intercept_strdup.cc:[[@LINE-17]]
+//
+// The first frame is our wrapper normally but will be malloc in the dynamic
+// config.
+// CHECK: #0 {{.*}} in {{malloc|__asan_wrap_strdup}}
+//
+// The local call to _strdup above may be the second or third frame depending
+// on whether we're using the dynamic config.
+// CHECK: #{{[12]}} {{.*}} in main {{.*}}intercept_strdup.cc:[[@LINE-21]]
free(ptr);
}
diff --git a/test/asan/TestCases/Windows/oom.cc b/test/asan/TestCases/Windows/oom.cc
index b24cddf17a97..3475af79e6a4 100644
--- a/test/asan/TestCases/Windows/oom.cc
+++ b/test/asan/TestCases/Windows/oom.cc
@@ -6,7 +6,6 @@
int main() {
while (true) {
void *ptr = malloc(200 * 1024 * 1024); // 200MB
- free(ptr);
}
// CHECK: failed to allocate
}
diff --git a/test/asan/TestCases/Windows/queue_user_work_item.cc b/test/asan/TestCases/Windows/queue_user_work_item.cc
index d99ea6fc2e45..2a0b622f6218 100644
--- a/test/asan/TestCases/Windows/queue_user_work_item.cc
+++ b/test/asan/TestCases/Windows/queue_user_work_item.cc
@@ -6,8 +6,7 @@
// the rest is built with Clang. This represents the typical scenario when we
// build a large project using "clang-cl -fallback -fsanitize=address".
//
-// RUN: cl -c %s -Fo%t.obj
-// RUN: %clangxx_asan -o %t.exe %s %t.obj
+// RUN: %clangxx_asan %s -o %t.exe
// RUN: %run %t.exe 2>&1 | FileCheck %s
#include <windows.h>
@@ -15,7 +14,6 @@
void ThrowAndCatch();
-#if !defined(__clang__)
__declspec(noinline)
void Throw() {
fprintf(stderr, "Throw\n");
@@ -32,7 +30,6 @@ void ThrowAndCatch() {
// CHECK: Catch
}
}
-#else
HANDLE done;
@@ -47,9 +44,13 @@ int main(int argc, char **argv) {
if (!done)
return 1;
QueueUserWorkItem(&work_item, nullptr, 0);
- if (WAIT_OBJECT_0 != WaitForSingleObject(done, INFINITE))
+ unsigned wait_result = WaitForSingleObject(done, 10 * 1000);
+ if (wait_result == WAIT_ABANDONED)
+ fprintf(stderr, "Timed out\n");
+ if (wait_result != WAIT_OBJECT_0) {
+ fprintf(stderr, "Wait for work item failed\n");
return 2;
+ }
fprintf(stderr, "Done!\n");
// CHECK: Done!
}
-#endif
diff --git a/test/asan/TestCases/Windows/queue_user_work_item_report.cc b/test/asan/TestCases/Windows/queue_user_work_item_report.cc
index f0d3d3e7cbcc..e500a919fdae 100644
--- a/test/asan/TestCases/Windows/queue_user_work_item_report.cc
+++ b/test/asan/TestCases/Windows/queue_user_work_item_report.cc
@@ -24,6 +24,6 @@ int main(int argc, char **argv) {
return 1;
// CHECK-NOT: Thread T1 created
QueueUserWorkItem(&work_item, nullptr, 0);
- if (WAIT_OBJECT_0 != WaitForSingleObject(done, INFINITE))
+ if (WAIT_OBJECT_0 != WaitForSingleObject(done, 10 * 1000))
return 2;
}
diff --git a/test/asan/TestCases/Windows/report_after_syminitialize.cc b/test/asan/TestCases/Windows/report_after_syminitialize.cc
index d83d7dc264a7..20bf69514179 100644
--- a/test/asan/TestCases/Windows/report_after_syminitialize.cc
+++ b/test/asan/TestCases/Windows/report_after_syminitialize.cc
@@ -14,8 +14,10 @@ int main() {
*(volatile int*)0 = 42;
// CHECK: ERROR: AddressSanitizer: access-violation on unknown address
+ // CHECK: The signal is caused by a WRITE memory access.
+ // CHECK: Hint: address points to the zero page.
// CHECK-NEXT: {{WARNING: Failed to use and restart external symbolizer}}
// CHECK-NEXT: {{WARNING: .*DbgHelp}}
- // CHECK: {{#0 0x.* in main.*report_after_syminitialize.cc:}}[[@LINE-4]]
+ // CHECK: {{#0 0x.* in main.*report_after_syminitialize.cc:}}[[@LINE-6]]
// CHECK: AddressSanitizer can not provide additional info.
}
diff --git a/test/asan/TestCases/Windows/throw_catch.cc b/test/asan/TestCases/Windows/throw_catch.cc
deleted file mode 100644
index 5313d25b26d6..000000000000
--- a/test/asan/TestCases/Windows/throw_catch.cc
+++ /dev/null
@@ -1,73 +0,0 @@
-// Clang doesn't support exceptions on Windows yet, so for the time being we
-// build this program in two parts: the code with exceptions is built with CL,
-// the rest is built with Clang. This represents the typical scenario when we
-// build a large project using "clang-cl -fallback -fsanitize=address".
-//
-// RUN: cl -c %s -Fo%t.obj
-// RUN: %clangxx_asan -o %t.exe %s %t.obj
-// RUN: %run %t.exe
-
-#include <assert.h>
-#include <stdio.h>
-
-// Should just "#include <sanitizer/asan_interface.h>" when C++ exceptions are
-// supported and we don't need to use CL.
-extern "C" bool __asan_address_is_poisoned(void *p);
-
-void ThrowAndCatch();
-void TestThrowInline();
-
-#if !defined(__clang__)
-__declspec(noinline)
-void Throw() {
- int local;
- fprintf(stderr, "Throw: %p\n", &local);
- throw 1;
-}
-
-__declspec(noinline)
-void ThrowAndCatch() {
- int local;
- try {
- Throw();
- } catch(...) {
- fprintf(stderr, "Catch: %p\n", &local);
- }
-}
-
-void TestThrowInline() {
- char x[32];
- fprintf(stderr, "Before: %p poisoned: %d\n", &x,
- __asan_address_is_poisoned(x + 32));
- try {
- Throw();
- } catch(...) {
- fprintf(stderr, "Catch\n");
- }
- fprintf(stderr, "After: %p poisoned: %d\n", &x,
- __asan_address_is_poisoned(x + 32));
- // FIXME: Invert this assertion once we fix
- // https://code.google.com/p/address-sanitizer/issues/detail?id=258
- assert(!__asan_address_is_poisoned(x + 32));
-}
-
-#else
-
-void TestThrow() {
- char x[32];
- fprintf(stderr, "Before: %p poisoned: %d\n", &x,
- __asan_address_is_poisoned(x + 32));
- assert(__asan_address_is_poisoned(x + 32));
- ThrowAndCatch();
- fprintf(stderr, "After: %p poisoned: %d\n", &x,
- __asan_address_is_poisoned(x + 32));
- // FIXME: Invert this assertion once we fix
- // https://code.google.com/p/address-sanitizer/issues/detail?id=258
- assert(!__asan_address_is_poisoned(x + 32));
-}
-
-int main(int argc, char **argv) {
- TestThrowInline();
- TestThrow();
-}
-#endif
diff --git a/test/asan/TestCases/alloca_constant_size.cc b/test/asan/TestCases/alloca_constant_size.cc
new file mode 100644
index 000000000000..61f6da710116
--- /dev/null
+++ b/test/asan/TestCases/alloca_constant_size.cc
@@ -0,0 +1,51 @@
+// Regression test for https://github.com/google/sanitizers/issues/691
+
+// RUN: %clangxx_asan -O0 %s -o %t -fstack-protector
+// RUN: %run %t 1 2>&1 | FileCheck %s
+// RUN: %run %t 2 2>&1 | FileCheck %s
+
+#include <stdio.h>
+#include <string.h>
+
+// MSVC provides _alloca instead of alloca.
+#if defined(_MSC_VER) && !defined(alloca)
+# define alloca _alloca
+#else
+#include <alloca.h>
+#endif
+
+
+void f1_alloca() {
+ char *dynamic_buffer = (char *)alloca(200);
+ fprintf(stderr, "dynamic_buffer = %p\n", dynamic_buffer);
+ memset(dynamic_buffer, 'y', 200);
+ return;
+}
+
+static const int kDynamicArraySize = 200;
+
+void f1_vla() {
+ char dynamic_buffer[kDynamicArraySize];
+ fprintf(stderr, "dynamic_buffer = %p\n", dynamic_buffer);
+ memset(dynamic_buffer, 'y', kDynamicArraySize);
+ return;
+}
+
+void f2() {
+ char buf[1024];
+ memset(buf, 'x', 1024);
+}
+
+int main(int argc, const char *argv[]) {
+ if (!strcmp(argv[1], "1")) {
+ f1_alloca();
+ } else if (!strcmp(argv[1], "2")) {
+ f1_vla();
+ }
+ f2();
+ fprintf(stderr, "Done.\n");
+ return 0;
+}
+
+// CHECK-NOT: ERROR: AddressSanitizer
+// CHECK: Done.
diff --git a/test/asan/TestCases/asan_and_llvm_coverage_test.cc b/test/asan/TestCases/asan_and_llvm_coverage_test.cc
index 4748481fe548..d53deb4475de 100644
--- a/test/asan/TestCases/asan_and_llvm_coverage_test.cc
+++ b/test/asan/TestCases/asan_and_llvm_coverage_test.cc
@@ -1,6 +1,8 @@
// RUN: %clangxx_asan -coverage -O0 %s -o %t
// RUN: %env_asan_opts=check_initialization_order=1 %run %t 2>&1 | FileCheck %s
-// XFAIL: android,win32
+// XFAIL: android
+// We don't really support running tests using profile runtime on Windows.
+// UNSUPPORTED: win32
#include <stdio.h>
int foo() { return 1; }
int XXX = foo();
diff --git a/test/asan/TestCases/contiguous_container_crash.cc b/test/asan/TestCases/contiguous_container_crash.cc
index 5b999c04930c..af2102e6a12d 100644
--- a/test/asan/TestCases/contiguous_container_crash.cc
+++ b/test/asan/TestCases/contiguous_container_crash.cc
@@ -23,6 +23,7 @@ int TestCrash() {
__sanitizer_annotate_contiguous_container(&t[0], &t[0] + 100, &t[0] + 100,
&t[0] + 50);
// CHECK-CRASH: AddressSanitizer: container-overflow
+// CHECK-CRASH: if you don't care about these errors you may set ASAN_OPTIONS=detect_container_overflow=0
return (int)t[60 * one]; // Touches the poisoned memory.
}
diff --git a/test/asan/TestCases/coverage-levels.cc b/test/asan/TestCases/coverage-levels.cc
index 612bbd83777a..83f7cf6f779d 100644
--- a/test/asan/TestCases/coverage-levels.cc
+++ b/test/asan/TestCases/coverage-levels.cc
@@ -25,10 +25,10 @@ int main(int argc, char **argv) {
// CHECK1: CovDump: bitset of 1 bits written for '{{.*}}', 1 bits are set
// CHECK1: 1 PCs written
-// CHECK2: CovDump: bitset of 3 bits written for '{{.*}}', 2 bits are set
-// CHECK2: 2 PCs written
-// CHECK3: CovDump: bitset of 4 bits written for '{{.*}}', 3 bits are set
-// CHECK3: 3 PCs written
+// CHECK2: CovDump: bitset of 2 bits written for '{{.*}}', 1 bits are set
+// CHECK2: 1 PCs written
+// CHECK3: CovDump: bitset of 3 bits written for '{{.*}}', 2 bits are set
+// CHECK3: 2 PCs written
// CHECK3_NOBITSET-NOT: bitset of
// CHECK3_NOPCS-NOT: PCs written
-// CHECK_COUNTERS: CovDump: 4 counters written for
+// CHECK_COUNTERS: CovDump: 3 counters written for
diff --git a/test/asan/TestCases/coverage-pc-buffer.cc b/test/asan/TestCases/coverage-pc-buffer.cc
index 67b6935ec602..5895a5c45d15 100644
--- a/test/asan/TestCases/coverage-pc-buffer.cc
+++ b/test/asan/TestCases/coverage-pc-buffer.cc
@@ -19,30 +19,47 @@ void assertNotZeroPcs(uintptr_t *buf, uintptr_t size) {
}
int main() {
- uintptr_t *buf = NULL;
- uintptr_t sz = __sanitizer_get_coverage_pc_buffer(&buf);
- assertNotZeroPcs(buf, sz);
- assert(sz);
-
- foo();
- bar();
- uintptr_t *buf1 = NULL;
- uintptr_t sz1 = __sanitizer_get_coverage_pc_buffer(&buf1);
- assertNotZeroPcs(buf1, sz1);
- assert(buf1 == buf);
- assert(sz1 > sz);
-
- bar();
- uintptr_t *buf2 = NULL;
- uintptr_t sz2 = __sanitizer_get_coverage_pc_buffer(&buf2);
- assertNotZeroPcs(buf2, sz2);
- assert(buf2 == buf);
- assert(sz2 > sz1);
-
- __sanitizer_reset_coverage();
- uintptr_t *buf3 = NULL;
- uintptr_t sz3 = __sanitizer_get_coverage_pc_buffer(&buf3);
- assertNotZeroPcs(buf3, sz3);
- assert(buf3 == buf);
- assert(sz3 < sz2);
+ {
+ uintptr_t *buf = NULL;
+ uintptr_t sz = __sanitizer_get_coverage_pc_buffer(&buf);
+ assertNotZeroPcs(buf, sz);
+ assert(sz);
+ }
+
+ {
+ uintptr_t *buf = NULL;
+ uintptr_t sz = __sanitizer_get_coverage_pc_buffer(&buf);
+ // call functions for the first time.
+ foo();
+ bar();
+ uintptr_t *buf1 = NULL;
+ uintptr_t sz1 = __sanitizer_get_coverage_pc_buffer(&buf1);
+ assertNotZeroPcs(buf1, sz1);
+ assert(buf1 == buf);
+ assert(sz1 > sz);
+ }
+
+ {
+ uintptr_t *buf = NULL;
+ uintptr_t sz = __sanitizer_get_coverage_pc_buffer(&buf);
+ // second call shouldn't increase coverage.
+ bar();
+ uintptr_t *buf1 = NULL;
+ uintptr_t sz1 = __sanitizer_get_coverage_pc_buffer(&buf1);
+ assertNotZeroPcs(buf1, sz1);
+ assert(buf1 == buf);
+ assert(sz1 == sz);
+ }
+
+ {
+ uintptr_t *buf = NULL;
+ uintptr_t sz = __sanitizer_get_coverage_pc_buffer(&buf);
+ // reset coverage to 0.
+ __sanitizer_reset_coverage();
+ uintptr_t *buf1 = NULL;
+ uintptr_t sz1 = __sanitizer_get_coverage_pc_buffer(&buf1);
+ assertNotZeroPcs(buf1, sz1);
+ assert(buf1 == buf);
+ assert(sz1 < sz);
+ }
}
diff --git a/test/asan/TestCases/coverage-reset.cc b/test/asan/TestCases/coverage-reset.cc
index eb8da8c1aa06..11c5ef66ecf6 100644
--- a/test/asan/TestCases/coverage-reset.cc
+++ b/test/asan/TestCases/coverage-reset.cc
@@ -13,6 +13,13 @@ static volatile int sink;
__attribute__((noinline)) void bar() { sink = 2; }
__attribute__((noinline)) void foo() { sink = 1; }
+// In MSVC 2015, printf is an inline function, which causes this test to fail as
+// it introduces an extra coverage point. Define away printf on that platform to
+// avoid the issue.
+#if _MSC_VER >= 1900
+# define printf(arg, ...)
+#endif
+
#define GET_AND_PRINT_COVERAGE() \
bitset = 0; \
for (size_t i = 0; i < n_guards; i++) \
diff --git a/test/asan/TestCases/coverage-trace-pc.cc b/test/asan/TestCases/coverage-trace-pc.cc
new file mode 100644
index 000000000000..c03a6f02f771
--- /dev/null
+++ b/test/asan/TestCases/coverage-trace-pc.cc
@@ -0,0 +1,31 @@
+// Test -fsanitize-coverage=edge,indirect-call,trace-pc
+// RUN: %clangxx_asan -O0 -DTRACE_RT %s -o %t-rt.o -c
+// RUN: %clangxx_asan -O0 -fsanitize-coverage=edge,trace-pc,indirect-calls %s -o %t %t-rt.o
+// RUN: %run %t
+#ifdef TRACE_RT
+int pc_count;
+void *last_callee;
+extern "C" void __sanitizer_cov_trace_pc() {
+ pc_count++;
+}
+extern "C" void __sanitizer_cov_trace_pc_indir(void *callee) {
+ last_callee = callee;
+}
+#else
+#include <stdio.h>
+#include <assert.h>
+extern int pc_count;
+extern void *last_callee;
+
+__attribute__((noinline)) void foo() { printf("foo\n"); }
+__attribute__((noinline)) void bar() { printf("bar\n"); }
+
+int main(int argc, char **argv) {
+ void (*f)(void) = argc ? foo : bar;
+ int c1 = pc_count;
+ f();
+ int c2 = pc_count;
+ assert(c1 < c2);
+ assert(last_callee == foo);
+}
+#endif
diff --git a/test/asan/TestCases/debug_ppc64_mapping.cc b/test/asan/TestCases/debug_ppc64_mapping.cc
index 753a6364f4ed..43e1183a2d03 100644
--- a/test/asan/TestCases/debug_ppc64_mapping.cc
+++ b/test/asan/TestCases/debug_ppc64_mapping.cc
@@ -1,7 +1,7 @@
// RUN: %clang_asan -O0 %s -o %t
// RUN: %env_asan_opts=verbosity=0 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-PPC64-V0
// RUN: %env_asan_opts=verbosity=2 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-PPC64
-// REQUIRES: powerpc64-supported-target
+// REQUIRES: powerpc64-target-arch
#include <stdio.h>
diff --git a/test/asan/TestCases/double-free.cc b/test/asan/TestCases/double-free.cc
index 3297b435e38e..9bd418fc6c80 100644
--- a/test/asan/TestCases/double-free.cc
+++ b/test/asan/TestCases/double-free.cc
@@ -4,6 +4,10 @@
// Also works if no malloc context is available.
// RUN: %env_asan_opts=malloc_context_size=0:fast_unwind_on_malloc=0 not %run %t 2>&1 | FileCheck %s
// RUN: %env_asan_opts=malloc_context_size=0:fast_unwind_on_malloc=1 not %run %t 2>&1 | FileCheck %s
+
+// RUN: %clangxx_asan -O0 -fsanitize-recover=address %s -o %t 2>&1
+// RUN: %env_asan_opts=halt_on_error=false %run %t 2>&1 | FileCheck %s --check-prefix CHECK-RECOVER
+
// XFAIL: arm-linux-gnueabi
// XFAIL: armv7l-unknown-linux-gnueabihf
@@ -23,5 +27,7 @@ int main(int argc, char **argv) {
// MALLOC-CTX: #1 0x{{.*}} in main {{.*}}double-free.cc:[[@LINE-7]]
// CHECK: allocated by thread T0 here:
// MALLOC-CTX: double-free.cc:[[@LINE-12]]
+ // CHECK-RECOVER: AddressSanitizer: attempting double-free{{.*}}in thread T0
+ // CHECK-RECOVER-NOT: AddressSanitizer CHECK failed:
return res;
}
diff --git a/test/asan/TestCases/initialization-bug.cc b/test/asan/TestCases/initialization-bug.cc
index f5497256354c..6f361cb2bad8 100644
--- a/test/asan/TestCases/initialization-bug.cc
+++ b/test/asan/TestCases/initialization-bug.cc
@@ -8,6 +8,9 @@
// FIXME: https://code.google.com/p/address-sanitizer/issues/detail?id=186
// XFAIL: darwin,win32
+// The test is expected to fail on OS X Yosemite and older
+// UNSUPPORTED: osx-no-ld64-live_support
+
#include <cstdio>
// The structure of the test is:
diff --git a/test/asan/TestCases/invalid-pointer-pairs.cc b/test/asan/TestCases/invalid-pointer-pairs.cc
new file mode 100644
index 000000000000..b36e6cd9c10a
--- /dev/null
+++ b/test/asan/TestCases/invalid-pointer-pairs.cc
@@ -0,0 +1,44 @@
+// RUN: %clangxx_asan -O0 %s -o %t -mllvm -asan-detect-invalid-pointer-pair
+
+// RUN: %env_asan_opts=detect_invalid_pointer_pairs=1 %run %t k 2>&1 | FileCheck %s -check-prefix=OK -allow-empty
+// RUN: %env_asan_opts=detect_invalid_pointer_pairs=1 not %run %t g 2>&1 | FileCheck %s -check-prefix=CMP -check-prefix=ALL-ERRORS
+// RUN: %env_asan_opts=detect_invalid_pointer_pairs=1 not %run %t s 2>&1 | FileCheck %s -check-prefix=SUB -check-prefix=ALL-ERRORS
+// RUN: %env_asan_opts=detect_invalid_pointer_pairs=1 not %run %t f 2>&1 | FileCheck %s -check-prefix=FREE -check-prefix=ALL-ERRORS
+
+#include <assert.h>
+#include <stdlib.h>
+
+int f(char c, char *p, char *q) {
+ // ALL-ERRORS: ERROR: AddressSanitizer: invalid-pointer-pair
+ // [[PTR1:0x[0-9a-f]+]] [[PTR2:0x[0-9a-f]+]]
+ switch (c) {
+ case 'g':
+ // CMP: #{{[0-9]+ .*}} in f({{char, char\*, char\*|char,char \*,char \*}}) {{.*}}invalid-pointer-pairs.cc:[[@LINE+1]]:14
+ return p > q;
+ case 's':
+ // SUB: #{{[0-9]+ .*}} in f({{char, char\*, char\*|char,char \*,char \*}}) {{.*}}invalid-pointer-pairs.cc:[[@LINE+1]]:14
+ return p - q;
+ case 'k': {
+ // OK-NOT: ERROR
+ char *p2 = p + 20;
+ return p > p2;
+ }
+ case 'f': {
+ char *p3 = p + 20;
+ free(p);
+ // FREE: #{{[0-9]+ .*}} in f({{char, char\*, char\*|char,char \*,char \*}}) {{.*}}invalid-pointer-pairs.cc:[[@LINE+2]]:14
+ // FREE: freed by thread
+ return p < p3;
+ }
+ }
+ assert(0);
+}
+
+int main(int argc, char **argv) {
+ char *p = (char *)malloc(42);
+ char *q = (char *)malloc(42);
+ assert(argc >= 2);
+ f(argv[1][0], p, q);
+ free(p);
+ free(q);
+}
diff --git a/test/asan/TestCases/large_func_test.cc b/test/asan/TestCases/large_func_test.cc
index 6b592f8c4397..8d9afaeb4a75 100644
--- a/test/asan/TestCases/large_func_test.cc
+++ b/test/asan/TestCases/large_func_test.cc
@@ -49,5 +49,5 @@ int main(int argc, char **argv) {
// 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;
+ delete[] x;
}
diff --git a/test/asan/TestCases/printf-2.c b/test/asan/TestCases/printf-2.c
index 4b5ae138dfff..0544847ff5bf 100644
--- a/test/asan/TestCases/printf-2.c
+++ b/test/asan/TestCases/printf-2.c
@@ -1,9 +1,9 @@
// RUN: %clang_asan -O2 %s -o %t
-// We need replace_str=0 and replace_intrin=0 to avoid reporting errors in
-// strlen() and memcpy() called by printf().
-// RUN: %env_asan_opts=replace_str=0:replace_intrin=0:check_printf=1 not %run %t 2>&1 | FileCheck --check-prefix=CHECK-ON %s
-// RUN: %env_asan_opts=replace_str=0:replace_intrin=0:check_printf=0 %run %t 2>&1 | FileCheck --check-prefix=CHECK-OFF %s
-// RUN: %env_asan_opts=replace_str=0:replace_intrin=0 not %run %t 2>&1 | FileCheck --check-prefix=CHECK-ON %s
+// We need replace_str=0, intercept_strlen=0 and replace_intrin=0 to avoid
+// reporting errors in strlen() and memcpy() called by printf().
+// RUN: %env_asan_opts=replace_str=0:intercept_strlen=0:replace_intrin=0:check_printf=1 not %run %t 2>&1 | FileCheck --check-prefix=CHECK-ON %s
+// RUN: %env_asan_opts=replace_str=0:intercept_strlen=0:replace_intrin=0:check_printf=0 %run %t 2>&1 | FileCheck --check-prefix=CHECK-OFF %s
+// RUN: %env_asan_opts=replace_str=0:intercept_strlen=0:replace_intrin=0 not %run %t 2>&1 | FileCheck --check-prefix=CHECK-ON %s
// FIXME: printf is not intercepted on Windows yet.
// XFAIL: win32
diff --git a/test/asan/TestCases/printf-4.c b/test/asan/TestCases/printf-4.c
index 13bfc876c36c..5a883fe99efd 100644
--- a/test/asan/TestCases/printf-4.c
+++ b/test/asan/TestCases/printf-4.c
@@ -1,10 +1,8 @@
// RUN: %clang_asan -O2 %s -o %t
-// We need replace_str=0 and replace_intrin=0 to avoid reporting errors in
-// strlen() and memcpy() called by puts().
-// RUN: %env_asan_opts=replace_str=0:replace_intrin=0:check_printf=1 not %run %t 2>&1 | FileCheck --check-prefix=CHECK-ON %s
-// RUN: %env_asan_opts=replace_str=0:replace_intrin=0 not %run %t 2>&1 | FileCheck --check-prefix=CHECK-ON %s
+// RUN: %env_asan_opts=check_printf=1 not %run %t 2>&1 | FileCheck --check-prefix=CHECK-ON %s
+// RUN: not %run %t 2>&1 | FileCheck --check-prefix=CHECK-ON %s
-// FIXME: printf is not intercepted on Windows yet.
+// FIXME: sprintf is not intercepted on Windows yet.
// XFAIL: win32
#include <stdio.h>
@@ -14,10 +12,14 @@ int main() {
volatile float f = 1.239;
volatile char s[] = "34";
volatile char buf[2];
+ fputs("before sprintf\n", stderr);
sprintf((char *)buf, "%c %d %.3f %s\n", c, x, f, s);
- puts((const char *)buf);
+ fputs("after sprintf", stderr);
+ fputs((const char *)buf, stderr);
return 0;
// Check that size of output buffer is sanitized.
+ // CHECK-ON: before sprintf
+ // CHECK-ON-NOT: after sprintf
// CHECK-ON: stack-buffer-overflow
// CHECK-ON-NOT: 0 12 1.239 34
}
diff --git a/test/asan/TestCases/stack-oob-frames.cc b/test/asan/TestCases/stack-oob-frames.cc
index 00db4b3e1875..3b5d511b2681 100644
--- a/test/asan/TestCases/stack-oob-frames.cc
+++ b/test/asan/TestCases/stack-oob-frames.cc
@@ -4,9 +4,6 @@
// RUN: not %run %t 2 2>&1 | FileCheck %s --check-prefix=CHECK2
// RUN: not %run %t 3 2>&1 | FileCheck %s --check-prefix=CHECK3
-// FIXME: Symbolization problems.
-// XFAIL: win32
-
#define NOINLINE __attribute__((noinline))
inline void break_optimization(void *arg) {
__asm__ __volatile__("" : : "r" (arg) : "memory");
diff --git a/test/asan/TestCases/strcasestr-2.c b/test/asan/TestCases/strcasestr-2.c
index cca6d208cd43..47fd69225de6 100644
--- a/test/asan/TestCases/strcasestr-2.c
+++ b/test/asan/TestCases/strcasestr-2.c
@@ -3,7 +3,7 @@
// Test intercept_strstr asan option
// Disable other interceptors because strlen may be called inside strcasestr
-// RUN: %env_asan_opts=intercept_strstr=false:replace_str=false %run %t 2>&1
+// RUN: %env_asan_opts=intercept_strstr=false:replace_str=false:intercept_strlen=false %run %t 2>&1
// There's no interceptor for strcasestr on Windows
// XFAIL: win32
diff --git a/test/asan/TestCases/strdup_oob_test.cc b/test/asan/TestCases/strdup_oob_test.cc
index a039568b2245..492555ad1019 100644
--- a/test/asan/TestCases/strdup_oob_test.cc
+++ b/test/asan/TestCases/strdup_oob_test.cc
@@ -3,6 +3,12 @@
// RUN: %clangxx_asan -O2 %s -o %t && not %run %t 2>&1 | FileCheck %s
// RUN: %clangxx_asan -O3 %s -o %t && not %run %t 2>&1 | FileCheck %s
+// When built as C on Linux, strdup is transformed to __strdup.
+// RUN: %clangxx_asan -O3 -xc %s -o %t && not %run %t 2>&1 | FileCheck %s
+
+// Unwind problem on arm: "main" is missing from the allocation stack trace.
+// UNSUPPORTED: armv7l-unknown-linux-gnueabihf
+
#include <string.h>
char kString[] = "foo";
@@ -14,7 +20,8 @@ int main(int argc, char **argv) {
// CHECK: #0 {{.*}}main {{.*}}strdup_oob_test.cc:[[@LINE-2]]
// CHECK-LABEL: allocated by thread T{{.*}} here:
// CHECK: #{{[01]}} {{.*}}strdup
+ // CHECK: #{{.*}}main {{.*}}strdup_oob_test.cc:[[@LINE-6]]
// CHECK-LABEL: SUMMARY
- // CHECK: strdup_oob_test.cc:[[@LINE-6]]
+ // CHECK: strdup_oob_test.cc:[[@LINE-7]]
return x;
}
diff --git a/test/asan/TestCases/strstr-2.c b/test/asan/TestCases/strstr-2.c
index edb700865b83..8bc6e9902dd0 100644
--- a/test/asan/TestCases/strstr-2.c
+++ b/test/asan/TestCases/strstr-2.c
@@ -3,7 +3,7 @@
// Test intercept_strstr asan option
// Disable other interceptors because strlen may be called inside strstr
-// RUN: %env_asan_opts=intercept_strstr=false:replace_str=false %run %t 2>&1
+// RUN: %env_asan_opts=intercept_strstr=false:replace_str=false:intercept_strlen=false %run %t 2>&1
#include <assert.h>
#include <string.h>
diff --git a/test/asan/TestCases/throw_call_test.cc b/test/asan/TestCases/throw_call_test.cc
index 4b3910dce1eb..5a8204a04a54 100644
--- a/test/asan/TestCases/throw_call_test.cc
+++ b/test/asan/TestCases/throw_call_test.cc
@@ -5,9 +5,6 @@
// Android builds with static libstdc++ by default.
// XFAIL: android
-// Clang doesn't support exceptions on Windows yet.
-// XFAIL: win32
-
#include <stdio.h>
static volatile int zero = 0;
inline void pretend_to_do_something(void *x) {
diff --git a/test/asan/TestCases/throw_invoke_test.cc b/test/asan/TestCases/throw_invoke_test.cc
index ec48fc7b6a49..e6e91d1879cb 100644
--- a/test/asan/TestCases/throw_invoke_test.cc
+++ b/test/asan/TestCases/throw_invoke_test.cc
@@ -1,8 +1,5 @@
// RUN: %clangxx_asan %s -o %t && %run %t
-// RUN: %clangxx_asan %s -o %t -static-libstdc++ && %run %t
-
-// Clang doesn't support exceptions on Windows yet.
-// XFAIL: win32
+// RUN: %clangxx_asan %s -o %t -stdlib=libstdc++ -static-libstdc++ && %run %t
#include <stdio.h>
static volatile int zero = 0;
diff --git a/test/asan/TestCases/uar_and_exceptions.cc b/test/asan/TestCases/uar_and_exceptions.cc
index 324e8a52bd54..2357ae803ac2 100644
--- a/test/asan/TestCases/uar_and_exceptions.cc
+++ b/test/asan/TestCases/uar_and_exceptions.cc
@@ -2,9 +2,6 @@
// RUN: %clangxx_asan -O0 %s -o %t
// RUN: %env_asan_opts=detect_stack_use_after_return=1 %run %t
-// Clang doesn't support exceptions on Windows yet.
-// XFAIL: win32
-
#include <stdio.h>
volatile char *g;
diff --git a/test/asan/TestCases/use-after-scope-capture.cc b/test/asan/TestCases/use-after-scope-capture.cc
new file mode 100644
index 000000000000..07aab672eecb
--- /dev/null
+++ b/test/asan/TestCases/use-after-scope-capture.cc
@@ -0,0 +1,17 @@
+// RUN: %clangxx_asan -std=c++11 -O1 -fsanitize-address-use-after-scope %s -o %t && \
+// RUN: not %run %t 2>&1 | FileCheck %s
+
+#include <functional>
+
+int main() {
+ std::function<int()> f;
+ {
+ int x = 0;
+ f = [&x]() {
+ return x; // BOOM
+ // CHECK: ERROR: AddressSanitizer: stack-use-after-scope
+ // CHECK: #0 0x{{.*}} in {{.*}}use-after-scope-capture.cc:[[@LINE-2]]
+ };
+ }
+ return f(); // BOOM
+}
diff --git a/test/asan/TestCases/use-after-scope-chars.cc b/test/asan/TestCases/use-after-scope-chars.cc
new file mode 100644
index 000000000000..51fc5fa38747
--- /dev/null
+++ b/test/asan/TestCases/use-after-scope-chars.cc
@@ -0,0 +1,15 @@
+// RUN: %clangxx_asan -O1 -fsanitize-address-use-after-scope %s -o %t && \
+// RUN: not %run %t 2>&1 | FileCheck %s
+// XFAIL: *
+
+// FIXME: This works only for arraysize <= 8.
+
+char *p = 0;
+
+int main() {
+ {
+ char x[1024] = {};
+ p = x;
+ }
+ return *p; // BOOM
+}
diff --git a/test/asan/TestCases/use-after-scope-dtor-order.cc b/test/asan/TestCases/use-after-scope-dtor-order.cc
index 7896dd30c400..8cdfa6a1cd41 100644
--- a/test/asan/TestCases/use-after-scope-dtor-order.cc
+++ b/test/asan/TestCases/use-after-scope-dtor-order.cc
@@ -1,6 +1,6 @@
-// RUN: %clangxx_asan -O0 -fsanitize=use-after-scope %s -o %t && \
+// RUN: %clangxx_asan -O1 -fsanitize-address-use-after-scope %s -o %t && \
// RUN: not %run %t 2>&1 | FileCheck %s
-// XFAIL: *
+
#include <stdio.h>
struct IntHolder {
@@ -8,7 +8,7 @@ struct IntHolder {
~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]]
+ // CHECK: #0 0x{{.*}} in IntHolder::~IntHolder{{.*}}.cc:[[@LINE-2]]
}
void set(int *val) { val_ = val; }
int *get() { return val_; }
diff --git a/test/asan/TestCases/use-after-scope-if.cc b/test/asan/TestCases/use-after-scope-if.cc
new file mode 100644
index 000000000000..8180077a0cc1
--- /dev/null
+++ b/test/asan/TestCases/use-after-scope-if.cc
@@ -0,0 +1,15 @@
+// RUN: %clangxx_asan -O1 -fsanitize-address-use-after-scope %s -o %t && \
+// RUN: not %run %t 2>&1 | FileCheck %s
+
+int *p;
+bool b = true;
+
+int main() {
+ if (b) {
+ int x[5];
+ p = x+1;
+ }
+ return *p; // BOOM
+ // CHECK: ERROR: AddressSanitizer: stack-use-after-scope
+ // CHECK: #0 0x{{.*}} in main {{.*}}.cc:[[@LINE-2]]
+}
diff --git a/test/asan/TestCases/use-after-scope-inlined.cc b/test/asan/TestCases/use-after-scope-inlined.cc
index a0a0d9461cb9..fc8c7f7bb87d 100644
--- a/test/asan/TestCases/use-after-scope-inlined.cc
+++ b/test/asan/TestCases/use-after-scope-inlined.cc
@@ -2,8 +2,8 @@
// happens. "always_inline" is not enough, as Clang doesn't emit
// llvm.lifetime intrinsics at -O0.
//
-// RUN: %clangxx_asan -O2 -fsanitize=use-after-scope %s -o %t && not %run %t 2>&1 | FileCheck %s
-// XFAIL: *
+// RUN: %clangxx_asan -O2 -fsanitize-address-use-after-scope %s -o %t && \
+// RUN: not %run %t 2>&1 | FileCheck %s
int *arr;
diff --git a/test/asan/TestCases/use-after-scope-loop-bug.cc b/test/asan/TestCases/use-after-scope-loop-bug.cc
new file mode 100644
index 000000000000..6ad9bf3260cc
--- /dev/null
+++ b/test/asan/TestCases/use-after-scope-loop-bug.cc
@@ -0,0 +1,16 @@
+// RUN: %clangxx_asan -O1 -fsanitize-address-use-after-scope %s -o %t && \
+// RUN: not %run %t 2>&1 | FileCheck %s
+//
+// FIXME: @llvm.lifetime.* are not emitted for x.
+// XFAIL: *
+
+int *p;
+
+int main() {
+ // Variable goes in and out of scope.
+ for (int i = 0; i < 3; ++i) {
+ int x[3] = {i, i, i};
+ p = x + i;
+ }
+ return *p; // BOOM
+}
diff --git a/test/asan/TestCases/use-after-scope-loop-removed.cc b/test/asan/TestCases/use-after-scope-loop-removed.cc
new file mode 100644
index 000000000000..cd71a5046cd4
--- /dev/null
+++ b/test/asan/TestCases/use-after-scope-loop-removed.cc
@@ -0,0 +1,19 @@
+// RUN: %clangxx_asan -O1 -fsanitize-address-use-after-scope %s -o %t && \
+// RUN: not %run %t 2>&1 | FileCheck %s
+//
+// FIXME: Compiler removes for-loop but keeps x variable. For unknown reason
+// @llvm.lifetime.* are not emitted for x.
+// XFAIL: *
+
+#include <stdlib.h>
+
+int *p;
+
+int main() {
+ for (int i = 0; i < 3; i++) {
+ int x;
+ p = &x;
+ }
+ return **p; // BOOM
+ // CHECK: ERROR: AddressSanitizer: stack-use-after-scope
+}
diff --git a/test/asan/TestCases/use-after-scope-loop.cc b/test/asan/TestCases/use-after-scope-loop.cc
new file mode 100644
index 000000000000..d99761bc7a84
--- /dev/null
+++ b/test/asan/TestCases/use-after-scope-loop.cc
@@ -0,0 +1,14 @@
+// RUN: %clangxx_asan -O1 -fsanitize-address-use-after-scope %s -o %t && \
+// RUN: not %run %t 2>&1 | FileCheck %s
+
+int *p[3];
+
+int main() {
+ for (int i = 0; i < 3; i++) {
+ int x;
+ p[i] = &x;
+ }
+ return **p; // BOOM
+ // CHECK: ERROR: AddressSanitizer: stack-use-after-scope
+ // CHECK: #0 0x{{.*}} in main {{.*}}.cc:[[@LINE-2]]
+}
diff --git a/test/asan/TestCases/use-after-scope-nobug.cc b/test/asan/TestCases/use-after-scope-nobug.cc
index 21b085c96275..cf471dc345fa 100644
--- a/test/asan/TestCases/use-after-scope-nobug.cc
+++ b/test/asan/TestCases/use-after-scope-nobug.cc
@@ -1,14 +1,15 @@
-// RUN: %clangxx_asan -O0 -fsanitize=use-after-scope %s -o %t && %run %t
-// XFAIL: *
+// RUN: %clangxx_asan -O1 -fsanitize-address-use-after-scope %s -o %t && %run %t
#include <stdio.h>
+#include <stdlib.h>
+
+int *p[3];
int main() {
- int *p = 0;
// Variable goes in and out of scope.
for (int i = 0; i < 3; i++) {
- int x = 0;
- p = &x;
+ int x;
+ p[i] = &x;
}
printf("PASSED\n");
return 0;
diff --git a/test/asan/TestCases/use-after-scope-temp.cc b/test/asan/TestCases/use-after-scope-temp.cc
index f9bd779ac1a2..3736f914d072 100644
--- a/test/asan/TestCases/use-after-scope-temp.cc
+++ b/test/asan/TestCases/use-after-scope-temp.cc
@@ -1,15 +1,10 @@
-// RUN: %clangxx_asan -O0 -fsanitize=use-after-scope %s -o %t && \
-// RUN: %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O1 -fsanitize-address-use-after-scope %s -o %t && \
+// RUN: not %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;
};
@@ -20,10 +15,9 @@ void save(const IntHolder &holder) {
}
int main(int argc, char *argv[]) {
- save(IntHolder(10));
+ save({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;
+// CHECK: ERROR: AddressSanitizer: stack-use-after-scope
+// CHECK: #0 0x{{.*}} in main {{.*}}use-after-scope-temp.cc:[[@LINE-2]]
+ return x;
}
diff --git a/test/asan/TestCases/use-after-scope.cc b/test/asan/TestCases/use-after-scope.cc
index 59a0e0cd6e44..1aa6758229dd 100644
--- a/test/asan/TestCases/use-after-scope.cc
+++ b/test/asan/TestCases/use-after-scope.cc
@@ -1,10 +1,9 @@
-// RUN: %clangxx_asan -O0 -fsanitize=use-after-scope %s -o %t && \
-// RUN: not %run %t 2>&1 | FileCheck %s
-// RUN: %env_asan_opts=detect_stack_use_after_return=1 not %run %t 2>&1 | FileCheck %s
-// XFAIL: *
+// RUN: %clangxx_asan -O1 -fsanitize-address-use-after-scope %s -o %t && \
+// RUN: not %run %t 2>&1 | FileCheck %s
+
+int *p = 0;
int main() {
- int *p = 0;
{
int x = 0;
p = &x;
diff --git a/test/asan/Unit/lit.site.cfg.in b/test/asan/Unit/lit.site.cfg.in
index b5991023ee8a..55631a6d927f 100644
--- a/test/asan/Unit/lit.site.cfg.in
+++ b/test/asan/Unit/lit.site.cfg.in
@@ -1,5 +1,4 @@
-## Autogenerated by LLVM/Clang configuration.
-# Do not edit!
+@LIT_SITE_CFG_IN_HEADER@
import os
diff --git a/test/asan/android_commands/android_common.py b/test/asan/android_commands/android_common.py
index 43ac7b48d770..1a295b7817aa 100644
--- a/test/asan/android_commands/android_common.py
+++ b/test/asan/android_commands/android_common.py
@@ -8,15 +8,30 @@ verbose = False
if os.environ.get('ANDROID_RUN_VERBOSE') == '1':
verbose = True
-def adb(args):
+def adb(args, attempts = 1):
if verbose:
print args
- devnull = open(os.devnull, 'w')
- return subprocess.call([ADB] + args, stdout=devnull, stderr=subprocess.STDOUT)
+ tmpname = tempfile.mktemp()
+ out = open(tmpname, 'w')
+ ret = 255
+ while attempts > 0 and ret != 0:
+ attempts -= 1
+ ret = subprocess.call([ADB] + args, stdout=out, stderr=subprocess.STDOUT)
+ if attempts != 0:
+ ret = 5
+ if ret != 0:
+ print "adb command failed", args
+ print tmpname
+ out.close()
+ out = open(tmpname, 'r')
+ print out.read()
+ out.close()
+ os.unlink(tmpname)
+ return ret
def pull_from_device(path):
tmp = tempfile.mktemp()
- adb(['pull', path, tmp])
+ adb(['pull', path, tmp], 5)
text = open(tmp, 'r').read()
os.unlink(tmp)
return text
@@ -25,5 +40,5 @@ def push_to_device(path):
# Workaround for https://code.google.com/p/android/issues/detail?id=65857
dst_path = os.path.join(ANDROID_TMPDIR, os.path.basename(path))
tmp_path = dst_path + '.push'
- adb(['push', path, tmp_path])
- adb(['shell', 'cp "%s" "%s" 2>&1' % (tmp_path, dst_path)])
+ adb(['push', path, tmp_path], 5)
+ adb(['shell', 'cp "%s" "%s" 2>&1' % (tmp_path, dst_path)], 5)
diff --git a/test/asan/lit.cfg b/test/asan/lit.cfg
index 835547090a17..894c3f859fbd 100644
--- a/test/asan/lit.cfg
+++ b/test/asan/lit.cfg
@@ -73,6 +73,8 @@ clang_asan_static_cflags = (["-fsanitize=address",
"-fno-omit-frame-pointer",
"-fno-optimize-sibling-calls"] +
config.debug_info_flags + target_cflags)
+if config.target_arch == 's390x':
+ clang_asan_static_cflags.append("-mbackchain")
clang_asan_static_cxxflags = config.cxx_mode_flags + clang_asan_static_cflags
if config.asan_dynamic:
@@ -138,7 +140,7 @@ sancov = os.path.join(sanitizer_common_source_dir, "scripts", "sancov.py")
if not os.path.exists(sancov):
lit_config.fatal("Can't find script on path %r" % sancov)
python_exec = get_required_attr(config, "python_executable")
-config.substitutions.append( ("%sancov", python_exec + " " + sancov + " ") )
+config.substitutions.append( ("%sancov ", python_exec + " " + sancov + " ") )
# Determine kernel bitness
if config.host_arch.find('64') != -1 and config.android != "1":
diff --git a/test/asan/lit.site.cfg.in b/test/asan/lit.site.cfg.in
index 332f9ad9f828..1b6fed2cb9d6 100644
--- a/test/asan/lit.site.cfg.in
+++ b/test/asan/lit.site.cfg.in
@@ -1,12 +1,10 @@
-## Autogenerated by LLVM/Clang configuration.
-# Do not edit!
+@LIT_SITE_CFG_IN_HEADER@
# Tool-specific config options.
config.name_suffix = "@ASAN_TEST_CONFIG_SUFFIX@"
config.asan_lit_source_dir = "@ASAN_LIT_SOURCE_DIR@"
config.target_cflags = "@ASAN_TEST_TARGET_CFLAGS@"
config.clang = "@ASAN_TEST_TARGET_CC@"
-config.llvm_tools_dir = "@LLVM_TOOLS_BINARY_DIR@"
config.bits = "@ASAN_TEST_BITS@"
config.android = "@ANDROID@"
config.asan_dynamic = @ASAN_TEST_DYNAMIC@
diff --git a/test/builtins/Unit/cpu_model_test.c b/test/builtins/Unit/cpu_model_test.c
new file mode 100644
index 000000000000..5a918bde7dda
--- /dev/null
+++ b/test/builtins/Unit/cpu_model_test.c
@@ -0,0 +1,19 @@
+//===-- cpu_model_test.c - Test __builtin_cpu_supports -------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file tests __builtin_cpu_supports for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
+
+int main (void) {
+ if(__builtin_cpu_supports("avx2"))
+ return 4;
+ else
+ return 3;
+}
diff --git a/test/cfi/CMakeLists.txt b/test/cfi/CMakeLists.txt
index 5626a6e50ed7..4c4debaf1a87 100644
--- a/test/cfi/CMakeLists.txt
+++ b/test/cfi/CMakeLists.txt
@@ -1,6 +1,13 @@
+set(CFI_LIT_TEST_MODE Standalone)
configure_lit_site_cfg(
${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
- ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg
+ ${CMAKE_CURRENT_BINARY_DIR}/Standalone/lit.site.cfg
+ )
+
+set(CFI_LIT_TEST_MODE Devirt)
+configure_lit_site_cfg(
+ ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
+ ${CMAKE_CURRENT_BINARY_DIR}/Devirt/lit.site.cfg
)
set(CFI_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS})
@@ -8,6 +15,8 @@ if(NOT COMPILER_RT_STANDALONE_BUILD)
list(APPEND CFI_TEST_DEPS
opt
ubsan
+ stats
+ sanstats
)
if(COMPILER_RT_HAS_CFI)
list(APPEND CFI_TEST_DEPS cfi)
@@ -30,12 +39,15 @@ if(NOT COMPILER_RT_STANDALONE_BUILD)
endif()
add_lit_testsuite(check-cfi "Running the cfi regression tests"
- ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_BINARY_DIR}/Standalone
+ ${CMAKE_CURRENT_BINARY_DIR}/Devirt
DEPENDS ${CFI_TEST_DEPS})
add_lit_target(check-cfi-and-supported "Running the cfi regression tests"
- ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_BINARY_DIR}/Standalone
+ ${CMAKE_CURRENT_BINARY_DIR}/Devirt
PARAMS check_supported=1
DEPENDS ${CFI_TEST_DEPS})
-set_target_properties(check-cfi PROPERTIES FOLDER "Tests")
+set_target_properties(check-cfi PROPERTIES FOLDER "Compiler-RT Misc")
+set_target_properties(check-cfi-and-supported PROPERTIES FOLDER "Compiler-RT Misc")
diff --git a/test/cfi/create-derivers.test b/test/cfi/create-derivers.test
index 79521e4d085a..a67562b1a6c8 100644
--- a/test/cfi/create-derivers.test
+++ b/test/cfi/create-derivers.test
@@ -1,20 +1,20 @@
REQUIRES: asserts
RUN: %clangxx_cfi -c -o %t1.o %S/simple-fail.cpp
-RUN: opt -lowerbitsets -debug-only=lowerbitsets -o /dev/null %t1.o 2>&1 | FileCheck --check-prefix=B0 %s
+RUN: opt -lowertypetests -debug-only=lowertypetests -o /dev/null %t1.o 2>&1 | FileCheck --check-prefix=B0 %s
B0: {{1B|B@@}}: {{.*}} size 1
RUN: %clangxx_cfi -DB32 -c -o %t2.o %S/simple-fail.cpp
-RUN: opt -lowerbitsets -debug-only=lowerbitsets -o /dev/null %t2.o 2>&1 | FileCheck --check-prefix=B32 %s
+RUN: opt -lowertypetests -debug-only=lowertypetests -o /dev/null %t2.o 2>&1 | FileCheck --check-prefix=B32 %s
B32: {{1B|B@@}}: {{.*}} size 24
B32-NOT: all-ones
RUN: %clangxx_cfi -DB64 -c -o %t3.o %S/simple-fail.cpp
-RUN: opt -lowerbitsets -debug-only=lowerbitsets -o /dev/null %t3.o 2>&1 | FileCheck --check-prefix=B64 %s
+RUN: opt -lowertypetests -debug-only=lowertypetests -o /dev/null %t3.o 2>&1 | FileCheck --check-prefix=B64 %s
B64: {{1B|B@@}}: {{.*}} size 54
B64-NOT: all-ones
RUN: %clangxx_cfi -DBM -c -o %t4.o %S/simple-fail.cpp
-RUN: opt -lowerbitsets -debug-only=lowerbitsets -o /dev/null %t4.o 2>&1 | FileCheck --check-prefix=BM %s
+RUN: opt -lowertypetests -debug-only=lowertypetests -o /dev/null %t4.o 2>&1 | FileCheck --check-prefix=BM %s
BM: {{1B|B@@}}: {{.*}} size 84
BM-NOT: all-ones
diff --git a/test/cfi/cross-dso/dlopen.cpp b/test/cfi/cross-dso/dlopen.cpp
new file mode 100644
index 000000000000..ee4dae2b5f7d
--- /dev/null
+++ b/test/cfi/cross-dso/dlopen.cpp
@@ -0,0 +1,147 @@
+// RUN: %clangxx_cfi_dso -DSHARED_LIB %s -fPIC -shared -o %t1-so.so
+// RUN: %clangxx_cfi_dso %s -o %t1
+// RUN: %expect_crash %t1 2>&1 | FileCheck --check-prefix=CFI %s
+// RUN: %expect_crash %t1 cast 2>&1 | FileCheck --check-prefix=CFI-CAST %s
+// RUN: %expect_crash %t1 dlclose 2>&1 | FileCheck --check-prefix=CFI %s
+
+// RUN: %clangxx_cfi_dso -DB32 -DSHARED_LIB %s -fPIC -shared -o %t2-so.so
+// RUN: %clangxx_cfi_dso -DB32 %s -o %t2
+// RUN: %expect_crash %t2 2>&1 | FileCheck --check-prefix=CFI %s
+// RUN: %expect_crash %t2 cast 2>&1 | FileCheck --check-prefix=CFI-CAST %s
+// RUN: %expect_crash %t2 dlclose 2>&1 | FileCheck --check-prefix=CFI %s
+
+// RUN: %clangxx_cfi_dso -DB64 -DSHARED_LIB %s -fPIC -shared -o %t3-so.so
+// RUN: %clangxx_cfi_dso -DB64 %s -o %t3
+// RUN: %expect_crash %t3 2>&1 | FileCheck --check-prefix=CFI %s
+// RUN: %expect_crash %t3 cast 2>&1 | FileCheck --check-prefix=CFI-CAST %s
+// RUN: %expect_crash %t3 dlclose 2>&1 | FileCheck --check-prefix=CFI %s
+
+// RUN: %clangxx_cfi_dso -DBM -DSHARED_LIB %s -fPIC -shared -o %t4-so.so
+// RUN: %clangxx_cfi_dso -DBM %s -o %t4
+// RUN: %expect_crash %t4 2>&1 | FileCheck --check-prefix=CFI %s
+// RUN: %expect_crash %t4 cast 2>&1 | FileCheck --check-prefix=CFI-CAST %s
+// RUN: %expect_crash %t4 dlclose 2>&1 | FileCheck --check-prefix=CFI %s
+
+// RUN: %clangxx -g -DBM -DSHARED_LIB -DNOCFI %s -fPIC -shared -o %t5-so.so
+// RUN: %clangxx -g -DBM -DNOCFI %s -ldl -o %t5
+// RUN: %t5 2>&1 | FileCheck --check-prefix=NCFI %s
+// RUN: %t5 cast 2>&1 | FileCheck --check-prefix=NCFI %s
+// RUN: %t5 dlclose 2>&1 | FileCheck --check-prefix=NCFI %s
+
+// Test that calls to uninstrumented library are unchecked.
+// RUN: %clangxx -DBM -DSHARED_LIB %s -fPIC -shared -o %t6-so.so
+// RUN: %clangxx_cfi_dso -DBM %s -o %t6
+// RUN: %t6 2>&1 | FileCheck --check-prefix=NCFI %s
+// RUN: %t6 cast 2>&1 | FileCheck --check-prefix=NCFI %s
+
+// Call-after-dlclose is checked on the caller side.
+// RUN: %expect_crash %t6 dlclose 2>&1 | FileCheck --check-prefix=CFI %s
+
+// Tests calls into dlopen-ed library.
+// REQUIRES: cxxabi
+
+#include <assert.h>
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/mman.h>
+
+#include <string>
+
+struct A {
+ virtual void f();
+};
+
+#ifdef SHARED_LIB
+
+#include "../utils.h"
+struct B {
+ virtual void f();
+};
+void B::f() {}
+
+extern "C" void *create_B() {
+ create_derivers<B>();
+ return (void *)(new B());
+}
+
+extern "C" __attribute__((aligned(4096))) void do_nothing() {}
+
+#else
+
+void A::f() {}
+
+static const int kCodeAlign = 4096;
+static const int kCodeSize = 4096;
+static char saved_code[kCodeSize];
+static char *real_start;
+
+static void save_code(char *p) {
+ real_start = (char *)(((uintptr_t)p) & ~(kCodeAlign - 1));
+ memcpy(saved_code, real_start, kCodeSize);
+}
+
+static void restore_code() {
+ char *code = (char *)mmap(real_start, kCodeSize, PROT_WRITE | PROT_EXEC,
+ MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, 0, 0);
+ assert(code == real_start);
+ memcpy(code, saved_code, kCodeSize);
+}
+
+int main(int argc, char *argv[]) {
+ const bool test_cast = argc > 1 && strcmp(argv[1], "cast") == 0;
+ const bool test_dlclose = argc > 1 && strcmp(argv[1], "dlclose") == 0;
+
+ std::string name = std::string(argv[0]) + "-so.so";
+ void *handle = dlopen(name.c_str(), RTLD_NOW);
+ assert(handle);
+ void *(*create_B)() = (void *(*)())dlsym(handle, "create_B");
+ assert(create_B);
+
+ void *p = create_B();
+ A *a;
+
+ // CFI: =0=
+ // CFI-CAST: =0=
+ // NCFI: =0=
+ fprintf(stderr, "=0=\n");
+
+ if (test_cast) {
+ // Test cast. BOOM.
+ a = (A*)p;
+ } else {
+ // Invisible to CFI. Test virtual call later.
+ memcpy(&a, &p, sizeof(a));
+ }
+
+ // CFI: =1=
+ // CFI-CAST-NOT: =1=
+ // NCFI: =1=
+ fprintf(stderr, "=1=\n");
+
+ if (test_dlclose) {
+ // Imitate an attacker sneaking in an executable page where a dlclose()d
+ // library was loaded. This needs to pass w/o CFI, so for the testing
+ // purpose, we just copy the bytes of a "void f() {}" function back and
+ // forth.
+ void (*do_nothing)() = (void (*)())dlsym(handle, "do_nothing");
+ assert(do_nothing);
+ save_code((char *)do_nothing);
+
+ int res = dlclose(handle);
+ assert(res == 0);
+
+ restore_code();
+
+ do_nothing(); // UB here
+ } else {
+ a->f(); // UB here
+ }
+
+ // CFI-NOT: =2=
+ // CFI-CAST-NOT: =2=
+ // NCFI: =2=
+ fprintf(stderr, "=2=\n");
+}
+#endif
diff --git a/test/cfi/cross-dso/icall/diag.cpp b/test/cfi/cross-dso/icall/diag.cpp
new file mode 100644
index 000000000000..c9ca28cbf2cd
--- /dev/null
+++ b/test/cfi/cross-dso/icall/diag.cpp
@@ -0,0 +1,159 @@
+// Cross-DSO diagnostics.
+// The rules are:
+// * If the library needs diagnostics, the main executable must request at
+// least some diagnostics as well (to link the diagnostic runtime).
+// * -fsanitize-trap on the caller side overrides everything.
+// * otherwise, the callee decides between trap/recover/norecover.
+
+// Full-recover.
+// RUN: %clangxx_cfi_dso_diag -g -DSHARED_LIB %s -fPIC -shared -o %t-so.so
+// RUN: %clangxx_cfi_dso_diag -g %s -o %t %t-so.so
+
+// RUN: %t icv 2>&1 | FileCheck %s --check-prefix=ICALL-DIAG --check-prefix=CAST-DIAG \
+// RUN: --check-prefix=VCALL-DIAG --check-prefix=ALL-RECOVER
+
+// RUN: %t i_v 2>&1 | FileCheck %s --check-prefix=ICALL-DIAG --check-prefix=CAST-NODIAG \
+// RUN: --check-prefix=VCALL-DIAG --check-prefix=ALL-RECOVER
+
+// RUN: %t _cv 2>&1 | FileCheck %s --check-prefix=ICALL-NODIAG --check-prefix=CAST-DIAG \
+// RUN: --check-prefix=VCALL-DIAG --check-prefix=ALL-RECOVER
+
+// RUN: %t ic_ 2>&1 | FileCheck %s --check-prefix=ICALL-DIAG --check-prefix=CAST-DIAG \
+// RUN: --check-prefix=VCALL-NODIAG --check-prefix=ALL-RECOVER
+
+// Trap on icall, no-recover on cast.
+// RUN: %clangxx_cfi_dso_diag -fsanitize-trap=cfi-icall -fno-sanitize-recover=cfi-unrelated-cast \
+// RUN: -g -DSHARED_LIB %s -fPIC -shared -o %t-so.so
+// RUN: %clangxx_cfi_dso_diag -fsanitize-trap=cfi-icall -fno-sanitize-recover=cfi-unrelated-cast \
+// RUN: -g %s -o %t %t-so.so
+
+// RUN: %expect_crash %t icv 2>&1 | FileCheck %s --check-prefix=ICALL-NODIAG --check-prefix=CAST-NODIAG \
+// RUN: --check-prefix=VCALL-NODIAG --check-prefix=ICALL-FATAL
+
+// RUN: not %t _cv 2>&1 | FileCheck %s --check-prefix=ICALL-NODIAG --check-prefix=CAST-DIAG \
+// RUN: --check-prefix=VCALL-NODIAG --check-prefix=CAST-FATAL
+
+// RUN: %t __v 2>&1 | FileCheck %s --check-prefix=ICALL-NODIAG --check-prefix=CAST-NODIAG \
+// RUN: --check-prefix=VCALL-DIAG
+
+// Callee: trap on icall, no-recover on cast.
+// Caller: recover on everything.
+// The same as in the previous case, behaviour is decided by the callee.
+// RUN: %clangxx_cfi_dso_diag -fsanitize-trap=cfi-icall -fno-sanitize-recover=cfi-unrelated-cast \
+// RUN: -g -DSHARED_LIB %s -fPIC -shared -o %t-so.so
+// RUN: %clangxx_cfi_dso_diag \
+// RUN: -g %s -o %t %t-so.so
+
+// RUN: %expect_crash %t icv 2>&1 | FileCheck %s --check-prefix=ICALL-NODIAG --check-prefix=CAST-NODIAG \
+// RUN: --check-prefix=VCALL-NODIAG --check-prefix=ICALL-FATAL
+
+// RUN: not %t _cv 2>&1 | FileCheck %s --check-prefix=ICALL-NODIAG --check-prefix=CAST-DIAG \
+// RUN: --check-prefix=VCALL-NODIAG --check-prefix=CAST-FATAL
+
+// RUN: %t __v 2>&1 | FileCheck %s --check-prefix=ICALL-NODIAG --check-prefix=CAST-NODIAG \
+// RUN: --check-prefix=VCALL-DIAG
+
+// Caller in trapping mode, callee with full diagnostic+recover.
+// Caller wins.
+// cfi-nvcall is non-trapping in the main executable to link the diagnostic runtime library.
+// RUN: %clangxx_cfi_dso_diag \
+// RUN: -g -DSHARED_LIB %s -fPIC -shared -o %t-so.so
+// RUN: %clangxx_cfi_dso -fno-sanitize-trap=cfi-nvcall \
+// RUN: -g %s -o %t %t-so.so
+
+// RUN: %expect_crash %t icv 2>&1 | FileCheck %s --check-prefix=ICALL-NODIAG --check-prefix=CAST-NODIAG \
+// RUN: --check-prefix=VCALL-NODIAG --check-prefix=ICALL-FATAL
+
+// RUN: %expect_crash %t _cv 2>&1 | FileCheck %s --check-prefix=ICALL-NODIAG --check-prefix=CAST-NODIAG \
+// RUN: --check-prefix=VCALL-NODIAG --check-prefix=CAST-FATAL
+
+// RUN: %expect_crash %t __v 2>&1 | FileCheck %s --check-prefix=ICALL-NODIAG --check-prefix=CAST-NODIAG \
+// RUN: --check-prefix=VCALL-NODIAG --check-prefix=VCALL-FATAL
+
+// REQUIRES: cxxabi
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+struct A {
+ virtual void f();
+};
+
+void *create_B();
+
+#ifdef SHARED_LIB
+
+#include "../../utils.h"
+struct B {
+ virtual void f();
+};
+void B::f() {}
+
+void *create_B() {
+ create_derivers<B>();
+ return (void *)(new B());
+}
+
+#else
+
+void A::f() {}
+
+int main(int argc, char *argv[]) {
+ assert(argc == 2);
+ assert(strlen(argv[1]) == 3);
+
+ // ICALL-FATAL: =0=
+ // CAST-FATAL: =0=
+ // VCALL-FATAL: =0=
+ // ALL-RECOVER: =0=
+ fprintf(stderr, "=0=\n");
+
+ void *p;
+ if (argv[1][0] == 'i') {
+ // ICALL-DIAG: runtime error: control flow integrity check for type 'void *(int)' failed during indirect function call
+ // ICALL-DIAG-NEXT: note: create_B() defined here
+ // ICALL-NODIAG-NOT: runtime error: control flow integrity check {{.*}} during indirect function call
+ p = ((void *(*)(int))create_B)(42);
+ } else {
+ p = create_B();
+ }
+
+ // ICALL-FATAL-NOT: =1=
+ // CAST-FATAL: =1=
+ // VCALL-FATAL: =1=
+ // ALL-RECOVER: =1=
+ fprintf(stderr, "=1=\n");
+
+ A *a;
+ if (argv[1][1] == 'c') {
+ // CAST-DIAG: runtime error: control flow integrity check for type 'A' failed during cast to unrelated type
+ // CAST-DIAG-NEXT: note: vtable is of type '{{(struct )?}}B'
+ // CAST-NODIAG-NOT: runtime error: control flow integrity check {{.*}} during cast to unrelated type
+ a = (A*)p;
+ } else {
+ // Invisible to CFI.
+ memcpy(&a, &p, sizeof(a));
+ }
+
+ // ICALL-FATAL-NOT: =2=
+ // CAST-FATAL-NOT: =2=
+ // VCALL-FATAL: =2=
+ // ALL-RECOVER: =2=
+ fprintf(stderr, "=2=\n");
+
+ // VCALL-DIAG: runtime error: control flow integrity check for type 'A' failed during virtual call
+ // VCALL-DIAG-NEXT: note: vtable is of type '{{(struct )?}}B'
+ // VCALL-NODIAG-NOT: runtime error: control flow integrity check {{.*}} during virtual call
+ if (argv[1][2] == 'v') {
+ a->f(); // UB here
+ }
+
+ // ICALL-FATAL-NOT: =3=
+ // CAST-FATAL-NOT: =3=
+ // VCALL-FATAL-NOT: =3=
+ // ALL-RECOVER: =3=
+ fprintf(stderr, "=3=\n");
+
+}
+#endif
diff --git a/test/cfi/cross-dso/icall/icall-from-dso.cpp b/test/cfi/cross-dso/icall/icall-from-dso.cpp
index 1995f05f43d4..93cf4f676f7b 100644
--- a/test/cfi/cross-dso/icall/icall-from-dso.cpp
+++ b/test/cfi/cross-dso/icall/icall-from-dso.cpp
@@ -1,17 +1,25 @@
// RUN: %clangxx_cfi_dso -DSHARED_LIB %s -fPIC -shared -o %t-so.so
// RUN: %clangxx_cfi_dso %s -o %t %t-so.so && %expect_crash %t 2>&1 | FileCheck %s
+// RUN: %clangxx_cfi_dso_diag -g -DSHARED_LIB %s -fPIC -shared -o %t2-so.so
+// RUN: %clangxx_cfi_dso_diag -g %s -o %t2 %t2-so.so && %t2 2>&1 | FileCheck %s --check-prefix=CFI-DIAG
+
#include <stdio.h>
#ifdef SHARED_LIB
void g();
void f() {
+ // CHECK-DIAG: =1=
// CHECK: =1=
fprintf(stderr, "=1=\n");
((void (*)(void))g)();
+ // CHECK-DIAG: =2=
// CHECK: =2=
fprintf(stderr, "=2=\n");
+ // CFI-DIAG: runtime error: control flow integrity check for type 'void (int)' failed during indirect function call
+ // CFI-DIAG-NEXT: note: g() defined here
((void (*)(int))g)(42); // UB here
+ // CHECK-DIAG: =3=
// CHECK-NOT: =3=
fprintf(stderr, "=3=\n");
}
diff --git a/test/cfi/cross-dso/icall/icall.cpp b/test/cfi/cross-dso/icall/icall.cpp
index d7cc2f9ca94d..6017b801436e 100644
--- a/test/cfi/cross-dso/icall/icall.cpp
+++ b/test/cfi/cross-dso/icall/icall.cpp
@@ -1,6 +1,9 @@
// RUN: %clangxx_cfi_dso -DSHARED_LIB %s -fPIC -shared -o %t-so.so
// RUN: %clangxx_cfi_dso %s -o %t %t-so.so && %expect_crash %t 2>&1 | FileCheck %s
+// RUN: %clangxx_cfi_dso_diag -g -DSHARED_LIB %s -fPIC -shared -o %t2-so.so
+// RUN: %clangxx_cfi_dso_diag -g %s -o %t2 %t2-so.so && %t2 2>&1 | FileCheck %s --check-prefix=CFI-DIAG
+
#include <stdio.h>
#ifdef SHARED_LIB
@@ -9,12 +12,17 @@ void f() {
#else
void f();
int main() {
+ // CHECK-DIAG: =1=
// CHECK: =1=
fprintf(stderr, "=1=\n");
((void (*)(void))f)();
+ // CHECK-DIAG: =2=
// CHECK: =2=
fprintf(stderr, "=2=\n");
+ // CFI-DIAG: runtime error: control flow integrity check for type 'void (int)' failed during indirect function call
+ // CFI-DIAG-NEXT: note: f() defined here
((void (*)(int))f)(42); // UB here
+ // CHECK-DIAG: =3=
// CHECK-NOT: =3=
fprintf(stderr, "=3=\n");
}
diff --git a/test/cfi/cross-dso/shadow_is_read_only.cpp b/test/cfi/cross-dso/shadow_is_read_only.cpp
new file mode 100644
index 000000000000..65aec826c001
--- /dev/null
+++ b/test/cfi/cross-dso/shadow_is_read_only.cpp
@@ -0,0 +1,85 @@
+// RUN: %clangxx_cfi_dso -std=c++11 -g -DSHARED_LIB %s -fPIC -shared -o %t-cfi-so.so
+// RUN: %clangxx -std=c++11 -g -DSHARED_LIB %s -fPIC -shared -o %t-nocfi-so.so
+// RUN: %clangxx_cfi_dso -std=c++11 -g %s -o %t
+
+// RUN: %expect_crash %t start 2>&1 | FileCheck %s
+// RUN: %expect_crash %t mmap 2>&1 | FileCheck %s
+// RUN: %expect_crash %t dlopen %t-cfi-so.so 2>&1 | FileCheck %s
+// RUN: %expect_crash %t dlclose %t-cfi-so.so 2>&1 | FileCheck %s
+// RUN: %expect_crash %t dlopen %t-nocfi-so.so 2>&1 | FileCheck %s
+// RUN: %expect_crash %t dlclose %t-nocfi-so.so 2>&1 | FileCheck %s
+
+// Tests that shadow is read-only most of the time.
+// REQUIRES: cxxabi
+
+#include <assert.h>
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+
+struct A {
+ virtual void f();
+};
+
+#ifdef SHARED_LIB
+
+void A::f() {}
+
+extern "C" A *create_A() { return new A(); }
+
+#else
+
+constexpr unsigned kShadowGranularity = 12;
+
+namespace __cfi {
+uintptr_t GetShadow();
+}
+
+void write_shadow(void *ptr) {
+ uintptr_t base = __cfi::GetShadow();
+ uint16_t *s =
+ (uint16_t *)(base + (((uintptr_t)ptr >> kShadowGranularity) << 1));
+ fprintf(stderr, "going to crash\n");
+ // CHECK: going to crash
+ *s = 42;
+ fprintf(stderr, "did not crash\n");
+ // CHECK-NOT: did not crash
+ exit(1);
+}
+
+int main(int argc, char *argv[]) {
+ assert(argc > 1);
+ const bool test_mmap = strcmp(argv[1], "mmap") == 0;
+ const bool test_start = strcmp(argv[1], "start") == 0;
+ const bool test_dlopen = strcmp(argv[1], "dlopen") == 0;
+ const bool test_dlclose = strcmp(argv[1], "dlclose") == 0;
+ const char *lib = argc > 2 ? argv[2] : nullptr;
+
+ if (test_start)
+ write_shadow((void *)&main);
+
+ if (test_mmap) {
+ void *p = mmap(nullptr, 1 << 20, PROT_READ | PROT_WRITE | PROT_EXEC,
+ MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
+ assert(p != MAP_FAILED);
+ write_shadow((char *)p + 100);
+ } else {
+ void *handle = dlopen(lib, RTLD_NOW);
+ assert(handle);
+ void *create_A = dlsym(handle, "create_A");
+ assert(create_A);
+
+ if (test_dlopen)
+ write_shadow(create_A);
+
+ int res = dlclose(handle);
+ assert(res == 0);
+
+ if (test_dlclose)
+ write_shadow(create_A);
+ }
+}
+#endif
diff --git a/test/cfi/cross-dso/simple-fail.cpp b/test/cfi/cross-dso/simple-fail.cpp
index 64db288a95b5..276b67d4b7f2 100644
--- a/test/cfi/cross-dso/simple-fail.cpp
+++ b/test/cfi/cross-dso/simple-fail.cpp
@@ -28,6 +28,11 @@
// RUN: %t6 2>&1 | FileCheck --check-prefix=NCFI %s
// RUN: %t6 x 2>&1 | FileCheck --check-prefix=NCFI %s
+// RUN: %clangxx_cfi_dso_diag -DSHARED_LIB %s -fPIC -shared -o %t7-so.so
+// RUN: %clangxx_cfi_dso_diag %s -o %t7 %t7-so.so
+// RUN: %t7 2>&1 | FileCheck --check-prefix=CFI-DIAG-CALL %s
+// RUN: %t7 x 2>&1 | FileCheck --check-prefix=CFI-DIAG-CALL --check-prefix=CFI-DIAG-CAST %s
+
// Tests that the CFI mechanism crashes the program when making a virtual call
// to an object of the wrong class but with a compatible vtable, by casting a
// pointer to such an object and attempting to make a call through it.
@@ -71,6 +76,8 @@ int main(int argc, char *argv[]) {
if (argc > 1 && argv[1][0] == 'x') {
// Test cast. BOOM.
+ // CFI-DIAG-CAST: runtime error: control flow integrity check for type 'A' failed during cast to unrelated type
+ // CFI-DIAG-CAST-NEXT: note: vtable is of type '{{(struct )?}}B'
a = (A*)p;
} else {
// Invisible to CFI. Test virtual call later.
@@ -82,6 +89,8 @@ int main(int argc, char *argv[]) {
// NCFI: =1=
fprintf(stderr, "=1=\n");
+ // CFI-DIAG-CALL: runtime error: control flow integrity check for type 'A' failed during virtual call
+ // CFI-DIAG-CALL-NEXT: note: vtable is of type '{{(struct )?}}B'
a->f(); // UB here
// CFI-NOT: =2=
diff --git a/test/cfi/cross-dso/stats.cpp b/test/cfi/cross-dso/stats.cpp
new file mode 100644
index 000000000000..3d25d7730c77
--- /dev/null
+++ b/test/cfi/cross-dso/stats.cpp
@@ -0,0 +1,59 @@
+// RUN: %clangxx_cfi_dso -DSHARED_LIB -fPIC -g -fsanitize-stats -shared -o %t.so %s
+// RUN: %clangxx_cfi_dso -g -fsanitize-stats -o %t %s %t.so
+// RUN: env SANITIZER_STATS_PATH=%t.stats %t
+// RUN: sanstats %t.stats | FileCheck %s
+
+struct ABase {};
+
+struct A : ABase {
+ virtual void vf() {}
+ void nvf() {}
+};
+
+extern "C" void vcall(A *a);
+extern "C" void nvcall(A *a);
+
+#ifdef SHARED_LIB
+
+extern "C" __attribute__((noinline)) void vcall(A *a) {
+ // CHECK: stats.cpp:[[@LINE+1]] vcall cfi-vcall 37
+ a->vf();
+}
+
+extern "C" __attribute__((noinline)) void nvcall(A *a) {
+ // CHECK: stats.cpp:[[@LINE+1]] nvcall cfi-nvcall 51
+ a->nvf();
+}
+
+#else
+
+extern "C" __attribute__((noinline)) A *dcast(A *a) {
+ // CHECK: stats.cpp:[[@LINE+1]] dcast cfi-derived-cast 24
+ return (A *)(ABase *)a;
+}
+
+extern "C" __attribute__((noinline)) A *ucast(A *a) {
+ // CHECK: stats.cpp:[[@LINE+1]] ucast cfi-unrelated-cast 81
+ return (A *)(char *)a;
+}
+
+extern "C" __attribute__((noinline)) void unreachable(A *a) {
+ // CHECK-NOT: unreachable
+ a->vf();
+}
+
+int main() {
+ A a;
+ for (unsigned i = 0; i != 37; ++i)
+ vcall(&a);
+ for (unsigned i = 0; i != 51; ++i)
+ nvcall(&a);
+ for (unsigned i = 0; i != 24; ++i)
+ dcast(&a);
+ for (unsigned i = 0; i != 81; ++i)
+ ucast(&a);
+ for (unsigned i = 0; i != 0; ++i)
+ unreachable(&a);
+}
+
+#endif
diff --git a/test/cfi/cross-dso/target_out_of_bounds.cpp b/test/cfi/cross-dso/target_out_of_bounds.cpp
new file mode 100644
index 000000000000..6353f030a6ac
--- /dev/null
+++ b/test/cfi/cross-dso/target_out_of_bounds.cpp
@@ -0,0 +1,64 @@
+// RUN: %clangxx_cfi_dso_diag -std=c++11 %s -o %t
+// RUN: %t zero 2>&1 | FileCheck --check-prefix=CHECK-ZERO %s
+// RUN: %t unaddressable 2>&1 | FileCheck --check-prefix=CHECK-UNADDR %s
+// RUN: %t 2>&1 | FileCheck --check-prefix=CHECK-TYPEINFO %s
+
+// RUN: %clangxx_cfi_diag -std=c++11 %s -o %t2
+// RUN: %t2 zero 2>&1 | FileCheck --check-prefix=CHECK-ZERO %s
+// RUN: %t2 unaddressable 2>&1 | FileCheck --check-prefix=CHECK-UNADDR %s
+// RUN: %t2 2>&1 | FileCheck --check-prefix=CHECK-TYPEINFO %s
+
+// REQUIRES: cxxabi
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+
+struct A {
+ virtual void f();
+};
+
+void A::f() {}
+
+int main(int argc, char *argv[]) {
+ char *volatile p = reinterpret_cast<char *>(new A());
+ if (argc > 1 && strcmp(argv[1], "unaddressable") == 0) {
+ void *vtable = mmap(nullptr, 4096, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
+ // Create an object with a vtable in an unaddressable memory region.
+ *(uintptr_t *)p = (uintptr_t)vtable + 64;
+ // CHECK-UNADDR: runtime error: control flow integrity check for type 'A' failed during cast
+ // CHECK-UNADDR: note: invalid vtable
+ // CHECK-UNADDR: <memory cannot be printed>
+ // CHECK-UNADDR: runtime error: control flow integrity check for type 'A' failed during cast
+ // CHECK-UNADDR: note: invalid vtable
+ // CHECK-UNADDR: <memory cannot be printed>
+ } else if (argc > 1 && strcmp(argv[1], "zero") == 0) {
+ // Create an object with a vtable outside of any known DSO, but still in an
+ // addressable area.
+ void *vtable = calloc(1, 128);
+ *(uintptr_t *)p = (uintptr_t)vtable + 64;
+ // CHECK-ZERO: runtime error: control flow integrity check for type 'A' failed during cast
+ // CHECK-ZERO: note: invalid vtable
+ // CHECK-ZERO: 00 00 00 00 00 00 00 00
+ // CHECK-ZERO: runtime error: control flow integrity check for type 'A' failed during cast
+ // CHECK-ZERO: note: invalid vtable
+ // CHECK-ZERO: 00 00 00 00 00 00 00 00
+ } else {
+ // Create an object with a seemingly fine vtable, but with an unaddressable
+ // typeinfo pointer.
+ void *vtable = calloc(1, 128);
+ memset(vtable, 0xFE, 128);
+ *(uintptr_t *)p = (uintptr_t)vtable + 64;
+ // CHECK-TYPEINFO: runtime error: control flow integrity check for type 'A' failed during cast
+ // CHECK-TYPEINFO: note: invalid vtable
+ // CHECK-TYPEINFO: fe fe fe fe fe fe fe fe
+ // CHECK-TYPEINFO: runtime error: control flow integrity check for type 'A' failed during cast
+ // CHECK-TYPEINFO: note: invalid vtable
+ // CHECK-TYPEINFO: fe fe fe fe fe fe fe fe
+ }
+
+ A *volatile pa = reinterpret_cast<A *>(p);
+ pa = reinterpret_cast<A *>(p);
+}
diff --git a/test/cfi/icall/bad-signature.c b/test/cfi/icall/bad-signature.c
index 43de1178fe6c..183e62738bb2 100644
--- a/test/cfi/icall/bad-signature.c
+++ b/test/cfi/icall/bad-signature.c
@@ -1,10 +1,10 @@
-// RUN: %clangxx -o %t1 %s
+// RUN: %clang -o %t1 %s
// RUN: %t1 2>&1 | FileCheck --check-prefix=NCFI %s
-// RUN: %clangxx_cfi -o %t2 %s
+// RUN: %clang_cfi -o %t2 %s
// RUN: %expect_crash %t2 2>&1 | FileCheck --check-prefix=CFI %s
-// RUN: %clangxx_cfi_diag -g -o %t3 %s
+// RUN: %clang_cfi_diag -g -o %t3 %s
// RUN: %t3 2>&1 | FileCheck --check-prefix=CFI-DIAG %s
#include <stdio.h>
@@ -18,7 +18,7 @@ int main() {
fprintf(stderr, "1\n");
// CFI-DIAG: runtime error: control flow integrity check for type 'void (int)' failed during indirect function call
- // CFI-DIAG: f() defined here
+ // CFI-DIAG: f defined here
((void (*)(int))f)(42); // UB here
// CFI-NOT: 2
diff --git a/test/cfi/icall/external-call.c b/test/cfi/icall/external-call.c
index 43fc25207562..e90c7e042c27 100644
--- a/test/cfi/icall/external-call.c
+++ b/test/cfi/icall/external-call.c
@@ -1,4 +1,4 @@
-// RUN: %clangxx_cfi -o %t1 %s
+// RUN: %clang_cfi -lm -o %t1 %s
// RUN: %t1 c 1 2>&1 | FileCheck --check-prefix=CFI %s
// RUN: %t1 s 2 2>&1 | FileCheck --check-prefix=CFI %s
diff --git a/test/cfi/lit.cfg b/test/cfi/lit.cfg
index 687c80f4f08d..3c0250632f5b 100644
--- a/test/cfi/lit.cfg
+++ b/test/cfi/lit.cfg
@@ -7,14 +7,28 @@ config.test_source_root = os.path.dirname(__file__)
clangxx = ' '.join([config.clang] + config.cxx_mode_flags)
+config.substitutions.append((r"%clang ", ' '.join([config.clang]) + ' '))
config.substitutions.append((r"%clangxx ", clangxx + ' '))
if config.lto_supported:
- clangxx_cfi = ' '.join(config.lto_launch + [clangxx] + config.lto_flags + ['-flto -fsanitize=cfi '])
- clangxx_cfi_diag = clangxx_cfi + '-fno-sanitize-trap=cfi -fsanitize-recover=cfi '
- config.substitutions.append((r"%clangxx_cfi ", clangxx_cfi))
- config.substitutions.append((r"%clangxx_cfi_diag ", clangxx_cfi_diag))
- config.substitutions.append((r"%clangxx_cfi_dso ", clangxx_cfi + '-fsanitize-cfi-cross-dso '))
- config.substitutions.append((r"%clangxx_cfi_dso_diag ", clangxx_cfi_diag + '-fsanitize-cfi-cross-dso '))
+ clang_cfi = ' '.join(config.lto_launch + [config.clang] + config.lto_flags + ['-flto -fsanitize=cfi '])
+
+ if config.cfi_lit_test_mode == "Devirt":
+ config.available_features.add('devirt')
+ clang_cfi += '-fwhole-program-vtables '
+ config.substitutions.append((r"%expect_crash_unless_devirt ", ""))
+ else:
+ config.substitutions.append((r"%expect_crash_unless_devirt ", config.expect_crash))
+
+ cxx = ' '.join(config.cxx_mode_flags) + ' '
+ diag = '-fno-sanitize-trap=cfi -fsanitize-recover=cfi '
+ non_dso = '-fvisibility=hidden '
+ dso = '-fsanitize-cfi-cross-dso -fvisibility=default '
+ config.substitutions.append((r"%clang_cfi ", clang_cfi + non_dso))
+ config.substitutions.append((r"%clangxx_cfi ", clang_cfi + cxx + non_dso))
+ config.substitutions.append((r"%clang_cfi_diag ", clang_cfi + non_dso + diag))
+ config.substitutions.append((r"%clangxx_cfi_diag ", clang_cfi + cxx + non_dso + diag))
+ config.substitutions.append((r"%clangxx_cfi_dso ", clang_cfi + cxx + dso))
+ config.substitutions.append((r"%clangxx_cfi_dso_diag ", clang_cfi + cxx + dso + diag))
else:
config.unsupported = True
diff --git a/test/cfi/lit.site.cfg.in b/test/cfi/lit.site.cfg.in
index 76897e701874..87e5b51e7c02 100644
--- a/test/cfi/lit.site.cfg.in
+++ b/test/cfi/lit.site.cfg.in
@@ -1,2 +1,6 @@
+@LIT_SITE_CFG_IN_HEADER@
+
+config.cfi_lit_test_mode = "@CFI_LIT_TEST_MODE@"
+
lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/test/lit.common.configured")
lit_config.load_config(config, "@CMAKE_CURRENT_SOURCE_DIR@/lit.cfg")
diff --git a/test/cfi/overwrite.cpp b/test/cfi/overwrite.cpp
index 90f995d87bca..48c0a89c8f66 100644
--- a/test/cfi/overwrite.cpp
+++ b/test/cfi/overwrite.cpp
@@ -1,5 +1,5 @@
// RUN: %clangxx_cfi -o %t1 %s
-// RUN: %expect_crash %t1 2>&1 | FileCheck --check-prefix=CFI %s
+// RUN: %expect_crash_unless_devirt %t1 2>&1 | FileCheck --check-prefix=CFI %s
// RUN: %clangxx_cfi -DB32 -o %t2 %s
// RUN: %expect_crash %t2 2>&1 | FileCheck --check-prefix=CFI %s
@@ -55,7 +55,10 @@ int main() {
// CFI-DIAG-NEXT: note: invalid vtable
a->f();
- // CFI-NOT: {{^2$}}
+ // We don't check for the absence of a 2 here because under devirtualization
+ // our virtual call may be devirtualized and we will proceed with execution
+ // rather than crashing.
+
// NCFI: {{^2$}}
fprintf(stderr, "2\n");
}
diff --git a/test/cfi/stats.cpp b/test/cfi/stats.cpp
new file mode 100644
index 000000000000..566fcfbc2581
--- /dev/null
+++ b/test/cfi/stats.cpp
@@ -0,0 +1,52 @@
+// RUN: %clangxx_cfi -g -fsanitize-stats -o %t %s
+// RUN: env SANITIZER_STATS_PATH=%t.stats %t
+// RUN: sanstats %t.stats | FileCheck %s
+
+// FIXME: We currently emit the wrong debug info under devirtualization.
+// UNSUPPORTED: devirt
+
+struct ABase {};
+
+struct A : ABase {
+ virtual void vf() {}
+ void nvf() {}
+};
+
+extern "C" __attribute__((noinline)) void vcall(A *a) {
+ // CHECK: stats.cpp:[[@LINE+1]] {{_?}}vcall cfi-vcall 37
+ a->vf();
+}
+
+extern "C" __attribute__((noinline)) void nvcall(A *a) {
+ // CHECK: stats.cpp:[[@LINE+1]] {{_?}}nvcall cfi-nvcall 51
+ a->nvf();
+}
+
+extern "C" __attribute__((noinline)) A *dcast(A *a) {
+ // CHECK: stats.cpp:[[@LINE+1]] {{_?}}dcast cfi-derived-cast 24
+ return (A *)(ABase *)a;
+}
+
+extern "C" __attribute__((noinline)) A *ucast(A *a) {
+ // CHECK: stats.cpp:[[@LINE+1]] {{_?}}ucast cfi-unrelated-cast 81
+ return (A *)(char *)a;
+}
+
+extern "C" __attribute__((noinline)) void unreachable(A *a) {
+ // CHECK-NOT: unreachable
+ a->vf();
+}
+
+int main() {
+ A a;
+ for (unsigned i = 0; i != 37; ++i)
+ vcall(&a);
+ for (unsigned i = 0; i != 51; ++i)
+ nvcall(&a);
+ for (unsigned i = 0; i != 24; ++i)
+ dcast(&a);
+ for (unsigned i = 0; i != 81; ++i)
+ ucast(&a);
+ for (unsigned i = 0; i != 0; ++i)
+ unreachable(&a);
+}
diff --git a/test/cfi/target_uninstrumented.cpp b/test/cfi/target_uninstrumented.cpp
new file mode 100644
index 000000000000..2ec2b5bbc978
--- /dev/null
+++ b/test/cfi/target_uninstrumented.cpp
@@ -0,0 +1,44 @@
+// RUN: %clangxx -g -DSHARED_LIB %s -fPIC -shared -o %T/target_uninstrumented-so.so
+// RUN: %clangxx_cfi_diag -g %s -o %t %T/target_uninstrumented-so.so
+// RUN: %t 2>&1 | FileCheck %s
+
+// REQUIRES: cxxabi
+
+#include <stdio.h>
+#include <string.h>
+
+struct A {
+ virtual void f();
+};
+
+void *create_B();
+
+#ifdef SHARED_LIB
+
+struct B {
+ virtual void f();
+};
+void B::f() {}
+
+void *create_B() {
+ return (void *)(new B());
+}
+
+#else
+
+void A::f() {}
+
+int main(int argc, char *argv[]) {
+ void *p = create_B();
+ // CHECK: runtime error: control flow integrity check for type 'A' failed during cast to unrelated type
+ // CHECK: invalid vtable in module {{.*}}target_uninstrumented-so.so
+ A *a = (A *)p;
+ memset(p, 0, sizeof(A));
+ // CHECK: runtime error: control flow integrity check for type 'A' failed during cast to unrelated type
+ // CHECK-NOT: invalid vtable in module
+ // CHECK: invalid vtable
+ a = (A *)p;
+ // CHECK: done
+ fprintf(stderr, "done %p\n", a);
+}
+#endif
diff --git a/test/dfsan/CMakeLists.txt b/test/dfsan/CMakeLists.txt
index 3fa1af24be51..c2baf930d768 100644
--- a/test/dfsan/CMakeLists.txt
+++ b/test/dfsan/CMakeLists.txt
@@ -1,8 +1,33 @@
set(DFSAN_LIT_TESTS_DIR ${CMAKE_CURRENT_SOURCE_DIR})
-configure_lit_site_cfg(
- ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
- ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg)
+set(DFSAN_TESTSUITES)
+
+set(DFSAN_TEST_ARCH ${DFSAN_SUPPORTED_ARCH})
+if(APPLE)
+ darwin_filter_host_archs(DFSAN_SUPPORTED_ARCH DFSAN_TEST_ARCH)
+endif()
+
+foreach(arch ${DFSAN_TEST_ARCH})
+ set(DFSAN_TEST_TARGET_ARCH ${arch})
+ string(TOLOWER "-${arch}" DFSAN_TEST_CONFIG_SUFFIX)
+ if(ANDROID OR ${arch} MATCHES "arm|aarch64")
+ # This is only true if we are cross-compiling.
+ # Build all tests with host compiler and use host tools.
+ set(DFSAN_TEST_TARGET_CC ${COMPILER_RT_TEST_COMPILER})
+ set(DFSAN_TEST_TARGET_CFLAGS ${COMPILER_RT_TEST_COMPILER_CFLAGS})
+ else()
+ get_target_flags_for_arch(${arch} DFSAN_TEST_TARGET_CFLAGS)
+ string(REPLACE ";" " " DFSAN_TEST_TARGET_CFLAGS "${DFSAN_TEST_TARGET_CFLAGS}")
+ endif()
+
+ string(TOUPPER ${arch} ARCH_UPPER_CASE)
+ set(CONFIG_NAME ${ARCH_UPPER_CASE}Config)
+
+ configure_lit_site_cfg(
+ ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
+ ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}/lit.site.cfg)
+ list(APPEND DFSAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME})
+endforeach()
set(DFSAN_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS})
if(NOT COMPILER_RT_STANDALONE_BUILD)
@@ -10,6 +35,6 @@ if(NOT COMPILER_RT_STANDALONE_BUILD)
endif()
add_lit_testsuite(check-dfsan "Running the DataFlowSanitizer tests"
- ${CMAKE_CURRENT_BINARY_DIR}
+ ${DFSAN_TESTSUITES}
DEPENDS ${DFSAN_TEST_DEPS})
-set_target_properties(check-dfsan PROPERTIES FOLDER "DFSan tests")
+set_target_properties(check-dfsan PROPERTIES FOLDER "Compiler-RT Misc")
diff --git a/test/dfsan/custom.cc b/test/dfsan/custom.cc
index 057b0608e038..71422f7ce834 100644
--- a/test/dfsan/custom.cc
+++ b/test/dfsan/custom.cc
@@ -536,7 +536,7 @@ void test_inet_pton() {
int ret4 = inet_pton(AF_INET, addr4, &in4);
assert(ret4 == 1);
ASSERT_READ_LABEL(&in4, sizeof(in4), i_label);
- assert(in4.s_addr == 0x0100007f);
+ assert(in4.s_addr == htonl(0x7f000001));
char addr6[] = "::1";
dfsan_set_label(j_label, addr6 + 3, 1);
diff --git a/test/dfsan/lit.cfg b/test/dfsan/lit.cfg
index e4d4e8f57af9..6dc0f9c45d10 100644
--- a/test/dfsan/lit.cfg
+++ b/test/dfsan/lit.cfg
@@ -3,13 +3,13 @@
import os
# Setup config name.
-config.name = 'DataFlowSanitizer'
+config.name = 'DataFlowSanitizer' + config.name_suffix
# Setup source root.
config.test_source_root = os.path.dirname(__file__)
# Setup default compiler flags used with -fsanitize=dataflow option.
-clang_dfsan_cflags = ["-fsanitize=dataflow", "-m64"]
+clang_dfsan_cflags = ["-fsanitize=dataflow", config.target_cflags]
clang_dfsan_cxxflags = config.cxx_mode_flags + clang_dfsan_cflags
def build_invocation(compile_flags):
diff --git a/test/dfsan/lit.site.cfg.in b/test/dfsan/lit.site.cfg.in
index 859284eca140..927ba11418ea 100644
--- a/test/dfsan/lit.site.cfg.in
+++ b/test/dfsan/lit.site.cfg.in
@@ -1,3 +1,10 @@
+@LIT_SITE_CFG_IN_HEADER@
+
+# Tool-specific config options.
+config.name_suffix = "@DFSAN_TEST_CONFIG_SUFFIX@"
+config.target_cflags = "@DFSAN_TEST_TARGET_CFLAGS@"
+config.target_arch = "@DFSAN_TEST_TARGET_ARCH@"
+
# Load common config for all compiler-rt lit tests.
lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/test/lit.common.configured")
diff --git a/test/esan/CMakeLists.txt b/test/esan/CMakeLists.txt
new file mode 100644
index 000000000000..bbdcd51af786
--- /dev/null
+++ b/test/esan/CMakeLists.txt
@@ -0,0 +1,32 @@
+set(ESAN_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS})
+if(NOT COMPILER_RT_STANDALONE_BUILD)
+ list(APPEND ESAN_TEST_DEPS esan)
+endif()
+
+set(ESAN_TESTSUITES)
+
+set(ESAN_TEST_ARCH ${ESAN_SUPPORTED_ARCH})
+
+set(ESAN_LIT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
+
+foreach(arch ${ESAN_TEST_ARCH})
+ set(ESAN_TEST_TARGET_ARCH ${arch})
+ string(TOLOWER "-${arch}" ESAN_TEST_CONFIG_SUFFIX)
+ get_target_flags_for_arch(${arch} ESAN_TEST_TARGET_CFLAGS)
+ string(REPLACE ";" " " ESAN_TEST_TARGET_CFLAGS "${ESAN_TEST_TARGET_CFLAGS}")
+
+ string(TOUPPER ${arch} ARCH_UPPER_CASE)
+ set(CONFIG_NAME ${ARCH_UPPER_CASE}Config)
+
+ configure_lit_site_cfg(
+ ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
+ ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}/lit.site.cfg)
+ list(APPEND ESAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME})
+endforeach()
+
+# TODO(bruening): add Unit/ tests as well
+
+add_lit_testsuite(check-esan "Running EfficiencySanitizer tests"
+ ${ESAN_TESTSUITES}
+ DEPENDS ${ESAN_TEST_DEPS})
+set_target_properties(check-esan PROPERTIES FOLDER "Compiler-RT Misc")
diff --git a/test/esan/TestCases/large-stack-linux.c b/test/esan/TestCases/large-stack-linux.c
new file mode 100644
index 000000000000..3e024fc4e900
--- /dev/null
+++ b/test/esan/TestCases/large-stack-linux.c
@@ -0,0 +1,74 @@
+// RUN: %clang_esan_wset -O0 %s -o %t 2>&1
+// RUN: %env_esan_opts="verbosity=1 record_snapshots=0" %run %t %t 2>&1 | FileCheck %s
+
+#include <assert.h>
+#include <stdio.h>
+#include <sys/mman.h>
+#include <sys/resource.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+static void testChildStackLimit(rlim_t StackLimit, char *ToRun) {
+ int Res;
+ struct rlimit Limit;
+ Limit.rlim_cur = RLIM_INFINITY;
+ Limit.rlim_max = RLIM_INFINITY;
+ Res = setrlimit(RLIMIT_STACK, &Limit);
+ if (Res != 0) {
+ // Probably our environment had a large limit and we ourselves got
+ // re-execed and can no longer raise our limit.
+ // We have to bail and emulate the regular test.
+ // We'd prefer to have branches in our FileCheck output to ensure the
+ // initial program was re-execed but this is the best we can do for now.
+ fprintf(stderr, "in esan::initializeLibrary\n");
+ fprintf(stderr, "==1234==The stack size limit is beyond the maximum supported.\n");
+ fprintf(stderr, "Re-execing with a stack size below 1TB.\n");
+ fprintf(stderr, "in esan::initializeLibrary\n");
+ fprintf(stderr, "done\n");
+ fprintf(stderr, "in esan::finalizeLibrary\n");
+ return;
+ }
+
+ pid_t Child = fork();
+ assert(Child >= 0);
+ if (Child > 0) {
+ pid_t WaitRes = waitpid(Child, NULL, 0);
+ assert(WaitRes == Child);
+ } else {
+ char *Args[2];
+ Args[0] = ToRun;
+ Args[1] = NULL;
+ Res = execv(ToRun, Args);
+ assert(0); // Should not be reached.
+ }
+}
+
+int main(int argc, char *argv[]) {
+ // The path to the program to exec must be passed in the first time.
+ if (argc == 2) {
+ fprintf(stderr, "Testing child with infinite stack\n");
+ testChildStackLimit(RLIM_INFINITY, argv[1]);
+ fprintf(stderr, "Testing child with 1TB stack\n");
+ testChildStackLimit(1ULL << 40, argv[1]);
+ }
+ fprintf(stderr, "done\n");
+ // CHECK: in esan::initializeLibrary
+ // CHECK: Testing child with infinite stack
+ // CHECK-NEXT: in esan::initializeLibrary
+ // CHECK-NEXT: =={{[0-9]+}}==The stack size limit is beyond the maximum supported.
+ // CHECK-NEXT: Re-execing with a stack size below 1TB.
+ // CHECK-NEXT: in esan::initializeLibrary
+ // CHECK: done
+ // CHECK: in esan::finalizeLibrary
+ // CHECK: Testing child with 1TB stack
+ // CHECK-NEXT: in esan::initializeLibrary
+ // CHECK-NEXT: =={{[0-9]+}}==The stack size limit is beyond the maximum supported.
+ // CHECK-NEXT: Re-execing with a stack size below 1TB.
+ // CHECK-NEXT: in esan::initializeLibrary
+ // CHECK: done
+ // CHECK-NEXT: in esan::finalizeLibrary
+ // CHECK: done
+ // CHECK-NEXT: in esan::finalizeLibrary
+ return 0;
+}
diff --git a/test/esan/TestCases/libc-intercept.c b/test/esan/TestCases/libc-intercept.c
new file mode 100644
index 000000000000..8d8d81f0bd03
--- /dev/null
+++ b/test/esan/TestCases/libc-intercept.c
@@ -0,0 +1,20 @@
+// RUN: %clang_esan_frag -O0 %s -o %t 2>&1
+// RUN: %env_esan_opts=verbosity=3 %run %t 2>&1 | FileCheck %s
+
+#include <string.h>
+
+int main(int argc, char **argv) {
+ char Buf[2048];
+ const char Str[] = "TestStringOfParticularLength"; // 29 chars.
+ strcpy(Buf, Str);
+ strncpy(Buf, Str, 17);
+ return strncmp(Buf, Str, 17);
+ // CHECK: in esan::initializeLibrary
+ // CHECK: in esan::processRangeAccess {{.*}} 29
+ // CHECK: in esan::processRangeAccess {{.*}} 29
+ // CHECK: in esan::processRangeAccess {{.*}} 17
+ // CHECK: in esan::processRangeAccess {{.*}} 17
+ // CHECK: in esan::processRangeAccess {{.*}} 17
+ // CHECK: in esan::processRangeAccess {{.*}} 17
+ // CHECK: in esan::finalizeLibrary
+}
diff --git a/test/esan/TestCases/mmap-shadow-conflict.c b/test/esan/TestCases/mmap-shadow-conflict.c
new file mode 100644
index 000000000000..4b3c58b06825
--- /dev/null
+++ b/test/esan/TestCases/mmap-shadow-conflict.c
@@ -0,0 +1,30 @@
+// RUN: %clang_esan_frag -O0 %s -o %t 2>&1
+// RUN: %env_esan_opts=verbosity=1 %run %t 2>&1 | FileCheck %s
+
+#include <unistd.h>
+#include <sys/mman.h>
+#include <stdio.h>
+
+int main(int argc, char **argv) {
+ void *Map = mmap((void *)0x0000016000000000ULL, 0x1000, PROT_READ,
+ MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0);
+ if (Map == (void *)-1)
+ fprintf(stderr, "map failed\n");
+ else
+ fprintf(stderr, "mapped %p\n", Map);
+ Map = mmap((void *)0x0000016000000000ULL, 0x1000, PROT_READ,
+ MAP_ANON|MAP_PRIVATE, -1, 0);
+ fprintf(stderr, "mapped %p\n", Map);
+ // CHECK: in esan::initializeLibrary
+ // (There can be a re-exec for stack limit here.)
+ // CHECK: Shadow scale=2 offset=0x440000000000
+ // CHECK-NEXT: Shadow #0: [110000000000-114000000000) (256GB)
+ // CHECK-NEXT: Shadow #1: [124000000000-12c000000000) (512GB)
+ // CHECK-NEXT: Shadow #2: [148000000000-150000000000) (512GB)
+ // CHECK-NEXT: mmap conflict: {{.*}}
+ // CHECK-NEXT: map failed
+ // CHECK-NEXT: mmap conflict: {{.*}}
+ // CHECK-NEXT: mapped {{.*}}
+ // CHECK-NEXT: in esan::finalizeLibrary
+ return 0;
+}
diff --git a/test/esan/TestCases/struct-simple.cpp b/test/esan/TestCases/struct-simple.cpp
new file mode 100644
index 000000000000..c52154e09421
--- /dev/null
+++ b/test/esan/TestCases/struct-simple.cpp
@@ -0,0 +1,204 @@
+// RUN: %clang_esan_frag -O0 %s -DPART1 -mllvm -esan-aux-field-info=0 -c -o %t-part1.o 2>&1
+// RUN: %clang_esan_frag -O0 %s -DPART2 -c -o %t-part2.o 2>&1
+// RUN: %clang_esan_frag -O0 %s -DMAIN -c -o %t-main.o 2>&1
+// RUN: %clang_esan_frag -O0 %t-part1.o %t-part2.o %t-main.o -o %t 2>&1
+// RUN: %env_esan_opts=verbosity=2 %run %t 2>&1 | FileCheck %s
+
+// We generate two different object files from this file with different
+// macros, and then link them together. We do this to test how we handle
+// separate compilation with multiple compilation units.
+
+#include <stdio.h>
+
+extern "C" {
+ void part1();
+ void part2();
+}
+
+//===-- compilation unit part1 without main function ----------------------===//
+
+#ifdef PART1
+struct A {
+ int x;
+ int y;
+};
+
+struct B {
+ float m;
+ double n;
+};
+
+union U {
+ float f;
+ double d;
+};
+
+// Same struct in both main and part1.
+struct S {
+ int s1;
+ int s2;
+};
+
+// Different structs with the same name in main and part1.
+struct D {
+ int d1;
+ int d2;
+ struct {
+ int x;
+ int y;
+ int z;
+ } ds[10];
+};
+
+void part1()
+{
+ struct A a;
+ struct B b;
+ union U u;
+ struct S s;
+ struct D d;
+ for (int i = 0; i < (1 << 11); i++)
+ a.x = 0;
+ a.y = 1;
+ b.m = 2.0;
+ for (int i = 0; i < (1 << 21); i++) {
+ b.n = 3.0;
+ d.ds[3].y = 0;
+ }
+ u.f = 0.0;
+ u.d = 1.0;
+ s.s1 = 0;
+ d.d1 = 0;
+}
+#endif // PART1
+
+//===-- compilation unit part2 without main function ----------------------===//
+#ifdef PART2
+// No struct in this part.
+void part2()
+{
+ // do nothing
+}
+#endif // PART2
+
+//===-- compilation unit with main function -------------------------------===//
+
+#ifdef MAIN
+class C {
+public:
+ struct {
+ int x;
+ int y;
+ } cs;
+ union {
+ float f;
+ double d;
+ } cu;
+ char c[10];
+};
+
+// Same struct in both main and part1.
+struct S {
+ int s1;
+ int s2;
+};
+
+// Different structs with the same name in main and part1.
+struct D {
+ int d1;
+ int d2;
+ int d3;
+};
+
+int main(int argc, char **argv) {
+ // CHECK: in esan::initializeLibrary
+ // CHECK: in esan::initializeCacheFrag
+ // CHECK-NEXT: in esan::processCompilationUnitInit
+ // CHECK-NEXT: in esan::processCacheFragCompilationUnitInit: {{.*}}struct-simple.cpp with 6 class(es)/struct(s)
+ // CHECK-NEXT: Register struct.A#2#11#11: 2 fields
+ // CHECK-NEXT: Register struct.B#2#3#2: 2 fields
+ // CHECK-NEXT: Register union.U#1#3: 1 fields
+ // CHECK-NEXT: Register struct.S#2#11#11: 2 fields
+ // CHECK-NEXT: Register struct.D#3#14#11#11: 3 fields
+ // CHECK-NEXT: Register struct.anon#3#11#11#11: 3 fields
+ // CHECK-NEXT: in esan::processCompilationUnitInit
+ // CHECK-NEXT: in esan::processCacheFragCompilationUnitInit: {{.*}}struct-simple.cpp with 0 class(es)/struct(s)
+ // CHECK-NEXT: in esan::processCompilationUnitInit
+ // CHECK-NEXT: in esan::processCacheFragCompilationUnitInit: {{.*}}struct-simple.cpp with 5 class(es)/struct(s)
+ // CHECK-NEXT: Register class.C#3#14#13#13: 3 fields
+ // CHECK-NEXT: Register struct.anon#2#11#11: 2 fields
+ // CHECK-NEXT: Register union.anon#1#3: 1 fields
+ // CHECK-NEXT: Duplicated struct.S#2#11#11: 2 fields
+ // CHECK-NEXT: Register struct.D#3#11#11#11: 3 fields
+ struct C c[2];
+ struct S s;
+ struct D d;
+ c[0].cs.x = 0;
+ c[1].cs.y = 1;
+ c[0].cu.f = 0.0;
+ c[1].cu.d = 1.0;
+ c[0].c[2] = 0;
+ s.s1 = 0;
+ d.d1 = 0;
+ d.d2 = 0;
+ part1();
+ part2();
+ return 0;
+ // CHECK: in esan::finalizeLibrary
+ // CHECK-NEXT: in esan::finalizeCacheFrag
+ // CHECK-NEXT: in esan::processCompilationUnitExit
+ // CHECK-NEXT: in esan::processCacheFragCompilationUnitExit: {{.*}}struct-simple.cpp with 5 class(es)/struct(s)
+ // CHECK-NEXT: Unregister class.C#3#14#13#13: 3 fields
+ // CHECK-NEXT: {{.*}} class C
+ // CHECK-NEXT: {{.*}} size = 32, count = 5, ratio = 3, array access = 5
+ // CHECK-NEXT: {{.*}} # 0: offset = 0, size = 8, count = 2, type = %struct.anon = type { i32, i32 }
+ // CHECK-NEXT: {{.*}} # 1: offset = 8, size = 8, count = 2, type = %union.anon = type { double }
+ // CHECK-NEXT: {{.*}} # 2: offset = 16, size = 10, count = 1, type = [10 x i8]
+ // CHECK-NEXT: Unregister struct.anon#2#11#11: 2 fields
+ // CHECK-NEXT: {{.*}} struct anon
+ // CHECK-NEXT: {{.*}} size = 8, count = 2, ratio = 1, array access = 0
+ // CHECK-NEXT: {{.*}} # 0: offset = 0, size = 4, count = 1, type = i32
+ // CHECK-NEXT: {{.*}} # 1: offset = 4, size = 4, count = 1, type = i32
+ // CHECK-NEXT: Unregister union.anon#1#3: 1 fields
+ // CHECK-NEXT: Unregister struct.S#2#11#11: 2 fields
+ // CHECK-NEXT: {{.*}} struct S
+ // CHECK-NEXT: {{.*}} size = 8, count = 2, ratio = 2, array access = 0
+ // CHECK-NEXT: {{.*}} # 0: count = 2
+ // CHECK-NEXT: {{.*}} # 1: count = 0
+ // CHECK-NEXT: Unregister struct.D#3#11#11#11: 3 fields
+ // CHECK-NEXT: {{.*}} struct D
+ // CHECK-NEXT: {{.*}} size = 12, count = 2, ratio = 2, array access = 0
+ // CHECK-NEXT: {{.*}} # 0: offset = 0, size = 4, count = 1, type = i32
+ // CHECK-NEXT: {{.*}} # 1: offset = 4, size = 4, count = 1, type = i32
+ // CHECK-NEXT: {{.*}} # 2: offset = 8, size = 4, count = 0, type = i32
+ // CHECK-NEXT: in esan::processCompilationUnitExit
+ // CHECK-NEXT: in esan::processCacheFragCompilationUnitExit: {{.*}}struct-simple.cpp with 0 class(es)/struct(s)
+ // CHECK-NEXT: in esan::processCompilationUnitExit
+ // CHECK-NEXT: in esan::processCacheFragCompilationUnitExit: {{.*}}struct-simple.cpp with 6 class(es)/struct(s)
+ // CHECK-NEXT: Unregister struct.A#2#11#11: 2 fields
+ // CHECK-NEXT: {{.*}} struct A
+ // CHECK-NEXT: {{.*}} size = 8, count = 2049, ratio = 2048, array access = 0
+ // CHECK-NEXT: {{.*}} # 0: count = 2048
+ // CHECK-NEXT: {{.*}} # 1: count = 1
+ // CHECK-NEXT: Unregister struct.B#2#3#2: 2 fields
+ // CHECK-NEXT: {{.*}} struct B
+ // CHECK-NEXT: {{.*}} size = 16, count = 2097153, ratio = 2097152, array access = 0
+ // CHECK-NEXT: {{.*}} # 0: count = 1
+ // CHECK-NEXT: {{.*}} # 1: count = 2097152
+ // CHECK-NEXT: Unregister union.U#1#3: 1 fields
+ // CHECK-NEXT: Duplicated struct.S#2#11#11: 2 fields
+ // CHECK-NEXT: Unregister struct.D#3#14#11#11: 3 fields
+ // CHECK-NEXT: {{.*}} struct D
+ // CHECK-NEXT: {{.*}} size = 128, count = 2097153, ratio = 2097153, array access = 0
+ // CHECK-NEXT: {{.*}} # 0: count = 1
+ // CHECK-NEXT: {{.*}} # 1: count = 0
+ // CHECK-NEXT: {{.*}} # 2: count = 2097152
+ // CHECK-NEXT: Unregister struct.anon#3#11#11#11: 3 fields
+ // CHECK-NEXT: {{.*}} struct anon
+ // CHECK-NEXT: {{.*}} size = 12, count = 2097152, ratio = 4194304, array access = 2097152
+ // CHECK-NEXT: {{.*}} # 0: count = 0
+ // CHECK-NEXT: {{.*}} # 1: count = 2097152
+ // CHECK-NEXT: {{.*}} # 2: count = 0
+ // CHECK-NEXT: {{.*}}EfficiencySanitizer: total struct field access count = 6293518
+}
+#endif // MAIN
diff --git a/test/esan/TestCases/verbose-simple.c b/test/esan/TestCases/verbose-simple.c
new file mode 100644
index 000000000000..0d867bf55d9e
--- /dev/null
+++ b/test/esan/TestCases/verbose-simple.c
@@ -0,0 +1,14 @@
+// RUN: %clang_esan_frag -O0 %s -o %t 2>&1
+// RUN: %env_esan_opts="verbosity=1 log_exe_name=1" %run %t 2>&1 | FileCheck %s
+
+int main(int argc, char **argv) {
+ // CHECK: in esan::initializeLibrary
+ // (There can be a re-exec for stack limit here.)
+ // CHECK: Shadow scale=2 offset=0x440000000000
+ // CHECK-NEXT: Shadow #0: [110000000000-114000000000) (256GB)
+ // CHECK-NEXT: Shadow #1: [124000000000-12c000000000) (512GB)
+ // CHECK-NEXT: Shadow #2: [148000000000-150000000000) (512GB)
+ // CHECK-NEXT: in esan::finalizeLibrary
+ // CHECK-NEXT: ==verbose-simple{{.*}}EfficiencySanitizer: total struct field access count = 0
+ return 0;
+}
diff --git a/test/esan/TestCases/workingset-early-fault.c b/test/esan/TestCases/workingset-early-fault.c
new file mode 100644
index 000000000000..1c420c368ca9
--- /dev/null
+++ b/test/esan/TestCases/workingset-early-fault.c
@@ -0,0 +1,33 @@
+// Test shadow faults during esan initialization as well as
+// faults during dlsym's calloc during interceptor init.
+//
+// RUN: %clang_esan_wset %s -o %t
+// RUN: %run %t 2>&1 | FileCheck %s
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+// Our goal is to emulate an instrumented allocator, whose calloc
+// invoked from dlsym will trigger shadow faults, to test an
+// early shadow fault during esan interceptor init.
+// We do this by replacing calloc:
+void *calloc(size_t size, size_t n) {
+ // Unfortunately we can't print anything to make the test
+ // ensure we got here b/c the sanitizer interceptors can't
+ // handle that during interceptor init.
+
+ // Ensure we trigger a shadow write fault:
+ int x[16];
+ x[0] = size;
+ // Now just emulate calloc.
+ void *res = malloc(size*n);
+ memset(res, 0, size*n);
+ return res;
+}
+
+int main(int argc, char **argv) {
+ printf("all done\n");
+ return 0;
+}
+// CHECK: all done
diff --git a/test/esan/TestCases/workingset-memset.cpp b/test/esan/TestCases/workingset-memset.cpp
new file mode 100644
index 000000000000..9c972ec7a738
--- /dev/null
+++ b/test/esan/TestCases/workingset-memset.cpp
@@ -0,0 +1,20 @@
+// RUN: %clang_esan_wset -O0 %s -o %t 2>&1
+// RUN: %run %t 2>&1 | FileCheck %s
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <assert.h>
+#include <string.h>
+
+int main(int argc, char **argv) {
+ const int size = 128*1024*1024;
+ char *p = (char *)mmap(0, size, PROT_READ | PROT_WRITE,
+ MAP_ANON | MAP_PRIVATE, -1, 0);
+ // Test the slowpath at different cache line boundaries.
+ for (int i = 0; i < 630; i++)
+ memset((char *)p + 63*i, i, 63*i);
+ munmap(p, size);
+ return 0;
+ // CHECK: {{.*}} EfficiencySanitizer: the total working set size: 77 KB (12{{[0-9]+}} cache lines)
+}
diff --git a/test/esan/TestCases/workingset-midreport.cpp b/test/esan/TestCases/workingset-midreport.cpp
new file mode 100644
index 000000000000..2c29cf48ccf7
--- /dev/null
+++ b/test/esan/TestCases/workingset-midreport.cpp
@@ -0,0 +1,71 @@
+// RUN: %clang_esan_wset -O0 %s -o %t 2>&1
+// RUN: %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-ESAN
+
+// RUN: %clang -O0 %s -o %t 2>&1
+// RUN: %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-NO-ESAN
+
+#include <sanitizer/esan_interface.h>
+#include <sched.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+
+const int size = 0x1 << 25; // 523288 cache lines
+const int iters = 6;
+
+int main(int argc, char **argv) {
+ char *buf = (char *)mmap(0, size, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ // To avoid flakiness stemming from whether the sideline thread
+ // is scheduled enough on a loaded test machine, we coordinate
+ // with esan itself:
+ if (__esan_get_sample_count) {
+ while (__esan_get_sample_count() < 4) {
+ for (int i = 0; i < size; ++i)
+ buf[i] = i;
+ sched_yield();
+ }
+ }
+ // Ensure a non-esan build works without ifdefs:
+ if (__esan_report) {
+ // We should get 2 roughly identical reports:
+ __esan_report();
+ }
+ munmap(buf, size);
+ fprintf(stderr, "all done\n");
+ // CHECK-NO-ESAN: all done
+ // We only check for a few samples here to reduce the chance of flakiness:
+ // CHECK-ESAN: =={{[0-9]+}}== Total number of samples: {{[0-9]+}}
+ // CHECK-ESAN-NEXT: =={{[0-9]+}}== Samples array #0 at period 20 ms
+ // CHECK-ESAN-NEXT: =={{[0-9]+}}==# 0: {{[ 0-9]+}} {{KB|MB|Bytes}} ({{[ 0-9]+}} cache lines)
+ // CHECK-ESAN-NEXT: =={{[0-9]+}}==# 1: {{[ 0-9]+}} {{KB|MB|Bytes}} ({{[ 0-9]+}} cache lines)
+ // CHECK-ESAN-NEXT: =={{[0-9]+}}==# 2: {{[ 0-9]+}} {{KB|MB|Bytes}} ({{[ 0-9]+}} cache lines)
+ // CHECK-ESAN-NEXT: =={{[0-9]+}}==# 3: {{[ 0-9]+}} {{KB|MB|Bytes}} ({{[ 0-9]+}} cache lines)
+ // CHECK-ESAN: =={{[0-9]+}}== Samples array #1 at period 80 ms
+ // CHECK-ESAN-NEXT: =={{[0-9]+}}==# 0: {{[ 0-9]+}} {{KB|MB|Bytes}} ({{[ 0-9]+}} cache lines)
+ // CHECK-ESAN: =={{[0-9]+}}== Samples array #2 at period 320 ms
+ // CHECK-ESAN: =={{[0-9]+}}== Samples array #3 at period 1280 ms
+ // CHECK-ESAN: =={{[0-9]+}}== Samples array #4 at period 5120 ms
+ // CHECK-ESAN: =={{[0-9]+}}== Samples array #5 at period 20 sec
+ // CHECK-ESAN: =={{[0-9]+}}== Samples array #6 at period 81 sec
+ // CHECK-ESAN: =={{[0-9]+}}== Samples array #7 at period 327 sec
+ // CHECK-ESAN: {{.*}} EfficiencySanitizer: the total working set size: 32 MB (5242{{[0-9][0-9]}} cache lines)
+ // CHECK-ESAN-NEXT: all done
+ // CHECK-ESAN-NEXT: =={{[0-9]+}}== Total number of samples: {{[0-9]+}}
+ // CHECK-ESAN-NEXT: =={{[0-9]+}}== Samples array #0 at period 20 ms
+ // CHECK-ESAN-NEXT: =={{[0-9]+}}==# 0: {{[ 0-9]+}} {{KB|MB|Bytes}} ({{[ 0-9]+}} cache lines)
+ // CHECK-ESAN-NEXT: =={{[0-9]+}}==# 1: {{[ 0-9]+}} {{KB|MB|Bytes}} ({{[ 0-9]+}} cache lines)
+ // CHECK-ESAN-NEXT: =={{[0-9]+}}==# 2: {{[ 0-9]+}} {{KB|MB|Bytes}} ({{[ 0-9]+}} cache lines)
+ // CHECK-ESAN-NEXT: =={{[0-9]+}}==# 3: {{[ 0-9]+}} {{KB|MB|Bytes}} ({{[ 0-9]+}} cache lines)
+ // CHECK-ESAN: =={{[0-9]+}}== Samples array #1 at period 80 ms
+ // CHECK-ESAN-NEXT: =={{[0-9]+}}==# 0: {{[ 0-9]+}} {{KB|MB|Bytes}} ({{[ 0-9]+}} cache lines)
+ // CHECK-ESAN: =={{[0-9]+}}== Samples array #2 at period 320 ms
+ // CHECK-ESAN: =={{[0-9]+}}== Samples array #3 at period 1280 ms
+ // CHECK-ESAN: =={{[0-9]+}}== Samples array #4 at period 5120 ms
+ // CHECK-ESAN: =={{[0-9]+}}== Samples array #5 at period 20 sec
+ // CHECK-ESAN: =={{[0-9]+}}== Samples array #6 at period 81 sec
+ // CHECK-ESAN: =={{[0-9]+}}== Samples array #7 at period 327 sec
+ // CHECK-ESAN: {{.*}} EfficiencySanitizer: the total working set size: 32 MB (5242{{[0-9][0-9]}} cache lines)
+ return 0;
+}
diff --git a/test/esan/TestCases/workingset-samples.cpp b/test/esan/TestCases/workingset-samples.cpp
new file mode 100644
index 000000000000..cf198d2f39ef
--- /dev/null
+++ b/test/esan/TestCases/workingset-samples.cpp
@@ -0,0 +1,44 @@
+// RUN: %clang_esan_wset -O0 %s -o %t 2>&1
+// RUN: %run %t 2>&1 | FileCheck %s
+
+#include <sanitizer/esan_interface.h>
+#include <sched.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+
+const int size = 0x1 << 25; // 523288 cache lines
+const int iters = 6;
+
+int main(int argc, char **argv) {
+ char *buf = (char *)mmap(0, size, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ // To avoid flakiness stemming from whether the sideline thread
+ // is scheduled enough on a loaded test machine, we coordinate
+ // with esan itself:
+ if (__esan_get_sample_count) {
+ while (__esan_get_sample_count() < 4) {
+ for (int i = 0; i < size; ++i)
+ buf[i] = i;
+ sched_yield();
+ }
+ }
+ munmap(buf, size);
+ // We only check for a few samples here to reduce the chance of flakiness.
+ // CHECK: =={{[0-9]+}}== Total number of samples: {{[0-9]+}}
+ // CHECK-NEXT: =={{[0-9]+}}== Samples array #0 at period 20 ms
+ // CHECK-NEXT: =={{[0-9]+}}==# 0: {{[ 0-9]+}} {{KB|MB|Bytes}} ({{[ 0-9]+}} cache lines)
+ // CHECK-NEXT: =={{[0-9]+}}==# 1: {{[ 0-9]+}} {{KB|MB|Bytes}} ({{[ 0-9]+}} cache lines)
+ // CHECK-NEXT: =={{[0-9]+}}==# 2: {{[ 0-9]+}} {{KB|MB|Bytes}} ({{[ 0-9]+}} cache lines)
+ // CHECK-NEXT: =={{[0-9]+}}==# 3: {{[ 0-9]+}} {{KB|MB|Bytes}} ({{[ 0-9]+}} cache lines)
+ // CHECK: =={{[0-9]+}}== Samples array #1 at period 80 ms
+ // CHECK-NEXT: =={{[0-9]+}}==# 0: {{[ 0-9]+}} {{KB|MB|Bytes}} ({{[ 0-9]+}} cache lines)
+ // CHECK: =={{[0-9]+}}== Samples array #2 at period 320 ms
+ // CHECK: =={{[0-9]+}}== Samples array #3 at period 1280 ms
+ // CHECK: =={{[0-9]+}}== Samples array #4 at period 5120 ms
+ // CHECK: =={{[0-9]+}}== Samples array #5 at period 20 sec
+ // CHECK: =={{[0-9]+}}== Samples array #6 at period 81 sec
+ // CHECK: =={{[0-9]+}}== Samples array #7 at period 327 sec
+ // CHECK: {{.*}} EfficiencySanitizer: the total working set size: 32 MB (5242{{[0-9][0-9]}} cache lines)
+ return 0;
+}
diff --git a/test/esan/TestCases/workingset-signal-posix.cpp b/test/esan/TestCases/workingset-signal-posix.cpp
new file mode 100644
index 000000000000..ba776fc02ed8
--- /dev/null
+++ b/test/esan/TestCases/workingset-signal-posix.cpp
@@ -0,0 +1,75 @@
+// RUN: %clang_esan_wset -O0 %s -o %t 2>&1
+// RUN: %run %t 2>&1 | FileCheck %s
+
+#include <assert.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+
+sigjmp_buf mark;
+
+static void SignalHandler(int Sig) {
+ if (Sig == SIGSEGV) {
+ fprintf(stderr, "Handling SIGSEGV for signal\n");
+ siglongjmp(mark, 1);
+ }
+ exit(1);
+}
+
+static void SigactionHandler(int Sig, siginfo_t *Info, void *Ctx) {
+ if (Sig == SIGSEGV) {
+ fprintf(stderr, "Handling SIGSEGV for sigaction\n");
+ siglongjmp(mark, 1);
+ }
+ exit(1);
+}
+
+int main(int argc, char **argv) {
+ __sighandler_t Prior = signal(SIGSEGV, SignalHandler);
+ assert(Prior == SIG_DFL);
+ if (sigsetjmp(mark, 1) == 0)
+ *((volatile int *)(ssize_t)argc) = 42; // Raise SIGSEGV
+ fprintf(stderr, "Past longjmp for signal\n");
+
+ Prior = signal(SIGSEGV, SIG_DFL);
+ assert(Prior == SignalHandler);
+
+ struct sigaction SigAct;
+ SigAct.sa_sigaction = SigactionHandler;
+ int Res = sigfillset(&SigAct.sa_mask);
+ assert(Res == 0);
+ SigAct.sa_flags = SA_SIGINFO;
+ Res = sigaction(SIGSEGV, &SigAct, NULL);
+ assert(Res == 0);
+
+ if (sigsetjmp(mark, 1) == 0)
+ *((volatile int *)(ssize_t)argc) = 42; // Raise SIGSEGV
+ fprintf(stderr, "Past longjmp for sigaction\n");
+
+ Res = sigaction(SIGSEGV, NULL, &SigAct);
+ assert(Res == 0);
+ assert(SigAct.sa_sigaction == SigactionHandler);
+
+ // Test blocking SIGSEGV and raising a shadow fault.
+ sigset_t Set;
+ sigemptyset(&Set);
+ sigaddset(&Set, SIGSEGV);
+ Res = sigprocmask(SIG_BLOCK, &Set, NULL);
+ // Make a large enough mapping that its start point will be before any
+ // prior library-region shadow access.
+ char *buf = (char *)mmap(0, 640*1024, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ buf[0] = 4;
+ munmap(buf, 640*1024);
+ fprintf(stderr, "Past blocked-SIGSEGV shadow fault\n");
+
+ return 0;
+}
+// CHECK: Handling SIGSEGV for signal
+// CHECK-NEXT: Past longjmp for signal
+// CHECK-NEXT: Handling SIGSEGV for sigaction
+// CHECK-NEXT: Past longjmp for sigaction
+// CHECK-NEXT: Past blocked-SIGSEGV shadow fault
+// CHECK: {{.*}} EfficiencySanitizer: the total working set size: {{[0-9]+}} Bytes ({{[0-9][0-9]}} cache lines)
diff --git a/test/esan/TestCases/workingset-simple.cpp b/test/esan/TestCases/workingset-simple.cpp
new file mode 100644
index 000000000000..c8a2d52e7b55
--- /dev/null
+++ b/test/esan/TestCases/workingset-simple.cpp
@@ -0,0 +1,30 @@
+// RUN: %clang_esan_wset -O0 %s -o %t 2>&1
+// RUN: %run %t 2>&1 | FileCheck %s
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <assert.h>
+
+const int size = 0x1 << 25; // 523288 cache lines
+const int line_size = 64;
+
+int main(int argc, char **argv) {
+ char *bufA = (char *)malloc(sizeof(char) * line_size);
+ char bufB[64];
+ char *bufC = (char *)mmap(0, size, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ bufA[0] = 0;
+ // This additional access to the same line should not increase the line
+ // count: but it's difficult to make a non-flaky test that measures the
+ // lines down to the ones digit so right now we're not really testing that.
+ // If we add a heap-only mode we may be able to be more precise.
+ bufA[1] = 0;
+ bufB[33] = 1;
+ for (int i = 0; i < size; i += line_size)
+ bufC[i] = 0;
+ free(bufA);
+ munmap(bufC, 0x4000);
+ // CHECK: {{.*}} EfficiencySanitizer: the total working set size: 32 MB (524{{[0-9][0-9][0-9]}} cache lines)
+ return 0;
+}
diff --git a/test/esan/Unit/circular_buffer.cpp b/test/esan/Unit/circular_buffer.cpp
new file mode 100644
index 000000000000..00999a2724c6
--- /dev/null
+++ b/test/esan/Unit/circular_buffer.cpp
@@ -0,0 +1,61 @@
+// RUN: %clangxx_unit -O0 %s -o %t 2>&1
+// RUN: %env_esan_opts="record_snapshots=0" %run %t 2>&1 | FileCheck %s
+
+#include "esan/esan_circular_buffer.h"
+#include "sanitizer_common/sanitizer_placement_new.h"
+#include <assert.h>
+#include <stdio.h>
+
+static const int TestBufCapacity = 4;
+
+// The buffer should have a capacity of TestBufCapacity.
+void testBuffer(__esan::CircularBuffer<int> *Buf) {
+ assert(Buf->size() == 0);
+ assert(Buf->empty());
+
+ Buf->push_back(1);
+ assert(Buf->back() == 1);
+ assert((*Buf)[0] == 1);
+ assert(Buf->size() == 1);
+ assert(!Buf->empty());
+
+ Buf->push_back(2);
+ Buf->push_back(3);
+ Buf->push_back(4);
+ Buf->push_back(5);
+ assert((*Buf)[0] == 2);
+ assert(Buf->size() == 4);
+
+ Buf->pop_back();
+ assert((*Buf)[0] == 2);
+ assert(Buf->size() == 3);
+
+ Buf->pop_back();
+ Buf->pop_back();
+ assert((*Buf)[0] == 2);
+ assert(Buf->size() == 1);
+ assert(!Buf->empty());
+
+ Buf->pop_back();
+ assert(Buf->empty());
+}
+
+int main()
+{
+ // Test initialize/free.
+ __esan::CircularBuffer<int> GlobalBuf;
+ GlobalBuf.initialize(TestBufCapacity);
+ testBuffer(&GlobalBuf);
+ GlobalBuf.free();
+
+ // Test constructor/free.
+ __esan::CircularBuffer<int> *LocalBuf;
+ static char placeholder[sizeof(*LocalBuf)];
+ LocalBuf = new(placeholder) __esan::CircularBuffer<int>(TestBufCapacity);
+ testBuffer(LocalBuf);
+ LocalBuf->free();
+
+ fprintf(stderr, "All checks passed.\n");
+ // CHECK: All checks passed.
+ return 0;
+}
diff --git a/test/esan/lit.cfg b/test/esan/lit.cfg
new file mode 100644
index 000000000000..cf16a6b5df44
--- /dev/null
+++ b/test/esan/lit.cfg
@@ -0,0 +1,44 @@
+# -*- Python -*-
+
+import os
+
+# Setup config name.
+config.name = 'EfficiencySanitizer' + config.name_suffix
+
+# Setup source root.
+config.test_source_root = os.path.dirname(__file__)
+
+# Setup default compiler flags used with -fsanitize=efficiency option.
+base_cflags = ([config.target_cflags] + config.debug_info_flags)
+base_cxxflags = config.cxx_mode_flags + base_cflags
+
+frag_cflags = (["-fsanitize=efficiency-cache-frag"] + base_cflags)
+wset_cflags = (["-fsanitize=efficiency-working-set"] + base_cflags)
+esan_incdir = config.test_source_root + "/../../lib"
+unit_cxxflags = (["-I%s" % esan_incdir, "-std=c++11",
+ # We need to link with the esan runtime.
+ # Tests should pass %env_esan_opts="record_snapshots=0".
+ "-fsanitize=efficiency-working-set"] + base_cxxflags)
+
+def build_invocation(compile_flags):
+ return " " + " ".join([config.clang] + compile_flags) + " "
+
+config.substitutions.append( ("%clang ",
+ build_invocation(base_cflags)) )
+config.substitutions.append( ("%clang_esan_frag ",
+ build_invocation(frag_cflags)) )
+config.substitutions.append( ("%clang_esan_wset ",
+ build_invocation(wset_cflags)) )
+config.substitutions.append( ("%clangxx_unit",
+ build_invocation(unit_cxxflags)) )
+
+default_esan_opts = ''
+config.substitutions.append(('%env_esan_opts=',
+ 'env ESAN_OPTIONS=' + default_esan_opts))
+
+# Default test suffixes.
+config.suffixes = ['.c', '.cpp']
+
+# EfficiencySanitizer tests are currently supported on Linux x86-64 only.
+if config.host_os not in ['Linux'] or config.target_arch != 'x86_64':
+ config.unsupported = True
diff --git a/test/esan/lit.site.cfg.in b/test/esan/lit.site.cfg.in
new file mode 100644
index 000000000000..b631ce42d4db
--- /dev/null
+++ b/test/esan/lit.site.cfg.in
@@ -0,0 +1,14 @@
+## Autogenerated by LLVM/Clang configuration.
+# Do not edit!
+
+# Tool-specific config options.
+config.name_suffix = "@ESAN_TEST_CONFIG_SUFFIX@"
+config.esan_lit_source_dir = "@ESAN_LIT_SOURCE_DIR@"
+config.target_cflags = "@ESAN_TEST_TARGET_CFLAGS@"
+config.target_arch = "@ESAN_TEST_TARGET_ARCH@"
+
+# Load common config for all compiler-rt lit tests.
+lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/test/lit.common.configured")
+
+# Load tool-specific config that would do the real work.
+lit_config.load_config(config, "@ESAN_LIT_SOURCE_DIR@/lit.cfg")
diff --git a/test/lit.common.cfg b/test/lit.common.cfg
index aa3fd03add5a..f19fde2f89eb 100644
--- a/test/lit.common.cfg
+++ b/test/lit.common.cfg
@@ -72,6 +72,9 @@ config.environment['PATH'] = path
if platform.system() == 'Windows' and '-win' in config.target_triple:
config.environment['LIB'] = os.environ['LIB']
+if re.match(r'^x86_64.*-linux', config.target_triple):
+ config.available_features.add("x86_64-linux")
+
# Use ugly construction to explicitly prohibit "clang", "clang++" etc.
# in RUN lines.
config.substitutions.append(
@@ -89,15 +92,17 @@ if config.host_os == 'Windows':
# does not crash but exits with a non-zero exit code. We ought to merge
# KillTheDoctor and not --crash to make the latter more useful and remove the
# need for this substitution.
- config.substitutions.append( ("%expect_crash ", "not KillTheDoctor ") )
+ config.expect_crash = "not KillTheDoctor "
else:
- config.substitutions.append( ("%expect_crash ", "not --crash ") )
+ config.expect_crash = "not --crash "
+
+config.substitutions.append( ("%expect_crash ", config.expect_crash) )
-# Add supported compiler_rt architectures to a list of available features.
-compiler_rt_arch = getattr(config, 'compiler_rt_arch', None)
-if compiler_rt_arch:
- for arch in compiler_rt_arch.split(";"):
- config.available_features.add(arch + "-supported-target")
+target_arch = getattr(config, 'target_arch', None)
+if target_arch:
+ config.available_features.add(target_arch + '-target-arch')
+ if target_arch in ['x86_64', 'i386', 'i686']:
+ config.available_features.add('x86-target-arch')
compiler_rt_debug = getattr(config, 'compiler_rt_debug', False)
if not compiler_rt_debug:
@@ -107,12 +112,35 @@ sanitizer_can_use_cxxabi = getattr(config, 'sanitizer_can_use_cxxabi', True)
if sanitizer_can_use_cxxabi:
config.available_features.add('cxxabi')
-# Test lld if it is available.
if config.has_lld:
config.available_features.add('lld')
+if config.can_symbolize:
+ config.available_features.add('can-symbolize')
+
lit.util.usePlatformSdkOnDarwin(config, lit_config)
+if config.host_os == 'Darwin':
+ try:
+ osx_version = subprocess.check_output(["sw_vers", "-productVersion"])
+ osx_version = tuple(int(x) for x in osx_version.split('.'))
+ if osx_version >= (10, 11):
+ config.available_features.add('osx-autointerception')
+ config.available_features.add('osx-ld64-live_support')
+ else:
+ # The ASAN initialization-bug.cc test should XFAIL on OS X systems
+ # older than El Capitan. By marking the test as being unsupported with
+ # this "feature", we can pass the test on newer OS X versions and other
+ # platforms.
+ config.available_features.add('osx-no-ld64-live_support')
+ except:
+ pass
+
+sancovcc_path = os.path.join(llvm_tools_dir, "sancov")
+if os.path.exists(sancovcc_path):
+ config.available_features.add("has_sancovcc")
+ config.substitutions.append( ("%sancovcc ", sancovcc_path) )
+
def is_darwin_lto_supported():
return os.path.exists(os.path.join(config.llvm_shlib_dir, 'libLTO.dylib'))
diff --git a/test/lit.common.configured.in b/test/lit.common.configured.in
index 877890257fc7..35aa78c984f0 100644
--- a/test/lit.common.configured.in
+++ b/test/lit.common.configured.in
@@ -1,5 +1,4 @@
-## Autogenerated by LLVM/Clang configuration.
-# Do not edit!
+@LIT_SITE_CFG_IN_HEADER@
# Set attribute value if it is unset.
def set_default(attr, value):
@@ -13,22 +12,22 @@ set_default("host_arch", "@HOST_ARCH@")
set_default("target_arch", "@COMPILER_RT_DEFAULT_TARGET_ARCH@")
set_default("host_os", "@HOST_OS@")
set_default("llvm_build_mode", "@LLVM_BUILD_MODE@")
-set_default("llvm_src_root", "@LLVM_SOURCE_DIR@")
+set_default("llvm_src_root", "@LLVM_MAIN_SRC_DIR@")
set_default("llvm_obj_root", "@LLVM_BINARY_DIR@")
set_default("compiler_rt_src_root", "@COMPILER_RT_SOURCE_DIR@")
set_default("compiler_rt_obj_root", "@COMPILER_RT_BINARY_DIR@")
-set_default("llvm_tools_dir", "@LLVM_TOOLS_DIR@")
+set_default("llvm_tools_dir", "@LLVM_TOOLS_BINARY_DIR@")
set_default("llvm_shlib_dir", "@SHLIBDIR@")
set_default("gold_executable", "@GOLD_EXECUTABLE@")
set_default("clang", "@COMPILER_RT_TEST_COMPILER@")
set_default("compiler_id", "@COMPILER_RT_TEST_COMPILER_ID@")
-set_default("compiler_rt_arch", "@COMPILER_RT_SUPPORTED_ARCH@")
set_default("python_executable", "@PYTHON_EXECUTABLE@")
set_default("compiler_rt_debug", @COMPILER_RT_DEBUG_PYBOOL@)
set_default("compiler_rt_libdir", "@COMPILER_RT_LIBRARY_OUTPUT_DIR@")
set_default("emulator", "@COMPILER_RT_EMULATOR@")
set_default("sanitizer_can_use_cxxabi", @SANITIZER_CAN_USE_CXXABI_PYBOOL@)
set_default("has_lld", @COMPILER_RT_HAS_LLD_SOURCES_PYBOOL@)
+set_default("can_symbolize", @CAN_SYMBOLIZE@)
# LLVM tools dir can be passed in lit parameters, so try to
# apply substitution.
diff --git a/test/lsan/CMakeLists.txt b/test/lsan/CMakeLists.txt
index 6cca00a90b6b..e3d363a1f275 100644
--- a/test/lsan/CMakeLists.txt
+++ b/test/lsan/CMakeLists.txt
@@ -1,21 +1,48 @@
set(LSAN_LIT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
-set(LSAN_LIT_TEST_MODE "Standalone")
-configure_lit_site_cfg(
- ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
- ${CMAKE_CURRENT_BINARY_DIR}/LsanConfig/lit.site.cfg)
+set(LSAN_TESTSUITES)
+
+set(LSAN_TEST_ARCH ${LSAN_SUPPORTED_ARCH})
+if(APPLE)
+ darwin_filter_host_archs(LSAN_SUPPORTED_ARCH LSAN_TEST_ARCH)
+endif()
+
+foreach(arch ${LSAN_TEST_ARCH})
+ set(LSAN_TEST_TARGET_ARCH ${arch})
+ string(TOLOWER "-${arch}" LSAN_TEST_CONFIG_SUFFIX)
+ if(ANDROID OR ${arch} MATCHES "arm|aarch64")
+ # This is only true if we are cross-compiling.
+ # Build all tests with host compiler and use host tools.
+ set(LSAN_TEST_TARGET_CC ${COMPILER_RT_TEST_COMPILER})
+ set(LSAN_TEST_TARGET_CFLAGS ${COMPILER_RT_TEST_COMPILER_CFLAGS})
+ else()
+ get_target_flags_for_arch(${arch} LSAN_TEST_TARGET_CFLAGS)
+ string(REPLACE ";" " " LSAN_TEST_TARGET_CFLAGS "${LSAN_TEST_TARGET_CFLAGS}")
+ endif()
+
+ string(TOUPPER ${arch} ARCH_UPPER_CASE)
+ set(LSAN_LIT_TEST_MODE "Standalone")
+ set(CONFIG_NAME ${ARCH_UPPER_CASE}LsanConfig)
+
+ configure_lit_site_cfg(
+ ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
+ ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}/lit.site.cfg)
+ list(APPEND LSAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME})
+
+ set(CONFIG_NAME ${ARCH_UPPER_CASE}AsanConfig)
+ set(LSAN_LIT_TEST_MODE "AddressSanitizer")
-set(LSAN_LIT_TEST_MODE "AddressSanitizer")
-configure_lit_site_cfg(
- ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
- ${CMAKE_CURRENT_BINARY_DIR}/AsanConfig/lit.site.cfg)
+ configure_lit_site_cfg(
+ ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
+ ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}/lit.site.cfg)
+ list(APPEND LSAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME})
+endforeach()
set(LSAN_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS})
if(NOT COMPILER_RT_STANDALONE_BUILD)
list(APPEND LSAN_TEST_DEPS lsan asan)
endif()
add_lit_testsuite(check-lsan "Running the LeakSanitizer tests"
- ${CMAKE_CURRENT_BINARY_DIR}/LsanConfig
- ${CMAKE_CURRENT_BINARY_DIR}/AsanConfig
+ ${LSAN_TESTSUITES}
DEPENDS ${LSAN_TEST_DEPS})
-set_target_properties(check-lsan PROPERTIES FOLDER "LSan tests")
+set_target_properties(check-lsan PROPERTIES FOLDER "Compiler-RT Misc")
diff --git a/test/lsan/TestCases/disabler_in_tsd_destructor.c b/test/lsan/TestCases/disabler_in_tsd_destructor.c
index 982fb899ec5b..4a3a7ac14c3b 100644
--- a/test/lsan/TestCases/disabler_in_tsd_destructor.c
+++ b/test/lsan/TestCases/disabler_in_tsd_destructor.c
@@ -1,5 +1,5 @@
// 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: LSAN_BASE="report_objects=1:use_registers=0:use_stacks=0:use_globals=0:use_tls=1:use_ld_allocations=0"
// RUN: %clang_lsan %s -o %t
// RUN: LSAN_OPTIONS=$LSAN_BASE %run %t
diff --git a/test/lsan/TestCases/guard-page.c b/test/lsan/TestCases/guard-page.c
new file mode 100644
index 000000000000..5c70a9f08aca
--- /dev/null
+++ b/test/lsan/TestCases/guard-page.c
@@ -0,0 +1,60 @@
+// Check that if LSan finds that SP doesn't point into thread stack (e.g.
+// if swapcontext is used), LSan will not hit the guard page.
+// RUN: %clang_lsan %s -o %t && %run %t
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+#include <ucontext.h>
+
+pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
+pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+int ctxfunc_started = 0;
+
+static void die(const char* msg, int err) {
+ if (err == 0)
+ err = errno;
+ fprintf(stderr, "%s: %s\n", msg, strerror(err));
+ exit(EXIT_FAILURE);
+}
+
+static void ctxfunc() {
+ pthread_mutex_lock(&mutex);
+ ctxfunc_started = 1;
+ pthread_cond_signal(&cond);
+ pthread_mutex_unlock(&mutex);
+ // Leave this context alive when the program exits.
+ for (;;);
+}
+
+static void* thread(void* arg) {
+ (void)arg;
+ ucontext_t ctx;
+ void* stack;
+
+ if (getcontext(&ctx) < 0)
+ die("getcontext", 0);
+ stack = malloc(1 << 10);
+ if (stack == NULL)
+ die("malloc", 0);
+ ctx.uc_stack.ss_sp = stack;
+ ctx.uc_stack.ss_size = 1 << 10;
+ makecontext(&ctx, ctxfunc, 0);
+ setcontext(&ctx);
+ die("setcontext", 0);
+ return NULL;
+}
+
+int main() {
+ pthread_t tid;
+ int i;
+
+ pthread_mutex_lock(&mutex);
+ i = pthread_create(&tid, NULL, thread, NULL);
+ if (i != 0)
+ die("pthread_create", i);
+ while (!ctxfunc_started) pthread_cond_wait(&cond, &mutex);
+ pthread_mutex_unlock(&mutex);
+ return 0;
+}
diff --git a/test/lsan/TestCases/high_allocator_contention.cc b/test/lsan/TestCases/high_allocator_contention.cc
index 2543897bcbb4..f423fd48c79c 100644
--- a/test/lsan/TestCases/high_allocator_contention.cc
+++ b/test/lsan/TestCases/high_allocator_contention.cc
@@ -1,7 +1,8 @@
// A benchmark that executes malloc/free pairs in parallel.
// Usage: ./a.out number_of_threads total_number_of_allocations
+// RUN: LSAN_BASE="use_ld_allocations=0"
// RUN: %clangxx_lsan %s -o %t
-// RUN: %run %t 5 1000000 2>&1
+// RUN: LSAN_OPTIONS=$LSAN_BASE %run %t 5 1000000 2>&1
#include <assert.h>
#include <pthread.h>
#include <stdlib.h>
diff --git a/test/lsan/TestCases/leak_check_before_thread_started.cc b/test/lsan/TestCases/leak_check_before_thread_started.cc
index 0bd4837f14c0..ca818e1e269c 100644
--- a/test/lsan/TestCases/leak_check_before_thread_started.cc
+++ b/test/lsan/TestCases/leak_check_before_thread_started.cc
@@ -4,12 +4,19 @@
// RUN: LSAN_OPTIONS="log_pointers=1:log_threads=1" %run %t
#include <assert.h>
#include <pthread.h>
+#include <stdio.h>
#include <stdlib.h>
-#include <unistd.h>
+
+pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
+pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+bool flag = false;
void *func(void *arg) {
- sleep(1);
+ // This mutex will never be grabbed.
+ fprintf(stderr, "entered func()\n");
+ pthread_mutex_lock(&mutex);
free(arg);
+ pthread_mutex_unlock(&mutex);
return 0;
}
@@ -22,6 +29,8 @@ void create_detached_thread() {
void *arg = malloc(1337);
assert(arg);
+ // This mutex is never unlocked by the main thread.
+ pthread_mutex_lock(&mutex);
int res = pthread_create(&thread_id, &attr, func, arg);
assert(res == 0);
}
diff --git a/test/lsan/TestCases/use_registers.cc b/test/lsan/TestCases/use_registers.cc
index ce11c3f77bcb..74301a26c32c 100644
--- a/test/lsan/TestCases/use_registers.cc
+++ b/test/lsan/TestCases/use_registers.cc
@@ -27,6 +27,11 @@ void *registers_thread_func(void *arg) {
:
: "r" (p)
);
+#elif defined(__mips__)
+ asm ( "move $16, %0"
+ :
+ : "r" (p)
+ );
#else
#error "Test is not supported on this architecture."
#endif
diff --git a/test/lsan/TestCases/use_tls_dynamic.cc b/test/lsan/TestCases/use_tls_dynamic.cc
index 860db041ae40..207894b0fffd 100644
--- a/test/lsan/TestCases/use_tls_dynamic.cc
+++ b/test/lsan/TestCases/use_tls_dynamic.cc
@@ -1,5 +1,5 @@
// 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: LSAN_BASE="report_objects=1:use_stacks=0:use_registers=0:use_ld_allocations=0"
// RUN: %clangxx %s -DBUILD_DSO -fPIC -shared -o %t-so.so
// RUN: %clangxx_lsan %s -o %t
// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=0" not %run %t 2>&1 | FileCheck %s
diff --git a/test/lsan/lit.common.cfg b/test/lsan/lit.common.cfg
index ba9c283ca84a..a04c113269f2 100644
--- a/test/lsan/lit.common.cfg
+++ b/test/lsan/lit.common.cfg
@@ -27,8 +27,9 @@ elif lsan_lit_test_mode == "AddressSanitizer":
config.available_features.add('asan')
else:
lit_config.fatal("Unknown LSan test mode: %r" % lsan_lit_test_mode)
+config.name += config.name_suffix
-clang_cflags = ["-O0", "-m64"] + config.debug_info_flags
+clang_cflags = ["-O0", config.target_cflags] + config.debug_info_flags
clang_cxxflags = config.cxx_mode_flags + clang_cflags
clang_lsan_cflags = clang_cflags + lsan_cflags
clang_lsan_cxxflags = clang_cxxflags + lsan_cflags
diff --git a/test/lsan/lit.site.cfg.in b/test/lsan/lit.site.cfg.in
index 7d2877bdc528..de893474d280 100644
--- a/test/lsan/lit.site.cfg.in
+++ b/test/lsan/lit.site.cfg.in
@@ -1,8 +1,13 @@
-# Load common config for all compiler-rt lit tests.
-lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/test/lit.common.configured")
+@LIT_SITE_CFG_IN_HEADER@
# Tool-specific config options.
+config.name_suffix = "@LSAN_TEST_CONFIG_SUFFIX@"
+config.target_cflags = "@LSAN_TEST_TARGET_CFLAGS@"
config.lsan_lit_test_mode = "@LSAN_LIT_TEST_MODE@"
+config.target_arch = "@LSAN_TEST_TARGET_ARCH@"
+
+# Load common config for all compiler-rt lit tests.
+lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/test/lit.common.configured")
# Load tool-specific config that would do the real work.
lit_config.load_config(config, "@LSAN_LIT_SOURCE_DIR@/lit.common.cfg")
diff --git a/test/msan/CMakeLists.txt b/test/msan/CMakeLists.txt
index 08786ee777eb..176fb4ae1846 100644
--- a/test/msan/CMakeLists.txt
+++ b/test/msan/CMakeLists.txt
@@ -1,8 +1,33 @@
set(MSAN_LIT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
-configure_lit_site_cfg(
- ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
- ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg)
+set(MSAN_TESTSUITES)
+
+set(MSAN_TEST_ARCH ${MSAN_SUPPORTED_ARCH})
+if(APPLE)
+ darwin_filter_host_archs(MSAN_SUPPORTED_ARCH MSAN_TEST_ARCH)
+endif()
+
+foreach(arch ${MSAN_TEST_ARCH})
+ set(MSAN_TEST_TARGET_ARCH ${arch})
+ string(TOLOWER "-${arch}" MSAN_TEST_CONFIG_SUFFIX)
+ if(ANDROID OR ${arch} MATCHES "arm|aarch64")
+ # This is only true if we are cross-compiling.
+ # Build all tests with host compiler and use host tools.
+ set(MSAN_TEST_TARGET_CC ${COMPILER_RT_TEST_COMPILER})
+ set(MSAN_TEST_TARGET_CFLAGS ${COMPILER_RT_TEST_COMPILER_CFLAGS})
+ else()
+ get_target_flags_for_arch(${arch} MSAN_TEST_TARGET_CFLAGS)
+ string(REPLACE ";" " " MSAN_TEST_TARGET_CFLAGS "${MSAN_TEST_TARGET_CFLAGS}")
+ endif()
+
+ string(TOUPPER ${arch} ARCH_UPPER_CASE)
+ set(CONFIG_NAME ${ARCH_UPPER_CASE}Config)
+
+ configure_lit_site_cfg(
+ ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
+ ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}/lit.site.cfg)
+ list(APPEND MSAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME})
+endforeach()
set(MSAN_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS})
if(NOT COMPILER_RT_STANDALONE_BUILD)
@@ -14,10 +39,11 @@ if(COMPILER_RT_INCLUDE_TESTS AND COMPILER_RT_HAS_LIBCXX_SOURCES)
${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.in
${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg)
list(APPEND MSAN_TEST_DEPS MsanUnitTests)
+ list(APPEND MSAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/Unit)
endif()
add_lit_testsuite(check-msan "Running the MemorySanitizer tests"
- ${CMAKE_CURRENT_BINARY_DIR}
+ ${MSAN_TESTSUITES}
DEPENDS ${MSAN_TEST_DEPS}
)
-set_target_properties(check-msan PROPERTIES FOLDER "MSan tests")
+set_target_properties(check-msan PROPERTIES FOLDER "Compiler-RT Misc")
diff --git a/test/msan/Linux/cmsghdr.cc b/test/msan/Linux/cmsghdr.cc
new file mode 100644
index 000000000000..daed1baad20d
--- /dev/null
+++ b/test/msan/Linux/cmsghdr.cc
@@ -0,0 +1,101 @@
+// RUN: %clangxx_msan %s -std=c++11 -DSENDMSG -DPOISONFD -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=SENDMSG
+// RUN: %clangxx_msan %s -std=c++11 -DSENDMSG -DPOISONCRED -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=SENDMSG
+// RUN: %clangxx_msan %s -std=c++11 -DSENDMSG -DPOISONLEN -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=SENDMSG
+// RUN: %clangxx_msan %s -std=c++11 -DSENDMSG -DPOISONLEVEL -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=SENDMSG
+// RUN: %clangxx_msan %s -std=c++11 -DSENDMSG -DPOISONTYPE -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=SENDMSG
+// RUN: %clangxx_msan %s -std=c++11 -DSENDMSG -DPOISONLEN2 -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=SENDMSG
+// RUN: %clangxx_msan %s -std=c++11 -DSENDMSG -DPOISONLEVEL2 -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=SENDMSG
+// RUN: %clangxx_msan %s -std=c++11 -DSENDMSG -DPOISONTYPE2 -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=SENDMSG
+// RUN: %clangxx_msan %s -std=c++11 -DSENDMSG -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=NEGATIVE
+
+// UNSUPPORTED: android
+
+#include <assert.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <netdb.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sanitizer/msan_interface.h>
+
+const int kBufSize = 10;
+
+int main() {
+ int ret;
+ char buf[kBufSize] = {0};
+ pthread_t client_thread;
+ struct sockaddr_un serveraddr;
+
+ int sock[2];
+ ret = socketpair(AF_UNIX, SOCK_STREAM, 0, sock);
+ assert(ret == 0);
+
+ int sockfd = sock[0];
+
+ struct iovec iov[] = {{buf, 10}};
+ struct msghdr msg = {0};
+ msg.msg_iov = iov;
+ msg.msg_iovlen = 1;
+ msg.msg_flags = 0;
+
+ static const int kNumFds = 3;
+ char controlbuf[CMSG_SPACE(kNumFds * sizeof(int)) +
+ CMSG_SPACE(sizeof(struct ucred))];
+ msg.msg_control = &controlbuf;
+ msg.msg_controllen = sizeof(controlbuf);
+
+ struct cmsghdr *cmsg = (struct cmsghdr *)&controlbuf;
+ assert(cmsg);
+ int myfds[kNumFds];
+ for (int &fd : myfds)
+ fd = sockfd;
+#ifdef POISONFD
+ __msan_poison(&myfds[1], sizeof(int));
+#endif
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ cmsg->cmsg_len = CMSG_LEN(kNumFds * sizeof(int));
+ memcpy(CMSG_DATA(cmsg), myfds, kNumFds * sizeof(int));
+#ifdef POISONLEVEL
+ __msan_poison(&cmsg->cmsg_level, sizeof(cmsg->cmsg_level));
+#endif
+#ifdef POISONTYPE
+ __msan_poison(&cmsg->cmsg_type, sizeof(cmsg->cmsg_type));
+#endif
+#ifdef POISONLEN
+ __msan_poison(&cmsg->cmsg_len, sizeof(cmsg->cmsg_len));
+#endif
+
+ cmsg = (struct cmsghdr *)(&controlbuf[CMSG_SPACE(kNumFds * sizeof(int))]);
+ assert(cmsg);
+ struct ucred cred = {getpid(), getuid(), getgid()};
+#ifdef POISONCRED
+ __msan_poison(&cred.uid, sizeof(cred.uid));
+#endif
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_CREDENTIALS;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
+ memcpy(CMSG_DATA(cmsg), &cred, sizeof(struct ucred));
+#ifdef POISONLEVEL2
+ __msan_poison(&cmsg->cmsg_level, sizeof(cmsg->cmsg_level));
+#endif
+#ifdef POISONTYPE2
+ __msan_poison(&cmsg->cmsg_type, sizeof(cmsg->cmsg_type));
+#endif
+#ifdef POISONLEN2
+ __msan_poison(&cmsg->cmsg_len, sizeof(cmsg->cmsg_len));
+#endif
+
+ ret = sendmsg(sockfd, &msg, 0);
+ // SENDMSG: MemorySanitizer: use-of-uninitialized-value
+ if (ret == -1) printf("%d: %s\n", errno, strerror(errno));
+ assert(ret > 0);
+
+ fprintf(stderr, "== done\n");
+ // NEGATIVE: == done
+ return 0;
+}
diff --git a/test/msan/Linux/eventfd.cc b/test/msan/Linux/eventfd.cc
new file mode 100644
index 000000000000..4399211258ff
--- /dev/null
+++ b/test/msan/Linux/eventfd.cc
@@ -0,0 +1,18 @@
+// RUN: %clangxx_msan -O0 %s -o %t && %run %t 2>&1
+
+#include <assert.h>
+#include <sys/eventfd.h>
+
+#include <sanitizer/msan_interface.h>
+
+int main(int argc, char *argv[]) {
+ int efd = eventfd(42, 0);
+ assert(efd >= 0);
+
+ eventfd_t v;
+ int ret = eventfd_read(efd, &v);
+ assert(ret == 0);
+ __msan_check_mem_is_initialized(&v, sizeof(v));
+
+ assert(v == 42);
+}
diff --git a/test/msan/Linux/process_vm_readv.cc b/test/msan/Linux/process_vm_readv.cc
index 601c0d247dc2..b61578d1bfda 100644
--- a/test/msan/Linux/process_vm_readv.cc
+++ b/test/msan/Linux/process_vm_readv.cc
@@ -9,26 +9,31 @@
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
+#include <errno.h>
typedef ssize_t (*process_vm_readwritev_fn)(pid_t, const iovec *, unsigned long,
const iovec *, unsigned long,
unsigned long);
-int main(void) {
- // This requires glibc 2.15.
- process_vm_readwritev_fn libc_process_vm_readv =
- (process_vm_readwritev_fn)dlsym(RTLD_NEXT, "process_vm_readv");
- if (!libc_process_vm_readv) {
// Exit with success, emulating the expected output.
+int exit_dummy()
+{
#ifdef POSITIVE
- printf("process_vm_readv not found!\n");
+ printf("process_vm_readv not found or not implemented!\n");
printf(
"WARNING: MemorySanitizer: use-of-uninitialized-value (not really)\n");
return 1;
#else
return 0;
#endif
- }
+}
+
+int main(void) {
+ // This requires glibc 2.15.
+ process_vm_readwritev_fn libc_process_vm_readv =
+ (process_vm_readwritev_fn)dlsym(RTLD_NEXT, "process_vm_readv");
+ if (!libc_process_vm_readv)
+ return exit_dummy();
process_vm_readwritev_fn process_vm_readv =
(process_vm_readwritev_fn)dlsym(RTLD_DEFAULT, "process_vm_readv");
@@ -44,6 +49,9 @@ int main(void) {
__msan_poison(&b, sizeof(b));
ssize_t res = process_vm_readv(getpid(), iov_b, 2, iov_a, 2, 0);
+ if (errno == ENOSYS) // Function not implemented
+ return exit_dummy();
+
assert(res == 30);
__msan_check_mem_is_initialized(b + 10, 10);
__msan_check_mem_is_initialized(b + 30, 20);
diff --git a/test/msan/Linux/sendmsg.cc b/test/msan/Linux/sendmsg.cc
new file mode 100644
index 000000000000..6a8ef83c118b
--- /dev/null
+++ b/test/msan/Linux/sendmsg.cc
@@ -0,0 +1,83 @@
+// RUN: %clangxx_msan %s -DSEND -DPOISON -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=SEND
+// RUN: %clangxx_msan %s -DSENDTO -DPOISON -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=SENDTO
+// RUN: %clangxx_msan %s -DSENDMSG -DPOISON -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=SENDMSG
+
+// RUN: %clangxx_msan %s -DSEND -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=NEGATIVE
+// RUN: %clangxx_msan %s -DSENDTO -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=NEGATIVE
+// RUN: %clangxx_msan %s -DSENDMSG -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=NEGATIVE
+
+// RUN: %clangxx_msan %s -DSEND -DPOISON -o %t && \
+// RUN: MSAN_OPTIONS=intercept_send=0 %run %t 2>&1 | FileCheck %s --check-prefix=NEGATIVE
+// RUN: %clangxx_msan %s -DSENDTO -DPOISON -o %t && \
+// RUN: MSAN_OPTIONS=intercept_send=0 %run %t 2>&1 | FileCheck %s --check-prefix=NEGATIVE
+// RUN: %clangxx_msan %s -DSENDMSG -DPOISON -o %t && \
+// RUN: MSAN_OPTIONS=intercept_send=0 %run %t 2>&1 | FileCheck %s --check-prefix=NEGATIVE
+
+// UNSUPPORTED: android
+
+#include <assert.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <netdb.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sanitizer/msan_interface.h>
+
+const int kBufSize = 10;
+int sockfd;
+
+int main() {
+ int ret;
+ char buf[kBufSize] = {0};
+ pthread_t client_thread;
+ struct sockaddr_in serveraddr;
+
+ sockfd = socket(AF_INET, SOCK_DGRAM, 0);
+
+ memset(&serveraddr, 0, sizeof(serveraddr));
+ serveraddr.sin_family = AF_INET;
+ serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
+ serveraddr.sin_port = 0;
+
+ bind(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));
+ socklen_t addrlen = sizeof(serveraddr);
+ getsockname(sockfd, (struct sockaddr *)&serveraddr, &addrlen);
+
+#if defined(POISON)
+ __msan_poison(buf + 7, 1);
+#endif
+
+#if defined(SENDMSG)
+ struct iovec iov[2] = {{buf, 5}, {buf + 5, 5}};
+ struct msghdr msg;
+ msg.msg_name = &serveraddr;
+ msg.msg_namelen = addrlen;
+ msg.msg_iov = iov;
+ msg.msg_iovlen = 2;
+ msg.msg_control = 0;
+ msg.msg_controllen = 0;
+ msg.msg_flags = 0;
+#endif
+
+#if defined(SEND)
+ ret = connect(sockfd, (struct sockaddr *)&serveraddr, addrlen);
+ assert(ret == 0);
+ ret = send(sockfd, buf, kBufSize, 0);
+ // SEND: Uninitialized bytes in __interceptor_send at offset 7 inside [{{.*}}, 10)
+ assert(ret > 0);
+#elif defined(SENDTO)
+ ret =
+ sendto(sockfd, buf, kBufSize, 0, (struct sockaddr *)&serveraddr, addrlen);
+ // SENDTO: Uninitialized bytes in __interceptor_sendto at offset 7 inside [{{.*}}, 10)
+ assert(ret > 0);
+#elif defined(SENDMSG)
+ ret = sendmsg(sockfd, &msg, 0);
+ // SENDMSG: Uninitialized bytes in {{.*}} at offset 2 inside [{{.*}}, 5)
+ assert(ret > 0);
+#endif
+ fprintf(stderr, "== done\n");
+ // NEGATIVE: == done
+ return 0;
+}
diff --git a/test/msan/Linux/syscalls.cc b/test/msan/Linux/syscalls.cc
index 78dba36638a6..c5ac3e27fa11 100644
--- a/test/msan/Linux/syscalls.cc
+++ b/test/msan/Linux/syscalls.cc
@@ -19,7 +19,7 @@
sanity of their behaviour. */
int main(int argc, char *argv[]) {
- char buf[1000];
+ char buf[1000] __attribute__((aligned(8)));
const int kTen = 10;
const int kFortyTwo = 42;
memset(buf, 0, sizeof(buf));
@@ -111,5 +111,17 @@ int main(int argc, char *argv[]) {
assert(__msan_test_shadow(&p, sizeof(p)) == -1);
assert(__msan_test_shadow(buf, sizeof(buf)) >= 32);
+ __msan_poison(buf, sizeof(buf));
+ __sanitizer_syscall_post_pipe(0, (int *)buf);
+ assert(__msan_test_shadow(buf, sizeof(buf)) == 2 * sizeof(int));
+
+ __msan_poison(buf, sizeof(buf));
+ __sanitizer_syscall_post_pipe2(0, (int *)buf, 0);
+ assert(__msan_test_shadow(buf, sizeof(buf)) == 2 * sizeof(int));
+
+ __msan_poison(buf, sizeof(buf));
+ __sanitizer_syscall_post_socketpair(0, 0, 0, 0, (int *)buf);
+ assert(__msan_test_shadow(buf, sizeof(buf)) == 2 * sizeof(int));
+
return 0;
}
diff --git a/test/msan/Linux/syscalls_sigaction.cc b/test/msan/Linux/syscalls_sigaction.cc
new file mode 100644
index 000000000000..1297fae13d12
--- /dev/null
+++ b/test/msan/Linux/syscalls_sigaction.cc
@@ -0,0 +1,40 @@
+// RUN: %clangxx_msan -DPRE1 -O0 %s -o %t && not %run %t 2>&1
+// RUN: %clangxx_msan -DPRE2 -O0 %s -o %t && not %run %t 2>&1
+// RUN: %clangxx_msan -DPRE3 -O0 %s -o %t && not %run %t 2>&1
+// RUN: %clangxx_msan -O0 %s -o %t && %run %t 2>&1
+
+#include <assert.h>
+#include <signal.h>
+#include <string.h>
+
+#include <sanitizer/linux_syscall_hooks.h>
+#include <sanitizer/msan_interface.h>
+
+struct my_kernel_sigaction {
+ long handler, flags, restorer;
+ uint64_t mask[20]; // larger than any known platform
+};
+
+int main() {
+ my_kernel_sigaction act = {}, oldact = {};
+
+#if defined(PRE1)
+ __msan_poison(&act.handler, sizeof(act.handler));
+ __sanitizer_syscall_pre_rt_sigaction(SIGUSR1, &act, &oldact, 20 * 8);
+#elif defined(PRE2)
+ __msan_poison(&act.flags, sizeof(act.flags));
+ __sanitizer_syscall_pre_rt_sigaction(SIGUSR1, &act, &oldact, 20 * 8);
+#elif defined(PRE3)
+ __msan_poison(&act.mask, 1);
+ __sanitizer_syscall_pre_rt_sigaction(SIGUSR1, &act, &oldact, 20 * 8);
+#else
+ // Uninit past the end of the mask is ignored.
+ __msan_poison(((char *)&act.mask) + 5, 1);
+ __sanitizer_syscall_pre_rt_sigaction(SIGUSR1, &act, &oldact, 5);
+
+ memset(&act, 0, sizeof(act));
+ __msan_poison(&oldact, sizeof(oldact));
+ __sanitizer_syscall_post_rt_sigaction(0, SIGUSR1, &act, &oldact, 5);
+ assert(__msan_test_shadow(&oldact, sizeof(oldact)) == sizeof(long)*3 + 5);
+#endif
+}
diff --git a/test/msan/Unit/lit.site.cfg.in b/test/msan/Unit/lit.site.cfg.in
index dc0e9613d59e..083a25bc882b 100644
--- a/test/msan/Unit/lit.site.cfg.in
+++ b/test/msan/Unit/lit.site.cfg.in
@@ -1,5 +1,4 @@
-## Autogenerated by LLVM/Clang configuration.
-# Do not edit!
+@LIT_SITE_CFG_IN_HEADER@
# Load common config for all compiler-rt unit tests.
lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/unittests/lit.common.unit.configured")
diff --git a/test/msan/coverage-levels.cc b/test/msan/coverage-levels.cc
index d71bfecb2ebb..710a69aff53a 100644
--- a/test/msan/coverage-levels.cc
+++ b/test/msan/coverage-levels.cc
@@ -24,5 +24,5 @@ int main(int argc, char **argv) {
// CHECK_WARN: WARNING: MemorySanitizer: use-of-uninitialized-value
// CHECK_NOWARN-NOT: ERROR
// CHECK1: 1 PCs written
-// CHECK2: 2 PCs written
-// CHECK3: 3 PCs written
+// CHECK2: 1 PCs written
+// CHECK3: 2 PCs written
diff --git a/test/msan/dlerror.cc b/test/msan/dlerror.cc
index 0ad5b35f5218..d5510b65c4a5 100644
--- a/test/msan/dlerror.cc
+++ b/test/msan/dlerror.cc
@@ -1,8 +1,4 @@
// RUN: %clangxx_msan -O0 %s -o %t && %run %t
-//
-// AArch64 shows fails with uninitialized bytes in __interceptor_strcmp from
-// dlfcn/dlerror.c:107 (glibc).
-// XFAIL: aarch64
#include <assert.h>
#include <dlfcn.h>
diff --git a/test/msan/dtls_test.c b/test/msan/dtls_test.c
index 4036f71a7f8e..49d95c44c1d8 100644
--- a/test/msan/dtls_test.c
+++ b/test/msan/dtls_test.c
@@ -4,7 +4,7 @@
Regression test for a bug in msan/glibc integration,
see https://sourceware.org/bugzilla/show_bug.cgi?id=16291
- and https://code.google.com/p/memory-sanitizer/issues/detail?id=44
+ and https://github.com/google/sanitizers/issues/547
*/
#ifndef BUILD_SO
diff --git a/test/msan/fork.cc b/test/msan/fork.cc
index 38c3616ec164..78a62d549ec3 100644
--- a/test/msan/fork.cc
+++ b/test/msan/fork.cc
@@ -4,11 +4,6 @@
// RUN: %clangxx_msan -std=c++11 -fsanitize-memory-track-origins=2 -g -O3 %s -o %t
// RUN: MSAN_OPTIONS=store_context_size=1000,origin_history_size=0,origin_history_per_stack_limit=0 %run %t |& FileCheck %s
-//
-// Big-endian mips64 currently hangs on this test. Mark it unsupported to allow
-// llvm-lit to finish. This also marks mips unsupported in most cases but msan
-// is already unsupported for 32-bit mips.
-// UNSUPPORTED: mips64-supported-target
// Fun fact: if test output is redirected to a file (as opposed to
// being piped directly to FileCheck), we may lose some "done"s due to
diff --git a/test/msan/lit.cfg b/test/msan/lit.cfg
index 011ccd2fae74..d23ff31bc748 100644
--- a/test/msan/lit.cfg
+++ b/test/msan/lit.cfg
@@ -3,17 +3,18 @@
import os
# Setup config name.
-config.name = 'MemorySanitizer'
+config.name = 'MemorySanitizer' + getattr(config, 'name_suffix', 'default')
# Setup source root.
config.test_source_root = os.path.dirname(__file__)
# 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",
- "-m64"] + config.debug_info_flags
+clang_msan_cflags = (["-fsanitize=memory",
+ "-mno-omit-leaf-frame-pointer",
+ "-fno-omit-frame-pointer",
+ "-fno-optimize-sibling-calls"] +
+ [config.target_cflags] +
+ config.debug_info_flags)
# Some Msan tests leverage backtrace() which requires libexecinfo on FreeBSD.
if config.host_os == 'FreeBSD':
clang_msan_cflags += ["-lexecinfo"]
@@ -31,3 +32,6 @@ config.suffixes = ['.c', '.cc', '.cpp']
# MemorySanitizer tests are currently supported on Linux only.
if config.host_os not in ['Linux']:
config.unsupported = True
+
+if config.target_arch != 'aarch64':
+ config.available_features.add('stable-runtime')
diff --git a/test/msan/lit.site.cfg.in b/test/msan/lit.site.cfg.in
index fb22a57a9e66..a9656f24d603 100644
--- a/test/msan/lit.site.cfg.in
+++ b/test/msan/lit.site.cfg.in
@@ -1,3 +1,10 @@
+@LIT_SITE_CFG_IN_HEADER@
+
+# Tool-specific config options.
+config.name_suffix = "@MSAN_TEST_CONFIG_SUFFIX@"
+config.target_cflags = "@MSAN_TEST_TARGET_CFLAGS@"
+config.target_arch = "@MSAN_TEST_TARGET_ARCH@"
+
# Load common config for all compiler-rt lit tests.
lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/test/lit.common.configured")
diff --git a/test/msan/memcmp_test.cc b/test/msan/memcmp_test.cc
index 95228eb127dd..5ade58a6004a 100644
--- a/test/msan/memcmp_test.cc
+++ b/test/msan/memcmp_test.cc
@@ -3,13 +3,16 @@
// RUN: MSAN_OPTIONS=intercept_memcmp=0 %run %t
#include <string.h>
+#include <stdio.h>
int main(int argc, char **argv) {
char a1[4];
char a2[4];
for (int i = 0; i < argc * 3; i++)
a2[i] = a1[i] = i;
int res = memcmp(a1, a2, 4);
- return res;
+ if (!res)
+ printf("equals");
+ return 0;
// CHECK: Uninitialized bytes in __interceptor_memcmp at offset 3
// CHECK: MemorySanitizer: use-of-uninitialized-value
}
diff --git a/test/msan/msan_print_shadow3.cc b/test/msan/msan_print_shadow3.cc
index b29f3222dc33..4783152797eb 100644
--- a/test/msan/msan_print_shadow3.cc
+++ b/test/msan/msan_print_shadow3.cc
@@ -6,7 +6,7 @@
int main(void) {
unsigned long long x = 0; // For 8-byte alignment.
- uint32_t x_s = 0x12345678U;
+ char x_s[4] = {0x87, 0x65, 0x43, 0x21};
__msan_partial_poison(&x, &x_s, sizeof(x_s));
__msan_print_shadow(&x, sizeof(x_s));
return 0;
diff --git a/test/msan/param_tls_limit.cc b/test/msan/param_tls_limit.cc
index 1c504da42825..d34376a1f0c4 100644
--- a/test/msan/param_tls_limit.cc
+++ b/test/msan/param_tls_limit.cc
@@ -20,6 +20,17 @@
// In case of no overflow, it is still poisoned.
#define NO_OVERFLOW(x) assert(__msan_test_shadow(&x, sizeof(x)) == 0)
+#if defined(__x86_64__)
+// In x86_64, if argument is partially outside tls, it is considered completly
+// unpoisoned
+#define PARTIAL_OVERFLOW(x) OVERFLOW(x)
+#else
+// In other archs, bigger arguments are splitted in multiple IR arguments, so
+// they are considered poisoned till tls limit. Checking last byte of such arg:
+#define PARTIAL_OVERFLOW(x) assert(__msan_test_shadow((char *)(&(x) + 1) - 1, 1) == -1)
+#endif
+
+
template<int N>
struct S {
char x[N];
@@ -34,17 +45,17 @@ void f800(S<800> s) {
}
void f801(S<801> s) {
- OVERFLOW(s);
+ PARTIAL_OVERFLOW(s);
}
void f1000(S<1000> s) {
- OVERFLOW(s);
+ PARTIAL_OVERFLOW(s);
}
void f_many(int a, double b, S<800> s, int c, double d) {
NO_OVERFLOW(a);
NO_OVERFLOW(b);
- OVERFLOW(s);
+ PARTIAL_OVERFLOW(s);
OVERFLOW(c);
OVERFLOW(d);
}
@@ -54,7 +65,7 @@ void f_many(int a, double b, S<800> s, int c, double d) {
void f_many2(int a, S<800 - 8 - 2> s, int c, double d) {
NO_OVERFLOW(a);
NO_OVERFLOW(s);
- OVERFLOW(c);
+ PARTIAL_OVERFLOW(c);
OVERFLOW(d);
}
diff --git a/test/msan/vector_cvt.cc b/test/msan/vector_cvt.cc
index 633a8b15c444..5541436ead82 100644
--- a/test/msan/vector_cvt.cc
+++ b/test/msan/vector_cvt.cc
@@ -1,6 +1,6 @@
// RUN: %clangxx_msan -O0 %s -o %t && %run %t
// RUN: %clangxx_msan -DPOSITIVE -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s
-// REQUIRES: x86_64-supported-target
+// REQUIRES: x86_64-target-arch
#include <emmintrin.h>
diff --git a/test/profile/CMakeLists.txt b/test/profile/CMakeLists.txt
index 28fb35a9f6f8..0eb2b894748c 100644
--- a/test/profile/CMakeLists.txt
+++ b/test/profile/CMakeLists.txt
@@ -1,16 +1,35 @@
set(PROFILE_LIT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
set(PROFILE_LIT_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
+set(PROFILE_TESTSUITES)
set(PROFILE_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS})
if(NOT COMPILER_RT_STANDALONE_BUILD)
- list(APPEND PROFILE_TEST_DEPS profile llvm-profdata)
+ list(APPEND PROFILE_TEST_DEPS profile llvm-profdata llvm-cov)
endif()
-configure_lit_site_cfg(
- ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
- ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg
- )
+set(PROFILE_TEST_ARCH ${PROFILE_SUPPORTED_ARCH})
+if(APPLE)
+ darwin_filter_host_archs(PROFILE_SUPPORTED_ARCH PROFILE_TEST_ARCH)
+endif()
+
+foreach(arch ${PROFILE_TEST_ARCH})
+ set(PROFILE_TEST_TARGET_ARCH ${arch})
+ if(${arch} MATCHES "arm|aarch64")
+ # This is only true if we're cross-compiling.
+ set(PROFILE_TEST_TARGET_CFLAGS ${COMPILER_RT_TEST_COMPILER_CFLAGS})
+ else()
+ get_target_flags_for_arch(${arch} PROFILE_TEST_TARGET_CFLAGS)
+ string(REPLACE ";" " " PROFILE_TEST_TARGET_CFLAGS "${PROFILE_TEST_TARGET_CFLAGS}")
+ endif()
+ set(CONFIG_NAME Profile-${arch})
+ configure_lit_site_cfg(
+ ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
+ ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}/lit.site.cfg
+ )
+ list(APPEND PROFILE_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME})
+endforeach()
+
add_lit_testsuite(check-profile "Running the profile tests"
- ${CMAKE_CURRENT_BINARY_DIR}
+ ${PROFILE_TESTSUITES}
DEPENDS ${PROFILE_TEST_DEPS})
-set_target_properties(check-profile PROPERTIES FOLDER "Profile tests")
+set_target_properties(check-profile PROPERTIES FOLDER "Compiler-RT Misc")
diff --git a/test/profile/Inputs/extern_template.cpp b/test/profile/Inputs/extern_template.cpp
new file mode 100644
index 000000000000..98c6c16b4a8a
--- /dev/null
+++ b/test/profile/Inputs/extern_template.cpp
@@ -0,0 +1,14 @@
+#define DEF
+#include "extern_template.h"
+#undef DEF
+extern int bar();
+extern int foo();
+extern Test<int> TO;
+int main() {
+ foo();
+ int R = bar();
+
+ if (R != 10)
+ return 1;
+ return 0;
+}
diff --git a/test/profile/Inputs/extern_template.h b/test/profile/Inputs/extern_template.h
new file mode 100644
index 000000000000..01c1d1abfff5
--- /dev/null
+++ b/test/profile/Inputs/extern_template.h
@@ -0,0 +1,17 @@
+template <typename T> struct Test {
+ Test() : M(10) {}
+ void doIt(int N) { // CHECK: 2| [[@LINE]]| void doIt
+ if (N > 10) { // CHECK: 2| [[@LINE]]| if (N > 10) {
+ M += 2; // CHECK: 1| [[@LINE]]| M += 2;
+ } else // CHECK: 1| [[@LINE]]| } else
+ M -= 2; // CHECK: 1| [[@LINE]]| M -= 2;
+ }
+ T M;
+};
+
+#ifdef USE
+extern template struct Test<int>;
+#endif
+#ifdef DEF
+template struct Test<int>;
+#endif
diff --git a/test/profile/Inputs/extern_template1.cpp b/test/profile/Inputs/extern_template1.cpp
new file mode 100644
index 000000000000..372ffd25109f
--- /dev/null
+++ b/test/profile/Inputs/extern_template1.cpp
@@ -0,0 +1,9 @@
+#define USE
+#include "extern_template.h"
+#undef USE
+
+Test<int> TO;
+int foo() {
+ TO.doIt(20);
+ return TO.M;
+}
diff --git a/test/profile/Inputs/extern_template2.cpp b/test/profile/Inputs/extern_template2.cpp
new file mode 100644
index 000000000000..ac2f8587b0d8
--- /dev/null
+++ b/test/profile/Inputs/extern_template2.cpp
@@ -0,0 +1,9 @@
+#define USE
+#include "extern_template.h"
+#undef USE
+
+extern Test<int> TO;
+int bar() {
+ TO.doIt(5);
+ return TO.M;
+}
diff --git a/test/profile/Inputs/instrprof-alloc.c b/test/profile/Inputs/instrprof-alloc.c
new file mode 100644
index 000000000000..08942371ce95
--- /dev/null
+++ b/test/profile/Inputs/instrprof-alloc.c
@@ -0,0 +1,41 @@
+/* This test case tests that when static allocation for value
+ * profiler is on, no malloc/calloc calls will be invoked by
+ * profile runtime library. */
+#include <stdlib.h>
+__attribute__((noinline)) void foo() {}
+__attribute__((noinline)) void foo2() {}
+void (*FP)();
+int MainEntered = 0;
+int CallocCalled = 0;
+int MallocCalled = 0;
+
+extern void *__real_calloc(size_t s, size_t n);
+extern void *__real_malloc(size_t s);
+
+void *__wrap_calloc(size_t s, size_t n) {
+ if (MainEntered)
+ CallocCalled = 1;
+ return __real_calloc(s, n);
+}
+void *__wrap_malloc(size_t s) {
+ if (MainEntered)
+ MallocCalled = 1;
+ return __real_malloc(s);
+}
+
+void getFP(int i) {
+ if (i % 2)
+ FP = foo;
+ else
+ FP = foo2;
+}
+
+int main() {
+ int i;
+ MainEntered = 1;
+ for (i = 0; i < 100; i++) {
+ getFP(i);
+ FP();
+ }
+ return CallocCalled + MallocCalled;
+}
diff --git a/test/profile/Inputs/instrprof-comdat-1.cpp b/test/profile/Inputs/instrprof-comdat-1.cpp
new file mode 100644
index 000000000000..bd574ec3fb89
--- /dev/null
+++ b/test/profile/Inputs/instrprof-comdat-1.cpp
@@ -0,0 +1,17 @@
+#include "instrprof-comdat.h"
+int g;
+extern int bar(int);
+
+int main() {
+
+ FOO<int> Foo;
+
+ int Res = Foo.DoIt(10);
+
+ if (Res > 10)
+ g = bar(10);
+ else
+ g = bar(1) + bar(2);
+ return 0;
+}
+
diff --git a/test/profile/Inputs/instrprof-comdat-2.cpp b/test/profile/Inputs/instrprof-comdat-2.cpp
new file mode 100644
index 000000000000..ce68d54e8c5e
--- /dev/null
+++ b/test/profile/Inputs/instrprof-comdat-2.cpp
@@ -0,0 +1,12 @@
+#include "instrprof-comdat.h"
+
+int bar(int I) {
+
+ FOO<long> Foo;
+ FOO<int> Foo2;
+
+ if (I > 5)
+ return (int)Foo.DoIt(10);
+ else
+ return (int)Foo2.DoIt(I);
+}
diff --git a/test/profile/Inputs/instrprof-comdat.h b/test/profile/Inputs/instrprof-comdat.h
new file mode 100644
index 000000000000..db1a5ba63e58
--- /dev/null
+++ b/test/profile/Inputs/instrprof-comdat.h
@@ -0,0 +1,23 @@
+// Template instantiations are placed into comdat sections. Check that
+// coverage data from different instantiations are mapped back to the correct
+// source regions.
+
+template <class T> class FOO {
+public:
+ FOO() : t(0) {}
+
+ T DoIt(T ti);
+
+private:
+ T t;
+};
+
+template <class T> T FOO<T>::DoIt(T ti) { // HEADER: 2| [[@LINE]]|template
+ for (T I = 0; I < ti; I++) { // HEADER: 22| [[@LINE]]| for (T
+ t += I; // HEADER: 20| [[@LINE]]| t += I;
+ if (I > ti / 2) // HEADER: 20| [[@LINE]]| if (I > ti
+ t -= 1; // HEADER: 8| [[@LINE]]| t -= 1;
+ } // HEADER: 10| [[@LINE]]| }
+ // HEADER: 1| [[@LINE]]|
+ return t; // HEADER: 1| [[@LINE]]| return t;
+}
diff --git a/test/profile/Inputs/instrprof-dynamic-a.cpp b/test/profile/Inputs/instrprof-dynamic-a.cpp
index 2ec484a5b381..5faa9c2b2a80 100644
--- a/test/profile/Inputs/instrprof-dynamic-a.cpp
+++ b/test/profile/Inputs/instrprof-dynamic-a.cpp
@@ -1,7 +1,7 @@
#include "instrprof-dynamic-header.h"
-void a() {
- if (true) {
- bar<void>(1);
- bar<char>(1);
- }
+void a() { // COV: 1| [[@LINE]]|void a
+ if (true) { // COV: 1| [[@LINE]]| if
+ bar<void>(1); // COV: 1| [[@LINE]]| bar
+ bar<char>(1); // COV: 1| [[@LINE]]| bar
+ } // COV: 1| [[@LINE]]| }
}
diff --git a/test/profile/Inputs/instrprof-file_ex.c b/test/profile/Inputs/instrprof-file_ex.c
new file mode 100644
index 000000000000..106e58989a7c
--- /dev/null
+++ b/test/profile/Inputs/instrprof-file_ex.c
@@ -0,0 +1,59 @@
+/* This is a test case where the parent process forks 10
+ * children which contend to write to the same file. With
+ * file locking support, the data from each child should not
+ * be lost.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/wait.h>
+
+extern FILE *lprofOpenFileEx(const char *);
+int main(int argc, char *argv[]) {
+ pid_t tid;
+ FILE *F;
+ const char *FN;
+ int child[10];
+ int c;
+ int i;
+
+ if (argc < 2) {
+ fprintf(stderr, "Requires one argument \n");
+ exit(1);
+ }
+ FN = argv[1];
+ truncate(FN, 0);
+
+ for (i = 0; i < 10; i++) {
+ c = fork();
+ // in child:
+ if (c == 0) {
+ FILE *F = lprofOpenFileEx(FN);
+ if (!F) {
+ fprintf(stderr, "Can not open file %s from child\n", FN);
+ exit(1);
+ }
+ fseek(F, 0, SEEK_END);
+ fprintf(F, "Dump from Child %d\n", i);
+ fclose(F);
+ exit(0);
+ } else {
+ child[i] = c;
+ }
+ }
+
+ // In parent
+ for (i = 0; i < 10; i++) {
+ int child_status;
+ if ((tid = waitpid(child[i], &child_status, 0)) == -1)
+ break;
+ }
+ F = lprofOpenFileEx(FN);
+ if (!F) {
+ fprintf(stderr, "Can not open file %s from parent\n", FN);
+ exit(1);
+ }
+ fseek(F, 0, SEEK_END);
+ fprintf(F, "Dump from parent %d\n", i);
+ return 0;
+}
diff --git a/test/profile/Inputs/instrprof-icall-promo.h b/test/profile/Inputs/instrprof-icall-promo.h
new file mode 100644
index 000000000000..531e8ac82da5
--- /dev/null
+++ b/test/profile/Inputs/instrprof-icall-promo.h
@@ -0,0 +1,4 @@
+struct A {
+ virtual int foo() { return 1; };
+ virtual int bar();
+};
diff --git a/test/profile/Inputs/instrprof-icall-promo_1.cc b/test/profile/Inputs/instrprof-icall-promo_1.cc
new file mode 100644
index 000000000000..e0a5e0693479
--- /dev/null
+++ b/test/profile/Inputs/instrprof-icall-promo_1.cc
@@ -0,0 +1,7 @@
+#include "instrprof-icall-promo.h"
+
+A a;
+
+A* ap = &a;
+
+int ref(A* ap) { return ap->A::foo(); }
diff --git a/test/profile/Inputs/instrprof-icall-promo_2.cc b/test/profile/Inputs/instrprof-icall-promo_2.cc
new file mode 100644
index 000000000000..658ab0bf44d1
--- /dev/null
+++ b/test/profile/Inputs/instrprof-icall-promo_2.cc
@@ -0,0 +1,15 @@
+#include "instrprof-icall-promo.h"
+extern int ref(A *);
+
+int A::bar() { return 2; }
+
+extern A *ap;
+int test() {
+ for (int i = 0; i < 10000; i++) ap->foo();
+ return ref(ap);
+}
+
+int main() {
+ test();
+ return 0;
+}
diff --git a/test/profile/Inputs/instrprof-merge-match-lib.c b/test/profile/Inputs/instrprof-merge-match-lib.c
new file mode 100644
index 000000000000..afe559e018ae
--- /dev/null
+++ b/test/profile/Inputs/instrprof-merge-match-lib.c
@@ -0,0 +1,39 @@
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int __llvm_profile_runtime = 0;
+uint64_t __llvm_profile_get_size_for_buffer(void);
+int __llvm_profile_write_buffer(char *);
+void __llvm_profile_reset_counters(void);
+int __llvm_profile_check_compatibility(const char *, uint64_t);
+
+int gg = 0;
+void bar(char c) {
+ if (c == '1')
+ gg++;
+ else
+ gg--;
+}
+
+/* Returns 0 (size) when an error occurs. */
+uint64_t libEntry(char *Buffer, uint64_t MaxSize) {
+
+ uint64_t Size = __llvm_profile_get_size_for_buffer();
+ if (Size > MaxSize)
+ return 0;
+
+ __llvm_profile_reset_counters();
+
+ bar('1');
+
+ if (__llvm_profile_write_buffer(Buffer))
+ return 0;
+
+ /* Now check compatibility. Should return 0. */
+ if (__llvm_profile_check_compatibility(Buffer, Size))
+ return 0;
+
+ return Size;
+}
+
diff --git a/test/profile/Inputs/instrprof-merge-match.c b/test/profile/Inputs/instrprof-merge-match.c
new file mode 100644
index 000000000000..6e29e4a4e512
--- /dev/null
+++ b/test/profile/Inputs/instrprof-merge-match.c
@@ -0,0 +1,54 @@
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+int __llvm_profile_runtime = 0;
+uint64_t __llvm_profile_get_size_for_buffer(void);
+int __llvm_profile_write_buffer(char *);
+void __llvm_profile_reset_counters(void);
+int __llvm_profile_check_compatibility(const char *, uint64_t);
+
+int g = 0;
+void foo(char c) {
+ if (c == '1')
+ g++;
+ else
+ g--;
+}
+
+extern uint64_t libEntry(char *Buffer, uint64_t MaxSize);
+
+int main(int argc, const char *argv[]) {
+ const uint64_t MaxSize = 10000;
+ static char Buffer[MaxSize];
+
+ uint64_t Size = __llvm_profile_get_size_for_buffer();
+ if (Size > MaxSize)
+ return 1;
+
+ __llvm_profile_reset_counters();
+ foo('0');
+
+ if (__llvm_profile_write_buffer(Buffer))
+ return 1;
+
+ /* Now check compatibility. Should return 0. */
+ if (__llvm_profile_check_compatibility(Buffer, Size))
+ return 1;
+
+ /* Clear the buffer. */
+ memset(Buffer, 0, MaxSize);
+
+ /* Collect profile from shared library. */
+ Size = libEntry(Buffer, MaxSize);
+
+ if (!Size)
+ return 1;
+
+ /* Shared library's profile should not match main executable's. */
+ if (!__llvm_profile_check_compatibility(Buffer, Size))
+ return 1;
+
+ return 0;
+}
+
diff --git a/test/profile/Inputs/instrprof-value-prof-evict.c b/test/profile/Inputs/instrprof-value-prof-evict.c
new file mode 100644
index 000000000000..3b72e6e8adc4
--- /dev/null
+++ b/test/profile/Inputs/instrprof-value-prof-evict.c
@@ -0,0 +1,141 @@
+void callee_0() {}
+void callee_1() {}
+void callee_2() {}
+void callee_3() {}
+
+void *CalleeAddrs[] = {callee_0, callee_1, callee_2, callee_3};
+extern void lprofSetMaxValsPerSite(unsigned);
+
+// sequences of callee ids
+
+// In the following sequences,
+// there are two targets, the dominating target is
+// target 0.
+int CallSeqTwoTarget_1[] = {0, 0, 0, 0, 0, 1, 1};
+int CallSeqTwoTarget_2[] = {1, 1, 0, 0, 0, 0, 0};
+int CallSeqTwoTarget_3[] = {1, 0, 0, 1, 0, 0, 0};
+int CallSeqTwoTarget_4[] = {0, 0, 0, 1, 0, 1, 0};
+
+// In the following sequences, there are three targets
+// The dominating target is 0 and has > 50% of total
+// counts.
+int CallSeqThreeTarget_1[] = {0, 0, 0, 0, 0, 0, 1, 2, 1};
+int CallSeqThreeTarget_2[] = {1, 2, 1, 0, 0, 0, 0, 0, 0};
+int CallSeqThreeTarget_3[] = {1, 0, 0, 2, 0, 0, 0, 1, 0};
+int CallSeqThreeTarget_4[] = {0, 0, 0, 1, 0, 1, 0, 0, 2};
+
+// Four target sequence --
+// There are two cold targets which occupies the value counters
+// early. There is also a very hot target and a medium hot target
+// which are invoked in an interleaved fashion -- the length of each
+// hot period in the sequence is shorter than the cold targets' count.
+// 1. If only two values are tracked, the Hot and Medium hot targets
+// should surive in the end
+// 2. If only three values are tracked, the top three targets should
+// surive in the end.
+int CallSeqFourTarget_1[] = {1, 1, 1, 2, 2, 2, 2, 0, 0, 3, 0, 0, 3, 0, 0, 3,
+ 0, 0, 3, 0, 0, 3, 0, 0, 3, 0, 0, 3, 0, 0, 3};
+
+// Same as above, but the cold entries are invoked later.
+int CallSeqFourTarget_2[] = {0, 0, 3, 0, 0, 3, 0, 0, 3, 0, 0, 3, 0, 0, 3, 0,
+ 0, 3, 0, 0, 3, 0, 0, 3, 1, 1, 1, 2, 2, 2, 2};
+
+// Same as above, but all the targets are interleaved.
+int CallSeqFourTarget_3[] = {0, 3, 0, 0, 1, 3, 0, 0, 0, 2, 0, 0, 3, 3, 0, 3,
+ 2, 2, 0, 3, 3, 1, 0, 0, 1, 0, 0, 3, 0, 2, 0};
+
+typedef void (*FPT)(void);
+
+
+// Testing value profiling eviction algorithm.
+FPT getCalleeFunc(int I) { return CalleeAddrs[I]; }
+
+int main() {
+ int I;
+
+#define INDIRECT_CALLSITE(Sequence, NumValsTracked) \
+ lprofSetMaxValsPerSite(NumValsTracked); \
+ for (I = 0; I < sizeof(Sequence) / sizeof(*Sequence); I++) { \
+ FPT FP = getCalleeFunc(Sequence[I]); \
+ FP(); \
+ }
+
+ // check site, target patterns
+ // CHECK: 0, callee_0
+ INDIRECT_CALLSITE(CallSeqTwoTarget_1, 1);
+
+ // CHECK-NEXT: 1, callee_0
+ INDIRECT_CALLSITE(CallSeqTwoTarget_2, 1);
+
+ // CHECK-NEXT: 2, callee_0
+ INDIRECT_CALLSITE(CallSeqTwoTarget_3, 1);
+
+ // CHECK-NEXT: 3, callee_0
+ INDIRECT_CALLSITE(CallSeqTwoTarget_4, 1);
+
+ // CHECK-NEXT: 4, callee_0
+ INDIRECT_CALLSITE(CallSeqThreeTarget_1, 1);
+
+ // CHECK-NEXT: 5, callee_0
+ INDIRECT_CALLSITE(CallSeqThreeTarget_2, 1);
+
+ // CHECK-NEXT: 6, callee_0
+ INDIRECT_CALLSITE(CallSeqThreeTarget_3, 1);
+
+ // CHECK-NEXT: 7, callee_0
+ INDIRECT_CALLSITE(CallSeqThreeTarget_4, 1);
+
+ // CHECK-NEXT: 8, callee_0
+ // CHECK-NEXT: 8, callee_1
+ INDIRECT_CALLSITE(CallSeqThreeTarget_1, 2);
+
+ // CHECK-NEXT: 9, callee_0
+ // CHECK-NEXT: 9, callee_1
+ INDIRECT_CALLSITE(CallSeqThreeTarget_2, 2);
+
+ // CHECK-NEXT: 10, callee_0
+ // CHECK-NEXT: 10, callee_1
+ INDIRECT_CALLSITE(CallSeqThreeTarget_3, 2);
+
+ // CHECK-NEXT: 11, callee_0
+ // CHECK-NEXT: 11, callee_1
+ INDIRECT_CALLSITE(CallSeqThreeTarget_4, 2);
+
+ // CHECK-NEXT: 12, callee_0
+ INDIRECT_CALLSITE(CallSeqFourTarget_1, 1);
+
+ // CHECK-NEXT: 13, callee_0
+ INDIRECT_CALLSITE(CallSeqFourTarget_2, 1);
+
+ // CHECK-NEXT: 14, callee_0
+ INDIRECT_CALLSITE(CallSeqFourTarget_3, 1);
+
+ // CHECK-NEXT: 15, callee_0
+ // CHECK-NEXT: 15, callee_3
+ INDIRECT_CALLSITE(CallSeqFourTarget_1, 2);
+
+ // CHECK-NEXT: 16, callee_0
+ // CHECK-NEXT: 16, callee_3
+ INDIRECT_CALLSITE(CallSeqFourTarget_2, 2);
+
+ // CHECK-NEXT: 17, callee_0
+ // CHECK-NEXT: 17, callee_3
+ INDIRECT_CALLSITE(CallSeqFourTarget_3, 2);
+
+ // CHECK-NEXT: 18, callee_0
+ // CHECK-NEXT: 18, callee_3
+ // CHECK-NEXT: 18, callee_2
+ INDIRECT_CALLSITE(CallSeqFourTarget_1, 3);
+
+ // CHECK-NEXT: 19, callee_0
+ // CHECK-NEXT: 19, callee_3
+ // CHECK-NEXT: 19, callee_2
+ INDIRECT_CALLSITE(CallSeqFourTarget_2, 3);
+
+ // CHECK-NEXT: 20, callee_0
+ // CHECK-NEXT: 20, callee_3
+ // CHECK-NEXT: 20, callee_2
+ INDIRECT_CALLSITE(CallSeqFourTarget_3, 3);
+
+ return 0;
+}
diff --git a/test/profile/Inputs/instrprof-value-prof-real.c b/test/profile/Inputs/instrprof-value-prof-real.c
new file mode 100644
index 000000000000..65e579900722
--- /dev/null
+++ b/test/profile/Inputs/instrprof-value-prof-real.c
@@ -0,0 +1,1096 @@
+#define DEF_FUNC(x) \
+ void x() {}
+#define DEF_2_FUNCS(x) DEF_FUNC(x##_1) DEF_FUNC(x##_2)
+#define DEF_4_FUNCS(x) DEF_2_FUNCS(x##_1) DEF_2_FUNCS(x##_2)
+#define DEF_8_FUNCS(x) DEF_4_FUNCS(x##_1) DEF_4_FUNCS(x##_2)
+#define DEF_16_FUNCS(x) DEF_8_FUNCS(x##_1) DEF_8_FUNCS(x##_2)
+#define DEF_32_FUNCS(x) DEF_16_FUNCS(x##_1) DEF_16_FUNCS(x##_2)
+#define DEF_64_FUNCS(x) DEF_32_FUNCS(x##_1) DEF_32_FUNCS(x##_2)
+#define DEF_128_FUNCS(x) DEF_64_FUNCS(x##_1) DEF_64_FUNCS(x##_2)
+#define DEF_256_FUNCS(x) DEF_128_FUNCS(x##_1) DEF_128_FUNCS(x##_2)
+#define DEF_512_FUNCS(x) DEF_256_FUNCS(x##_1) DEF_256_FUNCS(x##_2)
+
+#define FUNC_ADDR(x) &x,
+#define FUNC_2_ADDRS(x) FUNC_ADDR(x##_1) FUNC_ADDR(x##_2)
+#define FUNC_4_ADDRS(x) FUNC_2_ADDRS(x##_1) FUNC_2_ADDRS(x##_2)
+#define FUNC_8_ADDRS(x) FUNC_4_ADDRS(x##_1) FUNC_4_ADDRS(x##_2)
+#define FUNC_16_ADDRS(x) FUNC_8_ADDRS(x##_1) FUNC_8_ADDRS(x##_2)
+#define FUNC_32_ADDRS(x) FUNC_16_ADDRS(x##_1) FUNC_16_ADDRS(x##_2)
+#define FUNC_64_ADDRS(x) FUNC_32_ADDRS(x##_1) FUNC_32_ADDRS(x##_2)
+#define FUNC_128_ADDRS(x) FUNC_64_ADDRS(x##_1) FUNC_64_ADDRS(x##_2)
+#define FUNC_256_ADDRS(x) FUNC_128_ADDRS(x##_1) FUNC_128_ADDRS(x##_2)
+#define FUNC_512_ADDRS(x) FUNC_256_ADDRS(x##_1) FUNC_256_ADDRS(x##_2)
+
+DEF_512_FUNCS(foo)
+void *CalleeAddrs[] = {FUNC_512_ADDRS(foo)};
+
+typedef void (*FPT)(void);
+
+FPT getFunc(int I) { return CalleeAddrs[I]; }
+
+#ifdef SHARED_LIB
+int shared_entry() {
+#else
+#ifdef CALL_SHARED
+extern int shared_entry();
+#endif
+int main() {
+#endif
+ int I;
+ for (I = 0; I < 512; I++) {
+ FPT Fp = getFunc(I);
+ int J;
+ for (J = 0; J < 1000 - I; J++)
+ Fp();
+
+ Fp = getFunc(511 - I);
+ for (J = 0; J < 2000 - I; J++)
+ Fp();
+#ifdef STRESS
+ Fp = getFunc(I);
+ for (J = 0; J < 2000 - I; J++)
+ Fp();
+
+ Fp = getFunc(I);
+ for (J = 0; J < 2000 - I; J++)
+ Fp();
+
+ Fp = getFunc(I);
+ for (J = 0; J < 2000 - I; J++)
+ Fp();
+
+ Fp = getFunc(I);
+ for (J = 0; J < 2000 - I; J++)
+ Fp();
+#endif
+ }
+#ifdef CALL_SHARED
+ shared_entry();
+#endif
+ return 0;
+}
+
+// IR: :ir
+// CHECK-LABEL: main:
+// CHECK: [ 0, foo_1_1_1_1_1_1_1_1_1, 1000 ]
+// CHECK-NEXT: [ 0, foo_1_1_1_1_1_1_1_1_2, 999 ]
+// CHECK-NEXT: [ 0, foo_1_1_1_1_1_1_1_2_1, 998 ]
+// CHECK-NEXT: [ 0, foo_1_1_1_1_1_1_1_2_2, 997 ]
+// CHECK-NEXT: [ 0, foo_1_1_1_1_1_1_2_1_1, 996 ]
+// CHECK-NEXT: [ 0, foo_1_1_1_1_1_1_2_1_2, 995 ]
+// CHECK-NEXT: [ 0, foo_1_1_1_1_1_1_2_2_1, 994 ]
+// CHECK-NEXT: [ 0, foo_1_1_1_1_1_1_2_2_2, 993 ]
+// CHECK-NEXT: [ 0, foo_1_1_1_1_1_2_1_1_1, 992 ]
+// CHECK-NEXT: [ 0, foo_1_1_1_1_1_2_1_1_2, 991 ]
+// CHECK-NEXT: [ 0, foo_1_1_1_1_1_2_1_2_1, 990 ]
+// CHECK-NEXT: [ 0, foo_1_1_1_1_1_2_1_2_2, 989 ]
+// CHECK-NEXT: [ 0, foo_1_1_1_1_1_2_2_1_1, 988 ]
+// CHECK-NEXT: [ 0, foo_1_1_1_1_1_2_2_1_2, 987 ]
+// CHECK-NEXT: [ 0, foo_1_1_1_1_1_2_2_2_1, 986 ]
+// CHECK-NEXT: [ 0, foo_1_1_1_1_1_2_2_2_2, 985 ]
+// CHECK-NEXT: [ 0, foo_1_1_1_1_2_1_1_1_1, 984 ]
+// CHECK-NEXT: [ 0, foo_1_1_1_1_2_1_1_1_2, 983 ]
+// CHECK-NEXT: [ 0, foo_1_1_1_1_2_1_1_2_1, 982 ]
+// CHECK-NEXT: [ 0, foo_1_1_1_1_2_1_1_2_2, 981 ]
+// CHECK-NEXT: [ 0, foo_1_1_1_1_2_1_2_1_1, 980 ]
+// CHECK-NEXT: [ 0, foo_1_1_1_1_2_1_2_1_2, 979 ]
+// CHECK-NEXT: [ 0, foo_1_1_1_1_2_1_2_2_1, 978 ]
+// CHECK-NEXT: [ 0, foo_1_1_1_1_2_1_2_2_2, 977 ]
+// CHECK-NEXT: [ 0, foo_1_1_1_1_2_2_1_1_1, 976 ]
+// CHECK-NEXT: [ 0, foo_1_1_1_1_2_2_1_1_2, 975 ]
+// CHECK-NEXT: [ 0, foo_1_1_1_1_2_2_1_2_1, 974 ]
+// CHECK-NEXT: [ 0, foo_1_1_1_1_2_2_1_2_2, 973 ]
+// CHECK-NEXT: [ 0, foo_1_1_1_1_2_2_2_1_1, 972 ]
+// CHECK-NEXT: [ 0, foo_1_1_1_1_2_2_2_1_2, 971 ]
+// CHECK-NEXT: [ 0, foo_1_1_1_1_2_2_2_2_1, 970 ]
+// CHECK-NEXT: [ 0, foo_1_1_1_1_2_2_2_2_2, 969 ]
+// CHECK-NEXT: [ 0, foo_1_1_1_2_1_1_1_1_1, 968 ]
+// CHECK-NEXT: [ 0, foo_1_1_1_2_1_1_1_1_2, 967 ]
+// CHECK-NEXT: [ 0, foo_1_1_1_2_1_1_1_2_1, 966 ]
+// CHECK-NEXT: [ 0, foo_1_1_1_2_1_1_1_2_2, 965 ]
+// CHECK-NEXT: [ 0, foo_1_1_1_2_1_1_2_1_1, 964 ]
+// CHECK-NEXT: [ 0, foo_1_1_1_2_1_1_2_1_2, 963 ]
+// CHECK-NEXT: [ 0, foo_1_1_1_2_1_1_2_2_1, 962 ]
+// CHECK-NEXT: [ 0, foo_1_1_1_2_1_1_2_2_2, 961 ]
+// CHECK-NEXT: [ 0, foo_1_1_1_2_1_2_1_1_1, 960 ]
+// CHECK-NEXT: [ 0, foo_1_1_1_2_1_2_1_1_2, 959 ]
+// CHECK-NEXT: [ 0, foo_1_1_1_2_1_2_1_2_1, 958 ]
+// CHECK-NEXT: [ 0, foo_1_1_1_2_1_2_1_2_2, 957 ]
+// CHECK-NEXT: [ 0, foo_1_1_1_2_1_2_2_1_1, 956 ]
+// CHECK-NEXT: [ 0, foo_1_1_1_2_1_2_2_1_2, 955 ]
+// CHECK-NEXT: [ 0, foo_1_1_1_2_1_2_2_2_1, 954 ]
+// CHECK-NEXT: [ 0, foo_1_1_1_2_1_2_2_2_2, 953 ]
+// CHECK-NEXT: [ 0, foo_1_1_1_2_2_1_1_1_1, 952 ]
+// CHECK-NEXT: [ 0, foo_1_1_1_2_2_1_1_1_2, 951 ]
+// CHECK-NEXT: [ 0, foo_1_1_1_2_2_1_1_2_1, 950 ]
+// CHECK-NEXT: [ 0, foo_1_1_1_2_2_1_1_2_2, 949 ]
+// CHECK-NEXT: [ 0, foo_1_1_1_2_2_1_2_1_1, 948 ]
+// CHECK-NEXT: [ 0, foo_1_1_1_2_2_1_2_1_2, 947 ]
+// CHECK-NEXT: [ 0, foo_1_1_1_2_2_1_2_2_1, 946 ]
+// CHECK-NEXT: [ 0, foo_1_1_1_2_2_1_2_2_2, 945 ]
+// CHECK-NEXT: [ 0, foo_1_1_1_2_2_2_1_1_1, 944 ]
+// CHECK-NEXT: [ 0, foo_1_1_1_2_2_2_1_1_2, 943 ]
+// CHECK-NEXT: [ 0, foo_1_1_1_2_2_2_1_2_1, 942 ]
+// CHECK-NEXT: [ 0, foo_1_1_1_2_2_2_1_2_2, 941 ]
+// CHECK-NEXT: [ 0, foo_1_1_1_2_2_2_2_1_1, 940 ]
+// CHECK-NEXT: [ 0, foo_1_1_1_2_2_2_2_1_2, 939 ]
+// CHECK-NEXT: [ 0, foo_1_1_1_2_2_2_2_2_1, 938 ]
+// CHECK-NEXT: [ 0, foo_1_1_1_2_2_2_2_2_2, 937 ]
+// CHECK-NEXT: [ 0, foo_1_1_2_1_1_1_1_1_1, 936 ]
+// CHECK-NEXT: [ 0, foo_1_1_2_1_1_1_1_1_2, 935 ]
+// CHECK-NEXT: [ 0, foo_1_1_2_1_1_1_1_2_1, 934 ]
+// CHECK-NEXT: [ 0, foo_1_1_2_1_1_1_1_2_2, 933 ]
+// CHECK-NEXT: [ 0, foo_1_1_2_1_1_1_2_1_1, 932 ]
+// CHECK-NEXT: [ 0, foo_1_1_2_1_1_1_2_1_2, 931 ]
+// CHECK-NEXT: [ 0, foo_1_1_2_1_1_1_2_2_1, 930 ]
+// CHECK-NEXT: [ 0, foo_1_1_2_1_1_1_2_2_2, 929 ]
+// CHECK-NEXT: [ 0, foo_1_1_2_1_1_2_1_1_1, 928 ]
+// CHECK-NEXT: [ 0, foo_1_1_2_1_1_2_1_1_2, 927 ]
+// CHECK-NEXT: [ 0, foo_1_1_2_1_1_2_1_2_1, 926 ]
+// CHECK-NEXT: [ 0, foo_1_1_2_1_1_2_1_2_2, 925 ]
+// CHECK-NEXT: [ 0, foo_1_1_2_1_1_2_2_1_1, 924 ]
+// CHECK-NEXT: [ 0, foo_1_1_2_1_1_2_2_1_2, 923 ]
+// CHECK-NEXT: [ 0, foo_1_1_2_1_1_2_2_2_1, 922 ]
+// CHECK-NEXT: [ 0, foo_1_1_2_1_1_2_2_2_2, 921 ]
+// CHECK-NEXT: [ 0, foo_1_1_2_1_2_1_1_1_1, 920 ]
+// CHECK-NEXT: [ 0, foo_1_1_2_1_2_1_1_1_2, 919 ]
+// CHECK-NEXT: [ 0, foo_1_1_2_1_2_1_1_2_1, 918 ]
+// CHECK-NEXT: [ 0, foo_1_1_2_1_2_1_1_2_2, 917 ]
+// CHECK-NEXT: [ 0, foo_1_1_2_1_2_1_2_1_1, 916 ]
+// CHECK-NEXT: [ 0, foo_1_1_2_1_2_1_2_1_2, 915 ]
+// CHECK-NEXT: [ 0, foo_1_1_2_1_2_1_2_2_1, 914 ]
+// CHECK-NEXT: [ 0, foo_1_1_2_1_2_1_2_2_2, 913 ]
+// CHECK-NEXT: [ 0, foo_1_1_2_1_2_2_1_1_1, 912 ]
+// CHECK-NEXT: [ 0, foo_1_1_2_1_2_2_1_1_2, 911 ]
+// CHECK-NEXT: [ 0, foo_1_1_2_1_2_2_1_2_1, 910 ]
+// CHECK-NEXT: [ 0, foo_1_1_2_1_2_2_1_2_2, 909 ]
+// CHECK-NEXT: [ 0, foo_1_1_2_1_2_2_2_1_1, 908 ]
+// CHECK-NEXT: [ 0, foo_1_1_2_1_2_2_2_1_2, 907 ]
+// CHECK-NEXT: [ 0, foo_1_1_2_1_2_2_2_2_1, 906 ]
+// CHECK-NEXT: [ 0, foo_1_1_2_1_2_2_2_2_2, 905 ]
+// CHECK-NEXT: [ 0, foo_1_1_2_2_1_1_1_1_1, 904 ]
+// CHECK-NEXT: [ 0, foo_1_1_2_2_1_1_1_1_2, 903 ]
+// CHECK-NEXT: [ 0, foo_1_1_2_2_1_1_1_2_1, 902 ]
+// CHECK-NEXT: [ 0, foo_1_1_2_2_1_1_1_2_2, 901 ]
+// CHECK-NEXT: [ 0, foo_1_1_2_2_1_1_2_1_1, 900 ]
+// CHECK-NEXT: [ 0, foo_1_1_2_2_1_1_2_1_2, 899 ]
+// CHECK-NEXT: [ 0, foo_1_1_2_2_1_1_2_2_1, 898 ]
+// CHECK-NEXT: [ 0, foo_1_1_2_2_1_1_2_2_2, 897 ]
+// CHECK-NEXT: [ 0, foo_1_1_2_2_1_2_1_1_1, 896 ]
+// CHECK-NEXT: [ 0, foo_1_1_2_2_1_2_1_1_2, 895 ]
+// CHECK-NEXT: [ 0, foo_1_1_2_2_1_2_1_2_1, 894 ]
+// CHECK-NEXT: [ 0, foo_1_1_2_2_1_2_1_2_2, 893 ]
+// CHECK-NEXT: [ 0, foo_1_1_2_2_1_2_2_1_1, 892 ]
+// CHECK-NEXT: [ 0, foo_1_1_2_2_1_2_2_1_2, 891 ]
+// CHECK-NEXT: [ 0, foo_1_1_2_2_1_2_2_2_1, 890 ]
+// CHECK-NEXT: [ 0, foo_1_1_2_2_1_2_2_2_2, 889 ]
+// CHECK-NEXT: [ 0, foo_1_1_2_2_2_1_1_1_1, 888 ]
+// CHECK-NEXT: [ 0, foo_1_1_2_2_2_1_1_1_2, 887 ]
+// CHECK-NEXT: [ 0, foo_1_1_2_2_2_1_1_2_1, 886 ]
+// CHECK-NEXT: [ 0, foo_1_1_2_2_2_1_1_2_2, 885 ]
+// CHECK-NEXT: [ 0, foo_1_1_2_2_2_1_2_1_1, 884 ]
+// CHECK-NEXT: [ 0, foo_1_1_2_2_2_1_2_1_2, 883 ]
+// CHECK-NEXT: [ 0, foo_1_1_2_2_2_1_2_2_1, 882 ]
+// CHECK-NEXT: [ 0, foo_1_1_2_2_2_1_2_2_2, 881 ]
+// CHECK-NEXT: [ 0, foo_1_1_2_2_2_2_1_1_1, 880 ]
+// CHECK-NEXT: [ 0, foo_1_1_2_2_2_2_1_1_2, 879 ]
+// CHECK-NEXT: [ 0, foo_1_1_2_2_2_2_1_2_1, 878 ]
+// CHECK-NEXT: [ 0, foo_1_1_2_2_2_2_1_2_2, 877 ]
+// CHECK-NEXT: [ 0, foo_1_1_2_2_2_2_2_1_1, 876 ]
+// CHECK-NEXT: [ 0, foo_1_1_2_2_2_2_2_1_2, 875 ]
+// CHECK-NEXT: [ 0, foo_1_1_2_2_2_2_2_2_1, 874 ]
+// CHECK-NEXT: [ 0, foo_1_1_2_2_2_2_2_2_2, 873 ]
+// CHECK-NEXT: [ 0, foo_1_2_1_1_1_1_1_1_1, 872 ]
+// CHECK-NEXT: [ 0, foo_1_2_1_1_1_1_1_1_2, 871 ]
+// CHECK-NEXT: [ 0, foo_1_2_1_1_1_1_1_2_1, 870 ]
+// CHECK-NEXT: [ 0, foo_1_2_1_1_1_1_1_2_2, 869 ]
+// CHECK-NEXT: [ 0, foo_1_2_1_1_1_1_2_1_1, 868 ]
+// CHECK-NEXT: [ 0, foo_1_2_1_1_1_1_2_1_2, 867 ]
+// CHECK-NEXT: [ 0, foo_1_2_1_1_1_1_2_2_1, 866 ]
+// CHECK-NEXT: [ 0, foo_1_2_1_1_1_1_2_2_2, 865 ]
+// CHECK-NEXT: [ 0, foo_1_2_1_1_1_2_1_1_1, 864 ]
+// CHECK-NEXT: [ 0, foo_1_2_1_1_1_2_1_1_2, 863 ]
+// CHECK-NEXT: [ 0, foo_1_2_1_1_1_2_1_2_1, 862 ]
+// CHECK-NEXT: [ 0, foo_1_2_1_1_1_2_1_2_2, 861 ]
+// CHECK-NEXT: [ 0, foo_1_2_1_1_1_2_2_1_1, 860 ]
+// CHECK-NEXT: [ 0, foo_1_2_1_1_1_2_2_1_2, 859 ]
+// CHECK-NEXT: [ 0, foo_1_2_1_1_1_2_2_2_1, 858 ]
+// CHECK-NEXT: [ 0, foo_1_2_1_1_1_2_2_2_2, 857 ]
+// CHECK-NEXT: [ 0, foo_1_2_1_1_2_1_1_1_1, 856 ]
+// CHECK-NEXT: [ 0, foo_1_2_1_1_2_1_1_1_2, 855 ]
+// CHECK-NEXT: [ 0, foo_1_2_1_1_2_1_1_2_1, 854 ]
+// CHECK-NEXT: [ 0, foo_1_2_1_1_2_1_1_2_2, 853 ]
+// CHECK-NEXT: [ 0, foo_1_2_1_1_2_1_2_1_1, 852 ]
+// CHECK-NEXT: [ 0, foo_1_2_1_1_2_1_2_1_2, 851 ]
+// CHECK-NEXT: [ 0, foo_1_2_1_1_2_1_2_2_1, 850 ]
+// CHECK-NEXT: [ 0, foo_1_2_1_1_2_1_2_2_2, 849 ]
+// CHECK-NEXT: [ 0, foo_1_2_1_1_2_2_1_1_1, 848 ]
+// CHECK-NEXT: [ 0, foo_1_2_1_1_2_2_1_1_2, 847 ]
+// CHECK-NEXT: [ 0, foo_1_2_1_1_2_2_1_2_1, 846 ]
+// CHECK-NEXT: [ 0, foo_1_2_1_1_2_2_1_2_2, 845 ]
+// CHECK-NEXT: [ 0, foo_1_2_1_1_2_2_2_1_1, 844 ]
+// CHECK-NEXT: [ 0, foo_1_2_1_1_2_2_2_1_2, 843 ]
+// CHECK-NEXT: [ 0, foo_1_2_1_1_2_2_2_2_1, 842 ]
+// CHECK-NEXT: [ 0, foo_1_2_1_1_2_2_2_2_2, 841 ]
+// CHECK-NEXT: [ 0, foo_1_2_1_2_1_1_1_1_1, 840 ]
+// CHECK-NEXT: [ 0, foo_1_2_1_2_1_1_1_1_2, 839 ]
+// CHECK-NEXT: [ 0, foo_1_2_1_2_1_1_1_2_1, 838 ]
+// CHECK-NEXT: [ 0, foo_1_2_1_2_1_1_1_2_2, 837 ]
+// CHECK-NEXT: [ 0, foo_1_2_1_2_1_1_2_1_1, 836 ]
+// CHECK-NEXT: [ 0, foo_1_2_1_2_1_1_2_1_2, 835 ]
+// CHECK-NEXT: [ 0, foo_1_2_1_2_1_1_2_2_1, 834 ]
+// CHECK-NEXT: [ 0, foo_1_2_1_2_1_1_2_2_2, 833 ]
+// CHECK-NEXT: [ 0, foo_1_2_1_2_1_2_1_1_1, 832 ]
+// CHECK-NEXT: [ 0, foo_1_2_1_2_1_2_1_1_2, 831 ]
+// CHECK-NEXT: [ 0, foo_1_2_1_2_1_2_1_2_1, 830 ]
+// CHECK-NEXT: [ 0, foo_1_2_1_2_1_2_1_2_2, 829 ]
+// CHECK-NEXT: [ 0, foo_1_2_1_2_1_2_2_1_1, 828 ]
+// CHECK-NEXT: [ 0, foo_1_2_1_2_1_2_2_1_2, 827 ]
+// CHECK-NEXT: [ 0, foo_1_2_1_2_1_2_2_2_1, 826 ]
+// CHECK-NEXT: [ 0, foo_1_2_1_2_1_2_2_2_2, 825 ]
+// CHECK-NEXT: [ 0, foo_1_2_1_2_2_1_1_1_1, 824 ]
+// CHECK-NEXT: [ 0, foo_1_2_1_2_2_1_1_1_2, 823 ]
+// CHECK-NEXT: [ 0, foo_1_2_1_2_2_1_1_2_1, 822 ]
+// CHECK-NEXT: [ 0, foo_1_2_1_2_2_1_1_2_2, 821 ]
+// CHECK-NEXT: [ 0, foo_1_2_1_2_2_1_2_1_1, 820 ]
+// CHECK-NEXT: [ 0, foo_1_2_1_2_2_1_2_1_2, 819 ]
+// CHECK-NEXT: [ 0, foo_1_2_1_2_2_1_2_2_1, 818 ]
+// CHECK-NEXT: [ 0, foo_1_2_1_2_2_1_2_2_2, 817 ]
+// CHECK-NEXT: [ 0, foo_1_2_1_2_2_2_1_1_1, 816 ]
+// CHECK-NEXT: [ 0, foo_1_2_1_2_2_2_1_1_2, 815 ]
+// CHECK-NEXT: [ 0, foo_1_2_1_2_2_2_1_2_1, 814 ]
+// CHECK-NEXT: [ 0, foo_1_2_1_2_2_2_1_2_2, 813 ]
+// CHECK-NEXT: [ 0, foo_1_2_1_2_2_2_2_1_1, 812 ]
+// CHECK-NEXT: [ 0, foo_1_2_1_2_2_2_2_1_2, 811 ]
+// CHECK-NEXT: [ 0, foo_1_2_1_2_2_2_2_2_1, 810 ]
+// CHECK-NEXT: [ 0, foo_1_2_1_2_2_2_2_2_2, 809 ]
+// CHECK-NEXT: [ 0, foo_1_2_2_1_1_1_1_1_1, 808 ]
+// CHECK-NEXT: [ 0, foo_1_2_2_1_1_1_1_1_2, 807 ]
+// CHECK-NEXT: [ 0, foo_1_2_2_1_1_1_1_2_1, 806 ]
+// CHECK-NEXT: [ 0, foo_1_2_2_1_1_1_1_2_2, 805 ]
+// CHECK-NEXT: [ 0, foo_1_2_2_1_1_1_2_1_1, 804 ]
+// CHECK-NEXT: [ 0, foo_1_2_2_1_1_1_2_1_2, 803 ]
+// CHECK-NEXT: [ 0, foo_1_2_2_1_1_1_2_2_1, 802 ]
+// CHECK-NEXT: [ 0, foo_1_2_2_1_1_1_2_2_2, 801 ]
+// CHECK-NEXT: [ 0, foo_1_2_2_1_1_2_1_1_1, 800 ]
+// CHECK-NEXT: [ 0, foo_1_2_2_1_1_2_1_1_2, 799 ]
+// CHECK-NEXT: [ 0, foo_1_2_2_1_1_2_1_2_1, 798 ]
+// CHECK-NEXT: [ 0, foo_1_2_2_1_1_2_1_2_2, 797 ]
+// CHECK-NEXT: [ 0, foo_1_2_2_1_1_2_2_1_1, 796 ]
+// CHECK-NEXT: [ 0, foo_1_2_2_1_1_2_2_1_2, 795 ]
+// CHECK-NEXT: [ 0, foo_1_2_2_1_1_2_2_2_1, 794 ]
+// CHECK-NEXT: [ 0, foo_1_2_2_1_1_2_2_2_2, 793 ]
+// CHECK-NEXT: [ 0, foo_1_2_2_1_2_1_1_1_1, 792 ]
+// CHECK-NEXT: [ 0, foo_1_2_2_1_2_1_1_1_2, 791 ]
+// CHECK-NEXT: [ 0, foo_1_2_2_1_2_1_1_2_1, 790 ]
+// CHECK-NEXT: [ 0, foo_1_2_2_1_2_1_1_2_2, 789 ]
+// CHECK-NEXT: [ 0, foo_1_2_2_1_2_1_2_1_1, 788 ]
+// CHECK-NEXT: [ 0, foo_1_2_2_1_2_1_2_1_2, 787 ]
+// CHECK-NEXT: [ 0, foo_1_2_2_1_2_1_2_2_1, 786 ]
+// CHECK-NEXT: [ 0, foo_1_2_2_1_2_1_2_2_2, 785 ]
+// CHECK-NEXT: [ 0, foo_1_2_2_1_2_2_1_1_1, 784 ]
+// CHECK-NEXT: [ 0, foo_1_2_2_1_2_2_1_1_2, 783 ]
+// CHECK-NEXT: [ 0, foo_1_2_2_1_2_2_1_2_1, 782 ]
+// CHECK-NEXT: [ 0, foo_1_2_2_1_2_2_1_2_2, 781 ]
+// CHECK-NEXT: [ 0, foo_1_2_2_1_2_2_2_1_1, 780 ]
+// CHECK-NEXT: [ 0, foo_1_2_2_1_2_2_2_1_2, 779 ]
+// CHECK-NEXT: [ 0, foo_1_2_2_1_2_2_2_2_1, 778 ]
+// CHECK-NEXT: [ 0, foo_1_2_2_1_2_2_2_2_2, 777 ]
+// CHECK-NEXT: [ 0, foo_1_2_2_2_1_1_1_1_1, 776 ]
+// CHECK-NEXT: [ 0, foo_1_2_2_2_1_1_1_1_2, 775 ]
+// CHECK-NEXT: [ 0, foo_1_2_2_2_1_1_1_2_1, 774 ]
+// CHECK-NEXT: [ 0, foo_1_2_2_2_1_1_1_2_2, 773 ]
+// CHECK-NEXT: [ 0, foo_1_2_2_2_1_1_2_1_1, 772 ]
+// CHECK-NEXT: [ 0, foo_1_2_2_2_1_1_2_1_2, 771 ]
+// CHECK-NEXT: [ 0, foo_1_2_2_2_1_1_2_2_1, 770 ]
+// CHECK-NEXT: [ 0, foo_1_2_2_2_1_1_2_2_2, 769 ]
+// CHECK-NEXT: [ 0, foo_1_2_2_2_1_2_1_1_1, 768 ]
+// CHECK-NEXT: [ 0, foo_1_2_2_2_1_2_1_1_2, 767 ]
+// CHECK-NEXT: [ 0, foo_1_2_2_2_1_2_1_2_1, 766 ]
+// CHECK-NEXT: [ 0, foo_1_2_2_2_1_2_1_2_2, 765 ]
+// CHECK-NEXT: [ 0, foo_1_2_2_2_1_2_2_1_1, 764 ]
+// CHECK-NEXT: [ 0, foo_1_2_2_2_1_2_2_1_2, 763 ]
+// CHECK-NEXT: [ 0, foo_1_2_2_2_1_2_2_2_1, 762 ]
+// CHECK-NEXT: [ 0, foo_1_2_2_2_1_2_2_2_2, 761 ]
+// CHECK-NEXT: [ 0, foo_1_2_2_2_2_1_1_1_1, 760 ]
+// CHECK-NEXT: [ 0, foo_1_2_2_2_2_1_1_1_2, 759 ]
+// CHECK-NEXT: [ 0, foo_1_2_2_2_2_1_1_2_1, 758 ]
+// CHECK-NEXT: [ 0, foo_1_2_2_2_2_1_1_2_2, 757 ]
+// CHECK-NEXT: [ 0, foo_1_2_2_2_2_1_2_1_1, 756 ]
+// CHECK-NEXT: [ 0, foo_1_2_2_2_2_1_2_1_2, 755 ]
+// CHECK-NEXT: [ 0, foo_1_2_2_2_2_1_2_2_1, 754 ]
+// CHECK-NEXT: [ 0, foo_1_2_2_2_2_1_2_2_2, 753 ]
+// CHECK-NEXT: [ 0, foo_1_2_2_2_2_2_1_1_1, 752 ]
+// CHECK-NEXT: [ 0, foo_1_2_2_2_2_2_1_1_2, 751 ]
+// CHECK-NEXT: [ 0, foo_1_2_2_2_2_2_1_2_1, 750 ]
+// CHECK-NEXT: [ 0, foo_1_2_2_2_2_2_1_2_2, 749 ]
+// CHECK-NEXT: [ 0, foo_1_2_2_2_2_2_2_1_1, 748 ]
+// CHECK-NEXT: [ 0, foo_1_2_2_2_2_2_2_1_2, 747 ]
+// CHECK-NEXT: [ 0, foo
+// CHECK-NEXT: [ 1, foo_2_2_2_2_2_2_2_2_2, 2000 ]
+// CHECK-NEXT: [ 1, foo_2_2_2_2_2_2_2_2_1, 1999 ]
+// CHECK-NEXT: [ 1, foo_2_2_2_2_2_2_2_1_2, 1998 ]
+// CHECK-NEXT: [ 1, foo_2_2_2_2_2_2_2_1_1, 1997 ]
+// CHECK-NEXT: [ 1, foo_2_2_2_2_2_2_1_2_2, 1996 ]
+// CHECK-NEXT: [ 1, foo_2_2_2_2_2_2_1_2_1, 1995 ]
+// CHECK-NEXT: [ 1, foo_2_2_2_2_2_2_1_1_2, 1994 ]
+// CHECK-NEXT: [ 1, foo_2_2_2_2_2_2_1_1_1, 1993 ]
+// CHECK-NEXT: [ 1, foo_2_2_2_2_2_1_2_2_2, 1992 ]
+// CHECK-NEXT: [ 1, foo_2_2_2_2_2_1_2_2_1, 1991 ]
+// CHECK-NEXT: [ 1, foo_2_2_2_2_2_1_2_1_2, 1990 ]
+// CHECK-NEXT: [ 1, foo_2_2_2_2_2_1_2_1_1, 1989 ]
+// CHECK-NEXT: [ 1, foo_2_2_2_2_2_1_1_2_2, 1988 ]
+// CHECK-NEXT: [ 1, foo_2_2_2_2_2_1_1_2_1, 1987 ]
+// CHECK-NEXT: [ 1, foo_2_2_2_2_2_1_1_1_2, 1986 ]
+// CHECK-NEXT: [ 1, foo_2_2_2_2_2_1_1_1_1, 1985 ]
+// CHECK-NEXT: [ 1, foo_2_2_2_2_1_2_2_2_2, 1984 ]
+// CHECK-NEXT: [ 1, foo_2_2_2_2_1_2_2_2_1, 1983 ]
+// CHECK-NEXT: [ 1, foo_2_2_2_2_1_2_2_1_2, 1982 ]
+// CHECK-NEXT: [ 1, foo_2_2_2_2_1_2_2_1_1, 1981 ]
+// CHECK-NEXT: [ 1, foo_2_2_2_2_1_2_1_2_2, 1980 ]
+// CHECK-NEXT: [ 1, foo_2_2_2_2_1_2_1_2_1, 1979 ]
+// CHECK-NEXT: [ 1, foo_2_2_2_2_1_2_1_1_2, 1978 ]
+// CHECK-NEXT: [ 1, foo_2_2_2_2_1_2_1_1_1, 1977 ]
+// CHECK-NEXT: [ 1, foo_2_2_2_2_1_1_2_2_2, 1976 ]
+// CHECK-NEXT: [ 1, foo_2_2_2_2_1_1_2_2_1, 1975 ]
+// CHECK-NEXT: [ 1, foo_2_2_2_2_1_1_2_1_2, 1974 ]
+// CHECK-NEXT: [ 1, foo_2_2_2_2_1_1_2_1_1, 1973 ]
+// CHECK-NEXT: [ 1, foo_2_2_2_2_1_1_1_2_2, 1972 ]
+// CHECK-NEXT: [ 1, foo_2_2_2_2_1_1_1_2_1, 1971 ]
+// CHECK-NEXT: [ 1, foo_2_2_2_2_1_1_1_1_2, 1970 ]
+// CHECK-NEXT: [ 1, foo_2_2_2_2_1_1_1_1_1, 1969 ]
+// CHECK-NEXT: [ 1, foo_2_2_2_1_2_2_2_2_2, 1968 ]
+// CHECK-NEXT: [ 1, foo_2_2_2_1_2_2_2_2_1, 1967 ]
+// CHECK-NEXT: [ 1, foo_2_2_2_1_2_2_2_1_2, 1966 ]
+// CHECK-NEXT: [ 1, foo_2_2_2_1_2_2_2_1_1, 1965 ]
+// CHECK-NEXT: [ 1, foo_2_2_2_1_2_2_1_2_2, 1964 ]
+// CHECK-NEXT: [ 1, foo_2_2_2_1_2_2_1_2_1, 1963 ]
+// CHECK-NEXT: [ 1, foo_2_2_2_1_2_2_1_1_2, 1962 ]
+// CHECK-NEXT: [ 1, foo_2_2_2_1_2_2_1_1_1, 1961 ]
+// CHECK-NEXT: [ 1, foo_2_2_2_1_2_1_2_2_2, 1960 ]
+// CHECK-NEXT: [ 1, foo_2_2_2_1_2_1_2_2_1, 1959 ]
+// CHECK-NEXT: [ 1, foo_2_2_2_1_2_1_2_1_2, 1958 ]
+// CHECK-NEXT: [ 1, foo_2_2_2_1_2_1_2_1_1, 1957 ]
+// CHECK-NEXT: [ 1, foo_2_2_2_1_2_1_1_2_2, 1956 ]
+// CHECK-NEXT: [ 1, foo_2_2_2_1_2_1_1_2_1, 1955 ]
+// CHECK-NEXT: [ 1, foo_2_2_2_1_2_1_1_1_2, 1954 ]
+// CHECK-NEXT: [ 1, foo_2_2_2_1_2_1_1_1_1, 1953 ]
+// CHECK-NEXT: [ 1, foo_2_2_2_1_1_2_2_2_2, 1952 ]
+// CHECK-NEXT: [ 1, foo_2_2_2_1_1_2_2_2_1, 1951 ]
+// CHECK-NEXT: [ 1, foo_2_2_2_1_1_2_2_1_2, 1950 ]
+// CHECK-NEXT: [ 1, foo_2_2_2_1_1_2_2_1_1, 1949 ]
+// CHECK-NEXT: [ 1, foo_2_2_2_1_1_2_1_2_2, 1948 ]
+// CHECK-NEXT: [ 1, foo_2_2_2_1_1_2_1_2_1, 1947 ]
+// CHECK-NEXT: [ 1, foo_2_2_2_1_1_2_1_1_2, 1946 ]
+// CHECK-NEXT: [ 1, foo_2_2_2_1_1_2_1_1_1, 1945 ]
+// CHECK-NEXT: [ 1, foo_2_2_2_1_1_1_2_2_2, 1944 ]
+// CHECK-NEXT: [ 1, foo_2_2_2_1_1_1_2_2_1, 1943 ]
+// CHECK-NEXT: [ 1, foo_2_2_2_1_1_1_2_1_2, 1942 ]
+// CHECK-NEXT: [ 1, foo_2_2_2_1_1_1_2_1_1, 1941 ]
+// CHECK-NEXT: [ 1, foo_2_2_2_1_1_1_1_2_2, 1940 ]
+// CHECK-NEXT: [ 1, foo_2_2_2_1_1_1_1_2_1, 1939 ]
+// CHECK-NEXT: [ 1, foo_2_2_2_1_1_1_1_1_2, 1938 ]
+// CHECK-NEXT: [ 1, foo_2_2_2_1_1_1_1_1_1, 1937 ]
+// CHECK-NEXT: [ 1, foo_2_2_1_2_2_2_2_2_2, 1936 ]
+// CHECK-NEXT: [ 1, foo_2_2_1_2_2_2_2_2_1, 1935 ]
+// CHECK-NEXT: [ 1, foo_2_2_1_2_2_2_2_1_2, 1934 ]
+// CHECK-NEXT: [ 1, foo_2_2_1_2_2_2_2_1_1, 1933 ]
+// CHECK-NEXT: [ 1, foo_2_2_1_2_2_2_1_2_2, 1932 ]
+// CHECK-NEXT: [ 1, foo_2_2_1_2_2_2_1_2_1, 1931 ]
+// CHECK-NEXT: [ 1, foo_2_2_1_2_2_2_1_1_2, 1930 ]
+// CHECK-NEXT: [ 1, foo_2_2_1_2_2_2_1_1_1, 1929 ]
+// CHECK-NEXT: [ 1, foo_2_2_1_2_2_1_2_2_2, 1928 ]
+// CHECK-NEXT: [ 1, foo_2_2_1_2_2_1_2_2_1, 1927 ]
+// CHECK-NEXT: [ 1, foo_2_2_1_2_2_1_2_1_2, 1926 ]
+// CHECK-NEXT: [ 1, foo_2_2_1_2_2_1_2_1_1, 1925 ]
+// CHECK-NEXT: [ 1, foo_2_2_1_2_2_1_1_2_2, 1924 ]
+// CHECK-NEXT: [ 1, foo_2_2_1_2_2_1_1_2_1, 1923 ]
+// CHECK-NEXT: [ 1, foo_2_2_1_2_2_1_1_1_2, 1922 ]
+// CHECK-NEXT: [ 1, foo_2_2_1_2_2_1_1_1_1, 1921 ]
+// CHECK-NEXT: [ 1, foo_2_2_1_2_1_2_2_2_2, 1920 ]
+// CHECK-NEXT: [ 1, foo_2_2_1_2_1_2_2_2_1, 1919 ]
+// CHECK-NEXT: [ 1, foo_2_2_1_2_1_2_2_1_2, 1918 ]
+// CHECK-NEXT: [ 1, foo_2_2_1_2_1_2_2_1_1, 1917 ]
+// CHECK-NEXT: [ 1, foo_2_2_1_2_1_2_1_2_2, 1916 ]
+// CHECK-NEXT: [ 1, foo_2_2_1_2_1_2_1_2_1, 1915 ]
+// CHECK-NEXT: [ 1, foo_2_2_1_2_1_2_1_1_2, 1914 ]
+// CHECK-NEXT: [ 1, foo_2_2_1_2_1_2_1_1_1, 1913 ]
+// CHECK-NEXT: [ 1, foo_2_2_1_2_1_1_2_2_2, 1912 ]
+// CHECK-NEXT: [ 1, foo_2_2_1_2_1_1_2_2_1, 1911 ]
+// CHECK-NEXT: [ 1, foo_2_2_1_2_1_1_2_1_2, 1910 ]
+// CHECK-NEXT: [ 1, foo_2_2_1_2_1_1_2_1_1, 1909 ]
+// CHECK-NEXT: [ 1, foo_2_2_1_2_1_1_1_2_2, 1908 ]
+// CHECK-NEXT: [ 1, foo_2_2_1_2_1_1_1_2_1, 1907 ]
+// CHECK-NEXT: [ 1, foo_2_2_1_2_1_1_1_1_2, 1906 ]
+// CHECK-NEXT: [ 1, foo_2_2_1_2_1_1_1_1_1, 1905 ]
+// CHECK-NEXT: [ 1, foo_2_2_1_1_2_2_2_2_2, 1904 ]
+// CHECK-NEXT: [ 1, foo_2_2_1_1_2_2_2_2_1, 1903 ]
+// CHECK-NEXT: [ 1, foo_2_2_1_1_2_2_2_1_2, 1902 ]
+// CHECK-NEXT: [ 1, foo_2_2_1_1_2_2_2_1_1, 1901 ]
+// CHECK-NEXT: [ 1, foo_2_2_1_1_2_2_1_2_2, 1900 ]
+// CHECK-NEXT: [ 1, foo_2_2_1_1_2_2_1_2_1, 1899 ]
+// CHECK-NEXT: [ 1, foo_2_2_1_1_2_2_1_1_2, 1898 ]
+// CHECK-NEXT: [ 1, foo_2_2_1_1_2_2_1_1_1, 1897 ]
+// CHECK-NEXT: [ 1, foo_2_2_1_1_2_1_2_2_2, 1896 ]
+// CHECK-NEXT: [ 1, foo_2_2_1_1_2_1_2_2_1, 1895 ]
+// CHECK-NEXT: [ 1, foo_2_2_1_1_2_1_2_1_2, 1894 ]
+// CHECK-NEXT: [ 1, foo_2_2_1_1_2_1_2_1_1, 1893 ]
+// CHECK-NEXT: [ 1, foo_2_2_1_1_2_1_1_2_2, 1892 ]
+// CHECK-NEXT: [ 1, foo_2_2_1_1_2_1_1_2_1, 1891 ]
+// CHECK-NEXT: [ 1, foo_2_2_1_1_2_1_1_1_2, 1890 ]
+// CHECK-NEXT: [ 1, foo_2_2_1_1_2_1_1_1_1, 1889 ]
+// CHECK-NEXT: [ 1, foo_2_2_1_1_1_2_2_2_2, 1888 ]
+// CHECK-NEXT: [ 1, foo_2_2_1_1_1_2_2_2_1, 1887 ]
+// CHECK-NEXT: [ 1, foo_2_2_1_1_1_2_2_1_2, 1886 ]
+// CHECK-NEXT: [ 1, foo_2_2_1_1_1_2_2_1_1, 1885 ]
+// CHECK-NEXT: [ 1, foo_2_2_1_1_1_2_1_2_2, 1884 ]
+// CHECK-NEXT: [ 1, foo_2_2_1_1_1_2_1_2_1, 1883 ]
+// CHECK-NEXT: [ 1, foo_2_2_1_1_1_2_1_1_2, 1882 ]
+// CHECK-NEXT: [ 1, foo_2_2_1_1_1_2_1_1_1, 1881 ]
+// CHECK-NEXT: [ 1, foo_2_2_1_1_1_1_2_2_2, 1880 ]
+// CHECK-NEXT: [ 1, foo_2_2_1_1_1_1_2_2_1, 1879 ]
+// CHECK-NEXT: [ 1, foo_2_2_1_1_1_1_2_1_2, 1878 ]
+// CHECK-NEXT: [ 1, foo_2_2_1_1_1_1_2_1_1, 1877 ]
+// CHECK-NEXT: [ 1, foo_2_2_1_1_1_1_1_2_2, 1876 ]
+// CHECK-NEXT: [ 1, foo_2_2_1_1_1_1_1_2_1, 1875 ]
+// CHECK-NEXT: [ 1, foo_2_2_1_1_1_1_1_1_2, 1874 ]
+// CHECK-NEXT: [ 1, foo_2_2_1_1_1_1_1_1_1, 1873 ]
+// CHECK-NEXT: [ 1, foo_2_1_2_2_2_2_2_2_2, 1872 ]
+// CHECK-NEXT: [ 1, foo_2_1_2_2_2_2_2_2_1, 1871 ]
+// CHECK-NEXT: [ 1, foo_2_1_2_2_2_2_2_1_2, 1870 ]
+// CHECK-NEXT: [ 1, foo_2_1_2_2_2_2_2_1_1, 1869 ]
+// CHECK-NEXT: [ 1, foo_2_1_2_2_2_2_1_2_2, 1868 ]
+// CHECK-NEXT: [ 1, foo_2_1_2_2_2_2_1_2_1, 1867 ]
+// CHECK-NEXT: [ 1, foo_2_1_2_2_2_2_1_1_2, 1866 ]
+// CHECK-NEXT: [ 1, foo_2_1_2_2_2_2_1_1_1, 1865 ]
+// CHECK-NEXT: [ 1, foo_2_1_2_2_2_1_2_2_2, 1864 ]
+// CHECK-NEXT: [ 1, foo_2_1_2_2_2_1_2_2_1, 1863 ]
+// CHECK-NEXT: [ 1, foo_2_1_2_2_2_1_2_1_2, 1862 ]
+// CHECK-NEXT: [ 1, foo_2_1_2_2_2_1_2_1_1, 1861 ]
+// CHECK-NEXT: [ 1, foo_2_1_2_2_2_1_1_2_2, 1860 ]
+// CHECK-NEXT: [ 1, foo_2_1_2_2_2_1_1_2_1, 1859 ]
+// CHECK-NEXT: [ 1, foo_2_1_2_2_2_1_1_1_2, 1858 ]
+// CHECK-NEXT: [ 1, foo_2_1_2_2_2_1_1_1_1, 1857 ]
+// CHECK-NEXT: [ 1, foo_2_1_2_2_1_2_2_2_2, 1856 ]
+// CHECK-NEXT: [ 1, foo_2_1_2_2_1_2_2_2_1, 1855 ]
+// CHECK-NEXT: [ 1, foo_2_1_2_2_1_2_2_1_2, 1854 ]
+// CHECK-NEXT: [ 1, foo_2_1_2_2_1_2_2_1_1, 1853 ]
+// CHECK-NEXT: [ 1, foo_2_1_2_2_1_2_1_2_2, 1852 ]
+// CHECK-NEXT: [ 1, foo_2_1_2_2_1_2_1_2_1, 1851 ]
+// CHECK-NEXT: [ 1, foo_2_1_2_2_1_2_1_1_2, 1850 ]
+// CHECK-NEXT: [ 1, foo_2_1_2_2_1_2_1_1_1, 1849 ]
+// CHECK-NEXT: [ 1, foo_2_1_2_2_1_1_2_2_2, 1848 ]
+// CHECK-NEXT: [ 1, foo_2_1_2_2_1_1_2_2_1, 1847 ]
+// CHECK-NEXT: [ 1, foo_2_1_2_2_1_1_2_1_2, 1846 ]
+// CHECK-NEXT: [ 1, foo_2_1_2_2_1_1_2_1_1, 1845 ]
+// CHECK-NEXT: [ 1, foo_2_1_2_2_1_1_1_2_2, 1844 ]
+// CHECK-NEXT: [ 1, foo_2_1_2_2_1_1_1_2_1, 1843 ]
+// CHECK-NEXT: [ 1, foo_2_1_2_2_1_1_1_1_2, 1842 ]
+// CHECK-NEXT: [ 1, foo_2_1_2_2_1_1_1_1_1, 1841 ]
+// CHECK-NEXT: [ 1, foo_2_1_2_1_2_2_2_2_2, 1840 ]
+// CHECK-NEXT: [ 1, foo_2_1_2_1_2_2_2_2_1, 1839 ]
+// CHECK-NEXT: [ 1, foo_2_1_2_1_2_2_2_1_2, 1838 ]
+// CHECK-NEXT: [ 1, foo_2_1_2_1_2_2_2_1_1, 1837 ]
+// CHECK-NEXT: [ 1, foo_2_1_2_1_2_2_1_2_2, 1836 ]
+// CHECK-NEXT: [ 1, foo_2_1_2_1_2_2_1_2_1, 1835 ]
+// CHECK-NEXT: [ 1, foo_2_1_2_1_2_2_1_1_2, 1834 ]
+// CHECK-NEXT: [ 1, foo_2_1_2_1_2_2_1_1_1, 1833 ]
+// CHECK-NEXT: [ 1, foo_2_1_2_1_2_1_2_2_2, 1832 ]
+// CHECK-NEXT: [ 1, foo_2_1_2_1_2_1_2_2_1, 1831 ]
+// CHECK-NEXT: [ 1, foo_2_1_2_1_2_1_2_1_2, 1830 ]
+// CHECK-NEXT: [ 1, foo_2_1_2_1_2_1_2_1_1, 1829 ]
+// CHECK-NEXT: [ 1, foo_2_1_2_1_2_1_1_2_2, 1828 ]
+// CHECK-NEXT: [ 1, foo_2_1_2_1_2_1_1_2_1, 1827 ]
+// CHECK-NEXT: [ 1, foo_2_1_2_1_2_1_1_1_2, 1826 ]
+// CHECK-NEXT: [ 1, foo_2_1_2_1_2_1_1_1_1, 1825 ]
+// CHECK-NEXT: [ 1, foo_2_1_2_1_1_2_2_2_2, 1824 ]
+// CHECK-NEXT: [ 1, foo_2_1_2_1_1_2_2_2_1, 1823 ]
+// CHECK-NEXT: [ 1, foo_2_1_2_1_1_2_2_1_2, 1822 ]
+// CHECK-NEXT: [ 1, foo_2_1_2_1_1_2_2_1_1, 1821 ]
+// CHECK-NEXT: [ 1, foo_2_1_2_1_1_2_1_2_2, 1820 ]
+// CHECK-NEXT: [ 1, foo_2_1_2_1_1_2_1_2_1, 1819 ]
+// CHECK-NEXT: [ 1, foo_2_1_2_1_1_2_1_1_2, 1818 ]
+// CHECK-NEXT: [ 1, foo_2_1_2_1_1_2_1_1_1, 1817 ]
+// CHECK-NEXT: [ 1, foo_2_1_2_1_1_1_2_2_2, 1816 ]
+// CHECK-NEXT: [ 1, foo_2_1_2_1_1_1_2_2_1, 1815 ]
+// CHECK-NEXT: [ 1, foo_2_1_2_1_1_1_2_1_2, 1814 ]
+// CHECK-NEXT: [ 1, foo_2_1_2_1_1_1_2_1_1, 1813 ]
+// CHECK-NEXT: [ 1, foo_2_1_2_1_1_1_1_2_2, 1812 ]
+// CHECK-NEXT: [ 1, foo_2_1_2_1_1_1_1_2_1, 1811 ]
+// CHECK-NEXT: [ 1, foo_2_1_2_1_1_1_1_1_2, 1810 ]
+// CHECK-NEXT: [ 1, foo_2_1_2_1_1_1_1_1_1, 1809 ]
+// CHECK-NEXT: [ 1, foo_2_1_1_2_2_2_2_2_2, 1808 ]
+// CHECK-NEXT: [ 1, foo_2_1_1_2_2_2_2_2_1, 1807 ]
+// CHECK-NEXT: [ 1, foo_2_1_1_2_2_2_2_1_2, 1806 ]
+// CHECK-NEXT: [ 1, foo_2_1_1_2_2_2_2_1_1, 1805 ]
+// CHECK-NEXT: [ 1, foo_2_1_1_2_2_2_1_2_2, 1804 ]
+// CHECK-NEXT: [ 1, foo_2_1_1_2_2_2_1_2_1, 1803 ]
+// CHECK-NEXT: [ 1, foo_2_1_1_2_2_2_1_1_2, 1802 ]
+// CHECK-NEXT: [ 1, foo_2_1_1_2_2_2_1_1_1, 1801 ]
+// CHECK-NEXT: [ 1, foo_2_1_1_2_2_1_2_2_2, 1800 ]
+// CHECK-NEXT: [ 1, foo_2_1_1_2_2_1_2_2_1, 1799 ]
+// CHECK-NEXT: [ 1, foo_2_1_1_2_2_1_2_1_2, 1798 ]
+// CHECK-NEXT: [ 1, foo_2_1_1_2_2_1_2_1_1, 1797 ]
+// CHECK-NEXT: [ 1, foo_2_1_1_2_2_1_1_2_2, 1796 ]
+// CHECK-NEXT: [ 1, foo_2_1_1_2_2_1_1_2_1, 1795 ]
+// CHECK-NEXT: [ 1, foo_2_1_1_2_2_1_1_1_2, 1794 ]
+// CHECK-NEXT: [ 1, foo_2_1_1_2_2_1_1_1_1, 1793 ]
+// CHECK-NEXT: [ 1, foo_2_1_1_2_1_2_2_2_2, 1792 ]
+// CHECK-NEXT: [ 1, foo_2_1_1_2_1_2_2_2_1, 1791 ]
+// CHECK-NEXT: [ 1, foo_2_1_1_2_1_2_2_1_2, 1790 ]
+// CHECK-NEXT: [ 1, foo_2_1_1_2_1_2_2_1_1, 1789 ]
+// CHECK-NEXT: [ 1, foo_2_1_1_2_1_2_1_2_2, 1788 ]
+// CHECK-NEXT: [ 1, foo_2_1_1_2_1_2_1_2_1, 1787 ]
+// CHECK-NEXT: [ 1, foo_2_1_1_2_1_2_1_1_2, 1786 ]
+// CHECK-NEXT: [ 1, foo_2_1_1_2_1_2_1_1_1, 1785 ]
+// CHECK-NEXT: [ 1, foo_2_1_1_2_1_1_2_2_2, 1784 ]
+// CHECK-NEXT: [ 1, foo_2_1_1_2_1_1_2_2_1, 1783 ]
+// CHECK-NEXT: [ 1, foo_2_1_1_2_1_1_2_1_2, 1782 ]
+// CHECK-NEXT: [ 1, foo_2_1_1_2_1_1_2_1_1, 1781 ]
+// CHECK-NEXT: [ 1, foo_2_1_1_2_1_1_1_2_2, 1780 ]
+// CHECK-NEXT: [ 1, foo_2_1_1_2_1_1_1_2_1, 1779 ]
+// CHECK-NEXT: [ 1, foo_2_1_1_2_1_1_1_1_2, 1778 ]
+// CHECK-NEXT: [ 1, foo_2_1_1_2_1_1_1_1_1, 1777 ]
+// CHECK-NEXT: [ 1, foo_2_1_1_1_2_2_2_2_2, 1776 ]
+// CHECK-NEXT: [ 1, foo_2_1_1_1_2_2_2_2_1, 1775 ]
+// CHECK-NEXT: [ 1, foo_2_1_1_1_2_2_2_1_2, 1774 ]
+// CHECK-NEXT: [ 1, foo_2_1_1_1_2_2_2_1_1, 1773 ]
+// CHECK-NEXT: [ 1, foo_2_1_1_1_2_2_1_2_2, 1772 ]
+// CHECK-NEXT: [ 1, foo_2_1_1_1_2_2_1_2_1, 1771 ]
+// CHECK-NEXT: [ 1, foo_2_1_1_1_2_2_1_1_2, 1770 ]
+// CHECK-NEXT: [ 1, foo_2_1_1_1_2_2_1_1_1, 1769 ]
+// CHECK-NEXT: [ 1, foo_2_1_1_1_2_1_2_2_2, 1768 ]
+// CHECK-NEXT: [ 1, foo_2_1_1_1_2_1_2_2_1, 1767 ]
+// CHECK-NEXT: [ 1, foo_2_1_1_1_2_1_2_1_2, 1766 ]
+// CHECK-NEXT: [ 1, foo_2_1_1_1_2_1_2_1_1, 1765 ]
+// CHECK-NEXT: [ 1, foo_2_1_1_1_2_1_1_2_2, 1764 ]
+// CHECK-NEXT: [ 1, foo_2_1_1_1_2_1_1_2_1, 1763 ]
+// CHECK-NEXT: [ 1, foo_2_1_1_1_2_1_1_1_2, 1762 ]
+// CHECK-NEXT: [ 1, foo_2_1_1_1_2_1_1_1_1, 1761 ]
+// CHECK-NEXT: [ 1, foo_2_1_1_1_1_2_2_2_2, 1760 ]
+// CHECK-NEXT: [ 1, foo_2_1_1_1_1_2_2_2_1, 1759 ]
+// CHECK-NEXT: [ 1, foo_2_1_1_1_1_2_2_1_2, 1758 ]
+// CHECK-NEXT: [ 1, foo_2_1_1_1_1_2_2_1_1, 1757 ]
+// CHECK-NEXT: [ 1, foo_2_1_1_1_1_2_1_2_2, 1756 ]
+// CHECK-NEXT: [ 1, foo_2_1_1_1_1_2_1_2_1, 1755 ]
+// CHECK-NEXT: [ 1, foo_2_1_1_1_1_2_1_1_2, 1754 ]
+// CHECK-NEXT: [ 1, foo_2_1_1_1_1_2_1_1_1, 1753 ]
+// CHECK-NEXT: [ 1, foo_2_1_1_1_1_1_2_2_2, 1752 ]
+// CHECK-NEXT: [ 1, foo_2_1_1_1_1_1_2_2_1, 1751 ]
+// CHECK-NEXT: [ 1, foo_2_1_1_1_1_1_2_1_2, 1750 ]
+// CHECK-NEXT: [ 1, foo_2_1_1_1_1_1_2_1_1, 1749 ]
+// CHECK-NEXT: [ 1, foo_2_1_1_1_1_1_1_2_2, 1748 ]
+// CHECK-NEXT: [ 1, foo_2_1_1_1_1_1_1_2_1, 1747 ]
+// CHECK-NEXT: [ 1, foo
+
+// SHARED-LABEL: shared_entry:
+// SHARED: [ 0, foo_1_1_1_1_1_1_1_1_1, 1000 ]
+// SHARED-NEXT: [ 0, foo_1_1_1_1_1_1_1_1_2, 999 ]
+// SHARED-NEXT: [ 0, foo_1_1_1_1_1_1_1_2_1, 998 ]
+// SHARED-NEXT: [ 0, foo_1_1_1_1_1_1_1_2_2, 997 ]
+// SHARED-NEXT: [ 0, foo_1_1_1_1_1_1_2_1_1, 996 ]
+// SHARED-NEXT: [ 0, foo_1_1_1_1_1_1_2_1_2, 995 ]
+// SHARED-NEXT: [ 0, foo_1_1_1_1_1_1_2_2_1, 994 ]
+// SHARED-NEXT: [ 0, foo_1_1_1_1_1_1_2_2_2, 993 ]
+// SHARED-NEXT: [ 0, foo_1_1_1_1_1_2_1_1_1, 992 ]
+// SHARED-NEXT: [ 0, foo_1_1_1_1_1_2_1_1_2, 991 ]
+// SHARED-NEXT: [ 0, foo_1_1_1_1_1_2_1_2_1, 990 ]
+// SHARED-NEXT: [ 0, foo_1_1_1_1_1_2_1_2_2, 989 ]
+// SHARED-NEXT: [ 0, foo_1_1_1_1_1_2_2_1_1, 988 ]
+// SHARED-NEXT: [ 0, foo_1_1_1_1_1_2_2_1_2, 987 ]
+// SHARED-NEXT: [ 0, foo_1_1_1_1_1_2_2_2_1, 986 ]
+// SHARED-NEXT: [ 0, foo_1_1_1_1_1_2_2_2_2, 985 ]
+// SHARED-NEXT: [ 0, foo_1_1_1_1_2_1_1_1_1, 984 ]
+// SHARED-NEXT: [ 0, foo_1_1_1_1_2_1_1_1_2, 983 ]
+// SHARED-NEXT: [ 0, foo_1_1_1_1_2_1_1_2_1, 982 ]
+// SHARED-NEXT: [ 0, foo_1_1_1_1_2_1_1_2_2, 981 ]
+// SHARED-NEXT: [ 0, foo_1_1_1_1_2_1_2_1_1, 980 ]
+// SHARED-NEXT: [ 0, foo_1_1_1_1_2_1_2_1_2, 979 ]
+// SHARED-NEXT: [ 0, foo_1_1_1_1_2_1_2_2_1, 978 ]
+// SHARED-NEXT: [ 0, foo_1_1_1_1_2_1_2_2_2, 977 ]
+// SHARED-NEXT: [ 0, foo_1_1_1_1_2_2_1_1_1, 976 ]
+// SHARED-NEXT: [ 0, foo_1_1_1_1_2_2_1_1_2, 975 ]
+// SHARED-NEXT: [ 0, foo_1_1_1_1_2_2_1_2_1, 974 ]
+// SHARED-NEXT: [ 0, foo_1_1_1_1_2_2_1_2_2, 973 ]
+// SHARED-NEXT: [ 0, foo_1_1_1_1_2_2_2_1_1, 972 ]
+// SHARED-NEXT: [ 0, foo_1_1_1_1_2_2_2_1_2, 971 ]
+// SHARED-NEXT: [ 0, foo_1_1_1_1_2_2_2_2_1, 970 ]
+// SHARED-NEXT: [ 0, foo_1_1_1_1_2_2_2_2_2, 969 ]
+// SHARED-NEXT: [ 0, foo_1_1_1_2_1_1_1_1_1, 968 ]
+// SHARED-NEXT: [ 0, foo_1_1_1_2_1_1_1_1_2, 967 ]
+// SHARED-NEXT: [ 0, foo_1_1_1_2_1_1_1_2_1, 966 ]
+// SHARED-NEXT: [ 0, foo_1_1_1_2_1_1_1_2_2, 965 ]
+// SHARED-NEXT: [ 0, foo_1_1_1_2_1_1_2_1_1, 964 ]
+// SHARED-NEXT: [ 0, foo_1_1_1_2_1_1_2_1_2, 963 ]
+// SHARED-NEXT: [ 0, foo_1_1_1_2_1_1_2_2_1, 962 ]
+// SHARED-NEXT: [ 0, foo_1_1_1_2_1_1_2_2_2, 961 ]
+// SHARED-NEXT: [ 0, foo_1_1_1_2_1_2_1_1_1, 960 ]
+// SHARED-NEXT: [ 0, foo_1_1_1_2_1_2_1_1_2, 959 ]
+// SHARED-NEXT: [ 0, foo_1_1_1_2_1_2_1_2_1, 958 ]
+// SHARED-NEXT: [ 0, foo_1_1_1_2_1_2_1_2_2, 957 ]
+// SHARED-NEXT: [ 0, foo_1_1_1_2_1_2_2_1_1, 956 ]
+// SHARED-NEXT: [ 0, foo_1_1_1_2_1_2_2_1_2, 955 ]
+// SHARED-NEXT: [ 0, foo_1_1_1_2_1_2_2_2_1, 954 ]
+// SHARED-NEXT: [ 0, foo_1_1_1_2_1_2_2_2_2, 953 ]
+// SHARED-NEXT: [ 0, foo_1_1_1_2_2_1_1_1_1, 952 ]
+// SHARED-NEXT: [ 0, foo_1_1_1_2_2_1_1_1_2, 951 ]
+// SHARED-NEXT: [ 0, foo_1_1_1_2_2_1_1_2_1, 950 ]
+// SHARED-NEXT: [ 0, foo_1_1_1_2_2_1_1_2_2, 949 ]
+// SHARED-NEXT: [ 0, foo_1_1_1_2_2_1_2_1_1, 948 ]
+// SHARED-NEXT: [ 0, foo_1_1_1_2_2_1_2_1_2, 947 ]
+// SHARED-NEXT: [ 0, foo_1_1_1_2_2_1_2_2_1, 946 ]
+// SHARED-NEXT: [ 0, foo_1_1_1_2_2_1_2_2_2, 945 ]
+// SHARED-NEXT: [ 0, foo_1_1_1_2_2_2_1_1_1, 944 ]
+// SHARED-NEXT: [ 0, foo_1_1_1_2_2_2_1_1_2, 943 ]
+// SHARED-NEXT: [ 0, foo_1_1_1_2_2_2_1_2_1, 942 ]
+// SHARED-NEXT: [ 0, foo_1_1_1_2_2_2_1_2_2, 941 ]
+// SHARED-NEXT: [ 0, foo_1_1_1_2_2_2_2_1_1, 940 ]
+// SHARED-NEXT: [ 0, foo_1_1_1_2_2_2_2_1_2, 939 ]
+// SHARED-NEXT: [ 0, foo_1_1_1_2_2_2_2_2_1, 938 ]
+// SHARED-NEXT: [ 0, foo_1_1_1_2_2_2_2_2_2, 937 ]
+// SHARED-NEXT: [ 0, foo_1_1_2_1_1_1_1_1_1, 936 ]
+// SHARED-NEXT: [ 0, foo_1_1_2_1_1_1_1_1_2, 935 ]
+// SHARED-NEXT: [ 0, foo_1_1_2_1_1_1_1_2_1, 934 ]
+// SHARED-NEXT: [ 0, foo_1_1_2_1_1_1_1_2_2, 933 ]
+// SHARED-NEXT: [ 0, foo_1_1_2_1_1_1_2_1_1, 932 ]
+// SHARED-NEXT: [ 0, foo_1_1_2_1_1_1_2_1_2, 931 ]
+// SHARED-NEXT: [ 0, foo_1_1_2_1_1_1_2_2_1, 930 ]
+// SHARED-NEXT: [ 0, foo_1_1_2_1_1_1_2_2_2, 929 ]
+// SHARED-NEXT: [ 0, foo_1_1_2_1_1_2_1_1_1, 928 ]
+// SHARED-NEXT: [ 0, foo_1_1_2_1_1_2_1_1_2, 927 ]
+// SHARED-NEXT: [ 0, foo_1_1_2_1_1_2_1_2_1, 926 ]
+// SHARED-NEXT: [ 0, foo_1_1_2_1_1_2_1_2_2, 925 ]
+// SHARED-NEXT: [ 0, foo_1_1_2_1_1_2_2_1_1, 924 ]
+// SHARED-NEXT: [ 0, foo_1_1_2_1_1_2_2_1_2, 923 ]
+// SHARED-NEXT: [ 0, foo_1_1_2_1_1_2_2_2_1, 922 ]
+// SHARED-NEXT: [ 0, foo_1_1_2_1_1_2_2_2_2, 921 ]
+// SHARED-NEXT: [ 0, foo_1_1_2_1_2_1_1_1_1, 920 ]
+// SHARED-NEXT: [ 0, foo_1_1_2_1_2_1_1_1_2, 919 ]
+// SHARED-NEXT: [ 0, foo_1_1_2_1_2_1_1_2_1, 918 ]
+// SHARED-NEXT: [ 0, foo_1_1_2_1_2_1_1_2_2, 917 ]
+// SHARED-NEXT: [ 0, foo_1_1_2_1_2_1_2_1_1, 916 ]
+// SHARED-NEXT: [ 0, foo_1_1_2_1_2_1_2_1_2, 915 ]
+// SHARED-NEXT: [ 0, foo_1_1_2_1_2_1_2_2_1, 914 ]
+// SHARED-NEXT: [ 0, foo_1_1_2_1_2_1_2_2_2, 913 ]
+// SHARED-NEXT: [ 0, foo_1_1_2_1_2_2_1_1_1, 912 ]
+// SHARED-NEXT: [ 0, foo_1_1_2_1_2_2_1_1_2, 911 ]
+// SHARED-NEXT: [ 0, foo_1_1_2_1_2_2_1_2_1, 910 ]
+// SHARED-NEXT: [ 0, foo_1_1_2_1_2_2_1_2_2, 909 ]
+// SHARED-NEXT: [ 0, foo_1_1_2_1_2_2_2_1_1, 908 ]
+// SHARED-NEXT: [ 0, foo_1_1_2_1_2_2_2_1_2, 907 ]
+// SHARED-NEXT: [ 0, foo_1_1_2_1_2_2_2_2_1, 906 ]
+// SHARED-NEXT: [ 0, foo_1_1_2_1_2_2_2_2_2, 905 ]
+// SHARED-NEXT: [ 0, foo_1_1_2_2_1_1_1_1_1, 904 ]
+// SHARED-NEXT: [ 0, foo_1_1_2_2_1_1_1_1_2, 903 ]
+// SHARED-NEXT: [ 0, foo_1_1_2_2_1_1_1_2_1, 902 ]
+// SHARED-NEXT: [ 0, foo_1_1_2_2_1_1_1_2_2, 901 ]
+// SHARED-NEXT: [ 0, foo_1_1_2_2_1_1_2_1_1, 900 ]
+// SHARED-NEXT: [ 0, foo_1_1_2_2_1_1_2_1_2, 899 ]
+// SHARED-NEXT: [ 0, foo_1_1_2_2_1_1_2_2_1, 898 ]
+// SHARED-NEXT: [ 0, foo_1_1_2_2_1_1_2_2_2, 897 ]
+// SHARED-NEXT: [ 0, foo_1_1_2_2_1_2_1_1_1, 896 ]
+// SHARED-NEXT: [ 0, foo_1_1_2_2_1_2_1_1_2, 895 ]
+// SHARED-NEXT: [ 0, foo_1_1_2_2_1_2_1_2_1, 894 ]
+// SHARED-NEXT: [ 0, foo_1_1_2_2_1_2_1_2_2, 893 ]
+// SHARED-NEXT: [ 0, foo_1_1_2_2_1_2_2_1_1, 892 ]
+// SHARED-NEXT: [ 0, foo_1_1_2_2_1_2_2_1_2, 891 ]
+// SHARED-NEXT: [ 0, foo_1_1_2_2_1_2_2_2_1, 890 ]
+// SHARED-NEXT: [ 0, foo_1_1_2_2_1_2_2_2_2, 889 ]
+// SHARED-NEXT: [ 0, foo_1_1_2_2_2_1_1_1_1, 888 ]
+// SHARED-NEXT: [ 0, foo_1_1_2_2_2_1_1_1_2, 887 ]
+// SHARED-NEXT: [ 0, foo_1_1_2_2_2_1_1_2_1, 886 ]
+// SHARED-NEXT: [ 0, foo_1_1_2_2_2_1_1_2_2, 885 ]
+// SHARED-NEXT: [ 0, foo_1_1_2_2_2_1_2_1_1, 884 ]
+// SHARED-NEXT: [ 0, foo_1_1_2_2_2_1_2_1_2, 883 ]
+// SHARED-NEXT: [ 0, foo_1_1_2_2_2_1_2_2_1, 882 ]
+// SHARED-NEXT: [ 0, foo_1_1_2_2_2_1_2_2_2, 881 ]
+// SHARED-NEXT: [ 0, foo_1_1_2_2_2_2_1_1_1, 880 ]
+// SHARED-NEXT: [ 0, foo_1_1_2_2_2_2_1_1_2, 879 ]
+// SHARED-NEXT: [ 0, foo_1_1_2_2_2_2_1_2_1, 878 ]
+// SHARED-NEXT: [ 0, foo_1_1_2_2_2_2_1_2_2, 877 ]
+// SHARED-NEXT: [ 0, foo_1_1_2_2_2_2_2_1_1, 876 ]
+// SHARED-NEXT: [ 0, foo_1_1_2_2_2_2_2_1_2, 875 ]
+// SHARED-NEXT: [ 0, foo_1_1_2_2_2_2_2_2_1, 874 ]
+// SHARED-NEXT: [ 0, foo_1_1_2_2_2_2_2_2_2, 873 ]
+// SHARED-NEXT: [ 0, foo_1_2_1_1_1_1_1_1_1, 872 ]
+// SHARED-NEXT: [ 0, foo_1_2_1_1_1_1_1_1_2, 871 ]
+// SHARED-NEXT: [ 0, foo_1_2_1_1_1_1_1_2_1, 870 ]
+// SHARED-NEXT: [ 0, foo_1_2_1_1_1_1_1_2_2, 869 ]
+// SHARED-NEXT: [ 0, foo_1_2_1_1_1_1_2_1_1, 868 ]
+// SHARED-NEXT: [ 0, foo_1_2_1_1_1_1_2_1_2, 867 ]
+// SHARED-NEXT: [ 0, foo_1_2_1_1_1_1_2_2_1, 866 ]
+// SHARED-NEXT: [ 0, foo_1_2_1_1_1_1_2_2_2, 865 ]
+// SHARED-NEXT: [ 0, foo_1_2_1_1_1_2_1_1_1, 864 ]
+// SHARED-NEXT: [ 0, foo_1_2_1_1_1_2_1_1_2, 863 ]
+// SHARED-NEXT: [ 0, foo_1_2_1_1_1_2_1_2_1, 862 ]
+// SHARED-NEXT: [ 0, foo_1_2_1_1_1_2_1_2_2, 861 ]
+// SHARED-NEXT: [ 0, foo_1_2_1_1_1_2_2_1_1, 860 ]
+// SHARED-NEXT: [ 0, foo_1_2_1_1_1_2_2_1_2, 859 ]
+// SHARED-NEXT: [ 0, foo_1_2_1_1_1_2_2_2_1, 858 ]
+// SHARED-NEXT: [ 0, foo_1_2_1_1_1_2_2_2_2, 857 ]
+// SHARED-NEXT: [ 0, foo_1_2_1_1_2_1_1_1_1, 856 ]
+// SHARED-NEXT: [ 0, foo_1_2_1_1_2_1_1_1_2, 855 ]
+// SHARED-NEXT: [ 0, foo_1_2_1_1_2_1_1_2_1, 854 ]
+// SHARED-NEXT: [ 0, foo_1_2_1_1_2_1_1_2_2, 853 ]
+// SHARED-NEXT: [ 0, foo_1_2_1_1_2_1_2_1_1, 852 ]
+// SHARED-NEXT: [ 0, foo_1_2_1_1_2_1_2_1_2, 851 ]
+// SHARED-NEXT: [ 0, foo_1_2_1_1_2_1_2_2_1, 850 ]
+// SHARED-NEXT: [ 0, foo_1_2_1_1_2_1_2_2_2, 849 ]
+// SHARED-NEXT: [ 0, foo_1_2_1_1_2_2_1_1_1, 848 ]
+// SHARED-NEXT: [ 0, foo_1_2_1_1_2_2_1_1_2, 847 ]
+// SHARED-NEXT: [ 0, foo_1_2_1_1_2_2_1_2_1, 846 ]
+// SHARED-NEXT: [ 0, foo_1_2_1_1_2_2_1_2_2, 845 ]
+// SHARED-NEXT: [ 0, foo_1_2_1_1_2_2_2_1_1, 844 ]
+// SHARED-NEXT: [ 0, foo_1_2_1_1_2_2_2_1_2, 843 ]
+// SHARED-NEXT: [ 0, foo_1_2_1_1_2_2_2_2_1, 842 ]
+// SHARED-NEXT: [ 0, foo_1_2_1_1_2_2_2_2_2, 841 ]
+// SHARED-NEXT: [ 0, foo_1_2_1_2_1_1_1_1_1, 840 ]
+// SHARED-NEXT: [ 0, foo_1_2_1_2_1_1_1_1_2, 839 ]
+// SHARED-NEXT: [ 0, foo_1_2_1_2_1_1_1_2_1, 838 ]
+// SHARED-NEXT: [ 0, foo_1_2_1_2_1_1_1_2_2, 837 ]
+// SHARED-NEXT: [ 0, foo_1_2_1_2_1_1_2_1_1, 836 ]
+// SHARED-NEXT: [ 0, foo_1_2_1_2_1_1_2_1_2, 835 ]
+// SHARED-NEXT: [ 0, foo_1_2_1_2_1_1_2_2_1, 834 ]
+// SHARED-NEXT: [ 0, foo_1_2_1_2_1_1_2_2_2, 833 ]
+// SHARED-NEXT: [ 0, foo_1_2_1_2_1_2_1_1_1, 832 ]
+// SHARED-NEXT: [ 0, foo_1_2_1_2_1_2_1_1_2, 831 ]
+// SHARED-NEXT: [ 0, foo_1_2_1_2_1_2_1_2_1, 830 ]
+// SHARED-NEXT: [ 0, foo_1_2_1_2_1_2_1_2_2, 829 ]
+// SHARED-NEXT: [ 0, foo_1_2_1_2_1_2_2_1_1, 828 ]
+// SHARED-NEXT: [ 0, foo_1_2_1_2_1_2_2_1_2, 827 ]
+// SHARED-NEXT: [ 0, foo_1_2_1_2_1_2_2_2_1, 826 ]
+// SHARED-NEXT: [ 0, foo_1_2_1_2_1_2_2_2_2, 825 ]
+// SHARED-NEXT: [ 0, foo_1_2_1_2_2_1_1_1_1, 824 ]
+// SHARED-NEXT: [ 0, foo_1_2_1_2_2_1_1_1_2, 823 ]
+// SHARED-NEXT: [ 0, foo_1_2_1_2_2_1_1_2_1, 822 ]
+// SHARED-NEXT: [ 0, foo_1_2_1_2_2_1_1_2_2, 821 ]
+// SHARED-NEXT: [ 0, foo_1_2_1_2_2_1_2_1_1, 820 ]
+// SHARED-NEXT: [ 0, foo_1_2_1_2_2_1_2_1_2, 819 ]
+// SHARED-NEXT: [ 0, foo_1_2_1_2_2_1_2_2_1, 818 ]
+// SHARED-NEXT: [ 0, foo_1_2_1_2_2_1_2_2_2, 817 ]
+// SHARED-NEXT: [ 0, foo_1_2_1_2_2_2_1_1_1, 816 ]
+// SHARED-NEXT: [ 0, foo_1_2_1_2_2_2_1_1_2, 815 ]
+// SHARED-NEXT: [ 0, foo_1_2_1_2_2_2_1_2_1, 814 ]
+// SHARED-NEXT: [ 0, foo_1_2_1_2_2_2_1_2_2, 813 ]
+// SHARED-NEXT: [ 0, foo_1_2_1_2_2_2_2_1_1, 812 ]
+// SHARED-NEXT: [ 0, foo_1_2_1_2_2_2_2_1_2, 811 ]
+// SHARED-NEXT: [ 0, foo_1_2_1_2_2_2_2_2_1, 810 ]
+// SHARED-NEXT: [ 0, foo_1_2_1_2_2_2_2_2_2, 809 ]
+// SHARED-NEXT: [ 0, foo_1_2_2_1_1_1_1_1_1, 808 ]
+// SHARED-NEXT: [ 0, foo_1_2_2_1_1_1_1_1_2, 807 ]
+// SHARED-NEXT: [ 0, foo_1_2_2_1_1_1_1_2_1, 806 ]
+// SHARED-NEXT: [ 0, foo_1_2_2_1_1_1_1_2_2, 805 ]
+// SHARED-NEXT: [ 0, foo_1_2_2_1_1_1_2_1_1, 804 ]
+// SHARED-NEXT: [ 0, foo_1_2_2_1_1_1_2_1_2, 803 ]
+// SHARED-NEXT: [ 0, foo_1_2_2_1_1_1_2_2_1, 802 ]
+// SHARED-NEXT: [ 0, foo_1_2_2_1_1_1_2_2_2, 801 ]
+// SHARED-NEXT: [ 0, foo_1_2_2_1_1_2_1_1_1, 800 ]
+// SHARED-NEXT: [ 0, foo_1_2_2_1_1_2_1_1_2, 799 ]
+// SHARED-NEXT: [ 0, foo_1_2_2_1_1_2_1_2_1, 798 ]
+// SHARED-NEXT: [ 0, foo_1_2_2_1_1_2_1_2_2, 797 ]
+// SHARED-NEXT: [ 0, foo_1_2_2_1_1_2_2_1_1, 796 ]
+// SHARED-NEXT: [ 0, foo_1_2_2_1_1_2_2_1_2, 795 ]
+// SHARED-NEXT: [ 0, foo_1_2_2_1_1_2_2_2_1, 794 ]
+// SHARED-NEXT: [ 0, foo_1_2_2_1_1_2_2_2_2, 793 ]
+// SHARED-NEXT: [ 0, foo_1_2_2_1_2_1_1_1_1, 792 ]
+// SHARED-NEXT: [ 0, foo_1_2_2_1_2_1_1_1_2, 791 ]
+// SHARED-NEXT: [ 0, foo_1_2_2_1_2_1_1_2_1, 790 ]
+// SHARED-NEXT: [ 0, foo_1_2_2_1_2_1_1_2_2, 789 ]
+// SHARED-NEXT: [ 0, foo_1_2_2_1_2_1_2_1_1, 788 ]
+// SHARED-NEXT: [ 0, foo_1_2_2_1_2_1_2_1_2, 787 ]
+// SHARED-NEXT: [ 0, foo_1_2_2_1_2_1_2_2_1, 786 ]
+// SHARED-NEXT: [ 0, foo_1_2_2_1_2_1_2_2_2, 785 ]
+// SHARED-NEXT: [ 0, foo_1_2_2_1_2_2_1_1_1, 784 ]
+// SHARED-NEXT: [ 0, foo_1_2_2_1_2_2_1_1_2, 783 ]
+// SHARED-NEXT: [ 0, foo_1_2_2_1_2_2_1_2_1, 782 ]
+// SHARED-NEXT: [ 0, foo_1_2_2_1_2_2_1_2_2, 781 ]
+// SHARED-NEXT: [ 0, foo_1_2_2_1_2_2_2_1_1, 780 ]
+// SHARED-NEXT: [ 0, foo_1_2_2_1_2_2_2_1_2, 779 ]
+// SHARED-NEXT: [ 0, foo_1_2_2_1_2_2_2_2_1, 778 ]
+// SHARED-NEXT: [ 0, foo_1_2_2_1_2_2_2_2_2, 777 ]
+// SHARED-NEXT: [ 0, foo_1_2_2_2_1_1_1_1_1, 776 ]
+// SHARED-NEXT: [ 0, foo_1_2_2_2_1_1_1_1_2, 775 ]
+// SHARED-NEXT: [ 0, foo_1_2_2_2_1_1_1_2_1, 774 ]
+// SHARED-NEXT: [ 0, foo_1_2_2_2_1_1_1_2_2, 773 ]
+// SHARED-NEXT: [ 0, foo_1_2_2_2_1_1_2_1_1, 772 ]
+// SHARED-NEXT: [ 0, foo_1_2_2_2_1_1_2_1_2, 771 ]
+// SHARED-NEXT: [ 0, foo_1_2_2_2_1_1_2_2_1, 770 ]
+// SHARED-NEXT: [ 0, foo_1_2_2_2_1_1_2_2_2, 769 ]
+// SHARED-NEXT: [ 0, foo_1_2_2_2_1_2_1_1_1, 768 ]
+// SHARED-NEXT: [ 0, foo_1_2_2_2_1_2_1_1_2, 767 ]
+// SHARED-NEXT: [ 0, foo_1_2_2_2_1_2_1_2_1, 766 ]
+// SHARED-NEXT: [ 0, foo_1_2_2_2_1_2_1_2_2, 765 ]
+// SHARED-NEXT: [ 0, foo_1_2_2_2_1_2_2_1_1, 764 ]
+// SHARED-NEXT: [ 0, foo_1_2_2_2_1_2_2_1_2, 763 ]
+// SHARED-NEXT: [ 0, foo_1_2_2_2_1_2_2_2_1, 762 ]
+// SHARED-NEXT: [ 0, foo_1_2_2_2_1_2_2_2_2, 761 ]
+// SHARED-NEXT: [ 0, foo_1_2_2_2_2_1_1_1_1, 760 ]
+// SHARED-NEXT: [ 0, foo_1_2_2_2_2_1_1_1_2, 759 ]
+// SHARED-NEXT: [ 0, foo_1_2_2_2_2_1_1_2_1, 758 ]
+// SHARED-NEXT: [ 0, foo_1_2_2_2_2_1_1_2_2, 757 ]
+// SHARED-NEXT: [ 0, foo_1_2_2_2_2_1_2_1_1, 756 ]
+// SHARED-NEXT: [ 0, foo_1_2_2_2_2_1_2_1_2, 755 ]
+// SHARED-NEXT: [ 0, foo_1_2_2_2_2_1_2_2_1, 754 ]
+// SHARED-NEXT: [ 0, foo_1_2_2_2_2_1_2_2_2, 753 ]
+// SHARED-NEXT: [ 0, foo_1_2_2_2_2_2_1_1_1, 752 ]
+// SHARED-NEXT: [ 0, foo_1_2_2_2_2_2_1_1_2, 751 ]
+// SHARED-NEXT: [ 0, foo_1_2_2_2_2_2_1_2_1, 750 ]
+// SHARED-NEXT: [ 0, foo_1_2_2_2_2_2_1_2_2, 749 ]
+// SHARED-NEXT: [ 0, foo_1_2_2_2_2_2_2_1_1, 748 ]
+// SHARED-NEXT: [ 0, foo_1_2_2_2_2_2_2_1_2, 747 ]
+// SHARED-NEXT: [ 0, foo
+// SHARED-NEXT: [ 1, foo_2_2_2_2_2_2_2_2_2, 2000 ]
+// SHARED-NEXT: [ 1, foo_2_2_2_2_2_2_2_2_1, 1999 ]
+// SHARED-NEXT: [ 1, foo_2_2_2_2_2_2_2_1_2, 1998 ]
+// SHARED-NEXT: [ 1, foo_2_2_2_2_2_2_2_1_1, 1997 ]
+// SHARED-NEXT: [ 1, foo_2_2_2_2_2_2_1_2_2, 1996 ]
+// SHARED-NEXT: [ 1, foo_2_2_2_2_2_2_1_2_1, 1995 ]
+// SHARED-NEXT: [ 1, foo_2_2_2_2_2_2_1_1_2, 1994 ]
+// SHARED-NEXT: [ 1, foo_2_2_2_2_2_2_1_1_1, 1993 ]
+// SHARED-NEXT: [ 1, foo_2_2_2_2_2_1_2_2_2, 1992 ]
+// SHARED-NEXT: [ 1, foo_2_2_2_2_2_1_2_2_1, 1991 ]
+// SHARED-NEXT: [ 1, foo_2_2_2_2_2_1_2_1_2, 1990 ]
+// SHARED-NEXT: [ 1, foo_2_2_2_2_2_1_2_1_1, 1989 ]
+// SHARED-NEXT: [ 1, foo_2_2_2_2_2_1_1_2_2, 1988 ]
+// SHARED-NEXT: [ 1, foo_2_2_2_2_2_1_1_2_1, 1987 ]
+// SHARED-NEXT: [ 1, foo_2_2_2_2_2_1_1_1_2, 1986 ]
+// SHARED-NEXT: [ 1, foo_2_2_2_2_2_1_1_1_1, 1985 ]
+// SHARED-NEXT: [ 1, foo_2_2_2_2_1_2_2_2_2, 1984 ]
+// SHARED-NEXT: [ 1, foo_2_2_2_2_1_2_2_2_1, 1983 ]
+// SHARED-NEXT: [ 1, foo_2_2_2_2_1_2_2_1_2, 1982 ]
+// SHARED-NEXT: [ 1, foo_2_2_2_2_1_2_2_1_1, 1981 ]
+// SHARED-NEXT: [ 1, foo_2_2_2_2_1_2_1_2_2, 1980 ]
+// SHARED-NEXT: [ 1, foo_2_2_2_2_1_2_1_2_1, 1979 ]
+// SHARED-NEXT: [ 1, foo_2_2_2_2_1_2_1_1_2, 1978 ]
+// SHARED-NEXT: [ 1, foo_2_2_2_2_1_2_1_1_1, 1977 ]
+// SHARED-NEXT: [ 1, foo_2_2_2_2_1_1_2_2_2, 1976 ]
+// SHARED-NEXT: [ 1, foo_2_2_2_2_1_1_2_2_1, 1975 ]
+// SHARED-NEXT: [ 1, foo_2_2_2_2_1_1_2_1_2, 1974 ]
+// SHARED-NEXT: [ 1, foo_2_2_2_2_1_1_2_1_1, 1973 ]
+// SHARED-NEXT: [ 1, foo_2_2_2_2_1_1_1_2_2, 1972 ]
+// SHARED-NEXT: [ 1, foo_2_2_2_2_1_1_1_2_1, 1971 ]
+// SHARED-NEXT: [ 1, foo_2_2_2_2_1_1_1_1_2, 1970 ]
+// SHARED-NEXT: [ 1, foo_2_2_2_2_1_1_1_1_1, 1969 ]
+// SHARED-NEXT: [ 1, foo_2_2_2_1_2_2_2_2_2, 1968 ]
+// SHARED-NEXT: [ 1, foo_2_2_2_1_2_2_2_2_1, 1967 ]
+// SHARED-NEXT: [ 1, foo_2_2_2_1_2_2_2_1_2, 1966 ]
+// SHARED-NEXT: [ 1, foo_2_2_2_1_2_2_2_1_1, 1965 ]
+// SHARED-NEXT: [ 1, foo_2_2_2_1_2_2_1_2_2, 1964 ]
+// SHARED-NEXT: [ 1, foo_2_2_2_1_2_2_1_2_1, 1963 ]
+// SHARED-NEXT: [ 1, foo_2_2_2_1_2_2_1_1_2, 1962 ]
+// SHARED-NEXT: [ 1, foo_2_2_2_1_2_2_1_1_1, 1961 ]
+// SHARED-NEXT: [ 1, foo_2_2_2_1_2_1_2_2_2, 1960 ]
+// SHARED-NEXT: [ 1, foo_2_2_2_1_2_1_2_2_1, 1959 ]
+// SHARED-NEXT: [ 1, foo_2_2_2_1_2_1_2_1_2, 1958 ]
+// SHARED-NEXT: [ 1, foo_2_2_2_1_2_1_2_1_1, 1957 ]
+// SHARED-NEXT: [ 1, foo_2_2_2_1_2_1_1_2_2, 1956 ]
+// SHARED-NEXT: [ 1, foo_2_2_2_1_2_1_1_2_1, 1955 ]
+// SHARED-NEXT: [ 1, foo_2_2_2_1_2_1_1_1_2, 1954 ]
+// SHARED-NEXT: [ 1, foo_2_2_2_1_2_1_1_1_1, 1953 ]
+// SHARED-NEXT: [ 1, foo_2_2_2_1_1_2_2_2_2, 1952 ]
+// SHARED-NEXT: [ 1, foo_2_2_2_1_1_2_2_2_1, 1951 ]
+// SHARED-NEXT: [ 1, foo_2_2_2_1_1_2_2_1_2, 1950 ]
+// SHARED-NEXT: [ 1, foo_2_2_2_1_1_2_2_1_1, 1949 ]
+// SHARED-NEXT: [ 1, foo_2_2_2_1_1_2_1_2_2, 1948 ]
+// SHARED-NEXT: [ 1, foo_2_2_2_1_1_2_1_2_1, 1947 ]
+// SHARED-NEXT: [ 1, foo_2_2_2_1_1_2_1_1_2, 1946 ]
+// SHARED-NEXT: [ 1, foo_2_2_2_1_1_2_1_1_1, 1945 ]
+// SHARED-NEXT: [ 1, foo_2_2_2_1_1_1_2_2_2, 1944 ]
+// SHARED-NEXT: [ 1, foo_2_2_2_1_1_1_2_2_1, 1943 ]
+// SHARED-NEXT: [ 1, foo_2_2_2_1_1_1_2_1_2, 1942 ]
+// SHARED-NEXT: [ 1, foo_2_2_2_1_1_1_2_1_1, 1941 ]
+// SHARED-NEXT: [ 1, foo_2_2_2_1_1_1_1_2_2, 1940 ]
+// SHARED-NEXT: [ 1, foo_2_2_2_1_1_1_1_2_1, 1939 ]
+// SHARED-NEXT: [ 1, foo_2_2_2_1_1_1_1_1_2, 1938 ]
+// SHARED-NEXT: [ 1, foo_2_2_2_1_1_1_1_1_1, 1937 ]
+// SHARED-NEXT: [ 1, foo_2_2_1_2_2_2_2_2_2, 1936 ]
+// SHARED-NEXT: [ 1, foo_2_2_1_2_2_2_2_2_1, 1935 ]
+// SHARED-NEXT: [ 1, foo_2_2_1_2_2_2_2_1_2, 1934 ]
+// SHARED-NEXT: [ 1, foo_2_2_1_2_2_2_2_1_1, 1933 ]
+// SHARED-NEXT: [ 1, foo_2_2_1_2_2_2_1_2_2, 1932 ]
+// SHARED-NEXT: [ 1, foo_2_2_1_2_2_2_1_2_1, 1931 ]
+// SHARED-NEXT: [ 1, foo_2_2_1_2_2_2_1_1_2, 1930 ]
+// SHARED-NEXT: [ 1, foo_2_2_1_2_2_2_1_1_1, 1929 ]
+// SHARED-NEXT: [ 1, foo_2_2_1_2_2_1_2_2_2, 1928 ]
+// SHARED-NEXT: [ 1, foo_2_2_1_2_2_1_2_2_1, 1927 ]
+// SHARED-NEXT: [ 1, foo_2_2_1_2_2_1_2_1_2, 1926 ]
+// SHARED-NEXT: [ 1, foo_2_2_1_2_2_1_2_1_1, 1925 ]
+// SHARED-NEXT: [ 1, foo_2_2_1_2_2_1_1_2_2, 1924 ]
+// SHARED-NEXT: [ 1, foo_2_2_1_2_2_1_1_2_1, 1923 ]
+// SHARED-NEXT: [ 1, foo_2_2_1_2_2_1_1_1_2, 1922 ]
+// SHARED-NEXT: [ 1, foo_2_2_1_2_2_1_1_1_1, 1921 ]
+// SHARED-NEXT: [ 1, foo_2_2_1_2_1_2_2_2_2, 1920 ]
+// SHARED-NEXT: [ 1, foo_2_2_1_2_1_2_2_2_1, 1919 ]
+// SHARED-NEXT: [ 1, foo_2_2_1_2_1_2_2_1_2, 1918 ]
+// SHARED-NEXT: [ 1, foo_2_2_1_2_1_2_2_1_1, 1917 ]
+// SHARED-NEXT: [ 1, foo_2_2_1_2_1_2_1_2_2, 1916 ]
+// SHARED-NEXT: [ 1, foo_2_2_1_2_1_2_1_2_1, 1915 ]
+// SHARED-NEXT: [ 1, foo_2_2_1_2_1_2_1_1_2, 1914 ]
+// SHARED-NEXT: [ 1, foo_2_2_1_2_1_2_1_1_1, 1913 ]
+// SHARED-NEXT: [ 1, foo_2_2_1_2_1_1_2_2_2, 1912 ]
+// SHARED-NEXT: [ 1, foo_2_2_1_2_1_1_2_2_1, 1911 ]
+// SHARED-NEXT: [ 1, foo_2_2_1_2_1_1_2_1_2, 1910 ]
+// SHARED-NEXT: [ 1, foo_2_2_1_2_1_1_2_1_1, 1909 ]
+// SHARED-NEXT: [ 1, foo_2_2_1_2_1_1_1_2_2, 1908 ]
+// SHARED-NEXT: [ 1, foo_2_2_1_2_1_1_1_2_1, 1907 ]
+// SHARED-NEXT: [ 1, foo_2_2_1_2_1_1_1_1_2, 1906 ]
+// SHARED-NEXT: [ 1, foo_2_2_1_2_1_1_1_1_1, 1905 ]
+// SHARED-NEXT: [ 1, foo_2_2_1_1_2_2_2_2_2, 1904 ]
+// SHARED-NEXT: [ 1, foo_2_2_1_1_2_2_2_2_1, 1903 ]
+// SHARED-NEXT: [ 1, foo_2_2_1_1_2_2_2_1_2, 1902 ]
+// SHARED-NEXT: [ 1, foo_2_2_1_1_2_2_2_1_1, 1901 ]
+// SHARED-NEXT: [ 1, foo_2_2_1_1_2_2_1_2_2, 1900 ]
+// SHARED-NEXT: [ 1, foo_2_2_1_1_2_2_1_2_1, 1899 ]
+// SHARED-NEXT: [ 1, foo_2_2_1_1_2_2_1_1_2, 1898 ]
+// SHARED-NEXT: [ 1, foo_2_2_1_1_2_2_1_1_1, 1897 ]
+// SHARED-NEXT: [ 1, foo_2_2_1_1_2_1_2_2_2, 1896 ]
+// SHARED-NEXT: [ 1, foo_2_2_1_1_2_1_2_2_1, 1895 ]
+// SHARED-NEXT: [ 1, foo_2_2_1_1_2_1_2_1_2, 1894 ]
+// SHARED-NEXT: [ 1, foo_2_2_1_1_2_1_2_1_1, 1893 ]
+// SHARED-NEXT: [ 1, foo_2_2_1_1_2_1_1_2_2, 1892 ]
+// SHARED-NEXT: [ 1, foo_2_2_1_1_2_1_1_2_1, 1891 ]
+// SHARED-NEXT: [ 1, foo_2_2_1_1_2_1_1_1_2, 1890 ]
+// SHARED-NEXT: [ 1, foo_2_2_1_1_2_1_1_1_1, 1889 ]
+// SHARED-NEXT: [ 1, foo_2_2_1_1_1_2_2_2_2, 1888 ]
+// SHARED-NEXT: [ 1, foo_2_2_1_1_1_2_2_2_1, 1887 ]
+// SHARED-NEXT: [ 1, foo_2_2_1_1_1_2_2_1_2, 1886 ]
+// SHARED-NEXT: [ 1, foo_2_2_1_1_1_2_2_1_1, 1885 ]
+// SHARED-NEXT: [ 1, foo_2_2_1_1_1_2_1_2_2, 1884 ]
+// SHARED-NEXT: [ 1, foo_2_2_1_1_1_2_1_2_1, 1883 ]
+// SHARED-NEXT: [ 1, foo_2_2_1_1_1_2_1_1_2, 1882 ]
+// SHARED-NEXT: [ 1, foo_2_2_1_1_1_2_1_1_1, 1881 ]
+// SHARED-NEXT: [ 1, foo_2_2_1_1_1_1_2_2_2, 1880 ]
+// SHARED-NEXT: [ 1, foo_2_2_1_1_1_1_2_2_1, 1879 ]
+// SHARED-NEXT: [ 1, foo_2_2_1_1_1_1_2_1_2, 1878 ]
+// SHARED-NEXT: [ 1, foo_2_2_1_1_1_1_2_1_1, 1877 ]
+// SHARED-NEXT: [ 1, foo_2_2_1_1_1_1_1_2_2, 1876 ]
+// SHARED-NEXT: [ 1, foo_2_2_1_1_1_1_1_2_1, 1875 ]
+// SHARED-NEXT: [ 1, foo_2_2_1_1_1_1_1_1_2, 1874 ]
+// SHARED-NEXT: [ 1, foo_2_2_1_1_1_1_1_1_1, 1873 ]
+// SHARED-NEXT: [ 1, foo_2_1_2_2_2_2_2_2_2, 1872 ]
+// SHARED-NEXT: [ 1, foo_2_1_2_2_2_2_2_2_1, 1871 ]
+// SHARED-NEXT: [ 1, foo_2_1_2_2_2_2_2_1_2, 1870 ]
+// SHARED-NEXT: [ 1, foo_2_1_2_2_2_2_2_1_1, 1869 ]
+// SHARED-NEXT: [ 1, foo_2_1_2_2_2_2_1_2_2, 1868 ]
+// SHARED-NEXT: [ 1, foo_2_1_2_2_2_2_1_2_1, 1867 ]
+// SHARED-NEXT: [ 1, foo_2_1_2_2_2_2_1_1_2, 1866 ]
+// SHARED-NEXT: [ 1, foo_2_1_2_2_2_2_1_1_1, 1865 ]
+// SHARED-NEXT: [ 1, foo_2_1_2_2_2_1_2_2_2, 1864 ]
+// SHARED-NEXT: [ 1, foo_2_1_2_2_2_1_2_2_1, 1863 ]
+// SHARED-NEXT: [ 1, foo_2_1_2_2_2_1_2_1_2, 1862 ]
+// SHARED-NEXT: [ 1, foo_2_1_2_2_2_1_2_1_1, 1861 ]
+// SHARED-NEXT: [ 1, foo_2_1_2_2_2_1_1_2_2, 1860 ]
+// SHARED-NEXT: [ 1, foo_2_1_2_2_2_1_1_2_1, 1859 ]
+// SHARED-NEXT: [ 1, foo_2_1_2_2_2_1_1_1_2, 1858 ]
+// SHARED-NEXT: [ 1, foo_2_1_2_2_2_1_1_1_1, 1857 ]
+// SHARED-NEXT: [ 1, foo_2_1_2_2_1_2_2_2_2, 1856 ]
+// SHARED-NEXT: [ 1, foo_2_1_2_2_1_2_2_2_1, 1855 ]
+// SHARED-NEXT: [ 1, foo_2_1_2_2_1_2_2_1_2, 1854 ]
+// SHARED-NEXT: [ 1, foo_2_1_2_2_1_2_2_1_1, 1853 ]
+// SHARED-NEXT: [ 1, foo_2_1_2_2_1_2_1_2_2, 1852 ]
+// SHARED-NEXT: [ 1, foo_2_1_2_2_1_2_1_2_1, 1851 ]
+// SHARED-NEXT: [ 1, foo_2_1_2_2_1_2_1_1_2, 1850 ]
+// SHARED-NEXT: [ 1, foo_2_1_2_2_1_2_1_1_1, 1849 ]
+// SHARED-NEXT: [ 1, foo_2_1_2_2_1_1_2_2_2, 1848 ]
+// SHARED-NEXT: [ 1, foo_2_1_2_2_1_1_2_2_1, 1847 ]
+// SHARED-NEXT: [ 1, foo_2_1_2_2_1_1_2_1_2, 1846 ]
+// SHARED-NEXT: [ 1, foo_2_1_2_2_1_1_2_1_1, 1845 ]
+// SHARED-NEXT: [ 1, foo_2_1_2_2_1_1_1_2_2, 1844 ]
+// SHARED-NEXT: [ 1, foo_2_1_2_2_1_1_1_2_1, 1843 ]
+// SHARED-NEXT: [ 1, foo_2_1_2_2_1_1_1_1_2, 1842 ]
+// SHARED-NEXT: [ 1, foo_2_1_2_2_1_1_1_1_1, 1841 ]
+// SHARED-NEXT: [ 1, foo_2_1_2_1_2_2_2_2_2, 1840 ]
+// SHARED-NEXT: [ 1, foo_2_1_2_1_2_2_2_2_1, 1839 ]
+// SHARED-NEXT: [ 1, foo_2_1_2_1_2_2_2_1_2, 1838 ]
+// SHARED-NEXT: [ 1, foo_2_1_2_1_2_2_2_1_1, 1837 ]
+// SHARED-NEXT: [ 1, foo_2_1_2_1_2_2_1_2_2, 1836 ]
+// SHARED-NEXT: [ 1, foo_2_1_2_1_2_2_1_2_1, 1835 ]
+// SHARED-NEXT: [ 1, foo_2_1_2_1_2_2_1_1_2, 1834 ]
+// SHARED-NEXT: [ 1, foo_2_1_2_1_2_2_1_1_1, 1833 ]
+// SHARED-NEXT: [ 1, foo_2_1_2_1_2_1_2_2_2, 1832 ]
+// SHARED-NEXT: [ 1, foo_2_1_2_1_2_1_2_2_1, 1831 ]
+// SHARED-NEXT: [ 1, foo_2_1_2_1_2_1_2_1_2, 1830 ]
+// SHARED-NEXT: [ 1, foo_2_1_2_1_2_1_2_1_1, 1829 ]
+// SHARED-NEXT: [ 1, foo_2_1_2_1_2_1_1_2_2, 1828 ]
+// SHARED-NEXT: [ 1, foo_2_1_2_1_2_1_1_2_1, 1827 ]
+// SHARED-NEXT: [ 1, foo_2_1_2_1_2_1_1_1_2, 1826 ]
+// SHARED-NEXT: [ 1, foo_2_1_2_1_2_1_1_1_1, 1825 ]
+// SHARED-NEXT: [ 1, foo_2_1_2_1_1_2_2_2_2, 1824 ]
+// SHARED-NEXT: [ 1, foo_2_1_2_1_1_2_2_2_1, 1823 ]
+// SHARED-NEXT: [ 1, foo_2_1_2_1_1_2_2_1_2, 1822 ]
+// SHARED-NEXT: [ 1, foo_2_1_2_1_1_2_2_1_1, 1821 ]
+// SHARED-NEXT: [ 1, foo_2_1_2_1_1_2_1_2_2, 1820 ]
+// SHARED-NEXT: [ 1, foo_2_1_2_1_1_2_1_2_1, 1819 ]
+// SHARED-NEXT: [ 1, foo_2_1_2_1_1_2_1_1_2, 1818 ]
+// SHARED-NEXT: [ 1, foo_2_1_2_1_1_2_1_1_1, 1817 ]
+// SHARED-NEXT: [ 1, foo_2_1_2_1_1_1_2_2_2, 1816 ]
+// SHARED-NEXT: [ 1, foo_2_1_2_1_1_1_2_2_1, 1815 ]
+// SHARED-NEXT: [ 1, foo_2_1_2_1_1_1_2_1_2, 1814 ]
+// SHARED-NEXT: [ 1, foo_2_1_2_1_1_1_2_1_1, 1813 ]
+// SHARED-NEXT: [ 1, foo_2_1_2_1_1_1_1_2_2, 1812 ]
+// SHARED-NEXT: [ 1, foo_2_1_2_1_1_1_1_2_1, 1811 ]
+// SHARED-NEXT: [ 1, foo_2_1_2_1_1_1_1_1_2, 1810 ]
+// SHARED-NEXT: [ 1, foo_2_1_2_1_1_1_1_1_1, 1809 ]
+// SHARED-NEXT: [ 1, foo_2_1_1_2_2_2_2_2_2, 1808 ]
+// SHARED-NEXT: [ 1, foo_2_1_1_2_2_2_2_2_1, 1807 ]
+// SHARED-NEXT: [ 1, foo_2_1_1_2_2_2_2_1_2, 1806 ]
+// SHARED-NEXT: [ 1, foo_2_1_1_2_2_2_2_1_1, 1805 ]
+// SHARED-NEXT: [ 1, foo_2_1_1_2_2_2_1_2_2, 1804 ]
+// SHARED-NEXT: [ 1, foo_2_1_1_2_2_2_1_2_1, 1803 ]
+// SHARED-NEXT: [ 1, foo_2_1_1_2_2_2_1_1_2, 1802 ]
+// SHARED-NEXT: [ 1, foo_2_1_1_2_2_2_1_1_1, 1801 ]
+// SHARED-NEXT: [ 1, foo_2_1_1_2_2_1_2_2_2, 1800 ]
+// SHARED-NEXT: [ 1, foo_2_1_1_2_2_1_2_2_1, 1799 ]
+// SHARED-NEXT: [ 1, foo_2_1_1_2_2_1_2_1_2, 1798 ]
+// SHARED-NEXT: [ 1, foo_2_1_1_2_2_1_2_1_1, 1797 ]
+// SHARED-NEXT: [ 1, foo_2_1_1_2_2_1_1_2_2, 1796 ]
+// SHARED-NEXT: [ 1, foo_2_1_1_2_2_1_1_2_1, 1795 ]
+// SHARED-NEXT: [ 1, foo_2_1_1_2_2_1_1_1_2, 1794 ]
+// SHARED-NEXT: [ 1, foo_2_1_1_2_2_1_1_1_1, 1793 ]
+// SHARED-NEXT: [ 1, foo_2_1_1_2_1_2_2_2_2, 1792 ]
+// SHARED-NEXT: [ 1, foo_2_1_1_2_1_2_2_2_1, 1791 ]
+// SHARED-NEXT: [ 1, foo_2_1_1_2_1_2_2_1_2, 1790 ]
+// SHARED-NEXT: [ 1, foo_2_1_1_2_1_2_2_1_1, 1789 ]
+// SHARED-NEXT: [ 1, foo_2_1_1_2_1_2_1_2_2, 1788 ]
+// SHARED-NEXT: [ 1, foo_2_1_1_2_1_2_1_2_1, 1787 ]
+// SHARED-NEXT: [ 1, foo_2_1_1_2_1_2_1_1_2, 1786 ]
+// SHARED-NEXT: [ 1, foo_2_1_1_2_1_2_1_1_1, 1785 ]
+// SHARED-NEXT: [ 1, foo_2_1_1_2_1_1_2_2_2, 1784 ]
+// SHARED-NEXT: [ 1, foo_2_1_1_2_1_1_2_2_1, 1783 ]
+// SHARED-NEXT: [ 1, foo_2_1_1_2_1_1_2_1_2, 1782 ]
+// SHARED-NEXT: [ 1, foo_2_1_1_2_1_1_2_1_1, 1781 ]
+// SHARED-NEXT: [ 1, foo_2_1_1_2_1_1_1_2_2, 1780 ]
+// SHARED-NEXT: [ 1, foo_2_1_1_2_1_1_1_2_1, 1779 ]
+// SHARED-NEXT: [ 1, foo_2_1_1_2_1_1_1_1_2, 1778 ]
+// SHARED-NEXT: [ 1, foo_2_1_1_2_1_1_1_1_1, 1777 ]
+// SHARED-NEXT: [ 1, foo_2_1_1_1_2_2_2_2_2, 1776 ]
+// SHARED-NEXT: [ 1, foo_2_1_1_1_2_2_2_2_1, 1775 ]
+// SHARED-NEXT: [ 1, foo_2_1_1_1_2_2_2_1_2, 1774 ]
+// SHARED-NEXT: [ 1, foo_2_1_1_1_2_2_2_1_1, 1773 ]
+// SHARED-NEXT: [ 1, foo_2_1_1_1_2_2_1_2_2, 1772 ]
+// SHARED-NEXT: [ 1, foo_2_1_1_1_2_2_1_2_1, 1771 ]
+// SHARED-NEXT: [ 1, foo_2_1_1_1_2_2_1_1_2, 1770 ]
+// SHARED-NEXT: [ 1, foo_2_1_1_1_2_2_1_1_1, 1769 ]
+// SHARED-NEXT: [ 1, foo_2_1_1_1_2_1_2_2_2, 1768 ]
+// SHARED-NEXT: [ 1, foo_2_1_1_1_2_1_2_2_1, 1767 ]
+// SHARED-NEXT: [ 1, foo_2_1_1_1_2_1_2_1_2, 1766 ]
+// SHARED-NEXT: [ 1, foo_2_1_1_1_2_1_2_1_1, 1765 ]
+// SHARED-NEXT: [ 1, foo_2_1_1_1_2_1_1_2_2, 1764 ]
+// SHARED-NEXT: [ 1, foo_2_1_1_1_2_1_1_2_1, 1763 ]
+// SHARED-NEXT: [ 1, foo_2_1_1_1_2_1_1_1_2, 1762 ]
+// SHARED-NEXT: [ 1, foo_2_1_1_1_2_1_1_1_1, 1761 ]
+// SHARED-NEXT: [ 1, foo_2_1_1_1_1_2_2_2_2, 1760 ]
+// SHARED-NEXT: [ 1, foo_2_1_1_1_1_2_2_2_1, 1759 ]
+// SHARED-NEXT: [ 1, foo_2_1_1_1_1_2_2_1_2, 1758 ]
+// SHARED-NEXT: [ 1, foo_2_1_1_1_1_2_2_1_1, 1757 ]
+// SHARED-NEXT: [ 1, foo_2_1_1_1_1_2_1_2_2, 1756 ]
+// SHARED-NEXT: [ 1, foo_2_1_1_1_1_2_1_2_1, 1755 ]
+// SHARED-NEXT: [ 1, foo_2_1_1_1_1_2_1_1_2, 1754 ]
+// SHARED-NEXT: [ 1, foo_2_1_1_1_1_2_1_1_1, 1753 ]
+// SHARED-NEXT: [ 1, foo_2_1_1_1_1_1_2_2_2, 1752 ]
+// SHARED-NEXT: [ 1, foo_2_1_1_1_1_1_2_2_1, 1751 ]
+// SHARED-NEXT: [ 1, foo_2_1_1_1_1_1_2_1_2, 1750 ]
+// SHARED-NEXT: [ 1, foo_2_1_1_1_1_1_2_1_1, 1749 ]
+// SHARED-NEXT: [ 1, foo_2_1_1_1_1_1_1_2_2, 1748 ]
+// SHARED-NEXT: [ 1, foo_2_1_1_1_1_1_1_2_1, 1747 ]
+// SHARED-NEXT: [ 1, foo
diff --git a/test/profile/Inputs/instrprof-visibility-helper.cpp b/test/profile/Inputs/instrprof-visibility-helper.cpp
new file mode 100644
index 000000000000..6d3bc69b3007
--- /dev/null
+++ b/test/profile/Inputs/instrprof-visibility-helper.cpp
@@ -0,0 +1,3 @@
+namespace N1 {
+void f4() {}
+}
diff --git a/test/profile/Linux/coverage_ctors.cpp b/test/profile/Linux/coverage_ctors.cpp
new file mode 100644
index 000000000000..317dcfe18b50
--- /dev/null
+++ b/test/profile/Linux/coverage_ctors.cpp
@@ -0,0 +1,32 @@
+// RUN: %clangxx_profgen -std=c++11 -fuse-ld=gold -fcoverage-mapping -o %t %s
+// RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t
+// RUN: llvm-profdata merge -o %t.profdata %t.profraw
+// RUN: llvm-cov show %t -instr-profile %t.profdata -filename-equivalence 2>&1 | FileCheck %s
+
+struct Base {
+ int B;
+ Base() : B(0) {}
+ Base(const Base &b2) {
+ B = b2.B + 5;
+ }
+ Base(Base &&b2) {
+ B = b2.B + 10;
+ }
+};
+
+struct Derived : public Base {
+ Derived(const Derived &) = default; // CHECK: 2| [[@LINE]]| Derived(const Derived &) = default;
+ Derived(Derived &&) = default; // CHECK: 1| [[@LINE]]| Derived(Derived &&) = default;
+ Derived() = default; // CHECK: 1| [[@LINE]]| Derived() = default
+};
+
+Derived dd;
+int main() {
+ Derived dd2(dd);
+ Derived dd3(dd2);
+ Derived dd4(static_cast<Derived &&>(dd3));
+
+ if (dd.B != 0 || dd2.B != 5 || dd3.B != 10 || dd4.B != 20)
+ return 1; // CHECK: 0| [[@LINE]]| return 1;
+ return 0;
+}
diff --git a/test/profile/Linux/coverage_dtor.cpp b/test/profile/Linux/coverage_dtor.cpp
new file mode 100644
index 000000000000..f35eb100fa12
--- /dev/null
+++ b/test/profile/Linux/coverage_dtor.cpp
@@ -0,0 +1,26 @@
+// RUN: %clang_profgen -x c++ -fno-exceptions -std=c++11 -fuse-ld=gold -fcoverage-mapping -o %t %s
+// RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t
+// RUN: llvm-profdata merge -o %t.profdata %t.profraw
+// RUN: llvm-cov show %t -instr-profile %t.profdata -filename-equivalence 2>&1 | FileCheck %s
+
+int g = 100;
+struct Base {
+ int B;
+ Base(int B_) : B(B_) {}
+ ~Base() { g -= B; }
+};
+
+struct Derived : public Base {
+ Derived(int K) : Base(K) {}
+ ~Derived() = default; // CHECK: 2| [[@LINE]]| ~Derived() = default;
+};
+
+int main() {
+ {
+ Derived dd(10);
+ Derived dd2(90);
+ }
+ if (g != 0)
+ return 1; // CHECK: 0| [[@LINE]]| return 1;
+ return 0;
+}
diff --git a/test/profile/Linux/coverage_shared.test b/test/profile/Linux/coverage_shared.test
new file mode 100644
index 000000000000..e2b0e3e1160d
--- /dev/null
+++ b/test/profile/Linux/coverage_shared.test
@@ -0,0 +1,16 @@
+RUN: mkdir -p %t.d
+RUN: %clang_profgen -fdata-sections -ffunction-sections -fcoverage-mapping -c -o %t.d/a.shared.o -fPIC %S/../Inputs/instrprof-dynamic-a.cpp
+RUN: %clang_profgen -fdata-sections -ffunction-sections -fuse-ld=gold -Wl,--gc-sections -fcoverage-mapping -o %t.d/a.shared -fPIC -shared %S/../Inputs/instrprof-dynamic-a.cpp
+RUN: %clang_profgen -fdata-sections -ffunction-sections -fuse-ld=gold -Wl,--gc-sections -o %t-shared -fPIC -rpath %t.d %t.d/a.shared %S/../Inputs/instrprof-dynamic-b.cpp %S/../Inputs/instrprof-dynamic-main.cpp
+
+RUN: %clang_profgen -fdata-sections -ffunction-sections -fuse-ld=gold -Wl,--gc-sections -o %t-static %t.d/a.shared.o %S/../Inputs/instrprof-dynamic-b.cpp %S/../Inputs/instrprof-dynamic-main.cpp
+
+RUN: env LLVM_PROFILE_FILE=%t-static.profraw %run %t-static
+RUN: env LLVM_PROFILE_FILE=%t-shared.profraw %run %t-shared
+
+RUN: llvm-profdata merge -o %t-static.profdata %t-static.profraw
+RUN: llvm-profdata merge -o %t-shared.profdata %t-shared.profraw
+
+RUN: llvm-cov show -instr-profile %t-shared.profdata %t.d/a.shared | FileCheck --check-prefix=COV %S/../Inputs/instrprof-dynamic-a.cpp
+RUN: llvm-cov show -instr-profile %t-static.profdata %t-static | FileCheck --check-prefix=COV %S/../Inputs/instrprof-dynamic-a.cpp
+
diff --git a/test/profile/Linux/coverage_test.cpp b/test/profile/Linux/coverage_test.cpp
new file mode 100644
index 000000000000..9b4ba073cf0a
--- /dev/null
+++ b/test/profile/Linux/coverage_test.cpp
@@ -0,0 +1,35 @@
+// RUN: %clang_profgen -fuse-ld=gold -O2 -fdata-sections -ffunction-sections -fcoverage-mapping -Wl,--gc-sections -o %t %s
+// RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t
+// RUN: llvm-profdata merge -o %t.profdata %t.profraw
+// RUN: llvm-cov show %t -instr-profile %t.profdata -filename-equivalence 2>&1 | FileCheck %s
+// BFD linker older than 2.26 has a bug that per-func profile data will be wrongly garbage collected when GC is turned on. We only do end-to-end test here without GC:
+// RUN: %clang_profgen -O2 -fcoverage-mapping -o %t.2 %s
+// RUN: env LLVM_PROFILE_FILE=%t.2.profraw %run %t.2
+// RUN: llvm-profdata merge -o %t.2.profdata %t.2.profraw
+// RUN: llvm-cov show %t.2 -instr-profile %t.2.profdata -filename-equivalence 2>&1 | FileCheck %s
+// Check covmap is not garbage collected when GC is turned on with BFD linker. Due to the bug mentioned above, we can only
+// do the check with objdump:
+// RUN: %clang_profgen -O2 -fcoverage-mapping -Wl,--gc-sections -o %t.3 %s
+// RUN: llvm-objdump -h %t.3 | FileCheck --check-prefix COVMAP %s
+// Check PIE option
+// RUN: %clang_profgen -fuse-ld=gold -O2 -fdata-sections -ffunction-sections -fPIE -pie -fcoverage-mapping -Wl,--gc-sections -o %t.pie %s
+// RUN: env LLVM_PROFILE_FILE=%t.pie.profraw %run %t.pie
+// RUN: llvm-profdata merge -o %t.pie.profdata %t.pie.profraw
+// RUN: llvm-cov show %t.pie -instr-profile %t.pie.profdata -filename-equivalence 2>&1 | FileCheck %s
+
+void foo(bool cond) { // CHECK: 1| [[@LINE]]|void foo(
+ if (cond) { // CHECK: 1| [[@LINE]]| if (cond) {
+ } // CHECK: 0| [[@LINE]]| }
+} // CHECK: 1| [[@LINE]]|}
+void bar() { // CHECK: 1| [[@LINE]]|void bar() {
+} // CHECK: 1| [[@LINE]]|}
+void func() { // CHECK: 0| [[@LINE]]|void func(
+} // CHECK: 0| [[@LINE]]|}
+int main() { // CHECK: 1| [[@LINE]]|int main(
+ foo(false); // CHECK: 1| [[@LINE]]| foo(
+ bar(); // CHECK: 1| [[@LINE]]| bar(
+ return 0; // CHECK: 1| [[@LINE]]| return
+} // CHECK: 1| [[@LINE]]|}
+
+// COVMAP: __llvm_covmap {{.*}}
+
diff --git a/test/profile/Linux/extern_template.test b/test/profile/Linux/extern_template.test
new file mode 100644
index 000000000000..ada4d230e9bc
--- /dev/null
+++ b/test/profile/Linux/extern_template.test
@@ -0,0 +1,29 @@
+// RUN: %clang -O2 -c -o %t.0.o %S/../Inputs/extern_template.cpp
+// RUN: %clang_profgen -O2 -c -o %t.o %S/../Inputs/extern_template.cpp
+// RUN: %clang_profgen -O2 -fcoverage-mapping %S/../Inputs/extern_template1.cpp %S/../Inputs/extern_template2.cpp %t.o -o %t
+// RUN: env LLVM_PROFILE_FILE=%t.profraw %t
+// RUN: llvm-profdata show --all-functions %t.profraw | FileCheck %s
+// RUN: llvm-profdata merge -o %t.profdata %t.profraw
+// RUN: llvm-cov show -instr-profile=%t.profdata %t | FileCheck %S/../Inputs/extern_template.h
+// RUN: %clang_profgen -O2 -fcoverage-mapping %S/../Inputs/extern_template1.cpp %S/../Inputs/extern_template2.cpp %t.0.o -o %t.0
+// RUN: env LLVM_PROFILE_FILE=%t.0.profraw %t.0
+// RUN: llvm-profdata show --all-functions %t.0.profraw | FileCheck %s
+// RUN: llvm-profdata merge -o %t.0.profdata %t.0.profraw
+// RUN: llvm-cov show -instr-profile=%t.0.profdata %t.0 | FileCheck %S/../Inputs/extern_template.h
+#define DEF
+#include "extern_template.h"
+#undef DEF
+extern int bar();
+extern int foo();
+extern Test<int> TO;
+int main() {
+ foo();
+ int R = bar();
+
+ if (R != 10)
+ return 1;
+ return 0;
+}
+// No duplicate entries
+// CHECK: _ZN4TestIiE4doItEi:
+// CHECK-NOT: _ZN4TestIiE4doItEi:
diff --git a/test/profile/Linux/instrprof-alloc.test b/test/profile/Linux/instrprof-alloc.test
new file mode 100644
index 000000000000..752b10892170
--- /dev/null
+++ b/test/profile/Linux/instrprof-alloc.test
@@ -0,0 +1,6 @@
+// RUN: %clang_profgen -Xclang -fprofile-instrument=llvm -fuse-ld=gold -Wl,-wrap,malloc -Wl,-wrap,calloc -o %t -O3 %S/../Inputs/instrprof-alloc.c
+// RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t
+
+// RUN: %clang_profgen -Xclang -fprofile-instrument=llvm -mllvm -vp-static-alloc=false -fuse-ld=gold -Wl,-wrap,malloc -Wl,-wrap,calloc -o %t.dyn -O3 %S/../Inputs/instrprof-alloc.c
+// RUN: env LLVM_PROFILE_FILE=%t.profraw not %run %t.dyn
+
diff --git a/test/profile/Linux/instrprof-comdat.test b/test/profile/Linux/instrprof-comdat.test
new file mode 100644
index 000000000000..b933e96b4504
--- /dev/null
+++ b/test/profile/Linux/instrprof-comdat.test
@@ -0,0 +1,6 @@
+RUN: mkdir -p %t.d
+RUN: %clangxx_profgen -o %t.d/comdat -fcoverage-mapping -fuse-ld=gold %S/../Inputs/instrprof-comdat-1.cpp %S/../Inputs/instrprof-comdat-2.cpp
+RUN: LLVM_PROFILE_FILE=%t-comdat.profraw %t.d/comdat
+RUN: llvm-profdata merge -o %t.d/comdat.prof %t-comdat.profraw
+RUN: llvm-cov show --filename-equivalence --instr-profile=%t.d/comdat.prof %t.d/comdat | FileCheck --check-prefix=HEADER %S/../Inputs/instrprof-comdat.h
+
diff --git a/test/profile/Linux/instrprof-file_ex.test b/test/profile/Linux/instrprof-file_ex.test
new file mode 100644
index 000000000000..be899663dfdf
--- /dev/null
+++ b/test/profile/Linux/instrprof-file_ex.test
@@ -0,0 +1,17 @@
+RUN: mkdir -p %t.d
+RUN: %clang_profgen -fprofile-instr-generate %S/../Inputs/instrprof-file_ex.c -o %t
+RUN: rm -f %t.d/run.dump
+RUN: %run %t %t.d/run.dump
+RUN: sort %t.d/run.dump | FileCheck %s
+
+CHECK: Dump from Child 0
+CHECK-NEXT: Dump from Child 1
+CHECK-NEXT: Dump from Child 2
+CHECK-NEXT: Dump from Child 3
+CHECK-NEXT: Dump from Child 4
+CHECK-NEXT: Dump from Child 5
+CHECK-NEXT: Dump from Child 6
+CHECK-NEXT: Dump from Child 7
+CHECK-NEXT: Dump from Child 8
+CHECK-NEXT: Dump from Child 9
+CHECK-NEXT: Dump from parent 10
diff --git a/test/profile/Linux/instrprof-merge-vp.c b/test/profile/Linux/instrprof-merge-vp.c
new file mode 100644
index 000000000000..8daed3352b22
--- /dev/null
+++ b/test/profile/Linux/instrprof-merge-vp.c
@@ -0,0 +1,113 @@
+// RUN: %clang_profgen -mllvm --enable-value-profiling=true -mllvm -vp-static-alloc=true -mllvm -vp-counters-per-site=3 -O2 -o %t %s
+// RUN: %run %t %t.profraw
+// RUN: llvm-profdata merge -o %t.profdata %t.profraw
+// RUN: llvm-profdata show --all-functions --counts --ic-targets %t.profdata > %t.profdump
+// RUN: FileCheck --input-file %t.profdump %s --check-prefix=FOO
+// RUN: FileCheck --input-file %t.profdump %s --check-prefix=BAR
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+int __llvm_profile_runtime = 0;
+int __llvm_profile_write_file();
+void __llvm_profile_reset_counters(void);
+void __llvm_profile_merge_from_buffer(const char *, uint64_t);
+void __llvm_profile_set_filename(const char *);
+struct __llvm_profile_data;
+struct ValueProfData;
+void lprofMergeValueProfData(struct ValueProfData *, struct __llvm_profile_data *);
+/* Force the vp merger module to be linked in. */
+void *Dummy = &lprofMergeValueProfData;
+
+void callee1() {}
+void callee2() {}
+void callee3() {}
+
+typedef void (*FP)(void);
+FP Fps[3] = {callee1, callee2, callee3};
+
+void foo(int N) {
+ int I, J;
+ for (I = 0; I < 3; I++)
+ for (J = 0; J < I * 2 + 1; J++)
+ Fps[I]();
+
+ if (N < 2)
+ return;
+
+ for (I = 0; I < 3; I++)
+ for (J = 0; J < I * 2 + 1; J++)
+ Fps[2 - I]();
+}
+
+/* This function is not profiled */
+void bar(void) {
+ int I;
+ for (I = 0; I < 20; I++)
+ Fps[I % 3]();
+}
+
+int main(int argc, const char *argv[]) {
+ int i;
+ if (argc < 2)
+ return 1;
+
+ const char *FileN = argv[1];
+ __llvm_profile_set_filename(FileN);
+ /* Start profiling. */
+ __llvm_profile_reset_counters();
+ foo(1);
+ /* End profiling by freezing counters and
+ * dump them to the file. */
+ if (__llvm_profile_write_file())
+ return 1;
+
+ /* Read profile data into buffer. */
+ FILE *File = fopen(FileN, "r");
+ if (!File)
+ return 1;
+ fseek(File, 0, SEEK_END);
+ uint64_t Size = ftell(File);
+ fseek(File, 0, SEEK_SET);
+ char *Buffer = (char *)malloc(Size);
+ if (Size != fread(Buffer, 1, Size, File))
+ return 1;
+ fclose(File);
+
+ /* Its profile will be discarded. */
+ for (i = 0; i < 10; i++)
+ bar();
+
+ /* Start profiling again and merge in previously
+ saved counters in buffer. */
+ __llvm_profile_reset_counters();
+ __llvm_profile_merge_from_buffer(Buffer, Size);
+ foo(2);
+ /* End profiling. */
+ truncate(FileN, 0);
+ if (__llvm_profile_write_file())
+ return 1;
+
+ /* Its profile will be discarded. */
+ bar();
+
+ return 0;
+}
+
+// FOO-LABEL: foo:
+// FOO: Indirect Target Results:
+// FOO-NEXT: [ 0, callee3, 10 ]
+// FOO-NEXT: [ 0, callee2, 6 ]
+// FOO-NEXT: [ 0, callee1, 2 ]
+// FOO-NEXT: [ 1, callee1, 5 ]
+// FOO-NEXT: [ 1, callee2, 3 ]
+// FOO-NEXT: [ 1, callee3, 1 ]
+
+// BAR-LABEL: bar:
+// BAR: [ 0, callee1, 0 ]
+// BAR-NEXT: [ 0, callee2, 0 ]
+// BAR-NEXT: [ 0, callee3, 0 ]
+
diff --git a/test/profile/Linux/instrprof-set-filename-shared.test b/test/profile/Linux/instrprof-set-filename-shared.test
new file mode 100644
index 000000000000..29e6713289d9
--- /dev/null
+++ b/test/profile/Linux/instrprof-set-filename-shared.test
@@ -0,0 +1,8 @@
+# Test that __llvm_profile_set_filename is honored by shared libary too.
+RUN: mkdir -p %t.d
+RUN: %clang_profgen=%t.shared.profraw -fPIC -shared -o %t.d/t.shared %S/../Inputs/instrprof-dlopen-func.c
+RUN: %clang_profgen -DCALL_SHARED -o %t.m -O3 -rpath %t.d %t.d/t.shared %S/../instrprof-set-filename.c
+RUN: %run %t.m %t.main.profraw
+RUN: llvm-profdata show %t.main.profraw | FileCheck --check-prefix=SHARED %s
+
+# SHARED: Total functions: 2
diff --git a/test/profile/Linux/instrprof-value-prof-warn.test b/test/profile/Linux/instrprof-value-prof-warn.test
new file mode 100644
index 000000000000..26502cc900dc
--- /dev/null
+++ b/test/profile/Linux/instrprof-value-prof-warn.test
@@ -0,0 +1,8 @@
+RUN: %clang_profgen -O2 -mllvm -disable-vp=false -Xclang -fprofile-instrument=llvm -mllvm -vp-static-alloc=true -DSTRESS=1 -o %t.ir.warn %S/../Inputs/instrprof-value-prof-real.c
+RUN: env LLVM_PROFILE_FILE=%t.ir.profraw LLVM_VP_MAX_NUM_VALS_PER_SITE=255 %run %t.ir.warn 2>&1 |FileCheck --check-prefix=WARNING %s
+# Test that enough static counters have been allocated
+RUN: env LLVM_PROFILE_FILE=%t.ir.profraw LLVM_VP_MAX_NUM_VALS_PER_SITE=150 %run %t.ir.warn 2>&1 |FileCheck --check-prefix=NOWARNING --allow-empty %s
+
+# WARNING: LLVM Profile Warning:
+# NOWARNING-NOT: LLVM Profile Warning:
+
diff --git a/test/profile/gcc-flag-compatibility.test b/test/profile/gcc-flag-compatibility.test
index 8e8b55dafe23..b1087615ec51 100644
--- a/test/profile/gcc-flag-compatibility.test
+++ b/test/profile/gcc-flag-compatibility.test
@@ -1,3 +1,4 @@
+RUN: rm -rf %t.d
RUN: mkdir -p %t.d
RUN: %clang_profgen_gcc=%t.d/d1/d2 -o %t.d/code %S/Inputs/gcc-flag-compatibility.c
diff --git a/test/profile/instrprof-basic.c b/test/profile/instrprof-basic.c
index 995525bf9553..02549e1506ba 100644
--- a/test/profile/instrprof-basic.c
+++ b/test/profile/instrprof-basic.c
@@ -1,17 +1,31 @@
+// REQUIRES: shell
// RUN: %clang_profgen -o %t -O3 %s
// RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t
// RUN: llvm-profdata merge -o %t.profdata %t.profraw
-// RUN: %clang_profuse=%t.profdata -o - -S -emit-llvm %s | FileCheck %s
+// RUN: %clang_profuse=%t.profdata -o - -S -emit-llvm %s | FileCheck %s --check-prefix=COMMON --check-prefix=ORIG
+//
+// RUN: rm -f %t.profraw_e_*
+// RUN: env LLVM_PROFILE_FILE=%t.profraw_e_%1m %run %t
+// RUN: env LLVM_PROFILE_FILE=%t.profraw_e_%1m %run %t
+// RUN: llvm-profdata merge -o %t.em.profdata %t.profraw_e_*
+// RUN: %clang_profuse=%t.em.profdata -o - -S -emit-llvm %s | FileCheck %s --check-prefix=COMMON --check-prefix=MERGE
+//
+// RUN: %clang_profgen=%t.%m.profraw -o %t.merge -O3 %s
+// RUN: rm -f %t.*.profraw*
+// RUN: %run %t.merge
+// RUN: %run %t.merge
+// RUN: llvm-profdata merge -o %t.m.profdata %t.*.profraw
+// RUN: %clang_profuse=%t.m.profdata -o - -S -emit-llvm %s | FileCheck %s --check-prefix=COMMON --check-prefix=MERGE
int begin(int i) {
- // CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}, !prof ![[PD1:[0-9]+]]
+ // COMMON: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}, !prof ![[PD1:[0-9]+]]
if (i)
return 0;
return 1;
}
int end(int i) {
- // CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}, !prof ![[PD2:[0-9]+]]
+ // COMMON: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}, !prof ![[PD2:[0-9]+]]
if (i)
return 0;
return 1;
@@ -21,11 +35,13 @@ int main(int argc, const char *argv[]) {
begin(0);
end(1);
- // CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}, !prof ![[PD2:[0-9]+]]
+ // COMMON: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}, !prof ![[PD2:[0-9]+]]
if (argc)
return 0;
return 1;
}
-// CHECK: ![[PD1]] = !{!"branch_weights", i32 1, i32 2}
-// CHECK: ![[PD2]] = !{!"branch_weights", i32 2, i32 1}
+// ORIG: ![[PD1]] = !{!"branch_weights", i32 1, i32 2}
+// ORIG: ![[PD2]] = !{!"branch_weights", i32 2, i32 1}
+// MERGE: ![[PD1]] = !{!"branch_weights", i32 1, i32 3}
+// MERGE: ![[PD2]] = !{!"branch_weights", i32 3, i32 1}
diff --git a/test/profile/instrprof-bufferio.c b/test/profile/instrprof-bufferio.c
index eed548fd0da2..558425486c20 100644
--- a/test/profile/instrprof-bufferio.c
+++ b/test/profile/instrprof-bufferio.c
@@ -11,11 +11,11 @@
#include <string.h>
typedef struct ProfBufferIO ProfBufferIO;
-ProfBufferIO *llvmCreateBufferIOInternal(FILE *File, uint32_t DefaultBufferSz);
-void llvmDeleteBufferIO(ProfBufferIO *BufferIO);
+ProfBufferIO *lprofCreateBufferIOInternal(void *File, uint32_t BufferSz);
+void lprofDeleteBufferIO(ProfBufferIO *BufferIO);
-int llvmBufferIOWrite(ProfBufferIO *BufferIO, const char *Data, uint32_t Size);
-int llvmBufferIOFlush(ProfBufferIO *BufferIO);
+int lprofBufferIOWrite(ProfBufferIO *BufferIO, const char *Data, uint32_t Size);
+int lprofBufferIOFlush(ProfBufferIO *BufferIO);
int __llvm_profile_runtime = 0;
@@ -42,34 +42,35 @@ int main(int argc, const char *argv[]) {
if (!File[J])
return 1;
- BufferIO = llvmCreateBufferIOInternal(File[J], IOBufferSize[J]);
+ BufferIO = lprofCreateBufferIOInternal(File[J], IOBufferSize[J]);
- llvmBufferIOWrite(BufferIO, "Short Strings:\n", strlen("Short Strings:\n"));
+ lprofBufferIOWrite(BufferIO, "Short Strings:\n",
+ strlen("Short Strings:\n"));
for (I = 0; I < 1024; I++) {
- llvmBufferIOWrite(BufferIO, SmallData, strlen(SmallData));
+ lprofBufferIOWrite(BufferIO, SmallData, strlen(SmallData));
}
- llvmBufferIOWrite(BufferIO, "Long Strings:\n", strlen("Long Strings:\n"));
+ lprofBufferIOWrite(BufferIO, "Long Strings:\n", strlen("Long Strings:\n"));
for (I = 0; I < 1024; I++) {
- llvmBufferIOWrite(BufferIO, MediumData, strlen(MediumData));
+ lprofBufferIOWrite(BufferIO, MediumData, strlen(MediumData));
}
- llvmBufferIOWrite(BufferIO, "Extra Long Strings:\n",
+ lprofBufferIOWrite(BufferIO, "Extra Long Strings:\n",
strlen("Extra Long Strings:\n"));
for (I = 0; I < 10; I++) {
- llvmBufferIOWrite(BufferIO, LargeData, strlen(LargeData));
+ lprofBufferIOWrite(BufferIO, LargeData, strlen(LargeData));
}
- llvmBufferIOWrite(BufferIO, "Mixed Strings:\n", strlen("Mixed Strings:\n"));
+ lprofBufferIOWrite(BufferIO, "Mixed Strings:\n", strlen("Mixed Strings:\n"));
for (I = 0; I < 1024; I++) {
- llvmBufferIOWrite(BufferIO, MediumData, strlen(MediumData));
- llvmBufferIOWrite(BufferIO, SmallData, strlen(SmallData));
+ lprofBufferIOWrite(BufferIO, MediumData, strlen(MediumData));
+ lprofBufferIOWrite(BufferIO, SmallData, strlen(SmallData));
}
- llvmBufferIOWrite(BufferIO, "Endings:\n", strlen("Endings:\n"));
- llvmBufferIOWrite(BufferIO, "END\n", strlen("END\n"));
- llvmBufferIOWrite(BufferIO, "ENDEND\n", strlen("ENDEND\n"));
- llvmBufferIOWrite(BufferIO, "ENDENDEND\n", strlen("ENDENDEND\n"));
- llvmBufferIOWrite(BufferIO, "ENDENDENDEND\n", strlen("ENDENDENDEND\n"));
- llvmBufferIOFlush(BufferIO);
+ lprofBufferIOWrite(BufferIO, "Endings:\n", strlen("Endings:\n"));
+ lprofBufferIOWrite(BufferIO, "END\n", strlen("END\n"));
+ lprofBufferIOWrite(BufferIO, "ENDEND\n", strlen("ENDEND\n"));
+ lprofBufferIOWrite(BufferIO, "ENDENDEND\n", strlen("ENDENDEND\n"));
+ lprofBufferIOWrite(BufferIO, "ENDENDENDEND\n", strlen("ENDENDENDEND\n"));
+ lprofBufferIOFlush(BufferIO);
- llvmDeleteBufferIO(BufferIO);
+ lprofDeleteBufferIO(BufferIO);
fclose(File[J]);
}
diff --git a/test/profile/instrprof-error.c b/test/profile/instrprof-error.c
index 4386d5321878..3297c9d8840a 100644
--- a/test/profile/instrprof-error.c
+++ b/test/profile/instrprof-error.c
@@ -1,12 +1,9 @@
// RUN: %clang_profgen -o %t -O3 %s
-// RUN: touch %t.profraw
-// RUN: chmod -w %t.profraw
-// RUN: LLVM_PROFILE_FILE=%t.profraw LLVM_PROFILE_VERBOSE_ERRORS=1 %run %t 1 2>&1 | FileCheck %s
-// RUN: chmod +w %t.profraw
+// RUN: env LLVM_PROFILE_FILE=%t/ %run %t 1 2>&1 | FileCheck %s
int main(int argc, const char *argv[]) {
if (argc < 2)
return 1;
return 0;
}
-// CHECK: LLVM Profile: Failed to write file
+// CHECK: LLVM Profile Error: Failed to write file
diff --git a/test/profile/instrprof-hostname.c b/test/profile/instrprof-hostname.c
new file mode 100644
index 000000000000..b77cf8df158b
--- /dev/null
+++ b/test/profile/instrprof-hostname.c
@@ -0,0 +1,14 @@
+// RUN: %clang_profgen -o %t -O3 %s
+// RUN: env LLVM_PROFILE_FILE=%h.%t-%h.profraw_%h %run %t
+// RUN: %run uname -n > %t.n
+// RUN: llvm-profdata merge -o %t.profdata `cat %t.n`.%t-`cat %t.n`.profraw_`cat %t.n`
+// RUN: %clang_profuse=%t.profdata -o - -S -emit-llvm %s | FileCheck %s
+// REQUIRES: shell
+
+int main(int argc, const char *argv[]) {
+ // CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}, !prof ![[PD1:[0-9]+]]
+ if (argc > 2)
+ return 1;
+ return 0;
+}
+// CHECK: ![[PD1]] = !{!"branch_weights", i32 1, i32 2}
diff --git a/test/profile/instrprof-icall-promo.test b/test/profile/instrprof-icall-promo.test
new file mode 100644
index 000000000000..5332ef0e17c9
--- /dev/null
+++ b/test/profile/instrprof-icall-promo.test
@@ -0,0 +1,17 @@
+RUN: %clangxx_profgen -O2 -Xclang -fprofile-instrument=llvm -c -o %t.1.o %S/Inputs/instrprof-icall-promo_1.cc
+RUN: %clangxx_profgen -O2 -Xclang -fprofile-instrument=llvm -c -o %t.2.o %S/Inputs/instrprof-icall-promo_2.cc
+
+RUN: %clangxx_profgen -O2 -Xclang -fprofile-instrument=llvm %t.2.o %t.1.o -o %t.gen.1
+RUN: env LLVM_PROFILE_FILE=%t-icall.profraw %run %t.gen.1
+RUN: llvm-profdata merge -o %t-icall.profdata %t-icall.profraw
+RUN: %clangxx -O2 -Rpass=pgo-icall-prom -fprofile-instr-use=%t-icall.profdata -c -o %t.2.use.o %S/Inputs/instrprof-icall-promo_2.cc 2>&1 | FileCheck %s
+
+RUN: %clangxx_profgen -O2 -Xclang -fprofile-instrument=llvm %t.1.o %t.2.o -o %t.gen.2
+RUN: env LLVM_PROFILE_FILE=%t-icall2.profraw %run %t.gen.2
+RUN: llvm-profdata merge -o %t-icall2.profdata %t-icall2.profraw
+# The following test will be re-enabled once a compiler bug is fixed.
+RUN: %clangxx -O2 -Rpass=pgo-icall-prom -fprofile-instr-use=%t-icall2.profdata -c -o %t.2.use.o %S/Inputs/instrprof-icall-promo_2.cc 2>&1 | FileCheck %s
+
+
+# CHECK: Promote indirect call to
+
diff --git a/test/profile/instrprof-merge-match.test b/test/profile/instrprof-merge-match.test
new file mode 100644
index 000000000000..8345620dcf07
--- /dev/null
+++ b/test/profile/instrprof-merge-match.test
@@ -0,0 +1,5 @@
+// RUN: mkdir -p %t.d
+// RUN: %clang_profgen -o %t.d/libt.so -fPIC -shared %S/Inputs/instrprof-merge-match-lib.c
+// RUN: %clang_profgen -o %t -L %t.d -rpath %t.d %S/Inputs/instrprof-merge-match.c -lt
+// RUN: %run %t
+
diff --git a/test/profile/instrprof-merge.c b/test/profile/instrprof-merge.c
new file mode 100644
index 000000000000..ef24c83a1037
--- /dev/null
+++ b/test/profile/instrprof-merge.c
@@ -0,0 +1,96 @@
+// RUN: %clang_profgen -O2 -o %t %s
+// RUN: %run %t %t.profraw 1 1
+// RUN: llvm-profdata show --all-functions --counts %t.profraw | FileCheck %s
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int __llvm_profile_runtime = 0;
+uint64_t __llvm_profile_get_size_for_buffer(void);
+int __llvm_profile_write_buffer(char *);
+void __llvm_profile_reset_counters(void);
+void __llvm_profile_merge_from_buffer(const char *, uint64_t);
+
+int dumpBuffer(const char *FileN, const char *Buffer, uint64_t Size) {
+ FILE *File = fopen(FileN, "w");
+ if (!File)
+ return 1;
+ if (fwrite(Buffer, 1, Size, File) != Size)
+ return 1;
+ return fclose(File);
+}
+
+int g = 0;
+void foo(char c) {
+ if (c == '1')
+ g++;
+ else
+ g--;
+}
+
+/* This function is not profiled */
+void bar(int M) { g += M; }
+
+int main(int argc, const char *argv[]) {
+ int i;
+ if (argc < 4)
+ return 1;
+
+ const uint64_t MaxSize = 10000;
+ static char Buffer[MaxSize];
+
+ uint64_t Size = __llvm_profile_get_size_for_buffer();
+ if (Size > MaxSize)
+ return 1;
+
+ /* Start profiling. */
+ __llvm_profile_reset_counters();
+ foo(argv[2][0]);
+ /* End profiling by freezing counters. */
+ if (__llvm_profile_write_buffer(Buffer))
+ return 1;
+
+ /* Its profile will be discarded. */
+ for (i = 0; i < 10; i++)
+ bar(1);
+
+ /* Start profiling again and merge in previously
+ saved counters in buffer. */
+ __llvm_profile_reset_counters();
+ __llvm_profile_merge_from_buffer(Buffer, Size);
+ foo(argv[3][0]);
+ /* End profiling */
+ if (__llvm_profile_write_buffer(Buffer))
+ return 1;
+
+ /* Its profile will be discarded. */
+ bar(2);
+
+ /* Now it is time to dump the profile to file. */
+ return dumpBuffer(argv[1], Buffer, Size);
+}
+
+// Not profiled
+// CHECK-LABEL: dumpBuffer:
+// CHECK: Counters: 3
+// CHECK-NEXT: Function count: 0
+// CHECK-NEXT: Block counts: [0, 0]
+
+// Profiled with entry count == 2
+// CHECK-LABEL: foo:
+// CHECK: Counters: 2
+// CHECK-NEXT: Function count: 2
+// CHECK-NEXT: Block counts: [2]
+
+// Not profiled
+// CHECK-LABEL: bar:
+// CHECK: Counters: 1
+// CHECK-NEXT Function count: 0
+// CHECK-NEXT Block counts: []
+
+// Not profiled
+// CHECK-LABEL: main:
+// CHECK: Counters: 6
+// CHECK-NEXT: Function count: 0
+// CHECK-NEXT: Block counts: [0, 0, 0, 0, 0]
diff --git a/test/profile/instrprof-set-filename.c b/test/profile/instrprof-set-filename.c
index 51aa4234fea1..7635360d32fd 100644
--- a/test/profile/instrprof-set-filename.c
+++ b/test/profile/instrprof-set-filename.c
@@ -1,14 +1,57 @@
+// 1. Test that __llvm_profile_set_filename has higher precedence than
+// the default path.
// RUN: %clang_profgen -o %t -O3 %s
// RUN: %run %t %t.profraw
// RUN: llvm-profdata merge -o %t.profdata %t.profraw
// RUN: %clang_profuse=%t.profdata -o - -S -emit-llvm %s | FileCheck %s
+// RUN: rm %t.profraw
+// RUN: rm %t.profdata
+// 2. Test that __llvm_profile_set_filename has higher precedence than
+// environment variable
+// RUN: env LLVM_PROFILE_FILE=%t.env.profraw %run %t %t.profraw
+// RUN: llvm-profdata merge -o %t.profdata %t.profraw
+// RUN: %clang_profuse=%t.profdata -o - -S -emit-llvm %s | FileCheck %s
+// RUN: rm %t.profraw
+// RUN: rm %t.profdata
+// 3. Test that __llvm_profile_set_filename has higher precedence than
+// the command line.
+// RUN: %clang_profgen=%t.cmd.profraw -o %t.cmd -O3 %s
+// RUN: %run %t.cmd %t.profraw
+// RUN: llvm-profdata merge -o %t.profdata %t.profraw
+// RUN: %clang_profuse=%t.profdata -o - -S -emit-llvm %s | FileCheck %s
+// RUN: rm %t.profraw
+// RUN: rm %t.profdata
+// 4. Test that command line has high precedence than the default path
+// RUN: %clang_profgen=%t.cmd.profraw -DNO_API -o %t.cmd -O3 %s
+// RUN: %run %t.cmd %t.profraw
+// RUN: llvm-profdata merge -o %t.cmd.profdata %t.cmd.profraw
+// RUN: %clang_profuse=%t.cmd.profdata -o - -S -emit-llvm %s | FileCheck %s
+// RUN: rm %t.cmd.profraw
+// RUN: rm %t.cmd.profdata
+// 5. Test that the environment variable has higher precedence than
+// the command line.
+// RUN: env LLVM_PROFILE_FILE=%t.env.profraw %run %t.cmd %t.profraw
+// RUN: llvm-profdata merge -o %t.env.profdata %t.env.profraw
+// RUN: %clang_profuse=%t.env.profdata -o - -S -emit-llvm %s | FileCheck %s
+// RUN: rm %t.env.profraw
+// RUN: rm %t.env.profdata
+#ifdef CALL_SHARED
+extern void func(int);
+#endif
void __llvm_profile_set_filename(const char *);
int main(int argc, const char *argv[]) {
// CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}, !prof ![[PD1:[0-9]+]]
if (argc < 2)
return 1;
+#ifndef NO_API
__llvm_profile_set_filename(argv[1]);
+#endif
+
+#ifdef CALL_SHARED
+ func(1);
+#endif
return 0;
}
// CHECK: ![[PD1]] = !{!"branch_weights", i32 1, i32 2}
+// SHARED: Total functions: 2
diff --git a/test/profile/instrprof-value-prof-2.c b/test/profile/instrprof-value-prof-2.c
index 989353e1f53e..a5939fe5c53c 100644
--- a/test/profile/instrprof-value-prof-2.c
+++ b/test/profile/instrprof-value-prof-2.c
@@ -1,7 +1,13 @@
// RUN: %clang_profgen -O2 -o %t %s
// RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t
// RUN: llvm-profdata merge -o %t.profdata %t.profraw
-// RUN: llvm-profdata show --all-functions -ic-targets %t.profdata | FileCheck %s
+// RUN: llvm-profdata show --all-functions -ic-targets %t.profdata > %t.out
+// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-1 < %t.out
+// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-2 < %t.out
+// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-3 < %t.out
+// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-4 < %t.out
+// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-5 < %t.out
+// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-6 < %t.out
#include <stdint.h>
#include <stdio.h>
@@ -27,10 +33,19 @@ void caller_with_value_site_never_called2() {}
void caller_without_value_site2() {}
void caller_with_vp2() {}
+void (*callee1Ptr)();
+void (*callee2Ptr)();
+
+void __attribute__ ((noinline)) setFunctionPointers () {
+ callee1Ptr = callee1;
+ callee2Ptr = callee2;
+}
+
int main(int argc, const char *argv[]) {
unsigned S, NS = 10, V;
const __llvm_profile_data *Data, *DataEnd;
+ setFunctionPointers();
Data = __llvm_profile_begin_data();
DataEnd = __llvm_profile_end_data();
for (; Data < DataEnd; Data = __llvm_profile_iterate_data(Data)) {
@@ -49,87 +64,87 @@ int main(int argc, const char *argv[]) {
for (S = 0; S < NS; S++) {
unsigned C;
for (C = 0; C < S + 1; C++) {
- __llvm_profile_instrument_target((uint64_t)&callee1, (void *)Data, S);
+ __llvm_profile_instrument_target((uint64_t)callee1Ptr, (void *)Data, S);
if (C % 2 == 0)
- __llvm_profile_instrument_target((uint64_t)&callee2, (void *)Data, S);
+ __llvm_profile_instrument_target((uint64_t)callee2Ptr, (void *)Data, S);
}
}
}
}
-// CHECK-LABEL: caller_with_value_site_never_called2:
-// CHECK-NEXT: Hash: 0x0000000000000000
-// CHECK-NEXT: Counters:
-// CHECK-NEXT: Function count
-// CHECK-NEXT: Indirect Call Site Count: 10
-// CHECK-NEXT: Indirect Target Results:
-// CHECK-LABEL: caller_with_vp2:
-// CHECK-NEXT: Hash: 0x0000000000000000
-// CHECK-NEXT: Counters:
-// CHECK-NEXT: Function count:
-// CHECK-NEXT: Indirect Call Site Count: 10
-// CHECK-NEXT: Indirect Target Results:
-// CHECK-NEXT: [ 0, callee1, 1 ]
-// CHECK-NEXT: [ 0, callee2, 1 ]
-// CHECK-NEXT: [ 1, callee1, 2 ]
-// CHECK-NEXT: [ 1, callee2, 1 ]
-// CHECK-NEXT: [ 2, callee1, 3 ]
-// CHECK-NEXT: [ 2, callee2, 2 ]
-// CHECK-NEXT: [ 3, callee1, 4 ]
-// CHECK-NEXT: [ 3, callee2, 2 ]
-// CHECK-NEXT: [ 4, callee1, 5 ]
-// CHECK-NEXT: [ 4, callee2, 3 ]
-// CHECK-NEXT: [ 5, callee1, 6 ]
-// CHECK-NEXT: [ 5, callee2, 3 ]
-// CHECK-NEXT: [ 6, callee1, 7 ]
-// CHECK-NEXT: [ 6, callee2, 4 ]
-// CHECK-NEXT: [ 7, callee1, 8 ]
-// CHECK-NEXT: [ 7, callee2, 4 ]
-// CHECK-NEXT: [ 8, callee1, 9 ]
-// CHECK-NEXT: [ 8, callee2, 5 ]
-// CHECK-NEXT: [ 9, callee1, 10 ]
-// CHECK-NEXT: [ 9, callee2, 5 ]
-// CHECK-LABEL: caller_with_vp1:
-// CHECK-NEXT: Hash: 0x0000000000000000
-// CHECK-NEXT: Counters:
-// CHECK-NEXT: Function count
-// CHECK-NEXT: Indirect Call Site Count: 10
-// CHECK-NEXT: Indirect Target Results:
-// CHECK-NEXT: [ 0, callee1, 1 ]
-// CHECK-NEXT: [ 0, callee2, 1 ]
-// CHECK-NEXT: [ 1, callee1, 2 ]
-// CHECK-NEXT: [ 1, callee2, 1 ]
-// CHECK-NEXT: [ 2, callee1, 3 ]
-// CHECK-NEXT: [ 2, callee2, 2 ]
-// CHECK-NEXT: [ 3, callee1, 4 ]
-// CHECK-NEXT: [ 3, callee2, 2 ]
-// CHECK-NEXT: [ 4, callee1, 5 ]
-// CHECK-NEXT: [ 4, callee2, 3 ]
-// CHECK-NEXT: [ 5, callee1, 6 ]
-// CHECK-NEXT: [ 5, callee2, 3 ]
-// CHECK-NEXT: [ 6, callee1, 7 ]
-// CHECK-NEXT: [ 6, callee2, 4 ]
-// CHECK-NEXT: [ 7, callee1, 8 ]
-// CHECK-NEXT: [ 7, callee2, 4 ]
-// CHECK-NEXT: [ 8, callee1, 9 ]
-// CHECK-NEXT: [ 8, callee2, 5 ]
-// CHECK-NEXT: [ 9, callee1, 10 ]
-// CHECK-NEXT: [ 9, callee2, 5 ]
-// CHECK-LABEL: caller_with_value_site_never_called1:
-// CHECK-NEXT: Hash: 0x0000000000000000
-// CHECK-NEXT: Counters:
-// CHECK-NEXT: Function count:
-// CHECK-NEXT: Indirect Call Site Count: 10
-// CHECK-NEXT: Indirect Target Results:
-// CHECK-LABEL: caller_without_value_site2:
-// CHECK-NEXT: Hash: 0x0000000000000000
-// CHECK-NEXT: Counters:
-// CHECK-NEXT: Function count:
-// CHECK-NEXT: Indirect Call Site Count: 0
-// CHECK-NEXT: Indirect Target Results:
-// CHECK-LABEL: caller_without_value_site1:
-// CHECK-NEXT: Hash: 0x0000000000000000
-// CHECK-NEXT: Counters:
-// CHECK-NEXT: Function count:
-// CHECK-NEXT: Indirect Call Site Count: 0
-// CHECK-NEXT: Indirect Target Results:
+// CHECK-1-LABEL: caller_with_value_site_never_called2:
+// CHECK-1-NEXT: Hash: 0x0000000000000000
+// CHECK-1-NEXT: Counters:
+// CHECK-1-NEXT: Function count
+// CHECK-1-NEXT: Indirect Call Site Count: 10
+// CHECK-1-NEXT: Indirect Target Results:
+// CHECK-2-LABEL: caller_with_vp2:
+// CHECK-2-NEXT: Hash: 0x0000000000000000
+// CHECK-2-NEXT: Counters:
+// CHECK-2-NEXT: Function count:
+// CHECK-2-NEXT: Indirect Call Site Count: 10
+// CHECK-2-NEXT: Indirect Target Results:
+// CHECK-2-NEXT: [ 0, callee1, 1 ]
+// CHECK-2-NEXT: [ 0, callee2, 1 ]
+// CHECK-2-NEXT: [ 1, callee1, 2 ]
+// CHECK-2-NEXT: [ 1, callee2, 1 ]
+// CHECK-2-NEXT: [ 2, callee1, 3 ]
+// CHECK-2-NEXT: [ 2, callee2, 2 ]
+// CHECK-2-NEXT: [ 3, callee1, 4 ]
+// CHECK-2-NEXT: [ 3, callee2, 2 ]
+// CHECK-2-NEXT: [ 4, callee1, 5 ]
+// CHECK-2-NEXT: [ 4, callee2, 3 ]
+// CHECK-2-NEXT: [ 5, callee1, 6 ]
+// CHECK-2-NEXT: [ 5, callee2, 3 ]
+// CHECK-2-NEXT: [ 6, callee1, 7 ]
+// CHECK-2-NEXT: [ 6, callee2, 4 ]
+// CHECK-2-NEXT: [ 7, callee1, 8 ]
+// CHECK-2-NEXT: [ 7, callee2, 4 ]
+// CHECK-2-NEXT: [ 8, callee1, 9 ]
+// CHECK-2-NEXT: [ 8, callee2, 5 ]
+// CHECK-2-NEXT: [ 9, callee1, 10 ]
+// CHECK-2-NEXT: [ 9, callee2, 5 ]
+// CHECK-3-LABEL: caller_with_vp1:
+// CHECK-3-NEXT: Hash: 0x0000000000000000
+// CHECK-3-NEXT: Counters:
+// CHECK-3-NEXT: Function count
+// CHECK-3-NEXT: Indirect Call Site Count: 10
+// CHECK-3-NEXT: Indirect Target Results:
+// CHECK-3-NEXT: [ 0, callee1, 1 ]
+// CHECK-3-NEXT: [ 0, callee2, 1 ]
+// CHECK-3-NEXT: [ 1, callee1, 2 ]
+// CHECK-3-NEXT: [ 1, callee2, 1 ]
+// CHECK-3-NEXT: [ 2, callee1, 3 ]
+// CHECK-3-NEXT: [ 2, callee2, 2 ]
+// CHECK-3-NEXT: [ 3, callee1, 4 ]
+// CHECK-3-NEXT: [ 3, callee2, 2 ]
+// CHECK-3-NEXT: [ 4, callee1, 5 ]
+// CHECK-3-NEXT: [ 4, callee2, 3 ]
+// CHECK-3-NEXT: [ 5, callee1, 6 ]
+// CHECK-3-NEXT: [ 5, callee2, 3 ]
+// CHECK-3-NEXT: [ 6, callee1, 7 ]
+// CHECK-3-NEXT: [ 6, callee2, 4 ]
+// CHECK-3-NEXT: [ 7, callee1, 8 ]
+// CHECK-3-NEXT: [ 7, callee2, 4 ]
+// CHECK-3-NEXT: [ 8, callee1, 9 ]
+// CHECK-3-NEXT: [ 8, callee2, 5 ]
+// CHECK-3-NEXT: [ 9, callee1, 10 ]
+// CHECK-3-NEXT: [ 9, callee2, 5 ]
+// CHECK-4-LABEL: caller_with_value_site_never_called1:
+// CHECK-4-NEXT: Hash: 0x0000000000000000
+// CHECK-4-NEXT: Counters:
+// CHECK-4-NEXT: Function count:
+// CHECK-4-NEXT: Indirect Call Site Count: 10
+// CHECK-4-NEXT: Indirect Target Results:
+// CHECK-5-LABEL: caller_without_value_site2:
+// CHECK-5-NEXT: Hash: 0x0000000000000000
+// CHECK-5-NEXT: Counters:
+// CHECK-5-NEXT: Function count:
+// CHECK-5-NEXT: Indirect Call Site Count: 0
+// CHECK-5-NEXT: Indirect Target Results:
+// CHECK-6-LABEL: caller_without_value_site1:
+// CHECK-6-NEXT: Hash: 0x0000000000000000
+// CHECK-6-NEXT: Counters:
+// CHECK-6-NEXT: Function count:
+// CHECK-6-NEXT: Indirect Call Site Count: 0
+// CHECK-6-NEXT: Indirect Target Results:
diff --git a/test/profile/instrprof-value-prof-evict.test b/test/profile/instrprof-value-prof-evict.test
new file mode 100644
index 000000000000..de82581e451a
--- /dev/null
+++ b/test/profile/instrprof-value-prof-evict.test
@@ -0,0 +1,16 @@
+// RUN: %clang_profgen -O2 -mllvm -enable-value-profiling=true -mllvm -vp-static-alloc=true -mllvm -vp-counters-per-site=10 -o %t %S/Inputs/instrprof-value-prof-evict.c
+// RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t
+// RUN: llvm-profdata merge -o %t.profdata %t.profraw
+// RUN: llvm-profdata show --all-functions -ic-targets %t.profdata | FileCheck %S/Inputs/instrprof-value-prof-evict.c
+
+// IR level instrumentation
+// RUN: %clang_profgen -O2 -mllvm -disable-vp=false -mllvm -vp-static-alloc=true -mllvm -vp-counters-per-site=10 -Xclang -fprofile-instrument=llvm -o %t.ir %S/Inputs/instrprof-value-prof-evict.c
+// RUN: env LLVM_PROFILE_FILE=%t.ir.profraw %run %t.ir
+// RUN: llvm-profdata merge -o %t.ir.profdata %t.ir.profraw
+// RUN: llvm-profdata show --all-functions -ic-targets %t.ir.profdata | FileCheck %S/Inputs/instrprof-value-prof-evict.c
+
+// IR level instrumentation, dynamic allocation
+// RUN: %clang_profgen -O2 -mllvm -disable-vp=false -mllvm -vp-static-alloc=false -Xclang -fprofile-instrument=llvm -o %t.ir.dyn %S/Inputs/instrprof-value-prof-evict.c
+// RUN: env LLVM_PROFILE_FILE=%t.ir.dyn.profraw %run %t.ir.dyn
+// RUN: llvm-profdata merge -o %t.ir.dyn.profdata %t.ir.dyn.profraw
+// RUN: llvm-profdata show --all-functions -ic-targets %t.ir.dyn.profdata | FileCheck %S/Inputs/instrprof-value-prof-evict.c
diff --git a/test/profile/instrprof-value-prof-shared.test b/test/profile/instrprof-value-prof-shared.test
new file mode 100644
index 000000000000..5b6d627dbaf9
--- /dev/null
+++ b/test/profile/instrprof-value-prof-shared.test
@@ -0,0 +1,37 @@
+// RUN: mkdir -p %t.d
+// RUN: %clang_profgen -O2 -mllvm -enable-value-profiling=true -mllvm -vp-static-alloc=true -mllvm -vp-counters-per-site=256 -fPIC -shared -o %t.d/t.shared -DSHARED_LIB %S/Inputs/instrprof-value-prof-real.c
+// RUN: %clang_profgen -O2 -mllvm -enable-value-profiling=true -mllvm -vp-static-alloc=true -mllvm -vp-counters-per-site=256 -o %t -rpath %t.d %t.d/t.shared -DCALL_SHARED %S/Inputs/instrprof-value-prof-real.c
+// RUN: env LLVM_PROFILE_FILE=%t.profraw LLVM_VP_MAX_NUM_VALS_PER_SITE=255 %run %t
+// RUN: llvm-profdata merge -o %t.profdata %t.profraw
+// RUN: llvm-profdata show --all-functions -ic-targets %t.profdata | FileCheck %S/Inputs/instrprof-value-prof-real.c
+// RUN: llvm-profdata show --all-functions -ic-targets %t.profdata | FileCheck %S/Inputs/instrprof-value-prof-real.c --check-prefix=SHARED
+
+// IR level instrumentation
+// RUN: %clang_profgen -O2 -mllvm -disable-vp=false -Xclang -fprofile-instrument=llvm -mllvm -vp-static-alloc=true -mllvm -vp-counters-per-site=256 -fPIC -shared -o %t.d/t.ir.shared -DSHARED_LIB %S/Inputs/instrprof-value-prof-real.c
+// RUN: %clang_profgen -O2 -mllvm -disable-vp=false -Xclang -fprofile-instrument=llvm -mllvm -vp-static-alloc=true -mllvm -vp-counters-per-site=256 -rpath %t.d -o %t.ir %t.d/t.ir.shared -DCALL_SHARED %S/Inputs/instrprof-value-prof-real.c
+// RUN: env LLVM_PROFILE_FILE=%t.ir.profraw LLVM_VP_MAX_NUM_VALS_PER_SITE=255 %run %t.ir
+// RUN: llvm-profdata merge -o %t.ir.profdata %t.ir.profraw
+// RUN: llvm-profdata show --all-functions -ic-targets %t.ir.profdata | FileCheck %S/Inputs/instrprof-value-prof-real.c
+// RUN: llvm-profdata merge -text %t.ir.profdata -o %t.ir.proftxt
+// RUN: llvm-profdata show --all-functions -ic-targets %t.ir.profdata | FileCheck %S/Inputs/instrprof-value-prof-real.c --check-prefix=SHARED
+// RUN: FileCheck %S/Inputs/instrprof-value-prof-real.c --check-prefix=IR < %t.ir.proftxt
+
+// IR level instrumentation: dynamic memory allocation
+// RUN: %clang_profgen -O2 -mllvm -disable-vp=false -Xclang -fprofile-instrument=llvm -mllvm -vp-static-alloc=false -mllvm -vp-counters-per-site=256 -fPIC -shared -o %t.d/t.ir.dyn.shared -DSHARED_LIB %S/Inputs/instrprof-value-prof-real.c
+// RUN: %clang_profgen -O2 -mllvm -disable-vp=false -Xclang -fprofile-instrument=llvm -mllvm -vp-static-alloc=false -mllvm -vp-counters-per-site=256 -rpath %t.d -o %t.ir.dyn %t.d/t.ir.dyn.shared -DCALL_SHARED %S/Inputs/instrprof-value-prof-real.c
+// RUN: env LLVM_PROFILE_FILE=%t.ir.dyn.profraw %run %t.ir.dyn
+// RUN: llvm-profdata merge -o %t.ir.dyn.profdata %t.ir.dyn.profraw
+// RUN: llvm-profdata show --all-functions -ic-targets %t.ir.dyn.profdata | FileCheck %S/Inputs/instrprof-value-prof-real.c
+// RUN: llvm-profdata merge -text %t.ir.dyn.profdata -o %t.ir.dyn.proftxt
+// RUN: llvm-profdata show --all-functions -ic-targets %t.ir.dyn.profdata | FileCheck %S/Inputs/instrprof-value-prof-real.c --check-prefix=SHARED
+// RUN: FileCheck %S/Inputs/instrprof-value-prof-real.c --check-prefix=IR < %t.ir.dyn.proftxt
+
+// IR level instrumentation: main program uses static counter, shared library uses dynamic memory alloc.
+// RUN: %clang_profgen -O2 -mllvm -disable-vp=false -Xclang -fprofile-instrument=llvm -mllvm -vp-static-alloc=false -mllvm -vp-counters-per-site=256 -fPIC -shared -o %t.d/t.ir.dyn.shared -DSHARED_LIB %S/Inputs/instrprof-value-prof-real.c
+// RUN: %clang_profgen -O2 -mllvm -disable-vp=false -Xclang -fprofile-instrument=llvm -mllvm -vp-static-alloc=true -mllvm -vp-counters-per-site=256 -rpath %t.d -o %t.ir.mixed %t.d/t.ir.dyn.shared -DCALL_SHARED %S/Inputs/instrprof-value-prof-real.c
+// RUN: env LLVM_PROFILE_FILE=%t.ir.mixed.profraw LLVM_VP_MAX_NUM_VALS_PER_SITE=255 %run %t.ir.mixed
+// RUN: llvm-profdata merge -o %t.ir.mixed.profdata %t.ir.mixed.profraw
+// RUN: llvm-profdata show --all-functions -ic-targets %t.ir.mixed.profdata | FileCheck %S/Inputs/instrprof-value-prof-real.c
+// RUN: llvm-profdata merge -text %t.ir.mixed.profdata -o %t.ir.mixed.proftxt
+// RUN: llvm-profdata show --all-functions -ic-targets %t.ir.mixed.profdata | FileCheck %S/Inputs/instrprof-value-prof-real.c --check-prefix=SHARED
+// RUN: FileCheck %S/Inputs/instrprof-value-prof-real.c --check-prefix=IR < %t.ir.mixed.proftxt
diff --git a/test/profile/instrprof-value-prof.c b/test/profile/instrprof-value-prof.c
index f09e1ac432f1..3a5bdbdd552e 100644
--- a/test/profile/instrprof-value-prof.c
+++ b/test/profile/instrprof-value-prof.c
@@ -1,6 +1,6 @@
-// RUN: %clang_profgen -O2 -o %t %s
-// RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t 1
-// RUN: env LLVM_PROFILE_FILE=%t-2.profraw %run %t
+// RUN: %clang_profgen -mllvm -vp-static-alloc=false -O2 -o %t %s
+// RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t
+// RUN: env LLVM_PROFILE_FILE=%t-2.profraw %run %t DO_NOT_INSTRUMENT
// RUN: llvm-profdata merge -o %t.profdata %t.profraw
// RUN: llvm-profdata merge -o %t-2.profdata %t-2.profraw
// RUN: llvm-profdata merge -o %t-merged.profdata %t.profraw %t-2.profdata
@@ -8,11 +8,11 @@
// RUN: llvm-profdata show --all-functions -ic-targets %t.profdata | FileCheck %s
// RUN: llvm-profdata show --all-functions -ic-targets %t-merged.profdata | FileCheck %s
//
-// RUN: env LLVM_PROFILE_FILE=%t-3.profraw LLVM_VP_BUFFER_SIZE=1 %run %t 1
-// RUN: env LLVM_PROFILE_FILE=%t-4.profraw LLVM_VP_BUFFER_SIZE=8 %run %t 1
-// RUN: env LLVM_PROFILE_FILE=%t-5.profraw LLVM_VP_BUFFER_SIZE=128 %run %t 1
-// RUN: env LLVM_PROFILE_FILE=%t-6.profraw LLVM_VP_BUFFER_SIZE=1024 %run %t 1
-// RUN: env LLVM_PROFILE_FILE=%t-7.profraw LLVM_VP_BUFFER_SIZE=102400 %run %t 1
+// RUN: env LLVM_PROFILE_FILE=%t-3.profraw LLVM_VP_BUFFER_SIZE=1 %run %t
+// RUN: env LLVM_PROFILE_FILE=%t-4.profraw LLVM_VP_BUFFER_SIZE=8 %run %t
+// RUN: env LLVM_PROFILE_FILE=%t-5.profraw LLVM_VP_BUFFER_SIZE=128 %run %t
+// RUN: env LLVM_PROFILE_FILE=%t-6.profraw LLVM_VP_BUFFER_SIZE=1024 %run %t
+// RUN: env LLVM_PROFILE_FILE=%t-7.profraw LLVM_VP_BUFFER_SIZE=102400 %run %t
// RUN: llvm-profdata merge -o %t-3.profdata %t-3.profraw
// RUN: llvm-profdata merge -o %t-4.profdata %t-4.profraw
// RUN: llvm-profdata merge -o %t-5.profdata %t-5.profraw
@@ -80,7 +80,7 @@ int main(int argc, const char *argv[]) {
unsigned S, NS = 0, I, V, doInstrument = 1;
const __llvm_profile_data *Data, *DataEnd;
- if (argc < 2)
+ if (argc >= 2 && !strcmp(argv[1], "DO_NOT_INSTRUMENT"))
doInstrument = 0;
for (I = 0; I < 128; I++) {
@@ -90,9 +90,12 @@ int main(int argc, const char *argv[]) {
qsort(CallerInfos, sizeof(CallerInfos) / sizeof(CallerInfo), sizeof(CallerInfo),
cmpaddr);
- /* We will synthesis value profile data for 128 callers functions.
- * The number of * value sites. The number values for each value site
- * ranges from 0 to 8. */
+ /* We will synthesis value profile data for 128 callers functions declared.
+ * The number of value sites for each caller function is recorded in
+ * the NS field of the CallerInfo object. For each value site, the number of
+ * callee values is determined by the site index (modulo 8). The frequency
+ * of each callee target synthesized is equal to V + 1, in which V is the
+ * index of the target value for the callsite. */
Data = __llvm_profile_begin_data();
DataEnd = __llvm_profile_end_data();
diff --git a/test/profile/instrprof-value-prof.test b/test/profile/instrprof-value-prof.test
new file mode 100644
index 000000000000..8e7f513d20cb
--- /dev/null
+++ b/test/profile/instrprof-value-prof.test
@@ -0,0 +1,21 @@
+// RUN: %clang_profgen -O2 -mllvm -enable-value-profiling=true -mllvm -vp-static-alloc=true -mllvm -vp-counters-per-site=256 -o %t %S/Inputs/instrprof-value-prof-real.c
+// RUN: env LLVM_PROFILE_FILE=%t.profraw LLVM_VP_MAX_NUM_VALS_PER_SITE=255 %run %t
+// RUN: llvm-profdata merge -o %t.profdata %t.profraw
+// RUN: llvm-profdata show --all-functions -ic-targets %t.profdata | FileCheck %S/Inputs/instrprof-value-prof-real.c
+
+// IR level instrumentation
+// RUN: %clang_profgen -O2 -mllvm -disable-vp=false -Xclang -fprofile-instrument=llvm -mllvm -vp-static-alloc=true -mllvm -vp-counters-per-site=256 -o %t.ir %S/Inputs/instrprof-value-prof-real.c
+// RUN: env LLVM_PROFILE_FILE=%t.ir.profraw LLVM_VP_MAX_NUM_VALS_PER_SITE=255 %run %t.ir
+// RUN: llvm-profdata merge -o %t.ir.profdata %t.ir.profraw
+// RUN: llvm-profdata show --all-functions -ic-targets %t.ir.profdata | FileCheck %S/Inputs/instrprof-value-prof-real.c
+// RUN: llvm-profdata merge -text %t.ir.profdata -o %t.ir.proftxt
+// RUN: FileCheck %S/Inputs/instrprof-value-prof-real.c --check-prefix=IR < %t.ir.proftxt
+
+// IR level instrumentation with dynamic memory allocation
+// RUN: %clang_profgen -O2 -mllvm -disable-vp=false -Xclang -fprofile-instrument=llvm -mllvm -vp-static-alloc=false -mllvm -vp-counters-per-site=256 -o %t.ir.dyn %S/Inputs/instrprof-value-prof-real.c
+// RUN: env LLVM_PROFILE_FILE=%t.ir.dyn.profraw %run %t.ir.dyn
+// RUN: llvm-profdata merge -o %t.ir.dyn.profdata %t.ir.dyn.profraw
+// RUN: llvm-profdata show --all-functions -ic-targets %t.ir.dyn.profdata | FileCheck %S/Inputs/instrprof-value-prof-real.c
+// RUN: llvm-profdata merge -text %t.ir.dyn.profdata -o %t.ir.dyn.proftxt
+// RUN: FileCheck %S/Inputs/instrprof-value-prof-real.c --check-prefix=IR < %t.ir.dyn.proftxt
+
diff --git a/test/profile/instrprof-version-mismatch.c b/test/profile/instrprof-version-mismatch.c
index 49ce41177d3a..81ae52119693 100644
--- a/test/profile/instrprof-version-mismatch.c
+++ b/test/profile/instrprof-version-mismatch.c
@@ -1,5 +1,5 @@
// RUN: %clang_profgen -o %t -O3 %s
-// RUN: LLVM_PROFILE_VERBOSE_ERRORS=1 %run %t 1 2>&1 | FileCheck %s
+// RUN: %run %t 1 2>&1 | FileCheck %s
// override the version variable with a bogus version:
unsigned long long __llvm_profile_raw_version = 10000;
@@ -8,4 +8,4 @@ int main(int argc, const char *argv[]) {
return 1;
return 0;
}
-// CHECK: LLVM Profile: runtime and instrumentation version mismatch
+// CHECK: LLVM Profile Error: Runtime and instrumentation version mismatch
diff --git a/test/profile/instrprof-visibility-kinds.inc b/test/profile/instrprof-visibility-kinds.inc
new file mode 100644
index 000000000000..23b899dd8a3d
--- /dev/null
+++ b/test/profile/instrprof-visibility-kinds.inc
@@ -0,0 +1,36 @@
+void f1() {}
+
+#ifndef NO_WEAK
+void f2() __attribute__((weak));
+void f2() {}
+#endif
+
+void f3() __attribute__((always_inline));
+void f3() {}
+
+#ifndef NO_EXTERN
+extern void f4();
+#endif
+
+void f5() __attribute__((visibility("default")));
+void f5() {}
+
+void f6() __attribute__((visibility("hidden")));
+void f6() {}
+
+void f7() __attribute__((visibility("internal")));
+void f7() {}
+
+void call() {
+ f1();
+#ifndef NO_WEAK
+ f2();
+#endif
+ f3();
+#ifndef NO_EXTERN
+ f4();
+#endif
+ f5();
+ f6();
+ f7();
+}
diff --git a/test/profile/instrprof-visibility.cpp b/test/profile/instrprof-visibility.cpp
new file mode 100644
index 000000000000..08b886536fb4
--- /dev/null
+++ b/test/profile/instrprof-visibility.cpp
@@ -0,0 +1,89 @@
+// RUN: %clangxx_profgen -fcoverage-mapping %S/Inputs/instrprof-visibility-helper.cpp -o %t %s
+// RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t
+// RUN: llvm-profdata merge %t.profraw -o %t.profdata
+// RUN: llvm-profdata show --all-functions %t.profraw | FileCheck %s --check-prefix=PROFILE
+// RUN: llvm-cov show %t -instr-profile=%t.profdata | FileCheck %s --check-prefix=COV
+
+namespace {
+#define NO_WEAK
+#define NO_EXTERN
+#include "instrprof-visibility-kinds.inc"
+#undef NO_EXTERN
+#undef NO_WEAK
+}
+
+namespace N1 {
+#include "instrprof-visibility-kinds.inc"
+}
+
+int main() {
+ call();
+ N1::call();
+ return 0;
+}
+
+// PROFILE-DAG: _ZN2N12f1Ev
+// PROFILE-DAG: _ZN2N12f2Ev
+// PROFILE-DAG: _ZN2N12f3Ev
+// PROFILE-DAG: _ZN2N12f4Ev
+// PROFILE-DAG: _ZN2N12f5Ev
+// PROFILE-DAG: _ZN2N12f6Ev
+// PROFILE-DAG: _ZN2N12f7Ev
+// PROFILE-DAG: _ZN2N14callEv
+// PROFILE-DAG: main
+// PROFILE-DAG: instrprof-visibility.cpp:_ZN12_GLOBAL__N_14callEv
+// PROFILE-DAG: instrprof-visibility.cpp:_ZN12_GLOBAL__N_12f1Ev
+// PROFILE-DAG: instrprof-visibility.cpp:_ZN12_GLOBAL__N_12f3Ev
+// PROFILE-DAG: instrprof-visibility.cpp:_ZN12_GLOBAL__N_12f5Ev
+// PROFILE-DAG: instrprof-visibility.cpp:_ZN12_GLOBAL__N_12f6Ev
+// PROFILE-DAG: instrprof-visibility.cpp:_ZN12_GLOBAL__N_12f7Ev
+// PROFILE-DAG: Total functions: 15
+
+// COV-DAG: instrprof-visibility-helper.cpp
+
+// COV-DAG: instrprof-visibility-kinds.inc
+
+// COV-DAG: _ZN2N12f1Ev
+// COV-DAG: instrprof-visibility.cpp:_ZN12_GLOBAL__N_12f1Ev
+// COV-DAG: instrprof-visibility.cpp:_ZN12_GLOBAL__N_12f3Ev
+// COV-DAG: _ZN2N12f3Ev
+// COV-DAG: instrprof-visibility.cpp:_ZN12_GLOBAL__N_12f5Ev
+// COV-DAG: _ZN2N12f5Ev
+// COV-DAG: _ZN2N12f6Ev
+// COV-DAG: instrprof-visibility.cpp:_ZN12_GLOBAL__N_12f6Ev
+// COV-DAG: instrprof-visibility.cpp:_ZN12_GLOBAL__N_12f7Ev
+// COV-DAG: _ZN2N12f7Ev
+
+// --- Check coverage for functions in the anonymous namespace.
+// COV-DAG: instrprof-visibility.cpp:_ZN12_GLOBAL__N_14callEv
+// COV-DAG: 1|{{.*}}|void call() {
+// COV-DAG: 1|{{.*}}| f1();
+// COV-DAG: 1|{{.*}}|#ifndef NO_WEAK
+// COV-DAG: |{{.*}}| f2();
+// COV-DAG: |{{.*}}|#endif
+// COV-DAG: 1|{{.*}}| f3();
+// COV-DAG: 1|{{.*}}|#ifndef NO_EXTERN
+// COV-DAG: |{{.*}}| f4();
+// COV-DAG: |{{.*}}|#endif
+// COV-DAG: 1|{{.*}}| f5();
+// COV-DAG: 1|{{.*}}| f6();
+// COV-DAG: 1|{{.*}}| f7();
+// COV-DAG: 1|{{.*}}|}
+
+// --- Check coverage for functions in namespace N1.
+// COV-DAG: _ZN2N14callEv
+// COV-DAG: 1|{{.*}}|void call() {
+// COV-DAG: 1|{{.*}}| f1();
+// COV-DAG: 1|{{.*}}|#ifndef NO_WEAK
+// COV-DAG: 1|{{.*}}| f2();
+// COV-DAG: 1|{{.*}}|#endif
+// COV-DAG: 1|{{.*}}| f3();
+// COV-DAG: 1|{{.*}}|#ifndef NO_EXTERN
+// COV-DAG: 1|{{.*}}| f4();
+// COV-DAG: 1|{{.*}}|#endif
+// COV-DAG: 1|{{.*}}| f5();
+// COV-DAG: 1|{{.*}}| f6();
+// COV-DAG: 1|{{.*}}| f7();
+// COV-DAG: 1|{{.*}}|}
+
+// COV-DAG: instrprof-visibility.cpp
diff --git a/test/profile/instrprof-without-libc.c b/test/profile/instrprof-without-libc.c
index eb0a76ded39f..0708833e2bfd 100644
--- a/test/profile/instrprof-without-libc.c
+++ b/test/profile/instrprof-without-libc.c
@@ -15,6 +15,8 @@
int __llvm_profile_runtime = 0;
uint64_t __llvm_profile_get_size_for_buffer(void);
int __llvm_profile_write_buffer(char *);
+void __llvm_profile_merge_from_buffer(const char *, uint64_t Size);
+
int write_buffer(uint64_t, const char *);
int main(int argc, const char *argv[]) {
// CHECK-LABEL: define {{.*}} @main(
@@ -29,12 +31,14 @@ int main(int argc, const char *argv[]) {
if (Size > MaxSize)
return 1;
int Write = __llvm_profile_write_buffer(Buffer);
- if (__llvm_profile_write_buffer(Buffer))
+ if (Write)
return Write;
#ifdef CHECK_SYMBOLS
// Don't write it out. Since we're checking the symbols, we don't have libc
// available.
+ // Call merge function to make sure it does not bring in libc deps:
+ __llvm_profile_merge_from_buffer(Buffer, Size);
return 0;
#else
// Actually write it out so we can FileCheck the output.
@@ -48,19 +52,19 @@ int main(int argc, const char *argv[]) {
}
// CHECK: ![[PD1]] = !{!"branch_weights", i32 1, i32 2}
-// CHECK-SYMBOLS-NOT: ___cxx_global_var_init
-// CHECK-SYMBOLS-NOT: ___llvm_profile_register_write_file_atexit
-// CHECK-SYMBOLS-NOT: ___llvm_profile_set_filename
-// CHECK-SYMBOLS-NOT: ___llvm_profile_write_file
-// CHECK-SYMBOLS-NOT: _fdopen
-// CHECK-SYMBOLS-NOT: _fopen
-// CHECK-SYMBOLS-NOT: _fwrite
-// CHECK-SYMBOLS-NOT: _getenv
-// CHECK-SYMBOLS-NOT: getenv
-// CHECK-SYMBOLS-NOT: _malloc
-// CHECK-SYMBOLS-NOT: malloc
-// CHECK-SYMBOLS-NOT: _calloc
-// CHECK-SYMBOLS-NOT: calloc
-// CHECK-SYMBOLS-NOT: _free
-// CHECK-SYMBOLS-NOT: free
-// CHECK-SYMBOLS-NOT: _open
+// CHECK-SYMBOLS-NOT: {{ }}___cxx_global_var_init
+// CHECK-SYMBOLS-NOT: {{ }}___llvm_profile_register_write_file_atexit
+// CHECK-SYMBOLS-NOT: {{ }}___llvm_profile_set_filename
+// CHECK-SYMBOLS-NOT: {{ }}___llvm_profile_write_file
+// CHECK-SYMBOLS-NOT: {{ }}_fdopen
+// CHECK-SYMBOLS-NOT: {{ }}_fopen
+// CHECK-SYMBOLS-NOT: {{ }}_fwrite
+// CHECK-SYMBOLS-NOT: {{ }}_getenv
+// CHECK-SYMBOLS-NOT: {{ }}getenv
+// CHECK-SYMBOLS-NOT: {{ }}_malloc
+// CHECK-SYMBOLS-NOT: {{ }}malloc
+// CHECK-SYMBOLS-NOT: {{ }}_calloc
+// CHECK-SYMBOLS-NOT: {{ }}calloc
+// CHECK-SYMBOLS-NOT: {{ }}_free
+// CHECK-SYMBOLS-NOT: {{ }}free
+// CHECK-SYMBOLS-NOT: {{ }}_open
diff --git a/test/profile/instrprof-write-file-only.c b/test/profile/instrprof-write-file-only.c
index 4abbdea7c674..f505cf64a5c7 100644
--- a/test/profile/instrprof-write-file-only.c
+++ b/test/profile/instrprof-write-file-only.c
@@ -11,7 +11,7 @@ int foo(int);
int main(int argc, const char *argv[]) {
// CHECK-LABEL: define {{.*}} @main(
// CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}, !prof ![[PD1:[0-9]+]]
- if (argc > 1)
+ if (argc > 42)
return 1;
// Since the runtime has been suppressed, initialize the file name, as the
diff --git a/test/profile/lit.cfg b/test/profile/lit.cfg
index b1b44a1a0665..3512e0abcf1a 100644
--- a/test/profile/lit.cfg
+++ b/test/profile/lit.cfg
@@ -2,8 +2,17 @@
import os
+def get_required_attr(config, attr_name):
+ attr_value = getattr(config, attr_name, None)
+ if attr_value == None:
+ 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 = 'Profile'
+config.name = 'Profile-' + config.target_arch
# Setup source root.
config.test_source_root = os.path.dirname(__file__)
@@ -11,7 +20,7 @@ config.test_source_root = os.path.dirname(__file__)
# Setup executable root.
if hasattr(config, 'profile_lit_binary_dir') and \
config.profile_lit_binary_dir is not None:
- config.test_exec_root = config.profile_lit_binary_dir
+ config.test_exec_root = os.path.join(config.profile_lit_binary_dir, config.name)
# If the above check didn't work, we're probably in the source tree. Use some
# magic to re-execute from the build tree.
@@ -36,15 +45,21 @@ config.suffixes = ['.c', '.cc', '.cpp', '.m', '.mm', '.ll', '.test']
config.excludes = ['Inputs']
# Clang flags.
-clang_cflags = [config.target_cflags] + extra_linkflags
+target_cflags=[get_required_attr(config, "target_cflags")]
+clang_cflags = target_cflags + extra_linkflags
+clang_cxxflags = config.cxx_mode_flags + clang_cflags
def build_invocation(compile_flags):
return " " + " ".join([config.clang] + compile_flags) + " "
# Add clang substitutions.
config.substitutions.append( ("%clang ", build_invocation(clang_cflags)) )
+config.substitutions.append( ("%clangxx ", build_invocation(clang_cxxflags)) )
config.substitutions.append( ("%clang_profgen ", build_invocation(clang_cflags) + " -fprofile-instr-generate ") )
+config.substitutions.append( ("%clang_profgen=", build_invocation(clang_cflags) + " -fprofile-instr-generate=") )
config.substitutions.append( ("%clang_profuse=", build_invocation(clang_cflags) + " -fprofile-instr-use=") )
+config.substitutions.append( ("%clangxx_profgen ", build_invocation(clang_cxxflags) + " -fprofile-instr-generate ") )
+config.substitutions.append( ("%clangxx_profuse=", build_invocation(clang_cxxflags) + " -fprofile-instr-use=") )
config.substitutions.append( ("%clang_profgen_gcc=", build_invocation(clang_cflags) + " -fprofile-generate=") )
config.substitutions.append( ("%clang_profuse_gcc=", build_invocation(clang_cflags) + " -fprofile-use=") )
diff --git a/test/profile/lit.site.cfg.in b/test/profile/lit.site.cfg.in
index 758568d6753a..1cb61b51ccb1 100644
--- a/test/profile/lit.site.cfg.in
+++ b/test/profile/lit.site.cfg.in
@@ -1,8 +1,9 @@
-## Autogenerated by LLVM/Clang configuration.
-# Do not edit!
+@LIT_SITE_CFG_IN_HEADER@
# Tool-specific config options.
config.profile_lit_binary_dir = "@PROFILE_LIT_BINARY_DIR@"
+config.target_cflags = "@PROFILE_TEST_TARGET_CFLAGS@"
+config.target_arch = "@PROFILE_TEST_TARGET_ARCH@"
# Load common config for all compiler-rt lit tests.
lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/test/lit.common.configured")
diff --git a/test/safestack/CMakeLists.txt b/test/safestack/CMakeLists.txt
index 6f5c2f9b0af4..c56e81a3ce21 100644
--- a/test/safestack/CMakeLists.txt
+++ b/test/safestack/CMakeLists.txt
@@ -26,4 +26,4 @@ configure_lit_site_cfg(
add_lit_testsuite(check-safestack "Running the SafeStack tests"
${CMAKE_CURRENT_BINARY_DIR}
DEPENDS ${SAFESTACK_TEST_DEPS})
-set_target_properties(check-safestack PROPERTIES FOLDER "SafeStack tests")
+set_target_properties(check-safestack PROPERTIES FOLDER "Compiler-RT Misc")
diff --git a/test/safestack/canary.c b/test/safestack/canary.c
new file mode 100644
index 000000000000..c6b81f24327f
--- /dev/null
+++ b/test/safestack/canary.c
@@ -0,0 +1,37 @@
+// RUN: %clang_safestack -fno-stack-protector -D_FORTIFY_SOURCE=0 -g %s -o %t.nossp
+// RUN: %run %t.nossp 2>&1 | FileCheck --check-prefix=NOSSP %s
+
+// RUN: %clang_safestack -fstack-protector-all -D_FORTIFY_SOURCE=0 -g %s -o %t.ssp
+// RUN: not --crash %run %t.ssp 2>&1 | FileCheck -check-prefix=SSP %s
+
+// Test stack canaries on the unsafe stack.
+
+// REQUIRES: stable-runtime
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+__attribute__((noinline)) void f(unsigned *y) {
+ char x;
+ char *volatile p = &x;
+ char *volatile q = (char *)y;
+ assert(p < q);
+ assert(q - p < 1024); // sanity
+ // This has technically undefined behavior, but we know the actual layout of
+ // the unsafe stack and this should not touch anything important.
+ memset(&x, 0xab, q - p + sizeof(*y));
+}
+
+int main(int argc, char **argv)
+{
+ unsigned y;
+ // NOSSP: main 1
+ // SSP: main 1
+ fprintf(stderr, "main 1\n");
+ f(&y);
+ // NOSSP: main 2
+ // SSP-NOT: main 2
+ fprintf(stderr, "main 2\n");
+ return 0;
+}
diff --git a/test/safestack/lit.site.cfg.in b/test/safestack/lit.site.cfg.in
index cb1e7292e5f2..6864f39dfb31 100644
--- a/test/safestack/lit.site.cfg.in
+++ b/test/safestack/lit.site.cfg.in
@@ -1,5 +1,4 @@
-## Autogenerated by LLVM/Clang configuration.
-# Do not edit!
+@LIT_SITE_CFG_IN_HEADER@
# Load common config for all compiler-rt lit tests.
lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/test/lit.common.configured")
diff --git a/test/sanitizer_common/CMakeLists.txt b/test/sanitizer_common/CMakeLists.txt
index 54b9135278ca..9f121654318f 100644
--- a/test/sanitizer_common/CMakeLists.txt
+++ b/test/sanitizer_common/CMakeLists.txt
@@ -60,5 +60,5 @@ if(SANITIZER_COMMON_TESTSUITES AND
${SANITIZER_COMMON_TESTSUITES}
DEPENDS ${SANITIZER_COMMON_TEST_DEPS})
set_target_properties(check-sanitizer PROPERTIES FOLDER
- "sanitizer_common tests")
+ "Compiler-RT Misc")
endif()
diff --git a/test/sanitizer_common/TestCases/Darwin/abort_on_error.cc b/test/sanitizer_common/TestCases/Darwin/abort_on_error.cc
index dbab5253d8c1..e73f669d830c 100644
--- a/test/sanitizer_common/TestCases/Darwin/abort_on_error.cc
+++ b/test/sanitizer_common/TestCases/Darwin/abort_on_error.cc
@@ -4,7 +4,7 @@
// RUN: %clangxx %s -o %t
// Intentionally don't inherit the default options.
-// RUN: %tool_options='' not --crash %run %t 2>&1
+// RUN: env %tool_options='' not --crash %run %t 2>&1
// When we use lit's default options, we shouldn't crash.
// RUN: not %run %t 2>&1
diff --git a/test/sanitizer_common/TestCases/Linux/abort_on_error.cc b/test/sanitizer_common/TestCases/Linux/abort_on_error.cc
index 7e444c2103ee..a5ef66536478 100644
--- a/test/sanitizer_common/TestCases/Linux/abort_on_error.cc
+++ b/test/sanitizer_common/TestCases/Linux/abort_on_error.cc
@@ -4,7 +4,7 @@
// RUN: %clangxx %s -o %t
// Intentionally don't inherit the default options.
-// RUN: %tool_options='' not %run %t 2>&1
+// RUN: env %tool_options='' not %run %t 2>&1
// When we use lit's default options, we shouldn't crash either. On Linux
// lit doesn't set options anyway.
diff --git a/test/sanitizer_common/TestCases/Posix/decorate_proc_maps.cc b/test/sanitizer_common/TestCases/Linux/decorate_proc_maps.cc
index 36d4df567ee7..36d4df567ee7 100644
--- a/test/sanitizer_common/TestCases/Posix/decorate_proc_maps.cc
+++ b/test/sanitizer_common/TestCases/Linux/decorate_proc_maps.cc
diff --git a/test/sanitizer_common/TestCases/Linux/fpe.cc b/test/sanitizer_common/TestCases/Linux/fpe.cc
index b4be500732b7..9a6f808a5cd7 100644
--- a/test/sanitizer_common/TestCases/Linux/fpe.cc
+++ b/test/sanitizer_common/TestCases/Linux/fpe.cc
@@ -9,7 +9,7 @@
// XFAIL: tsan
//
// FIXME: seems to fail on ARM
-// REQUIRES: x86_64-supported-target
+// REQUIRES: x86_64-target-arch
#include <assert.h>
#include <stdio.h>
#include <sanitizer/asan_interface.h>
diff --git a/test/sanitizer_common/TestCases/Linux/ill.cc b/test/sanitizer_common/TestCases/Linux/ill.cc
index 1edad4817a2f..2c69618ad7cb 100644
--- a/test/sanitizer_common/TestCases/Linux/ill.cc
+++ b/test/sanitizer_common/TestCases/Linux/ill.cc
@@ -9,7 +9,7 @@
// XFAIL: tsan
//
// FIXME: seems to fail on ARM
-// REQUIRES: x86_64-supported-target
+// REQUIRES: x86_64-target-arch
#include <assert.h>
#include <stdio.h>
#include <sanitizer/asan_interface.h>
diff --git a/test/sanitizer_common/TestCases/Linux/open_memstream.cc b/test/sanitizer_common/TestCases/Linux/open_memstream.cc
index 3bce030ddb23..cf31f44be7e9 100644
--- a/test/sanitizer_common/TestCases/Linux/open_memstream.cc
+++ b/test/sanitizer_common/TestCases/Linux/open_memstream.cc
@@ -1,6 +1,6 @@
// RUN: %clangxx -m64 -O0 -g -xc++ %s -o %t && %run %t
// RUN: %clangxx -m64 -O3 -g -xc++ %s -o %t && %run %t
-// REQUIRES: x86_64-supported-target
+// REQUIRES: x86_64-target-arch
#include <assert.h>
#include <stdio.h>
diff --git a/test/sanitizer_common/TestCases/Linux/ptrace.cc b/test/sanitizer_common/TestCases/Linux/ptrace.cc
index 67b64743043b..b10aecd3579d 100644
--- a/test/sanitizer_common/TestCases/Linux/ptrace.cc
+++ b/test/sanitizer_common/TestCases/Linux/ptrace.cc
@@ -92,6 +92,26 @@ int main(void) {
printf("%x\n", fpregs.fpsr);
#endif // (__aarch64__)
+#if (__s390__)
+ struct iovec regset_io;
+
+ struct _user_regs_struct regs;
+ regset_io.iov_base = &regs;
+ regset_io.iov_len = sizeof(regs);
+ res = ptrace(PTRACE_GETREGSET, pid, (void*)NT_PRSTATUS, (void*)&regset_io);
+ assert(!res);
+ if (regs.psw.addr)
+ printf("%lx\n", regs.psw.addr);
+
+ struct _user_fpregs_struct fpregs;
+ regset_io.iov_base = &fpregs;
+ regset_io.iov_len = sizeof(fpregs);
+ res = ptrace(PTRACE_GETREGSET, pid, (void*)NT_FPREGSET, (void*)&regset_io);
+ assert(!res);
+ if (fpregs.fpc)
+ printf("%x\n", fpregs.fpc);
+#endif // (__s390__)
+
siginfo_t siginfo;
res = ptrace(PTRACE_GETSIGINFO, pid, NULL, &siginfo);
assert(!res);
diff --git a/test/sanitizer_common/TestCases/Linux/recv_msg_trunc.cc b/test/sanitizer_common/TestCases/Linux/recv_msg_trunc.cc
new file mode 100644
index 000000000000..a806ce0f15ed
--- /dev/null
+++ b/test/sanitizer_common/TestCases/Linux/recv_msg_trunc.cc
@@ -0,0 +1,36 @@
+// Test that ASan doesn't raise false alarm when MSG_TRUNC is present.
+//
+// RUN: %clangxx %s -o %t && %run %t 2>&1
+//
+// UNSUPPORTED: android
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/ip.h>
+#include <assert.h>
+
+int main() {
+ int fd_0 = socket(AF_INET, SOCK_DGRAM, 0);
+ int fd_1 = socket(AF_INET, SOCK_DGRAM, 0);
+ struct sockaddr_in sin;
+ socklen_t len = sizeof(sin);
+ char *buf = (char *)malloc(1);
+
+ sin.sin_family = AF_INET;
+ // Choose a random port to bind.
+ sin.sin_port = 0;
+ sin.sin_addr.s_addr = INADDR_ANY;
+
+ assert(bind(fd_1, (struct sockaddr *)&sin, sizeof(sin)) == 0);
+ // Get the address and port binded.
+ assert(getsockname(fd_1, (struct sockaddr *)&sin, &len) == 0);
+ assert(sendto(fd_0, "hello", strlen("hello"), MSG_DONTWAIT,
+ (struct sockaddr *)&sin, sizeof(sin)) != -1);
+ assert(recv(fd_1, buf, 1, MSG_TRUNC) != -1);
+ free(buf);
+
+ return 0;
+}
+
diff --git a/test/sanitizer_common/TestCases/Linux/sem_init_glibc.cc b/test/sanitizer_common/TestCases/Linux/sem_init_glibc.cc
index f17453b2d517..193b33d7976d 100644
--- a/test/sanitizer_common/TestCases/Linux/sem_init_glibc.cc
+++ b/test/sanitizer_common/TestCases/Linux/sem_init_glibc.cc
@@ -2,24 +2,35 @@
// This test depends on the glibc layout of struct sem_t and checks that we
// don't leave sem_t::private uninitialized.
// UNSUPPORTED: android
+#include <features.h>
#include <assert.h>
#include <semaphore.h>
#include <string.h>
+#include <stdint.h>
-void my_sem_init(bool priv, int value, unsigned *a, unsigned char *b) {
+// This condition needs to correspond to __HAVE_64B_ATOMICS macro in glibc.
+#if (defined(__x86_64__) || defined(__aarch64__) || defined(__powerpc64__) || \
+ defined(__s390x__) || defined(__sparc64__) || defined(__alpha__) || \
+ defined(__ia64__) || defined(__m68k__)) && __GLIBC_PREREQ(2, 21)
+typedef uint64_t semval_t;
+#else
+typedef unsigned semval_t;
+#endif
+
+void my_sem_init(bool priv, int value, semval_t *a, unsigned char *b) {
sem_t sem;
memset(&sem, 0xAB, sizeof(sem));
sem_init(&sem, priv, value);
char *p = (char *)&sem;
- memcpy(a, p, sizeof(unsigned));
- memcpy(b, p + sizeof(unsigned), sizeof(char));
+ memcpy(a, p, sizeof(semval_t));
+ memcpy(b, p + sizeof(semval_t), sizeof(char));
sem_destroy(&sem);
}
int main() {
- unsigned a;
+ semval_t a;
unsigned char b;
my_sem_init(false, 42, &a, &b);
diff --git a/test/sanitizer_common/TestCases/Linux/weak_hook_test.cc b/test/sanitizer_common/TestCases/Linux/weak_hook_test.cc
new file mode 100644
index 000000000000..d5667649bb9c
--- /dev/null
+++ b/test/sanitizer_common/TestCases/Linux/weak_hook_test.cc
@@ -0,0 +1,82 @@
+// Test the weak hooks.
+// RUN: %clangxx %s -o %t
+// RUN: %run %t
+
+// Hooks are not implemented for lsan.
+// XFAIL: lsan
+
+#include <string.h>
+#include <assert.h>
+
+bool seen_memcmp, seen_strncmp, seen_strncasecmp, seen_strcmp, seen_strcasecmp,
+ seen_strstr, seen_strcasestr, seen_memmem;
+
+extern "C" {
+void __sanitizer_weak_hook_memcmp(void *called_pc, const void *s1,
+ const void *s2, size_t n, int result) {
+ seen_memcmp = true;
+}
+void __sanitizer_weak_hook_strncmp(void *called_pc, const char *s1,
+ const char *s2, size_t n, int result) {
+ seen_strncmp = true;
+}
+void __sanitizer_weak_hook_strncasecmp(void *called_pc, const char *s1,
+ const char *s2, size_t n, int result){
+ seen_strncasecmp = true;
+}
+void __sanitizer_weak_hook_strcmp(void *called_pc, const char *s1,
+ const char *s2, int result){
+ seen_strcmp = true;
+}
+void __sanitizer_weak_hook_strcasecmp(void *called_pc, const char *s1,
+ const char *s2, int result){
+ seen_strcasecmp = true;
+}
+void __sanitizer_weak_hook_strstr(void *called_pc, const char *s1,
+ const char *s2, char *result){
+ seen_strstr = true;
+}
+void __sanitizer_weak_hook_strcasestr(void *called_pc, const char *s1,
+ const char *s2, char *result){
+ seen_strcasestr = true;
+}
+void __sanitizer_weak_hook_memmem(void *called_pc, const void *s1, size_t len1,
+ const void *s2, size_t len2, void *result){
+ seen_memmem = true;
+}
+} // extern "C"
+
+char s1[] = "ABCDEF";
+char s2[] = "CDE";
+
+static volatile int int_sink;
+static volatile void *ptr_sink;
+
+int main() {
+ assert(sizeof(s2) < sizeof(s1));
+
+ int_sink = memcmp(s1, s2, sizeof(s2));
+ assert(seen_memcmp);
+
+ int_sink = strncmp(s1, s2, sizeof(s2));
+ assert(seen_strncmp);
+
+ int_sink = strncasecmp(s1, s2, sizeof(s2));
+ assert(seen_strncasecmp);
+
+ int_sink = strcmp(s1, s2);
+ assert(seen_strcmp);
+
+ int_sink = strcasecmp(s1, s2);
+ assert(seen_strcasecmp);
+
+ ptr_sink = strstr(s1, s2);
+ assert(seen_strstr);
+
+ ptr_sink = strcasestr(s1, s2);
+ assert(seen_strcasestr);
+
+ ptr_sink = memmem(s1, sizeof(s1), s2, sizeof(s2));
+ assert(seen_memmem);
+ return 0;
+}
diff --git a/test/sanitizer_common/TestCases/Posix/dedup_token_length_test.cc b/test/sanitizer_common/TestCases/Posix/dedup_token_length_test.cc
new file mode 100644
index 000000000000..88d41b6d5fea
--- /dev/null
+++ b/test/sanitizer_common/TestCases/Posix/dedup_token_length_test.cc
@@ -0,0 +1,40 @@
+// Test dedup_token_length
+// RUN: %clangxx -O0 %s -o %t
+// RUN: env %tool_options='abort_on_error=0' not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK0
+// RUN: env %tool_options='abort_on_error=0, dedup_token_length=0' not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK0
+// RUN: env %tool_options='abort_on_error=0, dedup_token_length=1' not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1
+// RUN: env %tool_options='abort_on_error=0, dedup_token_length=2' not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2
+// RUN: env %tool_options='abort_on_error=0, dedup_token_length=3' not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK3
+
+// REQUIRES: stable-runtime
+// FIXME: implement SEGV handler in other sanitizers, not just asan.
+// XFAIL: msan
+// XFAIL: lsan
+// XFAIL: tsan
+
+volatile int *null = 0;
+
+namespace Xyz {
+ template<class A, class B> void Abc() {
+ *null = 0;
+ }
+}
+
+extern "C" void bar() {
+ Xyz::Abc<int, int>();
+}
+
+void FOO() {
+ bar();
+}
+
+int main(int argc, char **argv) {
+ FOO();
+}
+
+// CHECK0-NOT: DEDUP_TOKEN:
+// CHECK1: DEDUP_TOKEN: void Xyz::Abc<int, int>()
+// CHECK1-NOT: bar
+// CHECK2: DEDUP_TOKEN: void Xyz::Abc<int, int>()--bar
+// CHECK2-NOT: FOO
+// CHECK3: DEDUP_TOKEN: void Xyz::Abc<int, int>()--bar--FOO()
diff --git a/test/sanitizer_common/TestCases/Linux/getpass.cc b/test/sanitizer_common/TestCases/Posix/getpass.cc
index 902c9cb5655c..251f9119d682 100644
--- a/test/sanitizer_common/TestCases/Linux/getpass.cc
+++ b/test/sanitizer_common/TestCases/Posix/getpass.cc
@@ -4,7 +4,11 @@
#include <stdio.h>
#include <unistd.h>
#include <string.h>
+#if __linux__
#include <pty.h>
+#else
+#include <util.h>
+#endif
int
main (int argc, char** argv)
diff --git a/test/sanitizer_common/TestCases/Posix/lit.local.cfg b/test/sanitizer_common/TestCases/Posix/lit.local.cfg
index a6d96d3054cf..60a9460820a6 100644
--- a/test/sanitizer_common/TestCases/Posix/lit.local.cfg
+++ b/test/sanitizer_common/TestCases/Posix/lit.local.cfg
@@ -5,5 +5,5 @@ def getRoot(config):
root = getRoot(config)
-if root.host_os in ['Windows', 'Darwin']:
+if root.host_os in ['Windows']:
config.unsupported = True
diff --git a/test/sanitizer_common/TestCases/Linux/sanitizer_set_death_callback_test.cc b/test/sanitizer_common/TestCases/Posix/sanitizer_set_death_callback_test.cc
index fdb68c0cdea5..fdb68c0cdea5 100644
--- a/test/sanitizer_common/TestCases/Linux/sanitizer_set_death_callback_test.cc
+++ b/test/sanitizer_common/TestCases/Posix/sanitizer_set_death_callback_test.cc
diff --git a/test/sanitizer_common/TestCases/Posix/sanitizer_set_report_fd_test.cc b/test/sanitizer_common/TestCases/Posix/sanitizer_set_report_fd_test.cc
new file mode 100644
index 000000000000..af7eea1d7de2
--- /dev/null
+++ b/test/sanitizer_common/TestCases/Posix/sanitizer_set_report_fd_test.cc
@@ -0,0 +1,37 @@
+// Test __sanitizer_set_report_fd:
+// RUN: %clangxx -O2 %s -o %t
+// RUN: not %run %t 2>&1 | FileCheck %s
+// RUN: not %run %t stdout | FileCheck %s
+// RUN: not %run %t %t-out && FileCheck < %t-out %s
+
+// REQUIRES: stable-runtime
+// FIXME: implement SEGV handler in other sanitizers, not just asan.
+// XFAIL: msan
+// XFAIL: lsan
+// XFAIL: tsan
+
+#include <sanitizer/common_interface_defs.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <assert.h>
+
+volatile int *null = 0;
+
+int main(int argc, char **argv) {
+ if (argc == 2) {
+ if (!strcmp(argv[1], "stdout")) {
+ __sanitizer_set_report_fd(reinterpret_cast<void*>(1));
+ } else {
+ int fd = open(argv[1], O_CREAT | O_WRONLY | O_TRUNC, S_IRWXU);
+ assert(fd > 0);
+ __sanitizer_set_report_fd(reinterpret_cast<void*>(fd));
+ }
+ }
+ *null = 0;
+}
+
+// CHECK: ERROR: {{.*}} SEGV on unknown address
diff --git a/test/sanitizer_common/TestCases/malloc_hook.cc b/test/sanitizer_common/TestCases/malloc_hook.cc
index 9702249c57e2..59cd620b3f63 100644
--- a/test/sanitizer_common/TestCases/malloc_hook.cc
+++ b/test/sanitizer_common/TestCases/malloc_hook.cc
@@ -10,23 +10,43 @@
extern "C" {
const volatile void *global_ptr;
+#define WRITE(s) write(1, s, sizeof(s))
+
// Note: avoid calling functions that allocate memory in malloc/free
// to avoid infinite recursion.
void __sanitizer_malloc_hook(const volatile void *ptr, size_t sz) {
- if (__sanitizer_get_ownership(ptr)) {
- write(1, "MallocHook\n", sizeof("MallocHook\n"));
+ if (__sanitizer_get_ownership(ptr) && sz == 4) {
+ WRITE("MallocHook\n");
global_ptr = ptr;
}
}
void __sanitizer_free_hook(const volatile void *ptr) {
if (__sanitizer_get_ownership(ptr) && ptr == global_ptr)
- write(1, "FreeHook\n", sizeof("FreeHook\n"));
+ WRITE("FreeHook\n");
}
} // extern "C"
+volatile int *x;
+
+void MallocHook1(const volatile void *ptr, size_t sz) { WRITE("MH1\n"); }
+void MallocHook2(const volatile void *ptr, size_t sz) { WRITE("MH2\n"); }
+void FreeHook1(const volatile void *ptr) { WRITE("FH1\n"); }
+void FreeHook2(const volatile void *ptr) { WRITE("FH2\n"); }
+// Call this function with uninitialized arguments to poison
+// TLS shadow for function parameters before calling operator
+// new and, eventually, user-provided hook.
+__attribute__((noinline)) void allocate(int *unused1, int *unused2) {
+ x = new int;
+}
+
int main() {
- volatile int *x = new int;
+ __sanitizer_install_malloc_and_free_hooks(MallocHook1, FreeHook1);
+ __sanitizer_install_malloc_and_free_hooks(MallocHook2, FreeHook2);
+ int *undef1, *undef2;
+ allocate(undef1, undef2);
// CHECK: MallocHook
+ // CHECK: MH1
+ // CHECK: MH2
// Check that malloc hook was called with correct argument.
if (global_ptr != (void*)x) {
_exit(1);
@@ -34,5 +54,7 @@ int main() {
*x = 0;
delete x;
// CHECK: FreeHook
+ // CHECK: FH1
+ // CHECK: FH2
return 0;
}
diff --git a/test/sanitizer_common/TestCases/options-include.cc b/test/sanitizer_common/TestCases/options-include.cc
index 1528b15b9e9a..5b0b6d52585a 100644
--- a/test/sanitizer_common/TestCases/options-include.cc
+++ b/test/sanitizer_common/TestCases/options-include.cc
@@ -1,9 +1,10 @@
// RUN: %clangxx -O0 %s -o %t
// Recursive include: options1 includes options2
-// RUN: echo -e "symbolize=1\ninclude='%t.options2.txt'" >%t.options1.txt
-// RUN: echo -e "help=1\n" >%t.options2.txt
-// RUN: echo -e "help=1\n" >%t.options.options-include.cc.tmp
+// RUN: echo "symbolize=1" > %t.options1.txt
+// RUN: echo "include='%t.options2.txt'" >>%t.options1.txt
+// RUN: echo "help=1" >%t.options2.txt
+// RUN: echo "help=1" >%t.options.options-include.cc.tmp
// RUN: cat %t.options1.txt
// RUN: cat %t.options2.txt
diff --git a/test/sanitizer_common/TestCases/print-stack-trace.cc b/test/sanitizer_common/TestCases/print-stack-trace.cc
index 9134a88dac17..0055b279666e 100644
--- a/test/sanitizer_common/TestCases/print-stack-trace.cc
+++ b/test/sanitizer_common/TestCases/print-stack-trace.cc
@@ -14,11 +14,11 @@ int main() {
return 0;
}
// CHECK: {{ #0 0x.* in __sanitizer_print_stack_trace}}
-// CHECK: {{ #1 0x.* in FooBarBaz(\(\))? .*print-stack-trace.cc:9}}
-// CHECK: {{ #2 0x.* in main.*print-stack-trace.cc:13}}
+// CHECK: {{ #1 0x.* in FooBarBaz(\(\))? .*}}print-stack-trace.cc:[[@LINE-8]]
+// CHECK: {{ #2 0x.* in main.*}}print-stack-trace.cc:[[@LINE-5]]
-// CUSTOM: frame:1 lineno:9
-// CUSTOM: frame:2 lineno:13
+// CUSTOM: frame:1 lineno:[[@LINE-11]]
+// CUSTOM: frame:2 lineno:[[@LINE-8]]
// NOINLINE: #0 0x{{.*}} in __sanitizer_print_stack_trace
-// NOINLINE: #1 0x{{.*}} in main{{.*}}print-stack-trace.cc:9
+// NOINLINE: #1 0x{{.*}} in main{{.*}}print-stack-trace.cc:[[@LINE-15]]
diff --git a/test/sanitizer_common/TestCases/strnlen.c b/test/sanitizer_common/TestCases/strnlen.c
new file mode 100644
index 000000000000..8ab8ec91151d
--- /dev/null
+++ b/test/sanitizer_common/TestCases/strnlen.c
@@ -0,0 +1,12 @@
+// RUN: %clang %s -o %t && %run %t 2>&1
+
+#include <assert.h>
+#include <string.h>
+int main(int argc, char **argv) {
+ const char *s = "mytest";
+ assert(strnlen(s, 0) == 0UL);
+ assert(strnlen(s, 1) == 1UL);
+ assert(strnlen(s, 6) == strlen(s));
+ assert(strnlen(s, 7) == strlen(s));
+ return 0;
+}
diff --git a/test/sanitizer_common/Unit/lit.site.cfg.in b/test/sanitizer_common/Unit/lit.site.cfg.in
index 2600585702b2..c62e23c28803 100644
--- a/test/sanitizer_common/Unit/lit.site.cfg.in
+++ b/test/sanitizer_common/Unit/lit.site.cfg.in
@@ -1,5 +1,4 @@
-## Autogenerated by LLVM/Clang configuration.
-# Do not edit!
+@LIT_SITE_CFG_IN_HEADER@
# Load common config for all compiler-rt unit tests.
lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/unittests/lit.common.unit.configured")
diff --git a/test/sanitizer_common/lit.common.cfg b/test/sanitizer_common/lit.common.cfg
index 7abbfc2d3c3a..b32fb1ba9685 100644
--- a/test/sanitizer_common/lit.common.cfg
+++ b/test/sanitizer_common/lit.common.cfg
@@ -3,7 +3,7 @@
# Setup source root.
config.test_source_root = os.path.join(os.path.dirname(__file__), "TestCases")
-config.name = "SanitizerCommon-" + config.tool_name
+config.name = "SanitizerCommon-" + config.name_suffix
default_tool_options = []
if config.tool_name == "asan":
@@ -23,6 +23,9 @@ else:
config.available_features.add(config.tool_name)
+if config.target_arch not in ['arm', 'armhf', 'aarch64']:
+ config.available_features.add('stable-runtime')
+
if config.host_os == 'Darwin':
# On Darwin, we default to `abort_on_error=1`, which would make tests run
# much slower. Let's override this and run lit tests with 'abort_on_error=0'.
diff --git a/test/sanitizer_common/lit.site.cfg.in b/test/sanitizer_common/lit.site.cfg.in
index 64a3edf6c682..414eabad1846 100644
--- a/test/sanitizer_common/lit.site.cfg.in
+++ b/test/sanitizer_common/lit.site.cfg.in
@@ -1,11 +1,14 @@
-# Load common config for all compiler-rt lit tests.
-lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/test/lit.common.configured")
+@LIT_SITE_CFG_IN_HEADER@
# Tool-specific config options.
+config.name_suffix = "@CONFIG_NAME@"
config.tool_name = "@SANITIZER_COMMON_LIT_TEST_MODE@"
config.target_cflags = "@SANITIZER_COMMON_TEST_TARGET_CFLAGS@"
config.target_arch = "@SANITIZER_COMMON_TEST_TARGET_ARCH@"
+# Load common config for all compiler-rt lit tests.
+lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/test/lit.common.configured")
+
# Load tool-specific config that would do the real work.
lit_config.load_config(config, "@SANITIZER_COMMON_LIT_SOURCE_DIR@/lit.common.cfg")
diff --git a/test/scudo/CMakeLists.txt b/test/scudo/CMakeLists.txt
new file mode 100644
index 000000000000..b6cb2fd24f01
--- /dev/null
+++ b/test/scudo/CMakeLists.txt
@@ -0,0 +1,28 @@
+set(SCUDO_LIT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
+set(SCUDO_LIT_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
+
+
+set(SCUDO_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS})
+if(NOT COMPILER_RT_STANDALONE_BUILD)
+ list(APPEND SCUDO_TEST_DEPS scudo)
+endif()
+
+configure_lit_site_cfg(
+ ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
+ ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg
+ )
+
+if(CMAKE_SYSTEM_NAME MATCHES "Linux")
+ EXEC_PROGRAM(cat ARGS "/proc/cpuinfo" OUTPUT_VARIABLE CPUINFO)
+ STRING(REGEX REPLACE "^.*(sse4_2).*$" "\\1" SSE_THERE ${CPUINFO})
+ STRING(COMPARE EQUAL "sse4_2" "${SSE_THERE}" SSE42_TRUE)
+endif(CMAKE_SYSTEM_NAME MATCHES "Linux")
+
+if (SSE42_TRUE AND CMAKE_SIZEOF_VOID_P EQUAL 8)
+ add_lit_testsuite(check-scudo
+ "Running the Scudo Hardened Allocator tests"
+ ${CMAKE_CURRENT_BINARY_DIR}
+ DEPENDS ${SCUDO_TEST_DEPS})
+ set_target_properties(check-scudo PROPERTIES FOLDER
+ "Compiler-RT Misc")
+endif(SSE42_TRUE AND CMAKE_SIZEOF_VOID_P EQUAL 8)
diff --git a/test/scudo/alignment.cpp b/test/scudo/alignment.cpp
new file mode 100644
index 000000000000..c5e57d179907
--- /dev/null
+++ b/test/scudo/alignment.cpp
@@ -0,0 +1,25 @@
+// RUN: %clang_scudo %s -o %t
+// RUN: not %run %t pointers 2>&1 | FileCheck %s
+
+// Tests that a non-16-byte aligned pointer will trigger the associated error
+// on deallocation.
+
+#include <assert.h>
+#include <malloc.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+int main(int argc, char **argv)
+{
+ assert(argc == 2);
+ if (!strcmp(argv[1], "pointers")) {
+ void *p = malloc(1U << 16);
+ if (!p)
+ return 1;
+ free(reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(p) | 8));
+ }
+ return 0;
+}
+
+// CHECK: ERROR: attempted to deallocate a chunk not properly aligned
diff --git a/test/scudo/double-free.cpp b/test/scudo/double-free.cpp
new file mode 100644
index 000000000000..4f5bf0cb8e56
--- /dev/null
+++ b/test/scudo/double-free.cpp
@@ -0,0 +1,49 @@
+// RUN: %clang_scudo %s -o %t
+// RUN: not %run %t malloc 2>&1 | FileCheck %s
+// RUN: not %run %t new 2>&1 | FileCheck %s
+// RUN: not %run %t newarray 2>&1 | FileCheck %s
+// RUN: not %run %t memalign 2>&1 | FileCheck %s
+
+// Tests double-free error on pointers allocated with different allocation
+// functions.
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+int main(int argc, char **argv)
+{
+ assert(argc == 2);
+ if (!strcmp(argv[1], "malloc")) {
+ void *p = malloc(sizeof(int));
+ if (!p)
+ return 1;
+ free(p);
+ free(p);
+ }
+ if (!strcmp(argv[1], "new")) {
+ int *p = new int;
+ if (!p)
+ return 1;
+ delete p;
+ delete p;
+ }
+ if (!strcmp(argv[1], "newarray")) {
+ int *p = new int[8];
+ if (!p)
+ return 1;
+ delete[] p;
+ delete[] p;
+ }
+ if (!strcmp(argv[1], "memalign")) {
+ void *p = nullptr;
+ posix_memalign(&p, 0x100, sizeof(int));
+ if (!p)
+ return 1;
+ free(p);
+ free(p);
+ }
+ return 0;
+}
+
+// CHECK: ERROR: invalid chunk state when deallocating address
diff --git a/test/scudo/lit.cfg b/test/scudo/lit.cfg
new file mode 100644
index 000000000000..e2a4997dd3c2
--- /dev/null
+++ b/test/scudo/lit.cfg
@@ -0,0 +1,39 @@
+# -*- Python -*-
+
+import os
+
+# Setup config name.
+config.name = 'Scudo'
+
+# Setup source root.
+config.test_source_root = os.path.dirname(__file__)
+
+# Path to the static library
+base_lib = os.path.join(config.compiler_rt_libdir,
+ "libclang_rt.scudo-%s.a" % config.target_arch)
+whole_archive = "-Wl,-whole-archive %s -Wl,-no-whole-archive " % base_lib
+
+# Test suffixes.
+config.suffixes = ['.c', '.cc', '.cpp', '.m', '.mm', '.ll', '.test']
+
+# C flags.
+c_flags = ["-std=c++11",
+ "-lstdc++",
+ "-ldl",
+ "-lrt",
+ "-pthread",
+ "-latomic",
+ "-fPIE",
+ "-pie",
+ "-O0"]
+
+def build_invocation(compile_flags):
+ return " " + " ".join([config.clang] + compile_flags) + " "
+
+# Add clang substitutions.
+config.substitutions.append( ("%clang_scudo ",
+ build_invocation(c_flags) + whole_archive) )
+
+# Hardened Allocator tests are currently supported on Linux only.
+if config.host_os not in ['Linux']:
+ config.unsupported = True
diff --git a/test/scudo/lit.site.cfg.in b/test/scudo/lit.site.cfg.in
new file mode 100644
index 000000000000..64e2fb39eed8
--- /dev/null
+++ b/test/scudo/lit.site.cfg.in
@@ -0,0 +1,7 @@
+@LIT_SITE_CFG_IN_HEADER@
+
+# Load common config for all compiler-rt lit tests.
+lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/test/lit.common.configured")
+
+# Load tool-specific config that would do the real work.
+lit_config.load_config(config, "@SCUDO_LIT_SOURCE_DIR@/lit.cfg")
diff --git a/test/scudo/malloc.cpp b/test/scudo/malloc.cpp
new file mode 100644
index 000000000000..4507a5225ceb
--- /dev/null
+++ b/test/scudo/malloc.cpp
@@ -0,0 +1,27 @@
+// RUN: %clang_scudo %s -o %t
+// RUN: %run %t 2>&1
+
+// Tests that a regular workflow of allocation, memory fill and free works as
+// intended. Also tests that a zero-sized allocation succeeds.
+
+#include <malloc.h>
+#include <stdlib.h>
+#include <string.h>
+
+int main(int argc, char **argv)
+{
+ void *p;
+ size_t size = 1U << 8;
+
+ p = malloc(size);
+ if (!p)
+ return 1;
+ memset(p, 'A', size);
+ free(p);
+ p = malloc(0);
+ if (!p)
+ return 1;
+ free(p);
+
+ return 0;
+}
diff --git a/test/scudo/memalign.cpp b/test/scudo/memalign.cpp
new file mode 100644
index 000000000000..951d1aade6ec
--- /dev/null
+++ b/test/scudo/memalign.cpp
@@ -0,0 +1,45 @@
+// RUN: %clang_scudo %s -o %t
+// RUN: %run %t valid 2>&1
+// RUN: not %run %t invalid 2>&1 | FileCheck %s
+
+// Tests that the various aligned allocation functions work as intended. Also
+// tests for the condition where the alignment is not a power of 2.
+
+#include <assert.h>
+#include <malloc.h>
+#include <stdlib.h>
+#include <string.h>
+
+// Sometimes the headers may not have this...
+extern "C" void *aligned_alloc (size_t alignment, size_t size);
+
+int main(int argc, char **argv)
+{
+ void *p;
+ size_t alignment = 1U << 12;
+ size_t size = alignment;
+
+ assert(argc == 2);
+ if (!strcmp(argv[1], "valid")) {
+ p = memalign(alignment, size);
+ if (!p)
+ return 1;
+ free(p);
+ p = nullptr;
+ posix_memalign(&p, alignment, size);
+ if (!p)
+ return 1;
+ free(p);
+ p = aligned_alloc(alignment, size);
+ if (!p)
+ return 1;
+ free(p);
+ }
+ if (!strcmp(argv[1], "invalid")) {
+ p = memalign(alignment - 1, size);
+ free(p);
+ }
+ return 0;
+}
+
+// CHECK: ERROR: malloc alignment is not a power of 2
diff --git a/test/scudo/mismatch.cpp b/test/scudo/mismatch.cpp
new file mode 100644
index 000000000000..2d3d198af640
--- /dev/null
+++ b/test/scudo/mismatch.cpp
@@ -0,0 +1,41 @@
+// RUN: %clang_scudo %s -o %t
+// RUN: SCUDO_OPTIONS=DeallocationTypeMismatch=1 not %run %t mallocdel 2>&1 | FileCheck %s
+// RUN: SCUDO_OPTIONS=DeallocationTypeMismatch=0 %run %t mallocdel 2>&1
+// RUN: SCUDO_OPTIONS=DeallocationTypeMismatch=1 not %run %t newfree 2>&1 | FileCheck %s
+// RUN: SCUDO_OPTIONS=DeallocationTypeMismatch=0 %run %t newfree 2>&1
+// RUN: SCUDO_OPTIONS=DeallocationTypeMismatch=1 not %run %t memaligndel 2>&1 | FileCheck %s
+// RUN: SCUDO_OPTIONS=DeallocationTypeMismatch=0 %run %t memaligndel 2>&1
+
+// Tests that type mismatches between allocation and deallocation functions are
+// caught when the related option is set.
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <malloc.h>
+
+int main(int argc, char **argv)
+{
+ assert(argc == 2);
+ if (!strcmp(argv[1], "mallocdel")) {
+ int *p = (int *)malloc(16);
+ if (!p)
+ return 1;
+ delete p;
+ }
+ if (!strcmp(argv[1], "newfree")) {
+ int *p = new int;
+ if (!p)
+ return 1;
+ free((void *)p);
+ }
+ if (!strcmp(argv[1], "memaligndel")) {
+ int *p = (int *)memalign(0x10, 0x10);
+ if (!p)
+ return 1;
+ delete p;
+ }
+ return 0;
+}
+
+// CHECK: ERROR: allocation type mismatch on address
diff --git a/test/scudo/overflow.cpp b/test/scudo/overflow.cpp
new file mode 100644
index 000000000000..5b2cb7560133
--- /dev/null
+++ b/test/scudo/overflow.cpp
@@ -0,0 +1,38 @@
+// RUN: %clang_scudo %s -o %t
+// RUN: not %run %t malloc 2>&1 | FileCheck %s
+// RUN: SCUDO_OPTIONS=QuarantineSizeMb=1 not %run %t quarantine 2>&1 | FileCheck %s
+
+// Tests that header corruption of an allocated or quarantined chunk is caught.
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+int main(int argc, char **argv)
+{
+ assert(argc == 2);
+ if (!strcmp(argv[1], "malloc")) {
+ // Simulate a header corruption of an allocated chunk (1-bit)
+ void *p = malloc(1U << 4);
+ if (!p)
+ return 1;
+ ((char *)p)[-1] ^= 1;
+ free(p);
+ }
+ if (!strcmp(argv[1], "quarantine")) {
+ void *p = malloc(1U << 4);
+ if (!p)
+ return 1;
+ free(p);
+ // Simulate a header corruption of a quarantined chunk
+ ((char *)p)[-2] ^= 1;
+ // Trigger the quarantine recycle
+ for (int i = 0; i < 0x100; i++) {
+ p = malloc(1U << 16);
+ free(p);
+ }
+ }
+ return 0;
+}
+
+// CHECK: ERROR: corrupted chunk header at address
diff --git a/test/scudo/preinit.cpp b/test/scudo/preinit.cpp
new file mode 100644
index 000000000000..a280ae1d440a
--- /dev/null
+++ b/test/scudo/preinit.cpp
@@ -0,0 +1,38 @@
+// RUN: %clang_scudo %s -o %t
+// RUN: %run %t 2>&1
+
+// Verifies that calling malloc in a preinit_array function succeeds, and that
+// the resulting pointer can be freed at program termination.
+
+#include <malloc.h>
+#include <stdlib.h>
+#include <string.h>
+
+static void *global_p = nullptr;
+
+void __init(void) {
+ global_p = malloc(1);
+ if (!global_p)
+ exit(1);
+}
+
+void __fini(void) {
+ if (global_p)
+ free(global_p);
+}
+
+int main(int argc, char **argv)
+{
+ void *p = malloc(1);
+ if (!p)
+ return 1;
+ free(p);
+
+ return 0;
+}
+
+__attribute__((section(".preinit_array"), used))
+ void (*__local_preinit)(void) = __init;
+__attribute__((section(".fini_array"), used))
+ void (*__local_fini)(void) = __fini;
+
diff --git a/test/scudo/quarantine.cpp b/test/scudo/quarantine.cpp
new file mode 100644
index 000000000000..4ce0197acdec
--- /dev/null
+++ b/test/scudo/quarantine.cpp
@@ -0,0 +1,43 @@
+// RUN: %clang_scudo %s -o %t
+// RUN: SCUDO_OPTIONS=QuarantineSizeMb=1 %run %t 2>&1
+
+// Tests that the quarantine prevents a chunk from being reused right away.
+// Also tests that a chunk will eventually become available again for
+// allocation when the recycling criteria has been met.
+
+#include <malloc.h>
+#include <stdlib.h>
+#include <string.h>
+
+int main(int argc, char **argv)
+{
+ void *p, *old_p;
+ size_t size = 1U << 16;
+
+ // The delayed freelist will prevent a chunk from being available right away
+ p = malloc(size);
+ if (!p)
+ return 1;
+ old_p = p;
+ free(p);
+ p = malloc(size);
+ if (!p)
+ return 1;
+ if (old_p == p)
+ return 1;
+ free(p);
+
+ // Eventually the chunk should become available again
+ bool found = false;
+ for (int i = 0; i < 0x100 && found == false; i++) {
+ p = malloc(size);
+ if (!p)
+ return 1;
+ found = (p == old_p);
+ free(p);
+ }
+ if (found == false)
+ return 1;
+
+ return 0;
+}
diff --git a/test/scudo/realloc.cpp b/test/scudo/realloc.cpp
new file mode 100644
index 000000000000..2a7d5b69f5f2
--- /dev/null
+++ b/test/scudo/realloc.cpp
@@ -0,0 +1,69 @@
+// RUN: %clang_scudo %s -o %t
+// RUN: %run %t pointers 2>&1
+// RUN: %run %t contents 2>&1
+// RUN: not %run %t memalign 2>&1 | FileCheck %s
+
+// Tests that our reallocation function returns the same pointer when the
+// requested size can fit into the previously allocated chunk. Also tests that
+// a new chunk is returned if the size is greater, and that the contents of the
+// chunk are left unchanged.
+// As a final test, make sure that a chunk allocated by memalign cannot be
+// reallocated.
+
+#include <assert.h>
+#include <malloc.h>
+#include <string.h>
+
+int main(int argc, char **argv)
+{
+ void *p, *old_p;
+ size_t size = 32;
+
+ assert(argc == 2);
+ if (!strcmp(argv[1], "pointers")) {
+ old_p = p = realloc(nullptr, size);
+ if (!p)
+ return 1;
+ size = malloc_usable_size(p);
+ // Our realloc implementation will return the same pointer if the size
+ // requested is lower or equal to the usable size of the associated chunk.
+ p = realloc(p, size - 1);
+ if (p != old_p)
+ return 1;
+ p = realloc(p, size);
+ if (p != old_p)
+ return 1;
+ // And a new one if the size is greater.
+ p = realloc(p, size + 1);
+ if (p == old_p)
+ return 1;
+ // A size of 0 will free the chunk and return nullptr.
+ p = realloc(p, 0);
+ if (p)
+ return 1;
+ old_p = nullptr;
+ }
+ if (!strcmp(argv[1], "contents")) {
+ p = realloc(nullptr, size);
+ if (!p)
+ return 1;
+ for (int i = 0; i < size; i++)
+ reinterpret_cast<char *>(p)[i] = 'A';
+ p = realloc(p, size + 1);
+ // The contents of the reallocated chunk must match the original one.
+ for (int i = 0; i < size; i++)
+ if (reinterpret_cast<char *>(p)[i] != 'A')
+ return 1;
+ }
+ if (!strcmp(argv[1], "memalign")) {
+ // A chunk coming from memalign cannot be reallocated.
+ p = memalign(16, size);
+ if (!p)
+ return 1;
+ p = realloc(p, size);
+ free(p);
+ }
+ return 0;
+}
+
+// CHECK: ERROR: invalid chunk type when reallocating address
diff --git a/test/scudo/sized-delete.cpp b/test/scudo/sized-delete.cpp
new file mode 100644
index 000000000000..5b1bf5fd4cbe
--- /dev/null
+++ b/test/scudo/sized-delete.cpp
@@ -0,0 +1,40 @@
+// RUN: %clang_scudo -fsized-deallocation %s -o %t
+// RUN: SCUDO_OPTIONS=DeleteSizeMismatch=1 %run %t gooddel 2>&1
+// RUN: SCUDO_OPTIONS=DeleteSizeMismatch=1 not %run %t baddel 2>&1 | FileCheck %s
+// RUN: SCUDO_OPTIONS=DeleteSizeMismatch=0 %run %t baddel 2>&1
+// RUN: SCUDO_OPTIONS=DeleteSizeMismatch=1 %run %t gooddelarr 2>&1
+// RUN: SCUDO_OPTIONS=DeleteSizeMismatch=1 not %run %t baddelarr 2>&1 | FileCheck %s
+// RUN: SCUDO_OPTIONS=DeleteSizeMismatch=0 %run %t baddelarr 2>&1
+
+// Ensures that the sized delete operator errors out when the appropriate
+// option is passed and the sizes do not match between allocation and
+// deallocation functions.
+
+#include <new>
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+int main(int argc, char **argv)
+{
+ assert(argc == 2);
+ if (!strcmp(argv[1], "gooddel")) {
+ long long *p = new long long;
+ operator delete(p, sizeof(long long));
+ }
+ if (!strcmp(argv[1], "baddel")) {
+ long long *p = new long long;
+ operator delete(p, 2);
+ }
+ if (!strcmp(argv[1], "gooddelarr")) {
+ char *p = new char[64];
+ operator delete[](p, 64);
+ }
+ if (!strcmp(argv[1], "baddelarr")) {
+ char *p = new char[63];
+ operator delete[](p, 64);
+ }
+ return 0;
+}
+
+// CHECK: ERROR: invalid sized delete on chunk at address
diff --git a/test/scudo/sizes.cpp b/test/scudo/sizes.cpp
new file mode 100644
index 000000000000..7190cb64f337
--- /dev/null
+++ b/test/scudo/sizes.cpp
@@ -0,0 +1,61 @@
+// RUN: %clang_scudo %s -o %t
+// RUN: SCUDO_OPTIONS=allocator_may_return_null=0 not %run %t malloc 2>&1 | FileCheck %s
+// RUN: SCUDO_OPTIONS=allocator_may_return_null=1 %run %t malloc 2>&1
+// RUN: SCUDO_OPTIONS=allocator_may_return_null=0 not %run %t calloc 2>&1 | FileCheck %s
+// RUN: SCUDO_OPTIONS=allocator_may_return_null=1 %run %t calloc 2>&1
+// RUN: %run %t usable 2>&1
+
+// Tests for various edge cases related to sizes, notably the maximum size the
+// allocator can allocate. Tests that an integer overflow in the parameters of
+// calloc is caught.
+
+#include <assert.h>
+#include <malloc.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <limits>
+
+int main(int argc, char **argv)
+{
+ assert(argc == 2);
+ if (!strcmp(argv[1], "malloc")) {
+ // Currently the maximum size the allocator can allocate is 1ULL<<40 bytes.
+ size_t size = std::numeric_limits<size_t>::max();
+ void *p = malloc(size);
+ if (p)
+ return 1;
+ size = (1ULL << 40) - 16;
+ p = malloc(size);
+ if (p)
+ return 1;
+ }
+ if (!strcmp(argv[1], "calloc")) {
+ // Trigger an overflow in calloc.
+ size_t size = std::numeric_limits<size_t>::max();
+ void *p = calloc((size / 0x1000) + 1, 0x1000);
+ if (p)
+ return 1;
+ }
+ if (!strcmp(argv[1], "usable")) {
+ // Playing with the actual usable size of a chunk.
+ void *p = malloc(1007);
+ if (!p)
+ return 1;
+ size_t size = malloc_usable_size(p);
+ if (size < 1007)
+ return 1;
+ memset(p, 'A', size);
+ p = realloc(p, 2014);
+ if (!p)
+ return 1;
+ size = malloc_usable_size(p);
+ if (size < 2014)
+ return 1;
+ memset(p, 'B', size);
+ free(p);
+ }
+ return 0;
+}
+
+// CHECK: allocator is terminating the process
diff --git a/test/tsan/CMakeLists.txt b/test/tsan/CMakeLists.txt
index a058602659c1..e05b100f3699 100644
--- a/test/tsan/CMakeLists.txt
+++ b/test/tsan/CMakeLists.txt
@@ -22,6 +22,7 @@ if(APPLE)
endif()
foreach(arch ${TSAN_TEST_ARCH})
+ set(TSAN_TEST_TARGET_ARCH ${arch})
string(TOLOWER "-${arch}" TSAN_TEST_CONFIG_SUFFIX)
if(ANDROID OR ${arch} MATCHES "arm|aarch64")
# This is only true if we are cross-compiling.
@@ -53,4 +54,4 @@ endif()
add_lit_testsuite(check-tsan "Running ThreadSanitizer tests"
${TSAN_TESTSUITES}
DEPENDS ${TSAN_TEST_DEPS})
-set_target_properties(check-tsan PROPERTIES FOLDER "TSan tests")
+set_target_properties(check-tsan PROPERTIES FOLDER "Compiler-RT Tests")
diff --git a/test/tsan/Darwin/dispatch_main.mm b/test/tsan/Darwin/dispatch_main.mm
new file mode 100644
index 000000000000..75887547c606
--- /dev/null
+++ b/test/tsan/Darwin/dispatch_main.mm
@@ -0,0 +1,38 @@
+// Check that we don't crash when dispatch_main calls pthread_exit which
+// quits the main thread.
+
+// RUN: %clang_tsan %s -o %t -framework Foundation
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+
+#import <Foundation/Foundation.h>
+
+int main() {
+ fprintf(stderr,"Hello world");
+
+ dispatch_queue_t q = dispatch_queue_create("my.queue", DISPATCH_QUEUE_SERIAL);
+
+ dispatch_async(q, ^{
+ fprintf(stderr,"1");
+ });
+
+ dispatch_async(q, ^{
+ fprintf(stderr,"2");
+ });
+
+ dispatch_async(q, ^{
+ fprintf(stderr,"3");
+
+ dispatch_async(dispatch_get_main_queue(), ^{
+ fprintf(stderr,"Done.");
+ sleep(1);
+ exit(0);
+ });
+ });
+
+ dispatch_main();
+}
+
+// CHECK: Hello world
+// CHECK: Done.
+// CHECK-NOT: WARNING: ThreadSanitizer
+// CHECK-NOT: CHECK failed
diff --git a/test/tsan/Darwin/dispatch_once_deadlock.mm b/test/tsan/Darwin/dispatch_once_deadlock.mm
new file mode 100644
index 000000000000..e88cdc0d0da5
--- /dev/null
+++ b/test/tsan/Darwin/dispatch_once_deadlock.mm
@@ -0,0 +1,41 @@
+// Check that calling dispatch_once from a report callback works.
+
+// RUN: %clang_tsan %s -o %t -framework Foundation
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 not %run %t 2>&1 | FileCheck %s
+
+#import <Foundation/Foundation.h>
+#import <pthread.h>
+
+long g = 0;
+long h = 0;
+void f() {
+ static dispatch_once_t onceToken;
+ dispatch_once(&onceToken, ^{
+ g++;
+ });
+ h++;
+}
+
+extern "C" void __tsan_on_report() {
+ fprintf(stderr, "Report.\n");
+ f();
+}
+
+int main() {
+ fprintf(stderr, "Hello world.\n");
+
+ f();
+
+ pthread_mutex_t mutex = {0};
+ pthread_mutex_lock(&mutex);
+
+ fprintf(stderr, "g = %ld.\n", g);
+ fprintf(stderr, "h = %ld.\n", h);
+ fprintf(stderr, "Done.\n");
+}
+
+// CHECK: Hello world.
+// CHECK: Report.
+// CHECK: g = 1
+// CHECK: h = 2
+// CHECK: Done.
diff --git a/test/tsan/Darwin/dlopen.cc b/test/tsan/Darwin/dlopen.cc
new file mode 100644
index 000000000000..7382a6de28c5
--- /dev/null
+++ b/test/tsan/Darwin/dlopen.cc
@@ -0,0 +1,41 @@
+// Checks that on OS X 10.11+ (where we do not re-exec anymore, because
+// interceptors work automatically), dlopen'ing a TSanified library from a
+// non-instrumented program exits with a user-friendly message.
+
+// REQUIRES: osx-autointerception
+
+// RUN: %clangxx_tsan %s -o %t.so -shared -DSHARED_LIB
+// RUN: %clangxx_tsan -fno-sanitize=thread %s -o %t
+
+// RUN: TSAN_DYLIB_PATH=`%clangxx_tsan %s -### 2>&1 \
+// RUN: | grep "libclang_rt.tsan_osx_dynamic.dylib" \
+// RUN: | sed -e 's/.*"\(.*libclang_rt.tsan_osx_dynamic.dylib\)".*/\1/'`
+
+// Launching a non-instrumented binary that dlopen's an instrumented library should fail.
+// RUN: not %run %t %t.so 2>&1 | FileCheck %s --check-prefix=CHECK-FAIL
+// Launching a non-instrumented binary with an explicit DYLD_INSERT_LIBRARIES should work.
+// RUN: DYLD_INSERT_LIBRARIES=$TSAN_DYLIB_PATH %run %t %t.so 2>&1 | FileCheck %s
+
+#include <dlfcn.h>
+#include <pthread.h>
+#include <stdio.h>
+
+#if defined(SHARED_LIB)
+extern "C" void foo() {
+ fprintf(stderr, "Hello world.\n");
+}
+#else // defined(SHARED_LIB)
+int main(int argc, char *argv[]) {
+ void *handle = dlopen(argv[1], RTLD_NOW);
+ fprintf(stderr, "handle = %p\n", handle);
+ void (*foo)() = (void (*)())dlsym(handle, "foo");
+ fprintf(stderr, "foo = %p\n", foo);
+ foo();
+}
+#endif // defined(SHARED_LIB)
+
+// CHECK: Hello world.
+// CHECK-NOT: ERROR: Interceptors are not working.
+
+// CHECK-FAIL-NOT: Hello world.
+// CHECK-FAIL: ERROR: Interceptors are not working.
diff --git a/test/tsan/Darwin/gcd-after.mm b/test/tsan/Darwin/gcd-after.mm
new file mode 100644
index 000000000000..49b6bc6f71e9
--- /dev/null
+++ b/test/tsan/Darwin/gcd-after.mm
@@ -0,0 +1,41 @@
+// RUN: %clang_tsan %s -o %t -framework Foundation
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+
+#import <Foundation/Foundation.h>
+
+long my_global;
+long my_global2;
+
+void callback(void *context) {
+ my_global2 = 42;
+
+ dispatch_async(dispatch_get_main_queue(), ^{
+ CFRunLoopStop(CFRunLoopGetMain());
+ });
+}
+
+int main(int argc, const char *argv[]) {
+ fprintf(stderr, "start\n");
+
+ my_global = 10;
+ dispatch_queue_t q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10 * NSEC_PER_MSEC)), q, ^{
+ my_global = 42;
+
+ dispatch_async(dispatch_get_main_queue(), ^{
+ CFRunLoopStop(CFRunLoopGetMain());
+ });
+ });
+ CFRunLoopRun();
+
+ my_global2 = 10;
+ dispatch_after_f(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10 * NSEC_PER_MSEC)), q, NULL, &callback);
+ CFRunLoopRun();
+
+ fprintf(stderr, "done\n");
+ return 0;
+}
+
+// CHECK: start
+// CHECK: done
+// CHECK-NOT: WARNING: ThreadSanitizer
diff --git a/test/tsan/Darwin/gcd-apply-race.mm b/test/tsan/Darwin/gcd-apply-race.mm
new file mode 100644
index 000000000000..13b24e0fdb90
--- /dev/null
+++ b/test/tsan/Darwin/gcd-apply-race.mm
@@ -0,0 +1,26 @@
+// RUN: %clang_tsan %s -o %t -framework Foundation
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %deflake %run %t 2>&1 | FileCheck %s
+
+#import <Foundation/Foundation.h>
+
+#import "../test.h"
+
+long global;
+
+int main(int argc, const char *argv[]) {
+ barrier_init(&barrier, 2);
+ fprintf(stderr, "start\n");
+ dispatch_queue_t q = dispatch_queue_create("my.queue", DISPATCH_QUEUE_CONCURRENT);
+ dispatch_apply(2, q, ^(size_t i) {
+ global = i;
+ barrier_wait(&barrier);
+ });
+
+ fprintf(stderr, "done\n");
+ return 0;
+}
+
+// CHECK: start
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: Location is global 'global'
+// CHECK: done
diff --git a/test/tsan/Darwin/gcd-apply.mm b/test/tsan/Darwin/gcd-apply.mm
new file mode 100644
index 000000000000..e68a4b18205d
--- /dev/null
+++ b/test/tsan/Darwin/gcd-apply.mm
@@ -0,0 +1,44 @@
+// RUN: %clang_tsan %s -o %t -framework Foundation
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+
+#import <Foundation/Foundation.h>
+
+#import "../test.h"
+
+long global;
+long array[2];
+
+void callback(void *context, size_t i) {
+ long n = global;
+ array[i] = n + i;
+ barrier_wait(&barrier);
+}
+
+int main(int argc, const char *argv[]) {
+ barrier_init(&barrier, 2);
+ fprintf(stderr, "start\n");
+ dispatch_queue_t q = dispatch_queue_create("my.queue", DISPATCH_QUEUE_CONCURRENT);
+
+ global = 42;
+
+ dispatch_apply(100, q, ^(size_t i) {
+ long n = global;
+ array[i] = n + i;
+ barrier_wait(&barrier);
+ });
+
+ for (int i = 0; i < 100; i++) {
+ fprintf(stderr, "array[%d] = %ld\n", i, array[i]);
+ }
+
+ global = 43;
+
+ dispatch_apply_f(100, q, NULL, &callback);
+
+ fprintf(stderr, "done\n");
+ return 0;
+}
+
+// CHECK: start
+// CHECK: done
+// CHECK-NOT: WARNING: ThreadSanitizer
diff --git a/test/tsan/Darwin/gcd-async-norace.mm b/test/tsan/Darwin/gcd-async-norace.mm
index b987e00656fb..c7e28b4ce791 100644
--- a/test/tsan/Darwin/gcd-async-norace.mm
+++ b/test/tsan/Darwin/gcd-async-norace.mm
@@ -1,5 +1,5 @@
// RUN: %clang_tsan %s -o %t -framework Foundation
-// RUN: %run %t 2>&1
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
#import <Foundation/Foundation.h>
diff --git a/test/tsan/Darwin/gcd-async-race.mm b/test/tsan/Darwin/gcd-async-race.mm
index 31163f972896..1002a56b0a16 100644
--- a/test/tsan/Darwin/gcd-async-race.mm
+++ b/test/tsan/Darwin/gcd-async-race.mm
@@ -1,5 +1,5 @@
// RUN: %clang_tsan %s -o %t -framework Foundation
-// RUN: %deflake %run %t 2>&1
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %deflake %run %t 2>&1 | FileCheck %s
#import <Foundation/Foundation.h>
@@ -9,7 +9,7 @@ long global;
int main() {
NSLog(@"Hello world.");
- NSLog(@"addr=%p\n", &global);
+ print_address("addr=", 1, &global);
barrier_init(&barrier, 2);
global = 42;
@@ -34,5 +34,5 @@ int main() {
// CHECK: Hello world.
// CHECK: addr=[[ADDR:0x[0-9,a-f]+]]
// CHECK: WARNING: ThreadSanitizer: data race
-// CHECK: Location is global 'global' at [[ADDR]] (global_race.cc.exe+0x{{[0-9,a-f]+}})
+// CHECK: Location is global 'global' {{(of size 8 )?}}at [[ADDR]] (gcd-async-race.mm.tmp+0x{{[0-9,a-f]+}})
// CHECK: Done.
diff --git a/test/tsan/Darwin/gcd-barrier-race.mm b/test/tsan/Darwin/gcd-barrier-race.mm
new file mode 100644
index 000000000000..c42eaebded2b
--- /dev/null
+++ b/test/tsan/Darwin/gcd-barrier-race.mm
@@ -0,0 +1,48 @@
+// RUN: %clang_tsan %s -o %t -framework Foundation
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %deflake %run %t 2>&1 | FileCheck %s
+
+#import <Foundation/Foundation.h>
+
+#import "../test.h"
+
+long global;
+
+int main() {
+ fprintf(stderr, "Hello world.\n");
+ print_address("addr=", 1, &global);
+ barrier_init(&barrier, 2);
+
+ dispatch_queue_t q = dispatch_queue_create("my.queue", DISPATCH_QUEUE_CONCURRENT);
+ dispatch_queue_t bgq = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
+
+ dispatch_barrier_sync(q, ^{
+ global = 42;
+ });
+
+ dispatch_async(bgq, ^{
+ dispatch_sync(q, ^{
+ global = 43;
+ barrier_wait(&barrier);
+ });
+ });
+
+ dispatch_async(bgq, ^{
+ dispatch_sync(q, ^{
+ barrier_wait(&barrier);
+ global = 44;
+
+ dispatch_sync(dispatch_get_main_queue(), ^{
+ CFRunLoopStop(CFRunLoopGetCurrent());
+ });
+ });
+ });
+
+ CFRunLoopRun();
+ fprintf(stderr, "Done.\n");
+}
+
+// CHECK: Hello world.
+// CHECK: addr=[[ADDR:0x[0-9,a-f]+]]
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: Location is global 'global' {{(of size 8 )?}}at [[ADDR]] (gcd-barrier-race.mm.tmp+0x{{[0-9,a-f]+}})
+// CHECK: Done.
diff --git a/test/tsan/Darwin/gcd-barrier.mm b/test/tsan/Darwin/gcd-barrier.mm
new file mode 100644
index 000000000000..6f58cae7d8f5
--- /dev/null
+++ b/test/tsan/Darwin/gcd-barrier.mm
@@ -0,0 +1,49 @@
+// RUN: %clang_tsan %s -o %t -framework Foundation
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+
+#import <Foundation/Foundation.h>
+
+#import "../test.h"
+
+long global;
+
+int main() {
+ fprintf(stderr, "Hello world.\n");
+ print_address("addr=", 1, &global);
+ barrier_init(&barrier, 2);
+
+ dispatch_queue_t q = dispatch_queue_create("my.queue", DISPATCH_QUEUE_CONCURRENT);
+ dispatch_queue_t bgq = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
+
+ dispatch_async(bgq, ^{
+ dispatch_sync(q, ^{
+ global = 42;
+ });
+ barrier_wait(&barrier);
+ });
+
+ dispatch_async(bgq, ^{
+ barrier_wait(&barrier);
+ dispatch_barrier_sync(q, ^{
+ global = 43;
+ });
+
+ dispatch_async(bgq, ^{
+ barrier_wait(&barrier);
+ global = 44;
+ });
+
+ barrier_wait(&barrier);
+
+ dispatch_sync(dispatch_get_main_queue(), ^{
+ CFRunLoopStop(CFRunLoopGetCurrent());
+ });
+ });
+
+ CFRunLoopRun();
+ fprintf(stderr, "Done.\n");
+}
+
+// CHECK: Hello world.
+// CHECK: Done.
+// CHECK-NOT: WARNING: ThreadSanitizer
diff --git a/test/tsan/Darwin/gcd-blocks.mm b/test/tsan/Darwin/gcd-blocks.mm
new file mode 100644
index 000000000000..e0082605f24e
--- /dev/null
+++ b/test/tsan/Darwin/gcd-blocks.mm
@@ -0,0 +1,34 @@
+// RUN: %clangxx_tsan %s -o %t -framework Foundation
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+
+#import <Foundation/Foundation.h>
+
+int main() {
+ fprintf(stderr, "start\n");
+
+ dispatch_queue_t background_q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
+ dispatch_queue_t main_q = dispatch_get_main_queue();
+
+ dispatch_async(background_q, ^{
+ __block long block_var = 0;
+
+ dispatch_sync(main_q, ^{
+ block_var = 42;
+ });
+
+ fprintf(stderr, "block_var = %ld\n", block_var);
+
+ dispatch_sync(dispatch_get_main_queue(), ^{
+ CFRunLoopStop(CFRunLoopGetCurrent());
+ });
+ });
+
+ CFRunLoopRun();
+ fprintf(stderr, "done\n");
+}
+
+// CHECK: start
+// CHECK: block_var = 42
+// CHECK: done
+// CHECK-NOT: WARNING: ThreadSanitizer
+// CHECK-NOT: CHECK failed
diff --git a/test/tsan/Darwin/gcd-data.mm b/test/tsan/Darwin/gcd-data.mm
new file mode 100644
index 000000000000..a5154dc3598d
--- /dev/null
+++ b/test/tsan/Darwin/gcd-data.mm
@@ -0,0 +1,36 @@
+// RUN: %clang_tsan %s -o %t -framework Foundation
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+
+#import <Foundation/Foundation.h>
+
+long global;
+
+int main(int argc, const char *argv[]) {
+ fprintf(stderr, "Hello world.\n");
+
+ dispatch_queue_t q = dispatch_queue_create("my.queue", DISPATCH_QUEUE_SERIAL);
+ dispatch_semaphore_t sem = dispatch_semaphore_create(0);
+
+ global = 44;
+ dispatch_data_t data = dispatch_data_create("buffer", 6, q, ^{
+ fprintf(stderr, "Data destructor.\n");
+ global++;
+
+ dispatch_semaphore_signal(sem);
+ });
+ dispatch_release(data);
+ data = nil;
+
+ dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
+
+ data = dispatch_data_create("buffer", 6, q, DISPATCH_DATA_DESTRUCTOR_DEFAULT);
+ dispatch_release(data);
+ data = nil;
+
+ fprintf(stderr, "Done.\n");
+}
+
+// CHECK: Hello world.
+// CHECK: Data destructor.
+// CHECK-NOT: WARNING: ThreadSanitizer
+// CHECK: Done.
diff --git a/test/tsan/Darwin/gcd-fd.mm b/test/tsan/Darwin/gcd-fd.mm
new file mode 100644
index 000000000000..75da9cd4252d
--- /dev/null
+++ b/test/tsan/Darwin/gcd-fd.mm
@@ -0,0 +1,60 @@
+// RUN: %clang_tsan %s -o %t -framework Foundation
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+
+#import <Foundation/Foundation.h>
+
+long my_global = 0;
+
+int main(int argc, const char *argv[]) {
+ fprintf(stderr, "Hello world.\n");
+
+ dispatch_queue_t queue = dispatch_queue_create("my.queue", DISPATCH_QUEUE_SERIAL);
+ dispatch_semaphore_t sem = dispatch_semaphore_create(0);
+
+ NSString *path = [NSTemporaryDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:@"temp-gcd-io.%d", getpid()]];
+
+ dispatch_io_t channel = dispatch_io_create_with_path(DISPATCH_IO_STREAM, path.fileSystemRepresentation, O_CREAT | O_WRONLY,
+ 0666, queue, ^(int error) { });
+ dispatch_io_set_high_water(channel, 1);
+
+ NSData *ns_data = [NSMutableData dataWithLength:1000];
+ dispatch_data_t data = dispatch_data_create(ns_data.bytes, ns_data.length, NULL, DISPATCH_DATA_DESTRUCTOR_DEFAULT);
+
+ my_global++;
+ dispatch_io_write(channel, 0, data, queue, ^(bool done, dispatch_data_t remainingData, int error) {
+ my_global++;
+ dispatch_async(queue, ^{
+ my_global++;
+ if (done) {
+ dispatch_semaphore_signal(sem);
+ }
+ });
+ });
+
+ dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
+ my_global++;
+ dispatch_io_close(channel, 0);
+ channel = dispatch_io_create_with_path(DISPATCH_IO_STREAM, path.fileSystemRepresentation, O_RDONLY,
+ 0, queue, ^(int error) { });
+ dispatch_io_set_high_water(channel, 1);
+
+ my_global++;
+ dispatch_io_read(channel, 0, SIZE_MAX, queue, ^(bool done, dispatch_data_t remainingData, int error) {
+ my_global++;
+ dispatch_async(queue, ^{
+ my_global++;
+ if (done) {
+ dispatch_semaphore_signal(sem);
+ }
+ });
+ });
+
+ dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
+ my_global++;
+ fprintf(stderr, "Done.\n");
+ return 0;
+}
+
+// CHECK: Hello world.
+// CHECK-NOT: WARNING: ThreadSanitizer
+// CHECK: Done.
diff --git a/test/tsan/Darwin/gcd-groups-destructor.mm b/test/tsan/Darwin/gcd-groups-destructor.mm
new file mode 100644
index 000000000000..19c2c9bd147f
--- /dev/null
+++ b/test/tsan/Darwin/gcd-groups-destructor.mm
@@ -0,0 +1,43 @@
+// RUN: %clangxx_tsan %s -o %t -framework Foundation
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+
+#import <Foundation/Foundation.h>
+
+#import <memory>
+#import <stdatomic.h>
+
+_Atomic(long) destructor_counter = 0;
+
+struct MyStruct {
+ virtual ~MyStruct() {
+ usleep(10000);
+ atomic_fetch_add_explicit(&destructor_counter, 1, memory_order_relaxed);
+ }
+};
+
+int main(int argc, const char *argv[]) {
+ fprintf(stderr, "Hello world.\n");
+
+ dispatch_queue_t q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
+ dispatch_group_t g = dispatch_group_create();
+
+ for (int i = 0; i < 100; i++) {
+ std::shared_ptr<MyStruct> shared(new MyStruct());
+
+ dispatch_group_async(g, q, ^{
+ shared.get(); // just to make sure the object is captured by the block
+ });
+ }
+
+ dispatch_group_wait(g, DISPATCH_TIME_FOREVER);
+
+ if (destructor_counter != 100) {
+ abort();
+ }
+
+ fprintf(stderr, "Done.\n");
+}
+
+// CHECK: Hello world.
+// CHECK-NOT: WARNING: ThreadSanitizer
+// CHECK: Done.
diff --git a/test/tsan/Darwin/gcd-groups-leave.mm b/test/tsan/Darwin/gcd-groups-leave.mm
new file mode 100644
index 000000000000..6ecf85f5ff0d
--- /dev/null
+++ b/test/tsan/Darwin/gcd-groups-leave.mm
@@ -0,0 +1,56 @@
+// RUN: %clang_tsan %s -o %t -framework Foundation
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+
+#import <Foundation/Foundation.h>
+
+#import "../test.h"
+
+dispatch_semaphore_t sem;
+
+long global;
+long global2;
+
+void callback(void *context) {
+ global2 = 48;
+ barrier_wait(&barrier);
+
+ dispatch_semaphore_signal(sem);
+}
+
+int main() {
+ fprintf(stderr, "Hello world.\n");
+ barrier_init(&barrier, 2);
+
+ dispatch_queue_t q = dispatch_queue_create("my.queue", DISPATCH_QUEUE_CONCURRENT);
+ dispatch_group_t g = dispatch_group_create();
+ sem = dispatch_semaphore_create(0);
+
+ dispatch_group_enter(g);
+ dispatch_async(q, ^{
+ global = 47;
+ dispatch_group_leave(g);
+ barrier_wait(&barrier);
+ });
+ dispatch_group_notify(g, q, ^{
+ global = 48;
+ barrier_wait(&barrier);
+
+ dispatch_semaphore_signal(sem);
+ });
+ dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
+
+ dispatch_group_enter(g);
+ dispatch_async(q, ^{
+ global2 = 47;
+ dispatch_group_leave(g);
+ barrier_wait(&barrier);
+ });
+ dispatch_group_notify_f(g, q, NULL, &callback);
+ dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
+
+ fprintf(stderr, "Done.\n");
+}
+
+// CHECK: Hello world.
+// CHECK-NOT: WARNING: ThreadSanitizer
+// CHECK: Done.
diff --git a/test/tsan/Darwin/gcd-groups-norace.mm b/test/tsan/Darwin/gcd-groups-norace.mm
index fb4d804ed8c7..64ec386ca40f 100644
--- a/test/tsan/Darwin/gcd-groups-norace.mm
+++ b/test/tsan/Darwin/gcd-groups-norace.mm
@@ -1,5 +1,5 @@
// RUN: %clang_tsan %s -o %t -framework Foundation
-// RUN: %run %t 2>&1
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
#import <Foundation/Foundation.h>
diff --git a/test/tsan/Darwin/gcd-groups-stress.mm b/test/tsan/Darwin/gcd-groups-stress.mm
index 62a80085ed8d..457d9afd9c93 100644
--- a/test/tsan/Darwin/gcd-groups-stress.mm
+++ b/test/tsan/Darwin/gcd-groups-stress.mm
@@ -1,5 +1,5 @@
// RUN: %clang_tsan %s -o %t -framework Foundation
-// RUN: %run %t 2>&1
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
#import <Foundation/Foundation.h>
@@ -30,7 +30,7 @@ int main() {
dispatch_async(q, ^{
dispatch_group_leave(g);
});
- dispatch_group_notify_f(g, q, nullptr, &notify_callback);
+ dispatch_group_notify_f(g, q, NULL, &notify_callback);
dispatch_release(g);
}
diff --git a/test/tsan/Darwin/gcd-io-barrier-race.mm b/test/tsan/Darwin/gcd-io-barrier-race.mm
new file mode 100644
index 000000000000..fffc19bd16de
--- /dev/null
+++ b/test/tsan/Darwin/gcd-io-barrier-race.mm
@@ -0,0 +1,55 @@
+// RUN: %clang_tsan %s -o %t -framework Foundation
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %deflake %run %t 2>&1 | FileCheck %s
+
+#import <Foundation/Foundation.h>
+
+#import "../test.h"
+
+dispatch_queue_t queue;
+dispatch_data_t data;
+dispatch_semaphore_t sem;
+const char *path;
+
+long my_global = 0;
+
+int main(int argc, const char *argv[]) {
+ fprintf(stderr, "Hello world.\n");
+ print_address("addr=", 1, &my_global);
+ barrier_init(&barrier, 2);
+
+ queue = dispatch_queue_create("my.queue", DISPATCH_QUEUE_CONCURRENT);
+ sem = dispatch_semaphore_create(0);
+ NSString *ns_path = [NSTemporaryDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:@"temp-gcd-io.%d", getpid()]];
+ path = ns_path.fileSystemRepresentation;
+ NSData *ns_data = [NSMutableData dataWithLength:1000];
+ data = dispatch_data_create(ns_data.bytes, ns_data.length, NULL, DISPATCH_DATA_DESTRUCTOR_DEFAULT);
+
+ dispatch_io_t channel = dispatch_io_create_with_path(DISPATCH_IO_STREAM, path, O_CREAT | O_WRONLY, 0666, queue, ^(int error) { });
+ if (! channel) abort();
+ dispatch_io_set_high_water(channel, 1);
+
+ dispatch_io_write(channel, 0, data, queue, ^(bool done, dispatch_data_t remainingData, int error) {
+ if (error) abort();
+ my_global = 42;
+ barrier_wait(&barrier);
+ });
+
+ dispatch_io_barrier(channel, ^{
+ barrier_wait(&barrier);
+ my_global = 43;
+
+ dispatch_semaphore_signal(sem);
+ });
+
+ dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
+ dispatch_io_close(channel, 0);
+
+ fprintf(stderr, "Done.\n");
+ return 0;
+}
+
+// CHECK: Hello world.
+// CHECK: addr=[[ADDR:0x[0-9,a-f]+]]
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: Location is global 'my_global' {{(of size 8 )?}}at [[ADDR]] (gcd-io-barrier-race.mm.tmp+0x{{[0-9,a-f]+}})
+// CHECK: Done.
diff --git a/test/tsan/Darwin/gcd-io-barrier.mm b/test/tsan/Darwin/gcd-io-barrier.mm
new file mode 100644
index 000000000000..fe30138f6036
--- /dev/null
+++ b/test/tsan/Darwin/gcd-io-barrier.mm
@@ -0,0 +1,48 @@
+// RUN: %clang_tsan %s -o %t -framework Foundation
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+
+#import <Foundation/Foundation.h>
+
+dispatch_queue_t queue;
+dispatch_data_t data;
+dispatch_semaphore_t sem;
+const char *path;
+
+long my_global = 0;
+
+int main(int argc, const char *argv[]) {
+ fprintf(stderr, "Hello world.\n");
+
+ queue = dispatch_queue_create("my.queue", DISPATCH_QUEUE_CONCURRENT);
+ sem = dispatch_semaphore_create(0);
+ NSString *ns_path = [NSTemporaryDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:@"temp-gcd-io.%d", getpid()]];
+ path = ns_path.fileSystemRepresentation;
+ NSData *ns_data = [NSMutableData dataWithLength:1000];
+ data = dispatch_data_create(ns_data.bytes, ns_data.length, NULL, DISPATCH_DATA_DESTRUCTOR_DEFAULT);
+
+ dispatch_io_t channel = dispatch_io_create_with_path(DISPATCH_IO_STREAM, path, O_CREAT | O_WRONLY, 0666, queue, ^(int error) { });
+ if (! channel) abort();
+ dispatch_io_set_high_water(channel, 1);
+
+ for (int i = 0; i < 1000; i++) {
+ dispatch_io_barrier(channel, ^{
+ my_global = 42;
+ });
+ }
+
+ dispatch_io_barrier(channel, ^{
+ my_global = 43;
+
+ dispatch_semaphore_signal(sem);
+ });
+
+ dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
+ dispatch_io_close(channel, 0);
+
+ fprintf(stderr, "Done.\n");
+ return 0;
+}
+
+// CHECK: Hello world.
+// CHECK-NOT: WARNING: ThreadSanitizer
+// CHECK: Done.
diff --git a/test/tsan/Darwin/gcd-io-cleanup.mm b/test/tsan/Darwin/gcd-io-cleanup.mm
new file mode 100644
index 000000000000..b15fa0dc2532
--- /dev/null
+++ b/test/tsan/Darwin/gcd-io-cleanup.mm
@@ -0,0 +1,56 @@
+// RUN: %clang_tsan %s -o %t -framework Foundation
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+
+#import <Foundation/Foundation.h>
+
+long my_global = 0;
+
+int main(int argc, const char *argv[]) {
+ fprintf(stderr, "Hello world.\n");
+
+ dispatch_queue_t queue = dispatch_queue_create("my.queue", DISPATCH_QUEUE_CONCURRENT);
+ dispatch_semaphore_t sem = dispatch_semaphore_create(0);
+ NSString *ns_path = [NSTemporaryDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:@"temp-gcd-io.%d", getpid()]];
+ const char *path = ns_path.fileSystemRepresentation;
+ dispatch_io_t channel;
+
+ dispatch_fd_t fd = open(path, O_CREAT | O_WRONLY, 0666);
+ my_global++;
+ channel = dispatch_io_create(DISPATCH_IO_STREAM, fd, queue, ^(int error) {
+ my_global++;
+ dispatch_semaphore_signal(sem);
+ });
+ if (! channel) abort();
+ my_global++;
+ dispatch_io_close(channel, 0);
+ dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
+
+ my_global++;
+ channel = dispatch_io_create_with_path(DISPATCH_IO_STREAM, path, O_CREAT | O_WRONLY, 0666, queue, ^(int error) {
+ my_global++;
+ dispatch_semaphore_signal(sem);
+ });
+ if (! channel) abort();
+ my_global++;
+ dispatch_io_close(channel, 0);
+ dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
+
+ my_global++;
+ dispatch_io_t other_channel = dispatch_io_create_with_path(DISPATCH_IO_STREAM, path, O_CREAT | O_WRONLY, 0666, queue, ^(int error) { });
+ channel = dispatch_io_create_with_io(DISPATCH_IO_STREAM, other_channel, queue, ^(int error) {
+ my_global++;
+ dispatch_semaphore_signal(sem);
+ });
+ if (! channel) abort();
+ my_global++;
+ dispatch_io_close(channel, 0);
+ dispatch_io_close(other_channel, 0);
+ dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
+
+ fprintf(stderr, "Done.\n");
+ return 0;
+}
+
+// CHECK: Hello world.
+// CHECK-NOT: WARNING: ThreadSanitizer
+// CHECK: Done.
diff --git a/test/tsan/Darwin/gcd-io-race.mm b/test/tsan/Darwin/gcd-io-race.mm
new file mode 100644
index 000000000000..0bec28fdb758
--- /dev/null
+++ b/test/tsan/Darwin/gcd-io-race.mm
@@ -0,0 +1,56 @@
+// RUN: %clang_tsan %s -o %t -framework Foundation
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %deflake %run %t 2>&1 | FileCheck %s
+
+// REQUIRES: disabled
+
+#import <Foundation/Foundation.h>
+
+#import "../test.h"
+
+dispatch_queue_t queue;
+dispatch_data_t data;
+dispatch_semaphore_t sem;
+const char *path;
+
+long my_global = 0;
+
+int main(int argc, const char *argv[]) {
+ fprintf(stderr, "Hello world.\n");
+ print_address("addr=", 1, &my_global);
+ barrier_init(&barrier, 2);
+
+ queue = dispatch_queue_create("my.queue", DISPATCH_QUEUE_CONCURRENT);
+ sem = dispatch_semaphore_create(0);
+ NSString *ns_path = [NSTemporaryDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:@"temp-gcd-io.%d", getpid()]];
+ path = ns_path.fileSystemRepresentation;
+ NSData *ns_data = [NSMutableData dataWithLength:1000];
+ data = dispatch_data_create(ns_data.bytes, ns_data.length, NULL, DISPATCH_DATA_DESTRUCTOR_DEFAULT);
+
+ dispatch_io_t channel = dispatch_io_create_with_path(DISPATCH_IO_STREAM, path, O_CREAT | O_WRONLY, 0666, queue, ^(int error) { });
+ if (! channel) abort();
+ dispatch_io_set_high_water(channel, 1);
+
+ dispatch_io_write(channel, 0, data, queue, ^(bool done, dispatch_data_t remainingData, int error) {
+ my_global = 42;
+ barrier_wait(&barrier);
+ });
+
+ dispatch_io_write(channel, 0, data, queue, ^(bool done, dispatch_data_t remainingData, int error) {
+ barrier_wait(&barrier);
+ my_global = 42;
+
+ dispatch_semaphore_signal(sem);
+ });
+
+ dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
+ dispatch_io_close(channel, 0);
+
+ fprintf(stderr, "Done.\n");
+ return 0;
+}
+
+// CHECK: Hello world.
+// CHECK: addr=[[ADDR:0x[0-9,a-f]+]]
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: Location is global 'my_global' {{(of size 8 )?}}at [[ADDR]] (gcd-io-race.mm.tmp+0x{{[0-9,a-f]+}})
+// CHECK: Done.
diff --git a/test/tsan/Darwin/gcd-io.mm b/test/tsan/Darwin/gcd-io.mm
new file mode 100644
index 000000000000..4a1726dac8c7
--- /dev/null
+++ b/test/tsan/Darwin/gcd-io.mm
@@ -0,0 +1,117 @@
+// RUN: %clang_tsan %s -o %t -framework Foundation
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+
+#import <Foundation/Foundation.h>
+
+dispatch_queue_t queue;
+dispatch_data_t data;
+dispatch_semaphore_t sem;
+const char *path;
+
+long my_global = 0;
+
+void test_dispatch_io_write() {
+ dispatch_io_t channel = dispatch_io_create_with_path(DISPATCH_IO_STREAM, path, O_CREAT | O_WRONLY, 0666, queue, ^(int error) { });
+ if (! channel) abort();
+ dispatch_io_set_high_water(channel, 1);
+
+ my_global++;
+ dispatch_io_write(channel, 0, data, queue, ^(bool done, dispatch_data_t remainingData, int error) {
+ if (error) abort();
+ my_global++;
+ dispatch_async(queue, ^{
+ my_global++;
+ if (done) {
+ dispatch_semaphore_signal(sem);
+ }
+ });
+ });
+
+ dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
+ my_global++;
+ dispatch_io_close(channel, 0);
+}
+
+void test_dispatch_write() {
+ dispatch_fd_t fd = open(path, O_CREAT | O_WRONLY, 0666);
+ if (fd == -1) abort();
+
+ my_global++;
+ dispatch_write(fd, data, queue, ^(dispatch_data_t data, int error) {
+ if (error) abort();
+ my_global++;
+ dispatch_async(queue, ^{
+ my_global++;
+
+ dispatch_semaphore_signal(sem);
+ });
+ });
+
+ dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
+ my_global++;
+ close(fd);
+}
+
+void test_dispatch_io_read() {
+ dispatch_io_t channel = dispatch_io_create_with_path(DISPATCH_IO_STREAM, path, O_RDONLY,
+ 0, queue, ^(int error) { });
+ dispatch_io_set_high_water(channel, 1);
+
+ my_global++;
+ dispatch_io_read(channel, 0, SIZE_MAX, queue, ^(bool done, dispatch_data_t remainingData, int error) {
+ if (error) abort();
+ my_global++;
+ dispatch_async(queue, ^{
+ my_global++;
+ if (done) {
+ dispatch_semaphore_signal(sem);
+ }
+ });
+ });
+
+ dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
+ my_global++;
+ dispatch_io_close(channel, 0);
+}
+
+void test_dispatch_read() {
+ dispatch_fd_t fd = open(path, O_RDONLY, 0);
+ if (fd == -1) abort();
+
+ my_global++;
+ dispatch_read(fd, SIZE_MAX, queue, ^(dispatch_data_t data, int error) {
+ if (error) abort();
+ my_global++;
+ dispatch_async(queue, ^{
+ my_global++;
+ dispatch_semaphore_signal(sem);
+ });
+ });
+
+ dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
+ my_global++;
+ close(fd);
+}
+
+int main(int argc, const char *argv[]) {
+ fprintf(stderr, "Hello world.\n");
+
+ queue = dispatch_queue_create("my.queue", DISPATCH_QUEUE_SERIAL);
+ sem = dispatch_semaphore_create(0);
+ NSString *ns_path = [NSTemporaryDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:@"temp-gcd-io.%d", getpid()]];
+ path = ns_path.fileSystemRepresentation;
+ NSData *ns_data = [NSMutableData dataWithLength:1000];
+ data = dispatch_data_create(ns_data.bytes, ns_data.length, NULL, DISPATCH_DATA_DESTRUCTOR_DEFAULT);
+
+ test_dispatch_io_write();
+ test_dispatch_write();
+ test_dispatch_io_read();
+ test_dispatch_read();
+
+ fprintf(stderr, "Done.\n");
+ return 0;
+}
+
+// CHECK: Hello world.
+// CHECK-NOT: WARNING: ThreadSanitizer
+// CHECK: Done.
diff --git a/test/tsan/Darwin/gcd-once.mm b/test/tsan/Darwin/gcd-once.mm
index 17757d203751..3e4a5335607c 100644
--- a/test/tsan/Darwin/gcd-once.mm
+++ b/test/tsan/Darwin/gcd-once.mm
@@ -1,5 +1,5 @@
// RUN: %clang_tsan %s -o %t -framework Foundation
-// RUN: %run %t 2>&1
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
#import <Foundation/Foundation.h>
diff --git a/test/tsan/Darwin/gcd-semaphore-norace.mm b/test/tsan/Darwin/gcd-semaphore-norace.mm
index cd52a79ca65a..20bc5724d165 100644
--- a/test/tsan/Darwin/gcd-semaphore-norace.mm
+++ b/test/tsan/Darwin/gcd-semaphore-norace.mm
@@ -1,5 +1,5 @@
// RUN: %clang_tsan %s -o %t -framework Foundation
-// RUN: %run %t 2>&1
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
#import <Foundation/Foundation.h>
diff --git a/test/tsan/Darwin/gcd-serial-queue-norace.mm b/test/tsan/Darwin/gcd-serial-queue-norace.mm
index 8f6de27695a5..95efbb764c53 100644
--- a/test/tsan/Darwin/gcd-serial-queue-norace.mm
+++ b/test/tsan/Darwin/gcd-serial-queue-norace.mm
@@ -1,5 +1,5 @@
// RUN: %clang_tsan %s -o %t -framework Foundation
-// RUN: %run %t 2>&1
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
#import <Foundation/Foundation.h>
diff --git a/test/tsan/Darwin/gcd-source-cancel.mm b/test/tsan/Darwin/gcd-source-cancel.mm
new file mode 100644
index 000000000000..86e1b28a61c4
--- /dev/null
+++ b/test/tsan/Darwin/gcd-source-cancel.mm
@@ -0,0 +1,36 @@
+// RUN: %clang_tsan %s -o %t -framework Foundation
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+
+#import <Foundation/Foundation.h>
+
+long global;
+
+int main(int argc, const char *argv[]) {
+ dispatch_queue_t queue =
+ dispatch_queue_create("my.queue", DISPATCH_QUEUE_CONCURRENT);
+
+ dispatch_source_t source =
+ dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
+
+ dispatch_source_set_timer(source, dispatch_walltime(NULL, 0), 1e9, 5);
+
+ global = 42;
+
+ dispatch_source_set_cancel_handler(source, ^{
+ fprintf(stderr, "global = %ld\n", global);
+
+ dispatch_sync(dispatch_get_main_queue(), ^{
+ CFRunLoopStop(CFRunLoopGetCurrent());
+ });
+ });
+
+ dispatch_resume(source);
+ dispatch_cancel(source);
+
+ CFRunLoopRun();
+
+ return 0;
+}
+
+// CHECK: global = 42
+// CHECK-NOT: WARNING: ThreadSanitizer
diff --git a/test/tsan/Darwin/gcd-source-cancel2.mm b/test/tsan/Darwin/gcd-source-cancel2.mm
new file mode 100644
index 000000000000..956fe87298bb
--- /dev/null
+++ b/test/tsan/Darwin/gcd-source-cancel2.mm
@@ -0,0 +1,38 @@
+// RUN: %clang_tsan %s -o %t -framework Foundation
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+
+#import <Foundation/Foundation.h>
+
+long global;
+
+void handler(void *arg) {
+ fprintf(stderr, "global = %ld\n", global);
+
+ dispatch_sync(dispatch_get_main_queue(), ^{
+ CFRunLoopStop(CFRunLoopGetCurrent());
+ });
+}
+
+int main(int argc, const char *argv[]) {
+ dispatch_queue_t queue =
+ dispatch_queue_create("my.queue", DISPATCH_QUEUE_CONCURRENT);
+
+ dispatch_source_t source =
+ dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
+
+ dispatch_source_set_timer(source, dispatch_walltime(NULL, 0), 1e9, 5);
+
+ global = 42;
+
+ dispatch_source_set_cancel_handler_f(source, &handler);
+
+ dispatch_resume(source);
+ dispatch_cancel(source);
+
+ CFRunLoopRun();
+
+ return 0;
+}
+
+// CHECK: global = 42
+// CHECK-NOT: WARNING: ThreadSanitizer
diff --git a/test/tsan/Darwin/gcd-source-event.mm b/test/tsan/Darwin/gcd-source-event.mm
new file mode 100644
index 000000000000..e50cb568de1e
--- /dev/null
+++ b/test/tsan/Darwin/gcd-source-event.mm
@@ -0,0 +1,35 @@
+// RUN: %clang_tsan %s -o %t -framework Foundation
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+
+#import <Foundation/Foundation.h>
+
+long global;
+
+int main(int argc, const char *argv[]) {
+ dispatch_queue_t queue =
+ dispatch_queue_create("my.queue", DISPATCH_QUEUE_CONCURRENT);
+
+ dispatch_source_t source =
+ dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
+
+ dispatch_source_set_timer(source, dispatch_walltime(NULL, 0), 1e9, 5);
+
+ global = 42;
+
+ dispatch_source_set_event_handler(source, ^{
+ fprintf(stderr, "global = %ld\n", global);
+
+ dispatch_sync(dispatch_get_main_queue(), ^{
+ CFRunLoopStop(CFRunLoopGetCurrent());
+ });
+ });
+
+ dispatch_resume(source);
+
+ CFRunLoopRun();
+
+ return 0;
+}
+
+// CHECK: global = 42
+// CHECK-NOT: WARNING: ThreadSanitizer
diff --git a/test/tsan/Darwin/gcd-source-event2.mm b/test/tsan/Darwin/gcd-source-event2.mm
new file mode 100644
index 000000000000..c45d481a0028
--- /dev/null
+++ b/test/tsan/Darwin/gcd-source-event2.mm
@@ -0,0 +1,37 @@
+// RUN: %clang_tsan %s -o %t -framework Foundation
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+
+#import <Foundation/Foundation.h>
+
+long global;
+
+void handler(void *arg) {
+ fprintf(stderr, "global = %ld\n", global);
+
+ dispatch_sync(dispatch_get_main_queue(), ^{
+ CFRunLoopStop(CFRunLoopGetCurrent());
+ });
+}
+
+int main(int argc, const char *argv[]) {
+ dispatch_queue_t queue =
+ dispatch_queue_create("my.queue", DISPATCH_QUEUE_CONCURRENT);
+
+ dispatch_source_t source =
+ dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
+
+ dispatch_source_set_timer(source, dispatch_walltime(NULL, 0), 1e9, 5);
+
+ global = 42;
+
+ dispatch_source_set_event_handler_f(source, &handler);
+
+ dispatch_resume(source);
+
+ CFRunLoopRun();
+
+ return 0;
+}
+
+// CHECK: global = 42
+// CHECK-NOT: WARNING: ThreadSanitizer
diff --git a/test/tsan/Darwin/gcd-source-registration.mm b/test/tsan/Darwin/gcd-source-registration.mm
new file mode 100644
index 000000000000..db22613eddae
--- /dev/null
+++ b/test/tsan/Darwin/gcd-source-registration.mm
@@ -0,0 +1,33 @@
+// RUN: %clang_tsan %s -o %t -framework Foundation
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+
+#import <Foundation/Foundation.h>
+
+long global;
+
+int main(int argc, const char *argv[]) {
+ dispatch_queue_t queue =
+ dispatch_queue_create("my.queue", DISPATCH_QUEUE_CONCURRENT);
+
+ dispatch_source_t source =
+ dispatch_source_create(DISPATCH_SOURCE_TYPE_SIGNAL, SIGHUP, 0, queue);
+
+ global = 42;
+
+ dispatch_source_set_registration_handler(source, ^{
+ fprintf(stderr, "global = %ld\n", global);
+
+ dispatch_sync(dispatch_get_main_queue(), ^{
+ CFRunLoopStop(CFRunLoopGetCurrent());
+ });
+ });
+
+ dispatch_resume(source);
+
+ CFRunLoopRun();
+
+ return 0;
+}
+
+// CHECK: global = 42
+// CHECK-NOT: WARNING: ThreadSanitizer
diff --git a/test/tsan/Darwin/gcd-source-registration2.mm b/test/tsan/Darwin/gcd-source-registration2.mm
new file mode 100644
index 000000000000..4431bc9d6898
--- /dev/null
+++ b/test/tsan/Darwin/gcd-source-registration2.mm
@@ -0,0 +1,35 @@
+// RUN: %clang_tsan %s -o %t -framework Foundation
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+
+#import <Foundation/Foundation.h>
+
+long global;
+
+void handler(void *arg) {
+ fprintf(stderr, "global = %ld\n", global);
+
+ dispatch_sync(dispatch_get_main_queue(), ^{
+ CFRunLoopStop(CFRunLoopGetCurrent());
+ });
+}
+
+int main(int argc, const char *argv[]) {
+ dispatch_queue_t queue =
+ dispatch_queue_create("my.queue", DISPATCH_QUEUE_CONCURRENT);
+
+ dispatch_source_t source =
+ dispatch_source_create(DISPATCH_SOURCE_TYPE_SIGNAL, SIGHUP, 0, queue);
+
+ global = 42;
+
+ dispatch_source_set_registration_handler_f(source, handler);
+
+ dispatch_resume(source);
+
+ CFRunLoopRun();
+
+ return 0;
+}
+
+// CHECK: global = 42
+// CHECK-NOT: WARNING: ThreadSanitizer
diff --git a/test/tsan/Darwin/gcd-source-serial.mm b/test/tsan/Darwin/gcd-source-serial.mm
new file mode 100644
index 000000000000..c0989fcc732a
--- /dev/null
+++ b/test/tsan/Darwin/gcd-source-serial.mm
@@ -0,0 +1,33 @@
+// RUN: %clang_tsan %s -o %t -framework Foundation
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+
+#import <Foundation/Foundation.h>
+
+long global;
+
+int main(int argc, const char *argv[]) {
+ fprintf(stderr, "Hello world.\n");
+
+ dispatch_queue_t q = dispatch_queue_create("my.queue", DISPATCH_QUEUE_SERIAL);
+ dispatch_semaphore_t sem = dispatch_semaphore_create(0);
+ dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, q);
+ long long interval_ms = 10;
+ dispatch_source_set_timer(timer, dispatch_time(DISPATCH_TIME_NOW, 0), interval_ms * NSEC_PER_MSEC, 0);
+ dispatch_source_set_event_handler(timer, ^{
+ fprintf(stderr, "timer\n");
+ global++;
+
+ if (global > 50) {
+ dispatch_semaphore_signal(sem);
+ }
+ });
+ dispatch_resume(timer);
+
+ dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
+
+ fprintf(stderr, "Done.\n");
+}
+
+// CHECK: Hello world.
+// CHECK-NOT: WARNING: ThreadSanitizer
+// CHECK: Done.
diff --git a/test/tsan/Darwin/gcd-sync-norace.mm b/test/tsan/Darwin/gcd-sync-norace.mm
index f21cfdedbce1..c683524f73b6 100644
--- a/test/tsan/Darwin/gcd-sync-norace.mm
+++ b/test/tsan/Darwin/gcd-sync-norace.mm
@@ -1,5 +1,5 @@
// RUN: %clang_tsan %s -o %t -framework Foundation
-// RUN: %run %t 2>&1
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
#import <Foundation/Foundation.h>
diff --git a/test/tsan/Darwin/gcd-sync-race.mm b/test/tsan/Darwin/gcd-sync-race.mm
index 62901d9b2612..650faa4e082c 100644
--- a/test/tsan/Darwin/gcd-sync-race.mm
+++ b/test/tsan/Darwin/gcd-sync-race.mm
@@ -1,5 +1,5 @@
// RUN: %clang_tsan %s -o %t -framework Foundation
-// RUN: %deflake %run %t 2>&1
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %deflake %run %t 2>&1 | FileCheck %s
#import <Foundation/Foundation.h>
@@ -9,7 +9,7 @@ long global;
int main() {
NSLog(@"Hello world.");
- NSLog(@"addr=%p\n", &global);
+ print_address("addr=", 1, &global);
barrier_init(&barrier, 2);
dispatch_queue_t q1 = dispatch_queue_create("my.queue1", DISPATCH_QUEUE_CONCURRENT);
@@ -40,5 +40,5 @@ int main() {
// CHECK: Hello world.
// CHECK: addr=[[ADDR:0x[0-9,a-f]+]]
// CHECK: WARNING: ThreadSanitizer: data race
-// CHECK: Location is global 'global' at [[ADDR]] (global_race.cc.exe+0x{{[0-9,a-f]+}})
+// CHECK: Location is global 'global' {{(of size 8 )?}}at [[ADDR]] (gcd-sync-race.mm.tmp+0x{{[0-9,a-f]+}})
// CHECK: Done.
diff --git a/test/tsan/Darwin/ignored-interceptors.mm b/test/tsan/Darwin/ignored-interceptors.mm
new file mode 100644
index 000000000000..d51314281844
--- /dev/null
+++ b/test/tsan/Darwin/ignored-interceptors.mm
@@ -0,0 +1,55 @@
+// Check that ignore_interceptors_accesses=1 supresses reporting races from
+// system libraries on OS X. There are currently false positives coming from
+// libxpc, libdispatch, CoreFoundation and others, because these libraries use
+// TSan-invisible atomics as synchronization.
+
+// RUN: %clang_tsan %s -o %t -framework Foundation
+
+// Check that without the flag, there are false positives.
+// RUN: %deflake %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-RACE
+
+// With ignore_interceptors_accesses=1, no races are reported.
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+
+// With ignore_interceptors_accesses=1, races in user's code are still reported.
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %deflake %run %t race 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-RACE
+
+#import <Foundation/Foundation.h>
+
+#import "../test.h"
+
+long global;
+
+void *Thread1(void *x) {
+ barrier_wait(&barrier);
+ global = 42;
+ return NULL;
+}
+
+void *Thread2(void *x) {
+ global = 43;
+ barrier_wait(&barrier);
+ return NULL;
+}
+
+int main(int argc, char *argv[]) {
+ fprintf(stderr, "Hello world.\n");
+
+ // NSUserDefaults uses XPC which triggers the false positive.
+ NSDictionary *d = [[NSUserDefaults standardUserDefaults] dictionaryRepresentation];
+
+ if (argc > 1 && strcmp(argv[1], "race") == 0) {
+ barrier_init(&barrier, 2);
+ 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");
+}
+
+// CHECK: Hello world.
+// CHECK-RACE: SUMMARY: ThreadSanitizer: data race
+// CHECK: Done.
diff --git a/test/tsan/Darwin/libcxx-shared-ptr-recursive.mm b/test/tsan/Darwin/libcxx-shared-ptr-recursive.mm
new file mode 100644
index 000000000000..eea02dc561e1
--- /dev/null
+++ b/test/tsan/Darwin/libcxx-shared-ptr-recursive.mm
@@ -0,0 +1,36 @@
+// RUN: %clangxx_tsan %s -o %t -framework Foundation
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+
+#import <Foundation/Foundation.h>
+
+#import <memory>
+
+struct InnerStruct {
+ ~InnerStruct() {
+ fprintf(stderr, "~InnerStruct\n");
+ }
+};
+
+struct MyStruct {
+ std::shared_ptr<InnerStruct> inner_object;
+ ~MyStruct() {
+ fprintf(stderr, "~MyStruct\n");
+ }
+};
+
+int main(int argc, const char *argv[]) {
+ fprintf(stderr, "Hello world.\n");
+
+ {
+ std::shared_ptr<MyStruct> shared(new MyStruct());
+ shared->inner_object = std::shared_ptr<InnerStruct>(new InnerStruct());
+ }
+
+ fprintf(stderr, "Done.\n");
+}
+
+// CHECK: Hello world.
+// CHECK: ~MyStruct
+// CHECK: ~InnerStruct
+// CHECK: Done.
+// CHECK-NOT: WARNING: ThreadSanitizer
diff --git a/test/tsan/Darwin/libcxx-shared-ptr-stress.mm b/test/tsan/Darwin/libcxx-shared-ptr-stress.mm
new file mode 100644
index 000000000000..7c36729f010f
--- /dev/null
+++ b/test/tsan/Darwin/libcxx-shared-ptr-stress.mm
@@ -0,0 +1,75 @@
+// RUN: %clangxx_tsan %s -o %t -framework Foundation
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+
+#import <Foundation/Foundation.h>
+
+#import <assert.h>
+#import <memory>
+#import <stdatomic.h>
+
+_Atomic(long) shared_call_counter = 0;
+_Atomic(long) weak_call_counter = 0;
+_Atomic(long) destructor_counter = 0;
+_Atomic(long) weak_destroyed_counter = 0;
+
+struct MyStruct {
+ _Atomic(long) self_counter = 0;
+ virtual void shared_call() {
+ atomic_fetch_add_explicit(&self_counter, 1, memory_order_relaxed);
+ atomic_fetch_add_explicit(&shared_call_counter, 1, memory_order_relaxed);
+ }
+ virtual void weak_call() {
+ atomic_fetch_add_explicit(&weak_call_counter, 1, memory_order_relaxed);
+ }
+ virtual ~MyStruct() {
+ long n = self_counter;
+ assert(n == 1000);
+ atomic_fetch_add_explicit(&destructor_counter, 1, memory_order_relaxed);
+ }
+};
+
+int main(int argc, const char *argv[]) {
+ fprintf(stderr, "Hello world.\n");
+
+ dispatch_queue_t q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
+
+ dispatch_group_t g = dispatch_group_create();
+
+ for (int i = 0; i < 1000; i++) {
+ std::shared_ptr<MyStruct> shared(new MyStruct());
+ std::weak_ptr<MyStruct> weak(shared);
+
+ dispatch_group_async(g, q, ^{
+ for (int j = 0; j < 1000; j++) {
+ std::shared_ptr<MyStruct> shared_copy(shared);
+ shared_copy->shared_call();
+ }
+ });
+ dispatch_group_async(g, q, ^{
+ for (int j = 0; j < 1000; j++) {
+ std::shared_ptr<MyStruct> weak_copy = weak.lock();
+ if (weak_copy) {
+ weak_copy->weak_call();
+ } else {
+ atomic_fetch_add_explicit(&weak_destroyed_counter, 1, memory_order_relaxed);
+ break;
+ }
+ }
+ });
+ }
+
+ dispatch_group_wait(g, DISPATCH_TIME_FOREVER);
+
+ fprintf(stderr, "shared_call_counter = %ld\n", shared_call_counter);
+ fprintf(stderr, "weak_call_counter = %ld\n", weak_call_counter);
+ fprintf(stderr, "destructor_counter = %ld\n", destructor_counter);
+ fprintf(stderr, "weak_destroyed_counter = %ld\n", weak_destroyed_counter);
+
+ fprintf(stderr, "Done.\n");
+}
+
+// CHECK: Hello world.
+// CHECK: shared_call_counter = 1000000
+// CHECK: destructor_counter = 1000
+// CHECK: Done.
+// CHECK-NOT: WARNING: ThreadSanitizer
diff --git a/test/tsan/Darwin/libcxx-shared-ptr.mm b/test/tsan/Darwin/libcxx-shared-ptr.mm
new file mode 100644
index 000000000000..6187c438fec0
--- /dev/null
+++ b/test/tsan/Darwin/libcxx-shared-ptr.mm
@@ -0,0 +1,50 @@
+// RUN: %clangxx_tsan %s -o %t -framework Foundation
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+
+#import <Foundation/Foundation.h>
+
+#import <memory>
+
+#import "../test.h"
+
+long my_global;
+
+struct MyStruct {
+ void setGlobal() {
+ my_global = 42;
+ }
+ ~MyStruct() {
+ my_global = 43;
+ }
+};
+
+int main(int argc, const char *argv[]) {
+ fprintf(stderr, "Hello world.\n");
+ print_address("addr=", 1, &my_global);
+ barrier_init(&barrier, 2);
+
+ std::shared_ptr<MyStruct> shared(new MyStruct());
+
+ dispatch_queue_t q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
+
+ std::weak_ptr<MyStruct> weak(shared);
+
+ dispatch_async(q, ^{
+ {
+ std::shared_ptr<MyStruct> strong = weak.lock();
+ if (!strong) exit(1);
+
+ strong->setGlobal();
+ }
+ barrier_wait(&barrier);
+ });
+
+ barrier_wait(&barrier);
+ shared.reset();
+
+ fprintf(stderr, "Done.\n");
+}
+
+// CHECK: Hello world.
+// CHECK: Done.
+// CHECK-NOT: WARNING: ThreadSanitizer
diff --git a/test/tsan/Darwin/malloc-stack-logging.cc b/test/tsan/Darwin/malloc-stack-logging.cc
new file mode 100644
index 000000000000..8d9c2122d0e6
--- /dev/null
+++ b/test/tsan/Darwin/malloc-stack-logging.cc
@@ -0,0 +1,24 @@
+// Test that MallocStackLogging=1 doesn't crash. MallocStackLogging turns on
+// callbacks from mmap/munmap libc function into libmalloc. Darwin-specific
+// ThreadState initialization needs to avoid calling the library functions (and
+// use syscalls directly) to make sure other interceptors aren't called.
+
+// RUN: %clangxx_tsan -O1 %s -o %t
+// RUN: MallocStackLogging=1 %run %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+void *foo(void *p) {
+ return NULL;
+}
+
+int main() {
+ pthread_t t;
+ pthread_create(&t, NULL, foo, NULL);
+ pthread_join(t, NULL);
+ fprintf(stderr, "Done.\n");
+ return 0;
+}
+
+// CHECK: Done.
diff --git a/test/tsan/Darwin/malloc_size.mm b/test/tsan/Darwin/malloc_size.mm
new file mode 100644
index 000000000000..485d85bba4f8
--- /dev/null
+++ b/test/tsan/Darwin/malloc_size.mm
@@ -0,0 +1,57 @@
+// Test that malloc_zone_from_ptr returns a valid zone for a 0-sized allocation.
+
+// RUN: %clang_tsan %s -o %t -framework Foundation
+// RUN: %run %t 2>&1 | FileCheck %s
+
+#include <malloc/malloc.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+
+int some_global;
+
+void describe_zone(void *p) {
+ malloc_zone_t *z = malloc_zone_from_ptr(p);
+ if (z) {
+ fprintf(stderr, "zone = %p\n", z);
+ } else {
+ fprintf(stderr, "zone = no zone\n");
+ }
+}
+
+int main() {
+ void *p;
+ size_t s;
+
+ p = malloc(0x40);
+ s = malloc_size(p);
+ fprintf(stderr, "size = 0x%zx\n", s);
+ // CHECK: size = 0x40
+ describe_zone(p);
+ // CHECK: zone = 0x{{[0-9a-f]+}}
+
+ p = malloc(0);
+ s = malloc_size(p);
+ fprintf(stderr, "size = 0x%zx\n", s);
+ // CHECK: size = 0x1
+ describe_zone(p);
+ // CHECK: zone = 0x{{[0-9a-f]+}}
+
+ p = &some_global;
+ s = malloc_size(p);
+ fprintf(stderr, "size = 0x%zx\n", s);
+ // CHECK: size = 0x0
+ describe_zone(p);
+ // CHECK: zone = no zone
+
+ p = mmap(0, 0x1000, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0);
+ if (!p) {
+ fprintf(stderr, "mmap failed\n");
+ exit(1);
+ }
+ s = malloc_size(p);
+ fprintf(stderr, "size = 0x%zx\n", s);
+ // CHECK: size = 0x0
+ describe_zone(p);
+ // CHECK: zone = no zone
+}
diff --git a/test/tsan/Darwin/objc-race.mm b/test/tsan/Darwin/objc-race.mm
index bd93d2f1c2ea..82fcc4ef1785 100644
--- a/test/tsan/Darwin/objc-race.mm
+++ b/test/tsan/Darwin/objc-race.mm
@@ -1,5 +1,5 @@
// RUN: %clang_tsan %s -o %t -framework Foundation
-// RUN: %deflake %run %t 2>&1
+// RUN: %deflake %run %t 2>&1 | FileCheck %s
#import <Foundation/Foundation.h>
@@ -49,7 +49,7 @@ int main() {
// CHECK: WARNING: ThreadSanitizer: data race
// CHECK: Write of size 8
// CHECK: #0 -[MyClass method:]
-// CHECK: Write of size 8
+// CHECK: Previous write of size 8
// CHECK: #0 -[MyClass method:]
// CHECK: Location is heap block
// CHECK: Done.
diff --git a/test/tsan/Darwin/objc-simple.mm b/test/tsan/Darwin/objc-simple.mm
index a4bf1f1beaa0..a8fc35592962 100644
--- a/test/tsan/Darwin/objc-simple.mm
+++ b/test/tsan/Darwin/objc-simple.mm
@@ -1,7 +1,7 @@
// Test that a simple Obj-C program runs and exits without any warnings.
// RUN: %clang_tsan %s -o %t -framework Foundation
-// RUN: %run %t 2>&1
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
#import <Foundation/Foundation.h>
diff --git a/test/tsan/Darwin/osatomics-add.mm b/test/tsan/Darwin/osatomics-add.mm
new file mode 100644
index 000000000000..087958eff0f8
--- /dev/null
+++ b/test/tsan/Darwin/osatomics-add.mm
@@ -0,0 +1,48 @@
+// RUN: %clangxx_tsan %s -o %t -framework Foundation -std=c++11
+// RUN: %run %t 2>&1 | FileCheck %s
+
+#import <Foundation/Foundation.h>
+#import <libkern/OSAtomic.h>
+
+#include <thread>
+
+volatile int64_t retainCount = 0;
+
+long g = 0;
+
+void dealloc() {
+ g = 42;
+}
+
+void release() {
+ if (OSAtomicAdd64Barrier(-1, &retainCount) == 0) {
+ dealloc();
+ }
+}
+
+void retain() {
+ OSAtomicAdd64Barrier(1, &retainCount);
+}
+
+int main(int argc, const char * argv[]) {
+ fprintf(stderr, "start\n");
+ retain();
+ retain();
+
+ std::thread t([]{
+ release();
+ });
+
+ g = 47;
+
+ release();
+ t.join();
+
+ fprintf(stderr, "end, g = %ld\n", g);
+
+ return 0;
+}
+
+// CHECK: start
+// CHECK: end, g = 42
+// CHECK-NOT: WARNING: ThreadSanitizer
diff --git a/test/tsan/Darwin/osatomics-list.mm b/test/tsan/Darwin/osatomics-list.mm
new file mode 100644
index 000000000000..6c2fbe7e5c5a
--- /dev/null
+++ b/test/tsan/Darwin/osatomics-list.mm
@@ -0,0 +1,43 @@
+// RUN: %clangxx_tsan %s -o %t -framework Foundation -std=c++11
+// RUN: %run %t 2>&1 | FileCheck %s
+
+#import <Foundation/Foundation.h>
+#import <libkern/OSAtomic.h>
+
+#include <thread>
+
+#include "../test.h"
+
+typedef struct {
+ void *next;
+ long data;
+} ListItem;
+
+OSQueueHead q;
+
+int main(int argc, const char *argv[]) {
+ barrier_init(&barrier, 2);
+
+ std::thread t1([] {
+ ListItem *li = new ListItem{nullptr, 42};
+ OSAtomicEnqueue(&q, li, 0);
+ barrier_wait(&barrier);
+ });
+
+ std::thread t2([] {
+ barrier_wait(&barrier);
+ ListItem *li = (ListItem *)OSAtomicDequeue(&q, 0);
+ fprintf(stderr, "data = %ld\n", li->data);
+ });
+
+ t1.join();
+ t2.join();
+
+ fprintf(stderr, "done\n");
+
+ return 0;
+}
+
+// CHECK: data = 42
+// CHECK: done
+// CHECK-NOT: WARNING: ThreadSanitizer
diff --git a/test/tsan/Darwin/xpc-race.mm b/test/tsan/Darwin/xpc-race.mm
new file mode 100644
index 000000000000..9141da42e3a0
--- /dev/null
+++ b/test/tsan/Darwin/xpc-race.mm
@@ -0,0 +1,81 @@
+// RUN: %clang_tsan %s -o %t -framework Foundation
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %deflake %run %t 2>&1 | FileCheck %s
+
+#import <Foundation/Foundation.h>
+#import <xpc/xpc.h>
+
+#import "../test.h"
+
+long global;
+
+long received_msgs;
+xpc_connection_t server_conn;
+xpc_connection_t client_conns[2];
+
+int main(int argc, const char *argv[]) {
+ @autoreleasepool {
+ NSLog(@"Hello world.");
+ barrier_init(&barrier, 2);
+
+ dispatch_queue_t server_q = dispatch_queue_create("server.queue", DISPATCH_QUEUE_CONCURRENT);
+
+ server_conn = xpc_connection_create(NULL, server_q);
+
+ xpc_connection_set_event_handler(server_conn, ^(xpc_object_t client) {
+ NSLog(@"server event handler, client = %@", client);
+
+ if (client == XPC_ERROR_CONNECTION_INTERRUPTED || client == XPC_ERROR_CONNECTION_INVALID) {
+ return;
+ }
+ xpc_connection_set_event_handler(client, ^(xpc_object_t object) {
+ NSLog(@"received message: %@", object);
+
+ barrier_wait(&barrier);
+ global = 42;
+
+ dispatch_sync(dispatch_get_main_queue(), ^{
+ received_msgs++;
+
+ if (received_msgs >= 2) {
+ xpc_connection_cancel(client_conns[0]);
+ xpc_connection_cancel(client_conns[1]);
+ xpc_connection_cancel(server_conn);
+ CFRunLoopStop(CFRunLoopGetCurrent());
+ }
+ });
+ });
+
+ xpc_connection_resume(client);
+ });
+ xpc_connection_resume(server_conn);
+ xpc_endpoint_t endpoint = xpc_endpoint_create(server_conn);
+
+ for (int i = 0; i < 2; i++) {
+ client_conns[i] = xpc_connection_create_from_endpoint(endpoint);
+ xpc_connection_set_event_handler(client_conns[i], ^(xpc_object_t event) {
+ NSLog(@"client event handler, event = %@", event);
+ });
+
+ xpc_object_t msg = xpc_dictionary_create(NULL, NULL, 0);
+ xpc_dictionary_set_string(msg, "hello", "world");
+ NSLog(@"sending message: %@", msg);
+
+ xpc_connection_send_message(client_conns[i], msg);
+ xpc_connection_resume(client_conns[i]);
+ }
+
+ CFRunLoopRun();
+
+ NSLog(@"Done.");
+ }
+ return 0;
+}
+
+// CHECK: Hello world.
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: Write of size 8
+// CHECK: #0 {{.*}}xpc-race.mm:34
+// CHECK: Previous write of size 8
+// CHECK: #0 {{.*}}xpc-race.mm:34
+// CHECK: Location is global 'global'
+// CHECK: Done.
diff --git a/test/tsan/Darwin/xpc.mm b/test/tsan/Darwin/xpc.mm
new file mode 100644
index 000000000000..a939b02ef21a
--- /dev/null
+++ b/test/tsan/Darwin/xpc.mm
@@ -0,0 +1,74 @@
+// RUN: %clang_tsan %s -o %t -framework Foundation
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+
+#import <Foundation/Foundation.h>
+#import <xpc/xpc.h>
+
+long global;
+
+int main(int argc, const char *argv[]) {
+ @autoreleasepool {
+ NSLog(@"Hello world.");
+
+ dispatch_queue_t server_q = dispatch_queue_create("server.queue", DISPATCH_QUEUE_CONCURRENT);
+ dispatch_queue_t client_q = dispatch_queue_create("client.queue", DISPATCH_QUEUE_CONCURRENT);
+
+ xpc_connection_t server_conn = xpc_connection_create(NULL, server_q);
+
+ global = 42;
+
+ xpc_connection_set_event_handler(server_conn, ^(xpc_object_t client) {
+ NSLog(@"global = %ld", global);
+ NSLog(@"server event handler, client = %@", client);
+
+ if (client == XPC_ERROR_CONNECTION_INTERRUPTED || client == XPC_ERROR_CONNECTION_INVALID) {
+ return;
+ }
+ xpc_connection_set_event_handler(client, ^(xpc_object_t object) {
+ NSLog(@"received message: %@", object);
+
+ xpc_object_t reply = xpc_dictionary_create_reply(object);
+ if (!reply)
+ return;
+ xpc_dictionary_set_string(reply, "reply", "value");
+
+ xpc_connection_t remote = xpc_dictionary_get_remote_connection(object);
+ xpc_connection_send_message(remote, reply);
+ });
+
+ xpc_connection_resume(client);
+ });
+ xpc_connection_resume(server_conn);
+ xpc_endpoint_t endpoint = xpc_endpoint_create(server_conn);
+
+ xpc_connection_t client_conn = xpc_connection_create_from_endpoint(endpoint);
+ xpc_connection_set_event_handler(client_conn, ^(xpc_object_t event) {
+ NSLog(@"client event handler, event = %@", event);
+ });
+
+ xpc_object_t msg = xpc_dictionary_create(NULL, NULL, 0);
+ xpc_dictionary_set_string(msg, "hello", "world");
+ NSLog(@"sending message: %@", msg);
+
+ xpc_connection_send_message_with_reply(
+ client_conn, msg, client_q, ^(xpc_object_t object) {
+ NSLog(@"received reply: %@", object);
+
+ xpc_connection_cancel(client_conn);
+ xpc_connection_cancel(server_conn);
+
+ dispatch_sync(dispatch_get_main_queue(), ^{
+ CFRunLoopStop(CFRunLoopGetCurrent());
+ });
+ });
+ xpc_connection_resume(client_conn);
+
+ CFRunLoopRun();
+
+ NSLog(@"Done.");
+ }
+ return 0;
+}
+
+// CHECK: Done.
+// CHECK-NOT: WARNING: ThreadSanitizer
diff --git a/test/tsan/Linux/check_preinit.cc b/test/tsan/Linux/check_preinit.cc
new file mode 100644
index 000000000000..8f5bf4033760
--- /dev/null
+++ b/test/tsan/Linux/check_preinit.cc
@@ -0,0 +1,60 @@
+// RUN: %clang_tsan -fno-sanitize=thread -shared -fPIC -O1 -DBUILD_SO=1 %s -o \
+// RUN: %t.so && \
+// RUN: %clang_tsan -O1 %s %t.so -o %t && %run %t 2>&1 | FileCheck %s
+// RUN: llvm-objdump -t %t | FileCheck %s --check-prefix=CHECK-DUMP
+// CHECK-DUMP: {{[.]preinit_array.*__local_tsan_preinit}}
+
+// SANITIZER_CAN_USE_PREINIT_ARRAY is undefined on android.
+// UNSUPPORTED: android
+
+// Test checks if __tsan_init is called from .preinit_array.
+// Without initialization from .preinit_array, __tsan_init will be called from
+// constructors of the binary which are called after constructors of shared
+// library.
+
+#include <stdio.h>
+
+#if BUILD_SO
+
+// "volatile" is needed to avoid compiler optimize-out constructors.
+volatile int counter = 0;
+volatile int lib_constructor_call = 0;
+volatile int tsan_init_call = 0;
+
+__attribute__ ((constructor))
+void LibConstructor() {
+ lib_constructor_call = ++counter;
+};
+
+#else // BUILD_SO
+
+extern int counter;
+extern int lib_constructor_call;
+extern int tsan_init_call;
+
+volatile int bin_constructor_call = 0;
+
+__attribute__ ((constructor))
+void BinConstructor() {
+ bin_constructor_call = ++counter;
+};
+
+namespace __tsan {
+
+void OnInitialize() {
+ tsan_init_call = ++counter;
+}
+
+}
+
+int main() {
+ // CHECK: TSAN_INIT 1
+ // CHECK: LIB_CONSTRUCTOR 2
+ // CHECK: BIN_CONSTRUCTOR 3
+ printf("TSAN_INIT %d\n", tsan_init_call);
+ printf("LIB_CONSTRUCTOR %d\n", lib_constructor_call);
+ printf("BIN_CONSTRUCTOR %d\n", bin_constructor_call);
+ return 0;
+}
+
+#endif // BUILD_SO
diff --git a/test/tsan/Linux/user_malloc.cc b/test/tsan/Linux/user_malloc.cc
index c671bfcdd17a..9c3ce681d748 100644
--- a/test/tsan/Linux/user_malloc.cc
+++ b/test/tsan/Linux/user_malloc.cc
@@ -8,7 +8,7 @@ extern "C" void __interceptor_free(void *p);
extern "C" void *malloc(unsigned long size) {
static int first = 0;
if (__sync_lock_test_and_set(&first, 1) == 0)
- printf("user malloc\n");
+ fprintf(stderr, "user malloc\n");
return __interceptor_malloc(size);
}
diff --git a/test/tsan/Unit/lit.site.cfg.in b/test/tsan/Unit/lit.site.cfg.in
index 9498105653a1..23894a839856 100644
--- a/test/tsan/Unit/lit.site.cfg.in
+++ b/test/tsan/Unit/lit.site.cfg.in
@@ -1,5 +1,4 @@
-## Autogenerated by LLVM/Clang configuration.
-# Do not edit!
+@LIT_SITE_CFG_IN_HEADER@
# Load common config for all compiler-rt unit tests.
lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/unittests/lit.common.unit.configured")
diff --git a/test/tsan/aligned_vs_unaligned_race.cc b/test/tsan/aligned_vs_unaligned_race.cc
index 5c1189f34a4b..fb299da8e72e 100644
--- a/test/tsan/aligned_vs_unaligned_race.cc
+++ b/test/tsan/aligned_vs_unaligned_race.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t 2>&1 | FileCheck %s
// Race between an aligned access and an unaligned access, which
// touches the same memory region.
#include "test.h"
@@ -28,7 +28,7 @@ int main() {
pthread_create(&t[1], NULL, Thread2, NULL);
pthread_join(t[0], NULL);
pthread_join(t[1], NULL);
- printf("Pass\n");
+ fprintf(stderr, "Pass\n");
// CHECK: ThreadSanitizer: data race
// CHECK: Pass
return 0;
diff --git a/test/tsan/benign_race.cc b/test/tsan/benign_race.cc
index 2f72fe1860d0..90722aa93157 100644
--- a/test/tsan/benign_race.cc
+++ b/test/tsan/benign_race.cc
@@ -33,7 +33,7 @@ int main() {
Global = 43;
WTFGlobal = 143;
pthread_join(t, 0);
- printf("OK\n");
+ fprintf(stderr, "OK\n");
}
// CHECK-NOT: WARNING: ThreadSanitizer: data race
diff --git a/test/tsan/blacklist.cc b/test/tsan/blacklist.cc
index d6ca383cb758..c1bcca60d505 100644
--- a/test/tsan/blacklist.cc
+++ b/test/tsan/blacklist.cc
@@ -23,7 +23,7 @@ int main() {
pthread_create(&t[1], NULL, Blacklisted_Thread2, NULL);
pthread_join(t[0], NULL);
pthread_join(t[1], NULL);
- printf("PASS\n");
+ fprintf(stderr, "PASS\n");
return 0;
}
diff --git a/test/tsan/blacklist2.cc b/test/tsan/blacklist2.cc
index 629b58821bfe..bf6c4eb75b65 100644
--- a/test/tsan/blacklist2.cc
+++ b/test/tsan/blacklist2.cc
@@ -44,6 +44,6 @@ int main() {
pthread_create(&t[1], NULL, Blacklisted_Thread2, NULL);
pthread_join(t[0], NULL);
pthread_join(t[1], NULL);
- printf("PASS\n");
+ fprintf(stderr, "PASS\n");
return 0;
}
diff --git a/test/tsan/debugging.cc b/test/tsan/debugging.cc
new file mode 100644
index 000000000000..653364404eb0
--- /dev/null
+++ b/test/tsan/debugging.cc
@@ -0,0 +1,108 @@
+// RUN: %clangxx_tsan -O1 %s -o %t
+// RUN: %deflake %run %t 2>&1 | FileCheck %s
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "test.h"
+
+extern "C" {
+void __tsan_on_report(void *report);
+void *__tsan_get_current_report();
+int __tsan_get_report_data(void *report, const char **description, int *count,
+ int *stack_count, int *mop_count, int *loc_count,
+ int *mutex_count, int *thread_count,
+ int *unique_tid_count, void **sleep_trace,
+ unsigned long trace_size);
+int __tsan_get_report_mop(void *report, unsigned long idx, int *tid,
+ void **addr, int *size, int *write, int *atomic,
+ void **trace, unsigned long trace_size);
+int __tsan_get_report_thread(void *report, unsigned long idx, int *tid,
+ unsigned long *os_id, int *running,
+ const char **name, int *parent_tid, void **trace,
+ unsigned long trace_size);
+}
+
+long my_global;
+
+void *Thread(void *a) {
+ barrier_wait(&barrier);
+ my_global = 42;
+ return NULL;
+}
+
+int main() {
+ barrier_init(&barrier, 2);
+ fprintf(stderr, "&my_global = %p\n", &my_global);
+ // CHECK: &my_global = [[GLOBAL:0x[0-9a-f]+]]
+ pthread_t t;
+ pthread_create(&t, 0, Thread, 0);
+ my_global = 41;
+ barrier_wait(&barrier);
+ pthread_join(t, 0);
+ fprintf(stderr, "Done.\n");
+}
+
+void __tsan_on_report(void *report) {
+ fprintf(stderr, "__tsan_on_report(%p)\n", report);
+ fprintf(stderr, "__tsan_get_current_report() = %p\n",
+ __tsan_get_current_report());
+ // CHECK: __tsan_on_report([[REPORT:0x[0-9a-f]+]])
+ // CHECK: __tsan_get_current_report() = [[REPORT]]
+
+ const char *description;
+ int count;
+ int stack_count, mop_count, loc_count, mutex_count, thread_count,
+ unique_tid_count;
+ void *sleep_trace[16] = {0};
+ __tsan_get_report_data(report, &description, &count, &stack_count, &mop_count,
+ &loc_count, &mutex_count, &thread_count,
+ &unique_tid_count, sleep_trace, 16);
+ fprintf(stderr, "report type = '%s', count = %d\n", description, count);
+ // CHECK: report type = 'data-race', count = 0
+
+ fprintf(stderr, "mop_count = %d\n", mop_count);
+ // CHECK: mop_count = 2
+
+ int tid;
+ void *addr;
+ int size, write, atomic;
+ void *trace[16] = {0};
+
+ __tsan_get_report_mop(report, 0, &tid, &addr, &size, &write, &atomic, trace,
+ 16);
+ fprintf(stderr, "tid = %d, addr = %p, size = %d, write = %d, atomic = %d\n",
+ tid, addr, size, write, atomic);
+ // CHECK: tid = 1, addr = [[GLOBAL]], size = 8, write = 1, atomic = 0
+ fprintf(stderr, "trace[0] = %p, trace[1] = %p\n", trace[0], trace[1]);
+ // CHECK: trace[0] = 0x{{[0-9a-f]+}}, trace[1] = {{0x0|\(nil\)|\(null\)}}
+
+ __tsan_get_report_mop(report, 1, &tid, &addr, &size, &write, &atomic, trace,
+ 16);
+ fprintf(stderr, "tid = %d, addr = %p, size = %d, write = %d, atomic = %d\n",
+ tid, addr, size, write, atomic);
+ // CHECK: tid = 0, addr = [[GLOBAL]], size = 8, write = 1, atomic = 0
+ fprintf(stderr, "trace[0] = %p, trace[1] = %p\n", trace[0], trace[1]);
+ // CHECK: trace[0] = 0x{{[0-9a-f]+}}, trace[1] = {{0x0|\(nil\)|\(null\)}}
+
+ fprintf(stderr, "thread_count = %d\n", thread_count);
+ // CHECK: thread_count = 2
+
+ unsigned long os_id;
+ int running;
+ const char *name;
+ int parent_tid;
+
+ __tsan_get_report_thread(report, 0, &tid, &os_id, &running, &name, &parent_tid, trace, 16);
+ fprintf(stderr, "tid = %d\n", tid);
+ // CHECK: tid = 1
+
+ __tsan_get_report_thread(report, 1, &tid, &os_id, &running, &name, &parent_tid, trace, 16);
+ fprintf(stderr, "tid = %d\n", tid);
+ // CHECK: tid = 0
+}
+
+// CHECK: Done.
+// CHECK: ThreadSanitizer: reported 1 warnings
diff --git a/test/tsan/dl_iterate_phdr.cc b/test/tsan/dl_iterate_phdr.cc
index b9ce615f82fe..3c9821bf458a 100644
--- a/test/tsan/dl_iterate_phdr.cc
+++ b/test/tsan/dl_iterate_phdr.cc
@@ -47,7 +47,7 @@ int main(int argc, char *argv[]) {
dlclose(lib);
}
pthread_join(th, 0);
- printf("DONE\n");
+ fprintf(stderr, "DONE\n");
return 0;
}
diff --git a/test/tsan/dtls.c b/test/tsan/dtls.c
new file mode 100644
index 000000000000..51697565f1f1
--- /dev/null
+++ b/test/tsan/dtls.c
@@ -0,0 +1,62 @@
+// RUN: %clang_tsan %s -o %t
+// RUN: %clang_tsan %s -DBUILD_SO -fPIC -o %t-so.so -shared
+// RUN: %run %t 2>&1 | FileCheck %s
+
+// Test that tsan cleans up dynamic TLS memory between reuse.
+
+#include "test.h"
+
+#ifndef BUILD_SO
+#include <assert.h>
+#include <dlfcn.h>
+
+typedef volatile long *(* get_t)();
+get_t GetTls;
+
+void *Thread1(void *arg) {
+ pthread_detach(pthread_self());
+ volatile long *x = GetTls();
+ *x = 42;
+ fprintf(stderr, "stack: %p dtls: %p\n", &x, x);
+ barrier_wait(&barrier);
+ return 0;
+}
+
+void *Thread2(void *arg) {
+ volatile long *x = GetTls();
+ *x = 42;
+ fprintf(stderr, "stack: %p dtls: %p\n", &x, x);
+ return 0;
+}
+
+int main(int argc, char *argv[]) {
+ char path[4096];
+ snprintf(path, sizeof(path), "%s-so.so", argv[0]);
+
+ void *handle = dlopen(path, RTLD_LAZY);
+ if (!handle) fprintf(stderr, "%s\n", dlerror());
+ assert(handle != 0);
+ GetTls = (get_t)dlsym(handle, "GetTls");
+ assert(dlerror() == 0);
+
+ barrier_init(&barrier, 2);
+ pthread_t t[2];
+ pthread_create(&t[0], 0, Thread1, 0);
+ barrier_wait(&barrier);
+ // Wait for actual thread termination without using pthread_join,
+ // which would synchronize threads.
+ sleep(1);
+ pthread_create(&t[1], 0, Thread2, 0);
+ pthread_join(t[1], 0);
+ fprintf(stderr, "DONE\n");
+ return 0;
+}
+#else // BUILD_SO
+__thread long huge_thread_local_array[1 << 17];
+long *GetTls() {
+ return &huge_thread_local_array[0];
+}
+#endif
+
+// CHECK-NOT: ThreadSanitizer: data race
+// CHECK: DONE
diff --git a/test/tsan/fd_close_norace.cc b/test/tsan/fd_close_norace.cc
index 1b52c20f990c..7d9d491f1dcc 100644
--- a/test/tsan/fd_close_norace.cc
+++ b/test/tsan/fd_close_norace.cc
@@ -25,7 +25,7 @@ int main() {
pthread_create(&t[1], NULL, Thread2, NULL);
pthread_join(t[0], NULL);
pthread_join(t[1], NULL);
- printf("OK\n");
+ fprintf(stderr, "OK\n");
}
// CHECK-NOT: WARNING: ThreadSanitizer: data race
diff --git a/test/tsan/fd_close_norace2.cc b/test/tsan/fd_close_norace2.cc
index bf94fd5512b3..382ae5f34a83 100644
--- a/test/tsan/fd_close_norace2.cc
+++ b/test/tsan/fd_close_norace2.cc
@@ -23,7 +23,7 @@ int main() {
while (write(pipes[1], &t, 1) != 1) {
}
pthread_join(t, 0);
- printf("OK\n");
+ fprintf(stderr, "OK\n");
}
// CHECK-NOT: WARNING: ThreadSanitizer: data race
diff --git a/test/tsan/fd_dup_norace.cc b/test/tsan/fd_dup_norace.cc
index 5045325b22b5..e5995175bc0f 100644
--- a/test/tsan/fd_dup_norace.cc
+++ b/test/tsan/fd_dup_norace.cc
@@ -28,7 +28,7 @@ int main() {
pthread_create(&t[1], NULL, Thread2, NULL);
pthread_join(t[0], NULL);
pthread_join(t[1], NULL);
- printf("OK\n");
+ fprintf(stderr, "OK\n");
}
// CHECK-NOT: WARNING: ThreadSanitizer: data race
diff --git a/test/tsan/fd_dup_norace2.cc b/test/tsan/fd_dup_norace2.cc
index 662c686f33a8..31aaed9d356c 100644
--- a/test/tsan/fd_dup_norace2.cc
+++ b/test/tsan/fd_dup_norace2.cc
@@ -53,7 +53,7 @@ int main() {
exit(printf("close failed\n"));
if (close(fd2) == -1)
exit(printf("close failed\n"));
- printf("DONE\n");
+ fprintf(stderr, "DONE\n");
}
// CHECK-NOT: WARNING: ThreadSanitizer: data race
diff --git a/test/tsan/fd_dup_race.cc b/test/tsan/fd_dup_race.cc
index a1aee5500753..d665eebff987 100644
--- a/test/tsan/fd_dup_race.cc
+++ b/test/tsan/fd_dup_race.cc
@@ -27,7 +27,7 @@ int main() {
exit(printf("dup2 failed\n"));
barrier_wait(&barrier);
pthread_join(th, 0);
- printf("DONE\n");
+ fprintf(stderr, "DONE\n");
}
// CHECK: WARNING: ThreadSanitizer: data race
diff --git a/test/tsan/fd_pipe_norace.cc b/test/tsan/fd_pipe_norace.cc
index b434703d782a..01c4490c6c89 100644
--- a/test/tsan/fd_pipe_norace.cc
+++ b/test/tsan/fd_pipe_norace.cc
@@ -27,7 +27,7 @@ int main() {
pthread_create(&t[1], NULL, Thread2, NULL);
pthread_join(t[0], NULL);
pthread_join(t[1], NULL);
- printf("OK\n");
+ fprintf(stderr, "OK\n");
}
// CHECK-NOT: WARNING: ThreadSanitizer: data race
diff --git a/test/tsan/fd_socket_connect_norace.cc b/test/tsan/fd_socket_connect_norace.cc
index ab2a950f17d6..b9fb4340ad78 100644
--- a/test/tsan/fd_socket_connect_norace.cc
+++ b/test/tsan/fd_socket_connect_norace.cc
@@ -38,7 +38,7 @@ int main() {
pthread_join(t, 0);
close(c);
close(s);
- printf("OK\n");
+ fprintf(stderr, "OK\n");
}
// CHECK-NOT: WARNING: ThreadSanitizer: data race
diff --git a/test/tsan/fd_socket_norace.cc b/test/tsan/fd_socket_norace.cc
index 0f41c4357354..07b0cb356b8c 100644
--- a/test/tsan/fd_socket_norace.cc
+++ b/test/tsan/fd_socket_norace.cc
@@ -45,7 +45,7 @@ int main() {
close(c);
close(s);
pthread_join(t, 0);
- printf("OK\n");
+ fprintf(stderr, "OK\n");
}
// CHECK-NOT: WARNING: ThreadSanitizer: data race
diff --git a/test/tsan/fd_socketpair_norace.cc b/test/tsan/fd_socketpair_norace.cc
index a455d44a3965..bee030dd3249 100644
--- a/test/tsan/fd_socketpair_norace.cc
+++ b/test/tsan/fd_socketpair_norace.cc
@@ -31,7 +31,7 @@ int main() {
pthread_create(&t[1], NULL, Thread2, NULL);
pthread_join(t[0], NULL);
pthread_join(t[1], NULL);
- printf("OK\n");
+ fprintf(stderr, "OK\n");
}
// CHECK-NOT: WARNING: ThreadSanitizer: data race
diff --git a/test/tsan/fork_atexit.cc b/test/tsan/fork_atexit.cc
index 51a64fc264d1..15cf0a2485ca 100644
--- a/test/tsan/fork_atexit.cc
+++ b/test/tsan/fork_atexit.cc
@@ -1,5 +1,4 @@
// RUN: %clangxx_tsan -O1 %s -o %t && %env_tsan_opts=atexit_sleep_ms=50 %run %t 2>&1 | FileCheck %s
-// UNSUPPORTED: darwin
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
diff --git a/test/tsan/fork_deadlock.cc b/test/tsan/fork_deadlock.cc
index 22bed086f7d0..32006e2ae530 100644
--- a/test/tsan/fork_deadlock.cc
+++ b/test/tsan/fork_deadlock.cc
@@ -1,5 +1,4 @@
// RUN: %clangxx_tsan -O1 %s -o %t && %env_tsan_opts=atexit_sleep_ms=50 %run %t 2>&1 | FileCheck %s
-// UNSUPPORTED: darwin
#include "test.h"
#include <errno.h>
#include <sys/types.h>
@@ -13,18 +12,10 @@ static void *incrementer(void *p) {
return 0;
}
-static void *watchdog(void *p) {
- sleep(100); // is not intended to exit
- fprintf(stderr, "timed out after 100 seconds\n");
- exit(1);
- return 0;
-}
-
int main() {
barrier_init(&barrier, 2);
- pthread_t th1, th2;
+ pthread_t th1;
pthread_create(&th1, 0, incrementer, 0);
- pthread_create(&th2, 0, watchdog, 0);
for (int i = 0; i < 10; i++) {
switch (fork()) {
default: // parent
diff --git a/test/tsan/fork_multithreaded.cc b/test/tsan/fork_multithreaded.cc
index b345f58ad0c3..faf407b95656 100644
--- a/test/tsan/fork_multithreaded.cc
+++ b/test/tsan/fork_multithreaded.cc
@@ -1,13 +1,12 @@
// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s -check-prefix=CHECK-DIE
// RUN: %clangxx_tsan -O1 %s -o %t && %env_tsan_opts=die_after_fork=0 %run %t 2>&1 | FileCheck %s -check-prefix=CHECK-NODIE
-// UNSUPPORTED: darwin
#include "test.h"
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
static void *sleeper(void *p) {
- sleep(10); // not intended to exit during test
+ sleep(1000); // not intended to exit during test
return 0;
}
diff --git a/test/tsan/fork_multithreaded3.cc b/test/tsan/fork_multithreaded3.cc
index 5b8c13eb8b85..a651b3c18b4e 100644
--- a/test/tsan/fork_multithreaded3.cc
+++ b/test/tsan/fork_multithreaded3.cc
@@ -1,5 +1,4 @@
// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
-// UNSUPPORTED: darwin
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
diff --git a/test/tsan/ignore_lib4.cc b/test/tsan/ignore_lib4.cc
new file mode 100644
index 000000000000..193df11d2b2a
--- /dev/null
+++ b/test/tsan/ignore_lib4.cc
@@ -0,0 +1,48 @@
+// RUN: %clangxx_tsan -O1 %s -DLIB -fPIC -shared -o %T/libignore_lib4.so
+// RUN: %clangxx_tsan -O1 %s -o %t
+// RUN: echo "called_from_lib:libignore_lib4.so" > %t.supp
+// RUN: %env_tsan_opts=suppressions='%t.supp' %run %t 2>&1 | FileCheck %s
+
+// Longjmp assembly has not been implemented for mips64 yet
+// XFAIL: mips64
+// powerpc64 big endian bots failed with "FileCheck error: '-' is empty" due
+// to a segmentation fault.
+// UNSUPPORTED: powerpc64-unknown-linux-gnu
+// aarch64 bots failed with "called_from_lib suppression 'libignore_lib4.so'
+// is matched against 2 libraries".
+// UNSUPPORTED: aarch64
+
+// Test longjmp in ignored lib.
+// It used to crash since we jumped out of ScopedInterceptor scope.
+
+#include "test.h"
+#include <setjmp.h>
+#include <string.h>
+#include <errno.h>
+#include <libgen.h>
+#include <string>
+
+#ifdef LIB
+
+extern "C" void myfunc() {
+ for (int i = 0; i < (1 << 20); i++) {
+ jmp_buf env;
+ if (!setjmp(env))
+ longjmp(env, 1);
+ }
+}
+
+#else
+
+int main(int argc, char **argv) {
+ std::string lib = std::string(dirname(argv[0])) + "/libignore_lib4.so";
+ void *h = dlopen(lib.c_str(), RTLD_GLOBAL | RTLD_NOW);
+ void (*func)() = (void(*)())dlsym(h, "myfunc");
+ func();
+ fprintf(stderr, "DONE\n");
+ return 0;
+}
+
+#endif
+
+// CHECK: DONE
diff --git a/test/tsan/ignore_race.cc b/test/tsan/ignore_race.cc
index cc33b66b27d4..e410006ddc72 100644
--- a/test/tsan/ignore_race.cc
+++ b/test/tsan/ignore_race.cc
@@ -25,7 +25,7 @@ int main() {
barrier_wait(&barrier);
Global = 43;
pthread_join(t, 0);
- printf("OK\n");
+ fprintf(stderr, "OK\n");
}
// CHECK-NOT: WARNING: ThreadSanitizer: data race
diff --git a/test/tsan/ignored-interceptors-mmap.cc b/test/tsan/ignored-interceptors-mmap.cc
new file mode 100644
index 000000000000..8715883238e2
--- /dev/null
+++ b/test/tsan/ignored-interceptors-mmap.cc
@@ -0,0 +1,61 @@
+// RUN: %clangxx_tsan -O0 %s -o %t
+// RUN: not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-NORMAL
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-IGNORE
+
+#include <errno.h>
+#include <sys/mman.h>
+
+#include "test.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 *global_p;
+
+int mmap_and_ignore_reads_and_writes() {
+ const size_t kSize = sysconf(_SC_PAGESIZE);
+ void *p = mmap(0, kSize, PROT_READ|PROT_WRITE,
+ MAP_PRIVATE|MAP_ANON, -1, 0);
+ if (p == MAP_FAILED)
+ return printf("mmap failed with %d\n", errno);
+ munmap(p, kSize);
+
+ void *new_p = mmap(p, kSize, PROT_READ|PROT_WRITE,
+ MAP_PRIVATE|MAP_ANON, -1, 0);
+ if (p == MAP_FAILED || p != new_p)
+ return printf("second mmap failed with %d\n", errno);
+
+ AnnotateIgnoreWritesBegin(__FILE__, __LINE__);
+ global_p = p;
+ AnnotateIgnoreWritesEnd(__FILE__, __LINE__);
+ barrier_wait(&barrier);
+ return 0;
+}
+
+void *Thread(void *a) {
+ barrier_wait(&barrier);
+
+ ((int*)global_p)[1] = 10;
+ printf("Read the zero value from mmapped memory %d\n", ((int*)global_p)[1]);
+ return 0;
+}
+
+int main() {
+ barrier_init(&barrier, 2);
+ pthread_t t;
+ pthread_create(&t, 0, Thread, 0);
+ if (mmap_and_ignore_reads_and_writes())
+ return 1;
+ pthread_join(t, 0);
+ printf("OK\n");
+ return 0;
+}
+
+// CHECK-NORMAL: WARNING: ThreadSanitizer: data race
+// CHECK-NORMAL: OK
+// CHECK-IGNORE_NOT: WARNING: ThreadSanitizer: data race
+// CHECK-IGNORE: OK
diff --git a/test/tsan/inlined_memcpy_race.cc b/test/tsan/inlined_memcpy_race.cc
index 720f2bfcac8c..4d085893aae0 100644
--- a/test/tsan/inlined_memcpy_race.cc
+++ b/test/tsan/inlined_memcpy_race.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t 2>&1 | FileCheck %s
#include "test.h"
#include <string.h>
@@ -24,7 +24,7 @@ int main() {
pthread_create(&t[1], NULL, MemSetThread, x);
pthread_join(t[0], NULL);
pthread_join(t[1], NULL);
- printf("PASS\n");
+ fprintf(stderr, "PASS\n");
return 0;
}
diff --git a/test/tsan/inlined_memcpy_race2.cc b/test/tsan/inlined_memcpy_race2.cc
index 37414ba5d3db..906a52bd32e4 100644
--- a/test/tsan/inlined_memcpy_race2.cc
+++ b/test/tsan/inlined_memcpy_race2.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t 2>&1 | FileCheck %s
#include "test.h"
#include <string.h>
@@ -25,7 +25,7 @@ int main() {
pthread_join(t[0], NULL);
pthread_join(t[1], NULL);
- printf("PASS\n");
+ fprintf(stderr, "PASS\n");
return 0;
}
@@ -33,5 +33,5 @@ int main() {
// CHECK: #0 memset
// CHECK: #1 MemSetThread
// CHECK: Previous write
-// CHECK: #0 memmove
+// CHECK: #0 {{(memcpy|memmove)}}
// CHECK: #1 MemMoveThread
diff --git a/test/tsan/interface_atomic_test.c b/test/tsan/interface_atomic_test.c
index 18d860ea02e2..b7dfc86afa39 100644
--- a/test/tsan/interface_atomic_test.c
+++ b/test/tsan/interface_atomic_test.c
@@ -1,5 +1,5 @@
// Test that we can include header with TSan atomic interface.
-// RUN: %clang_tsan %s -o %t && %run %t | FileCheck %s
+// RUN: %clang_tsan %s -o %t && %run %t 2>&1 | FileCheck %s
#include <sanitizer/tsan_interface_atomic.h>
#include <stdio.h>
@@ -9,7 +9,7 @@ int main() {
int res = __tsan_atomic32_load(&a, __tsan_memory_order_acquire);
if (res == 100) {
// CHECK: PASS
- printf("PASS\n");
+ fprintf(stderr, "PASS\n");
return 0;
}
return 1;
diff --git a/test/tsan/java_alloc.cc b/test/tsan/java_alloc.cc
index 4a606f7940d3..94919a4373a4 100644
--- a/test/tsan/java_alloc.cc
+++ b/test/tsan/java_alloc.cc
@@ -26,10 +26,10 @@ int main() {
stress(jheap);
pthread_join(th, 0);
if (__tsan_java_fini() != 0) {
- printf("FAILED\n");
+ fprintf(stderr, "FAILED\n");
return 1;
}
- printf("DONE\n");
+ fprintf(stderr, "DONE\n");
return 0;
}
diff --git a/test/tsan/java_heap_init.cc b/test/tsan/java_heap_init.cc
index bb7357c25b42..47ec5dbad28e 100644
--- a/test/tsan/java_heap_init.cc
+++ b/test/tsan/java_heap_init.cc
@@ -20,7 +20,7 @@ int main() {
return printf("second mmap failed with %d\n", errno);
__tsan_java_init(jheap, kHeapSize);
__tsan_java_move(jheap + 16, jheap, 16);
- printf("DONE\n");
+ fprintf(stderr, "DONE\n");
return __tsan_java_fini();
}
diff --git a/test/tsan/java_lock_move.cc b/test/tsan/java_lock_move.cc
index fe5491dc2aa0..66599f8b7081 100644
--- a/test/tsan/java_lock_move.cc
+++ b/test/tsan/java_lock_move.cc
@@ -35,7 +35,7 @@ int main() {
barrier_wait(&barrier);
pthread_join(th, 0);
__tsan_java_free(varaddr2, kBlockSize);
- printf("DONE\n");
+ fprintf(stderr, "DONE\n");
return __tsan_java_fini();
}
diff --git a/test/tsan/java_lock_rec.cc b/test/tsan/java_lock_rec.cc
index f0bf40196e9f..aa8de97a148b 100644
--- a/test/tsan/java_lock_rec.cc
+++ b/test/tsan/java_lock_rec.cc
@@ -10,14 +10,14 @@ void *Thread(void *p) {
*(int*)varaddr = 42;
int rec = __tsan_java_mutex_unlock_rec(lockaddr);
if (rec != 2) {
- printf("FAILED 0 rec=%d\n", rec);
+ fprintf(stderr, "FAILED 0 rec=%d\n", rec);
exit(1);
}
barrier_wait(&barrier);
barrier_wait(&barrier);
__tsan_java_mutex_lock_rec(lockaddr, rec);
if (*(int*)varaddr != 43) {
- printf("FAILED 3 var=%d\n", *(int*)varaddr);
+ fprintf(stderr, "FAILED 3 var=%d\n", *(int*)varaddr);
exit(1);
}
__tsan_java_mutex_unlock(lockaddr);
@@ -40,7 +40,7 @@ int main() {
barrier_wait(&barrier);
__tsan_java_mutex_lock(lockaddr);
if (*(int*)varaddr != 42) {
- printf("FAILED 1 var=%d\n", *(int*)varaddr);
+ fprintf(stderr, "FAILED 1 var=%d\n", *(int*)varaddr);
exit(1);
}
*(int*)varaddr = 43;
@@ -48,7 +48,7 @@ int main() {
barrier_wait(&barrier);
pthread_join(th, 0);
__tsan_java_free(jheap, kBlockSize);
- printf("DONE\n");
+ fprintf(stderr, "DONE\n");
return __tsan_java_fini();
}
diff --git a/test/tsan/java_lock_rec_race.cc b/test/tsan/java_lock_rec_race.cc
index 3da8ad076990..bf56eef2022c 100644
--- a/test/tsan/java_lock_rec_race.cc
+++ b/test/tsan/java_lock_rec_race.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t 2>&1 | FileCheck %s
#include "java.h"
jptr varaddr;
@@ -10,7 +10,7 @@ void *Thread(void *p) {
__tsan_java_mutex_lock(lockaddr);
int rec = __tsan_java_mutex_unlock_rec(lockaddr);
if (rec != 3) {
- printf("FAILED 0 rec=%d\n", rec);
+ fprintf(stderr, "FAILED 0 rec=%d\n", rec);
exit(1);
}
*(int*)varaddr = 42;
@@ -42,7 +42,7 @@ int main() {
barrier_wait(&barrier);
pthread_join(th, 0);
__tsan_java_free(jheap, kBlockSize);
- printf("DONE\n");
+ fprintf(stderr, "DONE\n");
return __tsan_java_fini();
}
diff --git a/test/tsan/java_move_overlap.cc b/test/tsan/java_move_overlap.cc
index 7ed98ef1a210..bf8d1e1550fc 100644
--- a/test/tsan/java_move_overlap.cc
+++ b/test/tsan/java_move_overlap.cc
@@ -66,7 +66,7 @@ int main(int argc, char **argv) {
barrier_wait(&barrier);
pthread_join(th, 0);
__tsan_java_free(varaddr1_new, kBlockSize);
- printf("DONE\n");
+ fprintf(stderr, "DONE\n");
return __tsan_java_fini();
}
diff --git a/test/tsan/java_move_overlap_race.cc b/test/tsan/java_move_overlap_race.cc
index 874b90b26341..fbbcf2c8a33f 100644
--- a/test/tsan/java_move_overlap_race.cc
+++ b/test/tsan/java_move_overlap_race.cc
@@ -1,6 +1,6 @@
// RUN: %clangxx_tsan -O1 %s -o %t
-// RUN: %deflake %run %t | FileCheck %s
-// RUN: %deflake %run %t arg | FileCheck %s
+// RUN: %deflake %run %t 2>&1 | FileCheck %s
+// RUN: %deflake %run %t arg 2>&1 | FileCheck %s
#include "java.h"
jptr varaddr1_old;
@@ -46,7 +46,7 @@ int main(int argc, char **argv) {
barrier_wait(&barrier);
pthread_join(th, 0);
__tsan_java_free(varaddr1_new, kBlockSize);
- printf("DONE\n");
+ fprintf(stderr, "DONE\n");
return __tsan_java_fini();
}
diff --git a/test/tsan/java_race_pc.cc b/test/tsan/java_race_pc.cc
index 0745ade6c479..be1c5f26a3b1 100644
--- a/test/tsan/java_race_pc.cc
+++ b/test/tsan/java_race_pc.cc
@@ -1,8 +1,8 @@
// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
-// This test fails on powerpc64 on both VMA (44 and 46).
+// This test fails on powerpc64 big endian.
// The Tsan report is returning wrong information about
// the location of the race.
-// XFAIL: powerpc64
+// XFAIL: powerpc64-unknown-linux-gnu
#include "java.h"
void foobar() {
@@ -13,7 +13,7 @@ void barbaz() {
void *Thread(void *p) {
barrier_wait(&barrier);
- __tsan_read1_pc((jptr)p, (jptr)foobar + 1);
+ __tsan_read1_pc((jptr)p, (jptr)foobar + kPCInc);
return 0;
}
@@ -26,7 +26,7 @@ int main() {
__tsan_java_alloc(jheap, kBlockSize);
pthread_t th;
pthread_create(&th, 0, Thread, (void*)jheap);
- __tsan_write1_pc((jptr)jheap, (jptr)barbaz + 1);
+ __tsan_write1_pc((jptr)jheap, (jptr)barbaz + kPCInc);
barrier_wait(&barrier);
pthread_join(th, 0);
__tsan_java_free(jheap, kBlockSize);
diff --git a/test/tsan/java_rwlock.cc b/test/tsan/java_rwlock.cc
index a4cc92a13635..aa77273a41b5 100644
--- a/test/tsan/java_rwlock.cc
+++ b/test/tsan/java_rwlock.cc
@@ -29,7 +29,7 @@ int main() {
barrier_wait(&barrier);
pthread_join(th, 0);
__tsan_java_free(jheap, kBlockSize);
- printf("DONE\n");
+ fprintf(stderr, "DONE\n");
return __tsan_java_fini();
}
diff --git a/test/tsan/lit.cfg b/test/tsan/lit.cfg
index d141fc228512..1fc1eccd15ea 100644
--- a/test/tsan/lit.cfg
+++ b/test/tsan/lit.cfg
@@ -50,11 +50,12 @@ clang_tsan_cxxflags = config.cxx_mode_flags + clang_tsan_cflags
if config.has_libcxx and config.host_os != 'Darwin':
# FIXME: Dehardcode this path somehow.
libcxx_path = os.path.join(config.compiler_rt_obj_root, "lib",
- "tsan", "libcxx_tsan_" + config.arch)
+ "tsan", "libcxx_tsan_" + config.target_arch)
libcxx_incdir = os.path.join(libcxx_path, "include", "c++", "v1")
libcxx_libdir = os.path.join(libcxx_path, "lib")
libcxx_so = os.path.join(libcxx_libdir, "libc++.so")
clang_tsan_cxxflags += ["-std=c++11",
+ "-nostdinc++",
"-I%s" % libcxx_incdir,
libcxx_so,
"-Wl,-rpath=%s" % libcxx_libdir]
diff --git a/test/tsan/lit.site.cfg.in b/test/tsan/lit.site.cfg.in
index 08d4c1e00c7b..a87e8d25d6b2 100644
--- a/test/tsan/lit.site.cfg.in
+++ b/test/tsan/lit.site.cfg.in
@@ -1,10 +1,9 @@
-## Autogenerated by LLVM/Clang configuration.
-# Do not edit!
+@LIT_SITE_CFG_IN_HEADER@
config.name_suffix = "@TSAN_TEST_CONFIG_SUFFIX@"
-config.arch = "@arch@"
config.has_libcxx = @TSAN_HAS_LIBCXX@
config.target_cflags = "@TSAN_TEST_TARGET_CFLAGS@"
+config.target_arch = "@TSAN_TEST_TARGET_ARCH@"
# Load common config for all compiler-rt lit tests.
lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/test/lit.common.configured")
diff --git a/test/tsan/longjmp.cc b/test/tsan/longjmp.cc
index d642067391fd..61d285c11bf2 100644
--- a/test/tsan/longjmp.cc
+++ b/test/tsan/longjmp.cc
@@ -14,11 +14,11 @@ int foo(jmp_buf env) {
int main() {
jmp_buf env;
if (setjmp(env) == 42) {
- printf("JUMPED\n");
+ fprintf(stderr, "JUMPED\n");
return 0;
}
foo(env);
- printf("FAILED\n");
+ fprintf(stderr, "FAILED\n");
return 0;
}
diff --git a/test/tsan/longjmp2.cc b/test/tsan/longjmp2.cc
index eee423dc5fbe..2b2775a8ca1e 100644
--- a/test/tsan/longjmp2.cc
+++ b/test/tsan/longjmp2.cc
@@ -16,11 +16,11 @@ int main() {
sigjmp_buf env;
printf("env=%p\n", env);
if (sigsetjmp(env, 1) == 42) {
- printf("JUMPED\n");
+ fprintf(stderr, "JUMPED\n");
return 0;
}
foo(env);
- printf("FAILED\n");
+ fprintf(stderr, "FAILED\n");
return 0;
}
diff --git a/test/tsan/longjmp3.cc b/test/tsan/longjmp3.cc
index 79965c4193d3..197b91e1cdc3 100644
--- a/test/tsan/longjmp3.cc
+++ b/test/tsan/longjmp3.cc
@@ -1,4 +1,4 @@
-// RUN: %clang_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+// RUN: %clang_tsan -O1 %s -o %t && %deflake %run %t 2>&1 | FileCheck %s
// Longjmp assembly has not been implemented for mips64 yet
// XFAIL: mips64
@@ -34,7 +34,7 @@ void mymain() {
return;
}
foo(env);
- printf("FAILED\n");
+ fprintf(stderr, "FAILED\n");
}
int main() {
diff --git a/test/tsan/longjmp4.cc b/test/tsan/longjmp4.cc
index c8583997331e..3785a0f07261 100644
--- a/test/tsan/longjmp4.cc
+++ b/test/tsan/longjmp4.cc
@@ -1,4 +1,4 @@
-// RUN: %clang_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+// RUN: %clang_tsan -O1 %s -o %t && %deflake %run %t 2>&1 | FileCheck %s
// Longjmp assembly has not been implemented for mips64 yet
// XFAIL: mips64
@@ -37,7 +37,7 @@ void mymain() {
return;
}
foo(env);
- printf("FAILED\n");
+ fprintf(stderr, "FAILED\n");
}
int main() {
diff --git a/test/tsan/lots_of_threads.c b/test/tsan/lots_of_threads.c
new file mode 100644
index 000000000000..eef9b1cb036c
--- /dev/null
+++ b/test/tsan/lots_of_threads.c
@@ -0,0 +1,30 @@
+// RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+#include "test.h"
+
+void *thr(void *arg) {
+ // Create a sync object on stack, so there is something to free on thread end.
+ volatile int x;
+ __atomic_fetch_add(&x, 1, __ATOMIC_SEQ_CST);
+ barrier_wait(&barrier);
+ return 0;
+}
+
+int main() {
+ const int kThreads = 10;
+ barrier_init(&barrier, kThreads + 1);
+ pthread_t t[kThreads];
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 16 << 20);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+ for (int i = 0; i < kThreads; i++)
+ pthread_create(&t[i], &attr, thr, 0);
+ pthread_attr_destroy(&attr);
+ barrier_wait(&barrier);
+ sleep(1);
+ fprintf(stderr, "DONE\n");
+ return 0;
+}
+
+// CHECK: DONE
+
diff --git a/test/tsan/malloc_overflow.cc b/test/tsan/malloc_overflow.cc
index b2f9b0f57798..3db412978d04 100644
--- a/test/tsan/malloc_overflow.cc
+++ b/test/tsan/malloc_overflow.cc
@@ -6,17 +6,17 @@
int main() {
void *p = malloc((size_t)-1);
if (p != 0)
- printf("FAIL malloc(-1) = %p\n", p);
+ fprintf(stderr, "FAIL malloc(-1) = %p\n", p);
p = malloc((size_t)-1 / 2);
if (p != 0)
- printf("FAIL malloc(-1/2) = %p\n", p);
+ fprintf(stderr, "FAIL malloc(-1/2) = %p\n", p);
p = calloc((size_t)-1, (size_t)-1);
if (p != 0)
- printf("FAIL calloc(-1, -1) = %p\n", p);
+ fprintf(stderr, "FAIL calloc(-1, -1) = %p\n", p);
p = calloc((size_t)-1 / 2, (size_t)-1 / 2);
if (p != 0)
- printf("FAIL calloc(-1/2, -1/2) = %p\n", p);
- printf("OK\n");
+ fprintf(stderr, "FAIL calloc(-1/2, -1/2) = %p\n", p);
+ fprintf(stderr, "OK\n");
}
// CHECK-NOT: FAIL
diff --git a/test/tsan/mmap_stress.cc b/test/tsan/mmap_stress.cc
index e01e7e92b8f9..f272779a49b9 100644
--- a/test/tsan/mmap_stress.cc
+++ b/test/tsan/mmap_stress.cc
@@ -47,6 +47,10 @@ void *Worker(void *arg) {
}
int main() {
+ // This test is flaky on several builders:
+ // https://groups.google.com/d/msg/llvm-dev/KUFPdLhBN3Q/L75rwW9xBgAJ
+ // The cause is unknown (lit hides test output on failures).
+#if 0
pthread_t th[4];
for (int i = 0; i < 4; i++) {
if (pthread_create(&th[i], 0, Worker, 0))
@@ -56,6 +60,7 @@ int main() {
if (pthread_join(th[i], 0))
exit(printf("pthread_join failed: %d\n", errno));
}
+#endif
fprintf(stderr, "DONE\n");
}
diff --git a/test/tsan/mutex_annotations.cc b/test/tsan/mutex_annotations.cc
new file mode 100644
index 000000000000..59fa452c0a76
--- /dev/null
+++ b/test/tsan/mutex_annotations.cc
@@ -0,0 +1,49 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+#include "test.h"
+
+// Test that a linker-initialized mutex can be created/destroyed while in use.
+
+// Stub for testing, just invokes annotations.
+// Meant to be synchronized externally with test barrier.
+class Mutex {
+ public:
+ void Create(bool linker_initialized = false) {
+ if (linker_initialized)
+ ANNOTATE_RWLOCK_CREATE_STATIC(&state_);
+ else
+ ANNOTATE_RWLOCK_CREATE(&state_);
+ }
+
+ void Destroy() {
+ ANNOTATE_RWLOCK_DESTROY(&state_);
+ }
+
+ void Lock() {
+ ANNOTATE_RWLOCK_ACQUIRED(&state_, true);
+ }
+
+ void Unlock() {
+ ANNOTATE_RWLOCK_RELEASED(&state_, true);
+ }
+
+ private:
+ long long state_;
+};
+
+int main() {
+ Mutex m;
+
+ m.Lock();
+ m.Create(true);
+ m.Unlock();
+
+ m.Lock();
+ m.Destroy();
+ m.Unlock();
+
+ fprintf(stderr, "DONE\n");
+ return 0;
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer:
+// CHECK: DONE
diff --git a/test/tsan/mutex_cycle_long.c b/test/tsan/mutex_cycle_long.c
new file mode 100644
index 000000000000..b5d67c16c321
--- /dev/null
+++ b/test/tsan/mutex_cycle_long.c
@@ -0,0 +1,42 @@
+// RUN: %clangxx_tsan %s -o %t
+// RUN: not %run %t 5 2>&1 | FileCheck %s
+// RUN: not %run %t 10 2>&1 | FileCheck %s
+// RUN: not %run %t 15 2>&1 | FileCheck %s
+// RUN: not %run %t 20 2>&1 | FileCheck %s
+// RUN: %run %t 30 2>&1 | FileCheck %s --check-prefix=CHECK-TOO-LONG-CYCLE
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char *argv[]) {
+ int num_mutexes = 5;
+ if (argc > 1) num_mutexes = atoi(argv[1]);
+
+ pthread_mutex_t m[num_mutexes];
+ for (int i = 0; i < num_mutexes; ++i)
+ pthread_mutex_init(&m[i], NULL);
+
+ for (int i = 0; i < num_mutexes - 1; ++i) {
+ pthread_mutex_lock(&m[i]);
+ pthread_mutex_lock(&m[i + 1]);
+
+ pthread_mutex_unlock(&m[i]);
+ pthread_mutex_unlock(&m[i + 1]);
+ }
+
+ pthread_mutex_lock(&m[num_mutexes - 1]);
+ pthread_mutex_lock(&m[0]);
+
+ pthread_mutex_unlock(&m[num_mutexes - 1]);
+ pthread_mutex_unlock(&m[0]);
+
+ for (int i = 0; i < num_mutexes; ++i)
+ pthread_mutex_destroy(&m[i]);
+
+ fprintf(stderr, "PASS\n");
+}
+
+// CHECK: ThreadSanitizer: lock-order-inversion (potential deadlock)
+// CHECK-TOO-LONG-CYCLE: WARNING: too long mutex cycle found
+// CHECK: PASS
diff --git a/test/tsan/mutex_lock_destroyed.cc b/test/tsan/mutex_lock_destroyed.cc
new file mode 100644
index 000000000000..52d6be6210a6
--- /dev/null
+++ b/test/tsan/mutex_lock_destroyed.cc
@@ -0,0 +1,25 @@
+// RUN: %clangxx_tsan %s -o %t
+// RUN: %deflake %run %t | FileCheck %s
+// RUN: %deflake %run %t 1 | FileCheck %s
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char *argv[]) {
+ pthread_mutex_t *m = (pthread_mutex_t *)malloc(sizeof(pthread_mutex_t));
+ pthread_mutex_init(m, 0);
+ pthread_mutex_lock(m);
+ pthread_mutex_unlock(m);
+ pthread_mutex_destroy(m);
+
+ if (argc > 1 && argv[1][0] == '1')
+ free(m);
+
+ pthread_mutex_lock(m);
+ // CHECK: WARNING: ThreadSanitizer: use of an invalid mutex (e.g. uninitialized or destroyed)
+ // CHECK: #0 pthread_mutex_lock
+ // CHECK: #1 main {{.*}}mutex_lock_destroyed.cc:[[@LINE-3]]
+
+ return 0;
+}
diff --git a/test/tsan/pthread_key.cc b/test/tsan/pthread_key.cc
new file mode 100644
index 000000000000..798caa4aba86
--- /dev/null
+++ b/test/tsan/pthread_key.cc
@@ -0,0 +1,39 @@
+// RUN: %clangxx_tsan -O1 %s -DBUILD_SO -fPIC -shared -o %t-so.so
+// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+
+// Extracted from:
+// https://bugs.chromium.org/p/v8/issues/detail?id=4995
+
+#include "test.h"
+
+void* thr(void* arg) {
+ const int N = 32;
+ pthread_key_t keys_[N];
+ for (size_t i = 0; i < N; ++i) {
+ int err = pthread_key_create(&keys_[i], 0);
+ if (err) {
+ fprintf(stderr, "pthread_key_create failed with %d\n", err);
+ exit(1);
+ }
+ }
+ for (size_t i = 0; i < N; i++)
+ pthread_setspecific(keys_[i], (void*)(long)i);
+ for (size_t i = 0; i < N; i++)
+ pthread_key_delete(keys_[i]);
+ return 0;
+}
+
+int main() {
+ for (int i = 0; i < 10; i++) {
+ pthread_t th;
+ pthread_create(&th, 0, thr, 0);
+ pthread_join(th, 0);
+ }
+ pthread_t th[2];
+ pthread_create(&th[0], 0, thr, 0);
+ pthread_create(&th[1], 0, thr, 0);
+ pthread_join(th[0], 0);
+ pthread_join(th[1], 0);
+ fprintf(stderr, "DONE\n");
+ // CHECK: DONE
+}
diff --git a/test/tsan/race_on_mutex.c b/test/tsan/race_on_mutex.c
index d998fdca2df3..c7f5e06392c5 100644
--- a/test/tsan/race_on_mutex.c
+++ b/test/tsan/race_on_mutex.c
@@ -1,26 +1,30 @@
// RUN: %clang_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
-// This test fails on powerpc64 (VMA=46).
-// The size of the write reported by Tsan for T1 is 8 instead of 1.
-// XFAIL: powerpc64-unknown-linux-gnu
#include "test.h"
pthread_mutex_t Mtx;
int Global;
-void *Thread1(void *x) {
- pthread_mutex_init(&Mtx, 0);
+void *Thread2(void *x) {
+ barrier_wait(&barrier);
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK-NEXT: Atomic read of size 1 at {{.*}} by thread T2:
+// CHECK-NEXT: #0 pthread_mutex_lock
+// CHECK-NEXT: #1 Thread2{{.*}} {{.*}}race_on_mutex.c:[[@LINE+1]]{{(:3)?}} ({{.*}})
pthread_mutex_lock(&Mtx);
- Global = 42;
+ Global = 43;
pthread_mutex_unlock(&Mtx);
- barrier_wait(&barrier);
return NULL;
}
-void *Thread2(void *x) {
- barrier_wait(&barrier);
+void *Thread1(void *x) {
+// CHECK: Previous write of size {{[0-9]+}} at {{.*}} by thread T1:
+// CHECK: #{{[0-9]+}} {{.*}}pthread_mutex_init {{.*}} ({{.*}})
+// CHECK-NEXT: #{{[0-9]+}} Thread1{{.*}} {{.*}}race_on_mutex.c:[[@LINE+1]]{{(:3)?}} ({{.*}})
+ pthread_mutex_init(&Mtx, 0);
pthread_mutex_lock(&Mtx);
- Global = 43;
+ Global = 42;
pthread_mutex_unlock(&Mtx);
+ barrier_wait(&barrier);
return NULL;
}
@@ -34,11 +38,3 @@ int main() {
pthread_mutex_destroy(&Mtx);
return 0;
}
-
-// CHECK: WARNING: ThreadSanitizer: data race
-// CHECK-NEXT: Atomic read of size 1 at {{.*}} by thread T2:
-// CHECK-NEXT: #0 pthread_mutex_lock
-// CHECK-NEXT: #1 Thread2{{.*}} {{.*}}race_on_mutex.c:21{{(:3)?}} ({{.*}})
-// CHECK: Previous write of size 1 at {{.*}} by thread T1:
-// CHECK-NEXT: #0 pthread_mutex_init {{.*}} ({{.*}})
-// CHECK-NEXT: #1 Thread1{{.*}} {{.*}}race_on_mutex.c:11{{(:3)?}} ({{.*}})
diff --git a/test/tsan/race_on_speculative_load.cc b/test/tsan/race_on_speculative_load.cc
index dd40daeb5c19..5a9d698ca9a6 100644
--- a/